View Full Version : Representing seasons thru terrain change in-game


ww2commander
Mar 16, 2007, 12:34 AM
Hi,

I have tried my best to find an answer and hopefully someone can point me in the right direction if it exists.

I am tinkering with the idea of making a scenario where season plays an important role in unit movement and city food consumption.

I hope to learn XML and Python editing soon (I'm one of those people that spends more time daydreaming that doing :mischief: ) and want to know if there is a way to change terrain tiles in game.

I want to do something where if the date is Dec 2000 all terrain tiles in certains plots change from grassland to snow to represent winter time.

For those who played Red Front in CiV2, you will know what I am talking about.

Also, if changing the terrain is straight forward (hopefully), how hard would it be to do this on a 'whole map' level rather than just selected tiles.....I gather I must sit there and go thru all tiles manual in a xml file somewhere....which makes me wonder would this be a performance issue.

Any response would be much appreciated. :)

Paasky
Mar 16, 2007, 04:42 AM
Yes, it is totally possible with python.

Download the WWII Europe from my sig (3mb) and see for yourself as the land is covered in snow as winter comes.

You can also check through the code to see how snarko has done it. although, if you want to do it for the entire map, I think that can be done more easily than to write down all of the terrains.

ww2commander
Mar 16, 2007, 05:10 AM
Thank you very much for the response Paasky.

I will download and check out immediately.

Can you guide me as to which file(s) I should look into as I am a bit in the dark when it comes to reading thru the different files???

Paasky
Mar 16, 2007, 05:18 AM
Everything is done in python, so open WWIIsfnbEvents.py. there I've (unfortunately) had to set the plots twice (in def onLoadGame & onGameStart), then in onBeginGameTurn you can see where the snowcheck itself is called, and finally def snowcheck has the code.

I did the plot setting with excel, copypasted into notepad++, and replaced all tabs & enters with nothing, which made a looong list of plots.

ww2commander
Mar 16, 2007, 05:24 PM
Paasky,

With your permission, can I use graphic and mod components from your scenario such as the leaderhead flags for my scenario.

I ask as it seems you have put a lot of time and effort into this project and I dont want to use your graphics if they are exclusive to your project.

It look quite impressive the effort you have put into this project.:goodjob:

Paasky
Mar 16, 2007, 07:39 PM
Sure. But if you use the snow, remember to give thanks to snarko, who originally coded them. I mean it isn't a rule, but would be a nice thing to do :)

If you need other flags, give me a PM, I can do 1 flag in about 10secs ;)

ww2commander
Mar 16, 2007, 08:16 PM
Thanks.

I will make a note to include credits for all the mods and graphics I use.

I am trying to make an Eastern Front scenario and thus the reason for the seasons. Since the day I played Nemo's Red Front on Civ 2 I have been obsessed with the dream to make a CiV 4 version. I wont promise myself that it will reach beta stage because I tend to have a 'lazy bug' ingrown somewhere in my brain:lol:

I tried a simple swap of flags for the civs in my WBS mapfile and some display ok but some go a bit funny. I am using the USSR, UK, Sweden, Finland and German flags.
- The swedish flags cross is green
- The UK flag is very dark like shadowed or something
- USSR hammer and sickle dont appear:confused:

Do I have to set a palette somewhere or can I just port the flags in with no change except the files in Arts\.....\TeamColours

Paasky
Mar 16, 2007, 10:18 PM
You need to change WhiteFlag=1 from =0 in the wbs.

You wouldn't want to do a little merge? It would reduce your workload by a big amount, and give extra content for me ;)

ww2commander
Mar 16, 2007, 10:55 PM
I really dont have much at this stage to even call it a scenario...plus I dont want to go 'public' and then have the preasure to finish it if I dont have the time....so for now it will be a private scenario....but if it gets to a workable stage I would love your feedback :)

I am only working on the map right now and the city placement is driving me crazy.

Im hoping to recycle all the ww2 units already available as well as the bluemarble (sp?) terrain.

The thing that is scaring me off the whole thing is the custom events, seasons, improvements and other XML things....hell anything that involves XML or python scares the crap out of me right now :cry:

I just downloaded Rhye's and Fall of Civs mod to try and get marshes into the game....but all I have achieved so far is importing a bright red circle instead of new marsh terrain :crazyeye: I guess there is alot I dont know yet!!!

ww2commander
Mar 16, 2007, 11:10 PM
Whiteflag worked like a charm....thanks.

I feel stupid because I was reading the WBS file tutorial prior to importing your flags and stopped reading at the entry before 'whiteflag'. If only I had red the next entry I could have avoided this mistake.

Paasky
Mar 17, 2007, 06:06 AM
Oh boy, you've got a LOT of mistakes waiting for you ;)

Yeah, city placement in russia is very hard. I suggest you get a biggish map of Eastern Europe, and then a printout of your map (take a screenshot of YAME with your map open for example) and then draw the lat & long degrees on your printout. It helps a lot. (= how I did Russia & Southeast Europe)

If you get XMLSpy (google it), editing XML will be easy. Python is another thing, but a few evenings of bugfixing & copy-pasting with someone who knows atleast some python have tought me a lot.

ww2commander
Mar 17, 2007, 06:56 AM
Well the Civ gods have blessed me today. The map is coming along very well minus resources and features. Right now its only base terrain and city placement.

I have placed almost 98% of the Soviet cities and the total is around 40-50 cities. I agree with you, drawing Russian maps is hell given that the maps tend to bend or flex to give the wider perspective.

The way I got around this is with my beloved 'bible'....its an old book I picked up years ago which is the only WW2 atlas I use for all my needs....the book is called "The Times Atlas of the Second World War". Its a huge book with a cityview map of Stalingrad on the cover and the maps are amazing and very useful.

I found a map that was the perfect area for the scenario map and traced it out with tracing paper. Then I divided the traced map into grids which I roughly calculated into squares on the map. It took a while but the results were great. Every city fell perfectly into place (plus or minus a square) and even the rivers fell into place almost perfectly. I had to convert some of the rivers using the coast terrain to make them impassible except at city junctions.

The hardest part was everything east of the Volga which is where most maps bend....to get around this problem i cross referenced several maps and used rivers as the locating points....once again i was happy with the results but placement of cities north of the volga may be a bit off by a few squares but nothing majorly incorrect.

I also managed to get the marshes into the game...there seems to be a worldbuilder bug because you cant place marshes directly on the map!!!! Instead i draw the marshes out using the snow terrain and then did a textpad find/replace of the plots with marshes in the WBS file. When I reloaded the map, the marshes showed up fine...the only problem is the grid which wont display so i disabled this in the marsh areas.

In the next few days I will place all German, Sweddish and Finn cities on the map.

Then I move on to the resources, features and transport routes. :crazyeye:

IVZanIV
Mar 17, 2007, 11:06 AM
Python is another thing, but a few evenings of bugfixing & copy-pasting with someone who knows atleast some python have tought me a lot.

Hmm, wonder who... :crazyeye:

ww2commander, once you reach the Python stage I am willing to leave myself available to answer any questions and/or help you with as much coding as you need. I've done this with Paasky to the point where he doesn't even need my help 99% of the time anymore, and it's alot easier to learn with someone to ask every now and then.

ww2commander
Mar 17, 2007, 07:32 PM
IVZanIV thanks for the offer :)

I was starting to worry that the python events and so on would be the downfall of my idea as the Eastern Front has a lot of events that change the course of the war. At a quick glance I will need to represent the following in the scenario:

1. Partisan uprisings
2. Controlling techs based on the time of the year.
3. Seasons....Paasky's mod seems to have this already but I am clueless on how it works!
4. Naval convoys in the arctic generating based on time.
5. Oil/fuel as a consumable resource....someone on the forums already started a tutorial on this and I was hoping it may work for want to do.
6. Playing mini movies like the wonder movies everytime an event occurs such as the Battle for Stalingrad, Kursk and Berlin.

Last night I managed to get an intro movie to work as well as changing the menu music. I consider these as big baby steps for someone who does not know Python...hehe

All I can say is a very BG THANK YOU to all the people that take the time to make tutorials on this forum :goodjob:

ww2commander
Mar 18, 2007, 04:33 PM
I managed to finish all the Fin, Swed, Norway cities last night. I still have to finish off the some of the Soviet cities on the Polish border and all the eastern European cities.

I figured at this stage I would test out the season change concept. Can you guys give me a high level overview of what I may need to change in python to do the following:

1.) If month = one of the winter months then
2.) Get plot (x,y)
3.) If terrain is sea/ocean ignore
4.) If terrain is grass change to ice
5.) If terrain is plains change to tundra
6.) Increment plot to move across to next tile and repeat.
7.) Once row is complete move to next row

Paasky
Mar 18, 2007, 06:47 PM
Ah, that's easy.


