[PYTHONCOMP] Civ4lerts: Alert messages about in game events

Joined
Feb 25, 2003
Messages
811
This mod implements on screen alerts for a variety of in-game events such as city growth and the availability of new trade opportunities. The concept is modelled after the CivAssist tool for Civilization 3, and in fact, many of the alerts are the same.

The alerts will not reveal information that would otherwise be unavailable. They are simply intended to call the player's attention to situations as they arise without requiring tedious scanning of the advisor screens on each turn.

The alert messages are integrated with the existing event log. Like those messages, a notification is displayed on screen for a short period of time. Messages that have been cleared from the screen can be recalled by opening the event log. When appropriate, clicking on a message brings the camera focus to the site of the event.

The supported alerts are listed below. The alerts are documented in greater detail in the Features section

  • City will grow on the next turn
  • City will become unhealthy on the next turn
  • City will become angry on the next turn
  • City has grown
  • City has become unhealthy
  • City has become angry
  • Civilization has significant amount of gold available for trade
  • Civilization has significant amount of gold per turn available for trade

Future releases will include support for additional alerts and a user interface for configuring options.

Changes:
  • 2006-Aug-11
    • Updated for Warlords compatibility.
  • Appears to work with Civ4 version 1.61. No changes necessary.
  • 2006-Mar-12, v1.3
    • Fixed a bug with determining the user directory when the installation directory has been renamed. Thanks to 12monkeys
  • 2006-Feb-28, v1.2
    • Fixed the search path for .INI files. The parser was searching the Assets directories instead of their respective parent directories. Thanks to jray
    • Restored the 6 Boolean state flags to the event handler front end. Thanks to jray
  • 2006-Feb-2, v1.1
    • Added the CvModName feature to CvConfigParser to allow discovery of the active mod name under certain circumstances.
    • Fixed exception handling in INI file reader.

Civ4lerts.zip
 
CivFan91 said:
Sorry for the mini-bump, but I was wondering if you had any screenshots of the mod working. I'm wondering if it is like CivAssist II where you had to minimize Civ to see it. After all, it takes so long to get back into the game when cIV gets minimized... =/

I don't have any screenshots, but they wouldn't be very interesting anyway. No, it's not like CivAssist.

You know the messages that show up on screen saying things like "Hinduism has been founded in a far away land" or "India has declared war on the Spanish?" The alerts generated by this mod work the same way.

You'll get a little on-screen message about the event. The message will fade away after about 10 seconds. If you want to recall a message (like maybe you got a whole pile of them at once) you can open the event log that's usually shown in the upper left region of the screen.

Also, think about how the built in message work when a forest is chopped or when a city's cultural borders work. You know how there's a little icon you can click to zoom to the city or the tile that had the forest? Some of the alerts also have a similar icon. It doesn't make sense for all of them (where would you zoom for "Catherine has 63 gold available for trade," but alerts like city growth and health or happiness problems will all zoom to the city.

So, in summary, you might not see any signs that it's working if no city is growing. At the beginning of a game it might take as many as 10 or 20 turns before you see an alert, depending on your game speed, the city quality, and various other factors.

The easiest way to verify that it's working is probably to load an old save from late in a game when everyone is in the modern age and has lots of gold. Then skip to the next turn. The first turn after you load a saved game will always display a lot of trade alerts, because every trading opportunity is "new." That is, let's say Napoleon has 167 gold available. Since you just loaded this game, you haven't been alterted to that situation yet, so as soon as you skip to the next turn, you'll see a trading alert. Since most leaders will have at least 50 gold to trade late in the game, you'll always get a pile of warnings on that first turn.
 
Your Civ4lerts mod looks good, but whenever I try to load it the game says there's a problem with the CvEventInterface file. Any ideas? Thanks.
 
OblivionOdyssey said:
Your Civ4lerts mod looks good, but whenever I try to load it the game says there's a problem with the CvEventInterface file. Any ideas? Thanks.

