This commit is contained in:
Christoph Oelckers 2016-01-30 23:01:36 +01:00
commit 8bc7a0a24e
18 changed files with 269 additions and 222 deletions

View file

@ -369,14 +369,6 @@ bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill)
D_ReadUserInfoStrings (bnum, &info, false); 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). multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
players[bnum].Bot = new DBot; players[bnum].Bot = new DBot;
players[bnum].Bot->player = &players[bnum]; players[bnum].Bot->player = &players[bnum];

View file

@ -60,7 +60,7 @@
static FRandom pr_pickteam ("PickRandomTeam"); 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 (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Int, colorset, 0, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Int, colorset, 0, CVAR_USERINFO | CVAR_ARCHIVE);
@ -518,9 +518,9 @@ void D_UserInfoChanged (FBaseCVar *cvar)
autoaim = 0.0f; autoaim = 0.0f;
return; return;
} }
else if (autoaim > 5000.0f) else if (autoaim > 35.0f)
{ {
autoaim = 5000.f; autoaim = 35.f;
return; return;
} }
} }

View file

@ -492,6 +492,7 @@ public:
crouchdir = 0; crouchdir = 0;
crouching = 0; crouching = 0;
crouchviewdelta = 0; crouchviewdelta = 0;
viewheight = mo->ViewHeight;
} }
bool CanCrouch() const bool CanCrouch() const

View file

@ -1422,6 +1422,8 @@ bool G_CheckSpot (int playernum, FPlayerStart *mthing)
fixed_t z, oldz; fixed_t z, oldz;
int i; int i;
if (mthing->type == 0) return false;
x = mthing->x; x = mthing->x;
y = mthing->y; y = mthing->y;
z = mthing->z; z = mthing->z;
@ -1573,6 +1575,11 @@ void G_DeathMatchSpawnPlayer (int playernum)
// //
FPlayerStart *G_PickPlayerStart(int playernum, int flags) 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) || if ((level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) || (flags & PPS_FORCERANDOM) ||
playerstarts[playernum].type == 0) playerstarts[playernum].type == 0)
{ {
@ -1624,6 +1631,18 @@ static void G_QueueBody (AActor *body)
translationtables[TRANSLATION_PlayerCorpses][modslot]->UpdateNative(); 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++; bodyqueslot++;
} }
@ -2629,12 +2648,12 @@ bool G_ProcessIFFDemo (FString &mapname)
if (uncompSize > 0) 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)); int r = uncompress (uncompressed, &uncompSize, demo_p, uLong(zdembodyend - demo_p));
if (r != Z_OK) if (r != Z_OK)
{ {
Printf ("Could not decompress demo! %s\n", M_ZLibError(r).GetChars()); Printf ("Could not decompress demo! %s\n", M_ZLibError(r).GetChars());
delete[] uncompressed; M_Free(uncompressed);
return true; return true;
} }
M_Free (demobuffer); M_Free (demobuffer);

View file

@ -1195,74 +1195,83 @@ void G_FinishTravel ()
TThinkerIterator<APlayerPawn> it (STAT_TRAVELLING); TThinkerIterator<APlayerPawn> it (STAT_TRAVELLING);
APlayerPawn *pawn, *pawndup, *oldpawn, *next; APlayerPawn *pawn, *pawndup, *oldpawn, *next;
AInventory *inv; AInventory *inv;
FPlayerStart *start;
int pnum;
next = it.Next (); next = it.Next ();
while ( (pawn = next) != NULL) while ( (pawn = next) != NULL)
{ {
next = it.Next (); next = it.Next ();
pnum = int(pawn->player - players);
pawn->ChangeStatNum (STAT_PLAYER); pawn->ChangeStatNum (STAT_PLAYER);
pawndup = pawn->player->mo; pawndup = pawn->player->mo;
start = NULL;
assert (pawn != pawndup); assert (pawn != pawndup);
if (pawndup == NULL) if (pawndup == NULL)
{ // Oh no! there was no start for this player! { // Oh no! there was no start for this player!
pawn->flags |= MF_NOSECTOR|MF_NOBLOCKMAP; start = G_PickPlayerStart(pnum, PPS_FORCERANDOM);
pawn->Destroy (); if (start != NULL) 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 for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory)
// must not start any ENTER script or big problems will happen. {
pawndup = P_SpawnPlayer (&playerstarts[pawn->player - players], int(pawn->player - players), SPF_TEMPPLAYER); inv->ChangeStatNum (STAT_INVENTORY);
if (!(changeflags & CHANGELEVEL_KEEPFACING)) inv->LinkToWorld ();
{ inv->Travelled ();
pawn->angle = pawndup->angle; }
pawn->pitch = pawndup->pitch; if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED)
} {
pawn->SetXYZ(pawndup->X(), pawndup->Y(), pawndup->Z()); pawn->Speed = pawn->GetDefault()->Speed;
pawn->velx = pawndup->velx; }
pawn->vely = pawndup->vely; if (level.FromSnapshot)
pawn->velz = pawndup->velz; {
pawn->Sector = pawndup->Sector; FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true);
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);
}
} }
} }

