News:

Welcome to the new Sinister Design forums!

Main Menu

Question on Attacks in Custom Campaigns

Started by Sonicjumper, March 08, 2015, 07:01:34 PM

Previous topic - Next topic

Sonicjumper

I'm creating a new attack for my campaign in the Attacks.xml file, called "dream". It's a mental attack that deals omnidirectional mental damage and heals the user, however I cannot figure out how to put both functions into the same attack. If a make an attack like "Feedback", a "Mental" element attack with the selfHealFactor variable equal to 1, the attack will heal the character, but then the attack will not do any damage unless the caster is damaged(same as Feedback). If I make the attack a "Shield" element, then the attack will heal whoever it targets, not damage them. I need some way to both deal damage and heal the caster in the same attack, with both functions independent of each other(meaning the damage isn't dependent on how much it heals, and the healing isn't dependent on how much damage is dealt).

Here is my current attack in the XML file, any pointers on what to do?
[spoiler]
<Atk elem="Mental" name="Dream" d="0" cst="1" minRng="0" maxRng="0" shkMag="0" shkTim="0" strD="0" powD="2" defD="0" backstabFactor="1" sidestabFactor="1" selfHealFactor="0.5" selfFocusFactor="0" accMod="0" statFX="None" affects="Health" afterAtk="EndTurn" AOE="omnidirectional" particles="Sparks" targeting="constrained" moveType="Normal" knockback="0" creates="" createdOnTeam="" dependsUpon="" impactFrame="-15" soundAndFX="SFX[Charge Up:0],SFX[Mind Blast:8],VFX[MindBlast:OnSelf:12]" desc="Focus your inner strength to deal damage and heal yourself."></Atk>
[/spoiler]

bugfartboy

#1
The character using Dream in the following example will have the class "Hero".  I've thought about something like this in the past myself, and after some tinkering, here's the solution I came up with:

Assuming the character you want to use Dream has a unique class (such as Hero) you can use your Dream attack with a small modification to the attack, and a small modification to the character that uses it.


<Atk elem="Mental" name="Dream" d="0" cst="1" minRng="0" maxRng="0" shkMag="0" skhTim="0" strD="0" powD="2" defD="0" backstabFactor="1" sidestabFactor="1" selfHealFactor="0" selfFocusFactor="0" accMod="0" statFX="None" affects="Health" afterAtk="CanMove" AOE="3x3" particles="Sparks" targeting="constrained" moveType="Normal" knockback="0" creates="" createdOnTeam="" dependsUpon="" impactFrame="-15" shoundAndFX="SFX[Charge Up:0],SFX[Mind Blast:8],VFX[MindBlast:OnSelf:12]" desc="Focus your inner strength to deal damage and heal yourself."></Atk>

By changing the AOE to 3x3, we ensure that the caster gets targeted as well.

Whether we do it by way of an item that only they can equip, or adding it directly to them in CharClasses.xml, we then add the tag:
ModDmgForClass,*:-1:Hero
to the caster. I did this by adding the tag to an item, then equipping the item.

<Item name="Magic Keys" useableWith="Weapon Hand" requirements="c:Hero" endsStatus="" addsStatus="" grantsAtk="Dream" consumedAfter="10" fxLast="0" hpPlus="0" pspPlus="0" maxHPPlus="0" maxPsPPlus="0" spdPlus="0" dodgePlus="0" strPlus="0" perPlus="0" psyPPlus="0" psyDPlus="0" prcResPlus="0" slshResPlus="0" crshResPlus="0" mnResPlus="0" htResPlus="0" cdResPlus="0" ltResPlus="0" shResPlus="0" poiResPlus="0" accPlus="0" ctrLimitPlus="0" commonality="5" addsTags="ModDmgForClass,*:-1:Hero" image="Lockpicks" description="Reverse Damage to the Hero"></Item>



