
**********************************************
Remember the tag values that I had suggested in my first post in this thread?
How about extending them just a little bit to have some real programming ability here:
First of all, it would be good if we had more than one of those tags for each actor, for instance about 16 of them or any amount that you preffer, in an array like this:
int Variable[16];
Variable[0] is read only, and always contains the actor's index in the game's actor array.
Variable[1] contains the actor's user, and it is read only.
Variable[2] contains the actor's killer, and it is read only.
Variable[3] contains the actor's current target, and we can change it on the fly.
Variable[4]...Variable[15] usable for other purposes.
**********************************************
Action functions:
A_SetVariable( int index, int val1, int val2 )
Variable[index] = Random(val1,val2)
A_ChangeVariable( int index, int val1, int val2 )
Variable[index] = Variable[index]+Random(val1,val2)
A_CopyVariable( int index1, int index2 )
Variable[index2] = Variable[index1]
A_CompareVariables( int index1, int index2, int index3 )
if Variable[index1] < Variable[index2] then set Variable[index3] to -1
if Variable[index1] = Variable[index2] then set Variable[index3] to 0
if Variable[index1] > Variable[index2] then set Variable[index3] to 1
A_Jump_if_Variable_in( int index, int val1, int val2 )
if Variable[index] is inside the range (val1---val2) then jump.
ACS functions:
Actor_SetVariable( int tid, int index, int value )
Changes the the specific actor Variable, tid of 0 means the activator's variable.
int Actor_GetVariable( int tid, int index)
Gets one of the actor's variable's content.
**********************************************
If we had a function like Random( int val1, int val2), that we could use in DECORATE definitions, we could simplify the last section like this:
Action functions:
A_SetVariable( int index, value )
Variable[index] = value
A_ChangeVariable( int index, value )
Variable[index] = Variable[index]+value
...
**********************************************
OK now that we have some variables to play with, how about these additions, and removing any action functions that could be replaced by them:
A_Script( int activator_index, ... )
Calls a script, and sets the activator to the stored actor inside Variable[activator_index].
this means 0 is the current actor, and 1 is the user... and values bigger then 3 can be stored actors for later refrence, like:
A_CopyVariable(3,7), would store the current hate target inside Variable[7], and if there is no actor by the index of Variable[7], it would do nothing.
A_Special( int activator_index, ... )
Calls the special, and sets the activator to the stored actor inside Variable[activator_index]
**********************************************
A_GetHealth( int actor_index, int Index )
Variable[index] = Actor( Variable[actor_index] ) --> GetHealth;
A_SetHealth( int actor_index, int index )
Actor( Variable[actor_index] ) --> SetHealth( Variable[index] )
A_GetDistance( int actor_index, int index )
Variable[index] = GetDistance( Self, Actor( Variable[actor_index] ) );
A_GetSectorLight( int actor_index, int index )
Variable[index] = GetSectorLight( Actor( Variable[actor_index] ) );
A_GetSpeed( int actor_index, int index )
Variable[index] = GetSpeed( Actor( Variable[actor_index] ) );
A_SetSpeed( int actor_index, int index )
Actor( Variable[actor_index] ) --> SetSpeed( Variable[index] )
**********************************************
A_GetActorVariable( int actor_index, int index, int var_index )
Variable[index] = Actor( Variable[actor_index] ) --> Variable[var_index]
A_SetActorVariable( int actor_index, int index, int var_index )
Actor( Variable[actor_index] ) --> Variable[var_index] = Variable[index]
**********************************************
A_GetFlag( int actor_index, int index, int FlagTag )
Variable[index] = 1 if the specified flag of the specified actor is set, 0 otherwise.
A_SetFlag( int actor_index, int index, int FlagTag )
if Variable[index] is zero, it clears the specified flag of the specified actor, otherwise it would set it.
A_Check_in_WaterZone( int actor_index, int index )
Variable[index] = 1 if specified actor is in water zone, 0 otherwise.
A_Check_in_Sight( int actor_index, int index )
Variable[index] = 1 if the specified actor is in sight, 0 otherwise.
A_Check_Can_See( int actor_index, int index )
Variable[index] = 1 if the specified actor can see the current actor, 0 otherwise.
**********************************************
A_Jump( int steps )
Jump ahead by "steps" frames, "Random" function would take case of the rest.
A_JumpVar( int index )
Jump ahead by Variable[index] frames.
**********************************************
A_DropMarker( int actor_index, int index, bool NoGravity )
Drops a shootable, but invisible and nonblocking marker item at the specified actor, and keeps it's refrence inside Variable[index].
A_RemoveActor( int actor_index, int index )
Removes the specified actor from the game.
A_Check_Teleport( int target_index, int index, bool fog, bool telefrag )
Tries to teleport to the position of the specified target, and if successful, sets Variable[index] to 1, otherwise to 0, and would optionally have a teleport fog or force a telefrag if needed.
**********************************************
Some additional flags:
NORETALIATE: would ignore damage and would not change target.
NOFARATTACKS: would not jump to "Missile" state.
NONEARATTACKS[/b: would not jump to "Melee" state.
FLEETARGET: marks the actor as a flee target.
USETARGET: would not far attack the target and instead of a "Melee" attack, would "Use" it, i.e. forces it to jump to it's "Use" state.
Target has to have HOSTILEUSE it we want it to accept usage from enemy actors, and and if it has FACEUSER flag, then it would face the user actor before trying to call the "Use" state, even if it has no "Use" state.
ACS functions:
Thing_Use( int tid, int target_tid, bool Persistent );
Would set the actor's target to another actor and would set the USETARGET flag od the actor and would optionally set the NORETALIATE flag as well.
**********************************************
A_FindActorByFlags( int index, int max_distance, [FlagSet], [FlagClear] )
Finds the nearest actor that has all the flags in the [FlagSet] and none of the slags in [FlagClear] and places its refrence inside Variable[index], FlagSet can be like: SHOOTABLE+MONSTER+DORMANT... or SHOOTABLE+FLEETARGET...
The actors should be within the max_distance range, and a -1 in the resulting variable, means no matching actor was found.
A_FindPlayer( int index, int max_distance, int player_index )
If player_index is zero then finds the nearest player and places its refrence inside Variable[index], or it would find the specified player, and -1 means not found.
**********************************************
A_Push( int actor_index, int ParaForce, int DiagForce, int ZForce )
Pushes the specified actor to some direction:
ParaForce<0 means it is pulled toward the current actor.
ParaForce>0 means it is pushed away.
DiagForce<0 means it is pushed to left in the eyes of the current actor
DiagForce<0 means it is pushed to right in the eyes of the current actor
ZForce<0 means it is pushed up
ZForce<0 means it is pushed down
We can program MaxRange (of my last suggestion) ourselves.
If we can use the Random function here, then the better.
If the specified actor is the current actor then ParForce is in the currently facing direnction.
**********************************************
OK, here is a way to emulate some particle systems by making our own actors, without excessive A_Script calls and causing probable performance hit, useful to simulate snows and bubbles and smokes:(bigger sprites and translucent), or any other thing you can think of that requires some random or patterned movement around, controlled from inside the actor definitions.
**********************************************
It we do not have "Random" function at hand then we need some actions functions like these:
A_ForceX( int actor_index, int f1, int f2 )
A_ForceY( int actor_index, int f1, int f2 )
A_ForceZ( int actor_index, int f1, int f2 )
These would force the specified actor movement speed in specific directions by a random value between f1 and f2 and note that these values can be negative as well, for instance A_ForceX(-10,10) would act like:
XVelocity=XVelocity+Random(-10,10);
Otherwise we can have a single action function:
A_Force( int actor_index, int ForceX, int ForceY, int ForceZ )
**********************************************
A_ForceVarX( int actor_index, int index )
A_ForceVarY( int actor_index, int index )
A_ForceVarZ( int actor_index, int index )
**********************************************
A_ForceRotateVarZ( int actor_index, int index, int f1, int f2 )
Which can act like the combination of these:
A_ForceX( Random(f1,f2)*Cos( Variable[index] ) )
A_ForceY( Random(f1,f2)*Sin( Variable[index] ) )
It we have "Random" function at hand then:
A_ForceRotateVarZ( int actor_index, int index, int force ).
Combined with actors that were NoGravity LowGravity and Gravity dependant we can make lots of different effects by these.
A_ForceRotateVarX and A_ForceRotateVarY could also be good additions.
**********************************************
And if the actors have a will of their own (i.e. Monsters) then we can simulate some special moments for them, like when they shadder in pain, or they get trapped in a hurricane or tornado(can be triggered by Tag values), or they get a bit dizzy after a hard blow and do some random movement before gaining their ballance:(Declayed actions by the help of Tag loops...).
Note: All these can be programmed into the actor definitions and would not need any ACS code to accompany them, and would be more useful for casual designers, also they would hit performance less than calling ACS functions, because they are compiled code.
P.S. We can make monsters that cast a hurricane spell on their targets and so on...
**********************************************
O.K. I'm waiting for the punishments...