diff --git a/src/actor.h b/src/actor.h index 16643ee4d..6e5bd6049 100644 --- a/src/actor.h +++ b/src/actor.h @@ -985,6 +985,9 @@ public: FNameNoInit DeathType; const PClass *TeleFogSourceType; const PClass *TeleFogDestType; + int RipperLevel; + int RipLevelMin; + int RipLevelMax; FState *SpawnState; FState *SeeState; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 6014d6fee..e3433f12e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -529,24 +529,26 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor { AMorphedMonster *fakeme = static_cast(actor); AActor *realme = fakeme->UnmorphedMe; - if ((fakeme->UnmorphTime) && - (fakeme->MorphStyle & MORPH_UNDOBYDEATH) && - (realme)) + if (realme != NULL) { - int realstyle = fakeme->MorphStyle; - int realhealth = fakeme->health; - if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) + if ((fakeme->UnmorphTime) && + (fakeme->MorphStyle & MORPH_UNDOBYDEATH)) { - *morphed = realme; - *morphedstyle = realstyle; - *morphedhealth = realhealth; - return true; + int realstyle = fakeme->MorphStyle; + int realhealth = fakeme->health; + if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) + { + *morphed = realme; + *morphedstyle = realstyle; + *morphedhealth = realhealth; + return true; + } + } + if (realme->flags4 & MF4_BOSSDEATH) + { + realme->health = 0; // make sure that A_BossDeath considers it dead. + CALL_ACTION(A_BossDeath, realme); } - } - if (realme->flags4 & MF4_BOSSDEATH) - { - realme->health = 0; // make sure that A_BossDeath considers it dead. - CALL_ACTION(A_BossDeath, realme); } fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die() return false; diff --git a/src/p_local.h b/src/p_local.h index c0a754e25..fe7958807 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -133,7 +133,7 @@ enum EPuffFlags PF_NORANDOMZ = 16 }; -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0); +AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); diff --git a/src/p_map.cpp b/src/p_map.cpp index 456db2d0f..68d0b21f0 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -887,6 +887,20 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) return true; } + +//========================================================================== +// +// Isolated to keep the code readable and fix the logic +// +//========================================================================== + +static bool CheckRipLevel(AActor *victim, AActor *projectile) +{ + if (victim->RipLevelMin > 0 && projectile->RipperLevel < victim->RipLevelMin) return false; + if (victim->RipLevelMax > 0 && projectile->RipperLevel > victim->RipLevelMax) return false; + return true; +} + //========================================================================== // // PIT_CheckThing @@ -1207,7 +1221,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { return true; } - if (tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) + + if ((tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) && CheckRipLevel(thing, tm.thing)) { if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS)) { @@ -3761,14 +3776,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, puffFlags |= PF_HITTHINGBLEED; // We must pass the unreplaced puff type here - puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING); - } - - if (puffDefaults != NULL && trace.Actor != NULL && puff != NULL) - { - if (puffDefaults->flags7 && MF7_HITTARGET) puff->target = trace.Actor; - if (puffDefaults->flags7 && MF7_HITMASTER) puff->master = trace.Actor; - if (puffDefaults->flags7 && MF7_HITTRACER) puff->tracer = trace.Actor; + puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING, trace.Actor); } // Allow puffs to inflict poison damage, so that hitscans can poison, too. @@ -4211,14 +4219,9 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } if (spawnpuff) { - P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags); - } - if (hitactor != NULL && puffDefaults != NULL && thepuff != NULL) - { - if (puffDefaults->flags7 & MF7_HITTARGET) thepuff->target = hitactor; - if (puffDefaults->flags7 & MF7_HITMASTER) thepuff->master = hitactor; - if (puffDefaults->flags7 & MF7_HITTRACER) thepuff->tracer = hitactor; + P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor); } + if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8c76d793e..6a035933d 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -338,6 +338,13 @@ void AActor::Serialize (FArchive &arc) arc << TeleFogSourceType << TeleFogDestType; } + if (SaveVersion >= 4518) + { + arc << RipperLevel + << RipLevelMin + << RipLevelMax; + } + { FString tagstr; if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; @@ -1961,48 +1968,50 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) // Don't change the angle if there's THRUREFLECT on the monster. if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - int dir; - angle_t delta; - - if (BlockingMobj->flags7 & MF7_MIRRORREFLECT) - angle = mo->angle + ANG180; - else - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); - + //int dir; + //angle_t delta; + bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); // Change angle for deflection/reflection - // AIMREFLECT calls precedence so make sure not to bother with adjusting here if declared. - if (!(BlockingMobj->flags7 & MF7_AIMREFLECT) && (mo->AdjustReflectionAngle(BlockingMobj, angle))) - { - goto explode; - } - // Reflect the missile along angle - if (BlockingMobj->flags7 & MF7_AIMREFLECT) + if (!dontReflect) { - dir = P_FaceMobj(mo, mo->target, &delta); - if (dir) - { // Turn clockwise - mo->angle += delta; + bool tg = (mo->target != NULL); + bool blockingtg = (BlockingMobj->target != NULL); + if (BlockingMobj->flags7 & MF7_AIMREFLECT && (tg || blockingtg)) + { + AActor *origin; + if (tg) + origin = mo->target; + else if (blockingtg) + origin = BlockingMobj->target; + + float speed = (float)(mo->Speed); + //dest->x - source->x + FVector3 velocity(origin->x - mo->x, origin->y - mo->y, (origin->z + (origin->height/2)) - mo->z); + velocity.Resize(speed); + angle = mo->angle >> ANGLETOFINESHIFT; + mo->velx = (fixed_t)(velocity.X); + mo->vely = (fixed_t)(velocity.Y); + mo->velz = (fixed_t)(velocity.Z); + /* + mo->velx = FixedMul(mo->Speed, finecosine[angle]); + mo->vely = FixedMul(mo->Speed, finesine[angle]); + mo->velz = -mo->velz; + */ } else - { // Turn counter clockwise - mo->angle -= delta; + { + mo->angle = angle; + angle >>= ANGLETOFINESHIFT; + mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]); + mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]); + mo->velz = -mo->velz / 2; } - angle = mo->angle >> ANGLETOFINESHIFT; - mo->velx = FixedMul(mo->Speed, finecosine[angle]); - mo->vely = FixedMul(mo->Speed, finesine[angle]); - mo->velz = -mo->velz; } else { - mo->angle = angle; - angle >>= ANGLETOFINESHIFT; - mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]); - mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]); - mo->velz = -mo->velz / 2; - } - - + goto explode; + } } if (mo->flags2 & MF2_SEEKERMISSILE) { @@ -2928,8 +2937,10 @@ bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle) if (flags2 & MF2_DONTREFLECT) return true; if (thing->flags7 & MF7_THRUREFLECT) return false; + if (thing->flags7 & MF7_MIRRORREFLECT) + angle += ANGLE_180; // Change angle for reflection - if (thing->flags4&MF4_SHIELDREFLECT) + else if (thing->flags4&MF4_SHIELDREFLECT) { // Shield reflection (from the Centaur if (abs (angle - thing->angle)>>24 > 45) @@ -2952,6 +2963,13 @@ bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle) else angle -= ANG45; } + else if (thing->flags7 & MF7_AIMREFLECT) + { + if (this->target != NULL) + A_Face(this, this->target); + else if (thing->target != NULL) + A_Face(this, thing->target); + } else angle += ANGLE_1 * ((pr_reflect()%16)-8); return false; @@ -4919,7 +4937,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // P_SpawnPuff // -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags) +AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict) { AActor *puff; @@ -4929,9 +4947,17 @@ AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t puff = Spawn (pufftype, x, y, z, ALLOW_REPLACE); if (puff == NULL) return NULL; + //Moved puff creation and target/master/tracer setting to here. + if (puff && vict) + { + if (puff->flags7 & MF7_HITTARGET) puff->target = vict; + if (puff->flags7 & MF7_HITMASTER) puff->master = vict; + if (puff->flags7 & MF7_HITTRACER) puff->tracer = vict; + } // [BB] If the puff came from a player, set the target of the puff to this player. if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER)) puff->target = source; + if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y); diff --git a/src/p_user.cpp b/src/p_user.cpp index bf656d2b9..e91766cf0 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1365,7 +1365,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) weap->SpawnState != ::GetDefault()->SpawnState) { item = P_DropItem (this, weap->GetClass(), -1, 256); - if (item != NULL) + if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (weap->AmmoGive1 && weap->Ammo1) { diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 50969ce85..54645d864 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5613,3 +5613,45 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) self->TeleFogDestType = temp; } } + +//=========================================================================== +// +// A_SetRipperLevel(int level) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel) +{ + ACTION_PARAM_START(1); + ACTION_PARAM_INT(level, 0); + self->RipperLevel = level; +} + +//=========================================================================== +// +// A_SetRipMin(int min) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin) +{ + ACTION_PARAM_START(1); + ACTION_PARAM_INT(min, 1); + self->RipLevelMin = min; +} + +//=========================================================================== +// +// A_SetRipMin(int min) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) +{ + ACTION_PARAM_START(1); + ACTION_PARAM_INT(max, 1); + self->RipLevelMax = max; +} \ No newline at end of file diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index b6a2937ae..677979276 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1436,6 +1436,45 @@ DEFINE_PROPERTY(telefogdesttype, S, Actor) else defaults->TeleFogDestType = FindClassTentative(str, "TeleportFog"); } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(ripperlevel, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipperLevel must not be negative"); + } + defaults->RipperLevel = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(riplevelmin, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipLevelMin must not be negative"); + } + defaults->RipLevelMin = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(riplevelmax, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipLevelMax must not be negative"); + } + defaults->RipLevelMax = id; +} + //========================================================================== // // Special inventory properties diff --git a/src/version.h b/src/version.h index b0e69bb5d..4d65584ea 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4517 +#define SAVEVER 4518 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 73a5e0e4d..c32ecb958 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -28,6 +28,9 @@ ACTOR Actor native //: Thinker DeathType Normal TeleFogSourceType "TeleportFog" TeleFogDestType "TeleportFog" + RipperLevel 0 + RipLevelMin 0 + RipLevelMax 0 // Variables for the expression evaluator // NOTE: fixed_t and angle_t are only used here to ensure proper conversion @@ -321,6 +324,9 @@ ACTOR Actor native //: Thinker action native A_TakeFromSiblings(class itemtype, int amount = 0); action native A_SetTeleFog(name oldpos, name newpos); action native A_SwapTeleFog(); + action native A_SetRipperLevel(int level); + action native A_SetRipMin(int min); + action native A_SetRipMax(int max); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label);