week = (CyGame().getGameTurn() % 48) + 1 # If your using months, change 48 to 12
if week == 12 or week == 36: # Last week of September & last week of March, I think...
x = 0
y = 0
if week == 12:
terrainGTo = 0 #check http://civilization4.net/files/modding/PythonAPI/Types/TerrainTypes.html for these numbers
terrainGFrom = 4
terrainPTo = 1
terrainPFrom = 3
if week == 36:
terrainGFrom = 0
terrainGTo = 4
terrainPFrom = 1
terrainPTo = 3
while x <= 10: # Insert map width here
while y <= 10: # Insert map height here
if not CyMap().plot(x, y).getTerrainType == 5 or CyMap().plot(x, y).getTerrainType == 6:
if CyMap().plot(x, y).getTerrainType == terrainPFrom:
CyMap().plot(x, y).setTerrainType(terrainPTo, True, True)
if CyMap().plot(x, y).getTerrainType == terrainGFrom:
CyMap().plot(x, y).setTerrainType(terrainGTo, True, True)
y = y + 1
x = x + 1
I'm not sure about the getTerrainType, so it might not work. If it gives errors during loading or ingame (remember to set show python exceptions to 1 in your civ4.ini), take a screenshot & ask me or IVZanIV about it (preferably through one of the IM's).
ICQ 349611636
AIM Paaskyz
MSN my_junk88@hotmail.com
Yahoo! peksoft

IVZanIV
Mar 18, 2007, 07:25 PM
Ah, I think that should work but I would check your variables in there, you have pTo and pFrom in the while loops, but no definition of them...

AIM: DrkCloud5591
Yahoo!: DrkCloud5591
MSN: DrkCloud5591@hotmail.com

(Those are in order of my most active checking of them, I'm barely ever on MSN anymore.)

Paasky
Mar 18, 2007, 08:06 PM
Oops, forgot to name them after a copy-paste...
Edited the code :hammer:

Trillian ftw! I'm online with everyone of those 4 at the same time. ;)

EmperorFool
Mar 18, 2007, 09:48 PM
You also need to reset y to 0 each time through the x loop. I'm a coder but just learning Python and cIV modding, so here's my take for my own edification.

week = (CyGame().getGameTurn() % 48) + 1 # If your using months, change 48 to 12
if week == 12 or week == 36: # Last week of September & last week of March, I think...
if week == 12:
terrainGFrom = 4
terrainGTo = 0
terrainPFrom = 3
terrainPTo = 1
if week == 36:
terrainGFrom = 0
terrainGTo = 4
terrainPFrom = 1
terrainPTo = 3
map = CyMap()
for y in range(map.getGridHeight()):
for x in range(map.getGridWidth()):
plot = map.plot(x, y)
terrainType = plot.getTerrainType()
if terrainType == terrainPFrom:
plot.setTerrainType(terrainPTo, True, True)
elif terrainType == terrainGFrom:
plot.setTerrainType(terrainGTo, True, True)

The main changes I made are

1. Replace "while" loops with "for" loops using range().
2. Get width and height from CyMap.
3. Use local variables to hold CyMap, CyPlot and terrainType. This avoids recreating them each time, which when looping over the entire map may be noticable.

Mostly these boil down to "defensive coding." :goodjob:

Note that you cannot have any ice or tundra on the map during the non-winter months or they'll revert to grass/plains at the first spring thaw. I assume there are parts of Russia that are frozen over even during the summer. If so, you may be able to store a value on each plot that you changed at the start of winter (called pickling) and then look for those values when going to spring. However, I haven't read how to do that.

And finally a suggestion: if you are indeed having week-long turns, it might look cool to have the map freeze/thaw over a few turns instead of everywhere at once. Obviously tougher to code, but maybe a nice challenge. :)

ww2commander
Mar 18, 2007, 10:01 PM
Thanks for the fast feedabck from all of you. Much appreciated.

I am looking at your code at it seems to make sense to me on some levels but obviously I must know what variables to use based on the API website Paasky provided.

Right now I am at work :cry: , but when I get home I will do up a test map and try to get this code working.

With relation to the map, I avoided using tundra and snow during the warm months to make it easier to change the terrain across. The idea about gradual terrain change is cool but the programming would scare me from doing it....furthermore, I want to spend more time on gameplay rather than climate research as trying to get everything perfect mapwise can become a bit too tiresome and that leads to abondoning projects when they seem more like work then play :sleep:

Quick question....do I add the above code in my Cv'MyMod'Events.py file under the OnBeginTurn section?

Thanks heaps to all :worship: :thanx:

Paasky
Mar 18, 2007, 10:56 PM
Yes you do. Remember to call your new .py file in EventInterface.py. you can check wwii on how to do that).
Actually, making the plots be semi-random (like my winter, only less complicated) can be done quite easily. I'll see what I can whip up once I get my own events working ;)

Emperor: I've got a semi-random winter in my WWII mod, the code was created by snarko, and it works very nicely.
And I have to say your code looks better than mine. Then again, I've known python for about 2 weeks now...

EmperorFool
Mar 18, 2007, 11:29 PM
Paasky: I'll check out your mod when I get a chance, as the random freeze/thaw sounds really cool. As far as Python goes, I'm new like you. However, I've been coding in over ten languages or so for wow, 25 years now. After that long you can easily grok a lot of the syntax from sample code. Most of the coding habits carry over from language to language, including the bad ones! :cool:

ww2c: I'd love to help out with this part as it is the fun part for me. Looking further into the API, it seems that you should be able to use WorldBuilder to set tundra/ice as "origional" in that they'd remain as such during non-winter months. Then the code would leave those alone. I'll see if I can get that to work as I'm guessing you'd like some parts to be permanently ice/tundra.

The random/gradual change really depends on what effect you want and how long your turns are. For month-long turns, gradual change may not be desirable. As well, should some tiles below a certain latitude not freeze over? Again, all very doable but possibly not wanted from a game-design standpoint.

Let me know as it sounds like you have two of us that would enjoy that aspect. :)

ww2commander
Mar 19, 2007, 12:04 AM
I am not 100% sure on the actual climate change in the Eastern Front, but didn't almost all of Russia freeze over during the heavy winter months from Murmansk (sp)down to the Caucasus? Was there any areas that were not affected by snow?

The annoying thing is that last night I finished the terrain features for Norway, Sweden, Finland and all area of Russia above Leningrad/Kirov :( and did not inlcude any snor or tundra. Personally I am not fussed with a completely white or green map.

The most pressing question for now is what should I start after the map.....I am not sure if I should do the tech-tree, units or city buildings. Based on any personal experiences, which elements should I focus on and in which order.

I figured the following order would work best:
1. Map
2. Terrain bonus, including value modifications
3. Civ specific traits, perosnality and diplomacy
4. Tech-tree
5. Civics and religion
5. Buildings in cities
6. Culture values (personally I want to focus as little as possible on this area as cities will be changing hands quite often and culture didnt play a huge role on the Eastern Front.....I am open to a change of mind if this is not the case).
7. Units and placement
8. Events/Python
9. Presentation (pedia) and polish!

Also, how do you take screenshots in-game?

ww2commander
Mar 19, 2007, 03:45 AM
I just tried the code provided and it seemed to work perfectly.....except.....damn there is always an except. :(

1.) It took around 8 mins to convert my map x:105, y:95. :eek: Is this an acceptable time to wait for a map to convert between seasons? Keep in mind that I dont have any units on the map yet.


2.) Tundra did not look good for representing plains so I was thinking of just using snow for everything. Only problem is how do I keep a track of the plain and grassland tiles once they all get converted to snow in order to revert back to spring/summer? Will this further affect performance?

Paasky
Mar 19, 2007, 06:48 AM
I usually do the XML first, then the map, then starts the loong process of bugfixing, balancing & graphics.

Screenshots are done in the same way they're done in anything: Press Print Screen (should be next to scroll lock & pause) and then paste it to any image program, like paint or photoshop. Although, civ4 has it's own screenshot tool, but I find that harder to use.

That map is pretty big... I think mine is 62x48 or something. Mainly because I want to keep the 'Fast' part of my mod ;) But 8 mins!? What are your PC specs? Send the mod to me, I'll see how long it takes on my fairly high-end PC (Sempron 3000+, 1gb ram, radeon x1600).

You can keep track, it will just create a new huge variable. I don't know if you can save it into a savegame with sdToolKit, so you might want to get all data from your map, then try to output it somehow, and copy-paste into def onGameStart & def onGameLoad.

EmperorFool
Mar 19, 2007, 07:42 AM
I put together a test and ran it against a standard size map (84 x 52). It takes roughly 20 seconds on my Athlon 2800XP 2GB RAM box.

The culprit is definitely rebuilding the graphics. The second "True" argument to the setTerrainType() call tells the engine whether or not to rebuild the graphics for the changed plot. If you pass in "False", the whole thing is barely noticeable beyond the standard between-turn time.

Possibly -- though I haven't found it yet -- there's a way to tell the entire map to rebuild its graphics at the end. Usually with operations like this, especially since adjacent plots blend into each other, doing it once for all plots is faster than for each plot individually. If it weren't faster, loading any saved game for you should take 8 minutes. I doubt that's the case!

Anyway, I also modified mine to change both grass and plains to snow and store the original type for the thaw using setScriptData() as I mentioned above. It works great, and an added bonus is that you can have snow tiles on the original map that remain snow year-round if you want (as long as the game starts during non-winter). As well, it works across saves.

Put this part in the __init__ method of your custom event manager:

self.TERRAIN_GRASS_DATA = "G"
self.TERRAIN_PLAINS_DATA = "P"

self.TERRAIN_GRASS = gc.getInfoTypeForString("TERRAIN_GRASS")
self.TERRAIN_PLAINS = gc.getInfoTypeForString("TERRAIN_PLAINS")
self.TERRAIN_SNOW = gc.getInfoTypeForString("TERRAIN_SNOW")
self.TERRAIN_TUNDRA = gc.getInfoTypeForString("TERRAIN_TUNDRA")

And here's the onBeginGameTurn method:

