How to: crazy custom spikes

Post Reply
User avatar
TeoTwawki
Developer
Posts: 527
Joined: Mon Jul 15, 2013 9:50 pm

How to: crazy custom spikes

Post by TeoTwawki » Fri Oct 24, 2014 10:35 pm

2nd Warning: This post is a bit outdated. While all of this is still possible, the exact line numbers and their contents won't be identical to when I wrote this. It shouldn't be to hard to figure out, but if you need help don't be afraid to ask here.

Warning: Big post. Make a sandwich, get a drink, this is gonna take awhile for me to explain and you to absorb. If adding custom efefcts to your mobs and gear isn't your thing, you should save yourself the time and skip reading this.

Big fat important disclaimer notice:
Back your stuff up! I will not be held responsible for you screwing up your server. Absolutely do not pester the darkstar devs with bugs caused by attempts to make custom things, especially from the info in this post, or expect them to fix it. If you have trouble figuring out how to do something I'm willing to try and help you, but if people make this a hassle for either the DSP devs or myself, I'm more likely to erase/blank my post, capeesh? And if anyone wants to thank me, find something not working and fix it. The older the expansion it comes from the better.

I'm providing some example code here. This is custom content, so it hasn't gone into a pull request.

First, lets start with enabling the currently unused animations for spikes that don't exist!
(Earth, wind, and water element spike animations.)

You can also trigger counter/retaliation animations this way, which I'm doing in my examples.

In battelentity.h find the enumeration for SUBEFFECT, and add this line:

Code: Select all

	SUBEFFECT_DELUGE_SPIKES		= 9,
This will get you water spike animations. And hey lookit that, wind and earth animations are already enum'd even though nothing is using them yet.

In battleutils.cpp you need a case entry in HandleSpikesDamage in the switch statement if you intent to do an actual status effect or scripted mob spikes using your new animation. You see:

Code: Select all

        switch (Action->spikesEffect)
        {
            case SPIKE_BLAZE:
            case SPIKE_ICE:
            case SPIKE_SHOCK:
                PAttacker->addHP(-Action->spikesParam);
                break;
            case SPIKE_DREAD:
        }
And so on. Now lets add our new entry, right below the last one (reprisal):

Code: Select all

                break;
            case SPIKE_DELUGE:
                PAttacker->addHP(-Action->spikesParam);
                break;
We just made "Deluge Spikes" possible for scripts. But its not working on items yet. This is because we need to change these checks:

Code: Select all

                if (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) > 0 && ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) < 7)
Into these checks (this is enabling wind, earth, water, and counter/retaliation animations):

Code: Select all

                if (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) > 0 && (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) < 11 || ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) == 63))
While we're right here, lets look at how simple it is to add item types that can even have spikes (for gear that triggers spike effects, like Gothic Gauntlets. Say you want to make an earring with a spike effect. You can't change the in game text to show it, but you can easily create "hidden" spikes by adding another check (below the " // feet" area's if statement) like this:

Code: Select all

            // Earring (1)
            PItem = PCharDef->getEquip(SLOT_EAR1);

            if (PItem)
            {
                Action->spikesEffect = (SUBEFFECT)0;
                if (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) > 0 && (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) < 11 || ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) == 63))
                {
                    Action->spikesEffect = (SUBEFFECT)((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE);
                }

                Action->spikesParam = ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_DMG);
                chance = ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_CHANCE);

                if (Action->spikesEffect && HandleSpikesEquip(PAttacker, PDefender, Action, Action->spikesParam, Action->spikesEffect, chance))
                    return true;
            }

            // Earring (2)
            PItem = PCharDef->getEquip(SLOT_EAR2);

            if (PItem)
            {
                Action->spikesEffect = (SUBEFFECT)0;
                if (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) > 0 && (((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) < 11 || ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE) == 63))
                {
                    Action->spikesEffect = (SUBEFFECT)((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_TYPE);
                }

                Action->spikesParam = ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_DMG);
                chance = ((CItemArmor*)PItem)->getModifier(MOD_ITEM_SPIKES_CHANCE);

                if (Action->spikesEffect && HandleSpikesEquip(PAttacker, PDefender, Action, Action->spikesParam, Action->spikesEffect, chance))
                    return true;
            }
