DetectCollision Script Malfunction

Post » Sun Jan 24, 2010 4:09 am

So i'm typing away, writing my scripts when I get to a point where the player needs to walk over a blue collision box to activate the following script:
begin 01mc_collisionwall1155432short DoOnceif ( DoOnce == 1 )	returnendifif ( DoOnce == 0 )	if ( GetCollidingPC == 0 )		return	endif	if ( GetCollidingPC == 1 )		If ( GetJournalIndex "mc_dissidentpriest" != 340 )			return		endif		if ( GetJournalIndex "mc_dissidentpriest" = 340 )			"01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"			"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"			"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"			"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"			"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"			Journal "mc_dissidentpriest" 350			set DoOnce to 1		endif	endifendifend

What this does is gives a spell effect when you step on the box, and then the journal update starts another script that teleports each of the npc's being casted upon to a new location infront of you. This is the script on them:
begin 01mc_ordinatorsummonupshort DoOnceif ( DoOnce == 1 )	returnendifif ( DoOnce == 0 )	if ( GetJournalIndex != 350 )		return	endif	if ( GetJournalIndex = 350 )		"01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"		"01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"		"01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"		"01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"		Journal "mc_dissidentpriest" 360		Set DoOnce to 1	endifendifend
This script is placed on a red sound marker and the first one on the blue collision box, by suggestion of PeachyKeen.

Now, my problem is that when I walk over the box, the npc only cast the spell once, then nothing else happens. No journal update or anything. Is there a solution? Should I make a individual script for each one of the ordinator's that are being teleported?

EDIT: Is it possible to have multiple actors for one line?
i.e.:
"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator", "01mc_enslavedordinator1" ; etc.

User avatar
cassy
 
Posts: 3368
Joined: Mon Mar 05, 2007 12:57 am

Post » Sun Jan 24, 2010 11:30 am

There are a lot of people who can be more helpful than me on this question, but I think perhaps you are expecting too much out of one character in one frame. You could test that by commenting out all but one of those "cast" commands. If it then works and you get your journal update, you will have to find a different mechanism... for instance, the spell could summon all of the ordinators with one casting perhaps, or you could run a timer to have the separate summonings.
User avatar
LADONA
 
Posts: 3290
Joined: Wed Aug 15, 2007 3:52 am

Post » Sun Jan 24, 2010 10:27 am

neildarkstar has the general idea of it. If you add some delays, it should work much better (you're telling the AI to do 4 things at once, and it doesn't like to queue them up).

You cannot put more than one target in one line, either. The first way that comes to mind for this is a timer, which you could set to cast every 1-2 seconds. You might be able to use the cast sound (GetSoundPlaying) to check as well, but that's somewhat more complicated.
User avatar
Josh Dagreat
 
Posts: 3438
Joined: Fri Oct 19, 2007 3:07 am

Post » Sun Jan 24, 2010 8:50 am

There are a lot of people who can be more helpful than me on this question, but I think perhaps you are expecting too much out of one character in one frame. You could test that by commenting out all but one of those "cast" commands. If it then works and you get your journal update, you will have to find a different mechanism... for instance, the spell could summon all of the ordinators with one casting perhaps, or you could run a timer to have the separate summonings.

hmm, I think I'll use that time idea, it sounds like it would be cooler anyways :D

So, to anyone who can help, would this work for that?
begin mc_collisionwall1155432short DoOnceshort startshort statefloat lastTimefloat currentTimeif ( DoOnce == 1 )	returnendifif ( DoOnce == 0 )	if ( GetCollidingPC == 0 )		return	endif	if ( GetCollidingPC == 1 )		If ( GetJournalIndex "mc_dissidentpriest" != 340 )			return		endif		if ( GetJournalIndex "mc_dissidentpriest" == 340 )			"01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"			Journal "mc_dissidentpriest" 350			set DoOnce to 1			set Start to 1		endif	endifendifif ( start == 0 )    returnendif;block that only allows entry every 5 secondsset currentTime to currentTime + getSecondsPassedif ( currentTime < lastTime + 5 )    returnendifset lastTime to currentTimeset state to state + 1;the castingif ( state == 1 )	"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"	"01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"elseif ( state == 2 )	"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"	"01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"elseif ( state == 3 )	"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"	"01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"elseif ( state == 4 )	"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"	"01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"    journal "mc_dissidentpriest" 360    "01mc_drevisTaphael"->forcegreetingendifend


I've tried to make it to where, under the certain conditions in the beginning, it will allow it to pass through to the "State" section. What should happen is that after 5 seconds each one of these states will happen. I got this script from my other mod, and it was written by people in this forum, as i'm sure they'll remember upon seeing it, if they do. I'm unsure if this is a good method, but it would also disable the use of the second script, making only one script necessary.
User avatar
Stephanie Valentine
 
Posts: 3281
Joined: Wed Jun 28, 2006 2:09 pm

Post » Sun Jan 24, 2010 6:11 am

It looks to me as if it should work fine, but the acid test is just try it and see if you get what you want.
User avatar
Philip Lyon
 
Posts: 3297
Joined: Tue Aug 14, 2007 6:08 am