def onBeginGameTurn(self, argsList):
'Called at the beginning of each turn'
iGameTurn = argsList[0]
szMessage = "Game Turn %d" %(iGameTurn)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

bFreeze = False
if iGameTurn % 2 == 0:
szMessage = "Winter Freeze"
bFreeze = True
else:
szMessage = "Spring Thaw"
bFreeze = False

iGrass = 0
iPlains = 0
map = CyMap()
szMessage += " / Map: %d x %d" %(map.getGridWidth(), map.getGridHeight())
for y in range(map.getGridHeight()):
for x in range(map.getGridWidth()):
plot = map.plot(x, y)
iTerrainType = plot.getTerrainType()
if bFreeze:
if iTerrainType == self.TERRAIN_GRASS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_GRASS_DATA)
iGrass += 1
elif iTerrainType == self.TERRAIN_PLAINS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_PLAINS_DATA)
iPlains += 1
else:
if iTerrainType == self.TERRAIN_SNOW:
szData = plot.getScriptData()
if szData == self.TERRAIN_GRASS_DATA:
plot.setTerrainType(self.TERRAIN_GRASS, True, True)
iGrass += 1
elif szData == self.TERRAIN_PLAINS_DATA:
plot.setTerrainType(self.TERRAIN_PLAINS, True, True)
iPlains += 1

szMessage += " / Grass: %d / Plains: %d" %(iGrass, iPlains)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

return 1

Note that I have mine doing the operation each turn for testing.

Paasky
Mar 19, 2007, 08:31 AM
Hmm... I had a problem with __init__. If I even added it (without any code) tha game would give a million errors. http://forums.civfanatics.com/showthread.php?t=211289

Also, seeing as you know more of the inner workings of python than me:
I followed the code here: http://forums.civfanatics.com/showthread.php?t=183126 but know I have a problem. Civ says that File "CvWWIIsfnbEvents", line 43, in ?
Attribute Error: 'module' object has no attribute 'CvEventManager'

The code worked fine before. Also, when I commented out everyhting I had changed from wwii events, it still gave the same error. Which means that ScreensInterface.py has something I've done wrong or forgotten to add.

I have attached the edited python files here, if you want to recreate the error just replace my mods python with those, and start the mod.

EmperorFool
Mar 19, 2007, 09:21 AM
I think I see what's happening here. Basically, __init__ is a special function called a constructor. Whenever you create (construct) a new object, it is called to initialize its state. When you have a class that extends (subclasses) another class, your constructor should call the parent class's constructor first. This is called constructor chaining.

For example, a Car is a subclass of WheeledVehicle. WheeledVehicles have X number of wheels, while Cars all have 4 wheels but add a "model" and "year". Thus, WheeledVehicle's constructor takes "numWheels" and Car's takes "model" and "year". Car first tells the parent class that it has 4 wheels.


class WheeledVehicle:

def __init__(self, numWheels):
self.numWheels = numWheels

class Car (WheeledVehicle):

def __init__(self, model, year):

WheeledVehicle.__init__(self, 4)
self.model = model
self.year = year

The error you're getting in the linked post is caused by the fact that your subclass of CvEventManager doesn't call its parent constructor. Therefore, there is no EventHandlerMap. As per my example, it would be like telling the Car to drive but it would fail because WheeledVehicle was never told how many wheels it has. Does that make sense?

The following should fix it.

class CvWWIIsfnbEvents(CvEventManager.CvEventManager):
def __init__(self):
CvEventManager.CvEventManager.__init__(self)

You could then move the code that sets up the sectorX and sectorXweek maps to this new function.

Now, the error message directly above about not finding CvEventManager in the module ... looking at the code you attached it should see it. Try the above and see if it's fixed. :)

Paasky
Mar 19, 2007, 04:41 PM
The __init__ worked.

But I still get the module error. I renamed CvScreensInterface.py & it loads the game fine now. But I'm sure it needs to work in order to make the nifty events to work.

I'm sorry, but this goes waay above my understanding of coding. Before civ4, my most complicated project was a very small managment game in Basic. So yeah...

EmperorFool
Mar 19, 2007, 05:44 PM
I think I have it working. At least, I get free units when the game starts.

First, I renamed CvScreensInterface.py as you did so it is ignored. Second, I removed the lines that were creating the default CvEventManager in CvEventInterface.py. You want your EMgr to replace the original.

import CvUtil
# import CvEventManager <--
import CvWWIIsfnbEvents

#WWII SF&B OVERRIDE
wwiisfnbEventManager = CvWWIIsfnbEvents.CvWWIIsfnbEvents()
# normalEventManager = CvEventManager.CvEventManager() <--

I get no errors in the logs when I start the app or a new game, but let me know if that works for you.

On a side note, I can't fully test because no matter in which PublicMaps folder (mods\sfnb, warlords, cIV, my games) I put your map, I can't find how to use it (play scenario, custom scenario, custom game, play now). What am I missing?

Paasky
Mar 19, 2007, 06:03 PM
It friggin works now! YaY!

You extract the contents of the .rar into ...\civ4\warlords\mods\wwii europe\
Then load the wwii europe mod. The scenario needs that mod to work ;) Also, the python I've uploaded requires a few xml changes as well.




EDIT: No it doesn't. Crashed on initializing the map. And because I forgot to pre-select civ4.exe from the taskmanager, I had to reset.

EDIT2: As I presumed, the __init__ was the culprit. I removed that & the game loaded. The good news is that the CvScreensInterface.py works now, although it gave errors, they were completely understandable & mainly due to my sloppiness.

EmperorFool
Mar 19, 2007, 06:54 PM
You extract the contents of the .rar into ...\civ4\warlords\mods\wwii europe\
Then load the wwii europe mod.

Yup, that's exactly what I did. No matter how I start a game from there, I can't see an option to use your map. :( The mod loads just fine, though.

In the end, does it work for you? If I start a normal game using Fractal map, it all starts up and I get the free units with no errors. What are you getting?

I also put the CvScreensInterface.py file with no problems. That doesn't make sense because the popupmany() function references an unknown function CvWWIIsfnbEvents.eventlist(), but maybe it's okay because popupmany() doesn't get called yet.

ww2commander
Mar 19, 2007, 08:05 PM
Im at work right now so I cant check any of the coding suggestions but in relation to my specs I think I have a high end PC (Dual Core 3.4, 2gb RAM, 512mb 7600GS).

I personally dont mind waiting 8 mins for terrain to change but I want to make sure this is acceptable for others if ever released.....I have heard of people waiting up to 15mins to play turns on some scenarios!

I will try and provide a stripped version of the map (no intro music/video) for you tonight.

Paasky
Mar 19, 2007, 09:31 PM
I also put the CvScreensInterface.py file with no problems. That doesn't make sense because the popupmany() function references an unknown function CvWWIIsfnbEvents.eventlist(), but maybe it's okay because popupmany() doesn't get called yet.

Yes, I bumped into this. Once I selected one of the options from the messagebox (ingame), I got this error:
File "CvScreensInterface", line 728 in popupmany
AttributeError: 'module' object has no attribute 'eventlist'

Line 728 is, surprise surprise, CvWWIIsfnbEvents.eventlist(iData1)

Please please tell me how to fix it. I tried to add wwiisfnbEventManager = CvWWIIsfnbEvents.CvWWIIsfnbEvents() into the top, but that gave the old Attribute Error: 'module' object has no attribute 'WWIIsfnbEvents' on load.

I mean, come on! I've already imported my eventmanager, why won't the stupid game accept that I want to simply send one little piece of info into that other .py file!!!


That map-loading is strange... Have you tried opening the wbs directly into civ? It should load the mod & skip the menu, and give you the civlist.


Sorry to hijack the thread commander, but hey, these might come useful for you too ;)

ww2commander
Mar 19, 2007, 09:37 PM
Quick question.....

I just posted on the unit request thread for anyone to make a Karl or Dora seige gun. Assuming this is fulfilled by someone, is there a way to limit a unit to specific terrain tiles that contain railroad tracks...or any other way that would make it realistic???

The Karl Mortar had tracks but the Dora was on rails.

ww2commander
Mar 19, 2007, 09:40 PM
Paasky, the map loads very fast when starting. The waiting period is on the specified turn that the terrain needs to be changed to winter. I am willing to sacrifice speed if it means the scenario is more fun with seasons cause then I could represent the Russian rasputitsa (winter) and weaken the German units and provide terrain bonus to the russian units. Atleast thats how I evisioned it.

EmperorFool
Mar 19, 2007, 09:57 PM
Paasky: That first error message is telling you that the module CvWWIIsfnbEvents does not contain a top-level function named eventlist. A module (file) can define functions *and* classes that contain functions themselves.

# MyModule.py
import ...

def baz():
...

class Foo:
def bar():
...

The above allows calls from another module like these:

import MyModule

def myFunction():
1 MyModule.baz()
2 foo = MyModule.Foo()
3 foo.bar()

Line 1 calls the top-level function baz(). Line 2 creates an object of the Foo class. Line 3 calls the function bar() on the object just created.

What I think you're trying to do is call the function eventlist() on your event manager, but there is no function eventlist() in either the module or the class AFAICT. If the class had such a function, your code should look like this:

if iButtonId == 0:
CvEventManager.getEventManager().eventlist(iData1)

If instead you really are trying to call the function eventlist() defined in the CvWWIIsfnbEvents module, then CvWWIIsfnbEvents.py needs this:

