From 79177cf98e1385b62c6d36808797d1463049bee0 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 27 Jan 2016 14:54:46 -0600 Subject: [PATCH 01/20] Set up the subfunction. --- src/thingdef/thingdef_codeptr.cpp | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 1764717f5..46a358d20 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4975,6 +4975,127 @@ enum RadiusGiveFlags RGF_EITHER = 1 << 17, }; +static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int amount, fixed_t distance, int flags, const PClass *filter, FName species, fixed_t mindist) +{ + //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). + bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), + speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); + + if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass))) + { + if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. + return false; + } + + if (thing == self) + { + if (!(flags & RGF_GIVESELF)) + return false; + } + + //Check for target, master, and tracer flagging. + bool targetPass = true; + bool masterPass = true; + bool tracerPass = true; + bool ptrPass = false; + if ((thing != self) && (flags & (RGF_NOTARGET | RGF_NOMASTER | RGF_NOTRACER))) + { + if ((thing == self->target) && (flags & RGF_NOTARGET)) + targetPass = false; + if ((thing == self->master) && (flags & RGF_NOMASTER)) + masterPass = false; + if ((thing == self->tracer) && (flags & RGF_NOTRACER)) + tracerPass = false; + + ptrPass = (flags & RGF_INCLUSIVE) ? (targetPass || masterPass || tracerPass) : (targetPass && masterPass && tracerPass); + + //We should not care about what the actor is here. It's safe to abort this actor. + if (!ptrPass) + return false; + } + + //Next, actor flag checking. + bool selfPass = !!((flags & RGF_GIVESELF) && thing == self); + bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); + bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); + bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); + bool objectPass = !!((flags & RGF_OBJECTS) && (thing->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER)) + && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); + bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing)); + bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (thing->player->mo != thing)); + //Self calls priority over the rest of this. + if (!selfPass) + { + //If it's specifically a monster/object/player/voodoo... Can be either or... + if (monsterPass || objectPass || playerPass || voodooPass) + { + //...and is dead, without desire to give to the dead... + if (((thing->health <= 0) && !(corpsePass || killedPass))) + { + //Skip! + return false; + } + } + } + + bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); + bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); + + if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) + { + + fixedvec3 diff = self->Vec3To(thing); + diff.z += (thing->height - self->height) / 2; + if (flags & RGF_CUBE) + { // check if inside a cube + double dx = fabs((double)(diff.x)); + double dy = fabs((double)(diff.y)); + double dz = fabs((double)(diff.z)); + double dist = (double)distance; + double min = (double)mindist; + if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min))) + { + return false; + } + } + else + { // check if inside a sphere + double distsquared = double(distance) * double(distance); + double minsquared = double(mindist) * double(mindist); + double lengthsquared = TVector3(diff.x, diff.y, diff.z).LengthSquared(); + if (lengthsquared > distsquared || (minsquared && (lengthsquared < minsquared))) + { + return false; + } + } + + 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))) + { + gift->Amount *= amount; + } + else + { + gift->Amount = amount; + } + gift->flags |= MF_DROPPED; + gift->ClearCounters(); + if (!gift->CallTryPickup(thing)) + { + gift->Destroy(); + return false; + } + else + { + return true; + } + } + } + return false; +} + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { ACTION_PARAM_START(7); From 846f14c03de44f7298bfd3da48f8083d5f8a4828 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 27 Jan 2016 14:56:06 -0600 Subject: [PATCH 02/20] Remove the loop. --- src/thingdef/thingdef_codeptr.cpp | 121 +----------------------------- 1 file changed, 1 insertion(+), 120 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 46a358d20..d0eb6baf0 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5118,128 +5118,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) { amount = 1; } - FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); - AActor *thing; bool given = false; - while ((thing = it.Next())) - { - //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). - bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), - speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); - - if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass))) - { - if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. - continue; - } - - if (thing == self) - { - if (!(flags & RGF_GIVESELF)) - continue; - } - - //Check for target, master, and tracer flagging. - bool targetPass = true; - bool masterPass = true; - bool tracerPass = true; - bool ptrPass = false; - if ((thing != self) && (flags & (RGF_NOTARGET | RGF_NOMASTER | RGF_NOTRACER))) - { - if ((thing == self->target) && (flags & RGF_NOTARGET)) - targetPass = false; - if ((thing == self->master) && (flags & RGF_NOMASTER)) - masterPass = false; - if ((thing == self->tracer) && (flags & RGF_NOTRACER)) - tracerPass = false; - - ptrPass = (flags & RGF_INCLUSIVE) ? (targetPass || masterPass || tracerPass) : (targetPass && masterPass && tracerPass); - - //We should not care about what the actor is here. It's safe to abort this actor. - if (!ptrPass) - continue; - } - - //Next, actor flag checking. - bool selfPass = !!((flags & RGF_GIVESELF) && thing == self); - bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE); - bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED); - bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER); - bool objectPass = !!((flags & RGF_OBJECTS) && (thing->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER)) - && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))); - bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing)); - bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (thing->player->mo != thing)); - //Self calls priority over the rest of this. - if (!selfPass) - { - //If it's specifically a monster/object/player/voodoo... Can be either or... - if (monsterPass || objectPass || playerPass || voodooPass) - { - //...and is dead, without desire to give to the dead... - if (((thing->health <= 0) && !(corpsePass || killedPass))) - { - //Skip! - continue; - } - } - } - - bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); - bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); - - if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) - { - - fixedvec3 diff = self->Vec3To(thing); - diff.z += (thing->height - self->height) / 2; - if (flags & RGF_CUBE) - { // check if inside a cube - double dx = fabs((double)(diff.x)); - double dy = fabs((double)(diff.y)); - double dz = fabs((double)(diff.z)); - double dist = (double)distance; - double min = (double)mindist; - if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min))) - { - continue; - } - } - else - { // check if inside a sphere - double distsquared = double(distance) * double(distance); - double minsquared = double(mindist) * double(mindist); - double lengthsquared = TVector3(diff.x, diff.y, diff.z).LengthSquared(); - if (lengthsquared > distsquared || (minsquared && (lengthsquared < minsquared))) - { - continue; - } - } - - 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))) - { - gift->Amount *= amount; - } - else - { - gift->Amount = amount; - } - gift->flags |= MF_DROPPED; - gift->ClearCounters(); - if (!gift->CallTryPickup(thing)) - { - gift->Destroy(); - } - else - { - given = true; - } - } - } - } + ACTION_SET_RESULT(given); } From 2da868656eeba7197f1a371a5f097dae42a5c66c Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 27 Jan 2016 15:22:05 -0600 Subject: [PATCH 03/20] Finalize loop and prioritize missile searching. --- src/thingdef/thingdef_codeptr.cpp | 39 ++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d0eb6baf0..4f674955c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4977,6 +4977,19 @@ enum RadiusGiveFlags static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int amount, fixed_t distance, int flags, const PClass *filter, FName species, fixed_t mindist) { + // [MC] We only want to make an exception for missiles here. Nothing else. + bool missilePass = !!((flags & RGF_MISSILES) && thing->isMissile()); + if (thing == self) + { + if (!(flags & RGF_GIVESELF)) + return false; + } + else if (thing->isMissile()) + { + if (!missilePass) + return false; + } + //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); @@ -4987,12 +5000,6 @@ static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int am return false; } - if (thing == self) - { - if (!(flags & RGF_GIVESELF)) - return false; - } - //Check for target, master, and tracer flagging. bool targetPass = true; bool masterPass = true; @@ -5039,7 +5046,6 @@ static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int am } bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); - bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) { @@ -5120,7 +5126,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) } AActor *thing; bool given = false; - + if (flags & RGF_MISSILES) + { + TThinkerIterator it; + while ((thing = it.Next())) + { + bool giving = !!(DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)); + if (giving) given = true; + } + } + else + { + FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); + while ((thing = it.Next())) + { + bool giving = !!(DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)); + if (giving) given = true; + } + } ACTION_SET_RESULT(given); } From eeca536d9a38daf99ad8bc0c7ce9c360c550aaa9 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Fri, 29 Jan 2016 10:41:05 -0600 Subject: [PATCH 04/20] Clean up a few things. --- src/thingdef/thingdef_codeptr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4f674955c..b25d108cc 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5131,8 +5131,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) TThinkerIterator it; while ((thing = it.Next())) { - bool giving = !!(DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)); - if (giving) given = true; + if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true; } } else @@ -5140,8 +5139,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance)); while ((thing = it.Next())) { - bool giving = !!(DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)); - if (giving) given = true; + if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true; } } ACTION_SET_RESULT(given); From 1fcb9fcf06be8339c679178585d74b47431757a6 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 29 Jan 2016 23:10:10 -0500 Subject: [PATCH 05/20] - Fixed: Crash when automatically switching sound backends due to failure. --- src/sound/i_sound.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 78c4526e8..8997c9157 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -283,6 +283,7 @@ void I_InitSound () if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent()) { Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n"); + I_CloseSound(); GSnd = new OpenALSoundRenderer; snd_backend = "openal"; } @@ -300,6 +301,7 @@ void I_InitSound () if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent()) { Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n"); + I_CloseSound(); GSnd = new FMODSoundRenderer; snd_backend = "fmod"; } From a34a7ace1825725870faefa4e9ac599bdc757e7d Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Fri, 29 Jan 2016 23:37:38 -0500 Subject: [PATCH 06/20] - Some resolutions between 320x200 and 640x400 had non-square clean scaling factors. Maybe there was a reason for this in the past, but I can't think of a case where it'd actually look better to have 1:2 scaling in the menus and someone reported it. --- src/v_video.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index d48bd91ae..042469193 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1424,13 +1424,11 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real *cleany = cy2; } - if (*cleanx > 1 && *cleany > 1 && *cleanx != *cleany) - { - if (*cleanx < *cleany) - *cleany = *cleanx; - else - *cleanx = *cleany; - } + if (*cleanx < *cleany) + *cleany = *cleanx; + else + *cleanx = *cleany; + if (_cx1 != NULL) *_cx1 = cx1; if (_cx2 != NULL) *_cx2 = cx2; } From 5d6e8a73386540bbea62d2922a1cdeb36a44fbc4 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 30 Jan 2016 00:18:38 -0500 Subject: [PATCH 07/20] - Fixed: Possible timer overflow in PowerTimeFreezer. --- src/g_shared/a_artifacts.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index faa5392b7..42b286f53 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1500,7 +1500,9 @@ void APowerTimeFreezer::InitEffect() } else { - EffectTics++; + // Compensate for skipped tic, but beware of overflow. + if(EffectTics < INT_MAX) + EffectTics++; } } From c1e362ee83910195d4a3548d992f0373297d27c3 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 30 Jan 2016 22:02:27 +1300 Subject: [PATCH 08/20] Added level transition spawning for missing starts - Additional player bodies are spawned for any absent starts in co-op. - Removed now-redundant bot start limitation --- src/b_game.cpp | 8 ---- src/g_game.cpp | 2 + src/g_level.cpp | 119 ++++++++++++++++++++++++++---------------------- 3 files changed, 66 insertions(+), 63 deletions(-) diff --git a/src/b_game.cpp b/src/b_game.cpp index 5f852d043..44545f73d 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -369,14 +369,6 @@ bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill) D_ReadUserInfoStrings (bnum, &info, false); - if (!deathmatch && playerstarts[bnum].type == 0) - { - Printf ("%s tried to join, but there was no player %d start\n", - players[bnum].userinfo.GetName(), bnum+1); - ClearPlayer (bnum, false); // Make the bot inactive again - return false; - } - multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost). players[bnum].Bot = new DBot; players[bnum].Bot->player = &players[bnum]; diff --git a/src/g_game.cpp b/src/g_game.cpp index c97ea2198..091065b0a 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1422,6 +1422,8 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing) fixed_t z, oldz; int i; + if (mthing->type == 0) return false; + x = mthing->x; y = mthing->y; z = mthing->z; diff --git a/src/g_level.cpp b/src/g_level.cpp index 43a07a475..6ec7f9958 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1195,74 +1195,83 @@ void G_FinishTravel () TThinkerIterator it (STAT_TRAVELLING); APlayerPawn *pawn, *pawndup, *oldpawn, *next; AInventory *inv; + FPlayerStart *start; + int pnum; next = it.Next (); while ( (pawn = next) != NULL) { next = it.Next (); + pnum = (pawn->player - players); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; + start = NULL; assert (pawn != pawndup); if (pawndup == NULL) { // Oh no! there was no start for this player! - pawn->flags |= MF_NOSECTOR|MF_NOBLOCKMAP; - pawn->Destroy (); + start = G_PickPlayerStart(pnum, PPS_FORCERANDOM); + pawndup = P_SpawnPlayer(start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); + if (pawndup == NULL) + { + pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP; + pawn->Destroy(); + continue; + } } - else + + if (start == NULL) start = G_PickPlayerStart(pnum, 0); + oldpawn = pawndup; + + // The player being spawned here is a short lived dummy and + // must not start any ENTER script or big problems will happen. + pawndup = P_SpawnPlayer(start, pnum, SPF_TEMPPLAYER); + if (!(changeflags & CHANGELEVEL_KEEPFACING)) { - oldpawn = pawndup; + pawn->angle = pawndup->angle; + pawn->pitch = pawndup->pitch; + } + pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); + pawn->velx = pawndup->velx; + pawn->vely = pawndup->vely; + pawn->velz = pawndup->velz; + pawn->Sector = pawndup->Sector; + pawn->floorz = pawndup->floorz; + pawn->ceilingz = pawndup->ceilingz; + pawn->dropoffz = pawndup->dropoffz; + pawn->floorsector = pawndup->floorsector; + pawn->floorpic = pawndup->floorpic; + pawn->floorterrain = pawndup->floorterrain; + pawn->ceilingsector = pawndup->ceilingsector; + pawn->ceilingpic = pawndup->ceilingpic; + pawn->floorclip = pawndup->floorclip; + pawn->waterlevel = pawndup->waterlevel; + pawn->target = NULL; + pawn->lastenemy = NULL; + pawn->player->mo = pawn; + pawn->player->camera = pawn; + pawn->player->viewheight = pawn->ViewHeight; + pawn->flags2 &= ~MF2_BLASTED; + DObject::StaticPointerSubstitution (oldpawn, pawn); + oldpawn->Destroy(); + pawndup->Destroy (); + pawn->LinkToWorld (); + pawn->AddToHash (); + pawn->SetState(pawn->SpawnState); + pawn->player->SendPitchLimits(); - // The player being spawned here is a short lived dummy and - // must not start any ENTER script or big problems will happen. - pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], int(pawn->player - players), SPF_TEMPPLAYER); - if (!(changeflags & CHANGELEVEL_KEEPFACING)) - { - pawn->angle = pawndup->angle; - pawn->pitch = pawndup->pitch; - } - pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); - pawn->velx = pawndup->velx; - pawn->vely = pawndup->vely; - pawn->velz = pawndup->velz; - pawn->Sector = pawndup->Sector; - pawn->floorz = pawndup->floorz; - pawn->ceilingz = pawndup->ceilingz; - pawn->dropoffz = pawndup->dropoffz; - pawn->floorsector = pawndup->floorsector; - pawn->floorpic = pawndup->floorpic; - pawn->floorterrain = pawndup->floorterrain; - pawn->ceilingsector = pawndup->ceilingsector; - pawn->ceilingpic = pawndup->ceilingpic; - pawn->floorclip = pawndup->floorclip; - pawn->waterlevel = pawndup->waterlevel; - pawn->target = NULL; - pawn->lastenemy = NULL; - pawn->player->mo = pawn; - pawn->player->camera = pawn; - pawn->player->viewheight = pawn->ViewHeight; - pawn->flags2 &= ~MF2_BLASTED; - DObject::StaticPointerSubstitution (oldpawn, pawn); - oldpawn->Destroy(); - pawndup->Destroy (); - pawn->LinkToWorld (); - pawn->AddToHash (); - pawn->SetState(pawn->SpawnState); - pawn->player->SendPitchLimits(); - - for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) - { - inv->ChangeStatNum (STAT_INVENTORY); - inv->LinkToWorld (); - inv->Travelled (); - } - if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) - { - pawn->Speed = pawn->GetDefault()->Speed; - } - if (level.FromSnapshot) - { - FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); - } + for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) + { + inv->ChangeStatNum (STAT_INVENTORY); + inv->LinkToWorld (); + inv->Travelled (); + } + if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) + { + pawn->Speed = pawn->GetDefault()->Speed; + } + if (level.FromSnapshot) + { + FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); } } From fe52f9845960ed7d8172d1ff6bb397cc7cb15700 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 30 Jan 2016 22:04:09 +1300 Subject: [PATCH 09/20] Clamped r_maxparticles to the internal limit --- src/p_effect.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 84ed4c16f..62ddb7d3d 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -132,7 +132,9 @@ CUSTOM_CVAR( Int, r_maxparticles, 4000, CVAR_ARCHIVE ) { if ( self == 0 ) self = 4000; - else if ( self < 100 ) + else if (self > 65535) + self = 65535; + else if (self < 100) self = 100; if ( gamestate != GS_STARTUP ) From 40d90ba325d9c34c6425ff2aad62a4dc85cb96c0 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Sat, 30 Jan 2016 22:26:47 +1300 Subject: [PATCH 10/20] Game still needs to abort if no starts exist at all --- src/g_game.cpp | 5 +++++ src/g_level.cpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 091065b0a..7ca8b2b35 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1575,6 +1575,11 @@ void G_DeathMatchSpawnPlayer (int playernum) // FPlayerStart *G_PickPlayerStart(int playernum, int flags) { + if (AllPlayerStarts.Size() == 0) // No starts to pick + { + return NULL; + } + if ((level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) || (flags & PPS_FORCERANDOM) || playerstarts[playernum].type == 0) { diff --git a/src/g_level.cpp b/src/g_level.cpp index 6ec7f9958..d799cc893 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1209,8 +1209,8 @@ void G_FinishTravel () assert (pawn != pawndup); if (pawndup == NULL) { // Oh no! there was no start for this player! - start = G_PickPlayerStart(pnum, PPS_FORCERANDOM); - pawndup = P_SpawnPlayer(start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); + start = G_PickPlayerStart(pnum, PPS_FORCERANDOM); + if (start != NULL) pawndup = P_SpawnPlayer(start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); if (pawndup == NULL) { pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP; From b84207a089c326172686a55ed44c980bf2439b49 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 11:33:55 +0100 Subject: [PATCH 11/20] - use scaling, render style and alpha when drawing the cast call. --- src/intermission/intermission.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 44f52485c..1dc4b2f1a 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -591,6 +591,9 @@ void DIntermissionScreenCast::Drawer () // draw the current frame in the middle of the screen if (caststate != NULL) { + double castscalex = FIXED2DBL(mDefaults->scaleX); + double castscaley = FIXED2DBL(mDefaults->scaleY); + int castsprite = caststate->sprite; if (!(mDefaults->flags4 & MF4_NOSKIN) && @@ -604,7 +607,15 @@ void DIntermissionScreenCast::Drawer () { if (PlayerClasses[i].Type == mClass) { - castsprite = skins[players[consoleplayer].userinfo.GetSkin()].sprite; + FPlayerSkin *skin = &skins[players[consoleplayer].userinfo.GetSkin()]; + castsprite = skin->sprite; + + if (!(mDefaults->flags4 & MF4_NOSKIN)) + { + castscaley = FIXED2DBL(skin->ScaleY); + castscalex = FIXED2DBL(skin->ScaleX); + } + } } } @@ -615,6 +626,10 @@ void DIntermissionScreenCast::Drawer () screen->DrawTexture (pic, 160, 170, DTA_320x200, true, DTA_FlipX, sprframe->Flip & 1, + DTA_DestHeightF, pic->GetScaledHeightDouble() * castscaley, + DTA_DestWidthF, pic->GetScaledWidthDouble() * castscalex, + DTA_RenderStyle, mDefaults->RenderStyle, + DTA_Alpha, mDefaults->alpha, DTA_Translation, casttranslation, TAG_DONE); } From 6166520b33b3ec570556355c1404ab6a3095003b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 30 Jan 2016 12:49:38 +0200 Subject: [PATCH 12/20] Do not respawn on damaging floors when sv_samespawnspot is enabled See http://forum.zdoom.org/viewtopic.php?t=47191 --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index c9693ba47..789c468d1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4431,6 +4431,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) ( gameaction != ga_worlddone ) && ( p->mo != NULL ) && ( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && + ( NULL != p->attacker ) && // don't respawn on damaging floors ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter... { spawn_x = p->mo->X(); From 0ddf9db8dd33c3151300d64bc46d3aba3de27429 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 12:51:15 +0100 Subject: [PATCH 13/20] - fixed: Uncrouching a player also needs to reset the viewheight to its default. --- src/d_player.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_player.h b/src/d_player.h index 38879a63a..d6b039896 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -492,6 +492,7 @@ public: crouchdir = 0; crouching = 0; crouchviewdelta = 0; + viewheight = mo->ViewHeight; } bool CanCrouch() const From 0a0a2c4a410567fa0b08503ffa029d015baee285 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 12:59:15 +0100 Subject: [PATCH 14/20] - removed a warning. --- src/g_level.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index d799cc893..e8bf16004 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1202,7 +1202,7 @@ void G_FinishTravel () while ( (pawn = next) != NULL) { next = it.Next (); - pnum = (pawn->player - players); + pnum = int(pawn->player - players); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; start = NULL; From afcd755c7aadf1e8bded81412d473fed9078f9c3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 13:43:39 +0100 Subject: [PATCH 15/20] - changed autoaim menu option to a slider which allows a more precise control of the property. - having a value of 5000 as the default for autoaim makes no sense, since this is an angle value that will always be clamped to [0..35]. So now 35 is both the default and the maximum. --- src/d_netinfo.cpp | 6 +++--- src/menu/playermenu.cpp | 16 ++++------------ wadsrc/static/menudef.txt | 14 +------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6c5fbb6c5..3010de16d 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -60,7 +60,7 @@ static FRandom pr_pickteam ("PickRandomTeam"); -CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Float, autoaim, 35.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Int, colorset, 0, CVAR_USERINFO | CVAR_ARCHIVE); @@ -518,9 +518,9 @@ void D_UserInfoChanged (FBaseCVar *cvar) autoaim = 0.0f; return; } - else if (autoaim > 5000.0f) + else if (autoaim > 35.0f) { - autoaim = 5000.f; + autoaim = 35.f; return; } } diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index 58b08fc38..e6e25b394 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -479,7 +479,8 @@ void FSliderItem::Drawer(bool selected) screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE); int x = SmallFont->StringWidth ("Green") + 8 + mXpos; - DrawSlider (x, mYpos); + int x2 = SmallFont->StringWidth (mText) + 8 + mXpos; + DrawSlider (MAX(x2, x), mYpos); } @@ -630,14 +631,7 @@ void DPlayerMenu::Init(DMenu *parent, FListMenuDescriptor *desc) li = GetItem(NAME_Autoaim); if (li != NULL) { - int sel = - autoaim == 0 ? 0 : - autoaim <= 0.25 ? 1 : - autoaim <= 0.5 ? 2 : - autoaim <= 1 ? 3 : - autoaim <= 2 ? 4 : - autoaim <= 3 ? 5:6; - li->SetValue(0, sel); + li->SetValue(0, (int)autoaim); } li = GetItem(NAME_Switch); @@ -966,13 +960,11 @@ void DPlayerMenu::SkinChanged (FListMenuItem *li) void DPlayerMenu::AutoaimChanged (FListMenuItem *li) { - static const float ranges[] = { 0, 0.25, 0.5, 1, 2, 3, 5000 }; - int sel; if (li->GetValue(0, &sel)) { - autoaim = ranges[sel]; + autoaim = (float)sel; } } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index add844455..e198faa46 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -364,18 +364,6 @@ OptionValue "Gender" 2, "Other" } -OptionValue "Autoaim" -{ - 0, "Never" - 1, "Very low" - 2, "Low" - 3, "Medium" - 4, "High" - 5, "Very high" - 6, "Always" -} - - ListMenu "PlayerMenu" { StaticTextCentered 160, 6, "$MNU_PLAYERSETUP" @@ -414,7 +402,7 @@ ListMenu "PlayerMenu" ValueText "Class", "Class" ValueText "Skin", "Skin" ValueText "Gender", "Gender", "Gender" - ValueText "Autoaim", "Autoaim", "Autoaim" + Slider "Autoaim", "Autoaim", 0, 35, 1 ValueText "Switch on pickup", "Switch", "OffOn" ValueText "Always Run", "AlwaysRun", "OnOff" Class "PlayerMenu" From 36911bac4beb09cdedfe025d68fb3d76ffeec012 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 15:17:46 +0100 Subject: [PATCH 16/20] - fixed memory allocation type mismatch in demo code. --- src/g_game.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 7ca8b2b35..7257ed269 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2636,12 +2636,12 @@ bool G_ProcessIFFDemo (FString &mapname) if (uncompSize > 0) { - BYTE *uncompressed = new BYTE[uncompSize]; + BYTE *uncompressed = (BYTE*)M_Malloc(uncompSize); int r = uncompress (uncompressed, &uncompSize, demo_p, uLong(zdembodyend - demo_p)); if (r != Z_OK) { Printf ("Could not decompress demo! %s\n", M_ZLibError(r).GetChars()); - delete[] uncompressed; + M_Free(uncompressed); return true; } M_Free (demobuffer); From 6bce5ddc4b66e831896c86af17b64067f6a6ffd5 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 30 Jan 2016 18:30:20 +0200 Subject: [PATCH 17/20] Scale of player's skin is now preserved on corpses after reborn --- src/g_game.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/g_game.cpp b/src/g_game.cpp index 7257ed269..7f6305ca4 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1631,6 +1631,18 @@ static void G_QueueBody (AActor *body) translationtables[TRANSLATION_PlayerCorpses][modslot]->UpdateNative(); } + const int skinidx = body->player->userinfo.GetSkin(); + + if (0 != skinidx && !(body->flags4 & MF4_NOSKIN)) + { + // Apply skin's scale to actor's scale, it will be lost otherwise + const AActor *const defaultActor = body->GetDefault(); + const FPlayerSkin &skin = skins[skinidx]; + + body->scaleX = Scale(body->scaleX, skin.ScaleX, defaultActor->scaleX); + body->scaleY = Scale(body->scaleY, skin.ScaleY, defaultActor->scaleY); + } + bodyqueslot++; } From 06fdb6ca45d74ad797c2e90183ba05697c3aa0a7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 21:49:03 +0100 Subject: [PATCH 18/20] - fixed: The reverb editor failed to open in fullscreen mode at desktop resolution. According to Blzut3: The issue happens when the fullscreen resolution is the same as the desktop resolution. In this case WM_DISPLAYCHANGE doesn't occur so the editor never appears. This appears to be fixable by also catching WM_STYLECHANGED since at the very least the window caption will appear/disappear. --- src/win32/i_input.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 941fc15de..328caea06 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -525,6 +525,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_DISPLAYCHANGE: + case WM_STYLECHANGED: if (SpawnEAXWindow) { SpawnEAXWindow = false; From 46024398fea6d74ce40c685a80d19c1a8bfb5ae2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 30 Jan 2016 22:06:04 +0100 Subject: [PATCH 19/20] - fixed: Change FCheckPosition::LastRipped to a TMap so that it can track multiple overlapping actors being ripped during the same tic. --- src/g_shared/a_fastprojectile.cpp | 2 +- src/p_local.h | 3 +-- src/p_map.cpp | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index 725b858e3..1e536faa8 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -70,7 +70,7 @@ void AFastProjectile::Tick () { if (--ripcount <= 0) { - tm.LastRipped = NULL; // [RH] Do rip damage each step, like Hexen + tm.LastRipped.Clear(); // [RH] Do rip damage each step, like Hexen } if (!P_TryMove (this, X() + xfrac,Y() + yfrac, true, NULL, tm)) diff --git a/src/p_local.h b/src/p_local.h index c39bcef78..395a05990 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -445,13 +445,12 @@ struct FCheckPosition // [RH] These are used by PIT_CheckThing and P_XYMovement to apply // ripping damage once per tic instead of once per move. bool DoRipping; - AActor *LastRipped; + TMap LastRipped; int PushTime; FCheckPosition(bool rip=false) { DoRipping = rip; - LastRipped = NULL; PushTime = 0; FromPMove = false; } diff --git a/src/p_map.cpp b/src/p_map.cpp index 1aacff982..31f31e16c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1286,9 +1286,10 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS)) { - if (tm.LastRipped != thing) + bool *check = tm.LastRipped.CheckKey(thing); + if (check == NULL || !*check) { - tm.LastRipped = thing; + tm.LastRipped[thing] = true; if (!(thing->flags & MF_NOBLOOD) && !(thing->flags2 & MF2_REFLECTIVE) && !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && From d8f7785ad9fc99f90a63c6878d0f365ad87e261b Mon Sep 17 00:00:00 2001 From: John Palomo Jr Date: Sat, 30 Jan 2016 16:44:50 -0500 Subject: [PATCH 20/20] Added dimamount and dimcolor to display options menu. --- wadsrc/static/menudef.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index e198faa46..9370542e1 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -686,6 +686,8 @@ OptionMenu "VideoOptions" Option "Teleporter zoom", "telezoom", "OnOff" Slider "Earthquake shake intensity", "r_quakeintensity", 0.0, 1.0, 0.05, 2 Option "Interpolate monster movement", "nomonsterinterpolation", "NoYes" + Slider "Menu dim", "dimamount", 0, 1.0, 0.05, 2 + ColorPicker "Dim color", "dimcolor" } //-------------------------------------------------------------------------------------------