Jump to content

Object script not firing. Why?


NameNotPresent

Recommended Posts

:armscrossed: Why does this script not function? The gamemode block in particular. The gamemode block is very similar to another object script I have that successfully removes it's item in the same way. But this script is not working at all the object is not being removed. :wallbash:

 

I was using getsecondspassed and switched to getusertime as I thought that may have something to do with it but it did not.

 

 

scn AAAnnpAttackInteruptTimer ;This script is used on an item that is used as a flag to signal that the attack
;may be interupted. The Onhit script checks for this flag item.

float TimePassed
ref Attacker
float WeaponInteruptTime
ref Weapon
short WeaponAnimationType
float StartTime

begin onadd

Let StartTime := GetUserTime["Millisecond"]
set Attacker to GetContainer
set WeaponAnimationType to Attacker.GetWeaponAnimType
if WeaponAnimationType ==0 ;attacker is unarmed.
set WeaponInteruptTime to 1
if Attacker.IsPowerAttacking ==0
set WeaponInteruptTime to 300 ;Set the time duration the attack can be canceled.
else
if Attacker.IsAnimGroupPlaying attackpower
set WeaponInteruptTime to 500 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackForwardPower
set WeaponInteruptTime to 720 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackBackPower
set WeaponInteruptTime to 500 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackLeftPower
set WeaponInteruptTime to 500 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackRightPower
set WeaponInteruptTime to 500 / WeaponInteruptTime
endif
endif
elseif WeaponAnimationType ==1 ;One hand weapon.
set WeaponInteruptTime to GetWeaponSpeed Weapon
if Attacker.IsPowerAttacking ==0
set WeaponInteruptTime to 300 / WeaponInteruptTime ;Set the time duration the attack can be canceled.
else
if Attacker.IsAnimGroupPlaying attackpower
set WeaponInteruptTime to 400 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackForwardPower
set WeaponInteruptTime to 640 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackBackPower
set WeaponInteruptTime to 500 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackLeftPower
set WeaponInteruptTime to 510 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackRightPower
set WeaponInteruptTime to 670 / WeaponInteruptTime
endif
endif
elseif WeaponAnimationType ==2 ;Two hand weapon.
set WeaponInteruptTime to GetWeaponSpeed Weapon
if Attacker.IsPowerAttacking ==0
set WeaponInteruptTime to 300 / WeaponInteruptTime ;Set the time duration the attack can be canceled.
else
if Attacker.IsAnimGroupPlaying attackpower
set WeaponInteruptTime to 600 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackForwardPower
set WeaponInteruptTime to 620 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackBackPower
set WeaponInteruptTime to 600 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackLeftPower
set WeaponInteruptTime to 530 / WeaponInteruptTime
elseif Attacker.IsAnimGroupPlaying AttackRightPower
set WeaponInteruptTime to 600 / WeaponInteruptTime
endif
endif
endif

end

begin gamemode

if Attacker.IsAttacking
messageex "ATTACK"
Let TimePassed := GetUserTime["Millisecond"]
set TimePassed to TimePassed - StartTime
if TimePassed > WeaponInteruptTime
MessageEX "Time Up!"
RemoveMe
endif
else
MessageEX "Not Attacking"
RemoveMe
endif
if Attacker.GetDead ==1
RemoveMe
elseif Attacker.GetKnockedState !=0
RemoveMe
endif
end

 

This script is attached to an item that is added by an OnAttack eventhandler. The OnAttack eventhandler also adds another scripted item which removes it's self if the actor is not attacking the same as this scripted item should. :huh: :psyduck:

Edited by NameNotPresent
Link to comment
Share on other sites

What are you trying to do? Maybe the thing can be achieved with a smaller amount of scripting?

 

Your GameMode block fails to remove the item if:

  • ( Attacker is attacking ) AND
  • ( TimePassed <= WeaponInterruptTime ) AND
  • ( Attacker is not dead ) AND
  • ( Attacker is neither knocked down nor knocked out )

Edit: How do I format that... ? :psyduck:

 

