mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-03-02 06:42:03 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
This commit is contained in:
commit
1f400a604d
40 changed files with 753 additions and 318 deletions
|
@ -269,6 +269,9 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
|
||||
endif()
|
||||
set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" )
|
||||
|
||||
|
@ -296,6 +299,13 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
# With standard Apple tools -stdlib=libc++ needs to be specified in order to get
|
||||
# C++11 support using SDKs 10.7 and 10.8.
|
||||
if ( APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
|
||||
set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ ${CMAKE_EXE_LINKER_FLAGS}" )
|
||||
endif ()
|
||||
|
||||
# Remove extra warnings when using the official DirectX headers.
|
||||
# Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid,
|
||||
# which is a royal pain. The previous version I had been using was fine with them.
|
||||
|
|
|
@ -413,6 +413,7 @@ enum ActorRenderFlag
|
|||
RF_INVISIBLE = 0x8000, // Don't bother drawing this actor
|
||||
RF_ROLLSPRITE = 0x40000, //[marrub]roll the sprite billboard
|
||||
RF_DONTFLIP = 0x80000, // Don't flip it when viewed from behind.
|
||||
RF_ROLLCENTER = 0x100000, // Rotate from the center of sprite instead of offsets
|
||||
|
||||
RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
|
||||
RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)
|
||||
|
|
|
@ -533,7 +533,10 @@ public:
|
|||
void TickPSprites();
|
||||
void DestroyPSprites();
|
||||
DPSprite *FindPSprite(int layer);
|
||||
DPSprite *GetPSprite(PSPLayers layer); // Used ONLY for compatibility with the old hardcoded layers.
|
||||
// Used ONLY for compatibility with the old hardcoded layers.
|
||||
// Make sure that a state is properly set after calling this unless
|
||||
// you are 100% sure the context already implies the layer exists.
|
||||
DPSprite *GetPSprite(PSPLayers layer);
|
||||
};
|
||||
|
||||
// Bookkeeping on players - state.
|
||||
|
|
|
@ -1272,6 +1272,7 @@ void PFloat::WriteValue(FArchive &ar, const void *addr) const
|
|||
{
|
||||
ar.WriteByte(VAL_Float64);
|
||||
ar << doubleprecision;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -335,7 +335,7 @@ struct mapthinghexen_t
|
|||
SWORD z;
|
||||
SWORD angle;
|
||||
SWORD type;
|
||||
SWORD flags;
|
||||
WORD flags;
|
||||
BYTE special;
|
||||
BYTE args[5];
|
||||
};
|
||||
|
|
|
@ -728,13 +728,13 @@ void FArchive::WriteByte(BYTE val)
|
|||
|
||||
void FArchive::WriteInt16(WORD val)
|
||||
{
|
||||
WORD out = LittleShort(val);
|
||||
WORD out = SWAP_WORD(val);
|
||||
m_File->Write(&out, 2);
|
||||
}
|
||||
|
||||
void FArchive::WriteInt32(DWORD val)
|
||||
{
|
||||
int out = LittleLong(val);
|
||||
int out = SWAP_DWORD(val);
|
||||
m_File->Write(&out, 4);
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
|
|||
{
|
||||
spit->special2 = 0;
|
||||
}
|
||||
else if (fabs(spit->Vel.X) > fabs(spit->Vel.Y))
|
||||
else if (fabs(spit->Vel.Y) > fabs(spit->Vel.X))
|
||||
{
|
||||
spit->special2 = int((targ->Y() - self->Y()) / spit->Vel.Y);
|
||||
}
|
||||
|
|
|
@ -123,9 +123,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
|
|||
|
||||
void P_UpdateBeak (AActor *self)
|
||||
{
|
||||
if (self->player != nullptr)
|
||||
DPSprite *pspr;
|
||||
if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr)
|
||||
{
|
||||
self->player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + self->player->chickenPeck / 2;
|
||||
pspr->y = WEAPONTOP + self->player->chickenPeck / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1127,12 +1127,27 @@ void APowerWeaponLevel2::InitEffect ()
|
|||
|
||||
assert (sister->SisterWeapon == weapon);
|
||||
|
||||
Owner->player->ReadyWeapon = sister;
|
||||
|
||||
if (weapon->GetReadyState() != sister->GetReadyState())
|
||||
{
|
||||
Owner->player->ReadyWeapon = sister;
|
||||
P_SetPsprite(Owner->player, PSP_WEAPON, sister->GetReadyState());
|
||||
}
|
||||
else
|
||||
{
|
||||
DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
|
||||
if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
|
||||
{
|
||||
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
|
||||
psp->SetCaller(sister);
|
||||
Owner->player->ReadyWeapon = sister;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong. Initiate a regular weapon change.
|
||||
Owner->player->PendingWeapon = sister;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -642,7 +642,18 @@ void AWeapon::EndPowerup ()
|
|||
}
|
||||
else
|
||||
{
|
||||
Owner->player->ReadyWeapon = SisterWeapon;
|
||||
DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
|
||||
if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
|
||||
{
|
||||
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
|
||||
psp->SetCaller(SisterWeapon);
|
||||
Owner->player->ReadyWeapon = SisterWeapon;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something went wrong. Initiate a regular weapon change.
|
||||
Owner->player->PendingWeapon = SisterWeapon;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3440,6 +3440,30 @@ class CommandIfInvulnerable : public SBarInfoNegatableFlowControl
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CommandIfWaterLevel : public SBarInfoNegatableFlowControl
|
||||
{
|
||||
public:
|
||||
CommandIfWaterLevel(SBarInfo *script) : SBarInfoNegatableFlowControl(script)
|
||||
{
|
||||
}
|
||||
|
||||
void ParseNegatable(FScanner &sc, bool fullScreenOffsets)
|
||||
{
|
||||
sc.MustGetToken(TK_IntConst);
|
||||
value = sc.Number;
|
||||
}
|
||||
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
|
||||
{
|
||||
SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged);
|
||||
|
||||
SetTruth(statusBar->CPlayer->mo->waterlevel >= value, block, statusBar);
|
||||
}
|
||||
protected:
|
||||
int value;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *SBarInfoCommandNames[] =
|
||||
{
|
||||
"drawimage", "drawnumber", "drawswitchableimage",
|
||||
|
@ -3450,7 +3474,7 @@ static const char *SBarInfoCommandNames[] =
|
|||
"isselected", "usesammo", "usessecondaryammo",
|
||||
"hasweaponpiece", "inventorybarnotvisible",
|
||||
"weaponammo", "ininventory", "alpha", "ifhealth",
|
||||
"ifinvulnerable",
|
||||
"ifinvulnerable", "ifwaterlevel",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -3464,7 +3488,7 @@ enum SBarInfoCommands
|
|||
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
|
||||
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
|
||||
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_IFHEALTH,
|
||||
SBARINFO_IFINVULNERABLE,
|
||||
SBARINFO_IFINVULNERABLE, SBARINFO_IFWATERLEVEL,
|
||||
};
|
||||
|
||||
SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
||||
|
@ -3499,6 +3523,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
|
|||
case SBARINFO_ALPHA: return new CommandAlpha(script);
|
||||
case SBARINFO_IFHEALTH: return new CommandIfHealth(script);
|
||||
case SBARINFO_IFINVULNERABLE: return new CommandIfInvulnerable(script);
|
||||
case SBARINFO_IFWATERLEVEL: return new CommandIfWaterLevel(script);
|
||||
}
|
||||
|
||||
sc.ScriptError("Unknown command '%s'.\n", sc.String);
|
||||
|
|
|
@ -81,6 +81,7 @@ CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD
|
|||
CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD
|
||||
CVAR (Int , hud_showlag, 0, CVAR_ARCHIVE); // Show input latency (maketic - gametic difference)
|
||||
|
||||
CVAR (Int, hud_ammo_order, 0, CVAR_ARCHIVE); // ammo image and text order
|
||||
CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red
|
||||
CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green
|
||||
CVAR (Int, hud_health_red, 25, CVAR_ARCHIVE) // health amount less than which status is red
|
||||
|
@ -586,9 +587,21 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
|
|||
// ok, we got all ammo types. Now draw the list back to front (bottom to top)
|
||||
|
||||
int def_width = ConFont->StringWidth("000/000");
|
||||
x-=def_width;
|
||||
int yadd = ConFont->GetHeight();
|
||||
|
||||
int xtext = x - def_width;
|
||||
int ximage = x;
|
||||
|
||||
if (hud_ammo_order > 0)
|
||||
{
|
||||
xtext -= 24;
|
||||
ximage -= 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
ximage -= def_width + 20;
|
||||
}
|
||||
|
||||
for(i=orderedammos.Size()-1;i>=0;i--)
|
||||
{
|
||||
|
||||
|
@ -613,8 +626,8 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
|
|||
ammo < ( (maxammo * hud_ammo_red) / 100) ? CR_RED :
|
||||
ammo < ( (maxammo * hud_ammo_yellow) / 100) ? CR_GOLD : CR_GREEN );
|
||||
|
||||
DrawHudText(ConFont, fontcolor, buf, x-tex_width, y+yadd, trans);
|
||||
DrawImageToBox(TexMan[icon], x-20, y, 16, 8, trans);
|
||||
DrawHudText(ConFont, fontcolor, buf, xtext-tex_width, y+yadd, trans);
|
||||
DrawImageToBox(TexMan[icon], ximage, y, 16, 8, trans);
|
||||
y-=10;
|
||||
}
|
||||
return y;
|
||||
|
|
|
@ -352,22 +352,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns)
|
|||
|
||||
if (self->player != nullptr && self->player->mo == self)
|
||||
{
|
||||
FState *firehands = self->FindState("FireHands");
|
||||
if (firehands != NULL)
|
||||
{
|
||||
DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
|
||||
if (psp != nullptr)
|
||||
{
|
||||
psp->SetState(firehands);
|
||||
psp->Flags &= PSPF_ADDWEAPON | PSPF_ADDBOB;
|
||||
psp->y = WEAPONTOP;
|
||||
}
|
||||
P_SetPsprite(self->player, PSP_STRIFEHANDS, self->FindState("FireHands"));
|
||||
|
||||
self->player->ReadyWeapon = nullptr;
|
||||
self->player->PendingWeapon = WP_NOCHANGE;
|
||||
self->player->playerstate = PST_LIVE;
|
||||
self->player->extralight = 3;
|
||||
}
|
||||
self->player->ReadyWeapon = nullptr;
|
||||
self->player->PendingWeapon = WP_NOCHANGE;
|
||||
self->player->playerstate = PST_LIVE;
|
||||
self->player->extralight = 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -388,14 +378,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer)
|
|||
|
||||
if (self->player != nullptr && self->player->mo == self)
|
||||
{
|
||||
self->player->playerstate = PST_DEAD;
|
||||
|
||||
DPSprite *psp;
|
||||
psp = self->player->GetPSprite(PSP_STRIFEHANDS);
|
||||
|
||||
FState *firehandslower = self->FindState("FireHandsLower");
|
||||
FState *firehands = self->FindState("FireHands");
|
||||
if (firehandslower != NULL && firehands != NULL && firehands < firehandslower)
|
||||
psp->SetState(psp->GetState() + (firehandslower - firehands));
|
||||
FState *state = psp->GetState();
|
||||
|
||||
if (state != nullptr && firehandslower != nullptr && firehands != nullptr && firehands < firehandslower)
|
||||
{
|
||||
self->player->playerstate = PST_DEAD;
|
||||
psp->SetState(state + (firehandslower - firehands));
|
||||
}
|
||||
else if (state == nullptr)
|
||||
{
|
||||
psp->SetState(nullptr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -407,13 +405,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_HandLower)
|
|||
if (self->player != nullptr)
|
||||
{
|
||||
DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
|
||||
|
||||
if (psp->GetState() == nullptr)
|
||||
{
|
||||
psp->SetState(nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
psp->y += 9;
|
||||
if (psp->y > WEAPONBOTTOM*2)
|
||||
{
|
||||
psp->SetState(nullptr);
|
||||
}
|
||||
|
||||
if (self->player->extralight > 0) self->player->extralight--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,9 +56,8 @@ struct FPortal
|
|||
|
||||
struct FGLLinePortal
|
||||
{
|
||||
// defines the complete span of this portal
|
||||
vertex_t *v1, *v2; // vertices, from v1 to v2
|
||||
DVector2 delta; // precalculated v2 - v1 for side checking
|
||||
// defines the complete span of this portal, if this is of type PORTT_LINKED.
|
||||
vertex_t *v1 = nullptr, *v2 = nullptr; // vertices, from v1 to v2
|
||||
TArray<FLinePortal *> lines;
|
||||
int validcount = 0;
|
||||
};
|
||||
|
|
|
@ -443,54 +443,49 @@ void gl_InitPortals()
|
|||
tempindex[i] = glLinePortals.Size();
|
||||
line_t *pSrcLine = linePortals[i].mOrigin;
|
||||
line_t *pLine = linePortals[i].mDestination;
|
||||
FGLLinePortal glport;
|
||||
|
||||
glport.v1 = pLine->v1;
|
||||
glport.v2 = pLine->v2;
|
||||
glport.delta = { 0, 0 };
|
||||
FGLLinePortal &glport = glLinePortals[glLinePortals.Reserve(1)];
|
||||
glport.lines.Push(&linePortals[i]);
|
||||
glLinePortals.Push(glport);
|
||||
|
||||
// We cannot do this grouping for non-linked portals because they can be changed at run time.
|
||||
if (linePortals[i].mType == PORTT_LINKED)
|
||||
do
|
||||
if (linePortals[i].mType == PORTT_LINKED && pLine != nullptr)
|
||||
{
|
||||
// now collect all other colinear lines connected to this one. We run this loop as long as it still finds a match
|
||||
gotsome = false;
|
||||
for (unsigned j = 0; j < linePortals.Size(); j++)
|
||||
glport.v1 = pLine->v1;
|
||||
glport.v2 = pLine->v2;
|
||||
do
|
||||
{
|
||||
if (tempindex[j] == -1)
|
||||
// now collect all other colinear lines connected to this one. We run this loop as long as it still finds a match
|
||||
gotsome = false;
|
||||
for (unsigned j = 0; j < linePortals.Size(); j++)
|
||||
{
|
||||
line_t *pSrcLine2 = linePortals[j].mOrigin;
|
||||
line_t *pLine2 = linePortals[j].mDestination;
|
||||
// angular precision is intentionally reduced to 32 bit BAM to account for precision problems (otherwise many not perfectly horizontal or vertical portals aren't found here.)
|
||||
unsigned srcang = pSrcLine->Delta().Angle().BAMs();
|
||||
unsigned dstang = pLine->Delta().Angle().BAMs();
|
||||
if ((pSrcLine->v2 == pSrcLine2->v1 && pLine->v1 == pLine2->v2) ||
|
||||
(pSrcLine->v1 == pSrcLine2->v2 && pLine->v2 == pLine2->v1))
|
||||
if (tempindex[j] == -1)
|
||||
{
|
||||
// The line connects, now check the translation
|
||||
unsigned srcang2 = pSrcLine2->Delta().Angle().BAMs();
|
||||
unsigned dstang2 = pLine2->Delta().Angle().BAMs();
|
||||
if (srcang == srcang2 && dstang == dstang2)
|
||||
line_t *pSrcLine2 = linePortals[j].mOrigin;
|
||||
line_t *pLine2 = linePortals[j].mDestination;
|
||||
// angular precision is intentionally reduced to 32 bit BAM to account for precision problems (otherwise many not perfectly horizontal or vertical portals aren't found here.)
|
||||
unsigned srcang = pSrcLine->Delta().Angle().BAMs();
|
||||
unsigned dstang = pLine->Delta().Angle().BAMs();
|
||||
if ((pSrcLine->v2 == pSrcLine2->v1 && pLine->v1 == pLine2->v2) ||
|
||||
(pSrcLine->v1 == pSrcLine2->v2 && pLine->v2 == pLine2->v1))
|
||||
{
|
||||
// The lines connect and both source and destination are colinear, so this is a match
|
||||
gotsome = true;
|
||||
tempindex[j] = tempindex[i];
|
||||
if (pLine->v1 == pLine2->v2) glLinePortals[tempindex[i]].v1 = pLine2->v1;
|
||||
else glLinePortals[tempindex[i]].v2 = pLine2->v2;
|
||||
glLinePortals[tempindex[i]].lines.Push(&linePortals[j]);
|
||||
// The line connects, now check the translation
|
||||
unsigned srcang2 = pSrcLine2->Delta().Angle().BAMs();
|
||||
unsigned dstang2 = pLine2->Delta().Angle().BAMs();
|
||||
if (srcang == srcang2 && dstang == dstang2)
|
||||
{
|
||||
// The lines connect and both source and destination are colinear, so this is a match
|
||||
gotsome = true;
|
||||
tempindex[j] = tempindex[i];
|
||||
if (pLine->v1 == pLine2->v2) glport.v1 = pLine2->v1;
|
||||
else glport.v2 = pLine2->v2;
|
||||
glport.lines.Push(&linePortals[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (gotsome);
|
||||
} while (gotsome);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto glport : glLinePortals)
|
||||
{
|
||||
glport.delta = glport.v2->fPos() - glport.v1->fPos();
|
||||
}
|
||||
linePortalToGL.Resize(linePortals.Size());
|
||||
for (unsigned i = 0; i < linePortals.Size(); i++)
|
||||
{
|
||||
|
|
|
@ -460,7 +460,7 @@ void gl_InitModels()
|
|||
{
|
||||
int Lump, lastLump;
|
||||
FString path;
|
||||
int index;
|
||||
int index, surface;
|
||||
int i;
|
||||
|
||||
FSpriteModelFrame smf;
|
||||
|
@ -616,11 +616,19 @@ void gl_InitModels()
|
|||
}
|
||||
else if (sc.Compare("inheritactorpitch"))
|
||||
{
|
||||
smf.flags |= MDL_INHERITACTORPITCH;
|
||||
smf.flags |= MDL_USEACTORPITCH | MDL_BADROTATION;
|
||||
}
|
||||
else if (sc.Compare("inheritactorroll"))
|
||||
{
|
||||
smf.flags |= MDL_INHERITACTORROLL;
|
||||
smf.flags |= MDL_USEACTORROLL;
|
||||
}
|
||||
else if (sc.Compare("useactorpitch"))
|
||||
{
|
||||
smf.flags |= MDL_USEACTORPITCH;
|
||||
}
|
||||
else if (sc.Compare("useactorroll"))
|
||||
{
|
||||
smf.flags |= MDL_USEACTORROLL;
|
||||
}
|
||||
else if (sc.Compare("rotating"))
|
||||
{
|
||||
|
@ -688,6 +696,39 @@ void gl_InitModels()
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("surfaceskin"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
index = sc.Number;
|
||||
sc.MustGetNumber();
|
||||
surface = sc.Number;
|
||||
|
||||
if (index<0 || index >= MAX_MODELS_PER_FRAME)
|
||||
{
|
||||
sc.ScriptError("Too many models in %s", smf.type->TypeName.GetChars());
|
||||
}
|
||||
|
||||
if (surface<0 || surface >= MD3_MAX_SURFACES)
|
||||
{
|
||||
sc.ScriptError("Invalid MD3 Surface %d in %s", MD3_MAX_SURFACES, smf.type->TypeName.GetChars());
|
||||
}
|
||||
|
||||
sc.MustGetString();
|
||||
FixPathSeperator(sc.String);
|
||||
if (sc.Compare(""))
|
||||
{
|
||||
smf.surfaceskinIDs[index][surface] = FNullTextureID();
|
||||
}
|
||||
else
|
||||
{
|
||||
smf.surfaceskinIDs[index][surface] = LoadSkin(path.GetChars(), sc.String);
|
||||
if (!smf.surfaceskinIDs[index][surface].isValid())
|
||||
{
|
||||
Printf("Surface Skin '%s' not found in '%s'\n",
|
||||
sc.String, smf.type->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("frameindex") || sc.Compare("frame"))
|
||||
{
|
||||
bool isframe=!!sc.Compare("frame");
|
||||
|
@ -893,6 +934,8 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf,
|
|||
mdl->BuildVertexBuffer();
|
||||
gl_RenderState.SetVertexBuffer(mdl->mVBuf);
|
||||
|
||||
mdl->PushSpriteMDLFrame(smf, i);
|
||||
|
||||
if ( smfNext && smf->modelframes[i] != smfNext->modelframes[i] )
|
||||
mdl->RenderFrame(tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
||||
else
|
||||
|
@ -961,10 +1004,15 @@ void gl_RenderModel(GLSprite * spr)
|
|||
rotateOffset = float((time - xs_FloorToInt(time)) *360.f );
|
||||
}
|
||||
|
||||
// Added MDL_INHERITACTORPITCH and MDL_INHERITACTORROLL flags processing.
|
||||
// If both flags MDL_INHERITACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the momentum vector pitch.
|
||||
if(smf->flags & MDL_INHERITACTORPITCH) pitch -= spr->actor->Angles.Pitch.Degrees;
|
||||
if(smf->flags & MDL_INHERITACTORROLL) roll += spr->actor->Angles.Roll.Degrees;
|
||||
// Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing.
|
||||
// If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the momentum vector pitch.
|
||||
if (smf->flags & MDL_USEACTORPITCH)
|
||||
{
|
||||
double d = spr->actor->Angles.Pitch.Degrees;
|
||||
if (smf->flags & MDL_BADROTATION) pitch -= d;
|
||||
else pitch += d;
|
||||
}
|
||||
if(smf->flags & MDL_USEACTORROLL) roll += spr->actor->Angles.Roll.Degrees;
|
||||
|
||||
gl_RenderState.mModelMatrix.loadIdentity();
|
||||
|
||||
|
|
|
@ -16,9 +16,12 @@ enum { VX, VZ, VY };
|
|||
#define DMD_MAGIC 0x4D444D44
|
||||
#define MD3_MAGIC 0x33504449
|
||||
#define NUMVERTEXNORMALS 162
|
||||
#define MD3_MAX_SURFACES 32
|
||||
|
||||
FTextureID LoadSkin(const char * path, const char * fn);
|
||||
|
||||
// [JM] Necessary forward declaration
|
||||
typedef struct FSpriteModelFrame FSpriteModelFrame;
|
||||
|
||||
class FModel
|
||||
{
|
||||
|
@ -42,6 +45,10 @@ public:
|
|||
}
|
||||
virtual float getAspectFactor() { return 1.f; }
|
||||
|
||||
const FSpriteModelFrame *curSpriteMDLFrame;
|
||||
int curMDLIndex;
|
||||
void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; };
|
||||
|
||||
FModelVertexBuffer *mVBuf;
|
||||
FString mFileName;
|
||||
};
|
||||
|
@ -338,14 +345,16 @@ enum
|
|||
MDL_ROTATING = 4,
|
||||
MDL_INTERPOLATEDOUBLEDFRAMES = 8,
|
||||
MDL_NOINTERPOLATION = 16,
|
||||
MDL_INHERITACTORPITCH = 32,
|
||||
MDL_INHERITACTORROLL = 64, // useless for now
|
||||
MDL_USEACTORPITCH = 32,
|
||||
MDL_USEACTORROLL = 64,
|
||||
MDL_BADROTATION = 128,
|
||||
};
|
||||
|
||||
struct FSpriteModelFrame
|
||||
{
|
||||
int modelIDs[MAX_MODELS_PER_FRAME];
|
||||
FTextureID skinIDs[MAX_MODELS_PER_FRAME];
|
||||
FTextureID surfaceskinIDs[MAX_MODELS_PER_FRAME][MD3_MAX_SURFACES];
|
||||
int modelframes[MAX_MODELS_PER_FRAME];
|
||||
float xscale, yscale, zscale;
|
||||
// [BB] Added zoffset, rotation parameters and flags.
|
||||
|
|
|
@ -319,6 +319,11 @@ void FMD3Model::AddSkins(BYTE *hitlist)
|
|||
{
|
||||
for (int i = 0; i < numSurfaces; i++)
|
||||
{
|
||||
if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid())
|
||||
{
|
||||
hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTexture::TEX_Flat;
|
||||
}
|
||||
|
||||
MD3Surface * surf = &surfaces[i];
|
||||
for (int j = 0; j < surf->numSkins; j++)
|
||||
{
|
||||
|
@ -365,8 +370,15 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i
|
|||
FTexture *surfaceSkin = skin;
|
||||
if (!surfaceSkin)
|
||||
{
|
||||
if (surf->numSkins==0 || !surf->skins[0].isValid()) return;
|
||||
surfaceSkin = TexMan(surf->skins[0]);
|
||||
if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid())
|
||||
{
|
||||
surfaceSkin = TexMan(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i]);
|
||||
}
|
||||
else if(surf->numSkins > 0 && surf->skins[0].isValid())
|
||||
{
|
||||
surfaceSkin = TexMan(surf->skins[0]);
|
||||
}
|
||||
|
||||
if (!surfaceSkin) return;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ struct GLLinePortal : public GLPortal
|
|||
|
||||
GLLinePortal(FGLLinePortal *line)
|
||||
{
|
||||
if (line->lines[0]->mType != PORTT_LINKED)
|
||||
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
|
||||
{
|
||||
// For non-linked portals we must check the actual linedef.
|
||||
line_t *lline = line->lines[0]->mDestination;
|
||||
|
|
|
@ -1113,6 +1113,7 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhit
|
|||
}
|
||||
else if (smf->modelIDs[i] != -1)
|
||||
{
|
||||
Models[smf->modelIDs[i]]->PushSpriteMDLFrame(smf, i);
|
||||
Models[smf->modelIDs[i]]->AddSkins(texhitlist);
|
||||
}
|
||||
if (smf->modelIDs[i] != -1)
|
||||
|
|
|
@ -285,6 +285,7 @@ void GLSprite::Draw(int pass)
|
|||
// [Nash] is a flat sprite
|
||||
const bool isFlatSprite = (actor != NULL) && (spritetype == RF_WALLSPRITE || spritetype == RF_FLATSPRITE);
|
||||
const bool dontFlip = (actor != nullptr) && (actor->renderflags & RF_DONTFLIP);
|
||||
const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER);
|
||||
|
||||
// [Nash] check for special sprite drawing modes
|
||||
if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || isFlatSprite)
|
||||
|
@ -293,13 +294,15 @@ void GLSprite::Draw(int pass)
|
|||
float xcenter = (x1 + x2)*0.5;
|
||||
float ycenter = (y1 + y2)*0.5;
|
||||
float zcenter = (z1 + z2)*0.5;
|
||||
|
||||
float xx = -xcenter + x;
|
||||
float yy = -zcenter + z;
|
||||
float zz = -ycenter + y;
|
||||
Matrix3x4 mat;
|
||||
mat.MakeIdentity();
|
||||
mat.Translate(xcenter, zcenter, ycenter); // move to sprite center
|
||||
|
||||
// Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down).
|
||||
if (drawBillboardFacingCamera)
|
||||
if (drawBillboardFacingCamera && !isFlatSprite)
|
||||
{
|
||||
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
||||
// which is nicer in VR
|
||||
|
@ -337,13 +340,16 @@ void GLSprite::Draw(int pass)
|
|||
DAngle angto = diff.Angle();
|
||||
angto = deltaangle(actor->Angles.Yaw, angto);
|
||||
|
||||
float pitchDegrees = actor->Angles.Pitch.Degrees;
|
||||
float pitchDegrees = -actor->Angles.Pitch.Degrees;
|
||||
bool noFlipSprite = (!dontFlip || (fabs(angto) < 90.));
|
||||
mat.Rotate(0, 1, 0, (noFlipSprite) ? 0 : 180);
|
||||
|
||||
mat.Rotate(-yawvecY, 0, yawvecX, (noFlipSprite) ? -pitchDegrees : pitchDegrees);
|
||||
if (drawRollSpriteActor)
|
||||
{
|
||||
if (useOffsets) mat.Translate(xx, yy, zz);
|
||||
mat.Rotate(yawvecX, 0, yawvecY, (noFlipSprite) ? -rollDegrees : rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -yy, -zz);
|
||||
}
|
||||
}
|
||||
// [fgsfds] Rotate the sprite about the sight vector (roll)
|
||||
|
@ -351,15 +357,21 @@ void GLSprite::Draw(int pass)
|
|||
{
|
||||
mat.Rotate(0, 1, 0, 0);
|
||||
if (drawRollSpriteActor)
|
||||
{
|
||||
if (useOffsets) mat.Translate(xx, yy, zz);
|
||||
mat.Rotate(yawvecX, 0, yawvecY, rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -yy, -zz);
|
||||
}
|
||||
}
|
||||
else if (drawRollSpriteActor)
|
||||
{
|
||||
if (useOffsets) mat.Translate(xx, yy, zz);
|
||||
if (drawWithXYBillboard)
|
||||
{
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees);
|
||||
}
|
||||
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
|
||||
if (useOffsets) mat.Translate(-xx, -yy, -zz);
|
||||
}
|
||||
|
||||
// apply the transform
|
||||
|
@ -370,6 +382,7 @@ void GLSprite::Draw(int pass)
|
|||
// in the x/y plane.
|
||||
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees);
|
||||
}
|
||||
|
||||
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
|
||||
v1 = mat * FVector3(x1, z1, y1);
|
||||
v2 = mat * FVector3(x2, z1, y2);
|
||||
|
|
|
@ -380,9 +380,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
|
|||
// now draw the different layers of the weapon
|
||||
gl_RenderState.EnableBrightmap(true);
|
||||
gl_RenderState.SetObjectColor(ThingColor);
|
||||
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
||||
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
||||
|
||||
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
|
||||
// light mode here to draw the weapon sprite.
|
||||
|
|
|
@ -5712,8 +5712,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
argCount > 11 ? ACSToDouble(args[11]) : 1.0,
|
||||
argCount > 12 ? args[12] : 0,
|
||||
argCount > 13 ? args[13] : 0,
|
||||
argCount > 14 ? args[14] : 0,
|
||||
argCount > 15 ? args[15] : 0);
|
||||
argCount > 14 ? ACSToDouble(args[14]) : 0,
|
||||
argCount > 15 ? ACSToDouble(args[15]) : 0);
|
||||
}
|
||||
|
||||
case ACSF_SetLineActivation:
|
||||
|
|
|
@ -326,7 +326,8 @@ enum // P_LineAttack flags
|
|||
{
|
||||
LAF_ISMELEEATTACK = 1,
|
||||
LAF_NORANDOMPUFFZ = 2,
|
||||
LAF_NOIMPACTDECAL = 4
|
||||
LAF_NOIMPACTDECAL = 4,
|
||||
LAF_NOINTERACT = 8,
|
||||
};
|
||||
|
||||
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
|
||||
|
|
|
@ -4097,6 +4097,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata)
|
|||
AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
||||
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage)
|
||||
{
|
||||
bool nointeract = !!(flags & LAF_NOINTERACT);
|
||||
DVector3 direction;
|
||||
double shootz;
|
||||
FTraceResults trace;
|
||||
|
@ -4186,26 +4187,32 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
}
|
||||
|
||||
int tflags;
|
||||
if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) tflags = TRACE_NoSky;
|
||||
if (nointeract || (puffDefaults && puffDefaults->flags6 & MF6_NOTRIGGER)) tflags = TRACE_NoSky;
|
||||
else tflags = TRACE_NoSky | TRACE_Impact;
|
||||
|
||||
if (!Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance, MF_SHOOTABLE,
|
||||
ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN, t1, trace, tflags, CheckForActor, &TData))
|
||||
{ // hit nothing
|
||||
if (puffDefaults == NULL)
|
||||
{
|
||||
}
|
||||
else if (puffDefaults->ActiveSound)
|
||||
if (!nointeract && puffDefaults && puffDefaults->ActiveSound)
|
||||
{ // Play miss sound
|
||||
S_Sound(t1, CHAN_WEAPON, puffDefaults->ActiveSound, 1, ATTN_NORM);
|
||||
}
|
||||
if (puffDefaults != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
|
||||
|
||||
// [MC] LAF_NOINTERACT guarantees puff spawning and returns it directly to the calling function.
|
||||
// No damage caused, no sounds played, no blood splatters.
|
||||
|
||||
if (nointeract || (puffDefaults && puffDefaults->flags3 & MF3_ALWAYSPUFF))
|
||||
{ // Spawn the puff anyway
|
||||
puff = P_SpawnPuff(t1, pufftype, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget, 2, puffFlags);
|
||||
|
||||
if (nointeract)
|
||||
{
|
||||
return puff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4213,12 +4220,17 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
if (trace.HitType != TRACE_HitActor)
|
||||
{
|
||||
// position a bit closer for puffs
|
||||
if (trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
|
||||
if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
|
||||
{
|
||||
DVector2 pos = P_GetOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4);
|
||||
puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget,
|
||||
trace.SrcAngleFromTarget - 90, 0, puffFlags);
|
||||
puff->radius = 1/65536.;
|
||||
|
||||
if (nointeract)
|
||||
{
|
||||
return puff;
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Spawn a decal
|
||||
|
@ -4256,14 +4268,6 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
}
|
||||
else
|
||||
{
|
||||
bool bloodsplatter = (t1->flags5 & MF5_BLOODSPLATTER) ||
|
||||
(t1->player != NULL && t1->player->ReadyWeapon != NULL &&
|
||||
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
|
||||
|
||||
bool axeBlood = (t1->player != NULL &&
|
||||
t1->player->ReadyWeapon != NULL &&
|
||||
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
|
||||
|
||||
// Hit a thing, so it could be either a puff or blood
|
||||
DVector3 bleedpos = trace.HitPos;
|
||||
// position a bit closer for puffs/blood if using compatibility mode.
|
||||
|
@ -4276,7 +4280,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
}
|
||||
|
||||
// Spawn bullet puffs or blood spots, depending on target type.
|
||||
if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) ||
|
||||
if (nointeract || (puffDefaults && puffDefaults->flags3 & MF3_PUFFONACTORS) ||
|
||||
(trace.Actor->flags & MF_NOBLOOD) ||
|
||||
(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)))
|
||||
{
|
||||
|
@ -4285,6 +4289,11 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
|
||||
// We must pass the unreplaced puff type here
|
||||
puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 2, puffFlags | PF_HITTHING, trace.Actor);
|
||||
|
||||
if (nointeract)
|
||||
{
|
||||
return puff;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow puffs to inflict poison damage, so that hitscans can poison, too.
|
||||
|
@ -4321,6 +4330,14 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
|
|||
}
|
||||
if (!(puffDefaults != NULL && puffDefaults->flags3&MF3_BLOODLESSIMPACT))
|
||||
{
|
||||
bool bloodsplatter = (t1->flags5 & MF5_BLOODSPLATTER) ||
|
||||
(t1->player != nullptr && t1->player->ReadyWeapon != nullptr &&
|
||||
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
|
||||
|
||||
bool axeBlood = (t1->player != nullptr &&
|
||||
t1->player->ReadyWeapon != nullptr &&
|
||||
(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
|
||||
|
||||
if (!bloodsplatter && !axeBlood &&
|
||||
!(trace.Actor->flags & MF_NOBLOOD) &&
|
||||
!(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)))
|
||||
|
|
|
@ -216,15 +216,29 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
|
|||
}
|
||||
|
||||
// Always update the caller here in case we switched weapon
|
||||
// or if the layer was being used by an inventory item before.
|
||||
// or if the layer was being used by something else before.
|
||||
pspr->Caller = newcaller;
|
||||
|
||||
if (newcaller != oldcaller)
|
||||
{ // Only change the flags if this layer was created now or if we updated the caller.
|
||||
{ // Only reset stuff if this layer was created now or if it was being used before.
|
||||
if (layer >= PSP_TARGETCENTER)
|
||||
{ // The targeter layers were affected by those.
|
||||
pspr->Flags |= (PSPF_CVARFAST|PSPF_POWDOUBLE);
|
||||
pspr->Flags = (PSPF_CVARFAST|PSPF_POWDOUBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE);
|
||||
}
|
||||
if (layer == PSP_STRIFEHANDS)
|
||||
{
|
||||
// Some of the old hacks rely on this layer coming from the FireHands state.
|
||||
// This is the ONLY time a psprite's state is actually null.
|
||||
pspr->State = nullptr;
|
||||
pspr->y = WEAPONTOP;
|
||||
}
|
||||
|
||||
pspr->oldx = pspr->x;
|
||||
pspr->oldy = pspr->y;
|
||||
}
|
||||
|
||||
return pspr;
|
||||
|
|
|
@ -43,7 +43,7 @@ class FArchive;
|
|||
// drawn directly on the view screen,
|
||||
// coordinates are given for a 320*200 view screen.
|
||||
//
|
||||
enum PSPLayers // These are all called by the owner's ReadyWeapon.
|
||||
enum PSPLayers
|
||||
{
|
||||
PSP_STRIFEHANDS = -1,
|
||||
PSP_WEAPON = 1,
|
||||
|
@ -78,6 +78,7 @@ public:
|
|||
FState* GetState() const { return State; }
|
||||
DPSprite* GetNext() { return Next; }
|
||||
AActor* GetCaller() { return Caller; }
|
||||
void SetCaller(AActor *newcaller) { Caller = newcaller; }
|
||||
|
||||
double x, y;
|
||||
double oldx, oldy;
|
||||
|
|
|
@ -329,13 +329,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
|
|||
// NON-ACTION function to get the angle in degrees (normalized to -180..180)
|
||||
//
|
||||
//==========================================================================
|
||||
enum GAFlags
|
||||
{
|
||||
GAF_RELATIVE = 1,
|
||||
GAF_SWITCH = 1 << 1,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle)
|
||||
{
|
||||
if (numret > 0)
|
||||
{
|
||||
assert(ret != NULL);
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_BOOL(relative);
|
||||
PARAM_INT(flags);
|
||||
PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; }
|
||||
|
||||
AActor *target = COPY_AAPTR(self, ptr);
|
||||
|
@ -346,9 +352,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle)
|
|||
}
|
||||
else
|
||||
{
|
||||
DVector3 diff = self->Vec3To(target);
|
||||
DVector3 diff = (flags & GAF_SWITCH) ? target->Vec3To(self) : self->Vec3To(target);
|
||||
DAngle angto = diff.Angle();
|
||||
if (relative) angto = deltaangle(self->Angles.Yaw, angto);
|
||||
DAngle yaw = (flags & GAF_SWITCH) ? target->Angles.Yaw : self->Angles.Yaw;
|
||||
if (flags & GAF_RELATIVE) angto = deltaangle(yaw, angto);
|
||||
ret->SetFloat(angto.Degrees);
|
||||
}
|
||||
return 1;
|
||||
|
@ -1615,8 +1622,13 @@ enum CBA_Flags
|
|||
CBAF_EXPLICITANGLE = 4,
|
||||
CBAF_NOPITCH = 8,
|
||||
CBAF_NORANDOMPUFFZ = 16,
|
||||
CBAF_PUFFTARGET = 32,
|
||||
CBAF_PUFFMASTER = 64,
|
||||
CBAF_PUFFTRACER = 128,
|
||||
};
|
||||
|
||||
static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba);
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
@ -1628,6 +1640,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
|||
PARAM_FLOAT_OPT (range) { range = 0; }
|
||||
PARAM_INT_OPT (flags) { flags = 0; }
|
||||
PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; }
|
||||
PARAM_CLASS_OPT (missile, AActor) { missile = nullptr; }
|
||||
PARAM_FLOAT_OPT (Spawnheight) { Spawnheight = 32; }
|
||||
PARAM_FLOAT_OPT (Spawnofs_xy) { Spawnofs_xy = 0; }
|
||||
|
||||
AActor *ref = COPY_AAPTR(self, ptr);
|
||||
|
||||
|
@ -1672,7 +1687,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
|
|||
if (!(flags & CBAF_NORANDOM))
|
||||
damage *= ((pr_cabullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
if (missile != nullptr && pufftype != nullptr)
|
||||
{
|
||||
double x = Spawnofs_xy * angle.Cos();
|
||||
double y = Spawnofs_xy * angle.Sin();
|
||||
|
||||
DVector3 pos = self->Pos();
|
||||
self->SetXYZ(self->Vec3Offset(x, y, 0.));
|
||||
AActor *proj = P_SpawnMissileAngleZSpeed(self, self->Z() + self->GetBobOffset() + Spawnheight, missile, self->Angles.Yaw, 0, GetDefaultByType(missile)->Speed, self, false);
|
||||
self->SetXYZ(pos);
|
||||
|
||||
if (proj)
|
||||
{
|
||||
bool temp = (puff == nullptr);
|
||||
if (!puff)
|
||||
{
|
||||
puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
|
||||
}
|
||||
if (puff)
|
||||
{
|
||||
AimBulletMissile(proj, puff, flags, temp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -1801,8 +1839,46 @@ enum FB_Flags
|
|||
FBF_NOPITCH = 8,
|
||||
FBF_NOFLASH = 16,
|
||||
FBF_NORANDOMPUFFZ = 32,
|
||||
FBF_PUFFTARGET = 64,
|
||||
FBF_PUFFMASTER = 128,
|
||||
FBF_PUFFTRACER = 256,
|
||||
};
|
||||
|
||||
static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba)
|
||||
{
|
||||
if (proj && puff)
|
||||
{
|
||||
if (proj)
|
||||
{
|
||||
// FAF_BOTTOM = 1
|
||||
// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
|
||||
|
||||
A_Face(proj, puff, 0., 0., 0., 0., 1);
|
||||
proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
|
||||
|
||||
if (!temp)
|
||||
{
|
||||
if (cba)
|
||||
{
|
||||
if (flags & CBAF_PUFFTARGET) proj->target = puff;
|
||||
if (flags & CBAF_PUFFMASTER) proj->master = puff;
|
||||
if (flags & CBAF_PUFFTRACER) proj->tracer = puff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & FBF_PUFFTARGET) proj->target = puff;
|
||||
if (flags & FBF_PUFFMASTER) proj->master = puff;
|
||||
if (flags & FBF_PUFFTRACER) proj->tracer = puff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (puff && temp)
|
||||
{
|
||||
puff->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE;
|
||||
|
@ -1810,9 +1886,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
PARAM_ANGLE (spread_z);
|
||||
PARAM_INT (numbullets);
|
||||
PARAM_INT (damageperbullet);
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
|
||||
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = nullptr; }
|
||||
PARAM_INT_OPT (flags) { flags = FBF_USEAMMO; }
|
||||
PARAM_FLOAT_OPT (range) { range = 0; }
|
||||
PARAM_CLASS_OPT (missile, AActor) { missile = nullptr; }
|
||||
PARAM_FLOAT_OPT (Spawnheight) { Spawnheight = 0; }
|
||||
PARAM_FLOAT_OPT (Spawnofs_xy) { Spawnofs_xy = 0; }
|
||||
|
||||
if (!self->player) return 0;
|
||||
|
||||
|
@ -1851,7 +1930,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
if (!(flags & FBF_NORANDOM))
|
||||
damage *= ((pr_cwbullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
|
||||
if (missile != nullptr)
|
||||
{
|
||||
bool temp = false;
|
||||
DAngle ang = self->Angles.Yaw - 90;
|
||||
DVector2 ofs = ang.ToVector(Spawnofs_xy);
|
||||
AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, bangle, nullptr, nullptr, false, true);
|
||||
if (proj)
|
||||
{
|
||||
if (!puff)
|
||||
{
|
||||
temp = true;
|
||||
puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
|
||||
}
|
||||
AimBulletMissile(proj, puff, flags, temp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1878,7 +1974,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
|
|||
if (!(flags & FBF_NORANDOM))
|
||||
damage *= ((pr_cwbullet()%3)+1);
|
||||
|
||||
P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
|
||||
|
||||
if (missile != nullptr)
|
||||
{
|
||||
bool temp = false;
|
||||
DAngle ang = self->Angles.Yaw - 90;
|
||||
DVector2 ofs = ang.ToVector(Spawnofs_xy);
|
||||
AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
|
||||
if (proj)
|
||||
{
|
||||
if (!puff)
|
||||
{
|
||||
temp = true;
|
||||
puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
|
||||
}
|
||||
AimBulletMissile(proj, puff, flags, temp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -5669,7 +5782,9 @@ enum RadiusGiveFlags
|
|||
RGF_MONSTERS |
|
||||
RGF_OBJECTS |
|
||||
RGF_VOODOO |
|
||||
RGF_CORPSES | RGF_MISSILES,
|
||||
RGF_CORPSES |
|
||||
RGF_MISSILES |
|
||||
RGF_ITEMS,
|
||||
};
|
||||
|
||||
static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amount, double distance, int flags, PClassActor *filter, FName species, double mindist)
|
||||
|
|
|
@ -270,6 +270,7 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
|
||||
DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags),
|
||||
|
||||
// Bounce flags
|
||||
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
|
||||
|
|
|
@ -331,11 +331,11 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
|
|||
}
|
||||
else if (sc.CheckToken(TK_True))
|
||||
{
|
||||
return new FxConstant(1, scpos);
|
||||
return new FxConstant(true, scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_False))
|
||||
{
|
||||
return new FxConstant(0, scpos);
|
||||
return new FxConstant(false, scpos);
|
||||
}
|
||||
else if (sc.CheckToken(TK_IntConst))
|
||||
{
|
||||
|
|
|
@ -203,7 +203,6 @@ protected:
|
|||
public:
|
||||
virtual ~FxExpression() {}
|
||||
virtual FxExpression *Resolve(FCompileContext &ctx);
|
||||
FxExpression *ResolveAsBoolean(FCompileContext &ctx);
|
||||
|
||||
virtual bool isConstant() const;
|
||||
virtual void RequestAddress();
|
||||
|
@ -280,6 +279,13 @@ class FxConstant : public FxExpression
|
|||
ExpVal value;
|
||||
|
||||
public:
|
||||
FxConstant(bool val, const FScriptPosition &pos) : FxExpression(pos)
|
||||
{
|
||||
ValueType = value.Type = TypeBool;
|
||||
value.Int = val;
|
||||
isresolved = true;
|
||||
}
|
||||
|
||||
FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos)
|
||||
{
|
||||
ValueType = value.Type = TypeSInt32;
|
||||
|
@ -358,6 +364,19 @@ public:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxBoolCast : public FxExpression
|
||||
{
|
||||
FxExpression *basex;
|
||||
|
||||
public:
|
||||
|
||||
FxBoolCast(FxExpression *x);
|
||||
~FxBoolCast();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
class FxIntCast : public FxExpression
|
||||
{
|
||||
FxExpression *basex;
|
||||
|
@ -384,18 +403,6 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
class FxCastStateToBool : public FxExpression
|
||||
{
|
||||
FxExpression *basex;
|
||||
|
||||
public:
|
||||
FxCastStateToBool(FxExpression *x);
|
||||
~FxCastStateToBool();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxSign
|
||||
|
|
|
@ -177,38 +177,6 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx)
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
|
||||
{
|
||||
///FIXME: Use an actual boolean type
|
||||
FxExpression *x = Resolve(ctx);
|
||||
if (x != NULL)
|
||||
{
|
||||
if (x->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
x->ValueType = TypeSInt32;
|
||||
}
|
||||
else if (x->ValueType == TypeState)
|
||||
{
|
||||
x = new FxCastStateToBool(x);
|
||||
x = x->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Not an integral type");
|
||||
delete this;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -327,6 +295,104 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxBoolCast::FxBoolCast(FxExpression *x)
|
||||
: FxExpression(x->ScriptPosition)
|
||||
{
|
||||
basex = x;
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxBoolCast::~FxBoolCast()
|
||||
{
|
||||
SAFE_DELETE(basex);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxBoolCast::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(basex, ctx);
|
||||
|
||||
if (basex->ValueType == TypeBool)
|
||||
{
|
||||
FxExpression *x = basex;
|
||||
basex = nullptr;
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
else if (basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER)
|
||||
{
|
||||
if (basex->isConstant())
|
||||
{
|
||||
assert(basex->ValueType != TypeState && "We shouldn't be able to generate a constant state ref");
|
||||
|
||||
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
|
||||
FxExpression *x = new FxConstant(constval.GetBool(), ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit from = basex->Emit(build);
|
||||
assert(!from.Konst);
|
||||
assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER);
|
||||
ExpEmit to(build, REGT_INT);
|
||||
from.Free(build);
|
||||
|
||||
// Preload result with 0.
|
||||
build->Emit(OP_LI, to.RegNum, 0);
|
||||
|
||||
// Check source against 0.
|
||||
if (from.RegType == REGT_INT)
|
||||
{
|
||||
build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
|
||||
}
|
||||
else if (from.RegType == REGT_FLOAT)
|
||||
{
|
||||
build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
|
||||
}
|
||||
else if (from.RegNum == REGT_POINTER)
|
||||
{
|
||||
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
|
||||
}
|
||||
build->Emit(OP_JMP, 1);
|
||||
|
||||
// Reload result with 1 if the comparison fell through.
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxIntCast::FxIntCast(FxExpression *x)
|
||||
: FxExpression(x->ScriptPosition)
|
||||
{
|
||||
|
@ -504,67 +570,6 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxCastStateToBool::FxCastStateToBool(FxExpression *x)
|
||||
: FxExpression(x->ScriptPosition)
|
||||
{
|
||||
basex = x;
|
||||
ValueType = TypeSInt32;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxCastStateToBool::~FxCastStateToBool()
|
||||
{
|
||||
SAFE_DELETE(basex);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE(basex, ctx);
|
||||
|
||||
assert(basex->ValueType == TypeState);
|
||||
assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref");
|
||||
return this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxCastStateToBool::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit from = basex->Emit(build);
|
||||
assert(from.RegType == REGT_POINTER);
|
||||
from.Free(build);
|
||||
ExpEmit to(build, REGT_INT);
|
||||
|
||||
// If from is NULL, produce 0. Otherwise, produce 1.
|
||||
build->Emit(OP_LI, to.RegNum, 0);
|
||||
build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FxPlusSign::FxPlusSign(FxExpression *operand)
|
||||
: FxExpression(operand->ScriptPosition)
|
||||
{
|
||||
|
@ -765,10 +770,9 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
assert(ValueType == Operand->ValueType);
|
||||
assert(ValueType == TypeSInt32);
|
||||
assert(Operand->ValueType->GetRegType() == REGT_INT);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
assert(from.Konst == 0);
|
||||
assert(!from.Konst);
|
||||
// Do it in-place.
|
||||
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
|
||||
return from;
|
||||
|
@ -806,33 +810,23 @@ FxUnaryNotBoolean::~FxUnaryNotBoolean()
|
|||
FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
if (Operand)
|
||||
SAFE_RESOLVE(Operand, ctx);
|
||||
|
||||
if (Operand->ValueType != TypeBool)
|
||||
{
|
||||
Operand = Operand->ResolveAsBoolean(ctx);
|
||||
}
|
||||
if (!Operand)
|
||||
{
|
||||
delete this;
|
||||
return NULL;
|
||||
Operand = new FxBoolCast(Operand);
|
||||
SAFE_RESOLVE(Operand, ctx);
|
||||
}
|
||||
|
||||
if (Operand->IsNumeric() || Operand->IsPointer())
|
||||
if (Operand->isConstant())
|
||||
{
|
||||
if (Operand->isConstant())
|
||||
{
|
||||
bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
|
||||
FxExpression *e = new FxConstant(result, ScriptPosition);
|
||||
delete this;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
||||
bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
|
||||
FxExpression *e = new FxConstant(result, ScriptPosition);
|
||||
delete this;
|
||||
return NULL;
|
||||
return e;
|
||||
}
|
||||
ValueType = TypeSInt32;
|
||||
|
||||
ValueType = TypeBool;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -844,32 +838,14 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
assert(Operand->ValueType == ValueType);
|
||||
assert(ValueType == TypeBool);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
assert(!from.Konst);
|
||||
ExpEmit to(build, REGT_INT);
|
||||
from.Free(build);
|
||||
|
||||
// Preload result with 0.
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
|
||||
// Check source against 0.
|
||||
if (from.RegType == REGT_INT)
|
||||
{
|
||||
build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum);
|
||||
}
|
||||
else if (from.RegType == REGT_FLOAT)
|
||||
{
|
||||
build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0));
|
||||
}
|
||||
else if (from.RegNum == REGT_POINTER)
|
||||
{
|
||||
build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
|
||||
}
|
||||
build->Emit(OP_JMP, 1);
|
||||
|
||||
// Reload result with 1 if the comparison fell through.
|
||||
build->Emit(OP_LI, to.RegNum, 1);
|
||||
return to;
|
||||
// ~x & 1
|
||||
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
|
||||
build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
|
||||
return from;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -914,6 +890,10 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (left->ValueType == TypeBool && right->ValueType == TypeBool)
|
||||
{
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
ValueType = TypeSInt32;
|
||||
|
@ -1276,7 +1256,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
|
|||
return e;
|
||||
}
|
||||
Promote(ctx);
|
||||
ValueType = TypeSInt32;
|
||||
ValueType = TypeBool;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1327,7 +1307,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
|||
op1.Free(build);
|
||||
}
|
||||
|
||||
// See FxUnaryNotBoolean for comments, since it's the same thing.
|
||||
// See FxBoolCast for comments, since it's the same thing.
|
||||
build->Emit(OP_LI, to.RegNum, 0, 0);
|
||||
build->Emit(instr, check, op1.RegNum, op2.RegNum);
|
||||
build->Emit(OP_JMP, 1);
|
||||
|
@ -1392,7 +1372,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
|||
return e;
|
||||
}
|
||||
Promote(ctx);
|
||||
ValueType = TypeSInt32;
|
||||
ValueType = TypeBool;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1600,7 +1580,7 @@ FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
|
|||
Operator=o;
|
||||
left=l;
|
||||
right=r;
|
||||
ValueType = TypeSInt32;
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1624,16 +1604,22 @@ FxBinaryLogical::~FxBinaryLogical()
|
|||
FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
if (left) left = left->ResolveAsBoolean(ctx);
|
||||
if (right) right = right->ResolveAsBoolean(ctx);
|
||||
if (!left || !right)
|
||||
RESOLVE(left, ctx);
|
||||
RESOLVE(right, ctx);
|
||||
ABORT(right && left);
|
||||
|
||||
if (left->ValueType != TypeBool)
|
||||
{
|
||||
delete this;
|
||||
return NULL;
|
||||
left = new FxBoolCast(left);
|
||||
SAFE_RESOLVE(left, ctx);
|
||||
}
|
||||
if (right->ValueType != TypeBool)
|
||||
{
|
||||
right = new FxBoolCast(right);
|
||||
SAFE_RESOLVE(right, ctx);
|
||||
}
|
||||
|
||||
int b_left=-1, b_right=-1;
|
||||
|
||||
if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool();
|
||||
if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool();
|
||||
|
||||
|
@ -1643,13 +1629,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (b_left==0 || b_right==0)
|
||||
{
|
||||
FxExpression *x = new FxConstant(0, ScriptPosition);
|
||||
FxExpression *x = new FxConstant(true, ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
else if (b_left==1 && b_right==1)
|
||||
{
|
||||
FxExpression *x = new FxConstant(1, ScriptPosition);
|
||||
FxExpression *x = new FxConstant(false, ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
|
@ -1672,13 +1658,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
|
|||
{
|
||||
if (b_left==1 || b_right==1)
|
||||
{
|
||||
FxExpression *x = new FxConstant(1, ScriptPosition);
|
||||
FxExpression *x = new FxConstant(true, ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
if (b_left==0 && b_right==0)
|
||||
{
|
||||
FxExpression *x = new FxConstant(0, ScriptPosition);
|
||||
FxExpression *x = new FxConstant(false, ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
|
@ -1697,14 +1683,6 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
|
|||
return x;
|
||||
}
|
||||
}
|
||||
if (left->ValueType->GetRegType() != REGT_INT)
|
||||
{
|
||||
left = new FxIntCast(left);
|
||||
}
|
||||
if (right->ValueType->GetRegType() != REGT_INT)
|
||||
{
|
||||
right = new FxIntCast(right);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1804,17 +1782,25 @@ FxConditional::~FxConditional()
|
|||
FxExpression *FxConditional::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
if (condition) condition = condition->ResolveAsBoolean(ctx);
|
||||
RESOLVE(condition, ctx);
|
||||
RESOLVE(truex, ctx);
|
||||
RESOLVE(falsex, ctx);
|
||||
ABORT(condition && truex && falsex);
|
||||
|
||||
if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
|
||||
if (truex->ValueType == TypeBool && falsex->ValueType == TypeBool)
|
||||
ValueType = TypeBool;
|
||||
else if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
|
||||
ValueType = TypeSInt32;
|
||||
else if (truex->IsNumeric() && falsex->IsNumeric())
|
||||
ValueType = TypeFloat64;
|
||||
//else if (truex->ValueType != falsex->ValueType)
|
||||
|
||||
if (condition->ValueType != TypeBool)
|
||||
{
|
||||
condition = new FxBoolCast(condition);
|
||||
SAFE_RESOLVE(condition, ctx);
|
||||
}
|
||||
|
||||
if (condition->isConstant())
|
||||
{
|
||||
ExpVal condval = static_cast<FxConstant *>(condition)->GetValue();
|
||||
|
@ -1852,6 +1838,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
size_t truejump, falsejump;
|
||||
ExpEmit out;
|
||||
|
||||
// The true and false expressions ought to be assigned to the
|
||||
|
@ -1862,7 +1849,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
|||
|
||||
// Test condition.
|
||||
build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0));
|
||||
size_t patchspot = build->Emit(OP_JMP, 0);
|
||||
falsejump = build->Emit(OP_JMP, 0);
|
||||
|
||||
// Evaluate true expression.
|
||||
if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT)
|
||||
|
@ -1886,9 +1873,11 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
|||
out = trueop;
|
||||
}
|
||||
}
|
||||
// Make sure to skip the false path.
|
||||
truejump = build->Emit(OP_JMP, 0);
|
||||
|
||||
// Evaluate false expression.
|
||||
build->BackpatchToHere(patchspot);
|
||||
build->BackpatchToHere(falsejump);
|
||||
if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt());
|
||||
|
@ -1918,6 +1907,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
|||
}
|
||||
}
|
||||
}
|
||||
build->BackpatchToHere(truejump);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
@ -3735,23 +3725,32 @@ FxIfStatement::~FxIfStatement()
|
|||
FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
if (WhenTrue == NULL && WhenFalse == NULL)
|
||||
|
||||
if (WhenTrue == nullptr && WhenFalse == nullptr)
|
||||
{ // We don't do anything either way, so disappear
|
||||
delete this;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
Condition = Condition->ResolveAsBoolean(ctx);
|
||||
ABORT(Condition);
|
||||
if (WhenTrue != NULL)
|
||||
|
||||
SAFE_RESOLVE(Condition, ctx);
|
||||
|
||||
if (Condition->ValueType != TypeBool)
|
||||
{
|
||||
Condition = new FxBoolCast(Condition);
|
||||
SAFE_RESOLVE(Condition, ctx);
|
||||
}
|
||||
|
||||
if (WhenTrue != nullptr)
|
||||
{
|
||||
WhenTrue = WhenTrue->Resolve(ctx);
|
||||
ABORT(WhenTrue);
|
||||
}
|
||||
if (WhenFalse != NULL)
|
||||
if (WhenFalse != nullptr)
|
||||
{
|
||||
WhenFalse = WhenFalse->Resolve(ctx);
|
||||
ABORT(WhenFalse);
|
||||
}
|
||||
|
||||
ValueType = TypeVoid;
|
||||
|
||||
if (Condition->isConstant())
|
||||
|
@ -3766,6 +3765,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
|
|||
delete this;
|
||||
return e;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
|
|||
sc.MustGetString();
|
||||
x = new FxConstant(FSoundID(sc.String), sc);
|
||||
}
|
||||
else if (type == TypeSInt32 || type == TypeFloat64)
|
||||
else if (type == TypeBool || type == TypeSInt32 || type == TypeFloat64)
|
||||
{
|
||||
x = ParseExpression (sc, cls, constant);
|
||||
if (constant && !x->isConstant())
|
||||
|
@ -85,8 +85,12 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
|
|||
sc.ScriptMessage("Default parameter must be constant.");
|
||||
FScriptPosition::ErrorCounter++;
|
||||
}
|
||||
// Do automatic coercion between ints and floats.
|
||||
if (type == TypeSInt32)
|
||||
// Do automatic coercion between bools, ints and floats.
|
||||
if (type == TypeBool)
|
||||
{
|
||||
x = new FxBoolCast(x);
|
||||
}
|
||||
else if (type == TypeSInt32)
|
||||
{
|
||||
x = new FxIntCast(x);
|
||||
}
|
||||
|
@ -306,6 +310,9 @@ static void ParseArgListDef(FScanner &sc, PClassActor *cls,
|
|||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_Bool:
|
||||
type = TypeBool;
|
||||
break;
|
||||
|
||||
case TK_Int:
|
||||
type = TypeSInt32;
|
||||
break;
|
||||
|
@ -477,8 +484,11 @@ static void ParseNativeFunction(FScanner &sc, PClassActor *cls)
|
|||
sc.MustGetAnyToken();
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_Int:
|
||||
case TK_Bool:
|
||||
rets.Push(TypeBool);
|
||||
break;
|
||||
|
||||
case TK_Int:
|
||||
rets.Push(TypeSInt32);
|
||||
break;
|
||||
|
||||
|
@ -1064,7 +1074,11 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
|
|||
// check for a return value
|
||||
do
|
||||
{
|
||||
if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool))
|
||||
if (sc.CheckToken(TK_Bool))
|
||||
{
|
||||
rets.Push(TypeBool);
|
||||
}
|
||||
else if (sc.CheckToken(TK_Int))
|
||||
{
|
||||
rets.Push(TypeSInt32);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ ACTOR Actor native //: Thinker
|
|||
native bool IsPointerEqual(int ptr_select1, int ptr_select2);
|
||||
native int CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
|
||||
native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT);
|
||||
native float GetAngle(bool relative, int ptr = AAPTR_DEFAULT);
|
||||
native float GetAngle(int flags, int ptr = AAPTR_DEFAULT);
|
||||
native float GetZAt(float px = 0, float py = 0, float angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT);
|
||||
native int GetSpawnHealth();
|
||||
native int GetGibHealth();
|
||||
|
@ -189,7 +189,7 @@ ACTOR Actor native //: Thinker
|
|||
native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
|
||||
native state A_Jump(int chance = 256, state label, ...);
|
||||
native void A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET);
|
||||
native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET);
|
||||
native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET, class<Actor> missile = "", float Spawnheight = 32, float Spawnofs_xy = 0);
|
||||
native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
|
||||
native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
|
||||
native state A_JumpIfCloser(float distance, state label, bool noz = false);
|
||||
|
|
|
@ -652,3 +652,9 @@ enum
|
|||
BT_USER3 = 1<<23,
|
||||
BT_USER4 = 1<<24,
|
||||
};
|
||||
// Flags for GetAngle
|
||||
enum
|
||||
{
|
||||
GAF_RELATIVE = 1,
|
||||
GAF_SWITCH = 1 << 1,
|
||||
};
|
|
@ -9,7 +9,7 @@ ACTOR Inventory native
|
|||
|
||||
action native state A_JumpIfNoAmmo(state label);
|
||||
action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = "");
|
||||
action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
|
||||
action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0, class<Actor> missile = "", float Spawnheight = 32, float Spawnofs_xy = 0);
|
||||
action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0);
|
||||
action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
|
||||
action native A_Light(int extralight);
|
||||
|
|
|
@ -1835,6 +1835,7 @@ ALTHUDMNU_SHOWAMMO = "Show ammo for";
|
|||
ALTHUDMNU_SHOWTIME = "Show time";
|
||||
ALTHUDMNU_TIMECOLOR = "Time color";
|
||||
ALTHUDMNU_SHOWLAG = "Show network latency";
|
||||
ALTHUDMNU_AMMOORDER = "Ammo display order";
|
||||
ALTHUDMNU_AMMORED = "Red ammo display below %";
|
||||
ALTHUDMNU_AMMOYELLOW = "Yellow ammo display below %";
|
||||
ALTHUDMNU_HEALTHRED = "Red health display below";
|
||||
|
@ -2210,6 +2211,8 @@ OPTVAL_SYSTEMSECONDS = "System, seconds";
|
|||
OPTVAL_SYSTEM = "System";
|
||||
OPTVAL_NETGAMESONLY = "Netgames only";
|
||||
OPTVAL_ALWAYS = "Always";
|
||||
OPTVAL_AMMOIMAGETEXT = "Image and Text";
|
||||
OPTVAL_AMMOTEXTIMAGE = "Text and Image";
|
||||
OPTVAL_SCRIPTSONLY = "Scripts Only";
|
||||
OPTVAL_NEVER = "Never";
|
||||
OPTVAL_ALL = "All";
|
||||
|
|
|
@ -5,6 +5,7 @@ ClearLocks
|
|||
|
||||
Lock 1 Doom
|
||||
{
|
||||
//$Title "Red key card"
|
||||
RedCard
|
||||
Message "$PD_REDC"
|
||||
RemoteMessage "$PD_REDCO"
|
||||
|
@ -14,6 +15,7 @@ Lock 1 Doom
|
|||
|
||||
Lock 2 Doom
|
||||
{
|
||||
//$Title "Blue key card"
|
||||
BlueCard
|
||||
Message "$PD_BLUEC"
|
||||
RemoteMessage "$PD_BLUECO"
|
||||
|
@ -23,6 +25,7 @@ Lock 2 Doom
|
|||
|
||||
Lock 3 Doom
|
||||
{
|
||||
//$Title "Yellow key card"
|
||||
YellowCard
|
||||
Message "$PD_YELLOWC"
|
||||
RemoteMessage "$PD_YELLOWCO"
|
||||
|
@ -32,6 +35,7 @@ Lock 3 Doom
|
|||
|
||||
Lock 4 Doom
|
||||
{
|
||||
//$Title "Red skull"
|
||||
RedSkull
|
||||
Message "$PD_REDS"
|
||||
RemoteMessage "$PD_REDSO"
|
||||
|
@ -41,6 +45,7 @@ Lock 4 Doom
|
|||
|
||||
Lock 5 Doom
|
||||
{
|
||||
//$Title "Blue skull"
|
||||
BlueSkull
|
||||
Message "$PD_BLUES"
|
||||
RemoteMessage "$PD_BLUESO"
|
||||
|
@ -50,6 +55,7 @@ Lock 5 Doom
|
|||
|
||||
Lock 6 Doom
|
||||
{
|
||||
//$Title "Yellow skull"
|
||||
YellowSkull
|
||||
Message "$PD_YELLOWS"
|
||||
RemoteMessage "$PD_YELLOWSO"
|
||||
|
@ -59,6 +65,7 @@ Lock 6 Doom
|
|||
|
||||
Lock 129 Doom
|
||||
{
|
||||
//$Title "Any red key"
|
||||
Any { RedCard RedSkull KeyGreen }
|
||||
Message "$PD_REDK"
|
||||
RemoteMessage "$PD_REDO"
|
||||
|
@ -68,6 +75,7 @@ Lock 129 Doom
|
|||
|
||||
Lock 130 Doom
|
||||
{
|
||||
//$Title "Any blue key"
|
||||
Any { BlueCard BlueSkull KeyBlue }
|
||||
Message "$PD_BLUEK"
|
||||
RemoteMessage "$PD_BLUEO"
|
||||
|
@ -77,6 +85,7 @@ Lock 130 Doom
|
|||
|
||||
Lock 131 Doom
|
||||
{
|
||||
//$Title "Any yellow key"
|
||||
Any { YellowCard YellowSkull KeyYellow }
|
||||
Message "$PD_YELLOWK"
|
||||
RemoteMessage "$PD_YELLOWO"
|
||||
|
@ -86,6 +95,7 @@ Lock 131 Doom
|
|||
|
||||
Lock 132 Doom
|
||||
{
|
||||
//$Title "Red card or skull"
|
||||
Any { RedCard RedSkull }
|
||||
Message "$PD_REDK"
|
||||
RemoteMessage "$PD_REDO"
|
||||
|
@ -95,6 +105,7 @@ Lock 132 Doom
|
|||
|
||||
Lock 133 Doom
|
||||
{
|
||||
//$Title "Blue card or skull"
|
||||
Any { BlueCard BlueSkull }
|
||||
Message "$PD_BLUEK"
|
||||
RemoteMessage "$PD_BLUEO"
|
||||
|
@ -104,6 +115,7 @@ Lock 133 Doom
|
|||
|
||||
Lock 134 Doom
|
||||
{
|
||||
//$Title "Yellow card or skull"
|
||||
Any { YellowCard YellowSkull }
|
||||
Message "$PD_YELLOWK"
|
||||
RemoteMessage "$PD_YELLOWO"
|
||||
|
@ -112,6 +124,7 @@ Lock 134 Doom
|
|||
|
||||
Lock 100
|
||||
{
|
||||
//$Title "Any key"
|
||||
Message "$PD_ANY"
|
||||
RemoteMessage "$PD_ANYOBJ"
|
||||
Mapcolor 128 128 255
|
||||
|
@ -119,6 +132,7 @@ Lock 100
|
|||
|
||||
Lock 228
|
||||
{
|
||||
//$Title "Any key"
|
||||
Message "$PD_ANY"
|
||||
RemoteMessage "$PD_ANYOBJ"
|
||||
Mapcolor 128 128 255
|
||||
|
@ -126,6 +140,7 @@ Lock 228
|
|||
|
||||
Lock 229 Doom
|
||||
{
|
||||
//$Title "One of each color"
|
||||
Any { BlueCard BlueSkull KeyBlue}
|
||||
Any { YellowCard YellowSkull KeyYellow}
|
||||
Any { RedCard RedSkull KeyGreen}
|
||||
|
@ -135,6 +150,7 @@ Lock 229 Doom
|
|||
|
||||
Lock 101 Doom
|
||||
{
|
||||
//$Title "All keys"
|
||||
BlueCard
|
||||
BlueSkull
|
||||
YellowCard
|
||||
|
@ -151,6 +167,7 @@ Lock 101 Doom
|
|||
|
||||
Lock 1 Heretic
|
||||
{
|
||||
//$Title "Green key"
|
||||
KeyGreen
|
||||
Message "$TXT_NEEDGREENKEY"
|
||||
Mapcolor 0 255 0
|
||||
|
@ -159,6 +176,7 @@ Lock 1 Heretic
|
|||
|
||||
Lock 2 Heretic
|
||||
{
|
||||
//$Title "Blue key"
|
||||
KeyBlue
|
||||
Message "$TXT_NEEDBLUEKEY"
|
||||
Mapcolor 0 0 255
|
||||
|
@ -167,6 +185,7 @@ Lock 2 Heretic
|
|||
|
||||
Lock 3 Heretic
|
||||
{
|
||||
//$Title "Yellow key"
|
||||
KeyYellow
|
||||
Message "$TXT_NEEDYELLOWKEY"
|
||||
Mapcolor 255 255 0
|
||||
|
@ -175,6 +194,7 @@ Lock 3 Heretic
|
|||
|
||||
Lock 129 Heretic
|
||||
{
|
||||
//$Title "Green key"
|
||||
KeyGreen
|
||||
Message "$TXT_NEEDGREENKEY"
|
||||
Mapcolor 0 255 0
|
||||
|
@ -183,6 +203,7 @@ Lock 129 Heretic
|
|||
|
||||
Lock 130 Heretic
|
||||
{
|
||||
//$Title "Blue key"
|
||||
KeyBlue
|
||||
Message "$TXT_NEEDBLUEKEY"
|
||||
Mapcolor 0 0 255
|
||||
|
@ -191,6 +212,7 @@ Lock 130 Heretic
|
|||
|
||||
Lock 131 Heretic
|
||||
{
|
||||
//$Title "Yellow key"
|
||||
KeyYellow
|
||||
Message "$TXT_NEEDYELLOWKEY"
|
||||
Mapcolor 255 255 0
|
||||
|
@ -199,6 +221,7 @@ Lock 131 Heretic
|
|||
|
||||
Lock 229 Heretic
|
||||
{
|
||||
//$Title "All keys"
|
||||
KeyGreen
|
||||
KeyYellow
|
||||
KeyBlue
|
||||
|
@ -208,6 +231,7 @@ Lock 229 Heretic
|
|||
|
||||
Lock 101 Heretic
|
||||
{
|
||||
//$Title "All keys"
|
||||
KeyGreen
|
||||
KeyYellow
|
||||
KeyBlue
|
||||
|
@ -222,6 +246,7 @@ Lock 101 Heretic
|
|||
|
||||
Lock 1 Hexen
|
||||
{
|
||||
//$Title "Steel key"
|
||||
KeySteel
|
||||
Message "$TXT_NEED_KEY_STEEL"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -230,6 +255,7 @@ Lock 1 Hexen
|
|||
|
||||
Lock 2 Hexen
|
||||
{
|
||||
//$Title "Cave key"
|
||||
KeyCave
|
||||
Message "$TXT_NEED_KEY_CAVE"
|
||||
Mapcolor 255 218 0
|
||||
|
@ -238,6 +264,7 @@ Lock 2 Hexen
|
|||
|
||||
Lock 3 Hexen
|
||||
{
|
||||
//$Title "Axe key"
|
||||
KeyAxe
|
||||
Message "$TXT_NEED_KEY_AXE"
|
||||
Mapcolor 64 64 255
|
||||
|
@ -246,6 +273,7 @@ Lock 3 Hexen
|
|||
|
||||
Lock 4 Hexen
|
||||
{
|
||||
//$Title "Fire key"
|
||||
KeyFire
|
||||
Message "$TXT_NEED_KEY_FIRE"
|
||||
Mapcolor 255 128 0
|
||||
|
@ -254,6 +282,7 @@ Lock 4 Hexen
|
|||
|
||||
Lock 5 Hexen
|
||||
{
|
||||
//$Title "Emerald key"
|
||||
KeyEmerald
|
||||
Message "$TXT_NEED_KEY_EMERALD"
|
||||
Mapcolor 0 255 0
|
||||
|
@ -262,6 +291,7 @@ Lock 5 Hexen
|
|||
|
||||
Lock 6 Hexen
|
||||
{
|
||||
//$Title "Dungeon key"
|
||||
KeyDungeon
|
||||
Message "$TXT_NEED_KEY_DUNGEON"
|
||||
Mapcolor 47 151 255
|
||||
|
@ -270,6 +300,7 @@ Lock 6 Hexen
|
|||
|
||||
Lock 7 Hexen
|
||||
{
|
||||
//$Title "Silver key"
|
||||
KeySilver
|
||||
Message "$TXT_NEED_KEY_SILVER"
|
||||
Mapcolor 154 152 188
|
||||
|
@ -278,6 +309,7 @@ Lock 7 Hexen
|
|||
|
||||
Lock 8 Hexen
|
||||
{
|
||||
//$Title "Rusted key"
|
||||
KeyRusted
|
||||
Message "$TXT_NEED_KEY_RUSTED"
|
||||
Mapcolor 156 76 0
|
||||
|
@ -286,6 +318,7 @@ Lock 8 Hexen
|
|||
|
||||
Lock 9 Hexen
|
||||
{
|
||||
//$Title "Horn key"
|
||||
KeyHorn
|
||||
Message "$TXT_NEED_KEY_HORN"
|
||||
Mapcolor 255 218 0
|
||||
|
@ -294,6 +327,7 @@ Lock 9 Hexen
|
|||
|
||||
Lock 10 Hexen
|
||||
{
|
||||
//$Title "Swamp key"
|
||||
KeySwamp
|
||||
Message "$TXT_NEED_KEY_SWAMP"
|
||||
Mapcolor 64 255 64
|
||||
|
@ -302,6 +336,7 @@ Lock 10 Hexen
|
|||
|
||||
Lock 11 Hexen
|
||||
{
|
||||
//$Title "Castle key"
|
||||
KeyCastle
|
||||
Message "$TXT_NEED_KEY_CASTLE"
|
||||
Mapcolor 255 64 64
|
||||
|
@ -310,6 +345,7 @@ Lock 11 Hexen
|
|||
|
||||
Lock 101 Hexen
|
||||
{
|
||||
//$Title "All keys"
|
||||
KeySteel
|
||||
KeyCave
|
||||
KeyAxe
|
||||
|
@ -326,6 +362,7 @@ Lock 101 Hexen
|
|||
|
||||
Lock 229 Hexen
|
||||
{
|
||||
//$Title "All keys"
|
||||
KeySteel
|
||||
KeyCave
|
||||
KeyAxe
|
||||
|
@ -345,14 +382,16 @@ Lock 229 Hexen
|
|||
|
||||
Lock 1 Strife
|
||||
{
|
||||
//$Title "Base key"
|
||||
BaseKey
|
||||
Message "You don't have the key"
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
}
|
||||
|
||||
|
||||
Lock 2 Strife
|
||||
{
|
||||
//$Title "Governor's key"
|
||||
GovsKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -361,6 +400,7 @@ Lock 2 Strife
|
|||
|
||||
Lock 3 Strife
|
||||
{
|
||||
//$Title "Travel passcard"
|
||||
Passcard
|
||||
RemoteMessage "$TXT_NEED_PASSCARD"
|
||||
Message "$TXT_NEED_PASSCARD_DOOR"
|
||||
|
@ -370,6 +410,7 @@ Lock 3 Strife
|
|||
|
||||
Lock 4 Strife
|
||||
{
|
||||
//$Title "ID badge"
|
||||
IDBadge
|
||||
Message "$TXT_NEED_IDCARD"
|
||||
Mapcolor 255 128 0
|
||||
|
@ -378,6 +419,7 @@ Lock 4 Strife
|
|||
|
||||
Lock 5 Strife
|
||||
{
|
||||
//$Title "Prison key"
|
||||
PrisonKey
|
||||
Message "$TXT_NEED_PRISONKEY"
|
||||
Mapcolor 0 255 0
|
||||
|
@ -386,6 +428,7 @@ Lock 5 Strife
|
|||
|
||||
Lock 6 Strife
|
||||
{
|
||||
//$Title "Severed hand"
|
||||
SeveredHand
|
||||
Message "$TXT_NEED_HANDPRINT"
|
||||
Mapcolor 255 151 100
|
||||
|
@ -394,6 +437,7 @@ Lock 6 Strife
|
|||
|
||||
Lock 7 Strife
|
||||
{
|
||||
//$Title "Power key 1"
|
||||
Power1Key
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -402,6 +446,7 @@ Lock 7 Strife
|
|||
|
||||
Lock 8 Strife
|
||||
{
|
||||
//$Title "Power key 2"
|
||||
Power2Key
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -410,6 +455,7 @@ Lock 8 Strife
|
|||
|
||||
Lock 9 Strife
|
||||
{
|
||||
//$Title "Power key 3"
|
||||
Power3Key
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -418,6 +464,7 @@ Lock 9 Strife
|
|||
|
||||
Lock 10 Strife
|
||||
{
|
||||
//$Title "Gold key"
|
||||
GoldKey
|
||||
Message "$TXT_NEED_GOLDKEY"
|
||||
Mapcolor 255 200 0
|
||||
|
@ -426,6 +473,7 @@ Lock 10 Strife
|
|||
|
||||
Lock 11 Strife
|
||||
{
|
||||
//$Title "ID card"
|
||||
IDCard
|
||||
RemoteMessage "$TXT_NEED_IDBADGE"
|
||||
Message "$TXT_NEED_IDBADGE_DOOR"
|
||||
|
@ -434,6 +482,7 @@ Lock 11 Strife
|
|||
|
||||
Lock 12 Strife
|
||||
{
|
||||
//$Title "Silver key"
|
||||
SilverKey
|
||||
Message "$TXT_NEED_SILVERKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -441,6 +490,7 @@ Lock 12 Strife
|
|||
|
||||
Lock 13 Strife
|
||||
{
|
||||
//$Title "Oracle key"
|
||||
OracleKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -448,6 +498,7 @@ Lock 13 Strife
|
|||
|
||||
Lock 14 Strife
|
||||
{
|
||||
//$Title "Military key"
|
||||
MilitaryID
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -455,6 +506,7 @@ Lock 14 Strife
|
|||
|
||||
Lock 15 Strife
|
||||
{
|
||||
//$Title "Order key"
|
||||
OrderKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -462,6 +514,7 @@ Lock 15 Strife
|
|||
|
||||
Lock 16 Strife
|
||||
{
|
||||
//$Title "Warehouse key"
|
||||
WarehouseKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -469,6 +522,7 @@ Lock 16 Strife
|
|||
|
||||
Lock 17 Strife
|
||||
{
|
||||
//$Title "Brass key"
|
||||
BrassKey
|
||||
Message "$TXT_NEED_BRASSKEY"
|
||||
Mapcolor 150 75 0
|
||||
|
@ -476,6 +530,7 @@ Lock 17 Strife
|
|||
|
||||
Lock 18 Strife
|
||||
{
|
||||
//$Title "Red crystal key"
|
||||
RedCrystalKey
|
||||
Message "$TXT_NEED_REDCRYSTAL"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -483,6 +538,7 @@ Lock 18 Strife
|
|||
|
||||
Lock 19 Strife
|
||||
{
|
||||
//$Title "Blue crystal key"
|
||||
BlueCrystalKey
|
||||
Message "$TXT_NEED_BLUECRYSTAL"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -490,6 +546,7 @@ Lock 19 Strife
|
|||
|
||||
Lock 20 Strife
|
||||
{
|
||||
//$Title "Chapel key"
|
||||
ChapelKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -497,6 +554,7 @@ Lock 20 Strife
|
|||
|
||||
Lock 21 Strife
|
||||
{
|
||||
//$Title "Catacomb key"
|
||||
CatacombKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -504,6 +562,7 @@ Lock 21 Strife
|
|||
|
||||
Lock 22 Strife
|
||||
{
|
||||
//$Title "Security key"
|
||||
SecurityKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -511,6 +570,7 @@ Lock 22 Strife
|
|||
|
||||
Lock 23 Strife
|
||||
{
|
||||
//$Title "Core key"
|
||||
CoreKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -518,6 +578,7 @@ Lock 23 Strife
|
|||
|
||||
Lock 24 Strife
|
||||
{
|
||||
//$Title "Mauler key"
|
||||
MaulerKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -525,6 +586,7 @@ Lock 24 Strife
|
|||
|
||||
Lock 25 Strife
|
||||
{
|
||||
//$Title "Factory key"
|
||||
FactoryKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -532,6 +594,7 @@ Lock 25 Strife
|
|||
|
||||
Lock 26 Strife
|
||||
{
|
||||
//$Title "Mine key"
|
||||
MineKey
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -539,6 +602,7 @@ Lock 26 Strife
|
|||
|
||||
Lock 27 Strife
|
||||
{
|
||||
//$Title "New key 5"
|
||||
NewKey5
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -546,6 +610,7 @@ Lock 27 Strife
|
|||
|
||||
Lock 50 Strife
|
||||
{
|
||||
//$Title "Prison key"
|
||||
PrisonPass
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -553,6 +618,7 @@ Lock 50 Strife
|
|||
|
||||
Lock 51 Strife
|
||||
{
|
||||
//$Title "Oracle pass"
|
||||
OraclePass
|
||||
Message "$TXT_NEEDKEY"
|
||||
Mapcolor 150 150 150
|
||||
|
@ -564,6 +630,7 @@ Lock 51 Strife
|
|||
|
||||
Lock 1 Chex
|
||||
{
|
||||
//$Title "Red key card"
|
||||
ChexRedCard
|
||||
Message "$PD_REDC"
|
||||
RemoteMessage "$PD_REDCO"
|
||||
|
@ -573,6 +640,7 @@ Lock 1 Chex
|
|||
|
||||
Lock 2 Chex
|
||||
{
|
||||
//$Title "Blue key card"
|
||||
ChexBlueCard
|
||||
Message "$PD_BLUEC"
|
||||
RemoteMessage "$PD_BLUECO"
|
||||
|
@ -582,6 +650,7 @@ Lock 2 Chex
|
|||
|
||||
Lock 3 Chex
|
||||
{
|
||||
//$Title "Yellow key card"
|
||||
ChexYellowCard
|
||||
Message "$PD_YELLOWC"
|
||||
RemoteMessage "$PD_YELLOWCO"
|
||||
|
@ -590,6 +659,7 @@ Lock 3 Chex
|
|||
|
||||
Lock 129 Chex
|
||||
{
|
||||
//$Title "Red key"
|
||||
ChexRedCard
|
||||
Message "$PD_REDK"
|
||||
RemoteMessage "$PD_REDO"
|
||||
|
@ -599,6 +669,7 @@ Lock 129 Chex
|
|||
|
||||
Lock 130 Chex
|
||||
{
|
||||
//$Title "Blue key"
|
||||
ChexBlueCard
|
||||
Message "$PD_BLUEK"
|
||||
RemoteMessage "$PD_BLUEO"
|
||||
|
@ -608,6 +679,7 @@ Lock 130 Chex
|
|||
|
||||
Lock 131 Chex
|
||||
{
|
||||
//$Title "Yellow key"
|
||||
ChexYellowCard
|
||||
Message "$PD_YELLOWK"
|
||||
RemoteMessage "$PD_YELLOWO"
|
||||
|
|
|
@ -833,6 +833,12 @@ OptionValue "AltHUDLag"
|
|||
2, "$OPTVAL_ALWAYS"
|
||||
}
|
||||
|
||||
OptionValue "AltHUDAmmoOrder"
|
||||
{
|
||||
0, "$OPTVAL_AMMOIMAGETEXT"
|
||||
1, "$OPTVAL_AMMOTEXTIMAGE"
|
||||
}
|
||||
|
||||
OptionMenu "AltHUDOptions"
|
||||
{
|
||||
Title "$ALTHUDMNU_TITLE"
|
||||
|
@ -849,6 +855,7 @@ OptionMenu "AltHUDOptions"
|
|||
Option "$ALTHUDMNU_SHOWTIME", "hud_showtime", "AltHUDTime"
|
||||
Option "$ALTHUDMNU_TIMECOLOR", "hud_timecolor", "TextColors"
|
||||
Option "$ALTHUDMNU_SHOWLAG", "hud_showlag", "AltHUDLag"
|
||||
Option "$ALTHUDMNU_AMMOORDER", "hud_ammo_order", "AltHUDAmmoOrder"
|
||||
Slider "$ALTHUDMNU_AMMORED", "hud_ammo_red", 0, 100, 1, 0
|
||||
Slider "$ALTHUDMNU_AMMOYELLOW", "hud_ammo_yellow", 0, 100, 1, 0
|
||||
Slider "$ALTHUDMNU_HEALTHRED", "hud_health_red", 0, 100, 1, 0
|
||||
|
|
|
@ -234,3 +234,20 @@ enum
|
|||
447 = 0, Exit_Normal(0)
|
||||
448 = 0, Exit_Secret(0)
|
||||
449 = 0, Teleport_NewMap(0)
|
||||
450 = 0, Line_Horizon(0)
|
||||
451 = 0, Floor_RaiseAndCrush(0)
|
||||
452 = 0, Floor_CrushStop(0)
|
||||
453 = 0, FloorAndCeiling_LowerByValue(0)
|
||||
454 = 0, FloorAndCeiling_RaiseByValue(0)
|
||||
457 = 0, Door_LockedOpen(0)
|
||||
458 = 0, Elevator_RaiseToNearest(0)
|
||||
459 = 0, Elevator_LowerToNearest(0)
|
||||
460 = 0, Elevator_MoveToFloor(0)
|
||||
461 = 0, Light_MaxNeighbor(0)
|
||||
462 = 0, ChangeSkill(0)
|
||||
463 = 0, Light_StrobeDoom(0)
|
||||
464 = 0, Generic_Floor(0)
|
||||
465 = 0, Generic_Ceiling(0)
|
||||
466 = 0, Floor_TransferTrigger(0)
|
||||
467 = 0, Floor_TransferNumeric(0)
|
||||
468 = 0, FloorAndCeiling_LowerRaise(0)
|
||||
|
|
Loading…
Reference in a new issue