Aller au contenu

Photo

Tag Based Grenade Script


  • Veuillez vous connecter pour répondre
23 réponses à ce sujet

#1
henesua

henesua
  • Members
  • 3 863 messages
I liked the idea of creating potion grenades so I implemented a tag based system. You can use it too, if you follow these steps:
  • Implement tag based scripting.
  • Import the scripts listed below and adjust them to work in your module
  • change name of do_grenade: "do_" prefix should be your tag based prefix
  • write your own custom grenade behavior based on my aa_ex_trueform
  • Create a grenade object with the tag: grenade
  • Give the grenade the Property CastSpell(Unique)
  • Add a Local Var String to the Grenade which is the name of the script defining the grenade effect
Scripts
Tag Based Grenade Script
Example Grenade Script

Modifié par henesua, 12 juillet 2012 - 03:24 .


#2
GhostOfGod

GhostOfGod
  • Members
  • 863 messages
Awesome idea and implementation!

#3
Rolo Kipp

Rolo Kipp
  • Members
  • 2 791 messages
<dodging...>

And Carcerian made such great grenade icons (about 2/3rds down) for the May CCC - New Weapons :-)

Um... be careful with that thing, H. I thing this is the pin...

<...bullets>

#4
henesua

henesua
  • Members
  • 3 863 messages
I already see a flaw in this system as it doesn't preserve resources. All I have done is provide a framework that reduces duplication of code. I may modify my do_grenade script to contain the different kinds of special grenades.

#5
Shadooow

Shadooow
  • Members
  • 4 470 messages
not bad idea, yet it seems to me the tag-checking approach much better

