Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nwnx_creature #1792

Open
Darsiniux opened this issue Oct 20, 2024 · 11 comments
Open

nwnx_creature #1792

Darsiniux opened this issue Oct 20, 2024 · 11 comments

Comments

@Darsiniux
Copy link

Darsiniux commented Oct 20, 2024

Hi, great work on all these functions. I really appreciate what you guys did here. I'm posting because i'm having a bit of trouble understanding how i'm supposed to be using the NWNX_Creature_SetMovementRateFactor & NWNX_Creature_GetMovementRateFactor. No matter what I do I run into a laundry list of bugs. When I use these functions with the base NWN EffectMovementSpeedIncrease it causes issues with barbarian speed & monk speed among other things. They don't work well with the vanilla NWN haste property either. I literally attempted to rewrite every spell/feat, and even the haste itemproperty to make this work before realizing that I have no way of dealing with encumbrance causing a movement speed decrease which breaks everything.

@Darsiniux
Copy link
Author

Darsiniux commented Oct 20, 2024

Example of one of the scripts I wrote to fix monk speed.

#include "nwnx_events"
#include "nwnx_creature"

void main()
{
    string sEvent = NWNX_Events_GetCurrentEvent();
    int iMonk = GetLevelByClass(CLASS_TYPE_MONK, OBJECT_SELF);
    int iFeat = StringToInt(NWNX_Events_GetEventData("FEAT_ID"));

    if(iFeat == FEAT_MONK_ENDURANCE)
    {
        if(sEvent == "NWNX_ON_USE_FEAT_BEFORE")
        {
            if(iMonk >= 3 && GetLocalInt(OBJECT_SELF, "ONE") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "ONE", TRUE);
            }
            if(iMonk >= 6 && GetLocalInt(OBJECT_SELF, "TWO") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "TWO", TRUE);
            }
            if(iMonk >= 9 && GetLocalInt(OBJECT_SELF, "THREE") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "THREE", TRUE);
            }
            if(iMonk == 12 && GetLocalInt(OBJECT_SELF, "FOUR") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "FOUR", TRUE);
            }
            if(iMonk == 15 && GetLocalInt(OBJECT_SELF, "FIVE") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "FIVE", TRUE);
            }
            if(iMonk == 18 && GetLocalInt(OBJECT_SELF, "SIX") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "SIX", TRUE);
            }
            if(iMonk == 21 && GetLocalInt(OBJECT_SELF, "SEVEN") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "SEVEN", TRUE);
            }
            if(iMonk == 24 && GetLocalInt(OBJECT_SELF, "EIGHT") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "EIGHT", TRUE);
            }
            if(iMonk == 27 && GetLocalInt(OBJECT_SELF, "NINE") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "NINE", TRUE);
            }
            if(iMonk == 30 && GetLocalInt(OBJECT_SELF, "TEN") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "TEN", TRUE);
            }
            if(iMonk == 33 && GetLocalInt(OBJECT_SELF, "ELEVEN") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "ELEVEN", TRUE);
            }
            if(iMonk == 36 && GetLocalInt(OBJECT_SELF, "TWELVE") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "TWELVE", TRUE);
            }
            if(iMonk == 39 && GetLocalInt(OBJECT_SELF, "THIRTEEN") == FALSE)
            {
                NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, NWNX_Creature_GetMovementRateFactor(OBJECT_SELF)+0.10);
                SetLocalInt(OBJECT_SELF, "THIRTEEN", TRUE);
            }
        NWNX_Events_SkipEvent();
        }
    }
}

@Darsiniux
Copy link
Author

Barbarian speed fix...

#include "nwnx_events"
#include "nwnx_creature"

void main()
{
    // Initialize a variable to check the event data. Checks if user of the event is using the correct feat.
    int iHasFeat = StringToInt(NWNX_Events_GetEventData("FEAT_ID"));
    string sEvent = NWNX_Events_GetCurrentEvent();

    if(sEvent == "NWNX_ON_USE_FEAT_BEFORE")
    {
        if(iHasFeat == FEAT_BARBARIAN_ENDURANCE)
        {
            float fSpeed = NWNX_Creature_GetMovementRateFactor(OBJECT_SELF) + 0.10;
            NWNX_Creature_SetMovementRateFactor(OBJECT_SELF, fSpeed);
            NWNX_Events_SkipEvent();
        }
    }
}

@Darsiniux
Copy link
Author

Darsiniux commented Oct 20, 2024

While doing all this I also realized that the vanilla NWN monk speed is completely bugged at level 15 monk. It doesn't apply the correct movement speed. Also, when you use a haste item with barbarian, and then remove the haste item, the barbarian speed isn't retained where it should be at 1.1 without haste.

@Darsiniux
Copy link
Author

Darsiniux commented Oct 20, 2024

Unfortunately, none of the above fixes work when a vanilla speed increase/decrease occurs from encumberance, haste, slow, grease, acid fog, or any other thing effecting speed in the base game. I was literally in the process of rewriting everything but it's pointless when you can't do anything about encumberance. I was about to redo everything including called shot leg.

@Darsiniux
Copy link
Author

NWNX_Creature_SetMovementRateFactorCap causes lots of bugs to happen.

@Darsiniux
Copy link
Author

I even re-wrote the vanilla nwn haste property.

#include "nwnx_events"
#include "nwnx_effect"
#include "nwnx_creature"

