Home Risen Risen2 Risen3 Forum English Russian

Registrieren Hilfe Kalender Heutige Beiträge
Ergebnis 1 bis 12 von 12
  1. #1 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    Replacing the Interactions in a Potion template (or changing the model in a Spell template) works, but animations seem to be tied to scripts, so instead of drinking the potion our hero just "casts" the Potion.

    Any way around that or would this involve the use of the sdk to bring new scripts into the game?
    Bude ist offline

  2. #2 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    Nope, as far as I know you can't set the executed actions while consuming a item and the effects it should have separately.
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline

  3. #3 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    So I finally found some time and motivation to look into the SDK.
    Thanks to all the Scripts out there, I was able to get at least a basic grasp of the process.

    I was just gonna intercept InventoryUse_Player_Sprint, push in InventoryUse_Player_ConsumePotion before that - but that obv did not work, since I dont wait between them.
    (Is there a way to wait some time or wait for the Hero to end the Animation ?)

    I also found some Code where a specific Animation is called ("Teleport"). I put that in there instead of ConsumePotion, it was not perfect since the animations overlapped, but whatever.
    But where can I find a list of these Animation Strings?

    https://hastebin.com/uherevasox.cpp

    Hopefully someone with a little more knowledge than me can help me out a little bit.
    Bude ist offline

  4. #4 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    It's been a long time since I've worked on this stuff so take everything I say with a grain of salt.

    1. In the context of AIFunctions you should probably avoid playing animations by yourself. Let the AI system do it, gCScriptProcessingUnit::sAIPlayAniInstr.
    2. An AIFunction is a coroutine as far as I understand them. If you are not familiar with that term don't worry I'll explain it.
    An AIFunction isn't supposed to actually execute anything, instead it should post commands to the AI system, then wait for them to get done and post the next command until you are satisfied. This is because of the problem you described, you don't know when the animation has finished. But if you let the engine handle this stuff, it will notify you as soon as it's done.
    The return code of functions like gCScriptProcessingUnit::sAIPlayAniInstr tells you whether the engine needs some time to execute the instruction. If it does need some time, the AIFunction should pass control back to the engine and tell the engine that it should be called again when the instruction has been completed. That also means your AIFunction has to know where it left of last time. That's done through SRTSSStack and the macros FIRST_SUBTASK, NEXT_SUBTASK and SET_SUBTASK_DONE. Don't worry about how that actually works, I wrote it and I barely understood it back than. It doesn't matter when you are just using it.
    3. It's probably a bad idea to actually hook an AIFunction. You should register the old AIFunction under a new name and a new AIFunction under the old name. The new AIFunction does the additional stuff you want and then passes controll on to the old AIFunction using the engine.

    This is a more or less complex example of an AIFunction I wrote for dtc to show how the coroutine stuff works:
    Code:
    #include "Interact_Player_dtc_RopeRoll.h"
    
    #include "../hacks.h"
    #include "../ScriptAIUtil.h"
    #include "../SPU_AIInstr_structs.h"
    
    GEBool GE_STDCALL Interact_Player_dtc_RopeRoll::Impl(
        bTObjStack<gScriptRunTimeSingleState>& SRTSSStack, gCScriptProcessingUnit* SPU)
    {
        Entity Self;
        Entity Interactor;
        GELPByte __FIXME_0014 = reinterpret_cast<GELPByte>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014);
    
        if(__FIXME_0014)
        {
            Self.AttachTo(      reinterpret_cast<eCEntityProxy*>(__FIXME_0014 + 0x04)->GetEntity());
            Interactor.AttachTo(reinterpret_cast<eCEntityProxy*>(__FIXME_0014 + 0x10)->GetEntity());
        }
    
        FIRST_SUBTASK
    	{
            SET_SUBTASK_DONE;
    
            gui2.SetPageMode(gEPageMode_Panorama, GEFalse);
                
            EffectSystem::StartImageEffect("OverlayBlackScreen", 0.0, 1.0, 1.0);
    
            //Hero_Stand_None_None_P0_Kneel_Begin_N_Fwd_00_%_00_P0_0
            bCString Ani = Interactor.GetAni(g_strAction_Kneel, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0, gEAniState_Count);
            Interactor.AccessPropertySet<PSRoutine>().SetAniState(gEAniState_Kneel, gEAniState_Dummy0);
            CAIPlayAniInstr AIPlayAniInstr(Interactor, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
            if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
                return GEFalse;
        }
            
        NEXT_SUBTASK
    	{
    		SET_SUBTASK_DONE;
                
            //Hero_Kneel_None_None_P0_LockPick_Begin_N_Fwd_00_%_00_P0_0
            bCString Ani = Interactor.GetAni(g_strAction_Lockpick, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0, gEAniState_Count);
            CAIPlayAniInstr AIPlayAniInstr(Interactor, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
            if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
                return GEFalse;
    	}
            
        NEXT_SUBTASK
    	{
    		SET_SUBTASK_DONE;
            
            //Hero_Kneel_None_None_P0_LockPick_Loop_N_Fwd_00_%_00_P0_0
            bCString Ani = Interactor.GetAni(g_strAction_Lockpick, g_strPhase_Loop, gEDirection_Fwd, GEFalse, gECombatPose_P0, gEAniState_Count);
            Interactor.StartPlayAni(Ani, -1, GEFalse, 1.0f, GETrue, static_cast<eAnimShared::eEMotionType>(0));
    
            CAIWaitInstr AIWaitInstr(Interactor, 2000);
            if(!gCScriptProcessingUnit::sAIWaitInstr(&AIWaitInstr, SPU, GEFalse))
                return GEFalse;
        }
            
        NEXT_SUBTASK
    	{
    		SET_SUBTASK_DONE;
    
            EffectSystem::StopImageEffect();
            
            world.SetSectorStatus("RopeRoll", GEFalse);
            world.SetSectorStatus("RopeTeleporter", GETrue);
            
            //Hero_Kneel_None_None_P0_LockPick_End_N_Fwd_00_%_00_P0_0
            bCString Ani = Interactor.GetAni(g_strAction_Lockpick, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0, gEAniState_Count);
            CAIPlayAniInstr AIPlayAniInstr(Interactor, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
            if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
                return GEFalse;
    	}
            
        NEXT_SUBTASK
    	{
    		SET_SUBTASK_DONE;
            
            //Hero_Kneel_None_None_P0_Stand_Begin_N_Fwd_00_%_00_P0_0
            bCString Ani = Interactor.GetAni(g_strAction_Stand, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0, gEAniState_Count);
            Interactor.AccessPropertySet<PSRoutine>().SetAniState(gEAniState_Stand, gEAniState_Dummy0);
            CAIPlayAniInstr AIPlayAniInstr(Interactor, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
            if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
                return GEFalse;
    	}
            
        NEXT_SUBTASK
    	{
    		SET_SUBTASK_DONE;
                
            gui2.RestoreUserPageMode();
            Entity::SetCameraTarget(Interactor, Interactor, GEFalse, *Hacks::GetUserCameraOffset(), GEFalse, None, -1.0);
            Entity::SetCurrentCameraByName("cam_normal", GETrue);
            Entity::GetPlayer().AccessPropertySet<PSRoutine>().ContinueRoutine();
    	}
    
    	return GETrue;
    }

    and this one shows how one AIFunction passes controll onto another:
    Code:
    #include "PreInteract_Player_dtc_Goto.h"
    
    #include "../hacks.h"
    #include "../ScriptAIUtil.h"
    #include "../SPU_AIInstr_structs.h"
    
    namespace ScriptProxies
    {
        //note that Script_Game doesn't share AIFunction Proxies as far as i can tell.
        //i don't know if sharing them will cause problems
        gCScriptProxyAIFunction PreInteract_Player_Goto("PreInteract_Player_Goto");
    }
    
    GEBool GE_STDCALL PreInteract_Player_dtc_Goto::Impl(
        bTObjStack<gScriptRunTimeSingleState>& SRTSSStack, gCScriptProcessingUnit* SPU)
    {
        Entity Interact;
        Entity User;
        gSAIScriptArgs* AIScriptArgs = reinterpret_cast<gSAIScriptArgs*>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014);
    
        if(AIScriptArgs)
        {
            Interact.AttachTo(AIScriptArgs->m_Other.GetEntity());
            User.AttachTo(AIScriptArgs->m_Self.GetEntity());
        }
    
        FIRST_SUBTASK
    	{
            SET_SUBTASK_DONE;
    
            User.AccessPropertySet<PSRoutine>().SetLocalCallback("OnPlayerInteract_Cancel");
            gui2.SetPageMode(gEPageMode_UserMin, GEFalse);
    
            Entity::SetCameraTarget(Interact, User, GEFalse, bCVector(0, 100, 0), GEFalse, None, -1.0);
            Entity::SetCurrentCameraByName("cam_dtc_interact_fix", GEFalse);
    
            AIScriptArgs = GE_NEW(gSAIScriptArgs(User, Interact));
            
            return SPU->CallAIFunction(ScriptProxies::PreInteract_Player_Goto, AIScriptArgs);
        }
    
    	return GETrue;
    }
    So what you should do is in your FIRST_SUBTASK you issue an gCScriptProcessingUnit::sAIPlayAniInstr order. And in the NEXT_SUBTASK you pass controll to the old AIFunction.
    All this has to be done so we can these SUBTASK thingys without completely fucking up the SRTSSStack.
    There are certainly shorter and maybe even "easier" ways of doing all of this, but this is as far as I can tell the cleanest and correct one.
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline Geändert von Kuchenschlachter (18.03.2017 um 10:45 Uhr)

  5. #5 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    Thanks a lot.

    I have run into another problem though.
    The ConsumePotion animation does not play - that seems to be a problem for a few animations that require an item in the heroes hands to interact with.
    Other Animations such as Lockpick work though. So I tried getting the animation with GetHoldAni (not sure I used that right, but it certainly does not work).

    Any suggestions?

    Also is there an easy or prefered way to Debug stuff or at least write to the console?

    Code:
    #include "Script.h"
    #include "ScriptPolicies.h"
    #include "ScriptDLLInterface.h"
    #include "SPU_AIInstr_structs.h"
    #include "ScriptAIUtil.h"
    
    namespace ScriptProxies
    {
    	static gCScriptProxyAIFunction InventoryUse_Player_Sprint("InventoryUse_Player_Sprint");
    }
    
    
    struct InventoryUse_Player_ConsumePotion_Sprint
    {
        static GEBool GE_STDCALL Impl(
            bTObjStack<gScriptRunTimeSingleState>& SRTSSStack, gCScriptProcessingUnit* SPU)
        {
    		Entity Other;
    		Entity Self;
    		
    		gSAIScriptArgs* AIScriptArgs = reinterpret_cast<gSAIScriptArgs*>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014);
    
    		if(AIScriptArgs)
    		{
    			Other.AttachTo(AIScriptArgs->m_Other.GetEntity());
    			Self.AttachTo(AIScriptArgs->m_Self.GetEntity());
    		}
    	
    		FIRST_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    			
    			//Consume Potion
    			//Hero_Stand_None_None_P0_ConsumePotion_Begin_O_Fwd_00_%_00_P0_0
    			bCString Ani = Self.GetHoldAni(g_strAction_ConsumePotion, gEItemHoldType_Potion, gEItemHoldType_Potion, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0); 
    			CAIPlayAniInstr AIPlayAniInstr(Self, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
    			
    			if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
    				return GEFalse;
    		}
    
    		NEXT_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    
    			//Consume Potion
    			//Hero_Stand_None_None_P0_ConsumePotion_End_O_Fwd_00_%_00_P0_0
    			bCString Ani = Self.GetHoldAni(g_strAction_ConsumePotion, gEItemHoldType_Potion, gEItemHoldType_Potion, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0); 
    			CAIPlayAniInstr AIPlayAniInstr(Self, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
    			if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
    				return GEFalse;
    		}
    
    		NEXT_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    
    			//InventoryUse_Player_Sprint
    			AIScriptArgs = GE_NEW(gSAIScriptArgs(Self, Other));
    
    			return SPU->CallAIFunction(ScriptProxies::InventoryUse_Player_Sprint, AIScriptArgs);
    		}
    
    		return GETrue;
        }
    };
    
    void GE_STDCALL ScriptInitImplementation()
    {
    	bTObjArray<bCString> DLLNames;
    	DLLNames.Add("Script_Game.dll");
    	AssertDLLsAreLoaded(DLLNames);
    
    	using namespace ScriptPolicies;
    
    	MANAGED_REGISTER(EScriptType_ScriptAIFunction, "InventoryUse_Player_ConsumePotion_Sprint", ClearScriptAIFunction<InventoryUse_Player_ConsumePotion_Sprint>);
    }
    Bude ist offline

  6. #6 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    That's quiet surprising to me. I was sure that there is no intrinstic requirement for any sort of additional entity to play the animations of an actor.

    We usually use something like this and a tool like DebugView for logging.
    Code:
    void DbgOut(GELPCChar p_c_Format, ...)
    {
        va_list p_c_ArgList;
        va_start(p_c_ArgList, p_c_Format);
    
        GEChar a_c_Buffer[255];
        vsprintf_s(a_c_Buffer, 255, p_c_Format, p_c_ArgList);
        OutputDebugString(a_c_Buffer);
    
        va_end(p_c_ArgList);
    }
    Concerning debugging, there really isn't anything special about it. Either setup your visual studio project to start risen for debugging. Or just attach to a running risen instance.

    And you asked if there is a list of all animations, you can extract the the animations archives data/compiled/animations.p*.
    Maybe the most sensible approach would be instead of playing any animation just invoke InventoryUse_Player_ConsumePotion or _AI_Consume before InventoryUse_Player_Sprint. Allthough this might cause serious problems, as InventoryUse_Player_Sprint wants to consume the item, it is invoked on and InventoryUse_Player_ConsumePotion does the same. Consuming an item twice... well that might not be such a good thing.
    On the other hand I had a quick look at InventoryUse_Player_ConsumePotion and _AI_Consume, and there happens a hell of a lot of stuff to play all the necessary animations, get the rigth items into the actors hands and so on. InventoryUse_Player_Sprint is comparatively simple.
    By the way I assume you use all of this with a newly created item, does that item have a PSCastInfo? Because as far as I can tell InventoryUse_Player_Sprint should crash for any item that doesn't have one.
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline

  7. #7 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    That's quiet surprising to me. I was sure that there is no intrinstic requirement for any sort of additional entity to play the animations of an actor.


    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    We usually use something like this and a tool like DebugView for logging.
    Code:
    void DbgOut(GELPCChar p_c_Format, ...)
    {
        va_list p_c_ArgList;
        va_start(p_c_ArgList, p_c_Format);
    
        GEChar a_c_Buffer[255];
        vsprintf_s(a_c_Buffer, 255, p_c_Format, p_c_ArgList);
        OutputDebugString(a_c_Buffer);
    
        va_end(p_c_ArgList);
    }
    Concerning debugging, there really isn't anything special about it. Either setup your visual studio project to start risen for debugging. Or just attach to a running risen instance.
    Thanks, noted.
    Will play around with that tomorrow.

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    And you asked if there is a list of all animations, you can extract the the animations archives data/compiled/animations.p*.
    Yeah, I already found that, but it wasn't terribly helpful.
    I did search the SDK though and found a list of animation strings in Script\gs_psroutine.h.

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    Maybe the most sensible approach would be instead of playing any animation just invoke InventoryUse_Player_ConsumePotion or _AI_Consume before InventoryUse_Player_Sprint. Allthough this might cause serious problems, as InventoryUse_Player_Sprint wants to consume the item, it is invoked on and InventoryUse_Player_ConsumePotion does the same.
    That was kind of the original plan, but that did not really work because I could not wait on the first AIFunction to finish. But I might have done smth wrong then (in regards to Subtask and only hooking the function).
    Will try that again and report back tomorrow.

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    Consuming an item twice... well that might not be such a good thing.
    Well I don't know ... I think through all my tests the item I used was often times not consumed at all. (but maybe I just did not properly pass that to the next function...)

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    On the other hand I had a quick look at InventoryUse_Player_ConsumePotion and _AI_Consume, and there happens a hell of a lot of stuff to play all the necessary animations, get the rigth items into the actors hands and so on. InventoryUse_Player_Sprint is comparatively simple.
    How would one look at that?

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    By the way I assume you use all of this with a newly created item, does that item have a PSCastInfo? Because as far as I can tell InventoryUse_Player_Sprint should crash for any item that doesn't have one.
    I just copied a health potion, removed the health modifier, renamed it and put my InventoryUse_Player_ConsumePotion_Sprint in the Interactions.
    Just checked with tple and no, it does not actually have a PSCastInfo - the way I call InventoryUse_Player_ConsumePotion_Sprint inside does not seem to care to much about the item anyways since it does not consume it either.


    Thanks for being so helpful btw .
    Did not expect such thorough, nice and fast answers .
    Bude ist offline

  8. #8 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    The animations played during _AI_Consume are...
    Entity:etOverlayAni(g_strAction_ConsumePotion, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0)
    Entity:etOverlayAni(g_strAction_ConsumePotion, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0)

    Zitat Zitat von Bude Beitrag anzeigen
    That was kind of the original plan, but that did not really work because I could not wait on the first AIFunction to finish. But I might have done smth wrong then (in regards to Subtask and only hooking the function).
    Will try that again and report back tomorrow.
    Ahhh... you are probably passing a gSAIScriptArgs to InventoryUse_Player_ConsumePotion without setting m_iParameter, right?
    I guess InventoryUse_Player_ConsumePotion can't figure out which item it is supposed to process. Set it to the value of the AIScriptArgs.m_iParameter passed to you
    (gSAIScriptArgs* AIScriptArgs = reinterpret_cast<gSAIScriptArgs*>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014).
    That might actually do the trick. It's basically the index of the item in the players inventory.

    I also had a second glance at InventoryUse_Player_Sprint. It can be and is much more lenient on "wrong" and incomplete parameters. Since it does basically nothing with the item except for calling PSCastInfo::Consume, which itself is protected against calls for items that don't have a PSCastInfo.
    That explains why your Item isn't consumed.

    "How do you look at that?"
    Well... disassembler, I use IDA and everyone I've ever talked to does so too.

    Well, you know, this is actually a very interesting topic.
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline

  9. #9 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    The animations played during _AI_Consume are...
    Entity:etOverlayAni(g_strAction_ConsumePotion, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0)
    Entity:etOverlayAni(g_strAction_ConsumePotion, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0)
    Thanks .
    Should have really tried all of the options :C.

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    Ahhh... you are probably passing a gSAIScriptArgs to InventoryUse_Player_ConsumePotion without setting m_iParameter, right?
    I guess InventoryUse_Player_ConsumePotion can't figure out which item it is supposed to process. Set it to the value of the AIScriptArgs.m_iParameter passed to you
    (gSAIScriptArgs* AIScriptArgs = reinterpret_cast<gSAIScriptArgs*>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014).
    That might actually do the trick. It's basically the index of the item in the players inventory.
    That did the trick - combined with a PSCastInfo where ConsumeItem is set to true, the item gets properly consumed.
    I did remove the PSCastInfo later on though (i now just consume the item in the code manually), since it would display a ManaCost which is a little dumb for a potion.

    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    "How do you look at that?"
    Well... disassembler, I use IDA and everyone I've ever talked to does so too.
    Wasn't yet very motivated to anything in that direction, but maybe I will try next week .


    So here is what I got. Just putting the item in the heroes hands seems to be good enough for the animations.
    And it already works pretty well - Only thing I already found is that the hero does not go back to combat automatically if you use the potion with your weapon out.
    Code:
    #include "Script.h"
    #include "ScriptPolicies.h"
    #include "ScriptDLLInterface.h"
    #include "SPU_AIInstr_structs.h"
    #include "ScriptAIUtil.h"
    
    namespace ScriptProxies
    {
    	static gCScriptProxyAIFunction InventoryUse_Player_Sprint("InventoryUse_Player_Sprint");
    }
    
    
    struct InventoryUse_Player_ConsumePotion_Sprint
    {
        static GEBool GE_STDCALL Impl(
            bTObjStack<gScriptRunTimeSingleState>& SRTSSStack, gCScriptProcessingUnit* SPU)
        {
    		Entity Other;
    		Entity Self;
    		GEInt Parameter;
    		PSInventory& Inventory = Self.AccessPropertySet<PSInventory>();
    		//This is probably unnecessary
    		GEInt OldStack = Inventory.GetRightHoldStack();
    		gECombatMode combat = Self.GetRestorePlayerCombatMode();
    		
    		// get Arguments
    		gSAIScriptArgs* AIScriptArgs = reinterpret_cast<gSAIScriptArgs*>(SRTSSStack[SRTSSStack.GetCount() - 1].__FIXME_0014);
    		if(AIScriptArgs)
    		{
    			Other.AttachTo(AIScriptArgs->m_Other.GetEntity());
    			Self.AttachTo(AIScriptArgs->m_Self.GetEntity());
    			Parameter = AIScriptArgs->m_iParameter;
    		}
    		
    		//even if this worked, it would not conform to the mechanics of every other Spell (i think)
    		/*
    		if(Self.GetMovementMode() == gECharMovementMode_Sprint)
    			return GEFalse;
    		*/
    
    		FIRST_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    
    			//Put the Potion in the Heroes right hand
    			Inventory.HoldRightStack(Parameter);
    
    			//Consume Potion Animation
    			//Hero_Stand_None_None_P0_ConsumePotion_Begin_O_Fwd_00_%_00_P0_0
    			bCString Ani = Self.GetOverlayAni(g_strAction_ConsumePotion, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0);
    			//bCString Ani = Self.GetOverlayAni(g_strAction_ConsumePotion, gEItemHoldType_Potion, gEItemHoldType_Potion, g_strPhase_Begin, gEDirection_Fwd, GEFalse, gECombatPose_P0); 
    			CAIPlayAniInstr AIPlayAniInstr(Self, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
    			
    			if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
    				return GEFalse;
    		}
    		
    		NEXT_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    
    			//Consume Potion Animation
    			//Hero_Stand_None_None_P0_ConsumePotion_End_O_Fwd_00_%_00_P0_0
    			bCString Ani = Self.GetOverlayAni(g_strAction_ConsumePotion, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0);
    			//bCString Ani = Self.GetOverlayAni(g_strAction_ConsumePotion, gEItemHoldType_Potion, gEItemHoldType_Potion, g_strPhase_End, gEDirection_Fwd, GEFalse, gECombatPose_P0);
    			CAIPlayAniInstr AIPlayAniInstr(Self, 0, Ani, 0, GEFalse, 1.0, GEFalse, GEFalse, GEFalse);
    			if(!gCScriptProcessingUnit::sAIPlayAniInstr(&AIPlayAniInstr, SPU, GEFalse))
    				return GEFalse;
    		}
    
    		NEXT_SUBTASK
    		{
    			SET_SUBTASK_DONE;
    			
    			//Not really necessary, but looks a little nicer
    			Inventory.HoldRightStack(OldStack);
    
    			//InventoryUse_Player_Sprint
    			AIScriptArgs = GE_NEW(gSAIScriptArgs(Self, Other));//Dont need the Item here, It does not have PSCastInfo anyways (since that would show manacost lol)
    			GEBool Result = SPU->CallAIFunction(ScriptProxies::InventoryUse_Player_Sprint, AIScriptArgs);
    			
    			//Remove the Item from the Inventory
    			Inventory.ConsumeItems(Parameter, 1);
    
    			//definitely does not do what I thought I would
    			Self.SetRestorePlayerCombatMode(combat);
    
    			return Result;
    		}
    
    		return GETrue;
        }
    };
    
    void GE_STDCALL ScriptInitImplementation()
    {
    	bTObjArray<bCString> DLLNames;
    	DLLNames.Add("Script_Game.dll");
    	AssertDLLsAreLoaded(DLLNames);
    
    	using namespace ScriptPolicies;
    
    	MANAGED_REGISTER(EScriptType_ScriptAIFunction, "InventoryUse_Player_ConsumePotion_Sprint", ClearScriptAIFunction<InventoryUse_Player_ConsumePotion_Sprint>);
    }
    Bude ist offline

  10. #10 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    Zitat Zitat von Bude Beitrag anzeigen
    And it already works pretty well - Only thing I already found is that the hero does not go back to combat automatically if you use the potion with your weapon out.
    That's curious, when using an item from inventory weapons are sheathed, that's normal. Using an item through QuickUse the combat mode is restored automatically. This doesn't depend on your new AIFunction. QuickUse is implemented by the QuickUse_Player* scripts. QuickUse_Player just executes the items InventoryUse interaction and afterwards restores the combatmode by calling the script ResumePlayerTask. You shouldn't have to do anything for this to work correctly.

    Get-/SetRestorePlayerCombatMode does virtually nothing, it just sets a field that is used in ResumePlayerTask to actually restore the combat mode.

    Even if SetRestorePlayerCombatMode did what you thought it does you should call it in a separate SUBTASK. CallAIFunction probably returns imediatly, a long time before InventoryUse_Player_Sprint is actually done. Therefore your cleanup happens way too soon.

    I did try to figure out how the combat mode is restored for InventoryUse_Player_ConsumePotion, and I suspected it to be related to _AI_HoldInventoryItems but after some superficial investigation it could as easily be InventoryUse_Player_ConsumePotion itself. It checks whether the UseType of the currently held item is a weapon, sets some flag and then... well that's where the superficial investigation would have become an in depth analysis...
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline

  11. #11 Zitieren
    Abenteurer
    Registriert seit
    Mar 2009
    Beiträge
    94
    Zitat Zitat von Kuchenschlachter Beitrag anzeigen
    That's curious, when using an item from inventory weapons are sheathed, that's normal. Using an item through QuickUse the combat mode is restored automatically. [...]
    Yes, you are right.
    Apparently putting smth else in our heroes hand prevented that from happening.
    As you can see I tried restoring whatever he was holding already (see OldStack), but that didn't work at all.(obviously in hindsight) (local variable definition, setting/using in different subroutines)
    I just made it global and it seems to be working flawlessly now.

    Thanks
    Bude ist offline

  12. #12 Zitieren
    Ritter
    Registriert seit
    May 2009
    Beiträge
    1.688
    We're morons. Well, at least I am
    I'm glad it finally works.
    [Bild: dtc_sig.jpg]

    Harald Iken: Überhaupt sollte man als Spieleentwickler das Wort "einfach" oder noch besser "mal eben" aus seinem Wortschatz streichen.
    Kuchenschlachter ist offline

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •