Magic/Square Selection demo mod

talchas

Prince
Joined
Jan 3, 2006
Messages
428
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.
 

Attachments

  • Civ4ScreenShot0000.JPG
    Civ4ScreenShot0000.JPG
    210 KB · Views: 1,324
  • Spelldemo.zip
    Spelldemo.zip
    68.9 KB · Views: 458
  • spelleffect p1.jpg
    spelleffect p1.jpg
    155.9 KB · Views: 726
  • spelleffect p2.jpg
    spelleffect p2.jpg
    155.2 KB · Views: 662
You should check out my mod. It has fireballs, creatures you can summon, buff spells and other magical effects.
 
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.
 
Ahhh. Very cool. Might be nice to make cannons and such into ranged units even in non-magic mods.
 
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 :)
 
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)
 
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?
 
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:
Code:
...
from CvSpelldemoEventManager import *

class CvMODEventManager(CvSpelldemoEventManager):
...
and a CvEventInterface.py
Code:
...
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:
Code:
...
class CvMODEventManager(CvSpelldemoEventManager):
...
def onUnitPromoted(self, argsList):
    #do stuff
    super(CvMODEventManager,self).onUnitPromoted(argsList)
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
 
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.
 
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)
 
make it square root.

so that warriros get hurt bad, more that 1, but tanks only get huer 5, root(28)
 
Ten geishas and a small palace to whoever makes artillery work as in Civ3.
 
a4phantom said:
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.
 
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!
 
very nice work... it filled in the last piece of my ranged arms mod (targeting). You have definately secured a place in the credits :)
 
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!
 
The Great Apple said:
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.
 
talchas said:
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).
 
Back
Top Bottom