NameNotPresent Posted July 21, 2016 Share Posted July 21, 2016 (edited) :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 TimePassedref Attackerfloat WeaponInteruptTimeref Weaponshort WeaponAnimationTypefloat StartTimebegin 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 endifendbegin 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 endifend 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 July 21, 2016 by NameNotPresent Link to comment Share on other sites More sharing options...
Surilindur Posted July 22, 2016 Share Posted July 22, 2016 (edited) 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 contentAnd 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 July 22, 2016 by Contrathetix Link to comment Share on other sites More sharing options...
forli Posted July 22, 2016 Share Posted July 22, 2016 (edited) 1) GetUserTime vs GetSecondsPassedGetUserTime 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 blockWhile 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/GetKnockedStateApart 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 commandsThe 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 July 22, 2016 by forli Link to comment Share on other sites More sharing options...
NameNotPresent Posted July 25, 2016 Author Share Posted July 25, 2016 Thanks guys. I'll use the code tag next time. 2) GetContainer inside OnAdd blockWhile 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 More sharing options...
Recommended Posts