Author Topic: Zoeller  (Read 472 times)

Legacy_Highv Priest

  • Full Member
  • ***
  • Posts: 170
  • Karma: +0/-0
Zoeller
« on: December 24, 2012, 10:53:49 am »


               Something bugs me... "You do not understand ... but you will :)", some interesting words from Zoeller in the Dwarven Defender Defensive Stance feat.

Did anyone actually find out what this is a reference to? Is he trying to say you can add scripts to feats or something? Because being able to add a script to knockdown just to be able to hook it would be amazing. I never bothered, because I can just picture the new script for knockdown simply stopping the knockdown part from doing anything and all it would do then is execute the script.(since whirlwind attack does exactly that, working only through the script).

Anyone ever actually done any testing changing feats to have scripts attached to them?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Zoeller
« Reply #1 on: December 24, 2012, 03:29:44 pm »


               Yes, you can modify stuff like this. Some feats are already accessible through nwscript, like the PDK abilities added in 1.67. Others can only be hooked with nwnx_events. Here's our code for it, which handles all custom events (see the EVENT_TYPE_USE_FEAT partway down). This script bypasses the normal event, and fires our own custom script instead.


#include "hg_inc"

#include "fky_chat_instant"


void main() {
    int nEventType = GetEventType();
    int nSubType;
    string sCommand;
    location lTarget;
    object oTarget, oItem;

    switch (nEventType) {
        case EVENT_TYPE_CAST_SPELL:
            SetActionMode(OBJECT_SELF, ACTION_MODE_COUNTERSPELL, FALSE);

            nSubType = GetEventSubType();

            // 0x08000000 = already an instant spell; 0x03000000 = last legit class slot
            if (GetIsPC(OBJECT_SELF) && !(nSubType & 0x08000000) && (nSubType & 0x07000000) < 0x03000000) {
                switch (nSubType & 0xFFFF) {
                    case SPELL_TRUE_STRIKE:     /* don't let Nightblades cast True Strike swiftly when they go in */

                    case SPELL_LESSER_RESTORATION:
                    case SPELL_RESTORATION:
                    case HGSPELL_CRITICAL_STRIKE:
                    case HGSPELL_DOLOROUS_BLOW:
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                    case SPELL_HOLD_PERSON:
                        if (GetclassByPosition(((nSubType >> 24) & 0x7) + 1, OBJECT_SELF) != class_TYPE_CLERIC)
                            break;
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                    case HGSPELL_VOCALIZE:
                        if (1 || GetclassByPosition(((nSubType >> 24) & 0x7) + 1, OBJECT_SELF) != class_TYPE_WIZARD)
                            break;
                        if (GetObjectType(GetEventTarget()) != OBJECT_TYPE_ITEM) {
                            SetLocalInt(OBJECT_SELF, "EventSpell", nSubType);
                            SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                            DelayCommand(0.0, ExecuteScript("ev_swiftspell", OBJECT_SELF));
                            BypassEvent();
                        }
                        break;

                }
            }
            break;

        case EVENT_TYPE_USE_ITEM:
            oItem = GetEventItem();

            if (GetLocalInt(oItem, "FKY_CHAT_INSTANT")) {
                oTarget = GetEventTarget();
                if (GetObjectType(oTarget) == OBJECT_TYPE_TRIGGER)
                    lTarget = GetLocation(OBJECT_SELF);
                else
                    lTarget = Location(GetArea(OBJECT_SELF), GetEventPosition(), GetFacing(OBJECT_SELF));

                if (DoInstantUse(OBJECT_SELF, oItem, oTarget, lTarget))
                    BypassEvent();
            }
            break;

        case EVENT_TYPE_USE_FEAT:
            nSubType = GetEventSubType();

            if (nSubType == FEAT_STUNNING_FIST && GetLLControlclass(OBJECT_SELF) == class_TYPE_MONK) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_stunningfist", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_QUIVERING_PALM) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_quiveringpalm", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_CALLED_SHOT                   &&
                GetLevelByclass(class_TYPE_RANGER, OBJECT_SELF) >= 35 &&
                GetHasFeat(FEAT_EPIC_BANE_OF_ENEMIES, OBJECT_SELF)) {

                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_calledshot", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_DISARM || nSubType == FEAT_IMPROVED_DISARM || nSubType == HGFEAT_LEG_DISARM || nSubType == HGFEAT_PAR_DISARM) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_disarm", OBJECT_SELF));
                BypassEvent();
            } else if (nSubType == FEAT_KNOCKDOWN || nSubType == FEAT_IMPROVED_KNOCKDOWN || nSubType == HGFEAT_LEG_KNOCKDOWN || nSubType == HGFEAT_PAR_KNOCKDOWN) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_knockdown", OBJECT_SELF));
                BypassEvent();
            } else if (FindSubString(" 304 305 335 336 337 338 339 340 341 342 872 873 898 900 901 902 903 1060 1061 ", " " + IntToString(nSubType) + " ") >= 0) {
                if (GetHasEffectOfType(EFFECT_TYPE_POLYMORPH, OBJECT_SELF)) {
                    FloatingTextStringOnCreature("You cannot change shape while already polymorphed!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
            }

            break;

        case EVENT_TYPE_USE_SKILL:
            nSubType = GetEventSubType();

            if (nSubType == SKILL_TAUNT) {
                SetLocalObject(OBJECT_SELF, "EventTarget", GetEventTarget());
                DelayCommand(0.0, ExecuteScript("ev_taunt", OBJECT_SELF));
                BypassEvent();
            }
            break;

        case EVENT_TYPE_TOGGLE_MODE:
            nSubType = GetEventSubType();

            if (nSubType == ACTION_MODE_COUNTERSPELL) {
                if (GetIsObjectValid(GetAttackTarget(OBJECT_SELF)))
                    ClearAllActions(TRUE);
                RemoveEffectsOfType(EFFECT_TYPE_ETHEREAL, OBJECT_SELF);
            }

            break;

        case EVENT_TYPE_PICKPOCKET:
            oTarget = GetEventTarget();

            if (GetIsPC(OBJECT_SELF) && GetIsPC(oTarget)) {
                if (GetLocalInt(GetArea(OBJECT_SELF), "nopp")) {
                    FloatingTextStringOnCreature("You cannot pickpocket other players!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
                if (abs(GetHitDice(oTarget) - GetHitDice(OBJECT_SELF)) > 6) {
                    FloatingTextStringOnCreature("You cannot pickpocket players more than 6 levels above or below you!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
                if (GetIsHardcore(OBJECT_SELF) || GetIsHardcore(oTarget)) {
                    FloatingTextStringOnCreature("Hardcore players cannot pickpocket or be pickpocketed by other players!", OBJECT_SELF, FALSE);
                    BypassEvent();
                }
            }
            RemoveEffectsOfType(EFFECT_TYPE_ETHEREAL, OBJECT_SELF);
            break;

        case EVENT_TYPE_QUICKCHAT:
            nSubType = GetEventSubType();
            sCommand = GetLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));

            if (GetLocalString(OBJECT_SELF, "VoiceBind_Save") != "") {
                sCommand = GetLocalString(OBJECT_SELF, "VoiceBind_Save");
                DeleteLocalString(OBJECT_SELF, "VoiceBind_Save");

                if (nSubType >= 100                                                          ||
                    (nSubType >= VOICE_CHAT_ENEMIES  && nSubType <= VOICE_CHAT_FLEE)         ||
                    (nSubType >= VOICE_CHAT_LOOKHERE && nSubType <= VOICE_CHAT_TASKCOMPLETE) ||
                    (nSubType >= VOICE_CHAT_TALKTOME && nSubType <= VOICE_CHAT_BADIDEA)) {
                    if (GetStringLowerCase(sCommand) == "clear") {
                        DeleteLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));
                        DeletePersistentVariable(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType));

                        FloatingTextStringOnCreature(COLOR_GREEN + "Voice chat cleared!", OBJECT_SELF, FALSE);
                    } else {
                        SetLocalString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType), sCommand);
                        SetPersistentString(OBJECT_SELF, "VoiceBind_" + IntToString(nSubType), sCommand);

                        FloatingTextStringOnCreature(COLOR_GREEN + "Voice chat bound!", OBJECT_SELF, FALSE);
                    }
                } else
                    FloatingTextStringOnCreature(COLOR_RED + "You cannot bind that voice chat!", OBJECT_SELF, FALSE);

                BypassEvent();
            } else if (sCommand != "" || (nSubType >= 100 && nSubType <= 110)) {
                if (sCommand == "") {
                    switch (nSubType) {
                        case 100: sCommand = "!autocast";                    break;
                        case 101: sCommand = "!list imm";                    break;
                        case 102: sCommand = "!effects";                     break;
                        case 103: sCommand = "!who inparty class";           break;
                        case 104: sCommand = "!effects eq";                  break;
                        case 105: sCommand = "!list servers";                break;
                        case 107: sCommand = "!who player class group=area"; break;
                        case 108: sCommand = "!list voicebinds";             break;
                        case 109: sCommand = "!render";                      break;
                        case 110: sCommand = "!stuck";                       break;
                        default:  sCommand = "!time";                        break;
                    }
                }

                if (GetStringLeft(sCommand, 8) == "!target ") {
                    sCommand = GetSubString(sCommand, 8, 255);
                    DeleteLocalObject(OBJECT_SELF, "FKY_CHAT_TARGET");
                } else {
                    SetLocalObject(OBJECT_SELF, "FKY_CHAT_TARGET", OBJECT_SELF);
                    SetLocalInt(OBJECT_SELF, "FKY_CHAT_TARGET_CLEANUP", 1);
                }

                AssignCommand(OBJECT_SELF, SpeakString(sCommand, TALKVOLUME_WHISPER));
                BypassEvent();
            }
            break;
    }
}

If memory serves, defensive stance IS NOT directly accessible via nwscript - we made an item to fire our hgs_gen_damshld script which decrements its uses, instead of hooking it via nwnx_events. Here's the relevant section of code:


    if (GetResRef(si.item) == "ca_dwd_defense") {
        if (!GetHasFeat(FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE, si.caster)) {
            FloatingTextStringOnCreature("You have no uses of Defensive Stance remaining!", si.caster, FALSE);

            SetItemSpellUses(si.item, 0);

            return;
        }

        DecrementRemainingFeatUses(si.caster, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE);
        SetItemSpellUses(si.item, GetRemainingFeatUses(si.caster, FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE));

        si.id     = HGEFFECT_DEFENSIVE_WEAVE;
        si.clevel = GetLevelIncludingLLs(class_TYPE_DWARVEN_DEFENDER, si.caster);

        fDur = RoundsToSeconds(si.clevel * 2);

        eLink = EffectDamageShield((si.clevel * 3) / 2, DAMAGE_BONUS_1d6, DAMAGE_TYPE_BLUDGEONING);
        eLink = EffectLinkEffects(eLink, EffectVisualEffect(PRCVFX_DUR_STONE4));
        eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE));

        eLink = ExtraordinaryEffect(eLink);
        SetEffectSpellId(eLink, si.id);

        ApplyVisualToObject(VFX_IMP_DUST_EXPLOSION, si.caster);
    }
