Tooth and Tail

Tooth and Tail

25 ratings
Modding Guide
By Youthful Idealism and 2 collaborators
This is a guide to modding Tooth and Tail, the RTS in development by PocketwatchGames.
   
Award
Favorite
Favorited
Unfavorite
What do I need?
Well, what do you want to do?

The main tool is gonna be your text editor. On windows, Notepad will work--but I suggest something a little more sophisticated. Notepad++ is both adequate and free.

If you want to edit texture assets, you're gonna need an image modification program. GIMP is free, and adequate. Photoshop is better--if you're willing to dish out bucketloads of cash.
Accessing game contents
To acces game contents, go programFiles(x64/x86)/steam/steamapps/common/ToothAndTail/content. Everything there is moddeable in some way or another. If common/ToothAndTail is missing, common/ARMADA is an acceptable substitution.

Any file or folder I reference from here on out will assume ToothAndTail/content/ as the base directory.

To change text within the game, navigate to /strings, then select the XML file representing your language of choice.

To access most everything, go to /data. Mmmm. Meaty.
Within data, we have:
/actors, where moving units are stored.
/structures, where both factories and defensive structures are stored.
/weapons, where attack types are stored




/textures stores... well... textures. Anything image-related.
Screwing things up
So, you've done it. You've managed to completely break the game, making skunks that fire like machine guns, or turrets that pee blood, or owls that spawn so many toads that the game crashes. Or, maybe you just want to discard your changes and revert the game to it's native state, so that you can play with freinds who don't appreciate your brilliant MS paint art.

Just verify your cache.

<this will wipe out all your hard work, so back up your modfiles somewhere.>
Right-click on the game in steam, and click "properties" Navigate to the "Local Files" tab, and click "Verify integrity of game cache". Instant blank slate!
Changing Strings
<placeholder>

That said, this is pretty self-explanatory. Seriously.
God, you're boring.
Yeah, yeah, I get it. You wanna sink your arms elbow-deep in amazingness.

Fine, lets make ourselves a unit.

We're gonna ovverwrite snakes--at the time of writing this, they're broken, so that makes them ideal for changing.

Let's go to /data/actors, where the unit types are stored. Open up the snake's file. We're gonna change some data.

<ActorData>

//Here, we change the unit's name. I wanna add elmer f--ah, darryl. darryl.
<DisplayName>Darryl</DisplayName>

//Increase the damage, because darryl shouldn't have poison, and should have
//the ability to blow away small furry animals.
<Damage>20</Damage>

//Increase the health, because... reasons.
<Health>25</Health>

//traits, including attacks.
<Traits>

///We're swapping out the snake's venom attack for the ability to shoot stuff. Whee!
<Trait>pistolsquirrel</Trait>
<Trait></Trait>
<Trait></Trait>
<Trait></Trait>
</Traits>
...etc etc. Keep in mind that Traits aren't necessarily weapons. A trait might be associated with a weapon (like pistolsquirrel) but they will refer to the actual weapon. That is important to know especially if you want to create your own weapons, as you can bind additional parameters to the trait that don't fit the weapon scheme. An example for that is the sniper trait, which provides a normal unit with +4 vision. The trait itself holds the "+4 vision" part, while the weapon contains all the cooldowns and similar.

Ok, go ahead and save the file, and give it a run. The snake should now be named darryl, and have more health and damage, and attack like the squirrel.

Now, let's make the unit look a little different. I've created a new spritesheet for darryl, so if you want, you can use that. Put it in /textures/actors. Otherwise, modify one of the existing spritesheets.








To make this work, we'll have to change some stuff in the snake's xml file:

<ActorData>
etc, etc...
<Sprites>

//if you're using my darryl sprite, leave this the same. Otherwise, it needs to match
//whatever frame width and height you're using.
<Sprite FrameWidth="30" FrameHeight="30">

//Tells the game where your spritesheet is located. In this case, /textures/actors/darryl.png
<Texture Path="actors" Name="darryl"/>

//Wait, what?
//Don't worry. I'll get back to this later.
<TintMap Path="actors" Name="snake_tint"/>
<Animations>

//Animation frames start at 0. So, run starts at 0(the first one), and ends at 10(the 11th one.)
//We want the animation to run a little more slowly, so I switched frametime to 0.15
<Animation Name="run" StartFrame="4" EndFrame="10" FrameTime="0.15" Angle="0"/>
<Animation Name="run" StartFrame="4" EndFrame="10" FrameTime="0.15" Angle="1" Flip="true"/>