There are some caveats to this method, however:
1.   Due to how the game processes damage, it is possible for a character's health to be raised past its maximum with this ability.  This alone makes this method undesirable unless Craig modifies the game to enforce the health maximum against negative damage.
2.   The tag we added will affect all attacks against any character with that specific class.  If I had two "Hero"s on a map, and had one mind-blast the other it would heal them instead of damaging them.  This can be averted by assigning unique IDs to characters you want to use dream and using
ModDmgForTag,*:-1:ID[701]where ID[701] is a tag that points towards the Hero class.  This will allow multiple characters of class "Hero" on a map, but will only affect a specific Hero as long as it is defined separately in CharClasses.xml.


I know I kind of rambled, so if you have any questions feel free to ask and I'll do what I can to clarify.

Sonicjumper

#2
That's pretty much exactly what I was looking for, some way to "identify" the user so they heal instead of take damage. If the bug with raising above the maximum health doesn't get fixed I'll find a new method, maybe just a different action that heals separately. I've tried adding the tag to the CharClass xml and here's what I have.


<Char charname="Young/Tidus" spritetype="VillagerBoy" portrait="Villager Child_M" race="Human" sex="Male" classname="Dreamer" move="land" hurtParticle="Sparks" shadowType="Small" shadowY="32" charY="16" lighting="" ctr="Sword" onDeath="None" defaultAtkAnim="Cast" atk1="Dream" atk2="" atk3="" atk4="" atk5="" atk6="" atk7="" atk8="" hp="22" en="10" spd="4" ctrLimit="1" dodge="0" str="0" per="5" psyP="4" psyD="4" prcRes="0" slshRes="0" crshRes="0" mnRes="0" htRes="0" cdRes="0" ltRes="0" shRes="0" poiRes="0" acc="100" lvl="1" exp="0" pushable="true" tags="ModDmgForClass,*:-1:Dreamer">


And even without using the class dependency, another working solution(and probably better for what I want) is:

<Char charname="Young/Tidus" spritetype="VillagerBoy" portrait="Villager Child_M" race="Human" sex="Male" classname="Dreamer" move="land" hurtParticle="Sparks" shadowType="Small" shadowY="32" charY="16" lighting="" ctr="Sword" onDeath="None" defaultAtkAnim="Cast" atk1="Dream" atk2="" atk3="" atk4="" atk5="" atk6="" atk7="" atk8="" hp="22" en="10" spd="4" ctrLimit="1" dodge="0" str="0" per="5" psyP="4" psyD="4" prcRes="0" slshRes="0" crshRes="0" mnRes="0" htRes="0" cdRes="0" ltRes="0" shRes="0" poiRes="0" acc="100" lvl="1" exp="0" pushable="true" tags="ID[500], ModDmgForTag,*:-1:ID[500]">


Though I am not sure how to do multiple tags, since I can't find an example of it in the game's campaign. My worry about this method is that any damage inflicted on the user will actually heal, though in this instance it isn't a problem because this character doesn't ever have any other skills.

Edit: I noticed using a combination like you suggested, an ID on my character and the ModDmgForTag,*:-1:ID[500] on the skill, would cause only that skill to have the modified damage, not all damage caused by that character.

Edit of the Edit: I can't seem to add a tag like this to my attack, or is the "addsTags" just for items:

addsTags="ModDmgForTag,*:-1:ID[500]"

Sonicjumper

An additional feature I am trying to implement in my campaign: my basic idea is that a certain character has several abilities that allow him to "transform" into another creature with certain abilities and stats(and a different sprite of course). Several different transformations exist, and he needs to be able to "save" his stats between transformations(will still have same health, energy, resistance, etc.). Since I don't have the map editor I'm missing a lot of the "Dialog" part of the campaign, but here's my attempt at a solution:

Since there is no way for an attack to directly change the class, appearance, or other attacks of a character, I found the "Dialog" section of the manual, with which I can set triggers and use them to run scripts which change my character.