Don't forget you have to add mods to your item in the item_mods sql database table before that item can "proc" in game. Take a look at how other existing items are already done.

Now what if we want a status effect, like how shock spikes do stun? To do that, we need to modify HandleSpikesStatusEffect with another "case" after the previous case break, but before the default, like so:

Code: Select all

            break;
        }
        case SUBEFFECT_DELUGE_SPIKES: // Currently unused in retail
        {
            if(WELL512::irand()%100 <= 25+lvlDiff && PAttacker->StatusEffectContainer->HasStatusEffect(EFFECT_ATTACK_DOWN) == false)
            {
                PAttacker->StatusEffectContainer->AddStatusEffect(new CStatusEffect(EFFECT_ATTACK_DOWN, EFFECT_ATTACK_DOWN, 20, 0, 30));
            }
            break;
        }
        default:
I chose attack down for a total of 30 seconds in my example. You can get away with any status effect you there. I also have "dirt spikes" doing slow or petrify using a random number and an if/else to decide which goes off, with slow being the more likely of the two and petrify being a much shorter duration.

Now you may notice that dread spikes when assigned to equipment, isn't working. This is because there is no item in retail that does this, so that functionality was never coded into HandleSpikesEquip but don't worry, we can fix that easy peezy, and add TP for our fake retaliation procs on gear (counter spikes) there while we're at it, if you do a spike case for that back where we did with deluge spikes:

Code: Select all

bool HandleSpikesEquip(CBattleEntity* PAttacker, CBattleEntity* PDefender, apAction_t* Action, uint8 damage, SUBEFFECT spikesType, uint8 chance)
{
    int lvlDiff = dsp_cap((PDefender->GetMLevel() - PAttacker->GetMLevel()), -5, 5)*2;

    if(WELL512::irand()%100 <= chance+lvlDiff)
    {
        // Spikes landed
        if(spikesType == SUBEFFECT_CURSE_SPIKES)
        {
            Action->spikesMessage = 0; // Log says nothing?
            Action->spikesParam = EFFECT_CURSE_I;
        }
        else if(spikesType == SUBEFFECT_DREAD_SPIKES)
        {
            if (PAttacker->m_EcoSystem == SYSTEM_UNDEAD)
            {
                // Doesn't work on undead!
                Action->spikesMessage = 0;
                Action->spikesEffect = (SUBEFFECT)0;
                Action->spikesParam = 0;
                // Why is this STILL animating on undead mobs???
                return false;
            }
            else
            {
                uint8 ratio = dsp_cap((float)damage/4, 1, 255);
                Action->spikesMessage = 132;
                Action->spikesParam = HandleStoneskin(PAttacker, damage - WELL512::irand()%ratio + WELL512::irand()%ratio);
                PDefender->addHP(Action->spikesParam);
                PAttacker->addHP(-Action->spikesParam);
            }
        }
        else if(spikesType == SUBEFFECT_COUNTER)
        {
            uint8 ratio = dsp_cap((float)damage/4, 1, 255);
            Action->spikesParam = HandleStoneskin(PAttacker, damage - WELL512::irand()%ratio + WELL512::irand()%ratio);
            PAttacker->addHP(-Action->spikesParam);
            // PDefender->addTP(PDefender->GetWeaponDelay(true) / some_number? );
            PDefender->addTP(1);
        }
        else
        {
            uint8 ratio = dsp_cap((float)damage/4, 1, 255);
            Action->spikesParam = HandleStoneskin(PAttacker, damage - WELL512::irand()%ratio + WELL512::irand()%ratio);
            PAttacker->addHP(-Action->spikesParam);
        }
        return true;
    }
    return false;
}
Want to give a mob auto spikes of your new type? Take a look at the existing mobs that have auto spikes, like Autarch.

Want a mob that has it as a spell? Well thats a bit more involved. And I think I'll have to save making custom dummy entries in the spells table for another day. I can show you how to do the effect though. I have a few custom superbad NMs that get custom spikes as part of their TP moves (I beefed up some old NMs like Simurg, Roc, and LumberJack). Here is "Duluge Spikes" as a status effect:

Code: Select all

require("scripts/globals/status");

-----------------------------------
-- onEffectGain Action
-----------------------------------