///Our standard standing animation starts at 0, ends at 3.
<Animation Name="idle" StartFrame="0" EndFrame="3" FrameTime="0.15" Angle="0"/>
<Animation Name="idle" StartFrame="0" EndFrame="3" FrameTime="0.15" Angle="1" Flip="true"/>

//same for attack
<Animation Name="attack" StartFrame="12" EndFrame="15" FrameTime="0.08" Angle="0" Loop="0" CanInterrupt="false"/>
<Animation Name="attack" StartFrame="12" EndFrame="15" FrameTime="0.08" Angle="1" Flip="true" Loop="0" CanInterrupt="false"/>
<Animation Name="attackidle" StartFrame="12" EndFrame="12" FrameTime="0.08" Angle="0" LoopCounter="0"/>
<Animation Name="attackidle" StartFrame="12" EndFrame="12" FrameTime="0.08" Angle="1" LoopCounter="0" Flip="true"/>

//death is set to a blank frame.
<Animation Name="death" StartFrame="17" EndFrame="17" FrameTime="0.1" Angle="0" PauseOnComplete="true" CanInterrupt="false"/>
<Animation Name="death" StartFrame="27" EndFrame="17" FrameTime="0.1" Angle="1" Flip="true" PauseOnComplete="true" CanInterrupt="false"/>
</Animations>

//pivot changes the point at which the unit... pivots. :p
<Pivot>15,23</Pivot>
</Sprite>
</Sprites>
...etc etc

Go ahead and run it. Check out the snazzy new sprites! ...but wait... there's a snake underneath them. That's because we didn't specify a tint map. The tint map shows which places get switched to team colors. For the snake, it's the whole snake, meaning that it still displays.