View file

@ -1500,7 +1500,9 @@ void APowerTimeFreezer::InitEffect()
} }
else else
{ {
EffectTics++; // Compensate for skipped tic, but beware of overflow.
if(EffectTics < INT_MAX)
EffectTics++;
} }
} }

View file

@ -70,7 +70,7 @@ void AFastProjectile::Tick ()
{ {
if (--ripcount <= 0) 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)) if (!P_TryMove (this, X() + xfrac,Y() + yfrac, true, NULL, tm))

View file

@ -591,6 +591,9 @@ void DIntermissionScreenCast::Drawer ()
// draw the current frame in the middle of the screen // draw the current frame in the middle of the screen
if (caststate != NULL) if (caststate != NULL)
{ {
double castscalex = FIXED2DBL(mDefaults->scaleX);
double castscaley = FIXED2DBL(mDefaults->scaleY);
int castsprite = caststate->sprite; int castsprite = caststate->sprite;
if (!(mDefaults->flags4 & MF4_NOSKIN) && if (!(mDefaults->flags4 & MF4_NOSKIN) &&
@ -604,7 +607,15 @@ void DIntermissionScreenCast::Drawer ()
{ {
if (PlayerClasses[i].Type == mClass) 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, screen->DrawTexture (pic, 160, 170,
DTA_320x200, true, DTA_320x200, true,
DTA_FlipX, sprframe->Flip & 1, 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, DTA_Translation, casttranslation,
TAG_DONE); TAG_DONE);
} }

View file

@ -479,7 +479,8 @@ void FSliderItem::Drawer(bool selected)
screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE); screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
int x = SmallFont->StringWidth ("Green") + 8 + mXpos; 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); li = GetItem(NAME_Autoaim);
if (li != NULL) if (li != NULL)
{ {
int sel = li->SetValue(0, (int)autoaim);
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 = GetItem(NAME_Switch); li = GetItem(NAME_Switch);
@ -966,13 +960,11 @@ void DPlayerMenu::SkinChanged (FListMenuItem *li)
void DPlayerMenu::AutoaimChanged (FListMenuItem *li) void DPlayerMenu::AutoaimChanged (FListMenuItem *li)
{ {
static const float ranges[] = { 0, 0.25, 0.5, 1, 2, 3, 5000 };
int sel; int sel;
if (li->GetValue(0, &sel)) if (li->GetValue(0, &sel))
{ {
autoaim = ranges[sel]; autoaim = (float)sel;
} }
} }

View file

@ -132,7 +132,9 @@ CUSTOM_CVAR( Int, r_maxparticles, 4000, CVAR_ARCHIVE )
{ {
if ( self == 0 ) if ( self == 0 )
self = 4000; self = 4000;
else if ( self < 100 ) else if (self > 65535)
self = 65535;
else if (self < 100)
self = 100; self = 100;
if ( gamestate != GS_STARTUP ) if ( gamestate != GS_STARTUP )

View file

@ -445,13 +445,12 @@ struct FCheckPosition
// [RH] These are used by PIT_CheckThing and P_XYMovement to apply // [RH] These are used by PIT_CheckThing and P_XYMovement to apply
// ripping damage once per tic instead of once per move. // ripping damage once per tic instead of once per move.
bool DoRipping; bool DoRipping;
AActor *LastRipped; TMap<AActor*, bool> LastRipped;
int PushTime; int PushTime;
FCheckPosition(bool rip=false) FCheckPosition(bool rip=false)
{ {
DoRipping = rip; DoRipping = rip;
LastRipped = NULL;
PushTime = 0; PushTime = 0;
FromPMove = false; FromPMove = false;
} }

View file

@ -1286,9 +1286,10 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
{ {
if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS)) 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) && if (!(thing->flags & MF_NOBLOOD) &&
!(thing->flags2 & MF2_REFLECTIVE) && !(thing->flags2 & MF2_REFLECTIVE) &&
!(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) &&

View file

@ -4431,6 +4431,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
( gameaction != ga_worlddone ) && ( gameaction != ga_worlddone ) &&
( p->mo != NULL ) && ( p->mo != NULL ) &&
( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) && ( !(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... ( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter...
{ {
spawn_x = p->mo->X(); spawn_x = p->mo->X();

View file

@ -283,6 +283,7 @@ void I_InitSound ()
if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent()) if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent())
{ {
Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n"); Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n");
I_CloseSound();
GSnd = new OpenALSoundRenderer; GSnd = new OpenALSoundRenderer;
snd_backend = "openal"; snd_backend = "openal";
} }
@ -300,6 +301,7 @@ void I_InitSound ()
if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent()) if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent())
{ {
Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n"); Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n");
I_CloseSound();
GSnd = new FMODSoundRenderer; GSnd = new FMODSoundRenderer;
snd_backend = "fmod"; snd_backend = "fmod";
} }

View file

@ -4975,6 +4975,133 @@ enum RadiusGiveFlags
RGF_EITHER = 1 << 17, 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] 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));
if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass)))
{
if (thing != self) //Don't let filter and species obstruct 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)));
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<double>(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<AInventory *>(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) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
{ {
ACTION_PARAM_START(7); ACTION_PARAM_START(7);
@ -4997,126 +5124,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
{ {
amount = 1; amount = 1;
} }
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
AActor *thing; AActor *thing;
bool given = false; bool given = false;
while ((thing = it.Next())) if (flags & RGF_MISSILES)
{ {
//[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). TThinkerIterator<AActor> it;
bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), while ((thing = it.Next()))
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. if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true;
continue;
} }
}
if (thing == self) else
{
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
while ((thing = it.Next()))
{ {
if (!(flags & RGF_GIVESELF)) if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true;
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<double>(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<AInventory *>(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); ACTION_SET_RESULT(given);

View file

@ -1424,13 +1424,11 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real
*cleany = cy2; *cleany = cy2;
} }
if (*cleanx > 1 && *cleany > 1 && *cleanx != *cleany) if (*cleanx < *cleany)
{ *cleany = *cleanx;
if (*cleanx < *cleany) else
*cleany = *cleanx; *cleanx = *cleany;
else
*cleanx = *cleany;
}
if (_cx1 != NULL) *_cx1 = cx1; if (_cx1 != NULL) *_cx1 = cx1;
if (_cx2 != NULL) *_cx2 = cx2; if (_cx2 != NULL) *_cx2 = cx2;
} }

View file

@ -525,6 +525,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break; break;
case WM_DISPLAYCHANGE: case WM_DISPLAYCHANGE:
case WM_STYLECHANGED:
if (SpawnEAXWindow) if (SpawnEAXWindow)
{ {
SpawnEAXWindow = false; SpawnEAXWindow = false;

View file

@ -364,18 +364,6 @@ OptionValue "Gender"
2, "Other" 2, "Other"
} }
OptionValue "Autoaim"
{
0, "Never"
1, "Very low"
2, "Low"
3, "Medium"
4, "High"
5, "Very high"
6, "Always"
}
ListMenu "PlayerMenu" ListMenu "PlayerMenu"
{ {
StaticTextCentered 160, 6, "$MNU_PLAYERSETUP" StaticTextCentered 160, 6, "$MNU_PLAYERSETUP"
@ -414,7 +402,7 @@ ListMenu "PlayerMenu"
ValueText "Class", "Class" ValueText "Class", "Class"
ValueText "Skin", "Skin" ValueText "Skin", "Skin"
ValueText "Gender", "Gender", "Gender" ValueText "Gender", "Gender", "Gender"
ValueText "Autoaim", "Autoaim", "Autoaim" Slider "Autoaim", "Autoaim", 0, 35, 1
ValueText "Switch on pickup", "Switch", "OffOn" ValueText "Switch on pickup", "Switch", "OffOn"
ValueText "Always Run", "AlwaysRun", "OnOff" ValueText "Always Run", "AlwaysRun", "OnOff"
Class "PlayerMenu" Class "PlayerMenu"
@ -710,6 +698,8 @@ OptionMenu "VideoOptions"
Option "Teleporter zoom", "telezoom", "OnOff" Option "Teleporter zoom", "telezoom", "OnOff"
Slider "Earthquake shake intensity", "r_quakeintensity", 0.0, 1.0, 0.05, 2 Slider "Earthquake shake intensity", "r_quakeintensity", 0.0, 1.0, 0.05, 2
Option "Interpolate monster movement", "nomonsterinterpolation", "NoYes" Option "Interpolate monster movement", "nomonsterinterpolation", "NoYes"
Slider "Menu dim", "dimamount", 0, 1.0, 0.05, 2
ColorPicker "Dim color", "dimcolor"
} }
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------