- Moved the implementation for the Thing_Damage special into another function

so that I can create the ACS function Thing_Damage2. It's exactly the same as
  Thing_Damage, except the damage type is specified by name. When I did this,
  I noticed that it didn't do anything useful for a TID of 0, so I made it
  affect the activator in that case.
- Added a new SetActorState ACS function:
    int SetActorState (int tid, str statename, optional bool exact);
  If tid is 0, it affects the script activator, otherwise it affects all the
  matching actors. Statename is the name of the state you want to put the
  actor in. The final parameter, exact, specifies whether or not partial
  state name matches are accepted. If you don't specify it or set it to
  false, if you try to do something like:
    SetActorState (0, "Foo.Bar");
  And the actor has a Foo state but no Foo.Bar state, it will enter the Foo
  state. If you set exact to true:
    SetActorState (0, "Foo.Bar", true);
  Then the actor must have a Foo.Bar state, or it will not change state at
  all, even if it has a Foo state.
  The return value for this function is the number of actors that successfully
  changed state. Note that you should refrain from using this function to
  enter special states such as Death, or unpredictable results could occur.


SVN r505 (trunk)
This commit is contained in:
Randy Heit 2007-03-23 22:26:14 +00:00
parent 38c821a96e
commit 490742cf46
7 changed files with 131 additions and 32 deletions

View File

@ -1,6 +1,31 @@
March 20, 2007
- Moved the implementation for the Thing_Damage special into another function
so that I can create the ACS function Thing_Damage2. It's exactly the same as
Thing_Damage, except the damage type is specified by name. When I did this,
I noticed that it didn't do anything useful for a TID of 0, so I made it
affect the activator in that case.
March 19, 2007
- Added a new SetActorState ACS function:
int SetActorState (int tid, str statename, optional bool exact);
If tid is 0, it affects the script activator, otherwise it affects all the
matching actors. Statename is the name of the state you want to put the
actor in. The final parameter, exact, specifies whether or not partial
state name matches are accepted. If you don't specify it or set it to
false, if you try to do something like:
SetActorState (0, "Foo.Bar");
And the actor has a Foo state but no Foo.Bar state, it will enter the Foo
state. If you set exact to true:
SetActorState (0, "Foo.Bar", true);
Then the actor must have a Foo.Bar state, or it will not change state at
all, even if it has a Foo state.
The return value for this function is the number of actors that successfully
changed state. Note that you should refrain from using this function to
enter special states such as Death, or unpredictable results could occur.
March 13, 2007
- Fixed: Morphed players did not regain their innate armor when unmorphing.
(Only Hexen has players with innate armor.)
(Only Hexen has players with innate armor, under normal conditions.)
March 12, 2007
- Changed the default player.startitem amount from 0 to 1.

View File

@ -486,7 +486,7 @@ FState *AActor::FindState (FName label, FName sublabel, bool exact) const
FStateLabel *slabel = info->StateList->FindLabel (label);
if (slabel != NULL)
{
if (slabel->Children != NULL)
if (sublabel != NAME_None && slabel->Children != NULL)
{
FStateLabel *slabel2 = slabel->Children->FindLabel(sublabel);
if (slabel2 != NULL)
@ -494,7 +494,14 @@ FState *AActor::FindState (FName label, FName sublabel, bool exact) const
return slabel2->State;
}
}
if (!exact) return slabel->State;
if (sublabel == NAME_None && slabel->Children != NULL && exact)
{
return NULL;
}
if (!exact)
{
return slabel->State;
}
}
}
return NULL;

View File

@ -4990,6 +4990,57 @@ int DLevelScript::RunScript ()
sp -= 2;
break;
case PCD_SETACTORSTATE:
{
const char *statename = FBehavior::StaticLookupString (STACK(2));
const char *dot;
FName label1, label2;
FState *state;
dot = strchr (statename, '.');
if (dot != NULL)
{
label1 = FName(statename, dot - statename, true);
label2 = FName(dot + 1, true);
}
else
{
label1 = FName(statename, true);
}
if (STACK(3) == 0)
{
state = activator->FindState (label1, label2, !!STACK(1));
if (state != NULL)
{
activator->SetState (state);
STACK(3) = 1;
}
else
{
STACK(3) = 0;
}
}
else
{
FActorIterator iterator (STACK(3));
AActor *actor;
int count = 0;
while ( (actor = iterator.Next ()) )
{
state = actor->FindState (label1, label2, !!STACK(1));
if (state != NULL)
{
actor->SetState (state);
count++;
}
}
STACK(3) = count;
}
sp -= 2;
}
break;
case PCD_PLAYERCLASS: // [GRB]
if (STACK(1) < 0 || STACK(1) >= MAXPLAYERS || !playeringame[STACK(1)])
{
@ -5095,6 +5146,11 @@ int DLevelScript::RunScript ()
}
}
}
case PCD_THINGDAMAGE2:
STACK(3) = P_Thing_Damage (STACK(3), activator, STACK(2), FName(FBehavior::StaticLookupString(STACK(1))));
sp -= 2;
break;
}
}

View File

@ -3,7 +3,7 @@
** ACS script stuff
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -539,6 +539,8 @@ public:
PCD_GETACTORPITCH,
PCD_SETACTORPITCH,
PCD_PRINTBIND,
PCD_SETACTORSTATE,
PCD_THINGDAMAGE2,
PCODE_COMMAND_COUNT
};

View File

@ -1127,34 +1127,7 @@ FUNC(LS_Thing_Destroy)
FUNC(LS_Thing_Damage)
// Thing_Damage (tid, amount, MOD)
{
FActorIterator iterator (arg0);
AActor *actor;
actor = iterator.Next ();
while (actor)
{
AActor *next = iterator.Next ();
if (actor->flags & MF_SHOOTABLE)
{
if (arg1 > 0)
{
P_DamageMobj (actor, NULL, it, arg1, MODtoDamageType (arg2));
}
else if (actor->health < actor->GetDefault()->health)
{
actor->health -= arg1;
if (actor->health > actor->GetDefault()->health)
{
actor->health = actor->GetDefault()->health;
}
if (actor->player != NULL)
{
actor->player->health = actor->health;
}
}
}
actor = next;
}
P_Thing_Damage (arg0, it, arg1, MODtoDamageType (arg2));
return true;
}

View File

@ -131,6 +131,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_na
bool leadTarget);
bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog);
bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog);
int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type);
//
// P_ENEMY

View File

@ -375,6 +375,41 @@ nolead: mobj->angle = R_PointToAngle2 (mobj->x, mobj->y, targ->x, targ->y);
return rtn != 0;
}
int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type)
{
FActorIterator iterator (tid);
int count = 0;
AActor *actor;
actor = (tid == 0 ? whofor0 : iterator.Next());
while (actor)
{
AActor *next = tid == 0 ? NULL : iterator.Next ();
if (actor->flags & MF_SHOOTABLE)
{
if (amount > 0)
{
P_DamageMobj (actor, NULL, whofor0, amount, type);
}
else if (actor->health < actor->GetDefault()->health)
{
actor->health -= amount;
if (actor->health > actor->GetDefault()->health)
{
actor->health = actor->GetDefault()->health;
}
if (actor->player != NULL)
{
actor->player->health = actor->health;
}
}
count++;
}
actor = next;
}
return count;
}
CCMD (dumpspawnables)
{
int i;