Requesting following features

I wonder if we should merge the Utils and CustomFunctions together or just leave them apart? Because most likely the CustomFunctions will be carried into my future mods and it would then be a problem to just move seeing though it then contains your variables for JRM (which would not be present in JMM for example) and plus I kinda like having my own homemade file which is completly and utterly mine :p
Well, we could very well have "Jamie's Utils" and "Baldyr's Utils" but it doesn't make much sense to me. Because you should probably be using my helper functions in both this and any future project. You should take a look at them - or should I document them for you so that you know how to use them? Otherwise you will end up copy-pasting them into CustomFunctions anyway. (There is more utils in the new Rebellion module, by the way, and some of those could be useful in other modules as well, so those will probably get moved to Utils/CustomFunctions/whatever in time. Or I could make a new version shortly and include more utils.)

btw in case of merging required in the EventManager... I added a comment next to all I have edited in the file (aside from the very bottom). This comment reads: #Hi Baldyr! and in Utils, everything that is irregular unitwise has #Irregular next to it!
I'm thinking that I shouldn't make any more changes to EvEventManger myself - you're in charge of it now! :king: So I'll tell you where to put imports and function calls going forward. You'll manage it easily and you retain control over your own mod. This is sort of a coming-of-age or rite-of-passage thing, I guess. :goodjob:

(seeing though my Functions has more functions then Utils maybee Utils should become the variable Module and leave all functions to CustomFunctions :p)
Sure, when I'm done with working on your mod we can rename Utils to Constants and move all functions to CustomFunctions. But right now we might as well work on your respective modules, because otherwise we'll just lose track of who edited what.

I even think that you should put all the constants you're defining into your own module, for now. If you import Utils first and CustomFeatures only after it, then all duplicate names will be replaced with your correct versions. So you shouldn't even touch Utils and let me work on it on my own. (Everything will be yours in the end anyway, and you will be able to do whatever you want with all of it.)

EDIT: btw I had a quick look in the event XML and found these in the eventinfos (which define the options you get when a trigger is met ie: in the event forestfire you get 3 options, replant, lose etc) <PythonCallback/><PythonExpireCheck/><PythonCanDo/><PythonHelp/> and in the event trigger infos (defines what makes the event happen, like an if statement, but you probably already guessed that)<PythonCanDo/><PythonCanDoCity/><PythonCanDoUnit/><PythonCallback/>

is that anything like what you wanted before?
Yeah, I think I urged you to take a look at this stuff before deciding on plugging your events into the Event Manager. Because you could just have defined the events in XML and used Python functions for the tasks listed above. Its basically your decision.
 
ah but python is more fun and easier to do event wise than XML!

I got a python exception from asafs dll but maybee it was because I tried loading the 18 civ senario but I have it documented just in case!

busy doing the WBS file atm ready to pack everything up to be sent to you (hopefully but then end of the day...)
 
ok for you informaton in a 28civ DLL (btw that exception is gone) the barbarians take space 29 (the invisible space 28 in WBS) so you might still be able to use your function!

I'm going to fix the rebels as you said to do for the moment
 
your quick-fix failed. I am just doing some small testing on the 2 events I made and then I will pack everything up (I presume you still have those leader heads?)
 
Yeah, I already figured out that it would fail, as the code would inevitably be invoking a method on the value None. This is of course invalid and the exception should have pointed this out.

I have all previously sent files so you pretty much only need to send those folders that have been updated.
 
you are going to receive ALL my current files apart from the 2 Leaderheads (I don't actually know which ones I have changed :lol:)... these will be sent in 4 parts. delete the files you have aside from the 2 leaderheads and put everything I send you in their rightfull places (all of the zips are layed out in their correct file positions so it should be easy! Tell me if something is wrong and have fun!)

you also have my python (with the wrong dates on the 2 events but that should not be a problem!)
 
I didn't get a part 3... :confused:
 
mmm Yeah I sent that again a while ago and I just got the e-mail it failed - again. I guess it doesn't like part three... well I will put it here... sorry about that!

:D
 

Attachments

I guess 8MB is too much for your mail provider...

I don't actually know which ones I have changed :lol:

Try using version control ;)
 
no it can't be because I sent 10.1 MB as part 2

hmmm mystery
 
ok I am still powering on with my python (right now I am remaking the senate event to use some of the new helper functions I have availble to me since trying it last)

