Page 1 of 1

[?-r1884] inheritance oddities with "goto" (maybe not a bug)

Posted: Sun Sep 27, 2009 2:00 pm
by unknownna
When inheriting, shouldn't the new states override the inherited ones if defined?

Code: Select all

actor inheritance
{
states:
spawn:
     TNT1 A 4 A_Blah
     goto see
See:
     TNT1 A 4 A_BlahBlah
     goto spawn
   }
}

actor newactor : inheritance
{
states:
See:
     TNT1 A 8 A_DifferentBlahBlah
     goto spawn
   }
}
Not too sure on how to explain this properly, but I'll try.
Put simply, "newactor"'s see state will be ignored when it goes to spawn because of the goto see statement in "inheritance". Actually, this works both ways. Sometimes it does, and sometimes it does not. Check the wad I've included as a sample.

It includes 2 chainsaw marines. They're basically identical. They inherit from the same parent.
The first marine, "gmcs", doesn't have any states which goes to idle defined, but it does have it's own idle state defined.
The second one, "gmcs2", has every state which goes to idle defined.

For the second marine, everything works as it should.

For the first marine, the goto statements will randomly (so it seems) jump to either the newly defined states or to the states of the parent. Try to push the marine around. If the idle sounds stop playing, it has jumped to the parent's state.

Re: [?-r1884] inheritance oddities with "goto" (maybe not a bug)

Posted: Sun Sep 27, 2009 2:09 pm
by bagheadspidey
Unless this has changed recently, here's how it works: Goto destinations are resolved at compile time, and A_Jump* is resolved at run time... so in your inheritance::See state, the Goto "See" will go to inheritance::See, not the See state of your subclass.

An A_Jump(255,"See") should always go to the state belonging to whatever class is actually calling A_Jump.

Re: [?-r1884] inheritance oddities with "goto" (maybe not a bug)

Posted: Sun Sep 27, 2009 2:38 pm
by Gez
DECORATE manages to hide a part of the underlying code to the modder. A state, in Doom, has a pointer to the next state. Normally, this is set to the next state to be declared, but Goto, Wait, Loop and Stop all change the "next state" pointer.

Let's take a look at this code:

Code: Select all

Blah:
BLAH A 1
BLAH B 1
Loop
Blahblah:
BLAH C 1
BLAH D 1
BLAH E 1
Wait
Blahblahblah:
BLAH F 1
BLAH G 1
Goto "Blah"
Blahblahblahblah:
BLAH H 1
Stop
The result of that is that the first state (Blah+0) has its "next state" pointer set to Blah+1 because that's the state that follows it, and Blah+1 has its "next state" pointer set to Blah+0 because that's what the "loop" instruction tells it. Blahblah+2's pointer is set to itself, since the Wait instruction makes a state constantly loop on itself. Blahblahblah+1's pointer leads it to Blah. And Blahblahblahblah+0's pointer goes nowhere.

This is why gotos are static, not dynamic. Take this actor:

Code: Select all

Actor blah{
States
{
Spawn:
 BLAH A 1
 Goto "Blah1"
 BLAH B 1
Blah1:
 BLAH C 1
 Goto "Blah2"
 BLAH D 1
Blah2:
 BLAH E 1
 Goto "Spawn"
}}
This is technically the same as:

Code: Select all

Actor blah{
States
{
Spawn:
 BLAH A 1
 BLAH C 1
 BLAH E 1
 Loop
 BLAH B 1
 Goto Spawn + 1
 BLAH D 1
 Goto Spawn + 2
}}
Or, another example

Code: Select all

Spawn:
 BLAH ABC 1
Label:
 BLAH D 1
 Stop
Is the same as:

Code: Select all

Label:
 BLAH D 1
 Stop
 BLAH C 1
 Goto Label 
 BLAH B 1
 Goto Label + 1
Spawn:
 BLAH A 1
 Goto Label + 2
Obviously, the second version is silly. But they are indeed the same. There is no difference, as far as Doom is concerned, between the two versions; once parsed they'll be identical.

This is why dynamism requires the use of codepointers. When you have this code:

Code: Select all

State:
  BLAH A 1 A_JumpSomewhere
  BLAH B 1
the state after State+0 is State+1; however before State+0 is finished and Doom puts the actor in the next state, the codepointer will have changed the actor's state to something else (presumably). And codepointers are run by actors, so the logic here will be actor-dependent rather than state-dependent.