...*snip*...
    RemoveEffectsFromSpell(si.id, si.target);

    SignalEvent(si.target, EventSpellCastAt(si.caster, si.id, FALSE));

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, si.target, fDur);


Funky
               
               

               


                     Modifié par FunkySwerve, 24 décembre 2012 - 03:39 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Zoeller
« Reply #2 on: December 24, 2012, 07:40:09 pm »


               

Highv Priest wrote...

Something bugs me... "You do not understand ... but you will :)", some interesting words from Zoeller in the Dwarven Defender Defensive Stance feat.


You are looking at the script x2_s2_defstance.

If you look at the script notes, it describes a different script name x2_s1_defstance.  This script is a hardcoded resource, but giving a module script the same name does not seem to affect defensive stance.

EDIT: Looks x2_s1_defstance appears just to be a reserved namespace not a hardcoded script (because it begins with x2_).  My best guess is that the x2_s2_defstance script might be a module level override for a core game bug (e.g. a bugged hardcoded script might be x2_s2_defstance). 
               
               

               


                     Modifié par WhiZard, 24 décembre 2012 - 07:55 .
                     
                  


            

Legacy_leo_x

  • Sr. Member
  • ****
  • Posts: 403
  • Karma: +0/-0
Zoeller
« Reply #3 on: December 24, 2012, 09:28:42 pm »


               From what I remember, Defensive Stance is hardcoded to activate a combat mode (in CNWSCreature::UseFeat), hence no script will ever fire...in the default game, with NWNX maybe you could grab hold of it at UseFeat or ToggleMode...like in Funky's scripts above.   I have absolutely no clue what Zoeller could have meant tho.