function onEffectGain(target,effect)
    target:addMod(MOD_SPIKES,9);
    target:addMod(MOD_SPIKES_DMG, effect:getPower());
end;

-----------------------------------
-- onEffectTick Action
-----------------------------------

function onEffectTick(target,effect)
end;

-----------------------------------
-- onEffectLose Action
-----------------------------------

function onEffectLose(target,effect)
    target:delMod(MOD_SPIKES,9);
    target:delMod(MOD_SPIKES_DMG, effect:getPower());
end;
Now unlike our other custom spikes, deluge spikes does have an effect entry and an icon in the client, so you can use it just like any other effect. This is why I've called it "Deluge spikes" all throughout this post, instead of something like "flood spikes" or "water spikes" or something.

If you create other custom effects, you are going to need to add them in status.lua and status_effect.h, as well as status_effects.sql, and call them using addStatusEffectEx() instead of addStatusEffect() so you can dummy another icon and help text onto them. I suggest using "damage spikes" for your piggybacking needs.

It is also possible to make multiple effects that use the same animation if you are creative.

You can split curse spikes into one that does curse and no damage, and one that does darkness damage and a different effect.

I have a light element spike that gives you small amounts of mp, hidden away one of my items waiting for a lucky player to discover it, and it is not just reprisal with mp or a mini Ochain, nor is it aspir spikes.

With a little (ok, a lot..) of extra work, you can do all this stuff to teh weapon additional effects as well, without having to script every item, and even stuff them into custom augment table entries to boot.

Which reminds me... Don't try to place spike effects onto you main weapon, subweapon, ranged or ammo gear. Shields are the only thing that goes into one of those slots that you can safely stuff spikes onto without having to edit the source further to kill potential crashbugs. Stick to actual armor pieces.

It is also worth mentioning that its very easy to overpower gear this way, even with short duration effects or small damage amounts.


<.<

>.>

Man...Google image search has a really crappy selection of "spikes everywhere" meme material.
ImageImage
Last edited by TeoTwawki on Sat Jul 16, 2016 2:56 am, edited 2 times in total.
Hi, I run The Demiurge server.


Image
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. - Martin Golding
PLS USE [ code ] CODE TAGS [ /code ] WHEN POSTING CODE
DO NOT PRIVATE MESSAGE ME ABOUT BUGS

User avatar
TeoTwawki
Developer
Posts: 527
Joined: Mon Jul 15, 2013 9:50 pm

Re: How to: crazy custom spikes

Post by TeoTwawki » Fri Oct 24, 2014 10:35 pm

UPDATE:
I'll be changing spikes to use a script soon
Last edited by TeoTwawki on Sat Jul 16, 2016 2:47 am, edited 1 time in total.
Hi, I run The Demiurge server.


Image
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. - Martin Golding
PLS USE [ code ] CODE TAGS [ /code ] WHEN POSTING CODE
DO NOT PRIVATE MESSAGE ME ABOUT BUGS

User avatar
atom0s
Developer
Posts: 537
Joined: Thu Oct 25, 2012 9:52 am

Re: How to: crazy custom spikes

Post by atom0s » Fri Oct 24, 2014 10:37 pm

Would be nice to see this overhauled and moved to Lua scripts instead of being coded into the core. Allowing the Lua for each spike effect to control any aspect of the effect rather then it being hard coded into the core requiring recompiles to change.

User avatar
TeoTwawki
Developer
Posts: 527
Joined: Mon Jul 15, 2013 9:50 pm

Re: How to: crazy custom spikes

Post by TeoTwawki » Fri Oct 24, 2014 10:40 pm

atom0s wrote:Would be nice to see this overhauled and moved to Lua scripts instead of being coded into the core. Allowing the Lua for each spike effect to control any aspect of the effect rather then it being hard coded into the core requiring recompiles to change.
I made that exact suggestion before. We wound up with item_mods based spikes instead, dunno/remember why.

I kind of like how it turned out though since damage from item spikes doesn't vary much on retail, this winds up pretty accurate as is. The only recompiling required is to do non retail things - adding new items is just an sql edit.
Hi, I run The Demiurge server.


Image
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. - Martin Golding
PLS USE [ code ] CODE TAGS [ /code ] WHEN POSTING CODE
DO NOT PRIVATE MESSAGE ME ABOUT BUGS

Post Reply