...
sdSetGlobal = sdToolKit.sdSetGlobal
sdDelGlobal = sdToolKit.sdDelGlobal

def eventlist():
... code here ...

class CvWWIIsfnbEvents(CvEventManager.CvEventManager):
...

If you could explain what you want to happen, maybe I can help you figure out which way it should be. Either way, the definition of the eventlist() function is missing entirely. I checked CvEventManager to make sure it wasn't inherited, and it didn't define it either. Where is this function defined?

ww2c: You do mean 8 minutes as in go make yourself a sandwich, right? Not 8 seconds as in not enough time to go grab a soda? You're machine is definitely more powerful than mine, so there's something else going on.

Can you attach the file that has this code? It sounds like the code is being called many times instead of just once. 100x100 isn't significantly bigger than the standard map size I tried. Not nearly enough to turn 20 seconds into 8 minutes.

Try one thing for me: set the third parameter (second True) to False in all the setTerrainType() calls. This will alter the terrain without rebuilding the graphics. If this still takes a long time, it would seem that I'm right and it's being called many times.

ww2commander
Mar 19, 2007, 10:58 PM
It was around 8 mins.....I could have misjudged it as the game clock froze and I had to look at my watch instead.

The only thing that would differentiate our tests that I can think of is my map has 5 civs and around approx. 200 cities. No units yet.

I figured it must just be a case of it having to compare each tile in the code. I cant remember the area I put it in right now but I am certain it was onBegin Turn.

Will check tonight when I get home.

EDIT: One thing came to mind....I included a new terrain type called 'marsh' which remains untouched by the code. Could it have issues when hitting these tiles as the API values used dont consider it?

explorer2
Mar 19, 2007, 11:02 PM
You guys seem to be doing a monumental work here.
Have you checked out the Barbarossa scenario from Civ3. It was outstanding also.

Adding winter is crucial to Russian campaign.
AND supply lines!!! (Never been done that I know of)
The whole reason Germans did as well as they did is they were able to surround massive groups of Russians who surrendered knowing they were cut off from supplies. Without being able to simulate this in some way, there's no tactical accuracy to any scenario, and that has been my number one complaint to Firaxis of all the Civ versions.

You guys seem to be creative and talented (I may be the first, but certainly not the last). Do you think there's any way to add this? It would TOTALLY change tactics and accuracy of the game.

EmperorFool
Mar 19, 2007, 11:24 PM
It's just an educated guess, but I don't see that adding a new terrain type could affect the time noticeably. Perhaps 200 cities could, as it probably rebuilds the graphics for any cities near affected tiles, but again just a guess.

That's why I want to see what difference disabling the graphics updates makes (see my previous post). The first step is to eliminate that as the culprit, but I think it is said culprit.

All of the logic of the process is very simple and should execute very quickly. Comparing two integer values takes negligible time, and so does iterating over 10,000 such values. Rebuilding the graphics (specifying textures, calculating blends, replacing where all the buildings go, etc) is monumental compared to scanning the plots themselves.

BTW, how long does it take to load a saved game? This should be the baseline time to rebuild the graphics as I doubt the game saves that information. Instead, I suspect it saves only the map terrain info and what buildings exist in each city -- not where it drew those buildings. I'd bet my spleen that is all rebuilt when you load a game. :p

ww2commander
Mar 19, 2007, 11:59 PM
Believe it or not I have yet to try loading a saved game of the map. Everytime I do changes I just double click on the WBS file.

I will also try the load and see. Im expecting that once all the units are on the map the scenario may take up to 15mins to load initially:crazyeye:

explorer - with relation to supplies, I really want to try and atleast get consumable fuel resources working. I know someone was working on a tutorial for this at http://forums.civfanatics.com/showthread.php?t=201247

This way the fuel resources dry up faster during winter and the later was years.

ww2commander
Mar 20, 2007, 01:07 AM
explorer - I just checked out the Civ 3 Barbarossa thread and I have mixed feelings.

On the one hand I am impressed that these guys put so much effort into this scenario....but on the other hand......some of the feedback they received for their efforts seemed harsh and that scares me.

I guess this is one of the reasons I have not made an official announcement of my scenario and have kept it private. If something was to become of it I would be happy to make it available but I feel a small percentage of people need to get over the whole 'the correct spelling in Mongolian is' and 'that unit is in the incorrect location' discussions. I can tell you straight away that my Polish and Finnish cities are spelled in English characters because I do not have a clue how to get those characters in the city names!!

Sometimes I feel people are not grateful for the effort modders put in to their scenarios.

ww2commander
Mar 20, 2007, 04:37 AM
Something is not right anymore :(

I timed the old code Emperor provided and it took 6 mins in game to change the map to winter. I then change the code to the revised '___init___" version and now it sits on the start-up screen stuck on the Initialisation step :confused:

I let it run for about 11 mins and then ctrl+alt+del the game. It seems the init stage is really killing the loading time.

Here is my CustomEventManager.py

from CvPythonExtensions import *
import sys
import Popup as PyPopup
from PyHelpers import PyPlayer
import pickle
import CvEventManager
from CvScreenEnums import *
from PyHelpers import *
import CvUtil
import CvIntroMovieScreen

# globals
gc = CyGlobalContext()
localText = CyTranslator()

DefaultUnitAI = UnitAITypes.NO_UNITAI

class CvRSREvents(CvEventManager.CvEventManager):

def __init__(self, *args, **kwargs):
self.TERRAIN_GRASS_DATA = "G"
self.TERRAIN_PLAINS_DATA = "P"

self.TERRAIN_GRASS = gc.getInfoTypeForString("TERRAIN_GRASS")
self.TERRAIN_PLAINS = gc.getInfoTypeForString("TERRAIN_PLAINS")
self.TERRAIN_SNOW = gc.getInfoTypeForString("TERRAIN_SNOW")
self.TERRAIN_TUNDRA = gc.getInfoTypeForString("TERRAIN_TUNDRA")

def onGameStart(self, argsList):
# display mod's intro movie
introMovie = CvIntroMovieScreen.CvIntroMovieScreen()
introMovie.interfaceScreen()

# display DoM message
for iPlayer in range(gc.getMAX_PLAYERS()):
player = gc.getPlayer(iPlayer)
if (player.isAlive() and player.isHuman()):
popupInfo = CyPopupInfo()
popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON_SCREEN)
popupInfo.setText(u"showDawnOfMan")
popupInfo.addPopup(iPlayer)

def onBeginGameTurn(self, argsList):
'Called at the beginning of each turn'
iGameTurn = argsList[0]
szMessage = "Game Turn %d" %(iGameTurn)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

bFreeze = False
if iGameTurn % 2 == 0:
szMessage = "Winter Freeze"
bFreeze = True
else:
szMessage = "Spring Thaw"
bFreeze = False

iGrass = 0
iPlains = 0
map = CyMap()
szMessage += " / Map: %d x %d" %(map.getGridWidth(), map.getGridHeight())
for y in range(map.getGridHeight()):
for x in range(map.getGridWidth()):
plot = map.plot(x, y)
iTerrainType = plot.getTerrainType()
if bFreeze:
if iTerrainType == self.TERRAIN_GRASS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_GRASS_DATA)
iGrass += 1
elif iTerrainType == self.TERRAIN_PLAINS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_PLAINS_DATA)
iPlains += 1
else:
if iTerrainType == self.TERRAIN_SNOW:
szData = plot.getScriptData()
if szData == self.TERRAIN_GRASS_DATA:
plot.setTerrainType(self.TERRAIN_GRASS, True, True)
iGrass += 1
elif szData == self.TERRAIN_PLAINS_DATA:
plot.setTerrainType(self.TERRAIN_PLAINS, True, True)
iPlains += 1

szMessage += " / Grass: %d / Plains: %d" %(iGrass, iPlains)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

return 1

The OnGameStart is only loading a intro video and when I took out all 'season' code the map took 15secs to load.

I will let it do a complete run thru on the load and see roughly how long it takes.:(

ww2commander
Mar 20, 2007, 05:10 AM
I found out that all the extra stuff being defined first is causing the delay with the new code. I took it out and it loaded immediately. I had left this stuff from a cut/paste of an old event file I had tried to start way back and gave up.

Obviously I dont have a clue what I am doing.:confused:

Just to let you know that the new code is still not working. I am using months so I am not sure if this is the cause. I noticed that some messages are supposed to appear somewhere but I cant see anything on screen. Damn it feels bad being a newb to this coding stuff:blush:

EmperorFool
Mar 20, 2007, 05:51 AM
Don't worry about not getting it right away -- or even after a lot of effort. Coding is not simple, and object-oriented programming takes a whole different shift in thinking for wihch there really is no immediate real-world equivalent. That's why all the examples like mine above with the Car and WheeledVehicle seem so contrived. ;)

One immediate problem I see is that you're missing the first line in your __init__ function that tells CvEventManager to initialize itself. Here's how your class definition should start:

class CvRSREvents(CvEventManager.CvEventManager):

def __init__(self): # remove ", *args, **kwargs"
CvEventManager.CvEventManager.__init__(self) # add this line

self.TERRAIN_GRASS_DATA = "G"
self.TERRAIN_PLAINS_DATA = "P"
...

Can you post your CvEventsInterface.py as well? Also, it helps to wrap your code in [ CODE ] blocks when posting so that the indentation is maintained.

There's something else I just realized: just like with __init__() you should call the base CvEventManager events unless you are replacing their behavior.

