View Full Version : Magic/Square Selection demo mod
talchas Jan 03, 2006, 10:11 PM This mod is just a demonstration of how Civ4 could be modded to include some sort of magic system and how to allow the user to select a square using the main map.
It includes 1 unit that appears as "Mage Description" and 3 promotions, Mana1, Mana2 and Mana3 which each provide mana. It has 1 spell that deals 15% damage to all units on a square.
Things that would probably need to be changed for a real mod (other than the names + that sort of thing):
The spell just deals with percentage damage - a tank gets hurt just as fast as a warrior. Maybe divide by the strength, or sqrt/log of it. It could be interesting
The spell doesn't give xp for killing something, easy enough to change.
The spell doesn't require you to be at war, and doesn't trigger war. It wouldn't be too hard to check for war, but it might be more difficult to trigger war and give the normal warning.
Having a whole bunch of guys that can strike at range, or just without retaliation could be hard to balance, so at the very least it could be good other mages to retaliate - perhaps leading to a ranged battle. Maybe a 1 spell/turn limit or movement usage should be set up.
(bug)Currently if you pick a spell + then switch units, it still lets you try to cast and is generally bugged. It should just cancel casting when you switch. You could probably get around the preresquisites for a spell like this.
Changing the tooltips to add ones for the spell buttons and to display the mana for units would be nice too, but I have no idea if this is doable. Maybe if you used really large action numbers for appendMultiListButton that aren't used by Civ4 but are positive so you could somehow give them a tooltip? I haven't looked at that stuff.
I'm not sure if this belongs here or in the general forum, but this is as completed as it is likely to get, so I posted here.
The zip file should just be unzipped into the Mod folder. The mod is called Spelldemo.
If you like any or all of it feel free to take it.
Edit:
Added version with effects when casting.
Kael Jan 03, 2006, 10:19 PM You should check out my mod. It has fireballs, creatures you can summon, buff spells and other magical effects.
talchas Jan 04, 2006, 05:14 AM I have. I believe your mod works by creating "spells" that are units, that you then attack with. The idiea with this one was to directly select a given square.
Kael Jan 04, 2006, 07:21 AM Ahhh. Very cool. Might be nice to make cannons and such into ranged units even in non-magic mods.
woodelf Jan 04, 2006, 07:27 AM Cool potential.
Clifford Jan 04, 2006, 08:24 AM I see huge potential here. This is probably how we can create Civ3-style artillery and bombers when the SDK arrives. Could you explain briefly how the mod works? What kinds of scripts/Python? Just a hint would be nice :)
Coopa Jan 04, 2006, 12:44 PM Yeah surely this would mean Artillery was possible through a different stat. It could then have its strength decreased, although it should still do some damage before death (or if lucky victory)
RED DIAMOND Jan 04, 2006, 02:31 PM I have been able integrate most mods with the ones I already have and would like to use this one too. However, there are several python script files like CvEventInterface.py that are being used by other mods. Can your scripts be added to the exsiting python files with the same name like XML or is there something else needed to integrate them?
The Great Apple Jan 04, 2006, 02:53 PM Looks very very useful! Sounds to me like a way to make paratroopers work again.
talchas Jan 04, 2006, 03:35 PM To answer Clifford:
The python, by files/classes:
It uses a CvEventManager (through a subclass) for the square selection. It overrides onUpdate, which is called every frame. If it is in selection mode, onUpdate uses CyEngine().addColoredPlotAlt() to add the range and selection overlays. It discovers the CyPlot(square) that the mouse is hovering over with CyInterface().getMouseOverPlot(). It overrides onMouseEvent to detect when the mouse is clicked on the main map and process the click if it is in selection mode. onUnitBuilt and onUnitCreated ensure that all units have the scriptData setup properly. onUnitPromoted ensures that the MAX_MANA attribute is always updated.
CvSpelldemoGameUtils overrides CvGameUtils and detects whenever a button on the action panel is pressed that Civ4 doesn't recognize - namely the spell buttons. This then activates my EventManager's selection code.
CvSpelldemoMainInterface is an edited copy/paste of the 1.52 version. It adds the spell buttons and the mana line in the unit info.
CvEventInterface replaces the old event manager with mine, CvScreensInterface replaces the old CvMainInterface(should be called CvMainScreen maybe) and CvGameInterface replaces the original CvGameUtils.
Utils handles the storing of attributes in units' scriptData.
SpellInfo.py contains the class SpellInfo, which holds the data about each spell and also a couple of function for the current two spells. The only two functions which should be part of the public interface are getSpells() and getSpellFromAction(). It also defines which promotions give mana and how much. The promotion that gives the largest amount of mana is the one that is used - they aren't cumulative, but this could be changed easily.
SpellDemo handles the casting of spells and has several mana related utility methods.
The XML isn't anything special - it adds one new unit at the top of Units/CIV4UnitInfos.xml, a new unit class in Units/CIV4UnitClassInfos.xml and a set of promotions in Units/CIV4PromotionInfos.xml. There is a new UnitCombat type in BasicInfos/CIV4BasicInfos.xml because that is the only way to restrict promotions.
To answer RED DIAMOND:
The Python/EntryPoints/*.py files can't really be combined, but don't need to be. The simplest thing to do would be to leave any that aren't used by that mod and then change the others to call that mod's own CvEventManager/CvGameUtils/CvMainInterface.
Then leave CvSpelldemoEventManager.py and CvSpelldemoGameUtils.py in with the mod. Then create CvMODEventManager.py that starts like this:
...
from CvSpelldemoEventManager import *
class CvMODEventManager(CvSpelldemoEventManager):
...
and a CvEventInterface.py
...
normalEventManager = CvMODEventManager.CvMODEventManager()
...
Do not copy paste CvEventManager's code and put it in. Instead do what I did and just override the methods you need and call the super class version. BTW, the correct way to call the superclass version is this:
...
class CvMODEventManager(CvSpelldemoEventManager):
...
def onUnitPromoted(self, argsList):
#do stuff
super(CvMODEventManager,self).onUnitPromoted(argsL ist)
not what I did. What I did would cause my code to break if I changed the class's superclass.
For CvGameUtils do a similar thing - import my version and subclass.
However for CvSpelldemoMainInterface, I didn't subclass CvMainInterface, which may well have been a mistake. However it has big enough and odd enough methods that I don't know how well that would work. Instead I marked off with "### Spelldemo mod" tags wherever I made changes, and it shouldn't be any more difficult to edit than the original. If/When the next patch comes out, it will break however, which is the benefit of the subclassing method.
Whew, long post
Impaler[WrG] Jan 04, 2006, 03:36 PM It will need to be modularized and trimed down to the core tile selection ability and them tie that in with something that will create some kind of one sided combat between the Artilery and the Unit being fired upon. Perhaps the Artilery can be given 100% withdraw, moved next to its target, engaged with the unit and then have its health restored to what ever it had been before combat before being moved back to its original location. This would alow combat to make use of all the normal promotions.
In any case something can almost certanly be done.
talchas Jan 04, 2006, 04:02 PM The core tile selection ability includes these functions of CvSpelldemoEventManager: __init__, activatePlotChooser, onUpdate and onMouseEvent. You could just copy these functions over into the other mod's subclass of CvEventManager and modify them to fit. Also MY_PLOT_LAYER(2) would need to be copied as well (and preferably renamed)
afireinside Jan 04, 2006, 04:37 PM make it square root.
so that warriros get hurt bad, more that 1, but tanks only get huer 5, root(28)
a4phantom Jan 05, 2006, 07:46 AM Ten geishas and a small palace to whoever makes artillery work as in Civ3.
Clifford Jan 05, 2006, 09:08 AM Ten geishas and a small palace to whoever makes artillery work as in Civ3.
I second that!
Thanks for the excellent answer, I´m lacking necessesary Python skills myself but Im learning...
Things I imagine will be quite easily accomplished by this is bombing railroads/improvements as in Civ3, using artillery Civ3 style, Paratroopers and other unit-enhancing abilities. It´s a bright future for Civ4 modding.
DieselBiscuit Jan 08, 2006, 06:14 AM This has incredible potential! In addition it's very educational for a guy like me who's just beginning to get a grasp of how the interface works and the limitations/possibilities for a mod without the SDK. Thanks a bunch!
Déja Jan 11, 2006, 05:56 PM very nice work... it filled in the last piece of my ranged arms mod (targeting). You have definately secured a place in the credits :)
The Great Apple Jan 13, 2006, 12:44 PM Righty. I've been poking away all day trying to get teleportation to work... but I'm hitting one small snag. It would seem that self.chooserActive is never true, even when I've just set it to be true... which... is really quite frustrating.
There was a brief gap after that last paragraph where I thought "hmmm, I wonder what happens if I change it to a global thingy"... and it works!
Now to just get my teleport function working right...
EDIT: Got it working... :D:D:D thanks very much for the sample code, couldn't have done it without that! A few bugs (like I can actually teleport anywhere rather than just in the highlighted area... but it's probably my fault), but apart from that it's great!
talchas Jan 13, 2006, 04:33 PM EDIT: Got it working... :D:D:D thanks very much for the sample code, couldn't have done it without that! A few bugs (like I can actually teleport anywhere rather than just in the highlighted area... but it's probably my fault), but apart from that it's great!
Just make sure that the function you pass in as canCastFunc only returns true if the given target is inside the range you return from rangeFunc.
The Great Apple Jan 13, 2006, 04:57 PM Just make sure that the function you pass in as canCastFunc only returns true if the given target is inside the range you return from rangeFunc.Yes, managed to get that working fine.
About the self.chooserActive things - you probably know better than me, but IIRC you can't change their values at all can you? It seems the whole plot selection thing hinges on that, but as you managed to get it to work on your machine I guess it was me.
I'm also experiencing slight problems when I try to right-click to deselect the view - it always moves the unit to the square I right-click on (walking, not teleporting).
talchas Jan 14, 2006, 07:59 PM Righty. I've been poking away all day trying to get teleportation to work... but I'm hitting one small snag. It would seem that self.chooserActive is never true, even when I've just set it to be true... which... is really quite frustrating.
Thats odd, can you post an example?
Also, about the right click thing, one solution is to just change it so right-click brings up the popup menu (thats what I have normally). However, returning 1 from onMouseEvent supposedly consumes the click, but maybe it doesn't work for the main map.
RED DIAMOND Jan 30, 2006, 08:55 PM Well, finally got around to incoporating this ranged art into the game. Only problem, well not really a problem, but it would be nice to have some kind of explosion graphic to go along with the damage. Is there an easy way to release a version that incoporates an explosion upon use?:cool:
talchas Jan 31, 2006, 05:14 AM Well, finally got around to incoporating this ranged art into the game. Only problem, well not really a problem, but it would be nice to have some kind of explosion graphic to go along with the damage. Is there an easy way to release a version that incoporates an explosion upon use?:cool:
Well, if you can make an explosion graphic appear at all from the python, it would be easy to make it appear when you use this. I posted an idea about this over here http://forums.civfanatics.com/showthread.php?t=154225 but I haven't tried it to see if it would work.
talchas Jan 31, 2006, 07:05 PM Well, it works, see the other thread for details or download the new version yourself (once the attachments are no longer "In Progress").
Civmansam Jan 31, 2006, 07:53 PM Very good job.
Do you have any screens of the actual spells in action
talchas Jan 31, 2006, 08:23 PM Yeah, they are part of the "In progress" attachments. I'll add links manually to the first post.
RED DIAMOND Jan 31, 2006, 09:16 PM Hmm, attachment not worky:mad:
talchas Feb 01, 2006, 05:11 AM There we go. Try it now.
RED DIAMOND Feb 01, 2006, 07:14 AM There we go. Try it now.
Yippie:lol: Got it working bro! Now to test more effects. I think the bombing/bombardment effects might look better:D
Sound has been resolved by the man TALCHAS!
Taranthor Feb 06, 2006, 07:11 AM Hrmm do you think it would be psosible using this, to have targeted promotions?
So you select a particular person, and that person gets the selected promotion?
talchas Feb 06, 2006, 10:31 AM Hrmm do you think it would be psosible using this, to have targeted promotions?
So you select a particular person, and that person gets the selected promotion?
Yes, you could do that. Instead of casting a spell, you could use unit.setHasPromotion("PROMOTION_ABC",True) to give it the promotion. The only problem is that if you clicked on a square with multiple units in it you would need a way to select only one of them.
Shqype Feb 06, 2006, 08:12 PM Instead of casting the spell, can't you create a pop-up with a pulldown list of the units on that square, and a button called "Promote" or something?
You select the unit from the pulldown list, and then clicking the promote button returns the unit ID which then is affected by the setHasPromotion code.
The worldbuilder uses a pull-down menu when editing units... you select the unit you want to edit from the pulldown menu and then you edit that unit's stats. I'm sure it wouldn't be too difficult to look at that code and use it to choose who gets a promotion...
talchas Feb 06, 2006, 08:37 PM Yeah, you could do it - it would just take a bit more work.
Kael Feb 06, 2006, 08:49 PM Instead of casting the spell, can't you create a pop-up with a pulldown list of the units on that square, and a button called "Promote" or something?
You select the unit from the pulldown list, and then clicking the promote button returns the unit ID which then is affected by the setHasPromotion code.
The worldbuilder uses a pull-down menu when editing units... you select the unit you want to edit from the pulldown menu and then you edit that unit's stats. I'm sure it wouldn't be too difficult to look at that code and use it to choose who gets a promotion...
I need a pulldown like that when my units with "Marksmen" ability attack a stack. "Marksman" allows the attacker to pick the defender instead of the goign against the best defender.
So let me know if you work out a good way to do this.
TheLopez Feb 07, 2006, 01:50 PM 1st of all, very nice job talchas. Kudos to you. Anyways
(bug)Currently if you pick a spell + then switch units, it still lets you try to cast and is generally bugged. It should just cancel casting when you switch. You could probably get around the preresquisites for a spell like this.
Couldn't you use the onUnitSelected to cancel the casting after the player selects a unit, that is if casting is enabled?
Changing the tooltips to add ones for the spell buttons and to display the mana for units would be nice too, but I have no idea if this is doable. Maybe if you used really large action numbers for appendMultiListButton that aren't used by Civ4 but are positive so you could somehow give them a tooltip? I haven't looked at that stuff.
Unfortunately, I have tried changing the tooltips for some of the new custom features in my new unnamed mod and it is hardcoded. I guess we will have to wait until the SDK comes out. :cry:
talchas Feb 07, 2006, 02:03 PM Couldn't you use the onUnitSelected to cancel the casting after the player selects a unit, that is if casting is enabled?
Probably, I didn't really look to find a way around that problem.
The Great Apple Feb 07, 2006, 05:11 PM Couldn't you use the onUnitSelected to cancel the casting after the player selects a unit, that is if casting is enabled?
That's what I'm using and it seems to work fine, althought I don't do a check to see if it's enabled - surely it's quicker just to make it disabled no matter what?
RogerBacon Mar 29, 2006, 06:34 PM I'm getting an error with this mod. It works fine until I save the game and exit. Then when I reload I get:
Traceback (most recent call last):
File "CvScreensInterface", line 601, in forceScreenRedraw
File "CvMainInterface", line 826, in redraw
File "CvMainInterface", line 1518, in updateSelectionButtons
RuntimeError: unidentifiable C++ exception
ERR: Python function forceScreenRedraw failed, module CvScreensInterface
CvMainInterface (I thinik you called it SpellDemoInterface) at line 1518 is where you add the buttons for the spells:
for spell in spells:
#CyInterface().addImmediateMessage("spell %s number %d art %s" % (spell.getName(),spell.getActionNumber(),spell.get Button()),"")
art = spell.getButton()
actionnum =spell.getActionNumber() ##for some reason if I put this all on 1 line it gives me a MemoryError or an "unidentifiable c++ exception"
screen.appendMultiListButton( "BottomButtonContainer",art, 0, WidgetTypes.WIDGET_ACTION, actionnum, -1, False ) #adds the spell button
It also looks like you had the same problem and thought you fixed it by seperating some code on to two lines.
Anyone know what could be causing this? Like I said, it works fine until you save, exit civ, and then try to load and continue the game.
Roger Bacon
talchas Mar 29, 2006, 07:02 PM I believe that the reason my thing works at all is that C++ is lazy and accessing a negative array (or something) index works - it just points to some random bit of memory. You can see this if you do "print CyGlobalContext().getPromotionInfo(-1).getSomeProperty()" in the python console - sometimes it will work and give gibberish, sometimes it will error out. Theres a semi-workaround in the ActionButtons mod which essentially goes through and sees which ones crash out and which ones work, and only uses the ones that work, but I haven't backported the changes here because not as many people seemed to be using it. When Firaxis can release the new patch and the SDK, I'll release a new version of ActionButtons that doesn't rely on this hack.
RogerBacon Mar 29, 2006, 08:41 PM I believe that the reason my thing works at all is that C++ is lazy and accessing a negative array (or something) index works - it just points to some random bit of memory. You can see this if you do "print CyGlobalContext().getPromotionInfo(-1).getSomeProperty()" in the python console - sometimes it will work and give gibberish, sometimes it will error out. Theres a semi-workaround in the ActionButtons mod which essentially goes through and sees which ones crash out and which ones work, and only uses the ones that work, but I haven't backported the changes here because not as many people seemed to be using it. When Firaxis can release the new patch and the SDK, I'll release a new version of ActionButtons that doesn't rely on this hack.
So does this workaround allow you to continue a saved game? Right now I probably will not use this code because it makes it impossible to continue a saved game. Why are you using negative numbers for ACTION_NUMBER at all?
Roger Bacon
TheLopez Mar 29, 2006, 08:54 PM Hmmmm... thats interesting because I use negative numbers in the mercenaries mod, great statesman, great doctor and haven't seen any issues...
RogerBacon Mar 29, 2006, 09:13 PM OK, I added the workaround from the action buttons mod and it seems to be working. The first turn two of the buttons were grayed out but after that they work fine.
Someone help me understand the whole negative number thing. We're using negative numbers just so we do collide with the index of an existing button, right? Is there no way to find out how many buttons already exist and then index up from there? Or am I completely missing the point?
Roger Bacon
The Great Apple Mar 30, 2006, 04:20 AM OK, I added the workaround from the action buttons mod and it seems to be working. The first turn two of the buttons were grayed out but after that they work fine.
Someone help me understand the whole negative number thing. We're using negative numbers just so we do collide with the index of an existing button, right? Is there no way to find out how many buttons already exist and then index up from there? Or am I completely missing the point?
Roger Bacon
That's what I had presumed.
I did a test once and I seem to remember that there are ~ 300. Starting at 1000 would certainly work.
talchas Mar 30, 2006, 05:10 AM Yes, that would work, but you'd get the same problem (assuming I am correct about what it is) - if there are only really 300 actions, then action #1000 would also be outside the limits for that array. As far as I can tell, the only way to get Civ4 to pass the action to the cannotHandleAction in the python is to give it an invalid action. There may be a better way, but I haven't found it.
The Great Apple Mar 30, 2006, 11:53 AM Fair enough.
Was having a poke around today and found that some of the negative numbers seemed to activate mouseover info on the actions, which was a bit strange.
RogerBacon Mar 31, 2006, 05:59 PM edit. Never mind. It was a stupid question.
RogerBacon Mar 31, 2006, 06:06 PM In the SpellDemo code there is a hurtAll function. I want to modify it so that if a unit dies due to the spell the caster gets 1 exp. The arguments passed in inner are (caster,targetPlot). Is caster the unit? I seem to remember that it is the player's id. How would I modify the spell so that it knows the unit that cast it?
Roger Bacon
[edit]
Never mind. caster is the unit. I'll post the code here just in case anyone want to know it. It was pretty easy.
Does anyone know how to get the correct amount of experience a unit is supposed to get for killing another unit instead of just using 1?
for i in range(targetPlot.getNumUnits()):
targetPlot.getUnit(i).changeDamage(amount,gc.getGa me().getActivePlayer()) # not sure what the second arg does
if (targetPlot.getUnit(i).getDamage() >= 100): # Unit died
caster.setExperience(caster.getExperience()+1, 999)
TheLopez Apr 01, 2006, 12:51 PM I believe that the reason my thing works at all is that C++ is lazy and accessing a negative array (or something) index works - it just points to some random bit of memory. You can see this if you do "print CyGlobalContext().getPromotionInfo(-1).getSomeProperty()" in the python console - sometimes it will work and give gibberish, sometimes it will error out. Theres a semi-workaround in the ActionButtons mod which essentially goes through and sees which ones crash out and which ones work, and only uses the ones that work, but I haven't backported the changes here because not as many people seemed to be using it. When Firaxis can release the new patch and the SDK, I'll release a new version of ActionButtons that doesn't rely on this hack.
Talchas,
Since I couldn't find your workaround in the action buttons mod I am now just starting off the action buttons number using a random number. Since doing this I haven't gotten the C++ error. Its a hack but I haven't run into any issues yet...
talchas Apr 01, 2006, 04:02 PM The workaround was to link a specific number to a specific action only in CvMainInterface, when each was added succesfully. The inside of the loop was stuck in a try/except to catch the error.
Samuelson Apr 14, 2006, 08:22 PM This is awesome because it can be used to make a Civ 3 catapult for Civ 4. As we all know the Civ 4 "suicide catapults" are far from realistic. This mod could bring back the long-ranged artillary units.
|
|