Post » Sun Jan 24, 2010 10:15 am

It looks to me as if it should work fine, but the acid test is just try it and see if you get what you want.

I tried it and I got the journal update as it is supposed to be, but the npc interactions never occured. Grr. :brokencomputer:
User avatar
Dan Wright
 
Posts: 3308
Joined: Mon Jul 16, 2007 8:40 am

Post » Sun Jan 24, 2010 3:50 am

I'm not 100% certain, but I think the problem is that you have an if block right at the start of the script that sets return if DoOnce = 1.
then right after the journal update you set doonce to 1. I think the result is probably that after the first time through the script never gets to the timer or the associated code. The fix would be to either set a condition based on your variable "state" to that doOnce block or not set doOnce until the script has completed.
User avatar
lolly13
 
Posts: 3349
Joined: Tue Jul 25, 2006 11:36 am

Post » Sun Jan 24, 2010 11:29 am

I'm not 100% certain, but I think the problem is that you have an if block right at the start of the script that sets return if DoOnce = 1.
then right after the journal update you set doonce to 1. I think the result is probably that after the first time through the script never gets to the timer or the associated code. The fix would be to either set a condition based on your variable "state" to that doOnce block or not set doOnce until the script has completed.

That would have stopped it, but I changed it and still no response. I think i'll just rewrite it using different methods, and get it to work differently...

edit: I rewrote it, and it still doesn't work. I don't know whats wrong with either of them >.<
Heres the newer one :
begin mc_collisionwall1155432short DoOnceshort startshort statefloat timerif ( DoOnce == 1 )	returnendifif ( DoOnce == 0 )	if ( GetCollidingPC == 0 )		return	endif	if ( GetCollidingPC == 1 )		If ( GetJournalIndex "mc_dissidentpriest" != 340 )			return		endif		if ( GetJournalIndex "mc_dissidentpriest" == 340 )			"01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"			Journal "mc_dissidentpriest" 350			set Start to 1		endif	endifendifif ( start == 0 )    returnendifif ( start == 1 )    set state to 1endif;block that only allows entry every 5 secondsset timer to ( timer + getSecondsPassed )set state to state + 1;the castingif ( timer == 1 )	if ( state == 1 )		"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"		"01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"	endifelseif ( timer == 3 )	if ( state == 2 )		"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"		"01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"	endifelseif ( timer == 5 )	if ( state == 3 )		"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"		"01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"	endifelseif ( timer == 7 )	if ( state == 4 )		"01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"		"01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"    	journal "mc_dissidentpriest" 360    	"01mc_drevisTaphael"->forcegreeting		set DoOnce to 1	endifendifend

User avatar
Matthew Barrows
 
Posts: 3388
Joined: Thu Jun 28, 2007 11:24 pm

Post » Sat Jan 23, 2010 11:16 pm

The issue is most likely with the timers. Timer/time is a float, float rarely (if ever) == anything. You need to either provide a range (> 4 && < 5) or just use a greater-than test (preferable, since very low framerate can break even ranges). I'd suggest reseting the timer after each cast, something like:

set timer to ( timer + GetSecondsPassed )if ( timer > 5 ) ; Every 5 seconds, trigger the next action    if ( state == 1 )        "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"        "01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 2 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"                "01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 3 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"                "01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 4 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"                "01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 5 )        Journal "mc_dissidentpriest" 360        "01mc_drevisTaphael"->ForceGreeting        set DoOnce to 1        return ; Return to the top of the script since we are done here    endif    ; Now handle resetting the loop. Reset timer and increment the state. 5 seconds later, it will run through this again.    Set state To ( state + 1 )    Set timer To 0endif


That has somewhat less duplicate code, makes it easier to add new blocks, and could be more reliable overall (all good things). :)

Also, why are you using return so much? It's typically intended to dodge low-performance segments or break out of loops early, not so much a general stop. In addition, some of your conditions would read much simpler if you used if/elseif/else/endif more, for example:

if ( DoOnce == 1 )        if ( GetCollidingPC == 1 )                if ( GetJournalIndex "mc_dissidentpriest" == 340 )                        "01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"                        Journal "mc_dissidentpriest" 350                        set Start to 1                endif        endifendif


Those don't need "if [not condition] return" before each one. Simpler, clearer code is better, fewer bugs.
User avatar
Craig Martin
 
Posts: 3395
Joined: Wed Jun 06, 2007 4:25 pm

Post » Sun Jan 24, 2010 8:24 am

The issue is most likely with the timers. Timer/time is a float, float rarely (if ever) == anything. You need to either provide a range (> 4 && < 5) or just use a greater-than test (preferable, since very low framerate can break even ranges). I'd suggest reseting the timer after each cast, something like:

set timer to ( timer + GetSecondsPassed )if ( timer > 5 ) ; Every 5 seconds, trigger the next action    if ( state == 1 )        "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"        "01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 2 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"                "01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 3 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"                "01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 4 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"                "01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 5 )        Journal "mc_dissidentpriest" 360        "01mc_drevisTaphael"->ForceGreeting        set DoOnce to 1        return ; Return to the top of the script since we are done here    endif    ; Now handle resetting the loop. Reset timer and increment the state. 5 seconds later, it will run through this again.    Set state To ( state + 1 )    Set timer To 0endif


