Merge branch 'master' of https://github.com/rheit/zdoom into z_osx_pure

This commit is contained in:
alexey.lysiuk 2014-12-16 10:25:34 +02:00
commit 83c8f44cc4
20 changed files with 522 additions and 72 deletions

View file

@ -3,6 +3,7 @@ cmake_minimum_required( VERSION 2.4 )
make_release_only()
include( CheckFunctionExists )
include( CheckCXXCompilerFlag )
# DUMB is much slower in a Debug build than a Release build, so we force a Release
# build here, since we're not maintaining DUMB, only using it.
@ -104,5 +105,9 @@ add_library( dumb
target_link_libraries( dumb )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE )
if( DUMB_CAN_USE_SSE )
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
endif( DUMB_CAN_USE_SSE )
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )

View file

@ -27,7 +27,9 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
if( APPLE )
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
endif( APPLE )
if( CMAKE_SIZEOF_VOID_P MATCHES "8" )
set( X64 64 )
@ -548,6 +550,7 @@ set( PLAT_WIN32_SOURCES
set( PLAT_POSIX_SOURCES
posix/i_cd.cpp
posix/i_movie.cpp
posix/i_steam.cpp
posix/i_system.cpp
posix/st_start.cpp )
set( PLAT_SDL_SOURCES

View file

@ -347,6 +347,14 @@ enum
MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag.
MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't.
MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN.
MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles.
MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected.
MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile.
MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway.
MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target.
MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer.
// --- mobj.renderflags ---
@ -859,7 +867,7 @@ public:
DWORD flags4; // [RH] Even more flags!
DWORD flags5; // OMG! We need another one.
DWORD flags6; // Shit! Where did all the flags go?
DWORD flags7; //
DWORD flags7; // WHO WANTS TO BET ON 8!?
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
DWORD VisibleToTeam;

View file

@ -430,27 +430,11 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
}
}
}
#ifdef _WIN32
FString steam_path = I_GetSteamPath();
if (steam_path.IsNotEmpty())
TArray<FString> steam_path = I_GetSteamPath();
for (i = 0; i < steam_path.Size(); ++i)
{
static const char *const steam_dirs[] =
{
"doom 2/base",
"final doom/base",
"heretic shadow of the serpent riders/base",
"hexen/base",
"hexen deathkings of the dark citadel/base",
"ultimate doom/base",
"DOOM 3 BFG Edition/base/wads"
};
steam_path += "/SteamApps/common/";
for (i = 0; i < countof(steam_dirs); ++i)
{
CheckIWAD (steam_path + steam_dirs[i], &wads[0]);
}
CheckIWAD (steam_path[i], &wads[0]);
}
#endif
}
if (iwadparm != NULL && !wads[0].Path.IsEmpty())

View file

@ -116,6 +116,7 @@ CVAR (Bool, chasedemo, false, 0);
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, save_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Bool, cl_waitforsave, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
EXTERN_CVAR (Float, con_midtime);
//==========================================================================
@ -2147,6 +2148,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
filename = G_BuildSaveName ("demosave.zds", -1);
}
if (cl_waitforsave)
I_FreezeTime(true);
insave = true;
G_SnapshotLevel ();
@ -2156,6 +2160,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
{
Printf ("Could not create savegame '%s'\n", filename.GetChars());
insave = false;
I_FreezeTime(false);
return;
}
@ -2232,6 +2237,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
insave = false;
I_FreezeTime(false);
}

View file

@ -300,6 +300,7 @@ xx(CallACS)
xx(Sqrt)
xx(CheckClass)
xx(IsPointerEqual)
xx(Pick)
// Various actor names which are used internally
xx(MapSpot)

View file