Code:
##Byzantium Senate Prompt##
iSenateYear = 1350
iSenateEndYear = 1575
senateHeader = "Senate"
senateMessage1 = "The glorius Senate of Rome requests that you take the city of Byzantium. If you take it and hold it at the end of 30 turns (turn X) you will be greatly rewarded"
senateMessage2 = "The glorius Senate of Rome wishes that you make sure that you keep control of Byzantium by the end of 30 turns. If you successful, you will be rewarded!"
senateMessage3 = "The Senate notes that you have failed to control Byzantium and you will not be rewarded!"  
tByzantium = (46, 23)
def eventSenate():
    if pHumanCiv == eRome: #is this correct?
        if isDate(iSenateYear):
            if isPlotOwner(tByzantium, eRome) == False:
                showPopup(senateHeader, senateMessage1)
            if isPlotOwner(tByzantium, eRome) == True:
                showPopup(senateHeader, senateMessage2)
        if isDate(iSenateEndYear):
            if isPlotOwner(tByzantium, eRome) == True:
                #Give Reward#
                save()
            if isPlotOwner(tByzantium, eRome == False:
                showPopup(senateHeader, senateMessage3)

does the if pHumanPlayer == eRome work? (I will check the API but I am not sure)

and how would I go about gifting gold to Rome if they control byzantium? there is a VOID changeGold (INT iChange) in the API Which changes gold (I am guessing) (I will see what I can do about a helper function for this, I have one in mind I just need the relevant statement to construct it...)

of course, this event is quite devious, making the player try and take (or hold) Byzantium within 30 turns with promise of reward should make the player promptly go for it... This removes the question that was asked with byzantium first was brought up of: what happens if rome doesn't control any cities in the east? Well they don't appear... So my event will increase the chance of them appearing as long as the player is playing as rome...
 
also I made a helper function (I think it works?)

Code:
def hasCivLostCity(ePlayer):
    """
    Returns if the specified civ has lost any cities.
    True for lost 1 or more cities
    False for lost no cities
    """
    pPlayer = gc.getPlayer(ePlayer)
    if pPlayer.getCitiesLost() >= 1:
        return True
    else:
        return False

might be useful someday... Do you think this works? (see API cyPlayer 147)

EDIT: I found my statement (from post 572): INT getGold ()

so I will try and contruct a little helper function!

EDIT2: ok heres my shot at a GiveGold helper function:
Code:
def giveGold(iChange, ePlayer):
    pPlayer = gc.getPlayer(ePlayer)
    iGold = pPlayer.getGold()
    pPlayer.changeGold(iChange + iGold)

as you can see, some nice little maths going on there! The problem is... I don't know whether the original staement of changeGold changes the value of the the players gold (say enter in 3000 and the player now has 3000 gold regardless of previous values) or adds to it. So thats why it uses the current gold of the player to get the gold change: it can simply be change Gold to current Gold + iChange. Pretty simple really. However if changeGold adds to it instead of just changing it then the player will get double their gold + iChange :rolleyes: There is also
VOID setGold (INT iNewValue) which could be used in this (and is probably what I think changeGold is: a means of completly setting a persons gold to specified value, regardless of previous value) and might be if changeGold doesn't work...
 
Assuming that pHumanCiv is referring to the constant defined in Utils:
Code:
pHumanCiv = instance(Game.getActivePlayer())
...then its not a PlayerType (aka Player ID or a ePlayer) but a CivPlayer instance.

To retrieve the Player ID of a CivPlayer you use the get() method:
Code:
pHumanCiv.get(playerID)
But then again I don't know what the name eRome is referring to... Where is it defined? :confused:

Something you could do, with CivPlayer in mind, is to get the CivPlayer instance of the Roman player and compare it to pHumanCiv:
Code:
pRomanCiv = Civ("Rome")
if pHumanCiv == pRomanCiv:

By the way, there are 2 times 2 if statements in the script. You should probably make those 2 times 2 pairs of if/elif statements instead. Because only one of each will - and should - ever pass on any single game turn. This saves computing time, even if it wouldn't even be noticeable. It does add up however, and if this mod continues to grow there will eventually be noticeable lag...

Your very first helper function looks alright to me, so congratulations! :goodjob: But I might add that it could be shorted to just:
Code:
def hasCivLostCity(ePlayer):
    return gc.getPlayer(ePlayer).getCitiesLost() >= 1
:eek: Can you figure out why this is?

Regarding your second attempt, the giveGold() function, you probably missed the CyPlayer.setGold() method. These methods usually come in 3 varieties: get, set and change. The effect you're looking for could simply be achieved by:
Code:
pPlayer.changeGold(iChange)
But this would also work:
Code:
iGold = pPlayer.getGold()
pPlayer.setGold(iGold + iChange)
If you can access the Python console you can actually test these things while the game is running, and both get info from and change actual Cy objects! :king:

edit: I see that you already found setGold() ;)
 