@Funky On your use feat scripts how do you deal with distance?  I seem to remember trying it that way you could do a stunning fist from across the room.  Do you have a character close to range or just exit if the distance is too large?  And what of combat animtions?
               
               

               


                     Modifié par pope_leo, 24 décembre 2012 - 10:30 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Zoeller
« Reply #4 on: December 24, 2012, 10:35:46 pm »


               Here's the stunning fist script. Distance was a bit of a nuisance, and we wound up having to increase it a bit to account for larger critters. This is not really ideal, but it allowed us to do a lot of interesting things with it:


#include "hg_inc"
#include "ac_spell_inc"

void main () {
    object oPC = OBJECT_SELF;
    object oTarget = GetLocalObject(oPC, "EventTarget");

    DeleteLocalObject(oPC, "EventTarget");

    if (!GetIsObjectValid(oPC) || !GetIsObjectValid(oTarget) || !GetIsTarget(oTarget) || !GetHasFeat(FEAT_STUNNING_FIST, oPC))
        return;

    if (GetDistanceBetween(oPC, oTarget) > RADIUS_SIZE_LARGE) {
        FloatingTextStringOnCreature("You must be closer to your target to use Stunning Fist!", oPC, FALSE);
        return;
    }

    if (!CheckSwiftAction(oPC))
        return;

    DecrementRemainingFeatUses(oPC, FEAT_STUNNING_FIST);
    SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_POWER_WORD_STUN));

    int nFeats = GetKnowsFeatChain(FEAT_EPIC_IMPROVED_STUNNING_FIST_1, oPC);
    int nTouch, nDC = 10 +
                      (GetLevelIncludingLLs(class_TYPE_MONK, oPC) / 2) +
                      GetAbilityModifier(ABILITY_WISDOM, oPC) +
                      (nFeats * 3);

    nDC -= GetSpellAreaDCPenalty(oPC);

    if (nDC > 70)
        nDC = 70;

    if (GetHasFeat(FEAT_WEAPON_FINESSE, oPC) &&
        GetAbilityScore(oPC, ABILITY_DEXTERITY) > GetAbilityScore(oPC, ABILITY_STRENGTH))
        nTouch = TouchAttackRanged(oTarget);
    else
        nTouch = TouchAttackMelee(oTarget);


    if (nTouch && GetSaveCheckResult(SAVING_THROW_WILL, oTarget, nDC) <= 0) {
        if ((GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT) || GetLocalInt(oTarget, "NoDevCrit")) &&
            (GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS) || GetIsImmune(oTarget, IMMUNITY_TYPE_STUN))) {
            ApplyVisualToObject(VFX_IMP_GLOBE_USE, oTarget);
        } else {
            effect eStun = EffectCutsceneParalyze();
            eStun = EffectLinkEffects(eStun, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED));
            eStun = ExtraordinaryEffect(eStun);

            SetEffectSpellId(eStun, HGEFFECT_STUNNING_FIST);

            float fDur = RoundsToSeconds(d3(nTouch) + nTouch) + IntToFloat(nFeats);

            int i;
            for (i = 0; i < NUM_INVENTORY_SLOTS; i++) {
                if (GetLocalInt(GetItemInSlot(i, oPC), "ImproveStunningFistDur")) {
                    fDur *= 1.5;
                    break;
                }
            }

            ApplyVisualToObject(VFX_IMP_BIGBYS_FORCEFUL_HAND, oTarget);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStun, oTarget, fDur);
        }
    }
}