void main()
{
int nSpell = GetSpellId();
object oItem = GetSpellCastItem();
string sTag = GetTag(oItem);
 if(sTag == "x2_it_acidbomb")
 {
 DoGrenadeBomb(6,10,1, VFX_IMP_ACID_L, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ACID,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(AOE_PER_FOGACID), GetSpellTargetLocation(), RoundsToSeconds(5));
 }
 else if(sTag == "x2_it_firebomb")
 {
 DoGrenadeBomb(6,10,1, VFX_IMP_FLAME_M, VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectAreaOfEffect(AOE_PER_FOGFIRE), GetSpellTargetLocation(), RoundsToSeconds(5));
 }
 else if(sTag == "sh_firebomb001")
 {
 DoGrenadeBomb(4,1,1,VFX_IMP_FLAME_S,VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_firebomb002")
 {
 DoGrenadeBomb(6,1,1,VFX_IMP_FLAME_S,VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_firebomb003")
 {
 DoGrenadeBomb(8,1,1,VFX_IMP_FLAME_M,VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_firebomb004")
 {
 DoGrenadeBomb(10,1,1,VFX_IMP_FLAME_M,VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_acidbomb001")
 {
 DoGrenadeBomb(4,1,1, VFX_IMP_ACID_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ACID,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_acidbomb002")
 {
 DoGrenadeBomb(6,1,1, VFX_IMP_ACID_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ACID,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_acidbomb003")
 {
 DoGrenadeBomb(8,1,1, VFX_IMP_ACID_L, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ACID,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_acidbomb004")
 {
 DoGrenadeBomb(10,1,1, VFX_IMP_ACID_L, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ACID,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_elebomb001")
 {
 DoGrenadeBomb(4,1,1,VFX_IMP_LIGHTNING_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ELECTRICAL,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_elebomb002")
 {
 DoGrenadeBomb(6,1,1,VFX_IMP_LIGHTNING_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ELECTRICAL,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_elebomb003")
 {
 DoGrenadeBomb(8,1,1, VFX_IMP_LIGHTNING_M, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ELECTRICAL,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_elebomb004")
 {
 DoGrenadeBomb(10,1,1,VFX_IMP_LIGHTNING_M, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_ELECTRICAL,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_coldbomb001")
 {
 DoGrenadeBomb(4,1,1,VFX_IMP_FROST_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_COLD,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_coldbomb002")
 {
 DoGrenadeBomb(6,1,1,VFX_IMP_FROST_S, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_COLD,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_coldbomb003")
 {
 DoGrenadeBomb(8,1,1,VFX_IMP_FROST_L, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_COLD,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_coldbomb004")
 {
 DoGrenadeBomb(10,1,1,VFX_IMP_FROST_L, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_COLD,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_sonicbomb001")
 {
 DoGrenadeBomb(4,1,1,VFX_IMP_SONIC, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_SONIC,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_sonicbomb002")
 {
 DoGrenadeBomb(6,1,1,VFX_IMP_SONIC, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_SONIC,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_sonicbomb003")
 {
 DoGrenadeBomb(8,1,1,VFX_IMP_SONIC, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_SONIC,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_sonicbomb004")
 {
 DoGrenadeBomb(10,1,1,VFX_IMP_SONIC, VFX_FNF_LOS_NORMAL_30,DAMAGE_TYPE_SONIC,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }
 else if(sTag == "sh_uniq_firebomb")
 {
 DoGrenadeBomb(4,1,d6(),VFX_IMP_FLAME_S,VFX_FNF_FIREBALL,DAMAGE_TYPE_FIRE,RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
 }

this way you save many resources, while there would be only minor adjustions in the code for each grenade. Also its easier to understand and implement.

#6
henesua

henesua
  • Members
  • 3 863 messages
I could do that for myself, but I have implemented a tag suffix system for tag based scripts.

The problem with using tags for information in a tag based script is that each tag opens a different script. So I got around this by looking for a "prefix" which is ended by an underscore. Everything after that underscore is usable as data in the script. I mostly use this for keys. All keys launch a key script when used. But also have a complex tag since that is the "lock" pattern.

EDIT: also... the point of this system was to get away from the default DoGrenade function and to implement spell like affects.

Anyway here's a snippet from my module activate script which would enable me to do as you suggest albeit as a tag activated script:

     if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS))
     {
        SetUserDefinedItemEventNumber(X2_ITEM_EVENT_ACTIVATE);
        string sScript;
        string sPre = GetTagPrefix(sTag);
        if(sPre == "test" && TESTING)
            sScript = PREFIX + GetStringRight(sTag, GetStringLength(sTag)-5);
        else if(sPre!="")
            sScript = PREFIX + sPre;
        else
            sScript = GetUserDefinedItemEventScriptName(oItem);
        int nRet =   ExecuteScriptAndReturnInt(sScript,OBJECT_SELF);
        if (nRet == X2_EXECUTE_SCRIPT_END)
        {
           return;
        } 
    }

And the function GetTagPrefix:

string GetTagPrefix(string sTag)
{
    string sTagPrefix   = "";
    int iPos1           = FindSubString(sTag, "_");
    int iPos2;
    int iLastPos        = GetStringLength(sTag)-1;

    if (iPos1 > 0)
    {
        sTagPrefix   = GetStringLeft(sTag, iPos1); // returns prefix without underscores
    }
    else if (iPos1 == 0)
    {
        // we have a leading underscore
        iPos2 = FindSubString(sTag, "_", ++iPos1);// look for a second underscore
        if (iPos2 != -1 && iPos2 != 1 && iPos2 != iLastPos) // ignore: _XXXXX , __XXXX , _XXXX_
        {
            sTagPrefix  = GetSubString(sTag, iPos1, iPos2 - iPos1);
        }
    }

    return GetStringLowerCase(sTagPrefix);
}

Modifié par henesua, 12 juillet 2012 - 02:44 .


#7
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

EDIT: also... the point of this system was to get away from the default DoGrenade function and to implement spell like affects.

whats wrong on this function except few bugs in there like wrong damage multiplier in case of critical hit that can be fixed in that function again?

also since you are giving the grenade cast spell unique power, how do you establish the granade projectile vfx?

Modifié par ShaDoOoW, 12 juillet 2012 - 04:58 .


#8
henesua

henesua
  • Members
  • 3 863 messages
that function only does damage. I wanted a grenade to cast a spell.

Grenade VFX? I haven't figured that out yet.

Modifié par henesua, 12 juillet 2012 - 05:40 .


#9
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

that function only does damage. I wanted a grenade to cast a spell.

Grenade VFX? I haven't figured that out yet.

Well why dont you add the code you have now in unique power into default grenade script? If you dont like the name of the itemproperty, or script name, you can change it in 2da easily.

EDIT: thought you know, now I wonder - are you aware that you can put the code I posted above into default grenade script (x2_s3_bomb) and you retain both functionality (grenade projectile VFX), ability to add new grenades easily and name (cast spell: grenade) ? Not to mention the saving resources - in that regards there isnt actually any advantage in the way you are trying to do this.

Modifié par ShaDoOoW, 12 juillet 2012 - 05:55 .


#10
henesua

henesua
  • Members
  • 3 863 messages
i didn't know there was a default grenade script. I thought they were separate spell scripts. what is the name of the default grenade script?

#11
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

i didn't know there was a default grenade script. I thought they were separate spell scripts. what is the name of the default grenade script?

x2_s3_bomb
the itemproperty is cast spell (grenade bomb) or something like that, you can also use the x2_s3_gag ->  cast spell: chicken egg and other grenade-like items (think that acid bomb, alchemist fire, acid flask, fire bomb these all have their own itemproperty and script

#12
henesua

henesua
  • Members
  • 3 863 messages
ah.. that is what threw me off.. the moment I found the different grenade scripts with their own item property I gave up and rolled my own tag based solution.

I'll write my own modification to the bomb for spell-grenades.

... Thanks :)

Modifié par henesua, 12 juillet 2012 - 06:03 .


#13
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

ah.. that is what threw me off.. the moment I found the different grenade scripts with their own item property I gave up and rolled my own tag based solution.

yea thats the reason GrenadeBomb function deals only damage, projectile is handled automatically by the engine if you use on of the default grenade-like spells (no sure whether its hardcoded onto 2da line or those projectiles are done by the projectile model o they can be reused for custom grenade spell in 2da)

#14
valasc

valasc
  • Members
  • 23 messages
Did you ever get this to work? And if so, could you share. I am also trying to implement some custom grenades and would really love to be to use the grenade vfx.

#15
henesua

henesua
  • Members
  • 3 863 messages
I did. I tried it several different ways and will have to take a look again. I think it was shadooow's suggestion that I ultimately settled on.

#16
henesua

henesua
  • Members
  • 3 863 messages
 Here is what I ended up doing:

I added a line to spells.2da for a default grenade
867 Grenade_Spell 16777554 is_X1Grenade T M s **** 0x3e x2_s3_bomb **** **** **** **** **** **** 3 1500 hand **** **** **** **** **** **** up 1000 **** **** **** **** 1 it_potion_000 bounce hand spr_los path **** 0 **** **** **** **** **** 2 **** 4 **** 0 0 2732 1 **** **** **** 1

I then created a few lines in iprp_spells.2da so that a builder could set the caster level for the spell grenade
548 Grenade_Spell 16777554 3 3 300 867 1 01 1 iss_X1Grenade
549 Grenade_Spell 16777555 5 3 500 867 1 01 1 iss_X1Grenade
550 Grenade_Spell 16777556 7 3 700 867 1 01 1 iss_X1Grenade
551 Grenade_Spell 16777557 9 3 900 867 1 01 1 iss_X1Grenade
552 Grenade_Spell 16777558 11 3 1100 867 1 01 1 iss_X1Grenade

Then I edited x2_s3_bomb to first read the spellid that ran the script, and if it is my "Grenade_Spell" Spell I check the item tag and respond accordingly.

Modifié par henesua, 27 novembre 2012 - 03:46 .


#17
Shadooow

Shadooow
  • Members
  • 4 470 messages
isnt adding additional lines into iprp_spell needless? you can increase the cost via various item cost increase properties (CEP, HR, CP...) and you can set CL into integer variable on the grenade item in question. Grenades are not intented to penetrate spell resistence or anything that would be tied with CL so that shouldnt be problem.

#18
henesua

henesua
  • Members
  • 3 863 messages
local variables get lost on stacked items.

#19
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

local variables get lost on stacked items.

thats true but you dont want to stack different types of grenades together right?

#20
henesua

henesua
  • Members
  • 3 863 messages
I just didn't want to run into that pitfall later. Including those item properties made it safer.

#21
Shadooow

Shadooow
  • Members
  • 4 470 messages

henesua wrote...

I just didn't want to run into that pitfall later. Including those item properties made it safer.

hmm not really actually, stacking by default ignores differences between itemproperties: read this if you havent

#22
henesua

henesua
  • Members
  • 3 863 messages
Ah... interesting.

Solution then is to insert caster level as a suffix on the tag. That should do the trick.

#23
WhiZard

WhiZard
  • Members
  • 1 204 messages

henesua wrote...

Ah... interesting.

Solution then is to insert caster level as a suffix on the tag. That should do the trick.


While you're at it you can script the tag to consider an unlimited number of variations.

E.g.
#include "x0_i0_spells"
void main()
{
    int nVFX1, nVFX2, nDamType, nDamage;
    effect eAOE;
    object oGrenade = GetSpellCastItem();
    if(!GetIsObjectValid(oGrenade)) return;
    string sTag = GetTag(GetSpellCastItem());
    nDamage = StringToInt(GetStringRight(sTag, 2));
    sTag = GetStringLeft(sTag, GetStringLength(sTag) -2);
    if(sTag == "bombfire")
      {
      nVFX1 = VFX_IMP_FLAME_M;
      nVFX2 = VFX_FNF_FIREBALL;
      nDamType = DAMAGE_TYPE_FIRE;
      eAOE = EffectAreaOfEffect(AOE_PER_FOGFIRE);
      }
    else if(sTag == "bombacid")
     {
     nVFX1 = VFX_IMP_ACID_L;
     nVFX2 = VFX_FNF_LOS_NORMAL_30;
     nDamType = DAMAGE_TYPE_ACID;
     eAOE= EffectAreaOfEffect(AOE_PER_FOGACID);
     }
    else if(sTag == "bombsonic")
     {
     //Define other values here
     }
    DoGrenade(d6(nDamage), nDamage, nVFX1, nVFX2, nDamType, RADIUS_SIZE_HUGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAOE, GetSpellTargetLocation(), RoundsToSeconds(5));
    }

#24
henesua

henesua
  • Members
  • 3 863 messages
definitely. already done.