For example, onGameStart() displays the Dawn of Man screen. It also does some PBEM checks and calls setSoundSelectionReady(). If you want these to happen, you should make similar calls as above:

def onGameStart(self, argsList):
CvEventManager.CvEventManager.onGameStart(self, argsList)
# display mod's intro movie
...

If you want to only have part of the original function happen, then copy the part you want and do not call the original function.

To learn more about these concepts, Google "inheritence" and "oop" and "override function".

ww2commander
Mar 20, 2007, 06:01 AM
:wallbash: Cache :wallbash: Cache :wallbash: Cache

I am a complete and utter idiot. Damn I wasted 2 hours troubleshooting and then realised I needed to clear the cache :[pissed]

Ok, code works fine in that I can see the turn marker and spring thaw/winter freeze msg....but the terrain is not changing. I will fiddle more with it. Hopefully others will find this thread useful when it comes to both learning python and terrain related changes to scenarios.

EmperorFool
Mar 20, 2007, 06:20 AM
Okay, I split out my changes from the CustomAssets I had (Ruff Hi's CSG mod) and created a mod of my own for isolated testing. It contains two files only.

CvEventInterface.py:

from CvPythonExtensions import *
import WinterEventManager

eventManager = WinterEventManager.WinterEventManager()

def getEventManager():
return eventManager

def onEvent(argsList):
'Called when a game event happens - return 1 if the event was consumed'
return getEventManager().handleEvent(argsList)

def applyEvent(argsList):
context, playerID, netUserData, popupReturn = argsList
return getEventManager().applyEvent(argsList)

def beginEvent(context, argsList=-1):
return getEventManager().beginEvent(context, argsList)


WinterEventManager.py:

##-------------------------------------------------------------------
## Tests winter freeze global map change
##-------------------------------------------------------------------

from CvPythonExtensions import *
import CvEventManager

gc = CyGlobalContext()

class WinterEventManager(CvEventManager.CvEventManager):

def __init__(self):
CvEventManager.CvEventManager.__init__(self)

self.TERRAIN_GRASS_DATA = "G"
self.TERRAIN_PLAINS_DATA = "P"

self.TERRAIN_GRASS = gc.getInfoTypeForString("TERRAIN_GRASS")
self.TERRAIN_PLAINS = gc.getInfoTypeForString("TERRAIN_PLAINS")
self.TERRAIN_SNOW = gc.getInfoTypeForString("TERRAIN_SNOW")
self.TERRAIN_TUNDRA = gc.getInfoTypeForString("TERRAIN_TUNDRA")

def onBeginGameTurn(self, argsList):
CvEventManager.CvEventManager.onBeginGameTurn(self , argsList)

'Called at the beginning of each turn'
iGameTurn = argsList[0]
szMessage = "Game Turn %d" %(iGameTurn)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

if iGameTurn == 0:
# start in spring -- no need to thaw
return

bFreeze = False
iQuarter = iGameTurn % 4
if iQuarter == 3:
szMessage = "Winter Freeze"
bFreeze = True
elif iQuarter == 0:
szMessage = "Spring Thaw"
bFreeze = False
else:
return

iGrass = 0
iPlains = 0
map = CyMap()
szMessage += " / Map: %d x %d" %(map.getGridWidth(), map.getGridHeight())
for y in range(map.getGridHeight()):
for x in range(map.getGridWidth()):
plot = map.plot(x, y)
iTerrainType = plot.getTerrainType()
if bFreeze:
if iTerrainType == self.TERRAIN_GRASS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_GRASS_DATA)
iGrass += 1
elif iTerrainType == self.TERRAIN_PLAINS:
plot.setTerrainType(self.TERRAIN_SNOW, True, True)
plot.setScriptData(self.TERRAIN_PLAINS_DATA)
iPlains += 1
else:
if iTerrainType == self.TERRAIN_SNOW:
szData = plot.getScriptData()
if szData == self.TERRAIN_GRASS_DATA:
plot.setTerrainType(self.TERRAIN_GRASS, True, True)
iGrass += 1
elif szData == self.TERRAIN_PLAINS_DATA:
plot.setTerrainType(self.TERRAIN_PLAINS, True, True)
iPlains += 1

szMessage += " / Grass: %d / Plains: %d" %(iGrass, iPlains)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)


Does that help?

ww2commander
Mar 20, 2007, 06:25 AM
Emperor I gave it one last shot and I cant figure it out so I have attached my events file for you to test out. I cant get the terrain to change and I notice that the grass and plain counters never imcrement.:confused:

I think I will sleep this one out. :(

P.S I also changed the movie code like you suggested. :)

EmperorFool
Mar 20, 2007, 06:26 AM
Ok, code works fine in that I can see the turn marker and spring thaw/winter freeze msg....but the terrain is not changing.

Did you set the third parameter to setTerrainType() to False? One way to "see" the change without the long pause is to select a settler. All the yields on the map will change during freeze/thaw.

Does it tell you more than 0 grass/plains tiles were changed? Does it take longer than normal during freeze/thaw? If so, something is happening. ;)

Edit: From your attachment I see that a) 3rd parameters are True (so you should see change), b) it says 0 plains and 0 grass, and c) it doesn't take longer since no changes occur.

EmperorFool
Mar 20, 2007, 06:42 AM
I don't know what to tell ya. :( I took your file and copied the __init__() and onGameBeginTurn() functions exactly into my WinterEventManager (see above), and it worked just fine.

My only guess now is that the map is somehow interfering, but using getInfoTypeForString should allow your addition of swamp to play nice. Can you attach your map, or PM It to me if you want? Did you have to change much else to add swamp?

Maybe try your version against a standard map (pangea, fractal, continents, or some premade map) to see the difference.

ww2commander
Mar 20, 2007, 06:48 AM
Emperor, It does not take long, even with the last code you posted. I figured out what I had to do so ignore my PM

However, no, the counters never increment. Refer to attached screen shot.

Paasky
Mar 20, 2007, 07:32 AM
Let's see if I've got this right: Every time you use a . in the code, it calls ever deeper into that file?

Like CvWWIIsfnbEvents.eventlist() would call CvWWIIsfnbEvents.py, and def eventlist?

I placed CvWWIIsfnbEvents.CvWWIIsfnbEvents.eventlist(iData1 ) into the line (wouldn't that call the .py file, the class, and then the def inside that class?)
But, I got this error:
TypeError: unbound method eventlist() must be called with CvWWIIsfnbEvents instance as first argument (got int instance instead)
This error came after I had pressed a button, which means that the problem is still in CvScreensInterface.py.

To clarify, here's where my definitions are:
CvWWIIsfnbEvents.py:
43 class CvWWIIsfnbEvents(CvEventManager.CvEventManager):
...
...
844 def eventlist(self, eventnum):
845 if eventnum == 11: ### USSR demands land from Finland
846 pPlayer = gc.getPlayer(3)
847 if pPlayer.isHuman():
848 popupInfo = CyPopupInfo()
849 popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON)
850 popupInfo.setText(CyTranslator().getText("Demand Lands from Finland",()))
851 popupInfo.setData1(12)
852 popupInfo.setOnClickedPythonCallback("popupmany")
853 popupInfo.addPythonButton(CyTranslator().getText("We must demand the land that is rightfully ours! (Demand Viipuri from Finland)", ()), "")
854 popupInfo.addPythonButton(CyTranslator().getText("Rather not, we have more important things to do. (Nothing happens)", ()), "")
855 popupInfo.addPopup(3)
856 else:
857 if not gc.getTeam(pPlayer.getTeam()).isAtWar(0) or gc.getTeam(pPlayer.getTeam()).isAtWar(1) or gc.getTeam(pPlayer.getTeam()).isAtWar(3):
858 eventnum = 12
...

CvScreensInterface.py:

722 def popupmany(argsList):
723 iButtonId = argsList[0]
724 iData1 = argsList[1]
725 iData2 = argsList[2]
726 iData3 = argsList[3]
727 if iButtonId == 0:
728 CvWWIIsfnbEvents.CvWWIIsfnbEvents.eventlist(iData1 )
729 if iButtonId == 1:
730 CvWWIIsfnbEvents.CvWWIIsfnbEvents.eventlist(iData2 )
731 if iButtonId == 2:
732 CvWWIIsfnbEvents.CvWWIIsfnbEvents.eventlist(iData3 )

