From 2e8aa53e6ad0fb35728ffa2aff0227444f467966 Mon Sep 17 00:00:00 2001 From: yqco Date: Wed, 24 Aug 2016 04:21:46 -0600 Subject: [PATCH] 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 --- src/p_acs.cpp | 29 ++++++++++ src/thingdef/thingdef.h | 1 + src/thingdef/thingdef_codeptr.cpp | 85 +--------------------------- src/thingdef/thingdef_properties.cpp | 65 +++++++++++++++++++++ 4 files changed, 96 insertions(+), 84 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0157fda758..67ae377717 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -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; } diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 296383a3d5..3a419b112a 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -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); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d520a0b9d8..8c2a020c7d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -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; } diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 372f444cd3..f6ad511afe 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -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.