Edit 2: As in, for the item to be removed:

  • ( Attacker must not be attacking ) OR
  • ( Attacker must be attacking AND TimePassed > WeaponInteruptTime ) OR
  • ( Attacker must be dead ) OR
  • ( Attacker must be knocked down/out )

Edit 3: Also, to make it easier to read the script, you could use the code tags:

 

[ code ] content [ /code ]

 

turns into

 

content

And it is interesting how you are OBSE expressions and normal expressions mixed like that... (let and set). Maybe it is fine, but reading the thing becomes more interesting. You also have ( If <boolean_expression> == 1 ) and ( If <boolean_expression> ) mixed. And MessageEX, even though you do not supply anything other than a simple string to it. Trying to stick to some sort of personal guidelines is handy, and it makes reading the scripts easier. It is just a hobby, but still. :thumbsup:

Edited by Contrathetix
Link to comment
Share on other sites

1) GetUserTime vs GetSecondsPassed

GetUserTime is the Windows time, so if you save the game then reload after a day, the script will detect an entire day passed.

GetSecondsPassed is the right command to use when you need to only consider the "game" or "script" time (and not the real world time), but remember GetSecondsPassed calculate the time passed since the previous run of the script, so you need to cumulate the result like a counter.

Let TimePassed += GetSecondsPassed   ;use += to cumulate the time passed in every frame

.

 

2) GetContainer inside OnAdd block

While it seems an obvious choice, it's bad instead: OnAdd fires in the same frame the item is being added, and sometimes the item has not yet registered his container, so GetContainer may return 0. When the GameMode block checks Attacker.IsAttacking with Attacker == NULL, the script may crash. So, you need to call GetContainer in the GameMode block, and return if the container is still 0 / NULL.

Begin GameMode
  Let attacker := GetContainer
  If attacker == 0
    Return
  EndIf
  ...

.

 

3) IsAttacking and GetDead/GetKnockedState

Apart the fact == 1 and != 0 are totally useless/redundant (== 1 is useless in a boolean command/expression, while != 0 is always useless).

Think about it: if the actor is attacking, he can't be dead/knocked, else if not attacking, the item is removed. This means the script will NEVER have a chance to enter the GetDead/GetKnockedState blocks, which can be removed.

 

 

4) RemoveMe called after other commands
The script engine is very unstable with RemoveMe: this command must never be called after another command in the script in the same frame, else the game likes to CTD. Example: in the GameMode, you use RemoveMe after the commands IsAttacking, GetUserTime and MessageEx. This is bad.
What to do? Just set to 1 a variable/flag and remove the item in the next frame, ensuring no command is called before RemoveMe. This implies the GameMode block's first action should be checking such flag and eventually use RemoveMe immediately (even before the GetContainer check).
Begin GameMode
  If mustRemove   ;first check
    RemoveMe     ;RemoveMe called before any command. Good.
  EndIf

  Let attacker := GetContainer   ;Check for container here, as OnAdd is not reliable.
  If attacker == 0      ;no container. Stop before we cause problems.
    Return
  ElseIf Attacker.IsAttacking
    MessageEx "ATTACK"
    Let TimePassed += GetSecondsPassed   ;cumulate the time passed every frame
    If TimePassed > WeaponInteruptTime
      MessageEX "Time Up!"
      Let mustRemove := 1
    EndIf
  Else
    MessageEX "Not Attacking"
    Let mustRemove := 1
  EndIf
End
Edited by forli
Link to comment
Share on other sites

Thanks guys. I'll use the code tag next time.

 

 


2) GetContainer inside OnAdd block

While it seems an obvious choice, it's bad instead: OnAdd fires in the same frame the item is being added, and sometimes the item has not yet registered his container, so GetContainer may return 0. When the GameMode block checks Attacker.IsAttacking with Attacker == NULL, the script may crash. So, you need to call GetContainer in the GameMode block, and return if the container is still 0 / NULL.

Begin GameMode
  Let attacker := GetContainer
  If attacker == 0
    Return
  EndIf
  ...

:dance: That was it. Thank you very much.

 

I have the GetDead and GetKnockedState there because I had issues with another script if the actor died while performing a melee attack.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...