One such trigger, called "OnAttackSelect" can be used to watch for a specific attack to be used(this attack is specific to the character using it), and run a script containing several actions as follows:

There is an action called "ChangeCharClass nameOfChar,nameOfClass,nameOfSprites" which can be used to change the name and appearance of the character. Another action, "TeachAttack" can teach an Attack to a character. A third action, "SetStat" can be used to modify or set the health, energy, etc. of the character in case the transformation adds some stat bonus.

Possible issues with this method seem to be that there is no way to "remove" an attack from a character, at least not with any actions I have looked over. For anyone who has some experience working with scripts/dialog actions, do you think this method will work successfully? Are there any other problems that I'm not seeing that could be an issue?

bugfartboy

#4
I've thought of this before as well. Although I haven't gotten around to testing it, my idea for that is to have a set of character specific items that grant those transformation attacks, each with a durability of 1. You could then set up a dialog tree that runs every time it's the player's turn and check if they have a transformation active and if they have all of the items. When the attack is selected, scripts run and update tracking variables and apply the needed transformations.

I'll update this with details later, when I'm on my computer with all of my WIPs and scripts.

Now, the scripts themselves to determine if a character has the items they should are pretty straightforward.  We have the "IfItemGoTo" and "IfItemRun" dialog actions that do this for us.  But how do we determine whether or not it's the player's turn?  Simple, really:

<Dialog branch="0" r="-1">
   OnTurn/-TURN-/Information/
   <Action>IfStatRun/Hero,Done,=,0,PlayersTurn</Action>
   <Action>IfStatRun/Hero,Done,=,1,AIsTurn</Action>
   <Action>CheckForMoreDialog/</Action>
   <Reply>.../CheckForMoreDialog/</Reply>
</Dialog>

Let's break this down:
   As you might know from the manual, when -TURN- is used in dialog, it gets replaced with the integer value of the current turn, with the first turn being a value of 0. Thus, by telling the dialog tree to run whenever -TURN- equals itself, we get dialog tree that runs every single time -TURN- updates.

   But how do we know it's the player's turn? Take a look at the "IfStatRun" actions in the example above. This only works if you have a character that you know will appear in every map, and must be kept alive throughout the entire game.  Whenever a character finishes (whether it be by attacking with an "EndTurn" or "CanMove" attack or by simply clicking "Done" or "End Turn") that character's "Done" stat gets bumped up to 1. When a new turn rolls around, it gets reset to 0.  When the "Done" stat is at whatever point we need we can run whatever scripts we want.

   Now regarding the items, keep in mind that it is possible to run scripts whenever an item is used or equipped by listing a script name between the <Item></Item> tags. My example for you here is

<Item name="Azure Orb" useableWith="Back" requirements="c:Hero" endsStatus="" addsStatus="" grantsAtk="" consumedAfter="0" fxLast="0" hpPlus="0" pspPlus="0" maxHPPlus="0" maxPspPlus="0" spdPlus="0" dodgePlus="0" strPlus="0" perPlus="0" psyPPlus="0" psyDPlus="0" prcResPlus="0" slshResPlus="0" crshResPlus="0" mnResPlus="0" htResPlus="0" cdResPlus="0" ltResPlus="0" shResPlus="0" poiResPlus="0" accPlus="0" ctrLimitPlus="0" commonality="1" addsTags="" image="Orb Azure" description="Grants flight when equipped">Use Azure Orb</Item>

Any time my character with the class "Hero" equips or dequips the Azure Orb item, the "Use Azure Orb" script is called.  For convenience I keep it in PersistentDialog.xml. The script "Use Azure Orb" looks like this:

<Script>
   Use Azure Orb
   <Action>SetVal/AOrbActive,=,-VAL:AOrbActive-</Action>
   <Action>IfValRun/AOrbActive,=,1,AOrbto2</Action>
   <Action>IfValRun/AOrbActive,=,0,AOrbto1</Action>
   <Action>IfValRun/AOrbActive,=,2,AOrbto0</Action>
