Adding extra special abilities to units

Agentis

Chieftain
Joined
Aug 1, 2007
Messages
5
Hi everyone, I've only recently started attempting modding so I hope this issue isn't already addressed.

I'm making a mod and adding units which will have various special abilities, ie light a fire, terraform a plot, whatever. Though I think I've made a good start, I'm wondering a few things.

At the moment I am accomplishing my goal by editing UnitPanel.lua. Essentially I just added this chunk of code to UpdateUnitActions:

Code:
if(bUnitHasMovesLeft)
	then
		local thisUnitInfo = GameInfo.Units[unit:GetUnitType()];

		if (thisUnitInfo.Class == "UNITCLASS_WARRIOR") --This works, displaying the panel only when a warrior is selected
		then
			instance = g_BuildIM:GetInstance();
			instance.UnitActionButton:SetAnchor( "L,B" );
			instance.UnitActionButton:SetOffsetVal( (numBuildActions % numberOfButtonsPerRow) * buttonSize + buttonPadding + buttonOffsetX, math.floor(numBuildActions / numberOfButtonsPerRow) * buttonSize + buttonPadding + buttonOffsetY );				

			instance.UnitActionButton:RegisterCallback( Mouse.eLClick, OnWarriorActionClicked );

			activeUnit = unit;

			numBuildActions = numBuildActions + 1;
		end
	end

Obviously I also added a method OnWarriorActionClicked, which does some irrelevant things like print to FireTuner and use up a movement point.

This works but doesn't feel good to me as a programmer; is there a way to modify GameInfoActions to accomplish what I want? Where is GameInfoActions defined anyway?

My second question is to do with assigning an icon to the action button. I see this line:
Code:
IconHookup( buildInfo.IconIndex, actionIconSize, buildInfo.IconAtlas, Controls.RecommendedActionImage );
being used elsewhere in the file but I'm not 100% sure how to use it. Is buildInfo.IconAtlas an object or a string? Whats the last parameter exactly?

And if anyone knows whats going on behind the scenes when g_BuildIM:GetInstance() is called, it would be nice to know, I hate just relying on "its magic and it works!" :)

Thanks heaps; lets break stuff!
 
Why are you editing the Lua? The game ALREADY will draw whatever buttons are necessary for build actions defined in the XML. All you need to do is add those actions in the XML, and it'll all work correctly without a horrible Lua hack. My own mod added five terraforming options (plant forests, plant jungles, raise/lower hills, deep mining, terraform) this way.

Now, you'll still need Lua code to actually DO whatever it is that the button is supposed to trigger, but the UI does not need changing.

Is buildInfo.IconAtlas an object or a string?

