diff --git a/src/actor.h b/src/actor.h index b93abd3736..937bdbe3cd 100644 --- a/src/actor.h +++ b/src/actor.h @@ -344,6 +344,7 @@ enum MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters. MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. + MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. // --- mobj.renderflags --- diff --git a/src/g_heretic/a_ironlich.cpp b/src/g_heretic/a_ironlich.cpp index d8c1fd285c..dba16b622c 100644 --- a/src/g_heretic/a_ironlich.cpp +++ b/src/g_heretic/a_ironlich.cpp @@ -28,10 +28,14 @@ int AWhirlwind::DoSpecialDamage (AActor *target, int damage, FName damagetype) { int randVal; - target->angle += pr_foo.Random2() << 20; - target->velx += pr_foo.Random2() << 10; - target->vely += pr_foo.Random2() << 10; - if ((level.time & 16) && !(target->flags2 & MF2_BOSS)) + if (!(target->flags7 & MF7_DONTTHRUST)) + { + target->angle += pr_foo.Random2() << 20; + target->velx += pr_foo.Random2() << 10; + target->vely += pr_foo.Random2() << 10; + } + + if ((level.time & 16) && !(target->flags2 & MF2_BOSS) && !(target->flags7 & MF7_DONTTHRUST)) { randVal = pr_foo(); if (randVal > 160) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index e51d601f3a..ef6136fdc0 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -3161,7 +3161,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Die) ACTION_PARAM_START(1); ACTION_PARAM_NAME(damagetype, 0); - P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED); + if (self->flags & MF_MISSILE) + P_ExplodeMissile(self, NULL, NULL); + else + P_DamageMobj (self, NULL, NULL, self->health, damagetype, DMG_FORCED); } // diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 2ac29e11cf..860e30d0fe 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1053,8 +1053,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, return -1; } } - // Handle passive damage modifiers (e.g. PowerProtection) - if (target->Inventory != NULL) + // Handle passive damage modifiers (e.g. PowerProtection), provided they are not afflicted with protection penetrating powers. + if ((target->Inventory != NULL) && !(flags & DMG_NO_PROTECT)) { int olddam = damage; target->Inventory->ModifyDamage(olddam, mod, damage, true); @@ -1097,6 +1097,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, && !(target->flags & MF_NOCLIP) && !(inflictor->flags2 & MF2_NODMGTHRUST) && !(flags & DMG_THRUSTLESS) + && !(target->flags7 & MF7_DONTTHRUST) && (source == NULL || source->player == NULL || !(source->flags2 & MF2_NODMGTHRUST))) { int kickback; @@ -1324,7 +1325,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (target->health <= 0) { if ((target->flags7 & MF7_BUDDHA) && (damage < TELEFRAG_DAMAGE) && (!(inflictor->flags3 & MF7_FOILBUDDHA) && !(flags & DMG_FOILBUDDHA))) - { //Make sure FOILINVUL flags work here too for monsters. Or perhaps consider a FOILBUDDHA flag... + { //FOILBUDDHA or Telefrag damage must kill it. target->health = 1; } else @@ -1591,7 +1592,7 @@ bool AActor::OkayToSwitchTarget (AActor *other) bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison) { - if((player->cheats&CF_GODMODE) || (player->mo->flags2 & MF2_INVULNERABLE)) + if((player->cheats&CF_GODMODE) || (player->mo->flags2 & MF2_INVULNERABLE) || (player->cheats & CF_GODMODE2)) { return false; } @@ -1642,8 +1643,8 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, { return; } - if (damage < TELEFRAG_DAMAGE && ((target->flags2 & MF2_INVULNERABLE) || - (player->cheats & CF_GODMODE))) + if ((damage < TELEFRAG_DAMAGE && ((target->flags2 & MF2_INVULNERABLE) || + (player->cheats & CF_GODMODE))) || (player->cheats & CF_GODMODE2)) { // target is invulnerable return; } diff --git a/src/p_local.h b/src/p_local.h index f7e4738456..dec80ecaa1 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -560,6 +560,7 @@ enum EDmgFlags DMG_PLAYERATTACK = 32, DMG_FOILINVUL = 64, DMG_FOILBUDDHA = 128, + DMG_NO_PROTECT = 256, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 43b16a5064..b688ef43d9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4679,7 +4679,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo if (!(flags & RADF_NODAMAGE)) newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod); - else if (thing->player == NULL && !(flags & RADF_NOIMPACTDAMAGE)) + else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE) && !(thing->flags7 & MF7_DONTTHRUST))) thing->flags2 |= MF2_BLASTED; if (!(thing->flags & MF_ICECORPSE)) @@ -4691,25 +4691,29 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { - thrust = points * 0.5f / (double)thing->Mass; - if (bombsource == thing) + if (!(thing->flags7 & MF7_DONTTHRUST)) { - thrust *= selfthrustscale; + + thrust = points * 0.5f / (double)thing->Mass; + if (bombsource == thing) + { + thrust *= selfthrustscale; + } + velz = (double)(thing->z + (thing->height >> 1) - bombspot->z) * thrust; + if (bombsource != thing) + { + velz *= 0.5f; + } + else + { + velz *= 0.8f; + } + angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; + thing->velx += fixed_t(finecosine[ang] * thrust); + thing->vely += fixed_t(finesine[ang] * thrust); + if (!(flags & RADF_NODAMAGE)) + thing->velz += (fixed_t)velz; // this really doesn't work well } - velz = (double)(thing->z + (thing->height >> 1) - bombspot->z) * thrust; - if (bombsource != thing) - { - velz *= 0.5f; - } - else - { - velz *= 0.8f; - } - angle_t ang = R_PointToAngle2(bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT; - thing->velx += fixed_t(finecosine[ang] * thrust); - thing->vely += fixed_t(finesine[ang] * thrust); - if (!(flags & RADF_NODAMAGE)) - thing->velz += (fixed_t)velz; // this really doesn't work well } } } diff --git a/src/p_things.cpp b/src/p_things.cpp index 2a93ee31e0..0189848e4e 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -402,10 +402,14 @@ void P_RemoveThing(AActor * actor) // Don't remove live players. if (actor->player == NULL || actor != actor->player->mo) { + // Don't also remove owned inventory items + if (actor->IsKindOf(RUNTIME_CLASS(AInventory)) && static_cast(actor)->Owner != NULL) return; + // be friendly to the level statistics. ;) actor->ClearCounters(); actor->Destroy (); } + } bool P_Thing_Raise(AActor *thing) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 473cdcd814..b4700e8568 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -696,6 +696,7 @@ public: case NAME_FillColor: th->fillcolor = CheckInt(key); + break; case NAME_Health: th->health = CheckInt(key); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6a1cf6e674..80583b5870 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1677,6 +1677,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToTarget) DoGiveInventory(self->target, PUSH_PARAMINFO); } +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToChildren) +{ + TThinkerIterator it; + AActor * mo; + + while ((mo = it.Next())) + { + if (mo->master == self) DoGiveInventory(mo, PUSH_PARAMINFO); + } +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) +{ + TThinkerIterator it; + AActor * mo; + + if (self->master != NULL) + { + while ((mo = it.Next())) + { + if (mo->master == self->master && mo != self) DoGiveInventory(mo, PUSH_PARAMINFO); + } + } +} + //=========================================================================== // // A_TakeInventory @@ -1737,6 +1762,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromTarget) DoTakeInventory(self->target, PUSH_PARAMINFO); } +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromChildren) +{ + TThinkerIterator it; + AActor * mo; + + while ((mo = it.Next())) + { + if (mo->master == self) DoTakeInventory(mo, PUSH_PARAMINFO); + } +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_TakeFromSiblings) +{ + TThinkerIterator it; + AActor * mo; + + if (self->master != NULL) + { + while ((mo = it.Next())) + { + if (mo->master == self->master && mo != self) DoTakeInventory(mo, PUSH_PARAMINFO); + } + } +} + //=========================================================================== // // Common code for A_SpawnItem and A_SpawnItemEx @@ -4608,17 +4658,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate) //========================================================================== enum RadiusGiveFlags { - RGF_GIVESELF = 1, - RGF_PLAYERS = 2, - RGF_MONSTERS = 4, - RGF_OBJECTS = 8, - RGF_VOODOO = 16, - RGF_CORPSES = 32, - RGF_MASK = 63, - RGF_NOTARGET = 64, - RGF_NOTRACER = 128, - RGF_NOMASTER = 256, - RGF_CUBE = 512, + RGF_GIVESELF = 1 << 0, + RGF_PLAYERS = 1 << 1, + RGF_MONSTERS = 1 << 2, + RGF_OBJECTS = 1 << 3, + RGF_VOODOO = 1 << 4, + RGF_CORPSES = 1 << 5, + RGF_MASK = 63, + RGF_NOTARGET = 1 << 6, + RGF_NOTRACER = 1 << 7, + RGF_NOMASTER = 1 << 8, + RGF_CUBE = 1 << 9, + RGF_NOSIGHT = 1 << 10, + RGF_MISSILES = 1 << 11, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) @@ -4699,6 +4751,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) continue; } } + else if (thing->flags & MF_MISSILE) + { + if (!(flags & RGF_MISSILES)) + { + continue; + } + } else { continue; @@ -4724,8 +4783,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) } fixed_t dz = abs ((thing->z + thing->height/2) - (self->z + self->height/2)); - if (P_CheckSight (thing, self, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) - { // OK to give; target is in direct path + if ((flags & RGF_NOSIGHT) || P_CheckSight (thing, self, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) + { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. AInventory *gift = static_cast(Spawn (item, 0, 0, 0, NO_REPLACE)); if (gift->IsKindOf(RUNTIME_CLASS(AHealth))) { @@ -4832,6 +4891,7 @@ enum DMSS DMSS_KILL = 4, DMSS_NOFACTOR = 8, DMSS_FOILBUDDHA = 16, + DMSS_NOPROTECT = 32, }; static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags) @@ -4847,6 +4907,8 @@ static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageTy dmgFlags += DMG_NO_ARMOR; if (flags & DMSS_KILL) //Kill adds the value of the damage done to it. Allows for more controlled extreme death types. amount += dmgtarget->health; + if (flags & DMSS_NOPROTECT) //Ignore PowerProtection. + dmgFlags += DMG_NO_PROTECT; if (amount > 0) P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); //Should wind up passing them through just fine. diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 90c3313a69..dbd1f10318 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -244,6 +244,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF7, HARMFRIENDS, AActor, flags7), DEFINE_FLAG(MF7, BUDDHA, AActor, flags7), DEFINE_FLAG(MF7, FOILBUDDHA, AActor, flags7), + DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 280321ad09..e253f53ac9 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -312,6 +312,10 @@ ACTOR Actor native //: Thinker action native A_RemoveTarget(int flags = 0); action native A_RemoveTracer(int flags = 0); action native A_Remove(int removee, int flags = 0); + action native A_GiveToChildren(class itemtype, int amount = 0); + action native A_GiveToSiblings(class itemtype, int amount = 0); + action native A_TakeFromChildren(class itemtype, int amount = 0); + action native A_TakeFromSiblings(class itemtype, int amount = 0); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index f806f8224f..a43d90f96f 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -191,15 +191,17 @@ const int WAF_USEPUFF = 2; enum { RGF_GIVESELF = 1, - RGF_PLAYERS = 2, - RGF_MONSTERS = 4, - RGF_OBJECTS = 8, - RGF_VOODOO = 16, - RGF_CORPSES = 32, - RGF_NOTARGET = 64, - RGF_NOTRACER = 128, - RGF_NOMASTER = 256, - RGF_CUBE = 512, + RGF_PLAYERS = 1 << 1, + RGF_MONSTERS = 1 << 2, + RGF_OBJECTS = 1 << 3, + RGF_VOODOO = 1 << 4, + RGF_CORPSES = 1 << 5, + RGF_NOTARGET = 1 << 6, + RGF_NOTRACER = 1 << 7, + RGF_NOMASTER = 1 << 8, + RGF_CUBE = 1 << 9, + RGF_NOSIGHT = 1 << 10, + RGF_MISSILES = 1 << 11, }; // Activation flags @@ -383,6 +385,7 @@ const int DMSS_AFFECTARMOR = 2; const int DMSS_KILL = 4; const int DMSS_NOFACTOR = 8; const int DMSS_FOILBUDDHA = 16; +const int DMSS_NOPROTECT = 32; // Flags for A_AlertMonsters const int AMF_TARGETEMITTER = 1;