</Script>
<Script>
   AOrbto2
   <Action>SetVal/AOrbActive,=,2</Action>
</Script>
<Script>
   AOrbto1
   <Action>SetVal/AOrbActive,=,1</Action>
   <Action>SetStat/Hero,MoveType,=,0,flying</Action>
</Script>
<Script>
   AOrbto0
   <Action>SetVal/AOrbActive,=,0</Action>
   <Action>SetStat/Hero,MoveType,=,0,land</Action>
</Script>

Now let's break this one down.
   The first action sets "AOrbActive" equal to itself.  This is a little trick I picked up to ensure that a variable is initialized before you ever use it. I learned the hard way that "IfVal" actions don't work if the variable in question hasn't been set to something before. Fortunately if a variable get's called by its normal -VAL:- method, it always returns a number! This is important because when an uninitialized variable is called, it defaults to 0 This means we ensure that "AOrbActive" is set to something before we ever use it.

   The next three actions all run dependent on the results of the first.  It's fairly self-explanatory, but I'll elaborate anyway.  "AOrbActive" has a binary state, 1 or 0, on or off, true or false.  But it also has a temporary state "2". 

       
  • The first time a player equips the orb, "AOrbActive" will be 0 by default.  This means that "AOrbto1" gets called, setting the variable to 1 and changing the Hero's movetype to flying.  This is all that happens this pass.
  • When the player dequips the orb, the "Use Azure Orb" gets run again.  This time "AOrbActive" is 1, or true.  Now the script "AOrbto2" gets called.  Why?  Logic.  If we simply set the variable directly to 0, it will trip the "AOrbto1" script again, and nothing will change.  And if we put the action to set it to 1 after setting it to 0 we'll hit the same problem.  But by setting it to 2 we bypass the script that would set it to 1, and THEN we set it to 0 and change the movetype of the Hero.
By using this method we can track when an item is equipped or not.  But it doesn't have to be specific to one person.  We can use -FNAME- in place of "Hero" and suddenly anyone who can equip the orb gains flight when they use it.

This is just one example of what we can do by using items!  Instead of simply granting a character flight, we can do most, if not all, of the things you want to do with scripting!  We can change the user's class, name, movetype, health, energy, damage, drain, sprite, etc all when an item is used or equipped.  What's more is we can set all of these magical transformation items to use the same equip slot so that none of them try running at the same time.  We could have a basic "Human Form" item that grants the character the stats and abilities they'd have as a human, and then every other "Form" item would replace those attacks and stats.  I strongly advise against using "TeachAttack" and "TeachAttackTemp".  They seem friendly, but there is NO way to teach a character an attack for anything less than a single map.  Items are the way to go on that front.

That's all I've got for you tonight.  I've got a paper due Friday that I haven't started on yet, and I really need some sleep.  As always, if you need any ideas or concepts refined or clarified let me know.  I've been playing around with this stuff long enough that I'm slowly starting to get the hang of it, although I certainly bugged Craig for help more than I care to admit when I was starting out, and I'm more than happy to help out!


P.S.
I really only started looking at the power that item-triggered scripts wield a few days ago.  When you think about it, the amount of power over Telepath Tactics given to modders and content creators is actually astounding.  If you have the mind for it, the only thing you can't do is change the engine itself!  I love it!

bugfartboy

#5
I got bored during class this afternoon and decided to try it out.  I put together a campaign that demonstrates how you can change one unit's appearance and abilities with scripts.  A bit of a warning: sometimes the character sprite will NOT update, but everything else updates correctly.  As far as I can tell, the sprite doesn't update correctly if the player switches disguises too quickly.  Good news is it does change Phillip Suave back to his default sprite, instead of leaving him blank.



DOWNLOAD IT HERE