@ -1283,6 +1283,16 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
{
P_GiveBody(thing, -damage);
}
if ((thing->flags7 & MF7_THRUREFLECT) && (thing->flags2 & MF2_REFLECTIVE) && (tm.thing->flags & MF_MISSILE))
{
if (tm.thing->flags2 & MF2_SEEKERMISSILE)
{
tm.thing->tracer = tm.thing->target;
}
tm.thing->target = thing;
return true;
}
return false; // don't traverse any more
}
if (thing->flags2 & MF2_PUSHABLE && !(tm.thing->flags2 & MF2_CANNOTPUSH))
@ -1643,7 +1653,7 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj)
{ // Don't clip against self
continue;
}
if ((actor->flags & MF_MISSILE) && thing == actor->target)
if ((actor->flags & MF_MISSILE) && (thing == actor->target))
{ // Don't clip against whoever shot the missile.
continue;
}
@ -2983,18 +2993,20 @@ bool P_BounceWall(AActor *mo)
extern FRandom pr_bounce;
bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
{
//Don't go through all of this if the actor is reflective and wants things to pass through them.
if (BlockingMobj && ((BlockingMobj->flags2 & MF2_REFLECTIVE) && (BlockingMobj->flags7 & MF7_THRUREFLECT))) return true;
if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors)
|| ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) || (BlockingMobj->flags5 & MF5_DONTRIP) || ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE))
|| ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER)))
))
|| ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP)
|| (BlockingMobj->flags5 & MF5_DONTRIP)
|| ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE))
|| ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER)))))
{
if (mo->bouncecount > 0 && --mo->bouncecount == 0) return false;
if (!ontop)
{
fixed_t speed;
angle_t angle = R_PointToAngle2(BlockingMobj->x,
BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8);
angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8);
speed = P_AproxDistance(mo->velx, mo->vely);
speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
@ -5090,6 +5102,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
// is normally for projectiles which would have exploded by now anyway...
if (thing->flags6 & MF6_THRUSPECIES && thing->GetSpecies() == intersect->GetSpecies())
continue;
if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT))
continue;
if (!(intersect->flags2 & MF2_PASSMOBJ) ||
(!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) ||
(intersect->flags4 & MF4_ACTLIKEBRIDGE)
@ -5098,7 +5112,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
// Can't push bridges or things more massive than ourself
return 2;
}
fixed_t oldz = intersect->z;
fixed_t oldz;
oldz = intersect->z;
P_AdjustFloorCeil(intersect, cpos);
intersect->z = thing->z + thing->height + 1;
if (P_PushUp(intersect, cpos))

View file