EmperorFool
Mar 20, 2007, 08:35 AM
Let's see if I've got this right: Every time you use a . in the code, it calls ever deeper into that file?
You're partially correct.
Like CvWWIIsfnbEvents.eventlist() would call CvWWIIsfnbEvents.py, and def eventlist?
This part is correct.
I placed CvWWIIsfnbEvents.CvWWIIsfnbEvents.eventlist(iData1 ) into the line (wouldn't that call the .py file, the class, and then the def inside that class?)
This is where the pattern isn't quite correct. I highly recommend going through the Python tutorial at python.org (or anywhere really) as they'll probably explain it better than I can, but I'll give it a shot.

Each file is called a module, and modules can define classes. Often they are the same name which can be confusing. The CvWWIIsfnbEvents.py file contains the module CvWWIIsfnbEvents which defines the class CvWWIIsfnbEvents. "CvWWIIsfnbEvents.CvWWIIsfnbEvents" references the class definition, but you can't use that to directly access instances of that class.

Instances vs. Classes is the major distinction to get clear. A class defines the data and behavior of something as a general idea. An instance of a class is that idea in actual form. Each class may end up having many instances.

For example, a car is a vehicle with wheels and an engine that you can drive and park and crash. However, "car" just describes the idea. You can't drive "car" to work. You can drive my 1989 blue Chevy Nova with license plate 27CIA281. There is only one single idea of a car (class) yet there are millions of cars (instances) in existence.

Car is the class and Car("27CIA281") is a single instance of that class. That would look like this:

# CarModule.py
class Car:
def __init__(self, license):
self.license = license

def drive(self, driver):
print "%s is driving car %d" %(driver, self.license)

# Drive.py
import CarModule

car = CarModule.Car("27CIA281")
car.drive("Bob")

The drive() function belongs to the class Car, but you need an instance in order to call the function because the "self" argument is the instance.

To bring this back to your code, the CvEventInterface module creates a single instance of your CvWWIIsfnbEvents class when it is first loaded. Then other modules can call CvEventInterface.getEventManager() to access that instance.

Therefore, change popupmany() like this:

def popupmany(argsList):
...
if iButtonId == 0:
CvEventInterface.getEventManager().eventlist(iData 1)
...


Also, make sure CvScreensInterface.py imports CvEventInterface.

I hope that my explaining why helps you instead of just confusing. Object-oriented programming is a tough nut to crack.

Paasky
Mar 20, 2007, 09:42 AM
:lol: I read every sentence two times, very slowly, making sure that I got what it meant. And still the car made my head dizzy :p

But, I think I got the part about my code. So basically the hierarchy is this:
CvEventInterface defines an eventmanager, which is my events.py file (module)
If I want to access that module, I need to call it throught the CvEventInterface's eventmanager.

And the most important thing: It works! I mean it really, really works this time :D

ww2commander
Mar 20, 2007, 04:50 PM
On a side note Paasky....would you mind helping me out with any questions I may have about the Finnish-Soviet front as some of the books I have are pretty light on this subject. Also I may need you to check the names of the cities I have mapped out as I already noticed I spelt Viipuri incorrect on my map. Some of these Atlases do a good job of butchering city names.:lol:

Also your popup code is very very interesting and I will more than likley recycle it for similar purposes in my scenario....if thats Ok with you of course;)

EmperorFool
Mar 20, 2007, 09:03 PM
CvEventInterface defines an eventmanager, which is my events.py file (module)
If I want to access that module, I need to call it throught the CvEventInterface's eventmanager.

You got it exactly. :goodjob:

Paasky
Mar 21, 2007, 12:38 AM
commander: Sure-er-ree. Except I do believe Wikipedia is more edjucated on the subject than I am. I don't really own any history books (just a 1989 school atlas I found in our neighbours recycled paper bin about 10 years ago), and history at school never got past the industrial revolution.
But I do think I know the city names though ;)

Of course you can recycle the popupcode, seeing at it really isn't mine, but I copy-pasted & edited it from the pop-up tutorial ;) But you might want to wait for alpha3, which will have new, working events, a lá Hearts of Iron.

ww2commander
Mar 21, 2007, 02:15 AM
I just got home and I think I will give the season python code a rest for tonite as I dont have a clue what I am doing and hopefully Emperor can figure it out:confused:

I am about to add my first downloaded unit into the game so once again I am venturing into unknown terrain. I have printed off Sovarn's guide so hopefully it should be ok.:goodjob:

ww2commander
Mar 28, 2007, 08:37 AM
Im ressurecting this thread in the hope that someone with enough python experience can figure out a solution to changing the terrain on a map to represent seasons (with speed being the key factor).

This is the most important part of my scenario. The code that Paasky provided on the first page works but it takes up to 11 mins to complete where as the code EmperorFool provided seems to not be working on my custom map and I have but a few hairs left trying to get it to work.

If anyone wants to demonstrate their superior knowledge of python and find a solution to this problem then it would be hugely appreciated.

I gather there must be more that one modder wanting to represent seasons in their scenarios!

EDIT: I am willing to provide my map to those who ask for testing purposes :)

Paasky
Mar 28, 2007, 09:09 AM
Just use the fast code, then add
CyGInterfaceScreen().setForcedRedraw(0)
After it. I don't know if that works (ie redraw's the map, not something different). If it doesn't work, change the 0 into 1. If that still doesn't work, you'll have to try & search something that looks like it could redraw the map from http://civilization4.net/files/modding/PythonAPI/

How that works:
180. VOID setForcedRedraw(BOOL bRequiresForcedRedraw)
180 = just a number, but you have to use CyGInterfaceScreen(). as it is the 180th thingy under CyGInterfaceScreen.
VOID = this sets something, or makes something happen. You can only use these if you want something to happen.
BOOL = This can be 1 or 0. Or true/false.


Guru's are free to correct me ;)

ww2commander
Mar 28, 2007, 06:28 PM
I am at work right now so I cant do much but just to let you know I tried almost everything under the sun to get EmperorFool's code to actually change the terrain.

I changed his getInfoTypeForString(Terrain_name) entries by commenting them out and replacing them with the actual terrain values which kind of got the code working but the actual 'for' statements never seem to do anything. I then tried to 'reverse engineer' the codee by removing sections bit by bit but that just caused me more problems to the point where I was achieving nothing.

There must be an issue with the number of cities on the map for it to take so long to load!