As always: If you have any questions regarding how I did this, just ask! I'm happy to help.

-EDIT: Strike-through added, as download is no longer available.-

Sonicjumper

Thanks, I can always look at the XMLs to find out how you did certain things.

I decided to try it out as well, and basically extended the capability of the Azure Orb item. The only problem I found is that if I changed the class of the character then the item would not be equipped, but changing the class is an unnecessary detail. I may adapt the script you wrote for your "spy" character to fit the purposes of my "dreamer", if that's alright. I'm pretty much satisfied with this way to transform a character, some things I might want to implement in the future will be stat changes based on current character level, and other graphical effects while changing.

One question about your script, how does this line work?

<Script>
Add Disguise
<Action>SetString/CurrChar,-FNAME-</Action>
...
</Script>


I understand that you need to save the current character's name as a variable, to reference it later when changing stats and sprites and such, but how does -FNAME- know to get the specific name of the character that is changing disguise?

bugfartboy

Of course you can use it! I wouldn't have posted it if I didn't want that to happen.

Quote
The only problem I found is that if I changed the class of the character then the item would not be equipped, but changing the class is an unnecessary detail.
Yeah, that's the one drawback I can think of.  But you can also add the classes of the creatures your Dreamer will transform into to the list of acceptable classes.  It would look like: requirements="c:Dreamer,Thing1,Thing2,Etc"in ItemClasses.xml.

Section D. Dialog, Special Characters in Dialog Text lists all of the special characters that can be used almost everywhere within dialog.  One such place is actions and scripts.  -FNAME- represents the full name of the character that triggered that particular dialog or script instance.  This means that "CurrChar" gets set to whoever triggered the disguise script.


Excerpt from the Manual:
Quote

10. typing -FNAME- will substitute the full name of the character who triggered the dialog
(for dialog which is character-triggered).

I should note, however, that "CurrChar" is wholly unneeded and can be replaced by -FNAME- at every point in the Disguise Script.  The only reason I used "CurrChar" is in case I wanted to extend the abilities of the script beyond a single turn.  But that's just my preference.

Sonicjumper

I tinkered around with the script some more, playing with the variables that will "change" upon transformation, like disMaxHealth(named formMaxHealth in my script). You can implement a form of multiplication by using multiple Action blocks, since in-line arithmetic doesn't seem to like working(Ex. <Action>SetVal/formMaxHealth,=,5*-STAT:-FNAME-,Level-</Action>)

Example of working version:

<Action>SetVal/formMaxHealth,=,5</Action>
<Action>SetVal/formMaxHealth,*,-STAT:-FNAME-,Level-</Action>


However, one issue I found with doing this is that if you equip the item(and transform), then level up, then revert back, it will cause you to lose some total max health because when the script calculated the max health to revert you it used a different level.

Ex. Tidus is lvl 1 and equips the transform item. His MaxHealth raises by lvl*5 from 10 to 15. He then levels up, and then removes the item, causing his MaxHealth to lower by lvl*5 from 15 to 5.

To counter this problem I set up my Scripts to only calculate the values to change when entering the form, not when reverting, so the already stored values of formMaxHealth will be used.

Here's the new script(adapted from your "Swordsman Disguise" script):
http://pastebin.com/E9wC16ne

This ensures that the exact values used to transform the unit are used to undo those changes.

bugfartboy

Hey, whatever works dude/dudette.  The disguise scripts were just a proof-of-concept that I threw together.  They're entirely open to be changed and re-written however needed.  I'm just excited to see someone else on the forum taking an open interest in the modding side of the game! :D  Is there anything else you might need help with/ideas for?

Sonicjumper

I don't have the map editor yet, but when the full game comes out and I get my hands on it I will be making my own campaigns. In the meantime I'll be writing the story and working on custom attacks, items, and images for characters.

This really is a great game in terms of modding capability, so I'm going to be doing a lot with it in the future.