That has somewhat less duplicate code, makes it easier to add new blocks, and could be more reliable overall (all good things). :)

Also, why are you using return so much? It's typically intended to dodge low-performance segments or break out of loops early, not so much a general stop. In addition, some of your conditions would read much simpler if you used if/elseif/else/endif more, for example:

if ( DoOnce == 1 )        if ( GetCollidingPC == 1 )                if ( GetJournalIndex "mc_dissidentpriest" == 340 )                        "01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"                        Journal "mc_dissidentpriest" 350                        set Start to 1                endif        endifendif


Those don't need "if [not condition] return" before each one. Simpler, clearer code is better, fewer bugs.

I tried implementing your block into the script, and nothing happened :brokencomputer: :brokencomputer:
edit :This is my current script, it still only gets to the journal entry like before.
begin 01mc_collisionwall1155432short DoOnceshort statefloat timerif ( DoOnce == 1 )	returnendifif ( DoOnce == 0 )	if ( GetCollidingPC == 0 )		return	endif	if ( GetCollidingPC == 1 )		If ( GetJournalIndex "mc_dissidentpriest" != 340 )			return		endif		if ( GetJournalIndex "mc_dissidentpriest" == 340 )			"01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"			Journal "mc_dissidentpriest" 350		endif	endifendifset timer to ( timer + GetSecondsPassed );block that only allows entry every 5 secondsif ( timer > 3 ) ; Every 3 seconds, trigger the next action    if ( state == 1 )        "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator1"        "01mc_enslavedordinator1"->PositionCell, 2576 4568 12126 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 2 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator"                "01mc_enslavedordinator"->PositionCell, 2501 4503 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 3 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator2"                "01mc_enslavedordinator2"->PositionCell, 2505 4570 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 4 )                "01mc_DrevisTaphael"->cast "01mc_ordinatorsummonspell", "01mc_enslavedordinator3"                "01mc_enslavedordinator3"->PositionCell, 2505 4629 12125 0 "Abal ChuFlour's Shack, Hidden Area"    elseif ( state == 5 )        Journal "mc_dissidentpriest" 360        "01mc_drevisTaphael"->ForceGreeting        set DoOnce to 1        return ; Return to the top of the script since we are done here    endif    ; Now handle resetting the loop. Reset timer and increment the state. 5 seconds later, it will run through this again.    Set state To ( state + 1 )    Set timer To 0endifend

User avatar
Bereket Fekadu
 
Posts: 3421
Joined: Thu Jul 12, 2007 10:41 pm

Post » Sun Jan 24, 2010 4:59 am

In that, it looks like the returns are breaking it.

Look at the first if block:
if ( DoOnce == 1 )        returnendifif ( DoOnce == 0 )        if ( GetCollidingPC == 0 )                return        endif        if ( GetCollidingPC == 1 )                If ( GetJournalIndex "mc_dissidentpriest" != 340 )                        return                endif                if ( GetJournalIndex "mc_dissidentpriest" == 340 )                        "01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"                        Journal "mc_dissidentpriest" 350                endif        endifendif


That reads: "if ( DoOnce == 1 OR ( DoOnce == 0 AND GetCollidingPC != 1 AND GetJournalIndex != 340 ) ) return;".
That covers the vast majority of cases. Because you have returns, execution will rarely even hit the second block. You need to get rid of the returns, just keep a single one at the start, then use variables to switch between the start block and the timer.
User avatar
carrie roche
 
Posts: 3527
Joined: Mon Jul 17, 2006 7:18 pm

Post » Sun Jan 24, 2010 1:30 pm

In that, it looks like the returns are breaking it.

Look at the first if block:
if ( DoOnce == 1 )        returnendifif ( DoOnce == 0 )        if ( GetCollidingPC == 0 )                return        endif        if ( GetCollidingPC == 1 )                If ( GetJournalIndex "mc_dissidentpriest" != 340 )                        return                endif                if ( GetJournalIndex "mc_dissidentpriest" == 340 )                        "01mc_DrevisTaphael"->addspell "01mc_ordinatorsummonspell"                        Journal "mc_dissidentpriest" 350                endif        endifendif


That reads: "if ( DoOnce == 1 OR ( DoOnce == 0 AND GetCollidingPC != 1 AND GetJournalIndex != 340 ) ) return;".
That covers the vast majority of cases. Because you have returns, execution will rarely even hit the second block. You need to get rid of the returns, just keep a single one at the start, then use variables to switch between the start block and the timer.

Oh wow how obvious. Since it update the journal to 350 and only lets it continue if its 340, it's stopping it, Thanks!!

edit: it works now, thanks so much!
User avatar
CHANONE
 
Posts: 3377
Joined: Fri Mar 30, 2007 10:04 am

Post » Sun Jan 24, 2010 12:08 am

Are all those numbers really necessary in the script name? Always try and keep ID's short and sharp.
User avatar
sally R
 
Posts: 3503
Joined: Mon Sep 25, 2006 10:34 pm


Return to III - Morrowind