:( unfortunatly I still don't know what the python console's shortkey key is... The good thing is I can add my 2 new helper functions to the CustomFunctions module and use it to complete the senate event!

so would this work as a helper function to find the player?
Code:
def isHuman(Civilization): 
    pPlayer = Civ("Civilization")
    if pHumanCiv == pPlayer:
        return True
    else:
        return False
    #Don't put selected civ in brackets!!!

eRome = pointer("Rome", playerID) is in my Utils (and yours too now!)

I don't see why your simple version of my first helper function works?

untill you confirm whether the 3rd helper function would work or not the code is as follows:
Code:
##Byzantium Senate Prompt##
iSenateYear = 1350
iSenateEndYear = 1575
iSenateGold = 1000
senateHeader = "Senate"
senateMessage1 = "The glorius Senate of Rome requests that you take the city of Byzantium. If you take it and hold it at the end of 30 turns (turn X) you will be greatly rewarded"
senateMessage2 = "The glorius Senate of Rome wishes that you make sure that you keep control of Byzantium by the end of 30 turns. If you successful, you will be rewarded!"
senateMessage3 = "The Senate notes that you have failed to control Byzantium and you will not be rewarded!"  
tByzantium = (46, 23)
def eventSenate():
    if pHumanCiv == pRomanCiv: #if my 3rd helper function works this will become: if isHuman(Rome) == True:
        if isDate(iSenateYear):
            if isPlotOwner(tByzantium, eRome) == False:
                showPopup(senateHeader, senateMessage1)
            elif isPlotOwner(tByzantium, eRome) == True:
                showPopup(senateHeader, senateMessage2)
        elif? isDate(iSenateEndYear):
            if isPlotOwner(tByzantium, eRome) == True:
                giveGold(iSenateGold, eRome)
            elif isPlotOwner(tByzantium, eRome == False:
                showPopup(senateHeader, senateMessage3)
Do you think this works all fine? The thing I'm worried about is that elif statement... Because it says if the date is this show popup. In my mind this means that the code then stops once if has been fufilled even though elif hasn't been done (and that's the important part!). Am I right in thinking this?
 
so would this work as a helper function to find the player?
Code:
def isHuman(Civilization): 
    pPlayer = Civ("Civilization")
    if pHumanCiv == pPlayer:
        return True
    else:
        return False
    #Don't put selected civ in brackets!!!
This would work if you take away the quotations around the argument Civilization. (Could I suggest you simply call the argument/variable name?)

As with the last function, this one can also be shortened, but this time I'm gonna give you the missing link:
PHP:
def isHuman(name): 
    pCivPlayer = Civ(name)
    bIsHuman = pHumanCiv == pCivPlayer # assign the value of a boolean expression to a variable
    return bIsHuman # return the value of the variable
There is another way to make this function also, that would be valid for multiplayer:
PHP:
def isHuman(name): # takes the Civ name (string) as the argument
    pPlayer = pointer(name, CyPlayer) # assings the CyPlayer instance of the CivPlayer corresponding to name to the value pPlayer
    return pPlayer,isHuman() # return the return value of CyPlayer.isHuman()
eRome = pointer("Rome", playerID) is in my Utils (and yours too now!)
The way I designed CivPlayer is not to have to define PlayerTypes, CyPlayer instances and so on, but only define CivPlayer instances - since these contain all the other values (also teams and more).

So if you instead define:
Code:
pRomanCiv = Civ("Rome")
Then you can get the hold of the PlayerType any time you need it with:
Code:
eRome = pRomanCiv.get(playerID)
I think this is convenient, but others might not agree. :p

Do you think this works all fine? The thing I'm worried about is that elif statement... Because it says if the date is this show popup. In my mind this means that the code then stops once if has been fufilled even though elif hasn't been done (and that's the important part!). Am I right in thinking this?
This is how it works: Each if/elif/else statement tree is resolved separately. Only one of the branches will be executed. If you need several if statements to be executed then you can only use if:s. In this case I guess you only need one branch to fire at any given time. (Actually, logic will prevent anything else from even happening anyway.)

But since you're only checking whether one function call is returning True or False, then you don't even need the elif. You can get away with just the if and a else. Play around with it a bit and it'll make sense to you. I hope. :crazyeye:
Spoiler :
Code:
        if isDate(iSenateYear):
            if not isPlotOwner(tByzantium, eRome):
                showPopup(senateHeader, senateMessage1)
            else:
                showPopup(senateHeader, senateMessage2)
        elif isDate(iSenateEndYear):
            if isPlotOwner(tByzantium, eRome):
                giveGold(iSenateGold, eRome)
            else:
                showPopup(senateHeader, senateMessage3)
 
so the way it is set out above, will both the elif and the if fire at their given times or just if (because it's first)?

anyway finished (?) code for senate plus added helps in CustomFunctions:

Code:
##Byzantium Senate Prompt##
iSenateYear = 1350
iSenateEndYear = 1575
iSenateGold = 1000
senateHeader = "Senate"
senateMessage1 = "The glorius Senate of Rome requests that you take the city of Byzantium. If you take it and hold it at the end of 30 turns (turn X) you will be greatly rewarded"
senateMessage2 = "The glorius Senate of Rome wishes that you make sure that you keep control of Byzantium by the end of 30 turns. If you successful, you will be rewarded!"
senateMessage3 = "The Senate notes that you have failed to control Byzantium and you will not be rewarded!"  
tByzantium = (46, 23)
def eventSenate():
    if isHuman("Rome") == True:
        if isDate(iSenateYear):
            if isPlotOwner(tByzantium, eRome) == False:
                showPopup(senateHeader, senateMessage1)
            else:
                showPopup(senateHeader, senateMessage2)
        elif isDate(iSenateEndYear):
            if isPlotOwner(tByzantium, eRome) == True:
                giveGold(iSenateGold, eRome)
            else:
                showPopup(senateHeader, senateMessage3)
and
Code:
def hasCivLostCity(ePlayer):
    """
    Returns if the specified civ has lost any cities.
    True for lost 1 or more cities
    False for lost no cities
    """
    pPlayer = gc.getPlayer(ePlayer)
    if pPlayer.getCitiesLost() >= 1:
        return True
    else:
        return False

def giveGold(iChange, ePlayer):
    """
    Gives gold to the specified player!
    """
    pPlayer = gc.getPlayer(ePlayer)
    iGold = pPlayer.getGold()
    pPlayer.setGold(iChange + iGold)
    #Note to self: DO NOT USE iGold to define amount of gold to give!!!
    #Use a negative value to deduct money!

def isHuman(name):
    pPlayer = Civ(name)
    if pHumanCiv == pPlayer:
        return True
    else:
        return False
    #Use brackets to define name, e.g. isHuman("Rome") == True

I didn't shorten the functions yet...
 
so the way it is set out above, will both the elif and the if fire at their given times or just if (because it's first)?
Its actually a hierarchy, where the if is evaluated first, then all elif:s in order, and only then any else.
I didn't shorten the functions yet...
There is no real need to do so either. I was just pointing out something about boolean expressions in general. You might wanna consider reading up on the subject sometime in the future.

It'll be interesting to hear about your testing of this. :king: I'm not necessarily agreeing on the event design itself, but I can totally appreciate how much fun it must be for you to get into programming. :goodjob:
 
what don't you agree with may I ask? Yep I am loving python at the moment! :D
 
what don't you agree with may I ask?
Well, I didn't look too closely at the text messages or anything, but it seems a bit odd to be given a bogus "mission" to go and capture some city. (Doesn't the Senate have any other requests in this manner, might one ask?)

I of course understand the reason for the "event", but I wouldn't perhaps do it this way myself. The Byzantium spawn thing would probably be a more general event that could center around any eastern metropolis (with preference towards Byzantion), depending on the circumstances. Not as historical, but I suppose we're different people as scenario designers? :p

But I'm not here to put your design down - I'm here to help you implement it.

Yep I am loving python at the moment! :D
You can see how it was designed to be fun, right? :king:

About shortening or not, this should be a clearer and fully functioning version of the isDate() function:
Code:
def isDate(iDate):
    iCurrentGameYear = Game.getGameTurnYear()
    iCurrentGameTurn = Game.getGameTurn()
    iNextTurnGameYear = Game.getTurnYear(iCurrentGameTurn + 1)
    bIsNotHasDatePassed = iCurrentGameYear <= iDate
    bIsNextTurnPastDate = iNextTurnGameYear > iDate
    if bIsNotHasDatePassed and bIsNextTurnPastDate:
        return True
    else:
        return False
And lastly, why not build a Senate feature into the mod (Roman player only)? Sorta like a random events feature but you get tasked with different (historical) goals by the Senate? There could be rewards (not necessarily cash) involved.

I'm envisioning a Senate module as your next programming project. It would involve a Mission class which instances would be the various historical tasks. You'd define each mission by calling the Mission class constructor and supplying it a variety of settings, like starting and expiration dates, rewards and mission text tags. (Or these could be defined in a dictionary, so it would be sorta like working with XML.) There could be sub-classes for various kinds of missions. :D
 
Back
Top Bottom