mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-15 00:31:54 +00:00
Add SetActorFlag ACS function
int SetActorFlag(int tid, str flagname, bool value); - Mimics DECORATE's A_ChangeFlag - Returns number of actors affected (number of things with the flag) - Affects activator if TID is 0 # Conflicts: # src/p_acs.cpp
This commit is contained in:
parent
f536523fbd
commit
2e8aa53e6a
4 changed files with 96 additions and 84 deletions
|
@ -4451,6 +4451,7 @@ enum EACSFunctions
|
|||
|
||||
ACSF_CheckClass = 200,
|
||||
ACSF_DamageActor, // [arookas]
|
||||
ACSF_SetActorFlag,
|
||||
|
||||
// ZDaemon
|
||||
ACSF_GetTeamScore = 19620, // (int team)
|
||||
|
@ -6046,6 +6047,34 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype);
|
||||
}
|
||||
|
||||
case ACSF_SetActorFlag:
|
||||
{
|
||||
int tid = args[0];
|
||||
FString flagname = FBehavior::StaticLookupString(args[1]);
|
||||
bool flagvalue = !!args[2];
|
||||
int count = 0; // Return value; number of actors affected
|
||||
if (tid == 0)
|
||||
{
|
||||
if (ModActorFlag(activator, flagname, flagvalue))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FActorIterator it(tid);
|
||||
while ((actor = it.Next()) != nullptr)
|
||||
{
|
||||
// Don't log errors when affecting many actors because things might share a TID but not share the flag
|
||||
if (ModActorFlag(actor, flagname, flagvalue, false))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
|
|||
bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index);
|
||||
const char *GetFlagName(unsigned int flagnum, int flagoffset);
|
||||
void ModActorFlag(AActor *actor, FFlagDef *fd, bool set);
|
||||
bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror = true);
|
||||
INTBOOL CheckActorFlag(const AActor *actor, FFlagDef *fd);
|
||||
INTBOOL CheckActorFlag(const AActor *owner, const char *flagname, bool printerror = true);
|
||||
|
||||
|
|
|
@ -4681,90 +4681,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
|
|||
PARAM_STRING (flagname);
|
||||
PARAM_BOOL (value);
|
||||
|
||||
const char *dot = strchr(flagname, '.');
|
||||
FFlagDef *fd;
|
||||
PClassActor *cls = self->GetClass();
|
||||
|
||||
if (dot != NULL)
|
||||
{
|
||||
FString part1(flagname.GetChars(), dot - flagname);
|
||||
fd = FindFlag(cls, part1, dot + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = FindFlag(cls, flagname, NULL);
|
||||
}
|
||||
|
||||
if (fd != NULL)
|
||||
{
|
||||
bool kill_before, kill_after;
|
||||
INTBOOL item_before, item_after;
|
||||
INTBOOL secret_before, secret_after;
|
||||
|
||||
kill_before = self->CountsAsKill();
|
||||
item_before = self->flags & MF_COUNTITEM;
|
||||
secret_before = self->flags5 & MF5_COUNTSECRET;
|
||||
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
HandleDeprecatedFlags(self, cls, value, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
ActorFlags *flagp = (ActorFlags*) (((char*)self) + fd->structoffset);
|
||||
|
||||
// If these 2 flags get changed we need to update the blockmap and sector links.
|
||||
bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR);
|
||||
|
||||
if (linkchange) self->UnlinkFromWorld();
|
||||
ModActorFlag(self, fd, value);
|
||||
if (linkchange) self->LinkToWorld();
|
||||
}
|
||||
kill_after = self->CountsAsKill();
|
||||
item_after = self->flags & MF_COUNTITEM;
|
||||
secret_after = self->flags5 & MF5_COUNTSECRET;
|
||||
// Was this monster previously worth a kill but no longer is?
|
||||
// Or vice versa?
|
||||
if (kill_before != kill_after)
|
||||
{
|
||||
if (kill_after)
|
||||
{ // It counts as a kill now.
|
||||
level.total_monsters++;
|
||||
}
|
||||
else
|
||||
{ // It no longer counts as a kill.
|
||||
level.total_monsters--;
|
||||
}
|
||||
}
|
||||
// same for items
|
||||
if (item_before != item_after)
|
||||
{
|
||||
if (item_after)
|
||||
{ // It counts as an item now.
|
||||
level.total_items++;
|
||||
}
|
||||
else
|
||||
{ // It no longer counts as an item
|
||||
level.total_items--;
|
||||
}
|
||||
}
|
||||
// and secretd
|
||||
if (secret_before != secret_after)
|
||||
{
|
||||
if (secret_after)
|
||||
{ // It counts as an secret now.
|
||||
level.total_secrets++;
|
||||
}
|
||||
else
|
||||
{ // It no longer counts as an secret
|
||||
level.total_secrets--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
ModActorFlag(self, flagname, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -162,6 +162,71 @@ void ModActorFlag(AActor *actor, FFlagDef *fd, bool set)
|
|||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds a flag by name and sets or clears it
|
||||
//
|
||||
// Returns true if the flag was found for the actor; else returns false
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (actor != NULL)
|
||||
{
|
||||
const char *dot = strchr(flagname, '.');
|
||||
FFlagDef *fd;
|
||||
PClassActor *cls = actor->GetClass();
|
||||
|
||||
if (dot != NULL)
|
||||
{
|
||||
FString part1(flagname.GetChars(), dot - flagname);
|
||||
fd = FindFlag(cls, part1, dot + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = FindFlag(cls, flagname, NULL);
|
||||
}
|
||||
|
||||
if (fd != NULL)
|
||||
{
|
||||
found = true;
|
||||
|
||||
if (actor->CountsAsKill() && actor->health > 0) --level.total_monsters;
|
||||
if (actor->flags & MF_COUNTITEM) --level.total_items;
|
||||
if (actor->flags5 & MF5_COUNTSECRET) --level.total_secrets;
|
||||
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
HandleDeprecatedFlags(actor, cls, set, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
ActorFlags *flagp = (ActorFlags*)(((char*)actor) + fd->structoffset);
|
||||
|
||||
// If these 2 flags get changed we need to update the blockmap and sector links.
|
||||
bool linkchange = flagp == &actor->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR);
|
||||
|
||||
if (linkchange) actor->UnlinkFromWorld();
|
||||
ModActorFlag(actor, fd, set);
|
||||
if (linkchange) actor->LinkToWorld();
|
||||
}
|
||||
|
||||
if (actor->CountsAsKill() && actor->health > 0) ++level.total_monsters;
|
||||
if (actor->flags & MF_COUNTITEM) ++level.total_items;
|
||||
if (actor->flags5 & MF5_COUNTSECRET) ++level.total_secrets;
|
||||
}
|
||||
else if (printerror)
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "ACS/DECORATE: '%s' is not a flag in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Returns whether an actor flag is true or not.
|
||||
|
|
Loading…
Reference in a new issue