@ -1202,6 +1202,9 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
if (target != NULL && ((target->flags & (MF_SHOOTABLE|MF_CORPSE)) || (target->flags6 & MF6_KILLED)) )
{
if (mo->flags7 & MF7_HITTARGET) mo->target = target;
if (mo->flags7 & MF7_HITMASTER) mo->master = target;
if (mo->flags7 & MF7_HITTRACER) mo->tracer = target;
if (target->flags & MF_NOBLOOD) nextstate = mo->FindState(NAME_Crash);
if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme);
}
@ -1660,6 +1663,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
int steps, step, totalsteps;
fixed_t startx, starty;
fixed_t oldfloorz = mo->floorz;
fixed_t oldz = mo->z;
fixed_t maxmove = (mo->waterlevel < 1) || (mo->flags & MF_MISSILE) ||
(mo->player && mo->player->crouchoffset<-10*FRACUNIT) ? MAXMOVE : MAXMOVE/4;
@ -1949,20 +1953,53 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
}
if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE))
{
angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y);
// Change angle for deflection/reflection
if (mo->AdjustReflectionAngle (BlockingMobj, angle))
bool seeker = (mo->flags2 & MF2_SEEKERMISSILE) ? true : false;
// Don't change the angle if there's THRUREFLECT on the monster.
if (!(BlockingMobj->flags7 & MF7_THRUREFLECT))
{
goto explode;
}
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);
// Reflect the missile along angle
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;
// 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)
{
dir = P_FaceMobj(mo, mo->target, &delta);
if (dir)
{ // Turn clockwise
mo->angle += delta;
}
else
{ // Turn counter clockwise
mo->angle -= delta;
}
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;
}
}
if (mo->flags2 & MF2_SEEKERMISSILE)
{
mo->tracer = mo->target;
@ -2893,6 +2930,7 @@ int AActor::SpecialMissileHit (AActor *victim)
bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle)
{
if (flags2 & MF2_DONTREFLECT) return true;
if (thing->flags7 & MF7_THRUREFLECT) return false;
// Change angle for reflection
if (thing->flags4&MF4_SHIELDREFLECT)

228
src/posix/i_steam.cpp Normal file
View file

@ -0,0 +1,228 @@
/*
** i_steam.cpp
**
**---------------------------------------------------------------------------
** Copyright 2013 Braden Obrzut
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
**
*/
#include <sys/stat.h>
#include "doomerrors.h"
#include "d_main.h"
#include "zstring.h"
#include "sc_man.h"
static void PSR_FindEndBlock(FScanner &sc)
{
int depth = 1;
do
{
if(sc.CheckToken('}'))
--depth;
else if(sc.CheckToken('{'))
++depth;
else
sc.MustGetAnyToken();
}
while(depth);
}
static void PSR_SkipBlock(FScanner &sc)
{
sc.MustGetToken('{');
PSR_FindEndBlock(sc);
}
static bool PSR_FindAndEnterBlock(FScanner &sc, const char* keyword)
{
// Finds a block with a given keyword and then enter it (opening brace)
// Should be closed with PSR_FindEndBlock
while(sc.GetToken())
{
if(sc.TokenType == '}')
{
sc.UnGet();
return false;
}
sc.TokenMustBe(TK_StringConst);
if(!sc.Compare(keyword))
{
if(!sc.CheckToken(TK_StringConst))
PSR_SkipBlock(sc);
}
else
{
sc.MustGetToken('{');
return true;
}
}
return false;
}
static TArray<FString> PSR_ReadBaseInstalls(FScanner &sc)
{
TArray<FString> result;
// Get a list of possible install directories.
while(sc.GetToken())
{
if(sc.TokenType == '}')
break;
sc.TokenMustBe(TK_StringConst);
FString key(sc.String);
if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0)
{
sc.MustGetToken(TK_StringConst);
result.Push(FString(sc.String) + "/steamapps/common");
}
else
{
if(sc.CheckToken('{'))
PSR_FindEndBlock(sc);
else
sc.MustGetToken(TK_StringConst);
}
}
return result;
}
static TArray<FString> ParseSteamRegistry(const char* path)
{
TArray<FString> dirs;
// Read registry data
FScanner sc;
sc.OpenFile(path);
sc.SetCMode(true);
// Find the SteamApps listing
if(PSR_FindAndEnterBlock(sc, "InstallConfigStore"))
{
if(PSR_FindAndEnterBlock(sc, "Software"))
{
if(PSR_FindAndEnterBlock(sc, "Valve"))
{
if(PSR_FindAndEnterBlock(sc, "Steam"))
{
dirs = PSR_ReadBaseInstalls(sc);
}
PSR_FindEndBlock(sc);
}
PSR_FindEndBlock(sc);
}
PSR_FindEndBlock(sc);
}
return dirs;
}
static struct SteamAppInfo
{
const char* const BasePath;
const int AppID;
} AppInfo[] =
{
/*{"doom 2/base", 2300},
{"final doom/base", 2290},
{"heretic shadow of the serpent riders/base", 2390},
{"hexen/base", 2360},
{"hexen deathkings of the dark citadel/base", 2370},
{"ultimate doom/base", 2280},
{"DOOM 3 BFG Edition/base/wads", 208200},*/
{"Strife", 317040}
};
TArray<FString> I_GetSteamPath()
{
TArray<FString> result;
TArray<FString> SteamInstallFolders;
// Linux and OS X actually allow the user to install to any location, so
// we need to figure out on an app-by-app basis where the game is installed.
// To do so, we read the virtual registry.
#ifdef __APPLE__
FString appSupportPath;
{
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
appSupportPath = cpath;
}
}
FString regPath = appSupportPath + "/Steam/config/config.vdf";
try
{
SteamInstallFolders = ParseSteamRegistry(regPath);
}
catch(class CDoomError &error)
{
// If we can't parse for some reason just pretend we can't find anything.
return result;
}
SteamInstallFolders.Push(appSupportPath + "/Steam/SteamApps/common");
#else
char* home = getenv("HOME");
if(home != NULL && *home != '\0')
{
FString regPath;
regPath.Format("%s/.local/share/Steam/config/config.vdf", home);
try
{
SteamInstallFolders = ParseSteamRegistry(regPath);
}
catch(class CDoomError &error)
{
// If we can't parse for some reason just pretend we can't find anything.
return result;
}
regPath.Format("%s/.local/share/Steam/SteamApps/common", home);
SteamInstallFolders.Push(regPath);
}
#endif
for(unsigned int i = 0;i < SteamInstallFolders.Size();++i)
{
for(unsigned int app = 0;app < countof(AppInfo);++app)
{
struct stat st;
FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath);
if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode))
result.Push(candidate);
}
}
return result;
}