So, we can specify the tint map. (if you don't want to, you can just specify a blank image.) This goes in the same directory as the main sprite sheet.








We also need to change the xml file:
<TintMap Path="actors" Name="darryl_tint"/>

Give it a try! Everything should be working. Hopefully.


But, now we want a little more. We want Darryl to show up on the unit roster, instead of snakes. Everyone knows darryl isn't a snake!

So, we need to create a pog for him. This apparently does not mean "presentation on GUI", but is rather---a digression. Never mind. Have a pog image, or create your own:



...and a blank team color tint pog:



Now, we go into the structure for the unit we're replacing. In my case, it's the factory_snake.
<StructureData>

//Darryl isn't named snake. Name him something else.
<DisplayName>Darryl</DisplayName>

//A description for the unit card.
<Description>"Let's go skunk hunting!"</Description>

//The strategy hint may pop up when the unit is discovered.
<StrategyHint>Don't try to fight darryl. Just don't.</StrategyHint>

//Here are the pogs. Replace these, and you should be able to view darryl in all his pixelly glory ingame.
<PogTexture Path="ui/pogs" Name="unit_darryl_pog"/>
<PogTint Path="ui/pogs" Name="unit_darryl_pog_tint"/>


Now, we want to give Darryl A portrait. Here's one:





















...and, we put it in /texutres/UI/portraits, then modify the XML file:
<Portrait Path="ui/portraits" Name="darrylPortrait"/>


//remove this line. We don't need a tint.
<PortraitHueMask Path="ui/portraits" Name="snake_tint"/>

Give it a run!
Unit(Actor) specs
<?xml version="1.0" encoding="utf-8" ?>
<ActorData>

//What the unit's name is when shown to the player
<DisplayName>Stabby Lizards</DisplayName>

//damage, duh
<Damage>15</Damage>

//health, duh
<Health>10</Health>

//Unit attributes. (Swift, rifle, etc.)
//This is slightly deceptive--some traits,
//like attacks, may be per-unit.
//
//WARNING: don't add conflicting traits--like
//multiple attack types
<Traits>
<Trait>meleelizard</Trait>
<Trait>swift</Trait>
<Trait></Trait>
<Trait></Trait>
</Traits>

//Represents whether or not this unit can be built outside of your territory
<CanProxy>false</CanProxy>

//Changes AI.
//1 tries to stick the unit up front--where they can stab things and be stabbed.
//2 tries to stick the unit in back, where they can shoot and get shot.
<FormationPriority>1</FormationPriority>

//defines length that corpse stays on ground.
//Currently unused.
<DecayTime>0</DecayTime>

//Unusued
<Icon Path="character_icons" Name="icon_lizard"/>

//Unused
<EntitySoundPrefix>event:/sfx/unit/actors/test_</EntitySoundPrefix>

//Amount of time between dust particles when walking
<FootstepInterval>0.2</FootstepInterval>

//How high above the unit the health bar sits
<HealthBarYOffset>17</HealthBarYOffset>

//Lots of display and animation stuff
<Sprites>

//How wide/tall the unit is in a unit's spritesheet
<Sprite FrameWidth="32" FrameHeight="32">

//...where is the animation, exactly? Oh, here!
<Texture Path="actors" Name="lizard"/>

//each unit's frames needs a matching tint, to change side colors
<TintMap Path="actors" Name="lizard_tint"/>

//Animations.
<Animations>
//note: angle 0 is
<Animation Name="idle" StartFrame="0" EndFrame="3" FrameTime="0.2" Angle="0"/>
<Animation Name="idle" StartFrame="0" EndFrame="3" FrameTime="0.2" Angle="1" Flip="true"/>
<Animation Name="run" StartFrame="4" EndFrame="9" FrameTime="0.08" Angle="0"/>
<Animation Name="run" StartFrame="4" EndFrame="9" FrameTime="0.08" Angle="1" Flip="true"/>
<Animation Name="attackidle" StartFrame="10" EndFrame="10" FrameTime="0.08" Angle="0" LoopCounter="0"/>
<Animation Name="attackidle" StartFrame="10" EndFrame="10" FrameTime="0.08" Angle="1" Flip="true" LoopCounter="0"/>
<Animation Name="attack" StartFrame="11" EndFrame="18" FrameTime="0.08" Angle="0" Loop="0" CanInterrupt="false"/>
<Animation Name="attack" StartFrame="11" EndFrame="18" FrameTime="0.08" Angle="1" Flip="true" Loop="0" CanInterrupt="false"/>
<Animation Name="death" StartFrame="19" EndFrame="19" FrameTime="0.08" Angle="0" PauseOnComplete="true" CanInterrupt="false"/>
<Animation Name="death" StartFrame="19" EndFrame="19" FrameTime="0.08" Angle="1" Flip="true" PauseOnComplete="true" CanInterrupt="false"/>
</Animations>

//Gives the game the "center" of the object
<Pivot>16,29</Pivot>

</Sprite>
</Sprites>

//changes how the unit behaves. We're not going to touch this atm.
<Behaviors>
<Formation TargetDistance="10000" DestinationTolerance="0.1" TargetWeapon="true"/>
<Idle/>
</Behaviors>
<Events>
<Event Type="OnDamage">
<Scope>
<Action Type="ResetHealTimer"/>
</Scope>
</Event>
<Event Type="OnHealTimer" Time="10">
<Scope>
<Action Type="HealPerSecond" Value="0.5"/>
</Scope>
</Event>
<Event Type="OnDeath">
<Scope>
<Action Type="CreateParticleSystem" Data="UnitDeathSmallPSystem"/>
<Action Type="PlaySound" Data="event:/sfx/unit/shared/deathsplat_sml" Value="1"/>
<Action Type="PlayEntitySound" Data="death" Value="1"/>
</Scope>
<Scope Target="Other" TargetWithinAggroRange="true">
<Action Type="PlayEntitySound" Data="victory" Value="1"/>
</Scope>
</Event>
<Event Type="OnSpawn">
<Scope LocalPlayerOnly="true">
<Action Type="PlayEntitySound" Data="complete" Value="1"/>
<Action Type="CreateParticle" Data="UnitSpawnEmitter"/>
</Scope>
</Event>
<Event Type="OnSold">
<Scope LocalPlayerOnly="true">
<Action Type="CreateParticle" Data="UnitSoldEmitter"/>
</Scope>
</Event>
<Event Type="OnBattlecry">
<Scope>
<Action Type="PlayEntitySound" Data="battlecry" Value="1"/>
</Scope>
</Event>
<Event Type="OnKill">
<Scope>
<Action Type="PlayEntitySound" Data="victory_minor" Value="1"/>
</Scope>
</Event>
<Event Type="OnFidget">
<Scope TargetLocalPlayer="true">
<Action Type="PlayVocalSound" Data="idle" Value="1"/>
</Scope>
</Event>
<Event Type="OnSalute">
<Scope TargetLocalPlayer="true">
<Action Type="PlaySingleVocalSound" Data="idle" Value="1"/>
</Scope>
</Event>
<Event Type="OnFootstep">
<Scope>
<Action Type="CreateFootstepParticle" Data="FootstepEmitter"/>
</Scope>
</Event>
</Events>
</ActorData>
Structure (Factory and Defensive) spect
<?xml version="1.0" encoding="utf-8" ?>
<StructureData>

//Name shown to players
<DisplayName>Spitty Snakes</DisplayName>

//Description given in deck editor/on unit card
<Description>"So Spitty!"</Description>

//Strategy hint on first discovery
<StrategyHint>Don't let them bite you or else!</StrategyHint>

//Shows discovery message? Note: for defensive structs, maybe not. :)
<DiscoverMessage>true</DiscoverMessage>

//shown in deck editor?
<HideInDeckEditor>false</HideInDeckEditor>

//tier. Determines both cost and unit cost.
<Tier>2</Tier>

//How much territory is granted
<TerritoryRadius>0</TerritoryRadius>

//whether or not pathing is blocked through occupied tile
<BlockMovement>false</BlockMovement>

//changes perceived unit height when unit is on factory
<StandingHeight>1</StandingHeight>

//which tiles are contained by the structure
<CollisionTiles>
<Tile>0,0</Tile>
<Tile>0,1</Tile>
<Tile>1,0</Tile>
<Tile>1,1</Tile>
</CollisionTiles>


<EntitySoundPrefix></EntitySoundPrefix>

//portrait paths
<Portrait Path="ui/portraits" Name="snake"/>
<PortraitHueMask Path="ui/portraits" Name="snake_tint"/>

//changes where portrait is displayed
<PortraitOffset>400,600</PortraitOffset>
<ADPortraitOffset>456, 560</ADPortraitOffset>
<ADPortraitScale>0.95</ADPortraitScale>

//changes what the unit looks like in the army pallete
<PogTexture Path="ui/pogs" Name="unit_snake"/>
<PogTint Path="ui/pogs" Name="unit_snake_tint"/>

//changes where health bar is displayed
<HealthBarYOffset>13</HealthBarYOffset>

//animation stuff
<Sprites>
<Sprite FrameWidth="56" FrameHeight="38" IsDecal="true">
<Texture Path="structures" Name="factory_manhole_tier2"/>
<TintMap Path="structures" Name="factory_manhole_tier2_tint"/>
<Animations>
<Animation Name="idle" StartFrame="0" EndFrame="0" FrameTime="0.1"/>
<Animation Name="offline" StartFrame="0" EndFrame="0" FrameTime="0.1"/>
<Animation Name="constructionStage0" StartFrame="1" EndFrame="1" FrameTime="0.1"/>
<Animation Name="constructionStage1" StartFrame="2" EndFrame="25" FrameTime="0.1" PauseOnComplete="true" CanInterrupt="false">
<Events>
<Event Type="OnFrame" Time="2">
<Scope>
<Action Type="StopPersistentSound" Data="event:/sfx/unit/structures/shared/buildloop_tunnel"/>
<Action Type="PlaySound" Data="event:/sfx/unit/structures/t2/build_sequence"/>
<Action Type="RemoveAttachedParticles"/>
</Scope>
</Event>
</Events>
</Animation>
<Animation Name="unitProduced" StartFrame="25" EndFrame="30" FrameTime="0.1" CanInterrupt="false"/>
<Animation Name="death" StartFrame="31" EndFrame="31" FrameTime="0.1" PauseOnComplete="true" CanInterrupt="false"/>
</Animations>
<Pivot>29,18</Pivot>
</Sprite>
</Sprites>




//THIS IS IMPORTANT
<Behaviors>
//Changes what the building produces
<Production ProductionData="snake" MaxSpawnedAtOnce="2"/>
</Behaviors>
<Events>
<Event Type="OnDamage">
<Scope>
<Action Type="ResetHealTimer"/>
</Scope>
</Event>
<Event Type="OnHealTimer" Time="10">
<Scope>
<Action Type="HealPerSecond" Value="0.5"/>
</Scope>
</Event>
<Event Type="OnProduce">
<Scope LocalPlayerOnly="true">
<Action Type="PlaySound" Data="event:/sfx/unit/structures/t2/onproduce"/>
</Scope>
</Event>
<Event Type="OnDeath">
<Scope>
<Action Type="RemoveAttachedParticles"/>
<Action Type="CreateParticleSystem" Data="expStructurePSystem"/>
<Action Type="ScreenShake" Attenuation="50" Value="2" Time="0.5"/>
<Action Type="PlaySound" Data="event:/sfx/unit/structures/t2/shared/destroy"/>
</Scope>
</Event>
<Event Type="OnRefundTimerComplete">
<Scope>
<Action Type="PlayPersistentSound" Data="event:/sfx/unit/structures/shared/buildloop_tunnel"/>
<Action Type="PlaySound" Data="event:/sfx/unit/structures/shared/confirmed_main" Value="1"/>
<Action Type="RemoveAttachedParticles"/>
<Action Type="CreateParticleSystem" Data="structureBuildStartPSystem" Offset="0,0,0" Attach="true" InheritPosition="false"/>
<Action Type="CreateParticleSystem" Data="structureBuildStartPSystem" Offset="1,0,0" Attach="true" InheritPosition="false"/>
<Action Type="CreateParticleSystem" Data="structureBuildStartPSystem" Offset="0,0,1" Attach="true" InheritPosition="false"/>
<Action Type="CreateParticleSystem" Data="structureBuildStartPSystem" Offset="1,0,1" Attach="true" InheritPosition="false"/>
</Scope>
</Event>
<Event Type="OnBuildComplete">
<Scope>
<Action Type="PlaySound" Data="event:/sfx/unit/structures/shared/complete_main" Value="1"/>
<Action Type="RemoveAttachedParticles"/>
<Action Type="CreateParticleSystem" Data="structureBuildEndPSystem" Offset="0,0,0"/>
<Action Type="CreateParticleSystem" Data="structureBuildEndPSystem" Offset="1,0,0"/>
<Action Type="CreateParticleSystem" Data="structureBuildEndPSystem" Offset="0,0,1"/>
<Action Type="CreateParticleSystem" Data="structureBuildEndPSystem" Offset="1,0,1"/>
</Scope>
</Event>
<Event Type="OnSold">
<Scope LocalPlayerOnly="true">
<Action Type="PlaySound" Data="event:/sfx/general/build_sell"/>
<Action Type="CreateParticleSystem" Data="structureSoldPSystem"/>
</Scope>
</Event>
</Events>
<Tiles>
<Tile>0,1</Tile>
<Tile>1,0</Tile>
<Tile>1,1</Tile>
</Tiles>
</StructureData>
21 Comments
EELuminatus  [developer] 30 Mar, 2019 @ 2:22am 
Yes, data modding works flawlessly on Mac (and Linux), and you can use the same files that are used on Windows.

Only modding the executable file would be slightly different (but still possible).
Lord 29 Mar, 2019 @ 2:28pm 
does this work for mac?
EELuminatus  [developer] 11 Feb, 2019 @ 9:32pm 
As you say, content has meanwhile been split into core, singleplayer, and multiplayer.
Singleplayer is only relevant for the campaign, whereas multiplayer contains the data for both online and offline games. From there, everything should work as described: e.g. for giving Toads 12 HP, you go to content\data\multiplayer\actors\t1\toad.xml and change their Health.

There are a few values where changes won't have an effect, like Boar Damage (because fire damage is defined elsewhere). So if your changes still don't work: please tell what exactly you tried... there are a few special cases.

Also: such changes only get read when the game starts.
OrbitalDropGuy4 11 Feb, 2019 @ 1:46pm 
Hey. I have a question; You said to just go to data/actors to make changes. The files are displayed as data/actors: Core, Singleplayer, Multiplayer, then there's commanders and other. I'm unsure as to which folder I should go to to mod the units. The part of the game i'm trying to mod is just the multiplayer and offline and whenever I make changes to the scripts for the units, say health, name or damage, it won't make any changes. How would I fix this if possible?
ALE199 21 Oct, 2017 @ 9:18am 
Now we just need a site were modders post theyr mods!
Youthful Idealism  [author] 17 Oct, 2017 @ 6:15am 
Thanks. I'll try to get around to changing the guide text soon.
J Moldy 17 Oct, 2017 @ 6:12am 
While trying to mod this, I found that they made two separate directories under the content\data file: singleplayer and multiplayer. The data that had been in various folders is now duplicated into each of those folders.
Youthful Idealism  [author] 19 Sep, 2017 @ 7:35am 
I could be wrong, but it looks to me that the only way to change a unit's vision are to add the flying or sniper traits.
Doki 19 Sep, 2017 @ 4:37am 
Cheat List (Offline Only, be sure to enable cheats in the options menu)
H - Toggle Hud
` - Stats
O - Spectate
I - Units Invulnerable
P - Predict Motion Toggle
Enter - Switch Commander
+ - Starve
J - Commanders Invulnerable
. - Reveal Map
Home - Give 5000 food
Page Up - Heal Commanders
Page Down/ Delete - Remove all Food
End - Complete Construction
Insert - Toggle Rally

(Be sure to let me know if you discover others)
Raskolnikov 19 Sep, 2017 @ 4:36am 
change the vision of each unit. Sorry for my english :)