No idea about what the actual problem is, but I do know how to find out. Open your CivilizationIV.ini file (usually C:\Documents and Settings\User\My Documents\My Games\Sid Meier's Civilization 4\CivilizationIV.ini) and change the "LoggingEnabled" settings as shown below.

Code:
LoggingEnabled = 1

Then next time you run the game, it will create various files in the Logs directory (usually C:\Documents and Settings\User\My Documents\My Games\Sid Meier's Civilization 4\Logs). There should be a PythonErr2.log and a PythonErr.log. One or both of those should have some error messages in them. If you post those here, I can probably figure out what's causing the problem.

Thanks.
 
Awesome mod!!!

I wonder if you can help me with a problem. When I edit Civ4lerts.ini, I don't see the changes occuring in the game. For example, I set the gold trading notifications to False, but I still see them. (I have Civ4lerts.ini in the usual place, at My Games\Sid Meier's Civilization 4\).

I also have additional problems when I try to merge this mod with Alerum's Unaltered Gameplay. I don't know Python, but I'm a software developer and was pretty careful :cool:. After the merge, the in-game wonder movies and new-tech splash screens (the ones where Leanord Nimoy talks) stop happening. I also get errors in PythonErr.log (see below). I tried Alerum's mod alone, and it worked fine. When I try Civ4lerts alone, I see wonder movies, but they are choppy (actually... there may be another factor involved in this problem, since I think I was using a different Civ4.ini when I tried that... so forget that for now...).

I see the "CvModName import failed" message in the python error logs, but I assume this is expected since I don't have any mods. Everything is in CustomAssets. I'd be glad to send additional files if that would help debug things. Thanks in advance for help!

Below is a paste of the error message I get in PythonErr.log (repeated 6 times) after merging Civ4lerts and Alerum:

Code:
Traceback (most recent call last):

  File "CvEventInterface", line 23, in onEvent

  File "CvCustomEventManager", line 115, in handleEvent

  File "CvCustomEventManager", line 126, in _handleDefaultEvent

  File "CvEventManager", line 517, in onBuildingBuilt

AttributeError: 'CvCustomEventManager' object has no attribute 'bMultiPlayer'
ERR: Python function onEvent failed, module CvEventInterface

And here is the call at line 23 of CvEventInterface:

Code:
def onEvent(argsList):
	'Called when a game event happens - return 1 if the event was consumed'
	return getEventManager().handleEvent(argsList)
 
I know what the problem is with the exceptions in onBuildingBuilt. I did some "cleanup" in the handleEvent method, but since I don't know Python very well, I think I cleaned up some stuff that was important. Oops! :blush: I'll try to post a fixed version later today.

I'm not sure why your .INI file edits wouldn't be working, but since the defaults are set the way I like them, I don't actually do any overrides myself, so that stuff isn't very well tested. I'll do some experiments and see what I can come up with. It does sound like you have the .INI file in the correct place, and you're right that the error about CvModName doesn't matter (that's a weird hack to help find the .INI file if you install the mod in the Mods directory).
 
Thanks for the quick response!

I wonder if you could suggest a way to circumvent your custom parser, so I can try that and see if it's the cause of my .ini problem. Since I have all my .ini's in the same usual place, I don't need the custom parsing.
 
Turns out I was only partly right about the cause. It's in the area of the code I took out, but there was also a change made in Alerum's mod (or someone else's that got merged into his) that is part of the problem. If you change the CvCustomEventManager.handleEvent function as shown below, it should set bMultiPlayer properly. The change is the addition of three new lines at the beginning.

Code:
    def handleEvent(self, argsList):
        """Handles events by calling all installed handlers."""
        self.origArgsList = argsList
        flagsIndex = len(argsList) - 6
        self.bDbg, self.bMultiPlayer, self.bAlt, self.bCtrl, self.bShift, self.bAllowCheats = argsList[flagsIndex:]
        eventType = argsList[0]
        return {
            "kbdEvent": self._handleConsumableEvent,
            "mouseEvent": self._handleConsumableEvent,
            "OnSave": self._handleOnSaveEvent,
            "OnLoad": self._handleOnLoadEvent
        }.get(eventType, self._handleDefaultEvent)(eventType,
                                                   argsList[1:flagsIndex])

I don't think the INI files work like you think they do. ;) If you disable the CvConfigParser class in my mod, the INI file won't work at all, no matter where you put it.

The reason all that stuff is in there is that the Civ4 API's don't give mods any way of accessing settings from their INI files. You'll notice that every mod in the Mods directory has its own INI file with stuff like "SinglePlayerOnly," "AllowPublicMaps," "Name," etc. That looks like the perfect place to store all your custom mod settings, right? After all, that file is already read in by the game, so let's just put a few more values in there.

Great idear, but it doesn't actually work. Wherever the game puts that INI file after it reads it, it's not accessible from Python. So that's why I've got that parser class there. I sort of borrowed/stole the idea from the Hall of Fame mod and adapted it a bit to be more general and to have fewer/no hardcoded paths.

I'm about to try some tests to see if I can track down why it isn't working.
 
Code:
    def handleEvent(self, argsList):
        """Handles events by calling all installed handlers."""
        self.origArgsList = argsList
        flagsIndex = len(argsList) - 6
        self.bDbg, self.bMultiPlayer, self.bAlt, self.bCtrl, self.bShift, self.bAllowCheats = argsList[flagsIndex:]
        eventType = argsList[0]
        return {
            "kbdEvent": self._handleConsumableEvent,
            "mouseEvent": self._handleConsumableEvent,
            "OnSave": self._handleOnSaveEvent,
            "OnLoad": self._handleOnLoadEvent
        }.get(eventType, self._handleDefaultEvent)(eventType,
                                                   argsList[1:flagsIndex])

Don't make the change shown in the last line (:flagsIndex). Or if you do, make sure you also remove ":len(argsList) - 6" from each of the other handle*Event functions. They're both trying to do the same thing, and they step on each others toes if you have both.
 
Yay, it works now without any errors! Thanks so much!

I was also able to manually set the INI stuff in the .py files... was easy to find. But out of curiosity, is the INI file supposed to work if I just put it in the parent folder of CustomAssets and have all my .py files in CustomAssets (instead of MODS)?

FYI, I also merged in TheLopez's Specialist Stacker. I saw that he uses your custom config parser. Probably not a surprise, but I can't get it to read its INI either. But again it was easy to change the .py files directly, so oh well :).
 