View file

@ -120,6 +120,10 @@ void I_SetIWADInfo ();
// Pick from multiple IWADs to use
int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad);
// [RH] Checks the registry for Steam's install path, so we can scan its
// directories for IWADs if the user purchased any through Steam.
TArray<FString> I_GetSteamPath();
// The ini could not be saved at exit
bool I_WriteIniFailed ();

View file

@ -158,6 +158,7 @@ std2:
'random' { RET(TK_Random); }
'random2' { RET(TK_Random2); }
'frandom' { RET(TK_FRandom); }
'pick' { RET(TK_Pick); }
L (L|D)* { RET(TK_Identifier); }

View file

@ -122,4 +122,5 @@ xx(TK_Array, "'array'")
xx(TK_In, "'in'")
xx(TK_SizeOf, "'sizeof'")
xx(TK_AlignOf, "'alignof'")
xx(TK_Pick, "'pick'")
#undef xx

View file

@ -3071,37 +3071,41 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget)
enum CLOF_flags
{
CLOFF_NOAIM_VERT = 0x1,
CLOFF_NOAIM_HORZ = 0x2,
CLOFF_NOAIM_VERT = 0x00000001,
CLOFF_NOAIM_HORZ = 0x00000002,
CLOFF_JUMPENEMY = 0x4,
CLOFF_JUMPFRIEND = 0x8,
CLOFF_JUMPOBJECT = 0x10,
CLOFF_JUMPNONHOSTILE = 0x20,
CLOFF_JUMPENEMY = 0x00000004,
CLOFF_JUMPFRIEND = 0x00000008,
CLOFF_JUMPOBJECT = 0x00000010,
CLOFF_JUMPNONHOSTILE = 0x00000020,
CLOFF_SKIPENEMY = 0x40,
CLOFF_SKIPFRIEND = 0x80,
CLOFF_SKIPOBJECT = 0x100,
CLOFF_SKIPNONHOSTILE = 0x200,
CLOFF_SKIPENEMY = 0x00000040,
CLOFF_SKIPFRIEND = 0x00000080,
CLOFF_SKIPOBJECT = 0x00000100,
CLOFF_SKIPNONHOSTILE = 0x00000200,
CLOFF_MUSTBESHOOTABLE = 0x400,
CLOFF_MUSTBESHOOTABLE = 0x00000400,
CLOFF_SKIPTARGET = 0x800,
CLOFF_ALLOWNULL = 0x1000,
CLOFF_CHECKPARTIAL = 0x2000,
CLOFF_SKIPTARGET = 0x00000800,
CLOFF_ALLOWNULL = 0x00001000,
CLOFF_CHECKPARTIAL = 0x00002000,
CLOFF_MUSTBEGHOST = 0x4000,
CLOFF_IGNOREGHOST = 0x8000,
CLOFF_MUSTBEGHOST = 0x00004000,
CLOFF_IGNOREGHOST = 0x00008000,
CLOFF_MUSTBESOLID = 0x10000,
CLOFF_BEYONDTARGET = 0x20000,
CLOFF_MUSTBESOLID = 0x00010000,
CLOFF_BEYONDTARGET = 0x00020000,
CLOFF_FROMBASE = 0x40000,
CLOFF_MUL_HEIGHT = 0x80000,
CLOFF_MUL_WIDTH = 0x100000,
CLOFF_FROMBASE = 0x00040000,
CLOFF_MUL_HEIGHT = 0x00080000,
CLOFF_MUL_WIDTH = 0x00100000,
CLOFF_JUMP_ON_MISS = 0x200000,
CLOFF_AIM_VERT_NOOFFSET = 0x400000,
CLOFF_JUMP_ON_MISS = 0x00200000,
CLOFF_AIM_VERT_NOOFFSET = 0x00400000,
CLOFF_SETTARGET = 0x00800000,
CLOFF_SETMASTER = 0x01000000,
CLOFF_SETTRACER = 0x02000000,
};
struct LOFData
@ -3341,6 +3345,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
{
return;
}
if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor))
{
if (flags & (CLOFF_SETTARGET)) self->target = trace.Actor;
if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor;
if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor;
}
ACTION_JUMP(jump);
}
}