It is very fustrating trying to figure out how to get it to work, especially since I dont have a clue how to program python and 'mimic' other peoples code in examples :(

ww2commander
Mar 30, 2007, 08:03 AM
This is a last desperate cry for assistance on this code before I let this thread die in honour. Please if anyone who has the knowledge can provide input then it would be very helpful. :help:...:please:

ww2commander
Apr 15, 2007, 01:59 AM
I am raising this thread from the dead because I need someone who is experienced with python to figure out if it is possible to do this based on recent feedback I have received from Paasky and EmperorFool.

Currently I have the latest code below which converts grass/plain tiles to snow/tundra. The problem is that the code redraws features, rivers, resources and graphics incorrectly.

from CvPythonExtensions import *
import CvScreensInterface
import PyHelpers
import Popup as PyPopup
import CvTopCivs
import sys
import CvAdvisorUtils
import CvEventManager
import string
import CvUtil
import CvIntroMovieScreen

# globals
gc = CyGlobalContext()
localText = CyTranslator()

DefaultUnitAI = UnitAITypes.NO_UNITAI

class CvRSREvents(CvEventManager.CvEventManager):

def __init__(self):
CvEventManager.CvEventManager.__init__(self)
self.TERRAIN_GRASS_DATA = "G"
self.TERRAIN_PLAINS_DATA = "P"

#def onGameStart(self, argsList):
#display mod's intro movie
#introMovie = CvIntroMovieScreen.CvIntroMovieScreen()
#introMovie.interfaceScreen()

#display DoM message
#for iPlayer in range(gc.getMAX_PLAYERS()):
# player = gc.getPlayer(iPlayer)
# if (player.isAlive() and player.isHuman()):
# popupInfo = CyPopupInfo()
# popupInfo.setButtonPopupType(ButtonPopupTypes.BUTT ONPOPUP_PYTHON_SCREEN)
# popupInfo.setText(u"showDawnOfMan")
# popupInfo.addPopup(iPlayer)

def onBeginGameTurn(self, argsList):
CvEventManager.CvEventManager.onBeginGameTurn(self , argsList)

'Called at the beginning of each turn'
iGameTurn = argsList[0]
szMessage = "Game Turn %d" %(iGameTurn)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

if iGameTurn == 0:
# start in spring -- no need to thaw
return

bFreeze = False
iQuarter = iGameTurn % 4
if iQuarter == 3:
szMessage = "Winter Freeze"
bFreeze = True
elif iQuarter == 0:
szMessage = "Spring Thaw"
bFreeze = False
else:
return

iGrass = 0
iPlains = 0
map = CyMap()
szMessage += " / Map: %d x %d" %(map.getGridWidth(), map.getGridHeight())
for y in range(map.getGridHeight()):
for x in range(map.getGridWidth()):
plot = CyMap().plot(x,y)
iTerrainType = plot.getTerrainType()
if bFreeze:
if plot.getTerrainType() == 0:
plot.setTerrainType(4, True, False)
plot.setScriptData(self.TERRAIN_GRASS_DATA)
iGrass += 1
elif plot.getTerrainType() == 1:
plot.setTerrainType(4, True, False)
plot.setScriptData(self.TERRAIN_PLAINS_DATA)
iPlains += 1
else:
if plot.getTerrainType(4):
szData = plot.getScriptData()
if szData == self.TERRAIN_GRASS_DATA:
plot.setTerrainType(0, True, False)
iGrass += 1
elif szData == self.TERRAIN_PLAINS_DATA:
plot.setTerrainType(1, True, False)
iPlains += 1
CyMap().regenerateGameElements()

szMessage += " / Grass: %d / Plains: %d" %(iGrass, iPlains)
CyInterface().addMessage(CyGame().getActivePlayer( ), True, 10, szMessage, "", 2, None, ColorTypes(8), 0, 0, False, False)

I have attached a screenshot of the results when running this code to get an indication of the problem. It seems that the CyMap().regenerateGameElements() is killing all the features and not redrawing the map properly.

The river circled was not there before regeneration, all trees have been stripped off the map, the circled resource is newly placed, the terrain graphic is not drawn as obvious by the sharp line between white and green and on the minimap there are patches of grass still left after running the code.

http://forums.civfanatics.com/uploads/34965/test.JPG

If someone can please help out in making this code successfully change grass/plains to snow/tundra and keep the features and resources unaffected then it would help out in a huge way towards my scenario which needs to represent seasons.

I beg that someone who has the know how have a look and help out please

:please: :please: :please:

Paasky
Apr 15, 2007, 10:31 AM
Note: The reason it uses CyMap().regenerateGameElements() is because re-drawing every tile and it's neighbours takes about 8 minutes. If anyone knows a better python code for redrawing the map (terrain only even?) please share.

Btw, ww2commander, have you checked with the mouseinfo (mouse over terrain, bottom-left textbox) if the terrain is grass, or just looks like it? Same thing with the new resources & rivers.

ww2commander
Apr 15, 2007, 05:43 PM
Damn...never crossed my mind to check that. Will do when I get home.

I tried several other CyMapGenerator functions and so on (I admit my total lack of understanding of these functions) and they did nothing. I also tried to set the bRebuildGraphics value to True for all SetTerrainType lines and that just made the processing time horrendous.

From a logic point of view, if regenerateGameElements is the only way to refresh the map then the code would also need to store all features, resources and river info for each plot before it redraws the map in order to place them in the correct location again....is this a correct assumption?

I figure I am the only one who is actually trying to implement a season engine into a scenario cause I have yet to come across terrain changes on such a large scale.

Paasky
Apr 15, 2007, 11:33 PM
Mine does have a working season, for about ½ the map. But I've manually stored all the plots beforehand.

AFAIK, a python function needs to be a VOID for it to be able to do anything. INT's, BOOL's, etc can only be used in if bUnitHasMoved = true: things. Someone correct me if I'm wrong?

Dale
Apr 16, 2007, 07:00 AM
I got this working in a mod of mine using SDK by the following code (note, I change an area of the map to winter, not the lot):

Python file:

def doBitterWinter(self, value):
# Send off to do Bitter Winter
game.setBitterWinter(value)


CyGame.h

void setBitterWinter(bool bValue);


CyGame.cpp

void CyGame::setBitterWinter(bool bValue)
{
if(m_pGame)
{
m_pGame->setBitterWinter(bValue);
}
}


CyGameInterface.cpp

.def("setBitterWinter", &CyGame::setBitterWinter)


CvGame.h

public:
DllExport void setBitterWinter(bool bValue);
protected:
int m_iBitterWinter;


CvGame.cpp

void CvGame::setBitterWinter(bool value)
{
int count1, count2;
CvPlot* pPlot;
if(value)
{
m_iBitterWinter++;
for(count1 = 60; count1 < GC.getMapINLINE().getGridWidthINLINE(); count1++)
{
for(count2 = (GC.getMapINLINE().getGridHeightINLINE() - (m_iBitterWinter * 10)); count2 < (GC.getMapINLINE().getGridHeightINLINE() - ((m_iBitterWinter - 1) * 10)); count2++)
{
pPlot = GC.getMapINLINE().plotINLINE(count1, count2);
if (count2 > 46)
{
if (pPlot->getTerrainType() == 0 || pPlot->getTerrainType() == 1 || pPlot->getTerrainType() == 3 || pPlot->getTerrainType() == 7 || pPlot->getTerrainType() == 8)
{
pPlot->setTerrainType((TerrainTypes)(pPlot->getTerrainType() + 9), true, true);
}
if (pPlot->getFeatureType() == 4)
{
pPlot->setFeatureType((FeatureTypes)11, pPlot->getFeatureVariety());
}
}
if (count2 <= 46 && count1 >= (60 + (46 - count2)))
{
if (pPlot->getTerrainType() == 0 || pPlot->getTerrainType() == 1 || pPlot->getTerrainType() == 3 || pPlot->getTerrainType() == 7 || pPlot->getTerrainType() == 8)
{
pPlot->setTerrainType((TerrainTypes)(pPlot->getTerrainType() + 9), true, true);
}
if (pPlot->getFeatureType() == 4)
{
pPlot->setFeatureType((FeatureTypes)11, pPlot->getFeatureVariety());
}
}
}
}
} else {
if(m_iBitterWinter == 0)
{
return;
}
for(count1 = 60; count1 < GC.getMapINLINE().getGridWidthINLINE(); count1++)
{
for(count2 = (GC.getMapINLINE().getGridHeightINLINE() - (m_iBitterWinter * 10)); count2 < (GC.getMapINLINE().getGridHeightINLINE() - ((m_iBitterWinter - 1) * 10)); count2++)
{
if (count2 > 46)
{
pPlot = GC.getMapINLINE().plotINLINE(count1, count2);
if (pPlot->getTerrainType() == 9 || pPlot->getTerrainType() == 10 || pPlot->getTerrainType() == 12 || pPlot->getTerrainType() == 16 || pPlot->getTerrainType() == 17)
{
pPlot->setTerrainType((TerrainTypes)(pPlot->getTerrainType() - 9), true, true);
}
if (pPlot->getFeatureType() == 11)
{
pPlot->setFeatureType((FeatureTypes)4, pPlot->getFeatureVariety());
}
}
if (count2 <= 46 && count1 >= (60 + (46 - count2)))
{
pPlot = GC.getMapINLINE().plotINLINE(count1, count2);
if (pPlot->getTerrainType() == 9 || pPlot->getTerrainType() == 10 || pPlot->getTerrainType() == 12 || pPlot->getTerrainType() == 16 || pPlot->getTerrainType() == 17)
{
pPlot->setTerrainType((TerrainTypes)(pPlot->getTerrainType() - 9), true, true);
}
if (pPlot->getFeatureType() == 11)
{
pPlot->setFeatureType((FeatureTypes)4, pPlot->getFeatureVariety());
}
}
}
}
m_iBitterWinter--;
if(m_iBitterWinter < 0)
{
m_iBitterWinter = 0;
}
}
}


And finally initialise the game variable (also in CvGame.cpp)

// FUNCTION: reset()
// Initializes data members that are serialized.
void CvGame::reset(HandicapTypes eHandicap, bool bConstructorCall)
{
int iI;

//--------------------------------
// Uninit class
uninit();

m_iBitterWinter = 0;
...
...
...


Hope that heads you in the right direction. :)

PS: This code can change half a large map in about 1.5 mins.

PPS: You need to create new terrains and redirect the terrains graphics to the snow graphics. In terrain.xml it is important your winter terrains are in the SAME ORDER as the initial terrains or it won't switch correctly. Also setup new forests for each type of forest pointing them to the snow forest graphics.

PPPS: This code as written will cause winter to come south 10 plots per turn. As this occurs m_iBetterWinter increases so the code knows how many times to decrease winter in spring.

ww2commander
Apr 16, 2007, 07:07 AM
I did some testing and found out that the half green/half white bits are redraw issues as I saved the game and then went back in and it drew the snow correctly. The terrain type when you hover over it says 'ice' which is the snow terrain. I even went in to the world builder and tried to place ice over the green bits but it did not change as it already was that terrain type.

Thus I can conclude that the first issue is a redraw problem. The issue still remains in that the rivers and forests are wiped off the map after regenerating.

I seem to get a lot of views on this post but no one except Paasky and EmperorFool have suggested anything.....I would have thought there would be more people willing to step up and show their knowledge considering the high standard of existing mods :(

EDIT: Thanks for helping out Dale. I saw your post after replying....I am sorry to all if I come across a bit flustered as this problem is becoming a thorn in the side of my project :(

ww2commander
Apr 16, 2007, 07:18 AM
Dale,

Unfortunately I am not familiar with SDK modding yet. I am still struggling to understand python (I am embarressed to admit I suck at coding :cry: ). Is it possible if you can test my map with your code and see what you get?

Thanks for the feedback :)

Dale
Apr 16, 2007, 09:18 AM
BTW just so you're aware, the blending between tiles actually passes halfway into the neighbor. That's why redraw does the tile and all neighbors. This is what is giving you the half white/green. And yes, a redraw should change the hard lines with more natural lines.

As for my code, I am pressed for time but I can see what I can do. I'm pretty much booked solid for the next 3 months, but I'll see if I can slip it in in the next week.

EmperorFool
Apr 16, 2007, 01:09 PM
First, regenerateGameElements() is a map generator function to wipe the map of bonuses and rivers and regenerate them. It may even wipe cities and units, but I don't recall from reading it. You need to rebuild the graphics from the game elements, so this is not the function you want.

I read over Dale's code, and as far as I can tell it does the same thing as what we had before but in C++ instead of Python. All calls to change a plot's terrain type pass in "true" for the "rebuildGraphics" parameter. This seems a safe assumption as there's no call at the end to rebuild graphics for the whole map.

In short, it's faster because it does 10 lines of plots each time, but it suffers from the same problem as what we have so far.

ww2c, you may just be SOL on this one and have to accept long run times. I suspect that the reason people aren't responding is that there is no way around it. The best I can think of is if there's a C++ (SDK) function to do this, but you'll then need to do SDK coding and people can't use BetterAI.

You've got a few options I can see:

1. Leave it as-is (slow)
2. Precalculate winter tiles (minor improvement)
3. Use progressive winter (like Paasky and Dale's code)

The third option -- while the most "difficult" to implement -- is the only one that's going to gain you anything significant. Yes, the code is trickier, but I'd be glad to help you out at that point. You could also use Paasky's code as-is by changing the plot numbers.

That's usually the case with coding (and life): more work up front for a bigger payoff later. :)

Dale
Apr 16, 2007, 02:34 PM
To change an entire map in one hit is going to be a very intensive process on the CPU. Not only is it changing some data, but loading new graphics for the terrain, features, refreshing the screen and some other stuff, not just for the tile in question but all the neighbors too.

You'll have to suck it for long processing times.

I support the progressive winter method as it's more accurate. EG: in October there's snow in northern Scandinavia, but central Europe still enjoys mild weather. :)

ww2commander
Apr 16, 2007, 05:21 PM
Huge thanks for the feedback guys...I went to bed after my last post and could not stop thinking about this problem.:mad:

The more I think of it, Dales/Paasky's progressive way would work best for realism (third option). This will be a big job but atleast it will solve my problem.

EmperorFool, what do you need from me if you were to give option three a try. I want to help out as much as I can and also learn some bloody python before I go insane. I find that the 'stare and the code alone until you go numb in the brain' :ack: appraoch is not working for me!

EDIT: Can one of you explain to me what the difference is between working with plots and terrain in python/SDK? I always thought they were one and the same.

EmperorFool
Apr 16, 2007, 08:44 PM
Whether you use Python or the SDK (C++) to work with plots, you are touching the underlying data. The difference is that using Python uses the SDK itself, thus adding a layer.

Some grocery stores have self-checkout now. You can scan your items at a register yourself; this is using the SDK. You can still go to a checker who uses the same register; that's using Python. Also, the SDK may sometimes give you extra options not available through Python, like "discounting" some items by not scanning them.

Back to your scenario . . .

You can use Paasky's code as long as you don't mind specifically telling it which plots get changed and when. IIRC he has four sets of plots. The advantages to this method are that you can have some grass that doesn't freeze and some snow that doesn't thaw and freezing/thawing can happen in more realistic/interesting chunks (not just along straight latitude-delineation). The disadvantages are more up-front time picking plots and more work any time you change the map.

Or you can use Dale's method. The big advantage is that it works with any map out-of-the-box and doesn't require you to tell the code anything about plots. The disadvantage is that all grass in the "freezing latitudes" freezes and all snow there thaws and it's all done in stripes across the map.

I'm happy to help integrate the code for either one, but if you use Paasky's version, it's up to you to enter in all the plots manually. However, I bet I could get you started with a small program to at least scan the map for all grass areas. From there you simply delete those that shouldn't freeze and split them into blocks.

What I'd need from you is a functional map and mod folder that I can load and start successfully.

Paasky
Apr 16, 2007, 08:56 PM
I have to say, it really isn't my code, it was created by snarko.

But if you can make the game spit out the plots & save them, it would surely make you're job a lot easier. My map is fairly small, so I did them using YAME to check the plots & excel to write them. The notepad++ for finalisation.

ww2commander
Apr 16, 2007, 09:04 PM
Emperor, the zip I sent you via PM is the map with support mod folders to make the swamp work. If it is not working then I will restrip out the bits you dont need and send again. I am at work right now so dont have access to files.

Processing wise, would it be slower if I predefined chunks of plots that need to be changed compared to just grabbing x amount of strips and converting via Dale's method....I need to factor which is fastest as the player will already have a bit of a wait per turn with the number of cities and units that will be on the map.

I will try and sit down and figure out chunks of plots that can be progressivly changed from grass to tundra to snow. This way I can represent the muddy season before and after winter. Is there a way to switch on the plot numbers for each tile in the world builder as the only way I can figure how to get plots is to use the YAME editor. :confused:

Huge thanks guys :goodjob:

EDIT: Just saw your post Paasky....I guess YAME is the best method.

EmperorFool
Apr 16, 2007, 09:53 PM
Paasky, I'm calling it your code simply to avoid confusion since you sent it to ww2c. Props to snarko for the original.

ww2c, the time to scan x lines for grass versus knowing which of those plots are grass is negligable. The real time factor is actually changing the terrain type (the graphics of it and surrounding tiles) -- not looping through plots.

If you're going to stick to latitude strips, there's no reason to do all that extra work by hand. I'll give that ZIP you sent me a try later this week as I'm pretty busy. Think about which way you want to do it as I would much rather do it once on my end.

ww2commander
Apr 16, 2007, 10:35 PM
Progressive change of designated plot areas rather than using strips would be the preferred choice. I will break the map into managable plot areas.

How do you want the information formatted for easiest use?

Also give me some time to study climate change info for this region as the whole realism factor is one of the priorities....I dont want Riga freezing over before Leningrad :lol:

EmperorFool
Apr 17, 2007, 12:13 AM
Okay, knowing that you want to go this route lets me get the code integrated using a couple test plots I make up myself while you work on your research.

One idea I had to make it easier for you would be to write some Python that would write out the list of all plots containing a certain unit -- one unit for each step in the progression -- to a file on disk. So you'd use WB to place units where plots should freeze, run the code, and send me the file. Heck I could show you how to put the file into the Python. This way you can make changes easily.

Let me see what I can come up with over the next few days.

ww2commander
Apr 17, 2007, 01:49 AM
Thanks Emperor. I will try and get the plots sorted asap (subject to my real life :lol:)

Can you clarify on writing a list of units on the plot. What would this be used for as it sounds very interesting?

The reason I ask is that I dont have any units on the map yet or does 'units' refer to something else python wise.

EmperorFool
Apr 17, 2007, 02:15 AM
I didn't explain that very well. What I'm hoping to do is give you a way to "mark" the plots that should freeze in each "step" using the WorldBuilder. Then the Python I write will save turn that information into the list of plots that you eventually put into your scenario. This is all part of your creation process. Players won't see any of this.

Say you choose to have the full freeze take 3 steps. We pick three units as markers, for example a warrior, archer, and spearman.

First using WB, you place warriors on each plot that should freeze in the first step, archers on plots to freeze in the second step, and spearmen on plots to freeze in the third step.

The map would look like this:


WWWAAWWAA
WWAAAAWAA
SSSSAAAAS
SSSSS


Next you hit a key combination back in the normal game mode and Python code uses all those units you placed to write a file on disk containing the plot numbers grouped into steps.

The file would look something like this:


step1plots = [ 0, 1, 2, 5, 6, 9, 10, 15 ]
step2plots = [ 3, 4, 7, 8, 11, 12, 13, 14, 16, 17, 22, 23, 24, 25 ]
step3plots = [ 18, 19, 20, 21, 26, 30, 31, 32, 33, 34 ]


Finally, you take the file created and copy its contents into one of the Python files of your scenario.

Thus, you place units in WorldBuilder instead of typing all those numbers. Plus you can save this modified map and edit it later to rebuild the list of numbers.

Hmm, this gives me another idea. How are you adding marsh to your map? Did you add a marsh terrain type to WorldBuilder as well so you simply paint it on? If so, maybe you could add a new feature (like floodplains) for each step in the freeze and simply paint it directly.

Anyway, I'll take a look... Much fun ahead. :)

ww2commander
Apr 17, 2007, 04:15 AM
Understood. I will use this method.

Right now I am having a very hard time finding any kind of climate maps of Russia. Also anything about Russian seasons is hard to find in graphic format :(

EDIT: OK I found this website which kind of helps out with the mapped region. I can 'guesstimate' the east side of themap based on whats shown.
http://www.iiasa.ac.at/Research/LUC/GIS/jv/AnimEurMTmp.html

Paasky
Apr 17, 2007, 06:22 AM
Wow! That's the exact same map I used! :D

Basically, mid-january is the coldest. Also, climate change means that that map was a tad different in the 40's. Main example: Battle of the Bulge. How many times these days does the benelux countries get lots of snow?

But seeing as you've only got E-Euro, and this is a game, make sure every plot has a 100% chance of snow during mid-january, and then lower the chance in different stages.

Oh, I edited the winter a bit:
def snowcheck(self, sector, sectorweek):
loopcount = 1
weekcheck = self.week
chance = 0
while loopcount:
try: #If we can find the week stored exit the loop. If not we check the week before.
chance = sectorweek[weekcheck]
loopcount = 0
except:
loopcount = 1 #Just in case.
if weekcheck == 0:
weekcheck = 48
else:
weekcheck -= 1

for i in sector.keys():
coord = string.split(i, ",") #Splits the string into ["x", "y"]
if (CyGame().getSorenRandNum(100, 'snow making!') + 1) <= chance: #If the snow chance exceeds the random number make snow.
if self.week > 24: #New snow can only be created during the 2nd half of the year (jul-dec)
CyMap().plot(int(coord[0]), int(coord[1])).setTerrainType(gc.getInfoTypeForString('TERRAIN _SNOW'), True, True)
else: #If the snow chance is lower than the random num return it to original terrain.
if self.week < 24: # Snow can only melt during the 1st half of the year (jan-jun)
terrain = gc.getInfoTypeForString('TERRAIN_' + sector[i])
CyMap().plot(int(coord[0]), int(coord[1])).setTerrainType(terrain, True, True)
it 1) makes the change faster as snow can't melt until spring, nor can new snow fall during spring, and 2) fixes the chance calculation (previously it had a 1/101 chance of snowing even though the chance was at 0).

ww2commander
Apr 17, 2007, 07:34 AM
On my map I have divided the snow development across 7 turns. The aim is to have all the map covered in snow by first or second week of December and remain like that throughout January. I agree with the fact that we probably will never be able to know the exact pattern but atleast the map provided a pattern for me to follow from Oct-Nov-Dec.

Emperor - I have just finished covering the map in different types of units as you requested. Check your PM.