jray said:
is the INI file supposed to work if I just put it in the parent folder of CustomAssets and have all my .py files in CustomAssets (instead of MODS)?

Yes, it's supposed to "just work." I did some testing though, and I saw the same problem you did. After a little investigation, I discovered that it wasn't reading the config file at all (big surprise; you already knew that much :-)). The directory search path was wrong. It was looking in the assets directories instead of in their parents.

I just updated the attachment in the first post of the thread. That has both of these recent fixes. Alternatively, if it's easier for you to just change the code directly, you can change the __init__ method of CvConfigParser as shown below. The change is to the line that initializes filenames. I added "os.path.dirname(dir)" where it previously just said "dir".

Code:
    def __init__(self, filename = None, *args, **kwargs):
        """Initializes the parser by reading options from the named file."""
        super(CvConfigParser, self).__init__(*args, **kwargs)
        if (filename != None):
            filenames = [os.path.join(os.path.dirname(dir), filename) 
                         for dir in CvPath.assetsPath]
            filenames.reverse() 
            self.read(filenames)
 
Dr Elmer Jiggle said:
I just updated the attachment in the first post of the thread. That has both of these recent fixes. Alternatively, if it's easier for you to just change the code directly, you can change the __init__ method of CvConfigParser as shown below. The change is to the line that initializes filenames. I added "os.path.dirname(dir)" where it previously just said "dir".

Awesome, thanks! I appreciate you mentioning the changes since I had already done some merging. I'll let you know if I find any problems. I tried changing the Specialist Stacker INI file since that is faster to see the effects of (at least in my game right now, where I haven't met any competitors yet), and that worked. So I assume your INI will work fine too.
 
Nice work on the mod! :goodjob:

This is very useful to me, because I'm so forgetful during my games. I always end up neglecting to check and see how my populations are doing. :) So this helps me keep track of it all.
 
Dr Elmer Jiggle said:
(that's a weird hack to help find the .INI file if you install the mod in the Mods directory).

It might be a weird hack, but you know what? It has been working very well for me given that they didn't provide ANY way to get the name of the currently loaded mod.
 
Wow - I loaded this as a standalone mod, and it is exactly what I'm looking for.

Too bad (for me) I have no clue on how to incorporate this into my own fusion mod. I've fused together 28 or so mod components, many that use CvCustomEventManager and I don't know how to adopt Dr Jiggle's code into my hacked CvCustomEventManager.

But still, I'd like to try.

I wonder how I could tweak the following code in my hacked CvCustomEventManager:

def __init__(self):
# initialize base class
self.parent = CvEventManager.CvEventManager
self.parent.__init__(self)
self.Events[7501] = ('FreeTechPopup', self.__eventFreeTechApply , self.__eventFreeTechBegin)

def initValues(self):

self.iProphetID = CvUtil.findInfoTypeNum (gc.getUnitInfo,gc.getNumUnitInfos(),'UNIT_PROPHET')
etc.

... with respect to Dr Jiggle's code:

class CvCustomEventManager(CvEventManager.CvEventManager, object):

def __init__(self, *args, **kwargs):
super(CvCustomEventManager, self).__init__(*args, **kwargs)
# map the initial EventHandlerMap values into the new data structure
for eventType, eventHandler in self.EventHandlerMap.iteritems():
self.setEventHandler(eventType, eventHandler)
# --> INSERT EVENT HANDLER INITIALIZATION HERE <--
Civ4lerts.Civ4lerts(self)

def addEventHandler(self, eventType, eventHandler):
etc.

I respect the fact that Dr Jiggle's approach is compliant with a sensible way to fuse mods together. Unfortunately, while I have the time and will to fuse mods together, I don't have the time (and thus the will) to grasp the science I would need to fold this into my mod. Is there a way to sidestep the elegance of Dr Jiggle's method, just this once, to fold this into my CvCustomEventManager?

Respectfully,
Spocko

PS - I wonder whether I could reverse my question and learn how to fold my existing CvCustomEventManager into Dr Jiggle's?
 
I'll try to post some details later after I've had a chance to look over your example. It should be easy to do either way -- either fold my alerts into your event manager or install your handlers into my event manager. I had some documentation on doing this at one point, but I don't think I ever fleshed it out. This might motivate me to get back to it.
 
Back
Top Bottom