buildInfo is a structure, defined a few lines earlier in that Lua file, probably as GameInfo.Builds[whatever index we're on]. In this particular case, it's the XML <Row> in the <Builds> table corresponding to the particular action in question. So buildInfo.IconAtlas will just be equal to the value stored in the <IconAtlas> entry in that particular Row; buildInfo.Type would be its type (i.e., BUILD_FARM), buldInfo.Description will be the description text key (TXT_KEY_BUILD_FARM) which you'd need to pass through a localization filter to get actual text. And so on. This is how Lua accesses XML database variables.
So in this particular case, buildInfo.IconAtlas is a text string along the lines of "ATLAS_UNIT_ACTIONS" or whatever it is in the XML. Although, while it's a text string, I believe that it's an INDEXED text string; you can use it as an array index when looking at GameInfo.IconAtlases[] and it'll get the information for that atlas (barring the duplication issues of having multiple declarations per atlas).

Before the last big patch, the build actions used a lookup in ActionIcons.lua, which meant a lot more work for modders, but that's now been replaced by this direct XML lookup instead. Much better now.

And if anyone knows whats going on behind the scenes when g_BuildIM:GetInstance() is called, it would be nice to know,

Pretty much what it sounds like. It's getting the Instance for that particular build action; since it's an action you didn't have already, it's creating a new Instance with the standard format for an action button (with the "standard format" being defined in the corresponding UnitPanel.xml or UnitPanel_small.xml files). An "Instance" is basically one button/notification/symbol/action, so all that's saying is "I want to create a new button; set up the right structure for one").
 
It's good that there's a more "proper" way, but the idea is more of a fantasy spellcasting button/addition than a build action, so I'd want the build bar title to change, and the "ranged attack" style interface would have to appear to; but I'll look into how I can adjust the build actions for that, thanks. It feels like I'd still need to add some code to UnitPanel to just the title at least
 
If all you want to change is the title on the "Build" bar, then that's just a text key in the XML code. (I can get the exact key name when I get home, but you can probably find it just looking through the UnitPanel.xml file for yourself.) No need to change any UI files for that; basically, anything that uses actual text will use text keys to avoid language issues.


Basically, in UnitPanel.lua, UnitPanel.xml, and UnitPanel_small.xml, there are four types of action button:
> Primary buttons go on the bar along the left edge of the screen. These are any in the action table with priority less than 100, and include most of the Great Person actions (Culture Bomb, Trade Mission)
> Secondary buttons go on a temporary bar next to the primary bar when you click that small arrow button. (This is where the Disband button is, for instance.) These are any in the action table with priority greater than 100.
> The "Build a City" button for Settlers is placed at the top of the Primary bar, through a special bit of logic that overrides everything else.
> The floating box with small icons is used for the rest, mainly Build actions (workers or when GPs make Improvements) and the list of available promotions when a unit levels up. This box automatically resizes itself based on how many buttons it's trying to contain, so it's very flexible.

The point is that if you add a new action to the game, it'll automatically place it in the correct spot in the UI without you needing to add any extra code. If you want to create an entirely new box in a different spot than the Build/Promotion one for your new actions, then yes, it'd require some significant changes to all three UnitPanel files.
----------------
I just spent about four hours last weekend on this particular issue, because I was trying to do two things to the Unit Panel:
1> Make the little promotion icons showing what abilities your currently selected unit has go into two rows instead of just one. (If you had 11 or more promotions, they'd be underneath the image and so unable to be moused over.)
2> Add an "Edit" button so that units could be renamed at any time instead of just when they had a promotion pending.

I succeeded at both, for both styles of UI, and the changes will be in the next version of my mod. In the process, I made the Unit Panel box thinner by 48 pixels and taller by 32, so I know EXACTLY how screwed up it'd be to try adding another box for abilities; there are way too many places where sizes have to be set by hand, and most of the existing boxes auto-resize to fit however many buttons they need to include. So I'd think you'd probably just be better off either hijacking the Secondary box for your own "spells" or trying to add another bar with a similar mechanism.

EDIT: Okay, found it.
When it's putting a Worker action in that box, it's TXT_KEY_WORKERACTION_TEXT.
When it's putting a list of available promotions, it's TXT_KEY_UPANEL_UNIT_PROMOTED.
 
Now, you'll still need Lua code to actually DO whatever it is that the button is supposed to trigger, but the UI does not need changing.

How to you link a new xml "Build" (or "Command") to a Lua function? I could do it for the human through UnitPanel.lua, of course, but that would not fire for AI players, which I need.

For that matter, a new xml Build or Command may not be suitable for my purpose. The problem is that I need total Lua control for allowing/disallowing the action. Even linking it to a fake hidden tech won't work, because I need it to restrict it even within civ (and not by unitType). What I really need is a CanBuild check, but that doesn't exist as far as I know. I also need to be able to allow it in cities (depending). All of this makes me think that I can't use existing xml structures.

Well, that's fine, I've already added a half-dozen new tables. But these new "MyActions" that I'm adding need to show up in UnitPanel. They most logically fit under the Builds part. Does anyone have any code already for dropping something that isn't really a Build into the Builds panel?
 
How to you link a new xml "Build" (or "Command") to a Lua function? I could do it for the human through UnitPanel.lua, of course, but that would not fire for AI players, which I need.

Depends what you're doing. If you're adding a new Build action, then the AI handles this just fine, although it uses an unfortunately hard-coded method of yield comparisons to decide whether the improvement placed is superior to what's already on the hex. If you want to add something entirely new that isn't map-linked (like making a unit that can cast spells), then you'd need to put the callbacks directly into UnitPanel.lua, executing the commands through a previously set instance. This is generally pretty tricky, but you can pass any needed information to other functions through the MapModData structure. I do this in my own mods, where the Mythology mod's variables are stored in an instance of that structure, allowing them to be used by UI routines that aren't directly Mythology-related.

What I really need is a CanBuild check, but that doesn't exist as far as I know.

Unfortunately true. There are a lot of GameEvents that, if added, would make our lives much, much easier, and this is one of them. What you CAN do is use a different entity type as a placeholder, like using improvements to control the creation of Features (like planting a forest), but if you're trying to add complex rules (like you can't have two of an improvement next to each other) then it just won't work well.

Does anyone have any code already for dropping something that isn't really a Build into the Builds panel?

The game is already built to stick Builds (worker actions) and available Promotions into the same supplementary floating box; if you create a combat unit that can do worker actions (like a legion that makes roads), then it'll just pool the two together, to where when the unit gains a level it'll put the promotions you can add right next to the "Build Road" icon. It's a bit confusing, as you'd expect. So if you want to add a third type of action to that floating box, then it's a really simple change in Lua. I don't know of any way to do this without replacing UnitPanel.lua in its entirety, though.
 
Thanks! I spent a lot of hours this weekend learning the UnitPanel system. I've managed to hijack it to the point where I can add "city builds" (a worker-type construction on a city tile) using existing UI but bypassing the game engine entirely.

I've built a number of crude AI systems now to handle added content. I can drive AI units around and make them do something that is entirely new in my mod. Where I really struggle is when something is only half-new and half-base game, like builds and such (for now I'm using TECH_ALLOW_BUILD_...'s that I can turn on and off via Lua).
 
@Spatzimaus

If i understand, you said i can add a "plant forest" WITHOUT changing LUA ? Only with XML ?
can u explain me how? I have to create exactly a "plant forest" terraform action. Otherwise can you post a little part of your mod so i can learn from that?


I can't understand how to pass from a BUILD_PLANT_FOREST in the BuildFeature and Builds database tables, to an action that change terrain feature.

I've done something like that adding a LUA action that call:

plot:SetFeatureType(FeatureTypes.FEATURE_FOREST);


but still i can't bind that with XML and i don't know how to launch the action function when the build action is completed (same turn after) instead of at clicking the button.


I hope you can help me.
 
If i understand, you said i can add a "plant forest" WITHOUT changing LUA ? Only with XML ?

No. It still requires Lua to trigger, it just doesn't require modification of the UI Lua (which is what this thread ended up being about).

What you do is this:
1> Add a new improvement called "Plant a Forest". Make sure it's only buildable on terrain on which forests can be found. And make sure it uses a graphic that won't be too out-of-place during the period between when it's built and when it triggers forest construction.
2> Create a new Build action to create that improvement. I'd suggest forbidding a player from building this on top of an existing forest or jungle, but you're pretty flexible on this.
3> Give that Build action to some units. It doesn't matter whether you give them to existing worker units, or create specialized terraformer units.
4a> Use Lua to see whether that improvement exists on the map.
4b> Whenever it does, remove it from the hex and place a forest there.

That's all you need. The problem is that step 4a isn't simple; there's no single "on improvement created" Lua event that works for this, because SerialEventImprovementCreated only triggers if YOU (the active player) sees the hex in question; if you don't, it won't trigger until you move a unit to where it can see that hex. This is crippling for the AI.
The most effective way I've found is to use the standard start-of-turn GameEvent. Get the improvement count for the current player for that improvement type; if it's nonzero, then scan his territory to see which hexes have it, and go to step 4b. If you're not careful on how you do 4a, the overhead can be HUGE.
 
Sorry for misunderstanding the thread.
Anyway, thanks it was the kind of information i was searching for.

Last question. Does exists some place where i can read the list of LUA events and some even short, brief description about their behaviour?
I know i'm boring you...
 
For ANY Lua modding questions, you should bookmark this site. The Events and GameEvents are the triggers, and everything else are the commands you can use. They're not very well documented, though, so you should ALSO be in the habit of searching the game's files to see how each of these is used (if it's used).
 
Back
Top Bottom