View file

@ -247,6 +247,12 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7),
DEFINE_FLAG(MF7, ALLOWPAIN, AActor, flags7),
DEFINE_FLAG(MF7, CAUSEPAIN, AActor, flags7),
DEFINE_FLAG(MF7, THRUREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, MIRRORREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, AIMREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, HITTARGET, AActor, flags7),
DEFINE_FLAG(MF7, HITMASTER, AActor, flags7),
DEFINE_FLAG(MF7, HITTRACER, AActor, flags7),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View file

@ -371,6 +371,37 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls)
return new FxRandom(rng, min, max, sc);
}
else if (sc.CheckToken(TK_Pick))
{
FRandom *rng;
TArray<FxExpression*> list;
list.Clear();
int index = 0;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
while (!(sc.CheckToken(')')))
{
FxExpression *min = ParseExpressionM(sc, cls);
list.Push(min);
if (sc.CheckToken(')'))
break;
else
sc.MustGetToken(',');
}
return new FxPick(rng, list, sc);
}
else if (sc.CheckToken(TK_FRandom))
{
FRandom *rng;

View file

@ -559,6 +559,27 @@ public:
//
//==========================================================================
class FxPick : public FxExpression
{
protected:
FRandom * rng;
TDeletingArray<FxExpression*> min;
public:
FxPick(FRandom *, TArray<FxExpression*> mi, const FScriptPosition &pos);
~FxPick();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression(AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxFRandom : public FxRandom
{
public:

View file

@ -1691,6 +1691,73 @@ ExpVal FxRandom::EvalExpression (AActor *self)
return val;
}
//==========================================================================
//
//
//
//==========================================================================
FxPick::FxPick(FRandom * r, TArray<FxExpression*> mi, const FScriptPosition &pos)
: FxExpression(pos)
{
for (unsigned int index = 0; index < mi.Size(); index++)
{
min.Push(new FxIntCast(mi[index]));
}
rng = r;
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxPick::~FxPick()
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxPick::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
for (unsigned int index = 0; index < min.Size(); index++)
{
RESOLVE(min[index], ctx);
ABORT(min[index]);
}
return this;
};
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxPick::EvalExpression(AActor *self)
{
ExpVal val;
val.Type = VAL_Int;
int max = min.Size();
if (max > 0)
{
int select = (*rng)(max);
val.Int = min[select]->EvalExpression(self).GetInt();
}
else
{
val.Int = (*rng)();
}
return val;
}
//==========================================================================
//
//

View file

@ -1524,20 +1524,36 @@ static bool QueryPathKey(HKEY key, const char *keypath, const char *valname, FSt
//
//==========================================================================
FString I_GetSteamPath()
TArray<FString> I_GetSteamPath()
{
TArray<FString> result;
static const char *const steam_dirs[] =
{
"doom 2/base",
"final doom/base",
"heretic shadow of the serpent riders/base",
"hexen/base",
"hexen deathkings of the dark citadel/base",
"ultimate doom/base",
"DOOM 3 BFG Edition/base/wads",
"Strife"
};
FString path;
if (QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path))
if (!QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path))
{
return path;
if (!QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path))
return result;
}
if (QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path))
path += "/SteamApps/common/";
for(unsigned int i = 0; i < countof(steam_dirs); ++i)
{
return path;
result.Push(path + steam_dirs[i]);
}
path = "";
return path;
return result;
}
//==========================================================================

View file

@ -142,7 +142,7 @@ void I_SetWndProc();
// [RH] Checks the registry for Steam's install path, so we can scan its
// directories for IWADs if the user purchased any through Steam.
FString I_GetSteamPath();
TArray<FString> I_GetSteamPath();
// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
// giving them proper prototypes under Win32, they are just macros for

View file

@ -372,6 +372,10 @@ enum
CLOFF_JUMP_ON_MISS = 0x200000,
CLOFF_AIM_VERT_NOOFFSET = 0x400000,
CLOFF_SETTARGET = 0x800000,
CLOFF_SETMASTER = 0x1000000,
CLOFF_SETTRACER = 0x2000000,
CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE,
CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ
};