// Skips the haste item property on items and replaces it.
void main()
{
    string sEvent = NWNX_Events_GetCurrentEvent();
    int iProperty = StringToInt(NWNX_Events_GetEventData("PROPERTY"));
    object oPC = StringToObject(NWNX_Events_GetEventData("CREATURE"));
    int bLoading = StringToInt(NWNX_Events_GetEventData("LOADING_GAME"));
    effect eAPR = ExtraordinaryEffect(EffectModifyAttacks(1));
    effect eHaste = ExtraordinaryEffect(EffectIcon(EFFECT_ICON_HASTE));
    effect eHasteAC = ExtraordinaryEffect(EffectACIncrease(4));

    if(sEvent == NWNX_ON_ITEMPROPERTY_EFFECT_APPLIED_BEFORE)
    {
        if(StringToInt(NWNX_Events_GetEventData("PROPERTY")) == ITEM_PROPERTY_HASTE)
        {
            if(GetLocalInt(oPC, "SPEED") == FALSE)
            {
                if(!bLoading)
                {
                    ApplyEffectToObject(DURATION_TYPE_EQUIPPED, eAPR, oPC);
                    ApplyEffectToObject(DURATION_TYPE_EQUIPPED, eHaste, oPC);
                    ApplyEffectToObject(DURATION_TYPE_EQUIPPED, eHasteAC, oPC);
                    NWNX_Creature_SetMovementRateFactor(oPC, NWNX_Creature_GetMovementRateFactor(oPC) + 0.50);
                    SetLocalInt(oPC, "SPEED", TRUE);
                    //SendMessageToPC(oEquipped, "APPLIED BEFORE.");
                }
            }
            NWNX_Events_SkipEvent();
        }
    }

    if(sEvent == NWNX_ON_ITEMPROPERTY_EFFECT_REMOVED_AFTER)
    {
        if(iProperty == ITEM_PROPERTY_HASTE)
        {
            if(GetLocalInt(oPC, "SPEED") == TRUE)
            {
                RemoveEffect(oPC, ExtraordinaryEffect(EffectModifyAttacks(1)));
                RemoveEffect(oPC, ExtraordinaryEffect(EffectIcon(EFFECT_ICON_HASTE)));
                RemoveEffect(oPC, ExtraordinaryEffect(EffectACIncrease(4)));
                NWNX_Creature_SetMovementRateFactor(oPC, NWNX_Creature_GetMovementRateFactor(oPC) - 0.50);
                SetLocalInt(oPC, "SPEED", FALSE);
                //SendMessageToPC(oEquipped, "REMOVED AFTER.");
            }
        }
    }
}

@Darsiniux
Copy link
Author

Darsiniux commented Oct 20, 2024

Am I just using these wrong? Is there a better way to do all this without running into problems? It's so bugged in so many ways that it begs the question what is this even used for?

@Darsiniux
Copy link
Author

Darsiniux commented Oct 22, 2024

Need a way to replace the base games movement speed decrease with an event that uses the nwnx_creature functions to reduce the speed instead.

Either that or encumbrance events are needed like ENCUMBERED_BEFORE and NOT_ENCUMBERED_AFTER.

@Darsiniux
Copy link
Author

Does anybody know what LimitMovementSpeed = 59 is?? I was hoping it was for encumber but it's not. https://github.com/nwnxee/unified/blob/master/NWNXLib/API/Constants/Effect.hpp#L8 |

@Darsiniux
Copy link
Author

Darsiniux commented Oct 23, 2024

I incorrectly stated that the vanilla NWN stuff with movement speed is bugged. It's only bugged when you increase the movement rate cap with the nwnx_creature function, NWNX_Creature_SetMovementRateFactorCap(oPC, 3.0);

I thought it was vanilla NWN because I forgot to remove the cap increase.

@jd28
Copy link
Collaborator

jd28 commented Nov 4, 2024

It would probably be simpler for you to hook GetMovementRateFactor and do your own thing there and not modify what the game thinks obj->cre_move_rate should be, no clue what the actual variable is named.

Here is an example in Lua from an older project:

local Hook = require 'solstice.hooks'
local ffi = require 'ffi'
local C = ffi.C
local max = math.max

-- CNWSCreature::GetMovementRateFactor(void) 0x08123FD8
local Orig_GetMovementRateFactor
local function Hook_GetMovementRateFactor(obj)
  local cre = Game.GetObjectByID(obj.obj.obj_id)
  if cre:GetType() == OBJECT_TYPE_CREATURE then
    local mo, ba, ta = 0, 0, 0
    local can, level = Rules.CanUseClassAbilities(cre, CLASS_TYPE_MONK)
    if can and level > 3 then
      mo = 0.2
    end

    if cre:GetLevelByClass(CLASS_TYPE_BARBARIAN) >= 1 then
      ba = 0.1
    end

    ta = (cre['TA_MOVE_SPEED'] or 0) / 100 -- This is where you'd add in your custom factors,  I used a local var

    local mr = obj.cre_move_rate
    if mr > 1.5 then mr = 1.5 end
    return mr + ta + max(mo, ba)

  end

  return Orig_GetMovementRateFactor(cre)
end

Orig_GetMovementRateFactor = Hook.hook {
  name = "GetMovementRateFactor",
  func = Hook_GetMovementRateFactor,
  length = 5,
  address = 0x08123FD8,
  type = 'double (*)(CNWSCreature *)',
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants