mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-27 22:42:57 +00:00
- merged 3dfloors2 branch into trunk.
SVN r3124 (trunk)
This commit is contained in:
parent
a2acc382df
commit
fae8ed444c
41 changed files with 12357 additions and 444 deletions
|
@ -708,6 +708,7 @@ add_executable( zdoom WIN32
|
|||
p_xlat.cpp
|
||||
parsecontext.cpp
|
||||
po_man.cpp
|
||||
r_3dfloors.cpp
|
||||
r_bsp.cpp
|
||||
r_data.cpp
|
||||
r_draw.cpp
|
||||
|
@ -879,7 +880,18 @@ add_executable( zdoom WIN32
|
|||
timidity/resample.cpp
|
||||
timidity/timidity.cpp
|
||||
xlat/parse_xlat.cpp
|
||||
autozend.cpp )
|
||||
fragglescript/t_fspic.cpp
|
||||
fragglescript/t_func.cpp
|
||||
fragglescript/t_load.cpp
|
||||
fragglescript/t_oper.cpp
|
||||
fragglescript/t_parse.cpp
|
||||
fragglescript/t_prepro.cpp
|
||||
fragglescript/t_script.cpp
|
||||
fragglescript/t_spec.cpp
|
||||
fragglescript/t_variable.cpp
|
||||
fragglescript/t_cmd.cpp
|
||||
autozend.cpp
|
||||
)
|
||||
|
||||
set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" )
|
||||
set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" )
|
||||
|
|
134
src/am_map.cpp
134
src/am_map.cpp
|
@ -89,7 +89,7 @@ struct AMColor
|
|||
};
|
||||
|
||||
static AMColor Background, YourColor, WallColor, TSWallColor,
|
||||
FDWallColor, CDWallColor, ThingColor,
|
||||
FDWallColor, CDWallColor, EFWallColor, ThingColor,
|
||||
ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend,
|
||||
SpecialWallColor, SecretWallColor, GridColor, XHairColor,
|
||||
NotSeenColor,
|
||||
|
@ -171,6 +171,7 @@ CVAR (Color, am_specialwallcolor, 0xffffff, CVAR_ARCHIVE);
|
|||
CVAR (Color, am_tswallcolor, 0x888888, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_fdwallcolor, 0x887058, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_cdwallcolor, 0x4c3820, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_efwallcolor, 0x665555, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_thingcolor, 0xfcfcfc, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_gridcolor, 0x8b5a2b, CVAR_ARCHIVE);
|
||||
CVAR (Color, am_xhaircolor, 0x808080, CVAR_ARCHIVE);
|
||||
|
@ -909,7 +910,7 @@ static void AM_initColors (bool overlayed)
|
|||
ThingColor_Monster.FromCVar (am_ovthingcolor_monster);
|
||||
ThingColor.FromCVar (am_ovthingcolor);
|
||||
LockedColor.FromCVar (am_ovotherwallscolor);
|
||||
FDWallColor = CDWallColor = LockedColor;
|
||||
EFWallColor = FDWallColor = CDWallColor = LockedColor;
|
||||
TSWallColor.FromCVar (am_ovunseencolor);
|
||||
NotSeenColor = TSWallColor;
|
||||
InterTeleportColor.FromCVar (am_ovtelecolor);
|
||||
|
@ -928,6 +929,7 @@ static void AM_initColors (bool overlayed)
|
|||
TSWallColor.FromCVar (am_tswallcolor);
|
||||
FDWallColor.FromCVar (am_fdwallcolor);
|
||||
CDWallColor.FromCVar (am_cdwallcolor);
|
||||
EFWallColor.FromCVar (am_efwallcolor);
|
||||
ThingColor_Item.FromCVar (am_thingcolor_item);
|
||||
ThingColor_CountItem.FromCVar (am_thingcolor_citem);
|
||||
ThingColor_Friend.FromCVar (am_thingcolor_friend);
|
||||
|
@ -968,7 +970,7 @@ static void AM_initColors (bool overlayed)
|
|||
SpecialWallColor =
|
||||
WallColor = DoomColors[3];
|
||||
TSWallColor = DoomColors[4];
|
||||
FDWallColor = DoomColors[5];
|
||||
EFWallColor = FDWallColor = DoomColors[5];
|
||||
LockedColor =
|
||||
CDWallColor = DoomColors[6];
|
||||
ThingColor_Item =
|
||||
|
@ -990,7 +992,7 @@ static void AM_initColors (bool overlayed)
|
|||
SpecialWallColor =
|
||||
WallColor = StrifeColors[3];
|
||||
TSWallColor = StrifeColors[4];
|
||||
FDWallColor = StrifeColors[5];
|
||||
EFWallColor = FDWallColor = StrifeColors[5];
|
||||
LockedColor =
|
||||
CDWallColor = StrifeColors[6];
|
||||
ThingColor_Item = StrifeColors[10];
|
||||
|
@ -1012,7 +1014,7 @@ static void AM_initColors (bool overlayed)
|
|||
SpecialWallColor =
|
||||
WallColor = RavenColors[3];
|
||||
TSWallColor = RavenColors[4];
|
||||
FDWallColor = RavenColors[5];
|
||||
EFWallColor = FDWallColor = RavenColors[5];
|
||||
LockedColor =
|
||||
CDWallColor = RavenColors[6];
|
||||
ThingColor =
|
||||
|
@ -1647,6 +1649,56 @@ void AM_drawSubsectors()
|
|||
originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24));
|
||||
// Coloring for the polygon
|
||||
colormap = sec->ColorMap;
|
||||
|
||||
FTextureID maptex = sec->GetTexture(sector_t::floor);
|
||||
|
||||
#ifdef _3DFLOORS
|
||||
|
||||
if (sec->e->XFloor.ffloors.Size())
|
||||
{
|
||||
secplane_t *floorplane = &sec->floorplane;
|
||||
|
||||
// Look for the highest floor below the camera viewpoint.
|
||||
// Check the center of the subsector's sector. Do not check each
|
||||
// subsector separately because that might result in different planes for
|
||||
// different subsectors of the same sector which is not wanted here.
|
||||
// (Make the comparison in floating point to avoid overflows and improve performance.)
|
||||
double secx;
|
||||
double secy;
|
||||
double cmpz = FIXED2DBL(viewz);
|
||||
|
||||
if (players[consoleplayer].camera && sec == players[consoleplayer].camera->Sector)
|
||||
{
|
||||
// For the actual camera sector use the current viewpoint as reference.
|
||||
secx = FIXED2DBL(viewx);
|
||||
secy = FIXED2DBL(viewy);
|
||||
}
|
||||
else
|
||||
{
|
||||
secx = FIXED2DBL(sec->soundorg[0]);
|
||||
secy = FIXED2DBL(sec->soundorg[1]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sec->e->XFloor.ffloors.Size(); ++i)
|
||||
{
|
||||
F3DFloor *rover = sec->e->XFloor.ffloors[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->flags & FF_FOG) continue;
|
||||
if (rover->alpha == 0) continue;
|
||||
if (rover->top.plane->ZatPoint(secx, secy) < cmpz)
|
||||
{
|
||||
maptex = *(rover->top.texture);
|
||||
floorplane = rover->top.plane;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lightlist_t *light = P_GetPlaneLight(sec, floorplane, false);
|
||||
floorlight = *light->p_lightlevel;
|
||||
colormap = light->extra_colormap;
|
||||
}
|
||||
#endif
|
||||
|
||||
// If this subsector has not actually been seen yet (because you are cheating
|
||||
// to see it on the map), tint and desaturate it.
|
||||
if (!(subsectors[i].flags & SSECF_DRAWN))
|
||||
|
@ -1662,8 +1714,7 @@ void AM_drawSubsectors()
|
|||
}
|
||||
|
||||
// Draw the polygon.
|
||||
screen->FillSimplePoly(
|
||||
TexMan(sec->GetTexture(sector_t::floor)),
|
||||
screen->FillSimplePoly(TexMan(maptex),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
|
@ -1777,6 +1828,69 @@ void AM_showSS()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _3DFLOORS
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Determines if a 3D floor boundary should be drawn
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool AM_Check3DFloors(line_t *line)
|
||||
{
|
||||
TArray<F3DFloor*> &ff_front = line->frontsector->e->XFloor.ffloors;
|
||||
TArray<F3DFloor*> &ff_back = line->backsector->e->XFloor.ffloors;
|
||||
|
||||
// No 3D floors so there's no boundary
|
||||
if (ff_back.Size() == 0 && ff_front.Size() == 0) return false;
|
||||
|
||||
int realfrontcount = 0;
|
||||
int realbackcount = 0;
|
||||
|
||||
for(unsigned i=0;i<ff_front.Size();i++)
|
||||
{
|
||||
F3DFloor *rover = ff_front[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->alpha == 0) continue;
|
||||
realfrontcount++;
|
||||
}
|
||||
|
||||
for(unsigned i=0;i<ff_back.Size();i++)
|
||||
{
|
||||
F3DFloor *rover = ff_back[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->alpha == 0) continue;
|
||||
realbackcount++;
|
||||
}
|
||||
// if the amount of 3D floors does not match there is a boundary
|
||||
if (realfrontcount != realbackcount) return true;
|
||||
|
||||
for(unsigned i=0;i<ff_front.Size();i++)
|
||||
{
|
||||
F3DFloor *rover = ff_front[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->alpha == 0) continue;
|
||||
|
||||
bool found = false;
|
||||
for(unsigned j=0;j<ff_back.Size();j++)
|
||||
{
|
||||
F3DFloor *rover2 = ff_back[j];
|
||||
if (!(rover2->flags & FF_EXISTS)) continue;
|
||||
if (rover2->alpha == 0) continue;
|
||||
if (rover->model == rover2->model && rover->flags == rover2->flags)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// At least one 3D floor in the front sector didn't have a match in the back sector so there is a boundary.
|
||||
if (!found) return true;
|
||||
}
|
||||
// All 3D floors could be matched so let's not draw a boundary.
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Determines visible lines, draws them.
|
||||
|
@ -1895,6 +2009,12 @@ void AM_drawWalls (bool allmap)
|
|||
{
|
||||
AM_drawMline(&l, CDWallColor); // ceiling level change
|
||||
}
|
||||
#ifdef _3DFLOORS
|
||||
else if (AM_Check3DFloors(&lines[i]))
|
||||
{
|
||||
AM_drawMline(&l, EFWallColor); // Extra floor border
|
||||
}
|
||||
#endif
|
||||
else if (am_cheat != 0)
|
||||
{
|
||||
AM_drawMline(&l, TSWallColor);
|
||||
|
|
|
@ -264,7 +264,7 @@ void CheckCompatibility(MapData *map)
|
|||
// When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT.
|
||||
// I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt.
|
||||
// TNT's MAP31 also needs COMPATF_STAIRINDEX but that only gets activated for TNT.WAD.
|
||||
if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && !(level.flags & LEVEL_HEXENFORMAT))
|
||||
if (Wads.GetLumpFile(map->lumpnum) == 1 && (gameinfo.flags & GI_COMPATSHORTTEX) && level.maptype == MAPTYPE_DOOM)
|
||||
{
|
||||
ii_compatflags = COMPATF_SHORTTEX|COMPATF_LIGHT;
|
||||
if (gameinfo.flags & GI_COMPATSTAIRS) ii_compatflags |= COMPATF_STAIRINDEX;
|
||||
|
|
208
src/fragglescript/t_cmd.cpp
Normal file
208
src/fragglescript/t_cmd.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
** t_cmd.cpp
|
||||
** Emulation for selected Legacy console commands
|
||||
** Unfortunately Legacy allows full access of FS to the console
|
||||
** so everything that gets used by some map has to be emulated...
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 Christoph Oelckers
|
||||
** 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include "p_local.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "sc_man.h"
|
||||
#include "g_level.h"
|
||||
#ifdef GLSUPPORT
|
||||
#include "gl/gl_functions.h"
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void FS_Gimme(const char * what)
|
||||
{
|
||||
char buffer[80];
|
||||
|
||||
// This is intentionally limited to the few items
|
||||
// it can handle in Legacy.
|
||||
if (!strnicmp(what, "health", 6)) what="health";
|
||||
else if (!strnicmp(what, "ammo", 4)) what="ammo";
|
||||
else if (!strnicmp(what, "armor", 5)) what="greenarmor";
|
||||
else if (!strnicmp(what, "keys", 4)) what="keys";
|
||||
else if (!strnicmp(what, "weapons", 7)) what="weapons";
|
||||
else if (!strnicmp(what, "chainsaw", 8)) what="chainsaw";
|
||||
else if (!strnicmp(what, "shotgun", 7)) what="shotgun";
|
||||
else if (!strnicmp(what, "supershotgun", 12)) what="supershotgun";
|
||||
else if (!strnicmp(what, "rocket", 6)) what="rocketlauncher";
|
||||
else if (!strnicmp(what, "plasma", 6)) what="plasmarifle";
|
||||
else if (!strnicmp(what, "bfg", 3)) what="BFG9000";
|
||||
else if (!strnicmp(what, "chaingun", 8)) what="chaingun";
|
||||
else if (!strnicmp(what, "berserk", 7)) what="Berserk";
|
||||
else if (!strnicmp(what, "map", 3)) what="Allmap";
|
||||
else if (!strnicmp(what, "fullmap", 7)) what="Allmap";
|
||||
else return;
|
||||
|
||||
mysnprintf(buffer, countof(buffer), "give %.72s", what);
|
||||
AddCommandString(buffer);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FS_MapCmd(FScanner &sc)
|
||||
{
|
||||
char nextmap[9];
|
||||
int NextSkill = -1;
|
||||
int flags = CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH;
|
||||
if (dmflags & DF_NO_MONSTERS)
|
||||
flags |= CHANGELEVEL_NOMONSTERS;
|
||||
sc.MustGetString();
|
||||
strncpy (nextmap, sc.String, 8);
|
||||
nextmap[8]=0;
|
||||
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare("-skill"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
NextSkill = clamp<int>(sc.Number-1, 0, AllSkills.Size()-1);
|
||||
}
|
||||
else if (sc.Compare("-monsters"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
if (sc.Number)
|
||||
flags &= ~CHANGELEVEL_NOMONSTERS;
|
||||
else
|
||||
flags |= CHANGELEVEL_NOMONSTERS;
|
||||
}
|
||||
else if (sc.Compare("-noresetplayers"))
|
||||
{
|
||||
flags &= ~(CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH);
|
||||
}
|
||||
}
|
||||
G_ChangeLevel(nextmap, 0, flags, NextSkill);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FS_EmulateCmd(char * string)
|
||||
{
|
||||
FScanner sc;
|
||||
sc.OpenMem("RUNCMD", string, (int)strlen(string));
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare("GIMME"))
|
||||
{
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (!sc.Compare(";")) FS_Gimme(sc.String);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("ALLOWJUMP"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
if (sc.Number) dmflags = dmflags & ~DF_NO_JUMP;
|
||||
else dmflags=dmflags | DF_NO_JUMP;
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare(";")) break;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("gravity"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
level.gravity=(float)(sc.Float*800);
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare(";")) break;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("viewheight"))
|
||||
{
|
||||
sc.MustGetFloat();
|
||||
fixed_t playerviewheight = (fixed_t)(sc.Float*FRACUNIT);
|
||||
for(int i=0;i<MAXPLAYERS;i++)
|
||||
{
|
||||
// No, this is not correct. But this is the way Legacy WADs expect it to be handled!
|
||||
if (players[i].mo != NULL) players[i].mo->ViewHeight = playerviewheight;
|
||||
players[i].Uncrouch();
|
||||
}
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare(";")) break;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("map"))
|
||||
{
|
||||
FS_MapCmd(sc);
|
||||
}
|
||||
else if (sc.Compare("gr_fogdensity"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
// Using this disables most MAPINFO fog options!
|
||||
#ifdef GLSUPPORT
|
||||
gl_SetFogParams(sc.Number*70/400, 0xff000000, 0, 0);
|
||||
#endif
|
||||
}
|
||||
else if (sc.Compare("gr_fogcolor"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
level.fadeto = strtol(sc.String, NULL, 16);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Skip unhandled commands
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare(";")) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
src/fragglescript/t_fs.h
Normal file
14
src/fragglescript/t_fs.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
#ifndef T_FS_H
|
||||
#define T_FS_H
|
||||
|
||||
// global FS interface
|
||||
|
||||
struct MapData;
|
||||
class AActor;
|
||||
|
||||
void T_PreprocessScripts();
|
||||
void T_LoadScripts(MapData * map);
|
||||
void T_AddSpawnedThing(AActor * );
|
||||
|
||||
#endif
|
202
src/fragglescript/t_fspic.cpp
Normal file
202
src/fragglescript/t_fspic.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
** t_fspic.cpp
|
||||
** Fragglescript HUD pics (incomplete and untested!)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005 Christoph Oelckers
|
||||
** 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 "t_script.h"
|
||||
#include "doomtype.h"
|
||||
#include "p_local.h"
|
||||
#include "farchive.h"
|
||||
#include "sbar.h"
|
||||
|
||||
|
||||
|
||||
struct FHudPic
|
||||
{
|
||||
FTextureID texturenum;
|
||||
int xpos;
|
||||
int ypos;
|
||||
bool draw;
|
||||
|
||||
void Serialize(FArchive & arc)
|
||||
{
|
||||
arc << xpos << ypos << draw << texturenum;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
class DHUDPicManager : public DHUDMessage
|
||||
{
|
||||
// This is no real hudmessage but this way I don't need any external code to handle this
|
||||
// because the hudmessage and thinker code handles everything automatically
|
||||
DECLARE_CLASS(DHUDPicManager, DHUDMessage)
|
||||
float basetrans;
|
||||
|
||||
public:
|
||||
|
||||
TArray<FHudPic> piclist;
|
||||
|
||||
DHUDPicManager();
|
||||
~DHUDPicManager() {}
|
||||
void Serialize(FArchive & ar);
|
||||
virtual void DoDraw (int linenum, int x, int y, int hudheight, float translucent);
|
||||
} ;
|
||||
|
||||
IMPLEMENT_CLASS(DHUDPicManager)
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
DHUDPicManager::DHUDPicManager()
|
||||
{
|
||||
HUDWidth=HUDHeight=0;
|
||||
basetrans=0.8f;
|
||||
//SetID(0xffffffff);
|
||||
NumLines=1;
|
||||
HoldTics=0; // stay forever!
|
||||
//logtoconsole=false;
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
void DHUDPicManager::Serialize(FArchive & ar)
|
||||
{
|
||||
Super::Serialize(ar);
|
||||
|
||||
short count=piclist.Size();
|
||||
ar << count << basetrans;
|
||||
if (ar.IsLoading()) piclist.Resize(count);
|
||||
for(int i=0;i<count;i++) piclist[i].Serialize(ar);
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
void DHUDPicManager::DoDraw (int linenum, int x, int y, int hudheight, float translucent)
|
||||
{
|
||||
for(unsigned int i=0; i<piclist.Size();i++) if (piclist[i].texturenum.isValid() && piclist[i].draw)
|
||||
{
|
||||
FTexture * tex = TexMan[piclist[i].texturenum];
|
||||
if (tex) screen->DrawTexture(tex, piclist[i].xpos, piclist[i].ypos, DTA_320x200, true,
|
||||
DTA_Alpha, (fixed_t)(translucent*basetrans*FRACUNIT), TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
static TArray<FHudPic> & GetPicList()
|
||||
{
|
||||
//TThinkerIterator<DHUDPicManager> it;
|
||||
DHUDPicManager * pm=NULL;//it.Next();
|
||||
|
||||
if (!pm) pm=new DHUDPicManager;
|
||||
return pm->piclist;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
// External interface
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
int HU_GetFSPic(FTextureID texturenum, int xpos, int ypos)
|
||||
{
|
||||
TArray<FHudPic> &piclist=GetPicList();
|
||||
unsigned int i;
|
||||
|
||||
for(i=0;i<piclist.Size();i++) if (piclist[i].texturenum.isValid()) continue;
|
||||
if (i==piclist.Size()) i=piclist.Reserve(1);
|
||||
|
||||
FHudPic * pic=&piclist[i];
|
||||
|
||||
piclist[i].texturenum = texturenum;
|
||||
piclist[i].xpos = xpos;
|
||||
piclist[i].ypos = ypos;
|
||||
piclist[i].draw = false;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
int HU_DeleteFSPic(unsigned handle)
|
||||
{
|
||||
TArray<FHudPic> &piclist=GetPicList();
|
||||
|
||||
if(handle >= piclist.Size()) return -1;
|
||||
piclist[handle].texturenum.SetInvalid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
int HU_ModifyFSPic(unsigned handle, FTextureID texturenum, int xpos, int ypos)
|
||||
{
|
||||
TArray<FHudPic> &piclist=GetPicList();
|
||||
|
||||
if(handle >= piclist.Size()) return -1;
|
||||
if(!piclist[handle].texturenum.isValid()) return -1;
|
||||
|
||||
piclist[handle].texturenum = texturenum;
|
||||
piclist[handle].xpos = xpos;
|
||||
piclist[handle].ypos = ypos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//
|
||||
//======================================================================
|
||||
int HU_FSDisplay(unsigned handle, bool newval)
|
||||
{
|
||||
TArray<FHudPic> &piclist=GetPicList();
|
||||
|
||||
if(handle >= piclist.Size()) return -1;
|
||||
if(!piclist[handle].texturenum.isValid()) return -1;
|
||||
|
||||
piclist[handle].draw = newval;
|
||||
return 0;
|
||||
}
|
||||
|
4843
src/fragglescript/t_func.cpp
Normal file
4843
src/fragglescript/t_func.cpp
Normal file
File diff suppressed because it is too large
Load diff
368
src/fragglescript/t_load.cpp
Normal file
368
src/fragglescript/t_load.cpp
Normal file
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
** t_load.cpp
|
||||
** FraggleScript loader
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2005 Christoph Oelckers
|
||||
** 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 "w_wad.h"
|
||||
#include "tarray.h"
|
||||
#include "g_level.h"
|
||||
#include "sc_man.h"
|
||||
#include "s_sound.h"
|
||||
#include "r_data.h"
|
||||
#include "r_sky.h"
|
||||
#include "t_script.h"
|
||||
#include "cmdlib.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "gi.h"
|
||||
#include "xlat/xlat.h"
|
||||
|
||||
void T_Init();
|
||||
|
||||
class FScriptLoader
|
||||
{
|
||||
enum
|
||||
{
|
||||
RT_SCRIPT,
|
||||
RT_INFO,
|
||||
RT_OTHER,
|
||||
} readtype;
|
||||
|
||||
|
||||
int drownflag;
|
||||
bool HasScripts;
|
||||
bool IgnoreInfo;
|
||||
|
||||
void ParseInfoCmd(char *line, FString &scriptsrc);
|
||||
public:
|
||||
bool ParseInfo(MapData * map);
|
||||
};
|
||||
|
||||
struct FFsOptions : public FOptionalMapinfoData
|
||||
{
|
||||
FFsOptions()
|
||||
{
|
||||
identifier = "fragglescript";
|
||||
nocheckposition = false;
|
||||
}
|
||||
virtual FOptionalMapinfoData *Clone() const
|
||||
{
|
||||
FFsOptions *newopt = new FFsOptions;
|
||||
newopt->identifier = identifier;
|
||||
newopt->nocheckposition = nocheckposition;
|
||||
return newopt;
|
||||
}
|
||||
bool nocheckposition;
|
||||
};
|
||||
|
||||
DEFINE_MAP_OPTION(fs_nocheckposition, false)
|
||||
{
|
||||
FFsOptions *opt = info->GetOptData<FFsOptions>("fragglescript");
|
||||
|
||||
parse.ParseAssign();
|
||||
if (parse.CheckAssign())
|
||||
{
|
||||
parse.sc.MustGetNumber();
|
||||
opt->nocheckposition = !!parse.sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt->nocheckposition = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Process the lump to strip all unneeded information from it
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
|
||||
{
|
||||
char *temp;
|
||||
|
||||
// clear any control chars
|
||||
for(temp=line; *temp; temp++) if (*temp<32) *temp=32;
|
||||
|
||||
if(readtype != RT_SCRIPT) // not for scripts
|
||||
{
|
||||
temp = line+strlen(line)-1;
|
||||
|
||||
// strip spaces at the beginning and end of the line
|
||||
while(*temp == ' ') *temp-- = 0;
|
||||
while(*line == ' ') line++;
|
||||
|
||||
if(!*line) return;
|
||||
|
||||
if((line[0] == '/' && line[1] == '/') || // comment
|
||||
line[0] == '#' || line[0] == ';') return;
|
||||
}
|
||||
|
||||
if(*line == '[') // a new section seperator
|
||||
{
|
||||
line++;
|
||||
|
||||
if(!strnicmp(line, "scripts", 7))
|
||||
{
|
||||
readtype = RT_SCRIPT;
|
||||
HasScripts = true; // has scripts
|
||||
}
|
||||
else if (!strnicmp(line, "level info", 10))
|
||||
{
|
||||
readtype = RT_INFO;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (readtype==RT_SCRIPT)
|
||||
{
|
||||
scriptsrc << line << '\n';
|
||||
}
|
||||
else if (readtype==RT_INFO)
|
||||
{
|
||||
// Read the usable parts of the level info header
|
||||
// and ignore the rest.
|
||||
FScanner sc;
|
||||
sc.OpenMem("LEVELINFO", line, (int)strlen(line));
|
||||
sc.SetCMode(true);
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("levelname"))
|
||||
{
|
||||
char * beg = strchr(line, '=')+1;
|
||||
while (*beg<=' ') beg++;
|
||||
char * comm = strstr(beg, "//");
|
||||
if (comm) *comm=0;
|
||||
level.LevelName = beg;
|
||||
}
|
||||
else if (sc.Compare("partime"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetNumber();
|
||||
level.partime=sc.Number;
|
||||
}
|
||||
else if (sc.Compare("music"))
|
||||
{
|
||||
bool FS_ChangeMusic(const char * string);
|
||||
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
if (!FS_ChangeMusic(sc.String))
|
||||
{
|
||||
S_ChangeMusic(level.Music, level.musicorder);
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("skyname"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
|
||||
strncpy(level.skypic1, sc.String, 8);
|
||||
strncpy(level.skypic2, sc.String, 8);
|
||||
level.skypic1[8]=level.skypic2[8]=0;
|
||||
sky2texture = sky1texture = TexMan.GetTexture (sc.String, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
|
||||
R_InitSkyMap ();
|
||||
}
|
||||
else if (sc.Compare("interpic"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
level.info->ExitPic = sc.String;
|
||||
}
|
||||
else if (sc.Compare("gravity"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetNumber();
|
||||
level.gravity=sc.Number*8.f;
|
||||
}
|
||||
else if (sc.Compare("nextlevel"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
strncpy(level.nextmap, sc.String, 8);
|
||||
level.nextmap[8]=0;
|
||||
}
|
||||
else if (sc.Compare("nextsecret"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
strncpy(level.secretmap, sc.String, 8);
|
||||
level.secretmap[8]=0;
|
||||
}
|
||||
else if (sc.Compare("drown"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetNumber();
|
||||
drownflag=!!sc.Number;
|
||||
}
|
||||
else if (sc.Compare("consolecmd"))
|
||||
{
|
||||
char * beg = strchr(line, '=')+1;
|
||||
while (*beg<' ') beg++;
|
||||
char * comm = strstr(beg, "//");
|
||||
if (comm) *comm=0;
|
||||
FS_EmulateCmd(beg);
|
||||
}
|
||||
else if (sc.Compare("ignore"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetNumber();
|
||||
IgnoreInfo=!!sc.Number;
|
||||
}
|
||||
// Ignore anything unknows
|
||||
sc.Close();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Loads the scripts for the current map
|
||||
// Initializes all FS data
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool FScriptLoader::ParseInfo(MapData * map)
|
||||
{
|
||||
char *lump;
|
||||
char *rover;
|
||||
char *startofline;
|
||||
int lumpsize;
|
||||
bool fsglobal=false;
|
||||
FString scriptsrc;
|
||||
|
||||
// Global initializazion if not done yet.
|
||||
static bool done=false;
|
||||
|
||||
// Load the script lump
|
||||
IgnoreInfo = false;
|
||||
lumpsize = map->Size(0);
|
||||
if (lumpsize==0)
|
||||
{
|
||||
// Try a global FS lump
|
||||
int lumpnum=Wads.CheckNumForName("FSGLOBAL");
|
||||
if (lumpnum<0) return false;
|
||||
lumpsize=Wads.LumpLength(lumpnum);
|
||||
if (lumpsize==0) return false;
|
||||
fsglobal=true;
|
||||
lump=new char[lumpsize+3];
|
||||
Wads.ReadLump(lumpnum,lump);
|
||||
}
|
||||
else
|
||||
{
|
||||
lump=new char[lumpsize+3];
|
||||
map->Read(0, lump);
|
||||
}
|
||||
// Append a new line. The parser likes to crash when the last character is a valid token.
|
||||
lump[lumpsize]='\n';
|
||||
lump[lumpsize+1]='\r';
|
||||
lump[lumpsize+2]=0;
|
||||
lumpsize+=2;
|
||||
|
||||
rover = startofline = lump;
|
||||
HasScripts=false;
|
||||
drownflag=-1;
|
||||
|
||||
readtype = RT_OTHER;
|
||||
while(rover < lump+lumpsize)
|
||||
{
|
||||
if(*rover == '\n') // end of line
|
||||
{
|
||||
*rover = 0; // make it an end of string (0)
|
||||
if (!IgnoreInfo) ParseInfoCmd(startofline, scriptsrc);
|
||||
startofline = rover+1; // next line
|
||||
*rover = '\n'; // back to end of line
|
||||
}
|
||||
rover++;
|
||||
}
|
||||
if (HasScripts)
|
||||
{
|
||||
new DFraggleThinker;
|
||||
DFraggleThinker::ActiveThinker->LevelScript->data = copystring(scriptsrc.GetChars());
|
||||
|
||||
if (drownflag==-1) drownflag = (level.maptype != MAPTYPE_DOOM || fsglobal);
|
||||
if (!drownflag) level.airsupply=0; // Legacy doesn't to water damage so we need to check if it has to be disabled here.
|
||||
|
||||
FFsOptions *opt = level.info->GetOptData<FFsOptions>("fragglescript", false);
|
||||
if (opt != NULL)
|
||||
{
|
||||
DFraggleThinker::ActiveThinker->nocheckposition = opt->nocheckposition;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
delete lump;
|
||||
return HasScripts;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Starts the level info parser
|
||||
// and patches the global linedef translation table
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void T_LoadScripts(MapData *map)
|
||||
{
|
||||
FScriptLoader parser;
|
||||
|
||||
T_Init();
|
||||
|
||||
bool HasScripts = parser.ParseInfo(map);
|
||||
|
||||
// Hack for Legacy compatibility: Since 272 is normally an MBF sky transfer we have to patch it.
|
||||
// It could be done with an additional translator but that would be sub-optimal for the user.
|
||||
// To handle this the default translator defines the proper Legacy type at index 270.
|
||||
// This code then then swaps 270 and 272 - but only if this is either Doom or Heretic and
|
||||
// the default translator is being used.
|
||||
// Custom translators will not be patched.
|
||||
if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() &&
|
||||
level.maptype == MAPTYPE_DOOM && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
|
||||
{
|
||||
FLineTrans t = SimpleLineTranslations[270];
|
||||
SimpleLineTranslations[270] = SimpleLineTranslations[272];
|
||||
SimpleLineTranslations[272] = t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Adds an actor to the list of spawned things
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void T_AddSpawnedThing(AActor * ac)
|
||||
{
|
||||
if (DFraggleThinker::ActiveThinker)
|
||||
{
|
||||
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
SpawnedThings.Push(GC::ReadBarrier(ac));
|
||||
}
|
||||
}
|
653
src/fragglescript/t_oper.cpp
Normal file
653
src/fragglescript/t_oper.cpp
Normal file
|
@ -0,0 +1,653 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Operators
|
||||
//
|
||||
// Handler code for all the operators. The 'other half'
|
||||
// of the parsing.
|
||||
//
|
||||
// By Simon Howard
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
/* includes ************************/
|
||||
#include "t_script.h"
|
||||
|
||||
|
||||
#define evaluate_leftnright(a, b, c) {\
|
||||
EvaluateExpression(left, (a), (b)-1); \
|
||||
EvaluateExpression(right, (b)+1, (c)); }\
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
FParser::operator_t FParser::operators[]=
|
||||
{
|
||||
{"=", &FParser::OPequals, backward},
|
||||
{"||", &FParser::OPor, forward},
|
||||
{"&&", &FParser::OPand, forward},
|
||||
{"|", &FParser::OPor_bin, forward},
|
||||
{"&", &FParser::OPand_bin, forward},
|
||||
{"==", &FParser::OPcmp, forward},
|
||||
{"!=", &FParser::OPnotcmp, forward},
|
||||
{"<", &FParser::OPlessthan, forward},
|
||||
{">", &FParser::OPgreaterthan, forward},
|
||||
{"<=", &FParser::OPlessthanorequal, forward},
|
||||
{">=", &FParser::OPgreaterthanorequal, forward},
|
||||
|
||||
{"+", &FParser::OPplus, forward},
|
||||
{"-", &FParser::OPminus, forward},
|
||||
{"*", &FParser::OPmultiply, forward},
|
||||
{"/", &FParser::OPdivide, forward},
|
||||
{"%", &FParser::OPremainder, forward},
|
||||
{"~", &FParser::OPnot_bin, forward}, // haleyjd
|
||||
{"!", &FParser::OPnot, forward},
|
||||
{"++", &FParser::OPincrement, forward},
|
||||
{"--", &FParser::OPdecrement, forward},
|
||||
{".", &FParser::OPstructure, forward},
|
||||
};
|
||||
|
||||
int FParser::num_operators = sizeof(FParser::operators) / sizeof(FParser::operator_t);
|
||||
|
||||
/***************** logic *********************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPequals(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
DFsVariable *var;
|
||||
|
||||
var = Script->FindVariable(Tokens[start]);
|
||||
|
||||
if(var)
|
||||
{
|
||||
EvaluateExpression(result, n+1, stop);
|
||||
var->SetValue (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[start]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPor(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
int exprtrue = false;
|
||||
|
||||
// if first is true, do not evaluate the second
|
||||
|
||||
EvaluateExpression(result, start, n-1);
|
||||
|
||||
if(intvalue(result))
|
||||
exprtrue = true;
|
||||
else
|
||||
{
|
||||
EvaluateExpression(result, n+1, stop);
|
||||
exprtrue = !!intvalue(result);
|
||||
}
|
||||
|
||||
result.type = svt_int;
|
||||
result.value.i = exprtrue;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPand(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
int exprtrue = true;
|
||||
// if first is false, do not eval second
|
||||
|
||||
EvaluateExpression(result, start, n-1);
|
||||
|
||||
if(!intvalue(result) )
|
||||
exprtrue = false;
|
||||
else
|
||||
{
|
||||
EvaluateExpression(result, n+1, stop);
|
||||
exprtrue = !!intvalue(result);
|
||||
}
|
||||
|
||||
result.type = svt_int;
|
||||
result.value.i = exprtrue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPcmp(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
result.type = svt_int; // always an int returned
|
||||
|
||||
if(left.type == svt_string && right.type == svt_string)
|
||||
{
|
||||
result.value.i = !strcmp(left.string, right.string);
|
||||
return;
|
||||
}
|
||||
|
||||
// haleyjd: direct mobj comparison when both are mobj
|
||||
if(left.type == svt_mobj && right.type == svt_mobj)
|
||||
{
|
||||
// we can safely assume reference equivalency for
|
||||
// AActor's in all cases since they are static for the
|
||||
// duration of a level
|
||||
result.value.i = (left.value.mobj == right.value.mobj);
|
||||
return;
|
||||
}
|
||||
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
{
|
||||
result.value.i = (fixedvalue(left) == fixedvalue(right));
|
||||
return;
|
||||
}
|
||||
|
||||
result.value.i = (intvalue(left) == intvalue(right));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPnotcmp(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
OPcmp(result, start, n, stop);
|
||||
result.type = svt_int;
|
||||
result.value.i = !result.value.i;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPlessthan(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
result.type = svt_int;
|
||||
|
||||
// haleyjd: 8-17
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
result.value.i = (fixedvalue(left) < fixedvalue(right));
|
||||
else
|
||||
result.value.i = (intvalue(left) < intvalue(right));
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPgreaterthan(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
// haleyjd: 8-17
|
||||
result.type = svt_int;
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
result.value.i = (fixedvalue(left) > fixedvalue(right));
|
||||
else
|
||||
result.value.i = (intvalue(left) > intvalue(right));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPnot(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
EvaluateExpression(result, n+1, stop);
|
||||
|
||||
result.value.i = !intvalue(result);
|
||||
result.type = svt_int;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPplus(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
if (left.type == svt_string)
|
||||
{
|
||||
if (right.type == svt_string)
|
||||
{
|
||||
result.string.Format("%s%s", left.string.GetChars(), right.string.GetChars());
|
||||
}
|
||||
else if (right.type == svt_fixed)
|
||||
{
|
||||
result.string.Format("%s%4.4f", left.string.GetChars(), floatvalue(right));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.string.Format("%s%i", left.string.GetChars(), intvalue(right));
|
||||
}
|
||||
result.type = svt_string;
|
||||
}
|
||||
// haleyjd: 8-17
|
||||
else if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
{
|
||||
result.type = svt_fixed;
|
||||
result.value.f = fixedvalue(left) + fixedvalue(right);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) + intvalue(right);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPminus(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
// do they mean minus as in '-1' rather than '2-1'?
|
||||
if(start == n)
|
||||
{
|
||||
// kinda hack, hehe
|
||||
EvaluateExpression(right, n+1, stop);
|
||||
}
|
||||
else
|
||||
{
|
||||
evaluate_leftnright(start, n, stop);
|
||||
}
|
||||
|
||||
// haleyjd: 8-17
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
{
|
||||
result.type = svt_fixed;
|
||||
result.value.f = fixedvalue(left) - fixedvalue(right);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) - intvalue(right);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPmultiply(svalue_t &result,int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
// haleyjd: 8-17
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
{
|
||||
result.type = svt_fixed;
|
||||
result.value.f = FixedMul(fixedvalue(left), fixedvalue(right));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) * intvalue(right);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPdivide(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
// haleyjd: 8-17
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
{
|
||||
fixed_t fr;
|
||||
|
||||
if((fr = fixedvalue(right)) == 0)
|
||||
script_error("divide by zero\n");
|
||||
else
|
||||
{
|
||||
result.type = svt_fixed;
|
||||
result.value.f = FixedDiv(fixedvalue(left), fr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int ir;
|
||||
|
||||
if(!(ir = intvalue(right)))
|
||||
script_error("divide by zero\n");
|
||||
else
|
||||
{
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) / ir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPremainder(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
int ir;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
if(!(ir = intvalue(right)))
|
||||
script_error("divide by zero\n");
|
||||
else
|
||||
{
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) % ir;
|
||||
}
|
||||
}
|
||||
|
||||
/********** binary operators **************/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPor_bin(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) | intvalue(right);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPand_bin(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
result.type = svt_int;
|
||||
result.value.i = intvalue(left) & intvalue(right);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPnot_bin(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
EvaluateExpression(result, n+1, stop);
|
||||
|
||||
result.value.i = ~intvalue(result);
|
||||
result.type = svt_int;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPincrement(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
if(start == n) // ++n
|
||||
{
|
||||
DFsVariable *var;
|
||||
|
||||
var = Script->FindVariable(Tokens[stop]);
|
||||
if(!var)
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[stop]);
|
||||
}
|
||||
var->GetValue(result);
|
||||
|
||||
// haleyjd
|
||||
if(var->type != svt_fixed)
|
||||
{
|
||||
result.value.i = intvalue(result) + 1;
|
||||
result.type = svt_int;
|
||||
var->SetValue (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.value.f = fixedvalue(result) + FRACUNIT;
|
||||
result.type = svt_fixed;
|
||||
var->SetValue (result);
|
||||
}
|
||||
}
|
||||
else if(stop == n) // n++
|
||||
{
|
||||
svalue_t newvalue;
|
||||
DFsVariable *var;
|
||||
|
||||
var = Script->FindVariable(Tokens[start]);
|
||||
if(!var)
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[start]);
|
||||
}
|
||||
var->GetValue(result);
|
||||
|
||||
// haleyjd
|
||||
if(var->type != svt_fixed)
|
||||
{
|
||||
newvalue.type = svt_int;
|
||||
newvalue.value.i = intvalue(result) + 1;
|
||||
var->SetValue (newvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
newvalue.type = svt_fixed;
|
||||
newvalue.value.f = fixedvalue(result) + FRACUNIT;
|
||||
var->SetValue (newvalue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error("incorrect arguments to ++ operator\n");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPdecrement(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
if(start == n) // ++n
|
||||
{
|
||||
DFsVariable *var;
|
||||
|
||||
var = Script->FindVariable(Tokens[stop]);
|
||||
if(!var)
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[stop]);
|
||||
}
|
||||
var->GetValue(result);
|
||||
|
||||
// haleyjd
|
||||
if(var->type != svt_fixed)
|
||||
{
|
||||
result.value.i = intvalue(result) - 1;
|
||||
result.type = svt_int;
|
||||
var->SetValue (result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.value.f = fixedvalue(result) - FRACUNIT;
|
||||
result.type = svt_fixed;
|
||||
var->SetValue (result);
|
||||
}
|
||||
}
|
||||
else if(stop == n) // n++
|
||||
{
|
||||
svalue_t newvalue;
|
||||
DFsVariable *var;
|
||||
|
||||
var = Script->FindVariable(Tokens[start]);
|
||||
if(!var)
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[start]);
|
||||
}
|
||||
var->GetValue(result);
|
||||
|
||||
// haleyjd
|
||||
if(var->type != svt_fixed)
|
||||
{
|
||||
newvalue.type = svt_int;
|
||||
newvalue.value.i = intvalue(result) - 1;
|
||||
var->SetValue (newvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
newvalue.type = svt_fixed;
|
||||
newvalue.value.f = fixedvalue(result) - FRACUNIT;
|
||||
var->SetValue (newvalue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
script_error("incorrect arguments to ++ operator\n");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPlessthanorequal(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
result.type = svt_int;
|
||||
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
result.value.i = (fixedvalue(left) <= fixedvalue(right));
|
||||
else
|
||||
result.value.i = (intvalue(left) <= intvalue(right));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FParser::OPgreaterthanorequal(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
svalue_t left, right;
|
||||
|
||||
evaluate_leftnright(start, n, stop);
|
||||
|
||||
result.type = svt_int;
|
||||
|
||||
if(left.type == svt_fixed || right.type == svt_fixed)
|
||||
result.value.i = (fixedvalue(left) >= fixedvalue(right));
|
||||
else
|
||||
result.value.i = (intvalue(left) >= intvalue(right));
|
||||
}
|
||||
|
746
src/fragglescript/t_parse.cpp
Normal file
746
src/fragglescript/t_parse.cpp
Normal file
|
@ -0,0 +1,746 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
// Copyright(C) 2002-2008 Christoph Oelckers
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Parsing.
|
||||
//
|
||||
// Takes lines of code, or groups of lines and runs them.
|
||||
// The main core of FraggleScript
|
||||
//
|
||||
// By Simon Howard
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
/* includes ************************/
|
||||
#include <stdarg.h>
|
||||
#include "t_script.h"
|
||||
#include "s_sound.h"
|
||||
#include "v_text.h"
|
||||
#include "c_cvars.h"
|
||||
#include "i_system.h"
|
||||
|
||||
|
||||
CVAR(Bool, script_debug, false, 0)
|
||||
|
||||
/************ Divide into tokens **************/
|
||||
#define isnum(c) ( ((c)>='0' && (c)<='9') || (c)=='.')
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NextToken: end this token, go onto the next
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::NextToken()
|
||||
{
|
||||
if(Tokens[NumTokens-1][0] || TokenType[NumTokens-1]==string_)
|
||||
{
|
||||
NumTokens++;
|
||||
Tokens[NumTokens-1] = Tokens[NumTokens-2] + strlen(Tokens[NumTokens-2]) + 1;
|
||||
Tokens[NumTokens-1][0] = 0;
|
||||
}
|
||||
|
||||
// get to the next token, ignoring spaces, newlines,
|
||||
// useless chars, comments etc
|
||||
|
||||
while(1)
|
||||
{
|
||||
// empty whitespace
|
||||
if(*Rover && (*Rover==' ' || *Rover<32))
|
||||
{
|
||||
while((*Rover==' ' || *Rover<32) && *Rover) Rover++;
|
||||
}
|
||||
// end-of-script?
|
||||
if(!*Rover)
|
||||
{
|
||||
if(Tokens[0][0])
|
||||
{
|
||||
// line contains text, but no semicolon: an error
|
||||
script_error("missing ';'\n");
|
||||
}
|
||||
// empty line, end of command-list
|
||||
return;
|
||||
}
|
||||
break; // otherwise
|
||||
}
|
||||
|
||||
if(NumTokens>1 && *Rover == '(' && TokenType[NumTokens-2] == name_)
|
||||
TokenType[NumTokens-2] = function;
|
||||
|
||||
if(*Rover == '{' || *Rover == '}')
|
||||
{
|
||||
if(*Rover == '{')
|
||||
{
|
||||
BraceType = bracket_open;
|
||||
Section = Script->FindSectionStart(Rover);
|
||||
}
|
||||
else // closing brace
|
||||
{
|
||||
BraceType = bracket_close;
|
||||
Section = Script->FindSectionEnd(Rover);
|
||||
}
|
||||
if(!Section)
|
||||
{
|
||||
I_Error("section not found!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(*Rover == ':') // label
|
||||
{
|
||||
// ignore the label : reset
|
||||
NumTokens = 1;
|
||||
Tokens[0][0] = 0; TokenType[NumTokens-1] = name_;
|
||||
Rover++; // ignore
|
||||
}
|
||||
else if(*Rover == '\"')
|
||||
{
|
||||
TokenType[NumTokens-1] = string_;
|
||||
if(TokenType[NumTokens-2] == string_) NumTokens--; // join strings
|
||||
Rover++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TokenType[NumTokens-1] = isop(*Rover) ? operator_ : isnum(*Rover) ? number : name_;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// return an escape sequence (prefixed by a '\')
|
||||
// do not use all C escape sequences
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static char escape_sequence(char c)
|
||||
{
|
||||
if(c == 'n') return '\n';
|
||||
if(c == '\\') return '\\';
|
||||
if(c == '"') return '"';
|
||||
if(c == '?') return '?';
|
||||
if(c == 'a') return '\a'; // alert beep
|
||||
if(c == 't') return '\t'; //tab
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// add_char: add one character to the current token
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void add_char(char *tokn, char c)
|
||||
{
|
||||
char *out = tokn + strlen(tokn);
|
||||
|
||||
out[0] = c;
|
||||
out[1] = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// get_tokens.
|
||||
// Take a string, break it into tokens.
|
||||
//
|
||||
// individual tokens are stored inside the tokens[] array
|
||||
// tokentype is also used to hold the type for each token:
|
||||
//
|
||||
// name: a piece of text which starts with an alphabet letter.
|
||||
// probably a variable name. Some are converted into
|
||||
// function types later on in find_brackets
|
||||
// number: a number. like '12' or '1337'
|
||||
// operator: an operator such as '&&' or '+'. All FraggleScript
|
||||
// operators are either one character, or two character
|
||||
// (if 2 character, 2 of the same char or ending in '=')
|
||||
// string: a text string that was enclosed in quote "" marks in
|
||||
// the original text
|
||||
// unset: shouldn't ever end up being set really.
|
||||
// function: a function name (found in second stage parsing)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *FParser::GetTokens(char *s)
|
||||
{
|
||||
char *tokn = NULL;
|
||||
|
||||
Rover = s;
|
||||
NumTokens = 1;
|
||||
Tokens[0][0] = 0; TokenType[NumTokens-1] = name_;
|
||||
|
||||
Section = NULL; // default to no section found
|
||||
|
||||
NextToken();
|
||||
LineStart = Rover; // save the start
|
||||
|
||||
if(*Rover)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
tokn = Tokens[NumTokens-1];
|
||||
if(Section)
|
||||
{
|
||||
// a { or } section brace has been found
|
||||
break; // stop parsing now
|
||||
}
|
||||
else if(TokenType[NumTokens-1] != string_)
|
||||
{
|
||||
if(*Rover == ';') break; // check for end of command ';'
|
||||
}
|
||||
|
||||
switch(TokenType[NumTokens-1])
|
||||
{
|
||||
case unset:
|
||||
case string_:
|
||||
while(*Rover != '\"') // dedicated loop for speed
|
||||
{
|
||||
if(*Rover == '\\') // escape sequences
|
||||
{
|
||||
Rover++;
|
||||
if (*Rover>='0' && *Rover<='9')
|
||||
{
|
||||
add_char(tokn, TEXTCOLOR_ESCAPE);
|
||||
add_char(tokn, *Rover+'A'-'0');
|
||||
}
|
||||
else add_char(tokn, escape_sequence(*Rover));
|
||||
}
|
||||
else
|
||||
add_char(tokn, *Rover);
|
||||
Rover++;
|
||||
}
|
||||
Rover++;
|
||||
NextToken(); // end of this token
|
||||
continue;
|
||||
|
||||
case operator_:
|
||||
// all 2-character operators either end in '=' or
|
||||
// are 2 of the same character
|
||||
// do not allow 2-characters for brackets '(' ')'
|
||||
// which are still being considered as operators
|
||||
|
||||
// operators are only 2-char max, do not need
|
||||
// a seperate loop
|
||||
|
||||
if((*tokn && *Rover != '=' && *Rover!=*tokn) ||
|
||||
*tokn == '(' || *tokn == ')')
|
||||
{
|
||||
// end of operator
|
||||
NextToken();
|
||||
continue;
|
||||
}
|
||||
add_char(tokn, *Rover);
|
||||
break;
|
||||
|
||||
case number:
|
||||
|
||||
// haleyjd: 8-17
|
||||
// add while number chars are read
|
||||
|
||||
while(isnum(*Rover)) // dedicated loop
|
||||
add_char(tokn, *Rover++);
|
||||
NextToken();
|
||||
continue;
|
||||
|
||||
case name_:
|
||||
|
||||
// add the chars
|
||||
|
||||
while(!isop(*Rover)) // dedicated loop
|
||||
add_char(tokn, *Rover++);
|
||||
NextToken();
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Rover++;
|
||||
}
|
||||
}
|
||||
|
||||
// check for empty last token
|
||||
|
||||
if(!tokn || !tokn[0])
|
||||
{
|
||||
NumTokens = NumTokens - 1;
|
||||
}
|
||||
|
||||
Rover++;
|
||||
return Rover;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PrintTokens: add one character to the current token
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::PrintTokens() // DEBUG
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NumTokens; i++)
|
||||
{
|
||||
Printf("\n'%s' \t\t --", Tokens[i]);
|
||||
switch (TokenType[i])
|
||||
{
|
||||
case string_:
|
||||
Printf("string");
|
||||
break;
|
||||
case operator_:
|
||||
Printf("operator");
|
||||
break;
|
||||
case name_:
|
||||
Printf("name");
|
||||
break;
|
||||
case number:
|
||||
Printf("number");
|
||||
break;
|
||||
case unset:
|
||||
Printf("duh");
|
||||
break;
|
||||
case function:
|
||||
Printf("function name");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Printf("\n");
|
||||
if (Section)
|
||||
Printf("current section: offset %i\n", Section->start_index);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses a block of script code
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::Run(char *rover, char *data, char *end)
|
||||
{
|
||||
Rover = rover;
|
||||
try
|
||||
{
|
||||
PrevSection = NULL; // clear it
|
||||
|
||||
while(*Rover) // go through the script executing each statement
|
||||
{
|
||||
// past end of script?
|
||||
if(Rover > end)
|
||||
break;
|
||||
|
||||
PrevSection = Section; // store from prev. statement
|
||||
|
||||
// get the line and tokens
|
||||
GetTokens(Rover);
|
||||
|
||||
if(!NumTokens)
|
||||
{
|
||||
if(Section) // no tokens but a brace
|
||||
{
|
||||
// possible } at end of loop:
|
||||
// refer to spec.c
|
||||
spec_brace();
|
||||
}
|
||||
|
||||
continue; // continue to next statement
|
||||
}
|
||||
|
||||
if(script_debug) PrintTokens(); // debug
|
||||
RunStatement(); // run the statement
|
||||
}
|
||||
}
|
||||
catch (const CFsError &err)
|
||||
{
|
||||
ErrorMessage(err.msg);
|
||||
}
|
||||
catch (const CFsTerminator &)
|
||||
{
|
||||
// The script has signalled that it wants to be terminated in an orderly fashion.
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// decide what to do with it
|
||||
//
|
||||
// NB this stuff is a bit hardcoded:
|
||||
// it could be nicer really but i'm
|
||||
// aiming for speed
|
||||
//
|
||||
// if() and while() will be mistaken for functions
|
||||
// during token processing
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::RunStatement()
|
||||
{
|
||||
if(TokenType[0] == function)
|
||||
{
|
||||
if(!strcmp(Tokens[0], "if"))
|
||||
{
|
||||
Script->lastiftrue = spec_if();
|
||||
return;
|
||||
}
|
||||
else if(!strcmp(Tokens[0], "elseif"))
|
||||
{
|
||||
if(!PrevSection ||
|
||||
(PrevSection->type != st_if &&
|
||||
PrevSection->type != st_elseif))
|
||||
{
|
||||
script_error("elseif statement without if\n");
|
||||
return;
|
||||
}
|
||||
Script->lastiftrue = spec_elseif(Script->lastiftrue);
|
||||
return;
|
||||
}
|
||||
else if(!strcmp(Tokens[0], "else"))
|
||||
{
|
||||
if(!PrevSection ||
|
||||
(PrevSection->type != st_if &&
|
||||
PrevSection->type != st_elseif))
|
||||
{
|
||||
script_error("else statement without if\n");
|
||||
return;
|
||||
}
|
||||
spec_else(Script->lastiftrue);
|
||||
Script->lastiftrue = true;
|
||||
return;
|
||||
}
|
||||
else if(!strcmp(Tokens[0], "while"))
|
||||
{
|
||||
spec_while();
|
||||
return;
|
||||
}
|
||||
else if(!strcmp(Tokens[0], "for"))
|
||||
{
|
||||
spec_for();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(TokenType[0] == name_)
|
||||
{
|
||||
// NB: goto is a function so is not here
|
||||
|
||||
// Allow else without '()'
|
||||
if (!strcmp(Tokens[0], "else"))
|
||||
{
|
||||
if(!PrevSection ||
|
||||
(PrevSection->type != st_if &&
|
||||
PrevSection->type != st_elseif))
|
||||
{
|
||||
script_error("else statement without if\n");
|
||||
return;
|
||||
}
|
||||
spec_else(Script->lastiftrue);
|
||||
Script->lastiftrue = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// if a variable declaration, return now
|
||||
if(spec_variable()) return;
|
||||
}
|
||||
|
||||
// just a plain expression
|
||||
svalue_t scratch;
|
||||
EvaluateExpression(scratch,0, NumTokens-1);
|
||||
}
|
||||
|
||||
/***************** Evaluating Expressions ************************/
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// find a token, ignoring things in brackets
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FParser::FindOperator(int start, int stop, const char *value)
|
||||
{
|
||||
int i;
|
||||
int bracketlevel = 0;
|
||||
|
||||
for(i=start; i<=stop; i++)
|
||||
{
|
||||
// only interested in operators
|
||||
if(TokenType[i] != operator_) continue;
|
||||
|
||||
// use bracketlevel to check the number of brackets
|
||||
// which we are inside
|
||||
bracketlevel += Tokens[i][0]=='(' ? 1 :
|
||||
Tokens[i][0]==')' ? -1 : 0;
|
||||
|
||||
// only check when we are not in brackets
|
||||
if(!bracketlevel && !strcmp(value, Tokens[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// go through tokens the same as find_operator, but backwards
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FParser::FindOperatorBackwards(int start, int stop, const char *value)
|
||||
{
|
||||
int i;
|
||||
int bracketlevel = 0;
|
||||
|
||||
for(i=stop; i>=start; i--) // check backwards
|
||||
{
|
||||
// operators only
|
||||
|
||||
if(TokenType[i] != operator_) continue;
|
||||
|
||||
// use bracketlevel to check the number of brackets
|
||||
// which we are inside
|
||||
|
||||
bracketlevel += Tokens[i][0]=='(' ? -1 :
|
||||
Tokens[i][0]==')' ? 1 : 0;
|
||||
|
||||
// only check when we are not in brackets
|
||||
// if we find what we want, return it
|
||||
|
||||
if(!bracketlevel && !strcmp(value, Tokens[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// simple_evaluate is used once evalute_expression gets to the level
|
||||
// where it is evaluating just one token
|
||||
//
|
||||
// converts number tokens into svalue_ts and returns
|
||||
// the same with string tokens
|
||||
// name tokens are considered to be variables and
|
||||
// attempts are made to find the value of that variable
|
||||
// command tokens are executed (does not return a svalue_t)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::SimpleEvaluate(svalue_t &returnvar, int n)
|
||||
{
|
||||
DFsVariable *var;
|
||||
|
||||
switch(TokenType[n])
|
||||
{
|
||||
case string_:
|
||||
returnvar.type = svt_string;
|
||||
returnvar.string = Tokens[n];
|
||||
break;
|
||||
|
||||
case number:
|
||||
if(strchr(Tokens[n], '.'))
|
||||
{
|
||||
returnvar.type = svt_fixed;
|
||||
returnvar.value.f = (fixed_t)(atof(Tokens[n]) * FRACUNIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnvar.type = svt_int;
|
||||
returnvar.value.i = atoi(Tokens[n]);
|
||||
}
|
||||
break;
|
||||
|
||||
case name_:
|
||||
var = Script->FindVariable(Tokens[n]);
|
||||
if(!var)
|
||||
{
|
||||
script_error("unknown variable '%s'\n", Tokens[n]);
|
||||
}
|
||||
else var->GetValue(returnvar);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// pointless_brackets checks to see if there are brackets surrounding
|
||||
// an expression. eg. "(2+4)" is the same as just "2+4"
|
||||
//
|
||||
// because of the recursive nature of evaluate_expression, this function is
|
||||
// neccesary as evaluating expressions such as "2*(2+4)" will inevitably
|
||||
// lead to evaluating "(2+4)"
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::PointlessBrackets(int *start, int *stop)
|
||||
{
|
||||
int bracket_level, i;
|
||||
|
||||
// check that the start and end are brackets
|
||||
|
||||
while(Tokens[*start][0] == '(' && Tokens[*stop][0] == ')')
|
||||
{
|
||||
|
||||
bracket_level = 0;
|
||||
|
||||
// confirm there are pointless brackets..
|
||||
// if they are, bracket_level will only get to 0
|
||||
// at the last token
|
||||
// check up to <*stop rather than <=*stop to ignore
|
||||
// the last token
|
||||
|
||||
for(i = *start; i<*stop; i++)
|
||||
{
|
||||
if(TokenType[i] != operator_) continue; // ops only
|
||||
bracket_level += (Tokens[i][0] == '(');
|
||||
bracket_level -= (Tokens[i][0] == ')');
|
||||
if(bracket_level == 0) return; // stop if braces stop before end
|
||||
}
|
||||
|
||||
// move both brackets in
|
||||
|
||||
*start = *start + 1;
|
||||
*stop = *stop - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// evaluate_expresion is the basic function used to evaluate
|
||||
// a FraggleScript expression.
|
||||
// start and stop denote the tokens which are to be evaluated.
|
||||
//
|
||||
// works by recursion: it finds operators in the expression
|
||||
// (checking for each in turn), then splits the expression into
|
||||
// 2 parts, left and right of the operator found.
|
||||
// The handler function for that particular operator is then
|
||||
// called, which in turn calls evaluate_expression again to
|
||||
// evaluate each side. When it reaches the level of being asked
|
||||
// to evaluate just 1 token, it calls simple_evaluate
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::EvaluateExpression(svalue_t &result, int start, int stop)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
// possible pointless brackets
|
||||
if(TokenType[start] == operator_ && TokenType[stop] == operator_)
|
||||
PointlessBrackets(&start, &stop);
|
||||
|
||||
if(start == stop) // only 1 thing to evaluate
|
||||
{
|
||||
SimpleEvaluate(result, start);
|
||||
return;
|
||||
}
|
||||
|
||||
// go through each operator in order of precedence
|
||||
for(i=0; i<num_operators; i++)
|
||||
{
|
||||
// check backwards for the token. it has to be
|
||||
// done backwards for left-to-right reading: eg so
|
||||
// 5-3-2 is (5-3)-2 not 5-(3-2)
|
||||
|
||||
if (operators[i].direction==forward)
|
||||
{
|
||||
n = FindOperatorBackwards(start, stop, operators[i].string);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = FindOperator(start, stop, operators[i].string);
|
||||
}
|
||||
|
||||
if( n != -1)
|
||||
{
|
||||
// call the operator function and evaluate this chunk of tokens
|
||||
(this->*operators[i].handler)(result, start, n, stop);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(TokenType[start] == function)
|
||||
{
|
||||
EvaluateFunction(result, start, stop);
|
||||
return;
|
||||
}
|
||||
|
||||
// error ?
|
||||
{
|
||||
FString tempstr;
|
||||
|
||||
for(i=start; i<=stop; i++) tempstr << Tokens[i] << ' ';
|
||||
script_error("couldnt evaluate expression: %s\n",tempstr.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// intercepts an error message and inserts script/line information
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::ErrorMessage(FString msg)
|
||||
{
|
||||
int linenum = 0;
|
||||
|
||||
// find the line number
|
||||
if(Rover >= Script->data && Rover <= Script->data+Script->len)
|
||||
{
|
||||
char *temp;
|
||||
for(temp = Script->data; temp<LineStart; temp++)
|
||||
if(*temp == '\n') linenum++; // count EOLs
|
||||
}
|
||||
|
||||
//lineinfo.Format("Script %d, line %d: ", Script->scriptnum, linenum);
|
||||
I_Error("Script %d, line %d: %s", Script->scriptnum, linenum, msg.GetChars());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// throws an error message
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void script_error(const char *s, ...)
|
||||
{
|
||||
FString composed;
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
composed.VFormat(s, args);
|
||||
throw CFsError(composed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// EOF
|
445
src/fragglescript/t_prepro.cpp
Normal file
445
src/fragglescript/t_prepro.cpp
Normal file
|
@ -0,0 +1,445 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Preprocessor.
|
||||
//
|
||||
// The preprocessor must be called when the script is first loaded.
|
||||
// It performs 2 functions:
|
||||
// 1: blank out comments (which could be misinterpreted)
|
||||
// 2: makes a list of all the sections held within {} braces
|
||||
// 3: 'dry' runs the script: goes thru each statement and
|
||||
// sets the types of all the DFsSection's in the script
|
||||
// 4: Saves locations of all goto() labels
|
||||
//
|
||||
// the system of DFsSection's is pretty horrible really, but it works
|
||||
// and its probably the only way i can think of of saving scripts
|
||||
// half-way thru running
|
||||
//
|
||||
// By Simon Howard
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
/* includes ************************/
|
||||
|
||||
#include "t_script.h"
|
||||
#include "i_system.h"
|
||||
#include "w_wad.h"
|
||||
#include "farchive.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// {} sections
|
||||
//
|
||||
// during preprocessing all of the {} sections
|
||||
// are found. these are stored in a hash table
|
||||
// according to their offset in the script.
|
||||
// functions here deal with creating new sections
|
||||
// and finding them from a given offset.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(DFsSection)
|
||||
DECLARE_POINTER(next)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsSection::Serialize(FArchive &ar)
|
||||
{
|
||||
Super::Serialize(ar);
|
||||
ar << type << start_index << end_index << loop_index << next;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *DFsScript::SectionStart(const DFsSection *sec)
|
||||
{
|
||||
return data + sec->start_index;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *DFsScript::SectionEnd(const DFsSection *sec)
|
||||
{
|
||||
return data + sec->end_index;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *DFsScript::SectionLoop(const DFsSection *sec)
|
||||
{
|
||||
return data + sec->loop_index;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::ClearSections()
|
||||
{
|
||||
for(int i=0;i<SECTIONSLOTS;i++)
|
||||
{
|
||||
DFsSection * var = sections[i];
|
||||
while(var)
|
||||
{
|
||||
DFsSection *next = var->next;
|
||||
var->Destroy();
|
||||
var = next;
|
||||
}
|
||||
sections[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// create section
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsSection *DFsScript::NewSection(const char *brace)
|
||||
{
|
||||
int n = section_hash(brace);
|
||||
DFsSection *newsec = new DFsSection;
|
||||
|
||||
newsec->start_index = MakeIndex(brace);
|
||||
newsec->next = sections[n];
|
||||
sections[n] = newsec;
|
||||
GC::WriteBarrier(this, newsec);
|
||||
return newsec;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// find a Section from the location of the starting { brace
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsSection *DFsScript::FindSectionStart(const char *brace)
|
||||
{
|
||||
int n = section_hash(brace);
|
||||
DFsSection *current = sections[n];
|
||||
|
||||
// use the hash table: check the appropriate hash chain
|
||||
|
||||
while(current)
|
||||
{
|
||||
if(SectionStart(current) == brace) return current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return NULL; // not found
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// find a Section from the location of the closing } brace
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsSection *DFsScript::FindSectionEnd(const char *brace)
|
||||
{
|
||||
int n;
|
||||
|
||||
// hash table is no use, they are hashed according to
|
||||
// the offset of the starting brace
|
||||
|
||||
// we have to go through every entry to find from the
|
||||
// ending brace
|
||||
|
||||
for(n=0; n<SECTIONSLOTS; n++) // check all sections in all chains
|
||||
{
|
||||
DFsSection *current = sections[n];
|
||||
|
||||
while(current)
|
||||
{
|
||||
if(SectionEnd(current) == brace) return current; // found it
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
return NULL; // not found
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// preproocessor main loop
|
||||
//
|
||||
// This works by recursion. when a { opening
|
||||
// brace is found, another instance of the
|
||||
// function is called for the data inside
|
||||
// the {} section.
|
||||
// At the same time, the sections are noted
|
||||
// down and hashed. Goto() labels are noted
|
||||
// down, and comments are blanked out
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *DFsScript::ProcessFindChar(char *datap, char find)
|
||||
{
|
||||
while(*datap)
|
||||
{
|
||||
if(*datap==find) return datap;
|
||||
if(*datap=='\"') // found a quote: ignore stuff in it
|
||||
{
|
||||
datap++;
|
||||
while(*datap && *datap != '\"')
|
||||
{
|
||||
// escape sequence ?
|
||||
if(*datap=='\\') datap++;
|
||||
datap++;
|
||||
}
|
||||
// error: end of script in a constant
|
||||
if(!*datap) return NULL;
|
||||
}
|
||||
|
||||
// comments: blank out
|
||||
|
||||
if(*datap=='/' && *(datap+1)=='*') // /* -- */ comment
|
||||
{
|
||||
while(*datap && (*datap != '*' || *(datap+1) != '/') )
|
||||
{
|
||||
*datap=' '; datap++;
|
||||
}
|
||||
if(*datap)
|
||||
*datap = *(datap+1) = ' '; // blank the last bit
|
||||
else
|
||||
{
|
||||
// script terminated in comment
|
||||
script_error("script terminated inside comment\n");
|
||||
}
|
||||
}
|
||||
if(*datap=='/' && *(datap+1)=='/') // // -- comment
|
||||
{
|
||||
while(*datap != '\n')
|
||||
{
|
||||
*datap=' '; datap++; // blank out
|
||||
}
|
||||
}
|
||||
|
||||
/********** labels ****************/
|
||||
|
||||
// labels are also found during the
|
||||
// preprocessing. these are of the form
|
||||
//
|
||||
// label_name:
|
||||
//
|
||||
// and are used for the goto function.
|
||||
// goto labels are stored as variables.
|
||||
|
||||
if(*datap==':' && scriptnum != -1) // not in global scripts
|
||||
{
|
||||
char *labelptr = datap-1;
|
||||
|
||||
while(!isop(*labelptr)) labelptr--;
|
||||
|
||||
FString labelname(labelptr+1, strcspn(labelptr+1, ":"));
|
||||
|
||||
if (labelname.Len() == 0)
|
||||
{
|
||||
Printf(PRINT_BOLD,"Script %d: ':' encountrered in incorrect position!\n",scriptnum);
|
||||
}
|
||||
|
||||
DFsVariable *newlabel = NewVariable(labelname, svt_label);
|
||||
newlabel->value.i = MakeIndex(labelptr);
|
||||
}
|
||||
|
||||
if(*datap=='{') // { -- } sections: add 'em
|
||||
{
|
||||
DFsSection *newsec = NewSection(datap);
|
||||
|
||||
newsec->type = st_empty;
|
||||
// find the ending } and save
|
||||
char * theend = ProcessFindChar(datap+1, '}');
|
||||
if(!theend)
|
||||
{ // brace not found
|
||||
// This is fatal because it will cause a crash later
|
||||
// if the game isn't terminated.
|
||||
I_Error("Script %d: section error: no ending brace\n", scriptnum);
|
||||
}
|
||||
|
||||
newsec->end_index = MakeIndex(theend);
|
||||
// continue from the end of the section
|
||||
datap = theend;
|
||||
}
|
||||
datap++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// second stage parsing
|
||||
//
|
||||
// second stage preprocessing considers the script
|
||||
// in terms of tokens rather than as plain data.
|
||||
//
|
||||
// we 'dry' run the script: go thru each statement and
|
||||
// collect types for Sections
|
||||
//
|
||||
// this is an important thing to do, it cannot be done
|
||||
// at runtime for 2 reasons:
|
||||
// 1. gotos() jumping inside loops will pass thru
|
||||
// the end of the loop
|
||||
// 2. savegames. loading a script saved inside a
|
||||
// loop will let it pass thru the loop
|
||||
//
|
||||
// this is basically a cut-down version of the normal
|
||||
// parsing loop.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::DryRunScript()
|
||||
{
|
||||
char *end = data + len;
|
||||
char *rover = data;
|
||||
|
||||
// allocate space for the tokens
|
||||
FParser parse(this);
|
||||
try
|
||||
{
|
||||
while(rover < end && *rover)
|
||||
{
|
||||
rover = parse.GetTokens(rover);
|
||||
|
||||
if(!parse.NumTokens) continue;
|
||||
|
||||
if(parse.Section && parse.TokenType[0] == function)
|
||||
{
|
||||
if(!strcmp(parse.Tokens[0], "if"))
|
||||
{
|
||||
parse.Section->type = st_if;
|
||||
continue;
|
||||
}
|
||||
else if(!strcmp(parse.Tokens[0], "elseif")) // haleyjd: SoM's else code
|
||||
{
|
||||
parse.Section->type = st_elseif;
|
||||
continue;
|
||||
}
|
||||
else if(!strcmp(parse.Tokens[0], "else"))
|
||||
{
|
||||
parse.Section->type = st_else;
|
||||
continue;
|
||||
}
|
||||
else if(!strcmp(parse.Tokens[0], "while") ||
|
||||
!strcmp(parse.Tokens[0], "for"))
|
||||
{
|
||||
parse.Section->type = st_loop;
|
||||
parse.Section->loop_index = MakeIndex(parse.LineStart);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CFsError err)
|
||||
{
|
||||
parse.ErrorMessage(err.msg);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// main preprocess function
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::Preprocess()
|
||||
{
|
||||
len = (int)strlen(data);
|
||||
ProcessFindChar(data, 0); // fill in everything
|
||||
DryRunScript();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FraggleScript allows 'including' of other lumps.
|
||||
// we divert input from the current script (normally
|
||||
// levelscript) to a seperate lump. This of course
|
||||
// first needs to be preprocessed to remove comments
|
||||
// etc.
|
||||
//
|
||||
// parse an 'include' lump
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::ParseInclude(char *lumpname)
|
||||
{
|
||||
int lumpnum;
|
||||
char *lump;
|
||||
|
||||
if((lumpnum = Wads.CheckNumForName(lumpname)) == -1)
|
||||
{
|
||||
I_Error("include lump '%s' not found!\n", lumpname);
|
||||
return;
|
||||
}
|
||||
|
||||
int lumplen=Wads.LumpLength(lumpnum);
|
||||
lump=new char[lumplen+10];
|
||||
Wads.ReadLump(lumpnum,lump);
|
||||
|
||||
lump[lumplen]=0;
|
||||
|
||||
// preprocess the include
|
||||
// we assume that it does not include sections or labels or
|
||||
// other nasty things
|
||||
ProcessFindChar(lump, 0);
|
||||
|
||||
// now parse the lump
|
||||
FParser parse(this);
|
||||
parse.Run(lump, lump, lump+lumplen);
|
||||
|
||||
// free the lump
|
||||
delete[] lump;
|
||||
}
|
||||
|
725
src/fragglescript/t_script.cpp
Normal file
725
src/fragglescript/t_script.cpp
Normal file
|
@ -0,0 +1,725 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
// Copyright(C) 2005-2008 Christoph Oelckers
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// scripting.
|
||||
//
|
||||
// delayed scripts, running scripts, console cmds etc in here
|
||||
// the interface between FraggleScript and the rest of the game
|
||||
//
|
||||
// By Simon Howard
|
||||
//
|
||||
// (completely redone and cleaned up in 2008 by Christoph Oelckers)
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
#include "r_local.h"
|
||||
#include "t_script.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_keys.h"
|
||||
#include "d_player.h"
|
||||
#include "p_spec.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "i_system.h"
|
||||
#include "doomerrors.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// global variables
|
||||
// These two are the last remaining ones:
|
||||
// - The global script contains static data so it must be global
|
||||
// - The trigger is referenced by a global variable. However, it is set
|
||||
// each time a script is started so that's not a problem.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsScript *global_script;
|
||||
AActor *trigger_obj;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#define DECLARE_16_POINTERS(v, i) \
|
||||
DECLARE_POINTER(v[i]) \
|
||||
DECLARE_POINTER(v[i+1]) \
|
||||
DECLARE_POINTER(v[i+2]) \
|
||||
DECLARE_POINTER(v[i+3]) \
|
||||
DECLARE_POINTER(v[i+4]) \
|
||||
DECLARE_POINTER(v[i+5]) \
|
||||
DECLARE_POINTER(v[i+6]) \
|
||||
DECLARE_POINTER(v[i+7]) \
|
||||
DECLARE_POINTER(v[i+8]) \
|
||||
DECLARE_POINTER(v[i+9]) \
|
||||
DECLARE_POINTER(v[i+10]) \
|
||||
DECLARE_POINTER(v[i+11]) \
|
||||
DECLARE_POINTER(v[i+12]) \
|
||||
DECLARE_POINTER(v[i+13]) \
|
||||
DECLARE_POINTER(v[i+14]) \
|
||||
DECLARE_POINTER(v[i+15]) \
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(DFsScript)
|
||||
DECLARE_POINTER(parent)
|
||||
DECLARE_POINTER(trigger)
|
||||
DECLARE_16_POINTERS(sections, 0)
|
||||
DECLARE_POINTER(sections[16])
|
||||
DECLARE_16_POINTERS(variables, 0)
|
||||
DECLARE_16_POINTERS(children, 0)
|
||||
DECLARE_16_POINTERS(children, 16)
|
||||
DECLARE_16_POINTERS(children, 32)
|
||||
DECLARE_16_POINTERS(children, 48)
|
||||
DECLARE_16_POINTERS(children, 64)
|
||||
DECLARE_16_POINTERS(children, 80)
|
||||
DECLARE_16_POINTERS(children, 96)
|
||||
DECLARE_16_POINTERS(children, 112)
|
||||
DECLARE_16_POINTERS(children, 128)
|
||||
DECLARE_16_POINTERS(children, 144)
|
||||
DECLARE_16_POINTERS(children, 160)
|
||||
DECLARE_16_POINTERS(children, 176)
|
||||
DECLARE_16_POINTERS(children, 192)
|
||||
DECLARE_16_POINTERS(children, 208)
|
||||
DECLARE_16_POINTERS(children, 224)
|
||||
DECLARE_16_POINTERS(children, 240)
|
||||
DECLARE_POINTER(children[256])
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::ClearChildren()
|
||||
{
|
||||
int j;
|
||||
for(j=0;j<MAXSCRIPTS;j++) if (children[j])
|
||||
{
|
||||
children[j]->Destroy();
|
||||
children[j]=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsScript::DFsScript()
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<SECTIONSLOTS; i++) sections[i] = NULL;
|
||||
for(i=0; i<VARIABLESLOTS; i++) variables[i] = NULL;
|
||||
for(i=0; i<MAXSCRIPTS; i++) children[i] = NULL;
|
||||
|
||||
data = NULL;
|
||||
scriptnum = -1;
|
||||
len = 0;
|
||||
parent = NULL;
|
||||
trigger = NULL;
|
||||
lastiftrue = false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::Destroy()
|
||||
{
|
||||
ClearVariables(true);
|
||||
ClearSections();
|
||||
ClearChildren();
|
||||
parent = NULL;
|
||||
if (data != NULL) delete [] data;
|
||||
data = NULL;
|
||||
parent = NULL;
|
||||
trigger = NULL;
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::Serialize(FArchive &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
// don't save a reference to the global script
|
||||
if (parent == global_script) parent = NULL;
|
||||
|
||||
arc << data << scriptnum << len << parent << trigger << lastiftrue;
|
||||
for(int i=0; i< SECTIONSLOTS; i++) arc << sections[i];
|
||||
for(int i=0; i< VARIABLESLOTS; i++) arc << variables[i];
|
||||
for(int i=0; i< MAXSCRIPTS; i++) arc << children[i];
|
||||
|
||||
if (parent == NULL) parent = global_script;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// run_script
|
||||
//
|
||||
// the function called by t_script.c
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::ParseScript(char *position)
|
||||
{
|
||||
if (position == NULL)
|
||||
{
|
||||
lastiftrue = false;
|
||||
position = data;
|
||||
}
|
||||
|
||||
// check for valid position
|
||||
if(position < data || position > data+len)
|
||||
{
|
||||
Printf("script %d: trying to continue from point outside script!\n", scriptnum);
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_obj = trigger; // set trigger
|
||||
|
||||
try
|
||||
{
|
||||
FParser parse(this);
|
||||
parse.Run(position, data, data + len);
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
Printf ("%s\n", err.GetMessage());
|
||||
}
|
||||
|
||||
// dont clear global vars!
|
||||
if(scriptnum != -1) ClearVariables(); // free variables
|
||||
|
||||
// haleyjd
|
||||
lastiftrue = false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Running Scripts
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(DRunningScript)
|
||||
DECLARE_POINTER(prev)
|
||||
DECLARE_POINTER(next)
|
||||
DECLARE_POINTER(trigger)
|
||||
DECLARE_16_POINTERS(variables, 0)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DRunningScript::DRunningScript(AActor *trigger, DFsScript *owner, int index)
|
||||
{
|
||||
prev = next = NULL;
|
||||
script = owner;
|
||||
GC::WriteBarrier(this, script);
|
||||
save_point = index;
|
||||
wait_type = wt_none;
|
||||
wait_data = 0;
|
||||
|
||||
this->trigger = trigger;
|
||||
if (owner == NULL)
|
||||
{
|
||||
for(int i=0; i< VARIABLESLOTS; i++) variables[i] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// save the script variables
|
||||
for(int i=0; i<VARIABLESLOTS; i++)
|
||||
{
|
||||
variables[i] = owner->variables[i];
|
||||
|
||||
if (index == 0) // we are starting another Script:
|
||||
{
|
||||
// remove all the variables from the script variable list
|
||||
// we only start with the basic labels
|
||||
while(variables[i] && variables[i]->type != svt_label)
|
||||
variables[i] = variables[i]->next;
|
||||
}
|
||||
else // a script is being halted
|
||||
{
|
||||
// remove all the variables from the script variable list
|
||||
// to prevent them being removed when the script stops
|
||||
while(owner->variables[i] && owner->variables[i]->type != svt_label)
|
||||
owner->variables[i] = owner->variables[i]->next;
|
||||
|
||||
GC::WriteBarrier(owner, owner->variables[i]);
|
||||
}
|
||||
|
||||
GC::WriteBarrier(this, variables[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DRunningScript::Destroy()
|
||||
{
|
||||
int i;
|
||||
DFsVariable *current, *next;
|
||||
|
||||
for(i=0; i<VARIABLESLOTS; i++)
|
||||
{
|
||||
current = variables[i];
|
||||
|
||||
// go thru this chain
|
||||
while(current)
|
||||
{
|
||||
next = current->next; // save for after freeing
|
||||
current->Destroy();
|
||||
current = next; // go to next in chain
|
||||
}
|
||||
variables[i] = NULL;
|
||||
}
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DRunningScript::Serialize(FArchive &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
|
||||
arc << script << save_point << wait_type << wait_data << prev << next << trigger;
|
||||
for(int i=0; i< VARIABLESLOTS; i++) arc << variables[i];
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The main thinker
|
||||
//
|
||||
//==========================================================================
|
||||
IMPLEMENT_POINTY_CLASS(DFraggleThinker)
|
||||
DECLARE_POINTER(RunningScripts)
|
||||
DECLARE_POINTER(LevelScript)
|
||||
END_POINTERS
|
||||
|
||||
TObjPtr<DFraggleThinker> DFraggleThinker::ActiveThinker;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFraggleThinker::DFraggleThinker()
|
||||
: DThinker(STAT_SCRIPTS)
|
||||
{
|
||||
if (ActiveThinker)
|
||||
{
|
||||
I_Error ("Only one FraggleThinker is allowed to exist at a time.\nCheck your code.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveThinker = this;
|
||||
RunningScripts = new DRunningScript;
|
||||
LevelScript = new DFsScript;
|
||||
LevelScript->parent = global_script;
|
||||
GC::WriteBarrier(this, RunningScripts);
|
||||
GC::WriteBarrier(this, LevelScript);
|
||||
nocheckposition = false;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::Destroy()
|
||||
{
|
||||
DRunningScript *p = RunningScripts;
|
||||
while (p)
|
||||
{
|
||||
DRunningScript *q = p;
|
||||
p = p->next;
|
||||
q->prev = q->next = NULL;
|
||||
q->Destroy();
|
||||
}
|
||||
RunningScripts = NULL;
|
||||
|
||||
LevelScript->Destroy();
|
||||
LevelScript = NULL;
|
||||
|
||||
SpawnedThings.Clear();
|
||||
ActiveThinker = NULL;
|
||||
Super::Destroy();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::Serialize(FArchive &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
arc << LevelScript << RunningScripts << SpawnedThings << nocheckposition;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PAUSING SCRIPTS
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DFraggleThinker::wait_finished(DRunningScript *script)
|
||||
{
|
||||
switch(script->wait_type)
|
||||
{
|
||||
case wt_none: return true; // uh? hehe
|
||||
case wt_scriptwait: // waiting for script to finish
|
||||
{
|
||||
DRunningScript *current;
|
||||
for(current = RunningScripts->next; current; current = current->next)
|
||||
{
|
||||
if(current == script) continue; // ignore this script
|
||||
if(current->script->scriptnum == script->wait_data)
|
||||
return false; // script still running
|
||||
}
|
||||
return true; // can continue now
|
||||
}
|
||||
|
||||
case wt_delay: // just count down
|
||||
{
|
||||
return --script->wait_data <= 0;
|
||||
}
|
||||
|
||||
case wt_tagwait:
|
||||
{
|
||||
int secnum = -1;
|
||||
|
||||
while ((secnum = P_FindSectorFromTag(script->wait_data, secnum)) >= 0)
|
||||
{
|
||||
sector_t *sec = §ors[secnum];
|
||||
if(sec->floordata || sec->ceilingdata || sec->lightingdata)
|
||||
return false; // not finished
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case wt_scriptwaitpre: // haleyjd - wait for script to start
|
||||
{
|
||||
DRunningScript *current;
|
||||
for(current = RunningScripts->next; current; current=current->next)
|
||||
{
|
||||
if(current == script) continue; // ignore this script
|
||||
if(current->script->scriptnum == script->wait_data)
|
||||
return true; // script is now running
|
||||
}
|
||||
return false; // no running instances found
|
||||
}
|
||||
|
||||
default: return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::Tick()
|
||||
{
|
||||
DRunningScript *current, *next;
|
||||
int i;
|
||||
|
||||
current = RunningScripts->next;
|
||||
|
||||
while(current)
|
||||
{
|
||||
if(wait_finished(current))
|
||||
{
|
||||
// copy out the script variables from the
|
||||
// runningscript
|
||||
|
||||
for(i=0; i<VARIABLESLOTS; i++)
|
||||
{
|
||||
current->script->variables[i] = current->variables[i];
|
||||
GC::WriteBarrier(current->script, current->variables[i]);
|
||||
current->variables[i] = NULL;
|
||||
}
|
||||
current->script->trigger = current->trigger; // copy trigger
|
||||
|
||||
// unhook from chain
|
||||
current->prev->next = current->next;
|
||||
GC::WriteBarrier(current->prev, current->next);
|
||||
if(current->next)
|
||||
{
|
||||
current->next->prev = current->prev;
|
||||
GC::WriteBarrier(current->next, current->prev);
|
||||
}
|
||||
next = current->next; // save before freeing
|
||||
|
||||
// continue the script
|
||||
current->script->ParseScript (current->script->data + current->save_point);
|
||||
|
||||
// free
|
||||
current->Destroy();
|
||||
}
|
||||
else
|
||||
next = current->next;
|
||||
current = next; // continue to next in chain
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// We have to mark the SpawnedThings array manually because it's not
|
||||
// in the list of declared pointers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t DFraggleThinker::PropagateMark()
|
||||
{
|
||||
for(unsigned i=0;i<SpawnedThings.Size();i++)
|
||||
{
|
||||
GC::Mark(SpawnedThings[i]);
|
||||
}
|
||||
return Super::PropagateMark();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Again we have to handle the SpawnedThings array manually because
|
||||
// it's not in the list of declared pointers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld)
|
||||
{
|
||||
size_t changed = Super::PointerSubstitution(old, notOld);
|
||||
for(unsigned i=0;i<SpawnedThings.Size();i++)
|
||||
{
|
||||
if (SpawnedThings[i] == static_cast<AActor*>(old))
|
||||
{
|
||||
SpawnedThings[i] = static_cast<AActor*>(notOld);
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Adds a running script to the list of running scripts
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFraggleThinker::AddRunningScript(DRunningScript *runscr)
|
||||
{
|
||||
runscr->next = RunningScripts->next;
|
||||
GC::WriteBarrier(runscr, RunningScripts->next);
|
||||
|
||||
runscr->prev = RunningScripts;
|
||||
GC::WriteBarrier(runscr, RunningScripts);
|
||||
|
||||
runscr->prev->next = runscr;
|
||||
GC::WriteBarrier(runscr->prev, runscr);
|
||||
|
||||
if(runscr->next)
|
||||
{
|
||||
runscr->next->prev = runscr;
|
||||
GC::WriteBarrier(runscr->next, runscr);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void T_PreprocessScripts()
|
||||
{
|
||||
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
|
||||
if (th)
|
||||
{
|
||||
// run the levelscript first
|
||||
// get the other scripts
|
||||
|
||||
// levelscript started by player 0 'superplayer'
|
||||
th->LevelScript->trigger = players[0].mo;
|
||||
|
||||
th->LevelScript->Preprocess();
|
||||
th->LevelScript->ParseScript();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool RunScript(int snum, AActor * t_trigger)
|
||||
{
|
||||
DFraggleThinker *th = DFraggleThinker::ActiveThinker;
|
||||
if (th)
|
||||
{
|
||||
// [CO] It is far too dangerous to start the script right away.
|
||||
// Better queue it for execution for the next time
|
||||
// the runningscripts are checked.
|
||||
|
||||
if(snum < 0 || snum >= MAXSCRIPTS) return false;
|
||||
|
||||
DFsScript *script = th->LevelScript->children[snum];
|
||||
if(!script) return false;
|
||||
|
||||
DRunningScript *runscr = new DRunningScript(t_trigger, script, 0);
|
||||
// hook into chain at start
|
||||
th->AddRunningScript(runscr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int LS_FS_Execute (line_t *ln, AActor *it, bool backSide,
|
||||
int arg0, int arg1, int arg2, int arg3, int arg4)
|
||||
// FS_Execute(script#,firstsideonly,lock,msgtype)
|
||||
{
|
||||
if (arg1 && ln && backSide) return false;
|
||||
if (arg2!=0 && !P_CheckKeys(it, arg2, !!arg3)) return false;
|
||||
return RunScript(arg0,it);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FS_Close()
|
||||
{
|
||||
int i;
|
||||
DFsVariable *current, *next;
|
||||
|
||||
// we have to actually delete the global variables if we don't want
|
||||
// to get them reported as memory leaks.
|
||||
for(i=0; i<VARIABLESLOTS; i++)
|
||||
{
|
||||
current = global_script->variables[i];
|
||||
|
||||
while(current)
|
||||
{
|
||||
next = current->next; // save for after freeing
|
||||
|
||||
current->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete current;
|
||||
current = next; // go to next in chain
|
||||
}
|
||||
}
|
||||
GC::DelSoftRoot(global_script);
|
||||
global_script->ObjectFlags |= OF_YesReallyDelete;
|
||||
delete global_script;
|
||||
}
|
||||
|
||||
void T_Init()
|
||||
{
|
||||
void init_functions();
|
||||
|
||||
if (global_script == NULL)
|
||||
{
|
||||
// I'd rather link the special here than make another source file depend on FS!
|
||||
LineSpecials[FS_Execute]=LS_FS_Execute;
|
||||
global_script = new DFsScript;
|
||||
GC::AddSoftRoot(global_script);
|
||||
init_functions();
|
||||
atterm(FS_Close);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(fpuke)
|
||||
{
|
||||
int argc = argv.argc();
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
Printf (" fpuke <script>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
RunScript(atoi(argv[1]), players[consoleplayer].mo);
|
||||
}
|
||||
}
|
698
src/fragglescript/t_script.h
Normal file
698
src/fragglescript/t_script.h
Normal file
|
@ -0,0 +1,698 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
// Copyright(C) 2002-2008 Christoph Oelckers
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __T_SCRIPT_H__
|
||||
#define __T_SCRIPT_H__
|
||||
|
||||
#include "p_setup.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "m_fixed.h"
|
||||
#include "actor.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// This pragma saves 8kb of wasted code.
|
||||
#pragma pointers_to_members( full_generality, single_inheritance )
|
||||
#endif
|
||||
|
||||
class DRunningScript;
|
||||
|
||||
|
||||
|
||||
inline bool isop(int c)
|
||||
{
|
||||
return !( ( (c)<='Z' && (c)>='A') || ( (c)<='z' && (c)>='a') ||
|
||||
( (c)<='9' && (c)>='0') || ( (c)=='_') );
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
svt_string,
|
||||
svt_int,
|
||||
svt_mobj, // a map object
|
||||
svt_function, // functions are stored as variables
|
||||
svt_label, // labels for goto calls are variables
|
||||
svt_const, // const
|
||||
svt_fixed, // haleyjd: fixed-point int - 8-17 std
|
||||
svt_pInt, // pointer to game int
|
||||
svt_pMobj, // pointer to game mobj
|
||||
svt_linespec, // line special (can be used as both function and constant)
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct svalue_t
|
||||
{
|
||||
int type;
|
||||
FString string;
|
||||
union
|
||||
{
|
||||
int i;
|
||||
fixed_t f; // haleyjd: 8-17
|
||||
AActor *mobj;
|
||||
} value;
|
||||
|
||||
svalue_t()
|
||||
{
|
||||
type = svt_int;
|
||||
value.i = 0;
|
||||
}
|
||||
|
||||
svalue_t(const svalue_t & other)
|
||||
{
|
||||
type = other.type;
|
||||
string = other.string;
|
||||
value = other.value;
|
||||
}
|
||||
};
|
||||
|
||||
int intvalue(const svalue_t & v);
|
||||
fixed_t fixedvalue(const svalue_t & v);
|
||||
float floatvalue(const svalue_t & v);
|
||||
const char *stringvalue(const svalue_t & v);
|
||||
AActor *actorvalue(const svalue_t &svalue);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// varoius defines collected in a nicer manner
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum
|
||||
{
|
||||
VARIABLESLOTS = 16,
|
||||
SECTIONSLOTS = 17,
|
||||
T_MAXTOKENS = 256,
|
||||
TOKENLENGTH = 128,
|
||||
MAXARGS = 128,
|
||||
MAXSCRIPTS = 257,
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One variable
|
||||
//
|
||||
//==========================================================================
|
||||
struct FParser;
|
||||
|
||||
struct DFsVariable : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DFsVariable, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
public:
|
||||
FString Name;
|
||||
TObjPtr<DFsVariable> next; // for hashing
|
||||
|
||||
int type; // svt_string or svt_int: same as in svalue_t
|
||||
FString string;
|
||||
TObjPtr<AActor> actor;
|
||||
|
||||
union value_t
|
||||
{
|
||||
SDWORD i;
|
||||
fixed_t fixed; // haleyjd: fixed-point
|
||||
|
||||
// the following are only used in the global script so we don't need to bother with them
|
||||
// when serializing variables.
|
||||
int *pI; // pointer to game int
|
||||
AActor **pMobj; // pointer to game obj
|
||||
void (FParser::*handler)(); // for functions
|
||||
const FLineSpecial *ls;
|
||||
} value;
|
||||
|
||||
public:
|
||||
|
||||
DFsVariable(const char *_name = "");
|
||||
|
||||
void GetValue(svalue_t &result);
|
||||
void SetValue(const svalue_t &newvalue);
|
||||
void Serialize(FArchive &ar);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// hash the variables for speed: this is the hashkey
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
inline int variable_hash(const char *n)
|
||||
{
|
||||
return
|
||||
(n[0]? ( ( n[0] + n[1] +
|
||||
(n[1] ? n[2] +
|
||||
(n[2] ? n[3] : 0) : 0) ) % VARIABLESLOTS ) :0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Sections
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum // section types
|
||||
{
|
||||
st_empty, // empty {} braces
|
||||
st_if,
|
||||
st_elseif,
|
||||
st_else,
|
||||
st_loop,
|
||||
};
|
||||
|
||||
struct DFsSection : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DFsSection, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
int type;
|
||||
int start_index;
|
||||
int end_index;
|
||||
int loop_index;
|
||||
TObjPtr<DFsSection> next; // for hashing
|
||||
|
||||
DFsSection()
|
||||
{
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
void Serialize(FArchive &ar);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Tokens
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum tokentype_t
|
||||
{
|
||||
name_, // a name, eg 'count1' or 'frag'
|
||||
number,
|
||||
operator_,
|
||||
string_,
|
||||
unset,
|
||||
function // function name
|
||||
};
|
||||
|
||||
enum // brace types: where current_section is a { or }
|
||||
{
|
||||
bracket_open,
|
||||
bracket_close
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Errors
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class CFsError
|
||||
{
|
||||
public:
|
||||
// trying to throw strings crashes VC++ badly so we have to use a static buffer. :(
|
||||
char msg[2048];
|
||||
|
||||
CFsError(const FString &in)
|
||||
{
|
||||
strncpy(msg, in, 2047);
|
||||
msg[2047]=0;
|
||||
}
|
||||
};
|
||||
|
||||
// throw this object to regularly terminate a script's execution.
|
||||
class CFsTerminator
|
||||
{
|
||||
int fill;
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Scripts
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class DFsScript : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DFsScript, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
public:
|
||||
// script data
|
||||
|
||||
char *data;
|
||||
int scriptnum; // this script's number
|
||||
int len;
|
||||
|
||||
// {} sections
|
||||
|
||||
TObjPtr<DFsSection> sections[SECTIONSLOTS];
|
||||
|
||||
// variables:
|
||||
|
||||
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
|
||||
|
||||
// ptr to the parent script
|
||||
// the parent script is the script above this level
|
||||
// eg. individual linetrigger scripts are children
|
||||
// of the levelscript, which is a child of the
|
||||
// global_script
|
||||
TObjPtr<DFsScript> parent;
|
||||
|
||||
// haleyjd: 8-17
|
||||
// child scripts.
|
||||
// levelscript holds ptrs to all of the level's scripts
|
||||
// here.
|
||||
TObjPtr<DFsScript> children[MAXSCRIPTS];
|
||||
|
||||
|
||||
TObjPtr<AActor> trigger; // object which triggered this script
|
||||
|
||||
bool lastiftrue; // haleyjd: whether last "if" statement was
|
||||
// true or false
|
||||
|
||||
DFsScript();
|
||||
void Destroy();
|
||||
void Serialize(FArchive &ar);
|
||||
|
||||
DFsVariable *NewVariable(const char *name, int vtype);
|
||||
void NewFunction(const char *name, void (FParser::*handler)());
|
||||
|
||||
DFsVariable *VariableForName(const char *name);
|
||||
DFsVariable *FindVariable(const char *name);
|
||||
void ClearVariables(bool complete= false);
|
||||
DFsVariable *NewLabel(char *labelptr);
|
||||
char *LabelValue(const svalue_t &v);
|
||||
|
||||
char *SectionStart(const DFsSection *sec);
|
||||
char *SectionEnd(const DFsSection *sec);
|
||||
char *SectionLoop(const DFsSection *sec);
|
||||
void ClearSections();
|
||||
void ClearChildren();
|
||||
|
||||
int MakeIndex(const char *p) { return int(p-data); }
|
||||
|
||||
// preprocessor
|
||||
int section_hash(const char *b) { return MakeIndex(b) % SECTIONSLOTS; }
|
||||
DFsSection *NewSection(const char *brace);
|
||||
DFsSection *FindSectionStart(const char *brace);
|
||||
DFsSection *FindSectionEnd(const char *brace);
|
||||
char *ProcessFindChar(char *data, char find);
|
||||
void DryRunScript();
|
||||
void Preprocess();
|
||||
void ParseInclude(char *lumpname);
|
||||
void ParseScript(char *rover = NULL);
|
||||
void ParseData(char *rover, char *data, char *end);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The script parser
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FParser
|
||||
{
|
||||
struct operator_t
|
||||
{
|
||||
const char *string;
|
||||
void (FParser::*handler)(svalue_t &, int, int, int); // left, mid, right
|
||||
int direction;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
forward,
|
||||
backward
|
||||
};
|
||||
|
||||
static operator_t operators[];
|
||||
static int num_operators;
|
||||
|
||||
|
||||
char *LineStart;
|
||||
char *Rover;
|
||||
|
||||
char *Tokens[T_MAXTOKENS];
|
||||
tokentype_t TokenType[T_MAXTOKENS];
|
||||
int NumTokens;
|
||||
DFsScript *Script; // the current script
|
||||
DFsSection *Section;
|
||||
DFsSection *PrevSection;
|
||||
int BraceType;
|
||||
|
||||
int t_argc; // number of arguments
|
||||
svalue_t *t_argv; // arguments
|
||||
svalue_t t_return; // returned value
|
||||
FString t_func; // name of current function
|
||||
|
||||
FParser(DFsScript *scr)
|
||||
{
|
||||
LineStart = NULL;
|
||||
Rover = NULL;
|
||||
Tokens[0] = new char[scr->len+32]; // 32 for safety. FS seems to need a few bytes more than the script's actual length.
|
||||
NumTokens = 0;
|
||||
Script = scr;
|
||||
Section = PrevSection = NULL;
|
||||
BraceType = 0;
|
||||
}
|
||||
|
||||
~FParser()
|
||||
{
|
||||
if (Tokens[0]) delete [] Tokens[0];
|
||||
}
|
||||
|
||||
void NextToken();
|
||||
char *GetTokens(char *s);
|
||||
void PrintTokens();
|
||||
void ErrorMessage(FString msg);
|
||||
|
||||
void Run(char *rover, char *data, char *end);
|
||||
void RunStatement();
|
||||
int FindOperator(int start, int stop, const char *value);
|
||||
int FindOperatorBackwards(int start, int stop, const char *value);
|
||||
void SimpleEvaluate(svalue_t &, int n);
|
||||
void PointlessBrackets(int *start, int *stop);
|
||||
void EvaluateExpression(svalue_t &, int start, int stop);
|
||||
void EvaluateFunction(svalue_t &, int start, int stop);
|
||||
|
||||
void OPequals(svalue_t &, int, int, int); // =
|
||||
|
||||
void OPplus(svalue_t &, int, int, int); // +
|
||||
void OPminus(svalue_t &, int, int, int); // -
|
||||
void OPmultiply(svalue_t &, int, int, int); // *
|
||||
void OPdivide(svalue_t &, int, int, int); // /
|
||||
void OPremainder(svalue_t &, int, int, int); // %
|
||||
|
||||
void OPor(svalue_t &, int, int, int); // ||
|
||||
void OPand(svalue_t &, int, int, int); // &&
|
||||
void OPnot(svalue_t &, int, int, int); // !
|
||||
|
||||
void OPor_bin(svalue_t &, int, int, int); // |
|
||||
void OPand_bin(svalue_t &, int, int, int); // &
|
||||
void OPnot_bin(svalue_t &, int, int, int); // ~
|
||||
|
||||
void OPcmp(svalue_t &, int, int, int); // ==
|
||||
void OPnotcmp(svalue_t &, int, int, int); // !=
|
||||
void OPlessthan(svalue_t &, int, int, int); // <
|
||||
void OPgreaterthan(svalue_t &, int, int, int); // >
|
||||
|
||||
void OPincrement(svalue_t &, int, int, int); // ++
|
||||
void OPdecrement(svalue_t &, int, int, int); // --
|
||||
|
||||
void OPstructure(svalue_t &, int, int, int); // in t_vari.c
|
||||
|
||||
void OPlessthanorequal(svalue_t &, int, int, int); // <=
|
||||
void OPgreaterthanorequal(svalue_t &, int, int, int); // >=
|
||||
|
||||
void spec_brace();
|
||||
bool spec_if();
|
||||
bool spec_elseif(bool lastif);
|
||||
void spec_else(bool lastif);
|
||||
void spec_for();
|
||||
void spec_while();
|
||||
void CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop);
|
||||
void ParseVarLine(int newvar_type, DFsScript *newvar_script, int start);
|
||||
bool spec_variable();
|
||||
void spec_script();
|
||||
|
||||
DFsSection *looping_section();
|
||||
FString GetFormatString(int startarg);
|
||||
bool CheckArgs(int cnt);
|
||||
|
||||
void SF_Print();
|
||||
void SF_Rnd();
|
||||
void SF_Continue();
|
||||
void SF_Break();
|
||||
void SF_Goto();
|
||||
void SF_Return();
|
||||
void SF_Include();
|
||||
void SF_Input();
|
||||
void SF_Beep();
|
||||
void SF_Clock();
|
||||
void SF_ExitLevel();
|
||||
void SF_Tip();
|
||||
void SF_TimedTip();
|
||||
void SF_PlayerTip();
|
||||
void SF_Message();
|
||||
void SF_PlayerMsg();
|
||||
void SF_PlayerInGame();
|
||||
void SF_PlayerName();
|
||||
void SF_PlayerObj();
|
||||
void SF_StartScript(); // FPUKE needs to access this
|
||||
void SF_ScriptRunning();
|
||||
void SF_Wait();
|
||||
void SF_TagWait();
|
||||
void SF_ScriptWait();
|
||||
void SF_ScriptWaitPre(); // haleyjd: new wait types
|
||||
void SF_Player();
|
||||
void SF_Spawn();
|
||||
void SF_RemoveObj();
|
||||
void SF_KillObj();
|
||||
void SF_ObjX();
|
||||
void SF_ObjY();
|
||||
void SF_ObjZ();
|
||||
void SF_ObjAngle();
|
||||
void SF_Teleport();
|
||||
void SF_SilentTeleport();
|
||||
void SF_DamageObj();
|
||||
void SF_ObjSector();
|
||||
void SF_ObjHealth();
|
||||
void SF_ObjFlag();
|
||||
void SF_PushThing();
|
||||
void SF_ReactionTime();
|
||||
void SF_MobjTarget();
|
||||
void SF_MobjMomx();
|
||||
void SF_MobjMomy();
|
||||
void SF_MobjMomz();
|
||||
void SF_PointToAngle();
|
||||
void SF_PointToDist();
|
||||
void SF_SetCamera();
|
||||
void SF_ClearCamera();
|
||||
void SF_StartSound();
|
||||
void SF_StartSectorSound();
|
||||
void SF_FloorHeight();
|
||||
void SF_MoveFloor();
|
||||
void SF_CeilingHeight();
|
||||
void SF_MoveCeiling();
|
||||
void SF_LightLevel();
|
||||
void SF_FadeLight();
|
||||
void SF_FloorTexture();
|
||||
void SF_SectorColormap();
|
||||
void SF_CeilingTexture();
|
||||
void SF_ChangeHubLevel();
|
||||
void SF_StartSkill();
|
||||
void SF_OpenDoor();
|
||||
void SF_CloseDoor();
|
||||
void SF_RunCommand();
|
||||
void SF_LineTrigger();
|
||||
void SF_ChangeMusic();
|
||||
void SF_SetLineBlocking();
|
||||
void SF_SetLineMonsterBlocking();
|
||||
void SF_SetLineTexture();
|
||||
void SF_Max();
|
||||
void SF_Min();
|
||||
void SF_Abs();
|
||||
void SF_Gameskill();
|
||||
void SF_Gamemode();
|
||||
void SF_IsPlayerObj();
|
||||
void SF_PlayerKeys();
|
||||
void SF_PlayerAmmo();
|
||||
void SF_MaxPlayerAmmo();
|
||||
void SF_PlayerWeapon();
|
||||
void SF_PlayerSelectedWeapon();
|
||||
void SF_GiveInventory();
|
||||
void SF_TakeInventory();
|
||||
void SF_CheckInventory();
|
||||
void SF_SetWeapon();
|
||||
void SF_MoveCamera();
|
||||
void SF_ObjAwaken();
|
||||
void SF_AmbientSound();
|
||||
void SF_ExitSecret();
|
||||
void SF_MobjValue();
|
||||
void SF_StringValue();
|
||||
void SF_IntValue();
|
||||
void SF_FixedValue();
|
||||
void SF_SpawnExplosion();
|
||||
void SF_RadiusAttack();
|
||||
void SF_SetObjPosition();
|
||||
void SF_TestLocation();
|
||||
void SF_HealObj(); //no pain sound
|
||||
void SF_ObjDead();
|
||||
void SF_SpawnMissile();
|
||||
void SF_MapThingNumExist();
|
||||
void SF_MapThings();
|
||||
void SF_ObjState();
|
||||
void SF_LineFlag();
|
||||
void SF_PlayerAddFrag();
|
||||
void SF_SkinColor();
|
||||
void SF_PlayDemo();
|
||||
void SF_CheckCVar();
|
||||
void SF_Resurrect();
|
||||
void SF_LineAttack();
|
||||
void SF_ObjType();
|
||||
void SF_Sin();
|
||||
void SF_ASin();
|
||||
void SF_Cos();
|
||||
void SF_ACos();
|
||||
void SF_Tan();
|
||||
void SF_ATan();
|
||||
void SF_Exp();
|
||||
void SF_Log();
|
||||
void SF_Sqrt();
|
||||
void SF_Floor();
|
||||
void SF_Pow();
|
||||
void SF_NewHUPic();
|
||||
void SF_DeleteHUPic();
|
||||
void SF_ModifyHUPic();
|
||||
void SF_SetHUPicDisplay();
|
||||
void SF_SetCorona();
|
||||
void SF_Ls();
|
||||
void SF_LevelNum();
|
||||
void SF_MobjRadius();
|
||||
void SF_MobjHeight();
|
||||
void SF_ThingCount();
|
||||
void SF_SetColor();
|
||||
void SF_SpawnShot2();
|
||||
void SF_KillInSector();
|
||||
void SF_SectorType();
|
||||
void SF_SetLineTrigger();
|
||||
void SF_ChangeTag();
|
||||
void SF_WallGlow();
|
||||
void RunLineSpecial(const FLineSpecial *);
|
||||
|
||||
DRunningScript *SaveCurrentScript();
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Running scripts
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
enum waittype_e
|
||||
{
|
||||
wt_none, // not waiting
|
||||
wt_delay, // wait for a set amount of time
|
||||
wt_tagwait, // wait for sector to stop moving
|
||||
wt_scriptwait, // wait for script to finish
|
||||
wt_scriptwaitpre, // haleyjd - wait for script to start
|
||||
};
|
||||
|
||||
class DRunningScript : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DRunningScript, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
public:
|
||||
DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
|
||||
void Destroy();
|
||||
void Serialize(FArchive &arc);
|
||||
|
||||
TObjPtr<DFsScript> script;
|
||||
|
||||
// where we are
|
||||
int save_point;
|
||||
|
||||
int wait_type;
|
||||
int wait_data; // data for wait: tagnum, counter, script number etc
|
||||
|
||||
// saved variables
|
||||
TObjPtr<DFsVariable> variables[VARIABLESLOTS];
|
||||
|
||||
TObjPtr<DRunningScript> prev, next; // for chain
|
||||
TObjPtr<AActor> trigger;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This thinker eliminates the need to call the Fragglescript functions from the main code
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
class DFraggleThinker : public DThinker
|
||||
{
|
||||
DECLARE_CLASS(DFraggleThinker, DThinker)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
||||
TObjPtr<DFsScript> LevelScript;
|
||||
TObjPtr<DRunningScript> RunningScripts;
|
||||
TArray<TObjPtr<AActor> > SpawnedThings;
|
||||
bool nocheckposition;
|
||||
|
||||
DFraggleThinker();
|
||||
void Destroy();
|
||||
|
||||
|
||||
void Serialize(FArchive & arc);
|
||||
void Tick();
|
||||
size_t PropagateMark();
|
||||
size_t PointerSubstitution (DObject *old, DObject *notOld);
|
||||
bool wait_finished(DRunningScript *script);
|
||||
void AddRunningScript(DRunningScript *runscr);
|
||||
|
||||
static TObjPtr<DFraggleThinker> ActiveThinker;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Global stuff
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "t_fs.h"
|
||||
|
||||
void script_error(const char *s, ...);
|
||||
void FS_EmulateCmd(char * string);
|
||||
|
||||
extern AActor *trigger_obj;
|
||||
extern DFsScript *global_script;
|
||||
|
||||
|
||||
#endif
|
||||
|
628
src/fragglescript/t_spec.cpp
Normal file
628
src/fragglescript/t_spec.cpp
Normal file
|
@ -0,0 +1,628 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// 'Special' stuff
|
||||
//
|
||||
// if(), int statements, etc.
|
||||
//
|
||||
// By Simon Howard
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
#include "t_script.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ending brace found in parsing
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::spec_brace()
|
||||
{
|
||||
if(BraceType != bracket_close) // only deal with closing } braces
|
||||
return;
|
||||
|
||||
// if() requires nothing to be done
|
||||
if(Section->type == st_if || Section->type == st_else)
|
||||
return;
|
||||
|
||||
// if a loop, jump back to the start of the loop
|
||||
if(Section->type == st_loop)
|
||||
{
|
||||
Rover = Script->SectionLoop(Section);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 'if' statement -- haleyjd: changed to bool for else/elseif
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FParser::spec_if()
|
||||
{
|
||||
int endtoken;
|
||||
svalue_t eval;
|
||||
|
||||
|
||||
if((endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
|
||||
{
|
||||
script_error("parse error in if statement\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2 to skip past the 'if' and '('
|
||||
EvaluateExpression(eval, 2, endtoken-1);
|
||||
bool ifresult = !!intvalue(eval);
|
||||
|
||||
if(Section && BraceType == bracket_open && endtoken == NumTokens-1)
|
||||
{
|
||||
// {} braces
|
||||
if(!ifresult) // skip to end of section
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
else if(ifresult) // if() without {} braces
|
||||
{
|
||||
// nothing to do ?
|
||||
if(endtoken != NumTokens-1)
|
||||
EvaluateExpression(eval, endtoken+1, NumTokens-1);
|
||||
}
|
||||
|
||||
return ifresult;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 'elseif' statement
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FParser::spec_elseif(bool lastif)
|
||||
{
|
||||
int endtoken;
|
||||
svalue_t eval;
|
||||
|
||||
if((endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
|
||||
{
|
||||
script_error("parse error in elseif statement\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lastif)
|
||||
{
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
return true;
|
||||
}
|
||||
// 2 to skip past the 'elseif' and '('
|
||||
EvaluateExpression(eval, 2, endtoken-1);
|
||||
bool ifresult = !!intvalue(eval);
|
||||
|
||||
if(Section && BraceType == bracket_open
|
||||
&& endtoken == NumTokens-1)
|
||||
{
|
||||
// {} braces
|
||||
if(!ifresult) // skip to end of section
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
else if(ifresult) // elseif() without {} braces
|
||||
{
|
||||
// nothing to do ?
|
||||
if(endtoken != NumTokens-1)
|
||||
EvaluateExpression(eval, endtoken+1, NumTokens-1);
|
||||
}
|
||||
|
||||
return ifresult;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 'else' statement
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::spec_else(bool lastif)
|
||||
{
|
||||
if(lastif)
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// while() loop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::spec_while()
|
||||
{
|
||||
int endtoken;
|
||||
svalue_t eval;
|
||||
|
||||
if(!Section)
|
||||
{
|
||||
script_error("no {} section given for loop\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if( (endtoken = FindOperator(0, NumTokens-1, ")")) == -1)
|
||||
{
|
||||
script_error("parse error in loop statement\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EvaluateExpression(eval, 2, endtoken-1);
|
||||
|
||||
// skip if no longer valid
|
||||
if(!intvalue(eval)) Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// for() loop
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::spec_for()
|
||||
{
|
||||
svalue_t eval;
|
||||
int start;
|
||||
int comma1, comma2; // token numbers of the seperating commas
|
||||
|
||||
if(!Section)
|
||||
{
|
||||
script_error("need {} delimiters for for()\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// is a valid section
|
||||
|
||||
start = 2; // skip "for" and "(": start on third token(2)
|
||||
|
||||
// find the seperating commas first
|
||||
|
||||
if( (comma1 = FindOperator(start, NumTokens-1, ",")) == -1
|
||||
|| (comma2 = FindOperator(comma1+1, NumTokens-1, ",")) == -1)
|
||||
{
|
||||
script_error("incorrect arguments to for()\n"); // haleyjd:
|
||||
return; // said if()
|
||||
}
|
||||
|
||||
// are we looping back from a previous loop?
|
||||
if(Section == PrevSection)
|
||||
{
|
||||
// do the loop 'action' (third argument)
|
||||
EvaluateExpression(eval, comma2+1, NumTokens-2);
|
||||
|
||||
// check if we should run the loop again (second argument)
|
||||
EvaluateExpression(eval, comma1+1, comma2-1);
|
||||
if(!intvalue(eval))
|
||||
{
|
||||
// stop looping
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// first time: starting the loop
|
||||
// just evaluate the starting expression (first arg)
|
||||
EvaluateExpression(eval, start, comma1-1);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Variable Creation
|
||||
//
|
||||
// called for each individual variable in a statement
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop)
|
||||
{
|
||||
if(TokenType[start] != name_)
|
||||
{
|
||||
script_error("invalid name for variable: '%s'\n", Tokens[start]);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if already exists, only checking
|
||||
// the current script
|
||||
if(newvar_script->VariableForName (Tokens[start]))
|
||||
{
|
||||
// In Eternity this was fatal and in Legacy it was ignored
|
||||
// So make this a warning.
|
||||
Printf("FS: redefined symbol: '%s'\n", Tokens[start]);
|
||||
return; // already one
|
||||
}
|
||||
|
||||
// haleyjd: disallow mobj references in the hub script --
|
||||
// they cause dangerous dangling references and are of no
|
||||
// potential use
|
||||
if(newvar_script != Script && newvar_type == svt_mobj)
|
||||
{
|
||||
script_error("cannot create mobj reference in hub script\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newvar_script->NewVariable (Tokens[start], newvar_type);
|
||||
|
||||
if(stop != start)
|
||||
{
|
||||
svalue_t scratch;
|
||||
EvaluateExpression(scratch, start, stop);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// divide a statement (without type prefix) into individual
|
||||
// variables to create them using create_variable
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::ParseVarLine(int newvar_type, DFsScript *newvar_script, int start)
|
||||
{
|
||||
int starttoken = start, endtoken;
|
||||
|
||||
while(1)
|
||||
{
|
||||
endtoken = FindOperator(starttoken, NumTokens-1, ",");
|
||||
if(endtoken == -1) break;
|
||||
CreateVariable(newvar_type, newvar_script, starttoken, endtoken-1);
|
||||
starttoken = endtoken+1; //start next after end of this one
|
||||
}
|
||||
// dont forget the last one
|
||||
CreateVariable(newvar_type, newvar_script, starttoken, NumTokens-1);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// variable definition
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FParser::spec_variable()
|
||||
{
|
||||
int start = 0;
|
||||
|
||||
int newvar_type = -1; // init to -1
|
||||
DFsScript *newvar_script = Script; // use current script
|
||||
|
||||
// check for 'hub' keyword to make a hub variable
|
||||
if(!strcmp(Tokens[start], "hub"))
|
||||
{
|
||||
// The hub script doesn't work so it's probably safest to store the variable locally.
|
||||
//newvar_script = &hub_script;
|
||||
start++; // skip first token
|
||||
}
|
||||
|
||||
// now find variable type
|
||||
if(!strcmp(Tokens[start], "const"))
|
||||
{
|
||||
newvar_type = svt_const;
|
||||
start++;
|
||||
}
|
||||
else if(!strcmp(Tokens[start], "string"))
|
||||
{
|
||||
newvar_type = svt_string;
|
||||
start++;
|
||||
}
|
||||
else if(!strcmp(Tokens[start], "int"))
|
||||
{
|
||||
newvar_type = svt_int;
|
||||
start++;
|
||||
}
|
||||
else if(!strcmp(Tokens[start], "mobj"))
|
||||
{
|
||||
newvar_type = svt_mobj;
|
||||
start++;
|
||||
}
|
||||
else if(!strcmp(Tokens[start], "fixed") || !strcmp(Tokens[start], "float"))
|
||||
{
|
||||
newvar_type = svt_fixed;
|
||||
start++;
|
||||
}
|
||||
else if(!strcmp(Tokens[start], "script")) // check for script creation
|
||||
{
|
||||
spec_script();
|
||||
return true; // used tokens
|
||||
}
|
||||
|
||||
// are we creating a new variable?
|
||||
if(newvar_type != -1)
|
||||
{
|
||||
ParseVarLine(newvar_type, newvar_script, start);
|
||||
return true; // used tokens
|
||||
}
|
||||
|
||||
return false; // not used: try normal parsing
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ADD SCRIPT
|
||||
//
|
||||
// when the level is first loaded, all the
|
||||
// scripts are simply stored in the levelscript.
|
||||
// before the level starts, this script is
|
||||
// preprocessed and run like any other. This allows
|
||||
// the individual scripts to be derived from the
|
||||
// levelscript. When the interpreter detects the
|
||||
// 'script' keyword this function is called
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::spec_script()
|
||||
{
|
||||
int scriptnum;
|
||||
int datasize;
|
||||
DFsScript *newscript;
|
||||
|
||||
scriptnum = 0;
|
||||
|
||||
if(!Section)
|
||||
{
|
||||
script_error("need seperators for newscript\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// presume that the first token is "newscript"
|
||||
|
||||
if(NumTokens < 2)
|
||||
{
|
||||
script_error("need newscript number\n");
|
||||
return;
|
||||
}
|
||||
|
||||
svalue_t result;
|
||||
EvaluateExpression(result, 1, NumTokens-1);
|
||||
scriptnum = intvalue(result);
|
||||
|
||||
if(scriptnum < 0)
|
||||
{
|
||||
script_error("invalid newscript number\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newscript = new DFsScript;
|
||||
|
||||
// add to scripts list of parent
|
||||
Script->children[scriptnum] = newscript;
|
||||
GC::WriteBarrier(Script, newscript);
|
||||
|
||||
// copy newscript data
|
||||
// workout newscript size: -2 to ignore { and }
|
||||
datasize = (Section->end_index - Section->start_index - 2);
|
||||
|
||||
// alloc extra 10 for safety
|
||||
newscript->data = (char *)malloc(datasize+10);
|
||||
|
||||
// copy from parent newscript (levelscript)
|
||||
// ignore first char which is {
|
||||
memcpy(newscript->data, Script->SectionStart(Section) + 1, datasize);
|
||||
|
||||
// tack on a 0 to end the string
|
||||
newscript->data[datasize] = '\0';
|
||||
|
||||
newscript->scriptnum = scriptnum;
|
||||
newscript->parent = Script; // remember parent
|
||||
|
||||
// preprocess the newscript now
|
||||
newscript->Preprocess();
|
||||
|
||||
// we dont want to run the newscript, only add it
|
||||
// jump past the newscript in parsing
|
||||
|
||||
Rover = Script->SectionEnd(Section) + 1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// evaluate_function: once parse.c is pretty
|
||||
// sure it has a function to run it calls
|
||||
// this. evaluate_function makes sure that
|
||||
// it is a function call first, then evaluates all
|
||||
// the arguments given to the function.
|
||||
// these are built into an argc/argv-style
|
||||
// list. the function 'handler' is then called.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::EvaluateFunction(svalue_t &result, int start, int stop)
|
||||
{
|
||||
DFsVariable *func = NULL;
|
||||
int startpoint, endpoint;
|
||||
|
||||
// the arguments need to be built locally in case of
|
||||
// function returns as function arguments eg
|
||||
// print("here is a random number: ", rnd() );
|
||||
|
||||
int argc;
|
||||
svalue_t argv[MAXARGS];
|
||||
|
||||
if(TokenType[start] != function || TokenType[stop] != operator_
|
||||
|| Tokens[stop][0] != ')' )
|
||||
{
|
||||
script_error("misplaced closing paren\n");
|
||||
}
|
||||
|
||||
// all the functions are stored in the global script
|
||||
else if( !(func = global_script->VariableForName (Tokens[start])) )
|
||||
{
|
||||
script_error("no such function: '%s'\n",Tokens[start]);
|
||||
}
|
||||
|
||||
else if(func->type != svt_function && func->type != svt_linespec)
|
||||
{
|
||||
script_error("'%s' not a function\n", Tokens[start]);
|
||||
}
|
||||
|
||||
// build the argument list
|
||||
// use a C command-line style system rather than
|
||||
// a system using a fixed length list
|
||||
|
||||
argc = 0;
|
||||
endpoint = start + 2; // ignore the function name and first bracket
|
||||
|
||||
while(endpoint < stop)
|
||||
{
|
||||
startpoint = endpoint;
|
||||
endpoint = FindOperator(startpoint, stop-1, ",");
|
||||
|
||||
// check for -1: no more ','s
|
||||
if(endpoint == -1)
|
||||
{ // evaluate the last expression
|
||||
endpoint = stop;
|
||||
}
|
||||
if(endpoint-1 < startpoint)
|
||||
break;
|
||||
|
||||
EvaluateExpression(argv[argc], startpoint, endpoint-1);
|
||||
endpoint++; // skip the ','
|
||||
argc++;
|
||||
}
|
||||
|
||||
// store the arguments in the global arglist
|
||||
t_argc = argc;
|
||||
t_argv = argv;
|
||||
|
||||
// haleyjd: return values can propagate to void functions, so
|
||||
// t_return needs to be cleared now
|
||||
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = 0;
|
||||
|
||||
// now run the function
|
||||
if (func->type == svt_function)
|
||||
{
|
||||
(this->*func->value.handler)();
|
||||
}
|
||||
else
|
||||
{
|
||||
RunLineSpecial(func->value.ls);
|
||||
}
|
||||
|
||||
// return the returned value
|
||||
result = t_return;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// structure dot (.) operator
|
||||
// there are not really any structs in FraggleScript, it's
|
||||
// just a different way of calling a function that looks
|
||||
// nicer. ie
|
||||
// a.b() = a.b = b(a)
|
||||
// a.b(c) = b(a,c)
|
||||
//
|
||||
// this function is just based on the one above
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FParser::OPstructure(svalue_t &result, int start, int n, int stop)
|
||||
{
|
||||
DFsVariable *func = NULL;
|
||||
|
||||
// the arguments need to be built locally in case of
|
||||
// function returns as function arguments eg
|
||||
// print("here is a random number: ", rnd() );
|
||||
|
||||
int argc;
|
||||
svalue_t argv[MAXARGS];
|
||||
|
||||
// all the functions are stored in the global script
|
||||
if( !(func = global_script->VariableForName (Tokens[n+1])) )
|
||||
{
|
||||
script_error("no such function: '%s'\n",Tokens[n+1]);
|
||||
}
|
||||
|
||||
else if(func->type != svt_function)
|
||||
{
|
||||
script_error("'%s' not a function\n", Tokens[n+1]);
|
||||
}
|
||||
|
||||
// build the argument list
|
||||
|
||||
// add the left part as first arg
|
||||
|
||||
EvaluateExpression(argv[0], start, n-1);
|
||||
argc = 1; // start on second argv
|
||||
|
||||
if(stop != n+1) // can be a.b not a.b()
|
||||
{
|
||||
int startpoint, endpoint;
|
||||
|
||||
// ignore the function name and first bracket
|
||||
endpoint = n + 3;
|
||||
|
||||
while(endpoint < stop)
|
||||
{
|
||||
startpoint = endpoint;
|
||||
endpoint = FindOperator(startpoint, stop-1, ",");
|
||||
|
||||
// check for -1: no more ','s
|
||||
if(endpoint == -1)
|
||||
{ // evaluate the last expression
|
||||
endpoint = stop;
|
||||
}
|
||||
if(endpoint-1 < startpoint)
|
||||
break;
|
||||
|
||||
EvaluateExpression(argv[argc], startpoint, endpoint-1);
|
||||
endpoint++; // skip the ','
|
||||
argc++;
|
||||
}
|
||||
}
|
||||
|
||||
// store the arguments in the global arglist
|
||||
t_argc = argc;
|
||||
t_argv = argv;
|
||||
t_func = func->Name;
|
||||
|
||||
// haleyjd: return values can propagate to void functions, so
|
||||
// t_return needs to be cleared now
|
||||
|
||||
t_return.type = svt_int;
|
||||
t_return.value.i = 0;
|
||||
|
||||
// now run the function
|
||||
(this->*func->value.handler)();
|
||||
|
||||
// return the returned value
|
||||
result = t_return;
|
||||
}
|
||||
|
||||
|
437
src/fragglescript/t_variable.cpp
Normal file
437
src/fragglescript/t_variable.cpp
Normal file
|
@ -0,0 +1,437 @@
|
|||
// Emacs style mode select -*- C++ -*-
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2000 Simon Howard
|
||||
// Copyright(C) 2002-2008 Christoph Oelckers
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Variables.
|
||||
//
|
||||
// Variable code: create new variables, look up variables, get value,
|
||||
// set value
|
||||
//
|
||||
// variables are stored inside the individual scripts, to allow for
|
||||
// 'local' and 'global' variables. This way, individual scripts cannot
|
||||
// access variables in other scripts. However, 'global' variables can
|
||||
// be made which can be accessed by all scripts. These are stored inside
|
||||
// a dedicated DFsScript which exists only to hold all of these global
|
||||
// variables.
|
||||
//
|
||||
// functions are also stored as variables, these are kept in the global
|
||||
// script so they can be accessed by all scripts. function variables
|
||||
// cannot be set or changed inside the scripts themselves.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// FraggleScript is from SMMU which is under the GPL. Technically,
|
||||
// therefore, combining the FraggleScript code with the non-free
|
||||
// ZDoom code is a violation of the GPL.
|
||||
//
|
||||
// As this may be a problem for you, I hereby grant an exception to my
|
||||
// copyright on the SMMU source (including FraggleScript). You may use
|
||||
// any code from SMMU in (G)ZDoom, provided that:
|
||||
//
|
||||
// * For any binary release of the port, the source code is also made
|
||||
// available.
|
||||
// * The copyright notice is kept on any file containing my code.
|
||||
//
|
||||
//
|
||||
|
||||
#include "t_script.h"
|
||||
#include "a_pickups.h"
|
||||
#include "farchive.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int intvalue(const svalue_t &v)
|
||||
{
|
||||
return (v.type == svt_string ? atoi(v.string) :
|
||||
v.type == svt_fixed ? (int)(v.value.f / FRACUNIT) :
|
||||
v.type == svt_mobj ? -1 : v.value.i );
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
fixed_t fixedvalue(const svalue_t &v)
|
||||
{
|
||||
return (v.type == svt_fixed ? v.value.f :
|
||||
v.type == svt_string ? (fixed_t)(atof(v.string) * FRACUNIT) :
|
||||
v.type == svt_mobj ? -1*FRACUNIT : v.value.i * FRACUNIT );
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
float floatvalue(const svalue_t &v)
|
||||
{
|
||||
return (float)( (v.type == svt_string ? atof(v.string) :
|
||||
v.type == svt_fixed ? (float)(v.value.f / (float)FRACUNIT) :
|
||||
v.type == svt_mobj ? -1.f : (float)v.value.i ));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// sf: string value of an svalue_t
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char *stringvalue(const svalue_t & v)
|
||||
{
|
||||
static char buffer[256];
|
||||
|
||||
switch(v.type)
|
||||
{
|
||||
case svt_string:
|
||||
return v.string;
|
||||
|
||||
case svt_mobj:
|
||||
// return the class name
|
||||
return (const char *)v.value.mobj->GetClass()->TypeName;
|
||||
|
||||
case svt_fixed:
|
||||
{
|
||||
double val = ((double)v.value.f) / FRACUNIT;
|
||||
mysnprintf(buffer, countof(buffer), "%g", val);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
case svt_int:
|
||||
default:
|
||||
mysnprintf(buffer, countof(buffer), "%i", v.value.i);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
AActor* actorvalue(const svalue_t &svalue)
|
||||
{
|
||||
int intval;
|
||||
|
||||
if(svalue.type == svt_mobj)
|
||||
{
|
||||
// Inventory items in the player's inventory have to be considered non-present.
|
||||
if (svalue.value.mobj != NULL &&
|
||||
svalue.value.mobj->IsKindOf(RUNTIME_CLASS(AInventory)) &&
|
||||
static_cast<AInventory*>(svalue.value.mobj)->Owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return svalue.value.mobj;
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<TObjPtr<AActor> > &SpawnedThings = DFraggleThinker::ActiveThinker->SpawnedThings;
|
||||
// this requires some creativity. We use the intvalue
|
||||
// as the thing number of a thing in the level.
|
||||
intval = intvalue(svalue);
|
||||
|
||||
if(intval < 0 || intval >= (int)SpawnedThings.Size())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// Inventory items in the player's inventory have to be considered non-present.
|
||||
if (SpawnedThings[intval] != NULL &&
|
||||
SpawnedThings[intval]->IsKindOf(RUNTIME_CLASS(AInventory)) &&
|
||||
barrier_cast<AInventory*>(SpawnedThings[intval])->Owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SpawnedThings[intval];
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(DFsVariable)
|
||||
DECLARE_POINTER (next)
|
||||
DECLARE_POINTER (actor)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsVariable::DFsVariable(const char * _name)
|
||||
{
|
||||
Name=_name;
|
||||
type=svt_int;
|
||||
actor = NULL;
|
||||
value.i=0;
|
||||
next=NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// returns an svalue_t holding the current
|
||||
// value of a particular variable.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsVariable::GetValue(svalue_t &returnvar)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case svt_pInt:
|
||||
returnvar.type = svt_int;
|
||||
returnvar.value.i = *value.pI;
|
||||
break;
|
||||
|
||||
case svt_pMobj:
|
||||
returnvar.type = svt_mobj;
|
||||
returnvar.value.mobj = *value.pMobj;
|
||||
break;
|
||||
|
||||
case svt_mobj:
|
||||
returnvar.type = type;
|
||||
returnvar.value.mobj = actor;
|
||||
break;
|
||||
|
||||
case svt_linespec:
|
||||
returnvar.type = svt_int;
|
||||
returnvar.value.i = value.ls->number;
|
||||
break;
|
||||
|
||||
case svt_string:
|
||||
returnvar.type = type;
|
||||
returnvar.string = string;
|
||||
break;
|
||||
|
||||
default:
|
||||
// copy the value (also handles fixed)
|
||||
returnvar.type = type;
|
||||
returnvar.value.i = value.i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// set a variable to a value from an svalue_t
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsVariable::SetValue(const svalue_t &newvalue)
|
||||
{
|
||||
if(type == svt_const)
|
||||
{
|
||||
// const adapts to the value it is set to
|
||||
type = newvalue.type;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case svt_int:
|
||||
value.i = intvalue(newvalue);
|
||||
break;
|
||||
|
||||
case svt_string:
|
||||
if (newvalue.type == svt_string)
|
||||
{
|
||||
string = newvalue.string;
|
||||
}
|
||||
else
|
||||
{
|
||||
string = stringvalue(newvalue);
|
||||
}
|
||||
break;
|
||||
|
||||
case svt_fixed:
|
||||
value.fixed = fixedvalue(newvalue);
|
||||
break;
|
||||
|
||||
case svt_mobj:
|
||||
actor = actorvalue(newvalue);
|
||||
break;
|
||||
|
||||
case svt_pInt:
|
||||
*value.pI = intvalue(newvalue);
|
||||
break;
|
||||
|
||||
case svt_pMobj:
|
||||
*value.pMobj = actorvalue(newvalue);
|
||||
break;
|
||||
|
||||
case svt_function:
|
||||
script_error("attempt to set function to a value\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
script_error("invalid variable type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Archive one script variable
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsVariable::Serialize(FArchive & ar)
|
||||
{
|
||||
Super::Serialize(ar);
|
||||
ar << Name << type << string << actor << value.i << next;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// From here: variable related functions inside DFsScript
|
||||
//
|
||||
//==========================================================================
|
||||
//==========================================================================
|
||||
//
|
||||
// create a new variable in a particular script.
|
||||
// returns a pointer to the new variable.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsVariable *DFsScript::NewVariable(const char *name, int vtype)
|
||||
{
|
||||
DFsVariable *newvar = new DFsVariable(name);
|
||||
newvar->type = vtype;
|
||||
|
||||
int n = variable_hash(name);
|
||||
newvar->next = variables[n];
|
||||
variables[n] = newvar;
|
||||
GC::WriteBarrier(this, newvar);
|
||||
return newvar;
|
||||
}
|
||||
|
||||
|
||||
void DFsScript::NewFunction(const char *name, void (FParser::*handler)() )
|
||||
{
|
||||
NewVariable (name, svt_function)->value.handler = handler;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// search a particular script for a variable, which
|
||||
// is returned if it exists
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsVariable *DFsScript::VariableForName(const char *name)
|
||||
{
|
||||
int n = variable_hash(name);
|
||||
DFsVariable *current = variables[n];
|
||||
|
||||
while(current)
|
||||
{
|
||||
if(!strcmp(name, current->Name)) // found it?
|
||||
return current;
|
||||
current = current->next; // check next in chain
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// find_variable checks through the current script, level script
|
||||
// and global script to try to find the variable of the name wanted
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFsVariable *DFsScript::FindVariable(const char *name)
|
||||
{
|
||||
DFsVariable *var;
|
||||
DFsScript *current = this;
|
||||
|
||||
while(current)
|
||||
{
|
||||
// check this script
|
||||
if ((var = current->VariableForName(name)))
|
||||
return var;
|
||||
current = current->parent; // try the parent of this one
|
||||
}
|
||||
|
||||
return NULL; // no variable
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// free all the variables in a given script
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFsScript::ClearVariables(bool complete)
|
||||
{
|
||||
int i;
|
||||
DFsVariable *current, *next;
|
||||
|
||||
for(i=0; i<VARIABLESLOTS; i++)
|
||||
{
|
||||
current = variables[i];
|
||||
|
||||
// go thru this chain
|
||||
while(current)
|
||||
{
|
||||
// labels are added before variables, during
|
||||
// preprocessing, so will be at the end of the chain
|
||||
// we can be sure there are no more variables to free
|
||||
if(current->type == svt_label && !complete) break;
|
||||
|
||||
next = current->next; // save for after freeing
|
||||
|
||||
current->Destroy();
|
||||
current = next; // go to next in chain
|
||||
}
|
||||
// start of labels or NULL
|
||||
variables[i] = current;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
char *DFsScript::LabelValue(const svalue_t &v)
|
||||
{
|
||||
if (v.type == svt_label) return data + v.value.i;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1045,6 +1045,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
|
|||
x = self->x + ((pr_storm()&127) - 64) * FRACUNIT;
|
||||
y = self->y + ((pr_storm()&127) - 64) * FRACUNIT;
|
||||
mo = Spawn<ARainPillar> (x, y, ONCEILINGZ, ALLOW_REPLACE);
|
||||
#ifdef _3DFLOORS
|
||||
// We used bouncecount to store the 3D floor index in A_HideInCeiling
|
||||
if (!mo) return;
|
||||
fixed_t newz;
|
||||
if (self->bouncecount >= 0
|
||||
&& (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size())
|
||||
newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT;
|
||||
else
|
||||
newz = self->Sector->ceilingplane.ZatPoint(x, y);
|
||||
int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz);
|
||||
if (moceiling >= 0)
|
||||
mo->z = newz - mo->height;
|
||||
#endif
|
||||
mo->Translation = multiplayer ?
|
||||
TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0;
|
||||
mo->target = self->target;
|
||||
|
@ -1084,6 +1097,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact)
|
|||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
|
||||
{
|
||||
#ifdef _3DFLOORS
|
||||
// We use bouncecount to store the 3D floor index
|
||||
fixed_t foo;
|
||||
for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
|
||||
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
|
||||
|
||||
if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height))
|
||||
{
|
||||
self->z = foo + 4*FRACUNIT;
|
||||
self->bouncecount = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
self->bouncecount = -1;
|
||||
#endif
|
||||
self->z = self->ceilingz + 4*FRACUNIT;
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ enum ELevelFlags
|
|||
LEVEL_STARTLIGHTNING = 0x01000000, // Automatically start lightning
|
||||
LEVEL_FILTERSTARTS = 0x02000000, // Apply mapthing filtering to player starts
|
||||
LEVEL_LOOKUPLEVELNAME = 0x04000000, // Level name is the name of a language string
|
||||
LEVEL_HEXENFORMAT = 0x08000000, // Level uses the Hexen map format
|
||||
//LEVEL_HEXENFORMAT = 0x08000000, // Level uses the Hexen map format
|
||||
|
||||
LEVEL_SWAPSKIES = 0x10000000, // Used by lightning
|
||||
LEVEL_NOALLIES = 0x20000000, // i.e. Inside Strife's front base
|
||||
|
@ -253,6 +253,15 @@ struct FOptionalMapinfoDataPtr
|
|||
typedef TMap<FName, FOptionalMapinfoDataPtr> FOptData;
|
||||
typedef TMap<int, FName> FMusicMap;
|
||||
|
||||
enum EMapType
|
||||
{
|
||||
MAPTYPE_UNKNOWN = 0,
|
||||
MAPTYPE_DOOM,
|
||||
MAPTYPE_HEXEN,
|
||||
MAPTYPE_BUILD,
|
||||
MAPTYPE_UDMF // This does not distinguish between namespaces.
|
||||
};
|
||||
|
||||
struct level_info_t
|
||||
{
|
||||
int levelnum;
|
||||
|
@ -380,6 +389,7 @@ struct FLevelLocals
|
|||
char mapname[256]; // the lump name (E1M1, MAP01, etc)
|
||||
char nextmap[11]; // go here when using the regular exit
|
||||
char secretmap[11]; // map to go to when used secret exit
|
||||
EMapType maptype;
|
||||
|
||||
DWORD flags;
|
||||
DWORD flags2;
|
||||
|
|
|
@ -51,6 +51,58 @@
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Wrappers to access the colormap information
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FDynamicColormap *F3DFloor::GetColormap()
|
||||
{
|
||||
// If there's no fog in either model or target sector this is easy and fast.
|
||||
if ((target->ColorMap->Fade == 0 && model->ColorMap->Fade == 0) || (flags & FF_FADEWALLS))
|
||||
{
|
||||
return model->ColorMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We must create a new colormap combining the properties we need
|
||||
return GetSpecialLights(model->ColorMap->Color, target->ColorMap->Fade, model->ColorMap->Desaturate);
|
||||
}
|
||||
}
|
||||
|
||||
PalEntry F3DFloor::GetBlend()
|
||||
{
|
||||
// The model sector's fog is used as blend unless FF_FADEWALLS is set.
|
||||
if (!(flags & FF_FADEWALLS) && target->ColorMap->Fade != model->ColorMap->Fade)
|
||||
{
|
||||
return model->ColorMap->Fade;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void F3DFloor::UpdateColormap(FDynamicColormap *&map)
|
||||
{
|
||||
// If there's no fog in either model or target sector (or both have the same fog) this is easy and fast.
|
||||
if ((target->ColorMap->Fade == 0 && model->ColorMap->Fade == 0) || (flags & FF_FADEWALLS) ||
|
||||
target->ColorMap->Fade == model->ColorMap->Fade)
|
||||
{
|
||||
map = model->ColorMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
// since rebuilding the map is not a cheap operation let's only do it if something really changed.
|
||||
if (map->Color != model->ColorMap->Color || map->Fade != target->ColorMap->Fade ||
|
||||
map->Desaturate != model->ColorMap->Desaturate)
|
||||
{
|
||||
map = GetSpecialLights(model->ColorMap->Color, target->ColorMap->Fade, model->ColorMap->Desaturate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Add one 3D floor to the sector
|
||||
|
@ -61,13 +113,16 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
|
|||
F3DFloor* ffloor;
|
||||
unsigned i;
|
||||
|
||||
if(!(flags & FF_THISINSIDE)) {
|
||||
for(i = 0; i < sec2->e->XFloor.attached.Size(); i++) if(sec2->e->XFloor.attached[i] == sec) return;
|
||||
sec2->e->XFloor.attached.Push(sec);
|
||||
}
|
||||
|
||||
//Add the floor
|
||||
ffloor = new F3DFloor;
|
||||
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
|
||||
ffloor->target = sec;
|
||||
ffloor->ceilingclip = ffloor->floorclip = NULL;
|
||||
|
||||
if (!(flags&FF_THINFLOOR))
|
||||
{
|
||||
|
@ -133,7 +188,18 @@ static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flag
|
|||
ffloor->flags &= ~FF_ADDITIVETRANS;
|
||||
}
|
||||
|
||||
if(flags & FF_THISINSIDE) {
|
||||
// switch the planes
|
||||
F3DFloor::planeref sp = ffloor->top;
|
||||
ffloor->top=ffloor->bottom;
|
||||
ffloor->bottom=sp;
|
||||
}
|
||||
|
||||
sec->e->XFloor.ffloors.Push(ffloor);
|
||||
|
||||
// kg3D - software renderer only hack
|
||||
// this is really required because of ceilingclip and floorclip
|
||||
if(flags & FF_BOTHPLANES) P_Add3DFloor(sec, sec2, master, FF_EXISTS | FF_THISINSIDE | FF_RENDERPLANES | FF_NOSHADE | FF_SEETHROUGH | FF_SHOOTTHROUGH | (flags & FF_INVERTSECTOR), transluc);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -460,7 +526,9 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
lightlist[0].plane = sector->ceilingplane;
|
||||
lightlist[0].p_lightlevel = §or->lightlevel;
|
||||
lightlist[0].caster = NULL;
|
||||
lightlist[0].p_extra_colormap = §or->ColorMap;
|
||||
lightlist[0].lightsource = NULL;
|
||||
lightlist[0].extra_colormap = sector->ColorMap;
|
||||
lightlist[0].blend = 0;
|
||||
lightlist[0].flags = 0;
|
||||
|
||||
maxheight = sector->CenterCeiling();
|
||||
|
@ -479,7 +547,9 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
newlight.plane = *rover->top.plane;
|
||||
newlight.p_lightlevel = rover->toplightlevel;
|
||||
newlight.caster = rover;
|
||||
newlight.p_extra_colormap=&rover->model->ColorMap;
|
||||
newlight.lightsource = rover;
|
||||
newlight.extra_colormap = rover->GetColormap();
|
||||
newlight.blend = rover->GetBlend();
|
||||
newlight.flags = rover->flags;
|
||||
lightlist.Push(newlight);
|
||||
}
|
||||
|
@ -491,7 +561,9 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
// this segment begins over the ceiling and extends beyond it
|
||||
lightlist[0].p_lightlevel = rover->toplightlevel;
|
||||
lightlist[0].caster = rover;
|
||||
lightlist[0].p_extra_colormap=&rover->model->ColorMap;
|
||||
lightlist[0].lightsource = rover;
|
||||
lightlist[0].extra_colormap = rover->GetColormap();
|
||||
lightlist[0].blend = rover->GetBlend();
|
||||
lightlist[0].flags = rover->flags;
|
||||
}
|
||||
}
|
||||
|
@ -504,13 +576,17 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
newlight.plane = *rover->bottom.plane;
|
||||
if (lightlist.Size()>1)
|
||||
{
|
||||
newlight.lightsource = lightlist[lightlist.Size()-2].lightsource;
|
||||
newlight.p_lightlevel = lightlist[lightlist.Size()-2].p_lightlevel;
|
||||
newlight.p_extra_colormap = lightlist[lightlist.Size()-2].p_extra_colormap;
|
||||
newlight.extra_colormap = lightlist[lightlist.Size()-2].extra_colormap;
|
||||
newlight.blend = lightlist[lightlist.Size()-2].blend;
|
||||
}
|
||||
else
|
||||
{
|
||||
newlight.lightsource = NULL;
|
||||
newlight.p_lightlevel = §or->lightlevel;
|
||||
newlight.p_extra_colormap = §or->ColorMap;
|
||||
newlight.extra_colormap = sector->ColorMap;
|
||||
newlight.blend = 0;
|
||||
}
|
||||
newlight.flags = rover->flags;
|
||||
lightlist.Push(newlight);
|
||||
|
@ -520,6 +596,11 @@ void P_Recalculate3DFloors(sector_t * sector)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// recalculates 3D floors for all attached sectors
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_RecalculateAttached3DFloors(sector_t * sec)
|
||||
{
|
||||
|
@ -532,11 +613,55 @@ void P_RecalculateAttached3DFloors(sector_t * sec)
|
|||
P_Recalculate3DFloors(sec);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// recalculates light lists for this sector
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_RecalculateLights(sector_t *sector)
|
||||
{
|
||||
TArray<lightlist_t> &lightlist = sector->e->XFloor.lightlist;
|
||||
|
||||
for(unsigned i = 0; i < lightlist.Size(); i++)
|
||||
{
|
||||
lightlist_t *ll = &lightlist[i];
|
||||
if (ll->lightsource != NULL)
|
||||
{
|
||||
ll->lightsource->UpdateColormap(ll->extra_colormap);
|
||||
ll->blend = ll->lightsource->GetBlend();
|
||||
}
|
||||
else
|
||||
{
|
||||
ll->extra_colormap = sector->ColorMap;
|
||||
ll->blend = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// recalculates light lists for all attached sectors
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_RecalculateAttachedLights(sector_t *sector)
|
||||
{
|
||||
extsector_t::xfloor &x = sector->e->XFloor;
|
||||
|
||||
for(unsigned int i=0; i<x.attached.Size(); i++)
|
||||
{
|
||||
P_RecalculateLights(x.attached[i]);
|
||||
}
|
||||
P_RecalculateLights(sector);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
lightlist_t * P_GetPlaneLight(sector_t * sector, secplane_t * plane, bool underside)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -659,6 +784,11 @@ void P_Spawn3DFloors (void)
|
|||
break;
|
||||
|
||||
case Sector_Set3DFloor:
|
||||
// The flag high-byte/line id is only needed in Hexen format.
|
||||
// UDMF can set both of these parameters without any restriction of the usable values.
|
||||
// In Doom format the translators can take full integers for the tag and the line ID always is the same as the tag.
|
||||
if (level.maptype == MAPTYPE_HEXEN)
|
||||
{
|
||||
if (line->args[1]&8)
|
||||
{
|
||||
line->id = line->args[4];
|
||||
|
@ -668,6 +798,7 @@ void P_Spawn3DFloors (void)
|
|||
line->args[0]+=256*line->args[4];
|
||||
line->args[4]=0;
|
||||
}
|
||||
}
|
||||
P_Set3DFloor(line, line->args[1]&~8, line->args[2], line->args[3]);
|
||||
break;
|
||||
|
||||
|
@ -677,6 +808,11 @@ void P_Spawn3DFloors (void)
|
|||
line->special=0;
|
||||
line->args[0] = line->args[1] = line->args[2] = line->args[3] = line->args[4] = 0;
|
||||
}
|
||||
// kg3D - do it in software
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
P_Recalculate3DFloors(§ors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -707,5 +843,59 @@ secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z)
|
|||
return retplane;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Gives the index to an extra floor above or below the given location.
|
||||
// -1 means normal floor or ceiling
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz)
|
||||
{
|
||||
// If no sector given, find the one appropriate
|
||||
if (sec == NULL)
|
||||
sec = R_PointInSubsector(x, y)->sector;
|
||||
|
||||
// Above normal ceiling
|
||||
cmpz = sec->ceilingplane.ZatPoint(x, y);
|
||||
if (z >= cmpz)
|
||||
return -1;
|
||||
|
||||
// Below normal floor
|
||||
cmpz = sec->floorplane.ZatPoint(x, y);
|
||||
if (z <= cmpz)
|
||||
return -1;
|
||||
|
||||
// Looking through planes from top to bottom
|
||||
for (int i = 0; i < (signed)sec->e->XFloor.ffloors.Size(); ++i)
|
||||
{
|
||||
F3DFloor *rover = sec->e->XFloor.ffloors[i];
|
||||
|
||||
// We are only interested in solid 3D floors here
|
||||
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
|
||||
|
||||
if (above)
|
||||
{
|
||||
// z is above that floor
|
||||
if (floor && (z >= (cmpz = rover->top.plane->ZatPoint(x, y))))
|
||||
return i - 1;
|
||||
// z is above that ceiling
|
||||
if (z >= (cmpz = rover->bottom.plane->ZatPoint(x, y)))
|
||||
return i - 1;
|
||||
}
|
||||
else // below
|
||||
{
|
||||
// z is below that ceiling
|
||||
if (!floor && (z <= (cmpz = rover->bottom.plane->ZatPoint(x, y))))
|
||||
return i;
|
||||
// z is below that floor
|
||||
if (z <= (cmpz = rover->top.plane->ZatPoint(x, y)))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Failsafe
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#define CenterSpot(sec) (vertex_t*)&(sec)->soundorg[0]
|
||||
|
||||
//#define _3DFLOORS
|
||||
#define _3DFLOORS
|
||||
|
||||
// 3D floor flags. Most are the same as in Legacy but I added some for EDGE's and Vavoom's features as well.
|
||||
typedef enum
|
||||
|
@ -36,7 +36,7 @@ typedef enum
|
|||
FF_FADEWALLS = 0x8000000, // Applies real fog to walls and doesn't blend the view
|
||||
FF_ADDITIVETRANS = 0x10000000, // Render this floor with additive translucency
|
||||
FF_FLOOD = 0x20000000, // extends towards the next lowest flooding or solid 3D floor or the bottom of the sector
|
||||
|
||||
FF_THISINSIDE = 0x40000000, // hack for software 3D with FF_BOTHPLANES
|
||||
} ffloortype_e;
|
||||
|
||||
// This is for the purpose of Sector_SetContents:
|
||||
|
@ -64,6 +64,8 @@ enum
|
|||
|
||||
|
||||
struct secplane_t;
|
||||
struct FDynamicColormap;
|
||||
|
||||
|
||||
struct F3DFloor
|
||||
{
|
||||
|
@ -93,18 +95,26 @@ struct F3DFloor
|
|||
int lastlight;
|
||||
int alpha;
|
||||
|
||||
// kg3D - for software
|
||||
short *floorclip;
|
||||
short *ceilingclip;
|
||||
int validcount;
|
||||
|
||||
FDynamicColormap *GetColormap();
|
||||
void UpdateColormap(FDynamicColormap *&map);
|
||||
PalEntry GetBlend();
|
||||
};
|
||||
|
||||
|
||||
struct FDynamicColormap;
|
||||
|
||||
|
||||
struct lightlist_t
|
||||
{
|
||||
secplane_t plane;
|
||||
unsigned char * p_lightlevel;
|
||||
FDynamicColormap ** p_extra_colormap;
|
||||
FDynamicColormap * extra_colormap;
|
||||
PalEntry blend;
|
||||
int flags;
|
||||
F3DFloor* lightsource;
|
||||
F3DFloor* caster;
|
||||
};
|
||||
|
||||
|
@ -118,6 +128,9 @@ bool P_CheckFor3DFloorHit(AActor * mo);
|
|||
bool P_CheckFor3DCeilingHit(AActor * mo);
|
||||
void P_Recalculate3DFloors(sector_t *);
|
||||
void P_RecalculateAttached3DFloors(sector_t * sec);
|
||||
void P_RecalculateLights(sector_t *sector);
|
||||
void P_RecalculateAttachedLights(sector_t *sector);
|
||||
|
||||
lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside);
|
||||
void P_Spawn3DFloors( void );
|
||||
|
||||
|
@ -127,6 +140,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
|
|||
fixed_t x, fixed_t y, fixed_t refx, fixed_t refy);
|
||||
|
||||
secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z);
|
||||
int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz);
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -2514,6 +2514,25 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
|
|||
if ( abs(corpsehit-> x - viletryx) > maxdist ||
|
||||
abs(corpsehit-> y - viletryy) > maxdist )
|
||||
continue; // not actually touching
|
||||
#ifdef _3DFLOORS
|
||||
// Let's check if there are floors in between the archvile and its target
|
||||
sector_t *vilesec = self->Sector;
|
||||
sector_t *corpsec = corpsehit->Sector;
|
||||
// We only need to test if at least one of the sectors has a 3D floor.
|
||||
sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec :
|
||||
(vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL;
|
||||
if (testsec)
|
||||
{
|
||||
fixed_t zdist1, zdist2;
|
||||
if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1)
|
||||
!= P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2))
|
||||
{
|
||||
// Not on same floor
|
||||
if (vilesec == corpsec || abs(zdist1 - self->z) > self->height)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
corpsehit->velx = corpsehit->vely = 0;
|
||||
// [RH] Check against real height and radius
|
||||
|
|
|
@ -690,12 +690,14 @@ void sector_t::SetColor(int r, int g, int b, int desat)
|
|||
{
|
||||
PalEntry color = PalEntry (r,g,b);
|
||||
ColorMap = GetSpecialLights (color, ColorMap->Fade, desat);
|
||||
P_RecalculateAttachedLights(this);
|
||||
}
|
||||
|
||||
void sector_t::SetFade(int r, int g, int b)
|
||||
{
|
||||
PalEntry fade = PalEntry (r,g,b);
|
||||
ColorMap = GetSpecialLights (ColorMap->Color, fade, ColorMap->Desaturate);
|
||||
P_RecalculateAttachedLights(this);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
239
src/p_setup.cpp
239
src/p_setup.cpp
|
@ -67,6 +67,8 @@
|
|||
#include "compatibility.h"
|
||||
#include "po_man.h"
|
||||
|
||||
#include "fragglescript/t_fs.h"
|
||||
|
||||
void P_SpawnSlopeMakers (FMapThing *firstmt, FMapThing *lastmt);
|
||||
void P_SetSlopes ();
|
||||
void P_CopySlopes();
|
||||
|
@ -135,9 +137,6 @@ int numgamesubsectors;
|
|||
|
||||
bool hasglnodes;
|
||||
|
||||
FExtraLight* ExtraLights;
|
||||
FLightStack* LightStacks;
|
||||
|
||||
TArray<FMapThing> MapThingsConverted;
|
||||
|
||||
int sidecount;
|
||||
|
@ -653,28 +652,64 @@ static void SetTexture (side_t *side, int position, DWORD *blend, char *name8)
|
|||
side->SetTexture(position, texture);
|
||||
}
|
||||
|
||||
static void SetTextureNoErr (side_t *side, int position, DWORD *color, char *name8, bool *validcolor)
|
||||
static void SetTextureNoErr (side_t *side, int position, DWORD *color, char *name8, bool *validcolor, bool isFog)
|
||||
{
|
||||
char name[9];
|
||||
FTextureID texture;
|
||||
strncpy (name, name8, 8);
|
||||
name[8] = 0;
|
||||
|
||||
*validcolor = false;
|
||||
texture = TexMan.CheckForTexture (name, FTexture::TEX_Wall,
|
||||
FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny);
|
||||
if (!texture.Exists())
|
||||
{
|
||||
char name2[9];
|
||||
char *stop;
|
||||
strncpy (name2, name, 8);
|
||||
name2[8] = 0;
|
||||
*color = strtoul (name2, &stop, 16);
|
||||
strncpy (name2, name+1, 7);
|
||||
name2[7] = 0;
|
||||
if (*name != '#')
|
||||
{
|
||||
*color = strtoul (name, &stop, 16);
|
||||
texture = FNullTextureID();
|
||||
*validcolor = (*stop == 0) && (stop >= name2 + 2) && (stop <= name2 + 6);
|
||||
*validcolor = (*stop == 0) && (stop >= name + 2) && (stop <= name + 6);
|
||||
return;
|
||||
}
|
||||
else // Support for Legacy's color format!
|
||||
{
|
||||
int l=(int)strlen(name);
|
||||
texture = FNullTextureID();
|
||||
*validcolor = false;
|
||||
if (l>=7)
|
||||
{
|
||||
for(stop=name2;stop<name2+6;stop++) if (!isxdigit(*stop)) *stop='0';
|
||||
|
||||
int factor = l==7? 0 : clamp<int> ((name2[6]&223)-'A', 0, 25);
|
||||
|
||||
name2[6]=0; int blue=strtol(name2+4,NULL,16);
|
||||
name2[4]=0; int green=strtol(name2+2,NULL,16);
|
||||
name2[2]=0; int red=strtol(name2,NULL,16);
|
||||
|
||||
if (!isFog)
|
||||
{
|
||||
if (factor==0)
|
||||
{
|
||||
*validcolor=false;
|
||||
return;
|
||||
}
|
||||
factor = factor * 255 / 25;
|
||||
}
|
||||
else
|
||||
{
|
||||
*validcolor = false;
|
||||
factor=0;
|
||||
}
|
||||
|
||||
*color=MAKEARGB(factor, red, green, blue);
|
||||
texture = FNullTextureID();
|
||||
*validcolor = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
texture = FNullTextureID();
|
||||
}
|
||||
side->SetTexture(position, texture);
|
||||
}
|
||||
|
@ -1570,6 +1605,7 @@ void SpawnMapThing(int index, FMapThing *mt, int position)
|
|||
index, mt->x>>FRACBITS, mt->y>>FRACBITS, mt->z>>FRACBITS, mt->type, mt->flags,
|
||||
spawned? spawned->GetClass()->TypeName.GetChars() : "(none)");
|
||||
}
|
||||
T_AddSpawnedThing(spawned);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -1767,7 +1803,7 @@ void P_SetLineID (line_t *ld)
|
|||
// [RH] Set line id (as appropriate) here
|
||||
// for Doom format maps this must be done in P_TranslateLineDef because
|
||||
// the tag doesn't always go into the first arg.
|
||||
if (level.flags & LEVEL_HEXENFORMAT)
|
||||
if (level.maptype == MAPTYPE_HEXEN)
|
||||
{
|
||||
switch (ld->special)
|
||||
{
|
||||
|
@ -2334,8 +2370,8 @@ void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, mapside
|
|||
DWORD color = MAKERGB(255,255,255), fog = 0;
|
||||
bool colorgood, foggood;
|
||||
|
||||
SetTextureNoErr (sd, side_t::bottom, &fog, msd->bottomtexture, &foggood);
|
||||
SetTextureNoErr (sd, side_t::top, &color, msd->toptexture, &colorgood);
|
||||
SetTextureNoErr (sd, side_t::bottom, &fog, msd->bottomtexture, &foggood, true);
|
||||
SetTextureNoErr (sd, side_t::top, &color, msd->toptexture, &colorgood, false);
|
||||
strncpy (name, msd->midtexture, 8);
|
||||
SetTexture(sd, side_t::mid, msd->midtexture);
|
||||
|
||||
|
@ -2899,7 +2935,6 @@ line_t** linebuffer;
|
|||
static void P_GroupLines (bool buildmap)
|
||||
{
|
||||
cycle_t times[16];
|
||||
TArray<linf> exLightTags;
|
||||
int* linesDoneInEachSector;
|
||||
int i;
|
||||
int j;
|
||||
|
@ -2909,7 +2944,7 @@ static void P_GroupLines (bool buildmap)
|
|||
sector_t* sector;
|
||||
FBoundingBox bbox;
|
||||
bool flaggedNoFronts = false;
|
||||
unsigned int ii, jj;
|
||||
unsigned int jj;
|
||||
|
||||
for (i = 0; i < (int)countof(times); ++i)
|
||||
{
|
||||
|
@ -2960,29 +2995,6 @@ static void P_GroupLines (bool buildmap)
|
|||
li->backsector->linecount++;
|
||||
total++;
|
||||
}
|
||||
|
||||
// [RH] Count extra lights
|
||||
if (li->special == ExtraFloor_LightOnly)
|
||||
{
|
||||
int adder = li->args[1] == 1 ? 2 : 1;
|
||||
|
||||
for (ii = 0; ii < exLightTags.Size(); ++ii)
|
||||
{
|
||||
if (exLightTags[ii].tag == li->args[0])
|
||||
break;
|
||||
}
|
||||
if (ii == exLightTags.Size())
|
||||
{
|
||||
linf info = { li->args[0], adder };
|
||||
exLightTags.Push (info);
|
||||
totallights += adder;
|
||||
}
|
||||
else
|
||||
{
|
||||
totallights += adder;
|
||||
exLightTags[ii].count += adder;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flaggedNoFronts)
|
||||
{
|
||||
|
@ -2990,21 +3002,6 @@ static void P_GroupLines (bool buildmap)
|
|||
}
|
||||
times[1].Unclock();
|
||||
|
||||
// collect extra light info
|
||||
times[2].Clock();
|
||||
LightStacks = new FLightStack[totallights];
|
||||
ExtraLights = new FExtraLight[exLightTags.Size()];
|
||||
memset (ExtraLights, 0, exLightTags.Size()*sizeof(FExtraLight));
|
||||
|
||||
for (ii = 0, jj = 0; ii < exLightTags.Size(); ++ii)
|
||||
{
|
||||
ExtraLights[ii].Tag = exLightTags[ii].tag;
|
||||
ExtraLights[ii].NumLights = exLightTags[ii].count;
|
||||
ExtraLights[ii].Lights = &LightStacks[jj];
|
||||
jj += ExtraLights[ii].NumLights;
|
||||
}
|
||||
times[2].Unclock();
|
||||
|
||||
// build line tables for each sector
|
||||
times[3].Clock();
|
||||
linebuffer = new line_t *[total];
|
||||
|
@ -3060,43 +3057,6 @@ static void P_GroupLines (bool buildmap)
|
|||
sector->soundorg[0] = bbox.Right()/2 + bbox.Left()/2;
|
||||
sector->soundorg[1] = bbox.Top()/2 + bbox.Bottom()/2;
|
||||
sector->soundorg[2] = sector->floorplane.ZatPoint (sector->soundorg[0], sector->soundorg[1]);
|
||||
|
||||
// Find a triangle in the sector for sorting extra lights
|
||||
// The points must be in the sector, because intersecting
|
||||
// planes are okay so long as they intersect beyond all
|
||||
// sectors that use them.
|
||||
if (sector->linecount == 0)
|
||||
{ // If the sector has no lines, its tag is guaranteed to be 0, which
|
||||
// means it cannot be used for extralights. So just use some dummy
|
||||
// vertices for the triangle.
|
||||
sector->Triangle[0] = vertexes;
|
||||
sector->Triangle[1] = vertexes;
|
||||
sector->Triangle[2] = vertexes;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector->Triangle[0] = sector->lines[0]->v1;
|
||||
sector->Triangle[1] = sector->lines[0]->v2;
|
||||
sector->Triangle[2] = sector->Triangle[0]; // failsafe
|
||||
if (sector->linecount > 1)
|
||||
{
|
||||
fixed_t dx = sector->Triangle[1]->x - sector->Triangle[0]->x;
|
||||
fixed_t dy = sector->Triangle[1]->y - sector->Triangle[1]->y;
|
||||
// Find another point in the sector that does not lie
|
||||
// on the same line as the first two points.
|
||||
for (j = 2; j < sector->linecount*2; ++j)
|
||||
{
|
||||
vertex_t *v;
|
||||
|
||||
v = (j & 1) ? sector->lines[j>>1]->v1 : sector->lines[j>>1]->v2;
|
||||
if (DMulScale32 (v->y - sector->Triangle[0]->y, dx,
|
||||
sector->Triangle[0]->x - v->x, dy) != 0)
|
||||
{
|
||||
sector->Triangle[2] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] linesDoneInEachSector;
|
||||
times[3].Unclock();
|
||||
|
@ -3113,33 +3073,6 @@ static void P_GroupLines (bool buildmap)
|
|||
}
|
||||
times[5].Unclock();
|
||||
|
||||
times[6].Clock();
|
||||
for (i = 0, li = lines; i < numlines; ++i, ++li)
|
||||
{
|
||||
if (li->special == ExtraFloor_LightOnly)
|
||||
{
|
||||
for (ii = 0; ii < exLightTags.Size(); ++ii)
|
||||
{
|
||||
if (ExtraLights[ii].Tag == li->args[0])
|
||||
break;
|
||||
}
|
||||
if (ii < exLightTags.Size())
|
||||
{
|
||||
ExtraLights[ii].InsertLight (li->frontsector->ceilingplane, li, li->args[1] == 2);
|
||||
if (li->args[1] == 1)
|
||||
{
|
||||
ExtraLights[ii].InsertLight (li->frontsector->floorplane, li, 2);
|
||||
}
|
||||
j = -1;
|
||||
while ((j = P_FindSectorFromTag (li->args[0], j)) >= 0)
|
||||
{
|
||||
sectors[j].ExtraLights = &ExtraLights[ii];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
times[6].Unclock();
|
||||
|
||||
if (showloadtimes)
|
||||
{
|
||||
Printf ("---Group Lines Times---\n");
|
||||
|
@ -3150,56 +3083,6 @@ static void P_GroupLines (bool buildmap)
|
|||
}
|
||||
}
|
||||
|
||||
void FExtraLight::InsertLight (const secplane_t &inplane, line_t *line, int type)
|
||||
{
|
||||
// type 0 : !bottom, !flooder
|
||||
// type 1 : !bottom, flooder
|
||||
// type 2 : bottom, !flooder
|
||||
|
||||
vertex_t **triangle = line->frontsector->Triangle;
|
||||
int i, j;
|
||||
fixed_t diff = FIXED_MAX;
|
||||
secplane_t plane = inplane;
|
||||
|
||||
if (type != 2)
|
||||
{
|
||||
plane.FlipVert ();
|
||||
}
|
||||
|
||||
// Find the first plane this light is above and insert it there
|
||||
for (i = 0; i < NumUsedLights; ++i)
|
||||
{
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
diff = plane.ZatPoint (triangle[j]) - Lights[i].Plane.ZatPoint (triangle[j]);
|
||||
if (diff != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diff >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < NumLights)
|
||||
{
|
||||
for (j = MIN<int>(NumUsedLights, NumLights-1); j > i; --j)
|
||||
{
|
||||
Lights[j] = Lights[j-1];
|
||||
}
|
||||
Lights[i].Plane = plane;
|
||||
Lights[i].Master = type == 2 ? NULL : line->frontsector;
|
||||
Lights[i].bBottom = type == 2;
|
||||
Lights[i].bFlooder = type == 1;
|
||||
Lights[i].bOverlaps = diff == 0;
|
||||
if (NumUsedLights < NumLights)
|
||||
{
|
||||
++NumUsedLights;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// P_LoadReject
|
||||
//
|
||||
|
@ -3451,16 +3334,6 @@ void P_FreeLevelData ()
|
|||
delete[] rejectmatrix;
|
||||
rejectmatrix = NULL;
|
||||
}
|
||||
if (LightStacks != NULL)
|
||||
{
|
||||
delete[] LightStacks;
|
||||
LightStacks = NULL;
|
||||
}
|
||||
if (ExtraLights != NULL)
|
||||
{
|
||||
delete[] ExtraLights;
|
||||
ExtraLights = NULL;
|
||||
}
|
||||
if (linebuffer != NULL)
|
||||
{
|
||||
delete[] linebuffer;
|
||||
|
@ -3538,6 +3411,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
times[i].Reset();
|
||||
}
|
||||
|
||||
level.maptype = MAPTYPE_UNKNOWN;
|
||||
wminfo.partime = 180;
|
||||
|
||||
MapThingsConverted.Clear();
|
||||
|
@ -3618,7 +3492,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
if (map->HasBehavior)
|
||||
{
|
||||
P_LoadBehavior (map);
|
||||
level.flags |= LEVEL_HEXENFORMAT;
|
||||
level.maptype = MAPTYPE_HEXEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3641,9 +3515,14 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
}
|
||||
}
|
||||
P_LoadTranslator(translator);
|
||||
level.maptype = MAPTYPE_DOOM;
|
||||
}
|
||||
if (map->isText)
|
||||
{
|
||||
level.maptype = MAPTYPE_UDMF;
|
||||
}
|
||||
CheckCompatibility(map);
|
||||
|
||||
T_LoadScripts(map);
|
||||
|
||||
if (!map->HasBehavior || map->isText)
|
||||
{
|
||||
|
@ -3721,6 +3600,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
else
|
||||
{
|
||||
ForceNodeBuild = true;
|
||||
level.maptype = MAPTYPE_BUILD;
|
||||
}
|
||||
bool reloop = false;
|
||||
|
||||
|
@ -3996,6 +3876,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
}
|
||||
}
|
||||
|
||||
T_PreprocessScripts(); // preprocess FraggleScript scripts
|
||||
|
||||
// build subsector connect matrix
|
||||
// UNUSED P_ConnectSubsectors ();
|
||||
|
|
161
src/r_3dfloors.cpp
Normal file
161
src/r_3dfloors.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
** r_3dfloors.cpp
|
||||
** software 3D floors addon
|
||||
**
|
||||
** by kgsws
|
||||
*/
|
||||
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_local.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "r_local.h"
|
||||
#include "r_bsp.h"
|
||||
#include "r_plane.h"
|
||||
|
||||
#include "r_3dfloors.h"
|
||||
|
||||
// external variables
|
||||
int fake3D;
|
||||
F3DFloor *fakeFloor;
|
||||
fixed_t fakeHeight;
|
||||
fixed_t fakeAlpha;
|
||||
int fakeActive = 0;
|
||||
fixed_t sclipBottom;
|
||||
fixed_t sclipTop;
|
||||
HeightLevel *height_top = NULL;
|
||||
HeightLevel *height_cur = NULL;
|
||||
int CurrentMirror = 0;
|
||||
int CurrentSkybox = 0;
|
||||
|
||||
// private variables
|
||||
int height_max = -1;
|
||||
TArray<HeightStack> toplist;
|
||||
ClipStack *clip_top = NULL;
|
||||
ClipStack *clip_cur = NULL;
|
||||
|
||||
void R_3D_DeleteHeights()
|
||||
{
|
||||
height_cur = height_top;
|
||||
while(height_cur) {
|
||||
height_top = height_cur;
|
||||
height_cur = height_cur->next;
|
||||
M_Free(height_top);
|
||||
}
|
||||
height_max = -1;
|
||||
height_top = height_cur = NULL;
|
||||
}
|
||||
|
||||
void R_3D_AddHeight(secplane_t *add, sector_t *sec)
|
||||
{
|
||||
HeightLevel *near;
|
||||
HeightLevel *curr;
|
||||
fixed_t height;
|
||||
|
||||
height = add->ZatPoint(viewx, viewy);
|
||||
if(height >= sec->CenterCeiling()) return;
|
||||
if(height <= sec->CenterFloor()) return;
|
||||
|
||||
fakeActive = 1;
|
||||
|
||||
if(height_max >= 0) {
|
||||
near = height_top;
|
||||
while(near && near->height < height) near = near->next;
|
||||
if(near) {
|
||||
if(near->height == height) return;
|
||||
curr = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
|
||||
curr->height = height;
|
||||
curr->prev = near->prev;
|
||||
curr->next = near;
|
||||
if(near->prev) near->prev->next = curr;
|
||||
else height_top = curr;
|
||||
near->prev = curr;
|
||||
} else {
|
||||
curr = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
|
||||
curr->height = height;
|
||||
curr->prev = height_cur;
|
||||
curr->next = NULL;
|
||||
height_cur->next = curr;
|
||||
height_cur = curr;
|
||||
}
|
||||
} else {
|
||||
height_top = height_cur = (HeightLevel*)M_Malloc(sizeof(HeightLevel));
|
||||
height_top->height = height;
|
||||
height_top->prev = NULL;
|
||||
height_top->next = NULL;
|
||||
}
|
||||
height_max++;
|
||||
}
|
||||
|
||||
void R_3D_NewClip()
|
||||
{
|
||||
ClipStack *curr;
|
||||
// extern short floorclip[MAXWIDTH];
|
||||
// extern short ceilingclip[MAXWIDTH];
|
||||
|
||||
curr = (ClipStack*)M_Malloc(sizeof(ClipStack));
|
||||
curr->next = 0;
|
||||
memcpy(curr->floorclip, floorclip, sizeof(short) * MAXWIDTH);
|
||||
memcpy(curr->ceilingclip, ceilingclip, sizeof(short) * MAXWIDTH);
|
||||
curr->ffloor = fakeFloor;
|
||||
assert(fakeFloor->floorclip == NULL);
|
||||
assert(fakeFloor->ceilingclip == NULL);
|
||||
fakeFloor->floorclip = curr->floorclip;
|
||||
fakeFloor->ceilingclip = curr->ceilingclip;
|
||||
if(clip_top) {
|
||||
clip_cur->next = curr;
|
||||
clip_cur = curr;
|
||||
} else {
|
||||
clip_top = clip_cur = curr;
|
||||
}
|
||||
}
|
||||
|
||||
void R_3D_ResetClip()
|
||||
{
|
||||
clip_cur = clip_top;
|
||||
while(clip_cur)
|
||||
{
|
||||
assert(clip_cur->ffloor->floorclip != NULL);
|
||||
assert(clip_cur->ffloor->ceilingclip != NULL);
|
||||
clip_cur->ffloor->ceilingclip = clip_cur->ffloor->floorclip = NULL;
|
||||
clip_top = clip_cur;
|
||||
clip_cur = clip_cur->next;
|
||||
M_Free(clip_top);
|
||||
}
|
||||
clip_cur = clip_top = NULL;
|
||||
}
|
||||
|
||||
void R_3D_EnterSkybox()
|
||||
{
|
||||
HeightStack current;
|
||||
|
||||
current.height_top = height_top;
|
||||
current.height_cur = height_cur;
|
||||
current.height_max = height_max;
|
||||
|
||||
toplist.Push(current);
|
||||
|
||||
height_top = NULL;
|
||||
height_cur = NULL;
|
||||
height_max = -1;
|
||||
|
||||
CurrentSkybox++;
|
||||
}
|
||||
|
||||
void R_3D_LeaveSkybox()
|
||||
{
|
||||
HeightStack current;
|
||||
|
||||
current.height_top = NULL;
|
||||
current.height_cur = NULL;
|
||||
current.height_max = -1;
|
||||
|
||||
toplist.Pop(current);
|
||||
|
||||
height_top = current.height_top;
|
||||
height_cur = current.height_cur;
|
||||
height_max = current.height_max;
|
||||
|
||||
CurrentSkybox--;
|
||||
}
|
||||
|
69
src/r_3dfloors.h
Normal file
69
src/r_3dfloors.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef SOFT_FAKE3D_H
|
||||
#define SOFT_FAKE3D_H
|
||||
|
||||
#include "p_3dfloors.h"
|
||||
|
||||
// special types
|
||||
|
||||
struct HeightLevel
|
||||
{
|
||||
fixed_t height;
|
||||
struct HeightLevel *prev;
|
||||
struct HeightLevel *next;
|
||||
};
|
||||
|
||||
struct HeightStack
|
||||
{
|
||||
HeightLevel *height_top;
|
||||
HeightLevel *height_cur;
|
||||
int height_max;
|
||||
};
|
||||
|
||||
struct ClipStack
|
||||
{
|
||||
short floorclip[MAXWIDTH];
|
||||
short ceilingclip[MAXWIDTH];
|
||||
F3DFloor *ffloor;
|
||||
ClipStack *next;
|
||||
};
|
||||
|
||||
// external varialbes
|
||||
|
||||
// fake3D flags:
|
||||
enum
|
||||
{
|
||||
// BSP stage:
|
||||
FAKE3D_FAKEFLOOR = 1, // fake floor, mark seg as FAKE
|
||||
FAKE3D_FAKECEILING = 2, // fake ceiling, mark seg as FAKE
|
||||
FAKE3D_FAKEBACK = 4, // R_AddLine with fake backsector, mark seg as FAKE
|
||||
FAKE3D_FAKEMASK = 7,
|
||||
|
||||
// sorting stage:
|
||||
FAKE3D_CLIPBOTTOM = 1, // clip bottom
|
||||
FAKE3D_CLIPTOP = 2, // clip top
|
||||
FAKE3D_REFRESHCLIP = 4, // refresh clip info
|
||||
FAKE3D_DOWN2UP = 8, // rendering from down to up (floors)
|
||||
FAKE3D_16 = 16, // what is this?
|
||||
};
|
||||
|
||||
extern int fake3D;
|
||||
extern F3DFloor *fakeFloor;
|
||||
extern fixed_t fakeHeight;
|
||||
extern fixed_t fakeAlpha;
|
||||
extern int fakeActive;
|
||||
extern fixed_t sclipBottom;
|
||||
extern fixed_t sclipTop;
|
||||
extern HeightLevel *height_top;
|
||||
extern HeightLevel *height_cur;
|
||||
extern int CurrentMirror;
|
||||
extern int CurrentSkybox;
|
||||
|
||||
// functions
|
||||
void R_3D_DeleteHeights();
|
||||
void R_3D_AddHeight(secplane_t *add, sector_t *sec);
|
||||
void R_3D_NewClip();
|
||||
void R_3D_ResetClip();
|
||||
void R_3D_EnterSkybox();
|
||||
void R_3D_LeaveSkybox();
|
||||
|
||||
#endif
|
316
src/r_bsp.cpp
316
src/r_bsp.cpp
|
@ -42,6 +42,7 @@
|
|||
#include "r_plane.h"
|
||||
#include "r_draw.h"
|
||||
#include "r_things.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "nodebuild.h"
|
||||
|
@ -189,6 +190,10 @@ bool R_ClipWallSegment (int first, int last, bool solid)
|
|||
{
|
||||
// Post is entirely visible (above start).
|
||||
R_StoreWallRange (first, last);
|
||||
if (fake3D & FAKE3D_FAKEMASK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert a new clippost for solid walls.
|
||||
if (solid)
|
||||
|
@ -217,7 +222,7 @@ bool R_ClipWallSegment (int first, int last, bool solid)
|
|||
R_StoreWallRange (first, start->first);
|
||||
|
||||
// Adjust the clip size for solid walls
|
||||
if (solid)
|
||||
if (solid && !(fake3D & FAKE3D_FAKEMASK))
|
||||
{
|
||||
start->first = first;
|
||||
}
|
||||
|
@ -246,6 +251,10 @@ bool R_ClipWallSegment (int first, int last, bool solid)
|
|||
R_StoreWallRange (next->last, last);
|
||||
|
||||
crunch:
|
||||
if (fake3D & FAKE3D_FAKEMASK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (solid)
|
||||
{
|
||||
// Adjust the clip size.
|
||||
|
@ -715,8 +724,10 @@ void R_AddLine (seg_t *line)
|
|||
WallDepthScale = WallInvZstep * WallTMapScale2;
|
||||
WallDepthOrg = -WallUoverZstep * WallTMapScale2;
|
||||
|
||||
if (!(fake3D & FAKE3D_FAKEBACK))
|
||||
{
|
||||
backsector = line->backsector;
|
||||
|
||||
}
|
||||
rw_frontcz1 = frontsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y);
|
||||
rw_frontfz1 = frontsector->floorplane.ZatPoint (line->v1->x, line->v1->y);
|
||||
rw_frontcz2 = frontsector->ceilingplane.ZatPoint (line->v2->x, line->v2->y);
|
||||
|
@ -732,9 +743,11 @@ void R_AddLine (seg_t *line)
|
|||
}
|
||||
else
|
||||
{
|
||||
// killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
|
||||
// kg3D - its fake, no transfer_heights
|
||||
if (!(fake3D & FAKE3D_FAKEBACK))
|
||||
{ // killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
|
||||
backsector = R_FakeFlat (backsector, &tempsec, NULL, NULL, true);
|
||||
|
||||
}
|
||||
doorclosed = 0; // killough 4/16/98
|
||||
|
||||
rw_backcz1 = backsector->ceilingplane.ZatPoint (line->v1->x, line->v1->y);
|
||||
|
@ -817,6 +830,10 @@ void R_AddLine (seg_t *line)
|
|||
// [RH] and rotation
|
||||
|| backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
|
||||
|| backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
|
||||
|
||||
// kg3D - and fake lights
|
||||
|| (frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
|| (backsector->e && backsector->e->XFloor.lightlist.Size())
|
||||
)
|
||||
{
|
||||
solid = false;
|
||||
|
@ -1003,65 +1020,6 @@ static bool R_CheckBBox (fixed_t *bspcoord) // killough 1/28/98: static
|
|||
return true;
|
||||
}
|
||||
|
||||
void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el)
|
||||
{
|
||||
FDynamicColormap *floodcolormap;
|
||||
int floodlight;
|
||||
bool flooding;
|
||||
vertex_t **triangle;
|
||||
int i, j;
|
||||
fixed_t diff;
|
||||
|
||||
if (el == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
triangle = frontsector->Triangle;
|
||||
flooding = false;
|
||||
floodcolormap = basecolormap;
|
||||
floodlight = *light;
|
||||
|
||||
for (i = 0; i < el->NumUsedLights; ++i)
|
||||
{
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
diff = plane.ZatPoint (triangle[j]) - el->Lights[i].Plane.ZatPoint (triangle[j]);
|
||||
if (diff != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (diff >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!flooding || el->Lights[i].bFlooder)
|
||||
{
|
||||
if (el->Lights[i].Master == NULL)
|
||||
{
|
||||
basecolormap = floodcolormap;
|
||||
*light = floodlight;
|
||||
}
|
||||
else
|
||||
{
|
||||
basecolormap = el->Lights[i].Master->ColorMap;
|
||||
*light = el->Lights[i].Master->lightlevel;
|
||||
if (el->Lights[i].bFlooder)
|
||||
{
|
||||
flooding = true;
|
||||
floodcolormap = basecolormap;
|
||||
floodlight = *light;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FMiniBSP Constructor
|
||||
|
@ -1129,6 +1087,24 @@ static void R_AddPolyobjs(subsector_t *sub)
|
|||
}
|
||||
}
|
||||
|
||||
// kg3D - add fake segs, never rendered
|
||||
void R_FakeDrawLoop(subsector_t *sub)
|
||||
{
|
||||
int count;
|
||||
seg_t* line;
|
||||
|
||||
count = sub->numlines;
|
||||
line = sub->firstline;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if ((line->sidedef) && !(line->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
R_AddLine (line);
|
||||
}
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// R_Subsector
|
||||
|
@ -1144,6 +1120,13 @@ void R_Subsector (subsector_t *sub)
|
|||
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
||||
int ceilinglightlevel; // killough 4/11/98
|
||||
bool outersubsector;
|
||||
int fll, cll;
|
||||
|
||||
// kg3D - fake floor stuff
|
||||
visplane_t *backupfp;
|
||||
visplane_t *backupcp;
|
||||
//secplane_t templane;
|
||||
lightlist_t *light;
|
||||
|
||||
if (InSubsector != NULL)
|
||||
{ // InSubsector is not NULL. This means we are rendering from a mini-BSP.
|
||||
|
@ -1181,13 +1164,26 @@ void R_Subsector (subsector_t *sub)
|
|||
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
||||
&ceilinglightlevel, false); // killough 4/11/98
|
||||
|
||||
basecolormap = frontsector->ColorMap;
|
||||
R_GetExtraLight (&ceilinglightlevel, frontsector->ceilingplane, frontsector->ExtraLights);
|
||||
fll = floorlightlevel;
|
||||
cll = ceilinglightlevel;
|
||||
|
||||
// [RH] set foggy flag
|
||||
foggy = level.fadeto || frontsector->ColorMap->Fade || (level.flags & LEVEL_HASFADETABLE);
|
||||
r_actualextralight = foggy ? 0 : extralight << 4;
|
||||
|
||||
// kg3D - fake lights
|
||||
if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(frontsector, &frontsector->ceilingplane, false);
|
||||
basecolormap = light->extra_colormap;
|
||||
ceilinglightlevel = *light->p_lightlevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
basecolormap = frontsector->ColorMap;
|
||||
ceilinglightlevel = frontsector->lightlevel;
|
||||
}
|
||||
|
||||
ceilingplane = frontsector->ceilingplane.ZatPoint (viewx, viewy) > viewz ||
|
||||
frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
|
||||
(frontsector->CeilingSkyBox != NULL && frontsector->CeilingSkyBox->bAlways) ||
|
||||
|
@ -1207,8 +1203,17 @@ void R_Subsector (subsector_t *sub)
|
|||
frontsector->CeilingSkyBox
|
||||
) : NULL;
|
||||
|
||||
if (fixedlightlev < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(frontsector, &frontsector->floorplane, false);
|
||||
basecolormap = light->extra_colormap;
|
||||
floorlightlevel = *light->p_lightlevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
basecolormap = frontsector->ColorMap;
|
||||
R_GetExtraLight (&floorlightlevel, frontsector->floorplane, frontsector->ExtraLights);
|
||||
floorlightlevel = frontsector->lightlevel;
|
||||
}
|
||||
|
||||
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check
|
||||
// killough 3/16/98: add floorlightlevel
|
||||
|
@ -1232,6 +1237,142 @@ void R_Subsector (subsector_t *sub)
|
|||
frontsector->FloorSkyBox
|
||||
) : NULL;
|
||||
|
||||
// kg3D - fake planes rendering
|
||||
if (frontsector->e && frontsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
backupfp = floorplane;
|
||||
backupcp = ceilingplane;
|
||||
// first check all floors
|
||||
for (int i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
fakeFloor = frontsector->e->XFloor.ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (fakeFloor->bottom.plane->a || fakeFloor->bottom.plane->b) continue;
|
||||
if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES|FF_RENDERSIDES)))
|
||||
{
|
||||
R_3D_AddHeight(fakeFloor->top.plane, frontsector);
|
||||
}
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR) continue;
|
||||
fakeAlpha = MIN(Scale(fakeFloor->alpha, OPAQUE, 255), OPAQUE);
|
||||
if (fakeFloor->validcount != validcount)
|
||||
{
|
||||
fakeFloor->validcount = validcount;
|
||||
R_3D_NewClip();
|
||||
}
|
||||
fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->soundorg[0], frontsector->soundorg[0]);
|
||||
if (fakeHeight < viewz &&
|
||||
fakeHeight > frontsector->floorplane.ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]))
|
||||
{
|
||||
fake3D = FAKE3D_FAKEFLOOR;
|
||||
tempsec = *fakeFloor->model;
|
||||
tempsec.floorplane = *fakeFloor->top.plane;
|
||||
if (!(fakeFloor->flags & FF_THISINSIDE) && !(fakeFloor->flags & FF_INVERTSECTOR))
|
||||
{
|
||||
tempsec.SetTexture(sector_t::floor, tempsec.GetTexture(sector_t::ceiling));
|
||||
}
|
||||
frontsector = &tempsec;
|
||||
|
||||
if (fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(sub->sector, &frontsector->floorplane, false);
|
||||
basecolormap = light->extra_colormap;
|
||||
floorlightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
ceilingplane = NULL;
|
||||
floorplane = R_FindPlane(frontsector->floorplane,
|
||||
frontsector->GetTexture(sector_t::floor),
|
||||
floorlightlevel + r_actualextralight, // killough 3/16/98
|
||||
frontsector->GetAlpha(sector_t::floor),
|
||||
frontsector->GetXOffset(sector_t::floor), // killough 3/7/98
|
||||
frontsector->GetYOffset(sector_t::floor), // killough 3/7/98
|
||||
frontsector->GetXScale(sector_t::floor),
|
||||
frontsector->GetYScale(sector_t::floor),
|
||||
frontsector->GetAngle(sector_t::floor),
|
||||
frontsector->sky,
|
||||
NULL);
|
||||
|
||||
R_FakeDrawLoop(sub);
|
||||
fake3D = 0;
|
||||
frontsector = sub->sector;
|
||||
}
|
||||
}
|
||||
// and now ceilings
|
||||
for (unsigned int i = 0; i < frontsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
fakeFloor = frontsector->e->XFloor.ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (fakeFloor->top.plane->a || fakeFloor->top.plane->b) continue;
|
||||
if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES|FF_RENDERSIDES)))
|
||||
{
|
||||
R_3D_AddHeight(fakeFloor->bottom.plane, frontsector);
|
||||
}
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (!(fakeFloor->flags & FF_THISINSIDE) && (fakeFloor->flags & (FF_SWIMMABLE|FF_INVERTSECTOR)) == (FF_SWIMMABLE|FF_INVERTSECTOR)) continue;
|
||||
fakeAlpha = MIN(Scale(fakeFloor->alpha, OPAQUE, 255), OPAQUE);
|
||||
|
||||
if (fakeFloor->validcount != validcount)
|
||||
{
|
||||
fakeFloor->validcount = validcount;
|
||||
R_3D_NewClip();
|
||||
}
|
||||
fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]);
|
||||
if (fakeHeight > viewz &&
|
||||
fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->soundorg[0], frontsector->soundorg[1]))
|
||||
{
|
||||
fake3D = FAKE3D_FAKECEILING;
|
||||
tempsec = *fakeFloor->model;
|
||||
tempsec.ceilingplane = *fakeFloor->bottom.plane;
|
||||
if (!(fakeFloor->flags & FF_THISINSIDE) &&
|
||||
!(fakeFloor->flags & FF_INVERTSECTOR) ||
|
||||
fakeFloor->flags & FF_THISINSIDE &&
|
||||
fakeFloor->flags & FF_INVERTSECTOR)
|
||||
{
|
||||
tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor));
|
||||
}
|
||||
frontsector = &tempsec;
|
||||
|
||||
tempsec.ceilingplane.ChangeHeight(-1);
|
||||
if (fixedlightlev < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
light = P_GetPlaneLight(sub->sector, &frontsector->ceilingplane, false);
|
||||
basecolormap = light->extra_colormap;
|
||||
ceilinglightlevel = *light->p_lightlevel;
|
||||
}
|
||||
tempsec.ceilingplane.ChangeHeight(1);
|
||||
|
||||
floorplane = NULL;
|
||||
ceilingplane = R_FindPlane(frontsector->ceilingplane, // killough 3/8/98
|
||||
frontsector->GetTexture(sector_t::ceiling),
|
||||
ceilinglightlevel + r_actualextralight, // killough 4/11/98
|
||||
frontsector->GetAlpha(sector_t::ceiling),
|
||||
frontsector->GetXOffset(sector_t::ceiling), // killough 3/7/98
|
||||
frontsector->GetYOffset(sector_t::ceiling), // killough 3/7/98
|
||||
frontsector->GetXScale(sector_t::ceiling),
|
||||
frontsector->GetYScale(sector_t::ceiling),
|
||||
frontsector->GetAngle(sector_t::ceiling),
|
||||
frontsector->sky,
|
||||
NULL);
|
||||
|
||||
R_FakeDrawLoop(sub);
|
||||
fake3D = 0;
|
||||
frontsector = sub->sector;
|
||||
}
|
||||
}
|
||||
fakeFloor = NULL;
|
||||
floorplane = backupfp;
|
||||
ceilingplane = backupcp;
|
||||
}
|
||||
|
||||
basecolormap = frontsector->ColorMap;
|
||||
floorlightlevel = fll;
|
||||
ceilinglightlevel = cll;
|
||||
|
||||
// killough 9/18/98: Fix underwater slowdown, by passing real sector
|
||||
// instead of fake one. Improve sprite lighting by basing sprite
|
||||
// lightlevels on floor & ceiling lightlevels in the surrounding area.
|
||||
|
@ -1250,11 +1391,52 @@ void R_Subsector (subsector_t *sub)
|
|||
}
|
||||
}
|
||||
|
||||
count = sub->numlines;
|
||||
line = sub->firstline;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (!outersubsector || line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
R_AddLine (line);
|
||||
// kg3D - fake planes bounding calculation
|
||||
if (line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
backupfp = floorplane;
|
||||
backupcp = ceilingplane;
|
||||
floorplane = NULL;
|
||||
ceilingplane = NULL;
|
||||
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
fakeFloor = line->backsector->e->XFloor.ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
fake3D = FAKE3D_FAKEBACK;
|
||||
tempsec = *fakeFloor->model;
|
||||
tempsec.floorplane = *fakeFloor->top.plane;
|
||||
tempsec.ceilingplane = *fakeFloor->bottom.plane;
|
||||
backsector = &tempsec;
|
||||
if (fakeFloor->validcount != validcount)
|
||||
{
|
||||
fakeFloor->validcount = validcount;
|
||||
R_3D_NewClip();
|
||||
}
|
||||
if (frontsector->CenterFloor() >= backsector->CenterFloor())
|
||||
{
|
||||
fake3D |= FAKE3D_DOWN2UP;
|
||||
}
|
||||
if (frontsector->CenterCeiling() <= backsector->CenterCeiling())
|
||||
{
|
||||
fake3D |= FAKE3D_16;
|
||||
}
|
||||
R_AddLine(line); // fake
|
||||
}
|
||||
fakeFloor = NULL;
|
||||
fake3D = 0;
|
||||
floorplane = backupfp;
|
||||
ceilingplane = backupcp;
|
||||
}
|
||||
R_AddLine (line); // now real
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ struct drawseg_t
|
|||
fixed_t yrepeat;
|
||||
BYTE silhouette; // 0=none, 1=bottom, 2=top, 3=both
|
||||
BYTE bFogBoundary;
|
||||
BYTE bFakeBoundary; // for fake walls
|
||||
int shade;
|
||||
// Pointers to lists for sprite clipping,
|
||||
// all three adjusted so [x1] is first value.
|
||||
|
@ -46,6 +47,10 @@ struct drawseg_t
|
|||
ptrdiff_t sprbottomclip; // type short
|
||||
ptrdiff_t maskedtexturecol; // type short
|
||||
ptrdiff_t swall; // type fixed_t
|
||||
int fake; // ident fake drawseg, don't draw and clip sprites
|
||||
// backups
|
||||
ptrdiff_t bkup; // sprtopclip backup, for mid and fake textures
|
||||
float WallUoverZorg, WallUoverZstep, WallInvZorg, WallInvZstep, WallDepthScale, WallDepthOrg;
|
||||
};
|
||||
|
||||
|
||||
|
|
35
src/r_defs.h
35
src/r_defs.h
|
@ -212,6 +212,12 @@ struct secplane_t
|
|||
|
||||
fixed_t a, b, c, d, ic;
|
||||
|
||||
// Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes
|
||||
fixed_t Zat0 () const
|
||||
{
|
||||
return ic < 0? d:-d;
|
||||
}
|
||||
|
||||
// Returns the value of z at (x,y)
|
||||
fixed_t ZatPoint (fixed_t x, fixed_t y) const
|
||||
{
|
||||
|
@ -348,24 +354,6 @@ enum
|
|||
|
||||
struct FDynamicColormap;
|
||||
|
||||
struct FLightStack
|
||||
{
|
||||
secplane_t Plane; // Plane above this light (points up)
|
||||
sector_t *Master; // Sector to get light from (NULL for owner)
|
||||
BITFIELD bBottom:1; // Light is from the bottom of a block?
|
||||
BITFIELD bFlooder:1; // Light floods lower lights until another flooder is reached?
|
||||
BITFIELD bOverlaps:1; // Plane overlaps the next one
|
||||
};
|
||||
|
||||
struct FExtraLight
|
||||
{
|
||||
short Tag;
|
||||
WORD NumLights;
|
||||
WORD NumUsedLights;
|
||||
FLightStack *Lights; // Lights arranged from top to bottom
|
||||
|
||||
void InsertLight (const secplane_t &plane, line_t *line, int type);
|
||||
};
|
||||
|
||||
struct FLinkedSector
|
||||
{
|
||||
|
@ -616,7 +604,10 @@ struct sector_t
|
|||
|
||||
sector_t *GetHeightSec() const
|
||||
{
|
||||
return (heightsec && !(heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))? heightsec : NULL;
|
||||
return (heightsec &&
|
||||
!(heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
|
||||
!(this->e && this->e->XFloor.ffloors.Size())
|
||||
)? heightsec : NULL;
|
||||
}
|
||||
|
||||
void ChangeLightLevel(int newval)
|
||||
|
@ -725,10 +716,6 @@ struct sector_t
|
|||
// regular sky.
|
||||
TObjPtr<ASkyViewpoint> FloorSkyBox, CeilingSkyBox;
|
||||
|
||||
// Planes that partition this sector into different light zones.
|
||||
FExtraLight *ExtraLights;
|
||||
|
||||
vertex_t *Triangle[3]; // Three points that can define a plane
|
||||
short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap)
|
||||
int sectornum; // for comparing sector copies
|
||||
|
||||
|
@ -1072,6 +1059,8 @@ struct vissprite_t
|
|||
lighttable_t *colormap;
|
||||
sector_t *heightsec; // killough 3/27/98: height sector for underwater/fake ceiling
|
||||
sector_t *sector; // [RH] sector this sprite is in
|
||||
F3DFloor *fakefloor;
|
||||
F3DFloor *fakeceiling;
|
||||
fixed_t alpha;
|
||||
fixed_t floorclip;
|
||||
union
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "r_interpolate.h"
|
||||
#include "r_bsp.h"
|
||||
#include "r_plane.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "v_palette.h"
|
||||
#include "po_man.h"
|
||||
|
||||
|
@ -1147,10 +1148,36 @@ void R_SetupFrame (AActor *actor)
|
|||
}
|
||||
|
||||
extralight = camera->player ? camera->player->extralight : 0;
|
||||
newblend = 0;
|
||||
|
||||
// killough 3/20/98, 4/4/98: select colormap based on player status
|
||||
// [RH] Can also select a blend
|
||||
|
||||
TArray<lightlist_t> &lightlist = viewsector->e->XFloor.lightlist;
|
||||
if (lightlist.Size() > 0)
|
||||
{
|
||||
for(unsigned int i=0;i<lightlist.Size();i++)
|
||||
{
|
||||
fixed_t lightbottom;
|
||||
if (i<lightlist.Size()-1)
|
||||
lightbottom = lightlist[i+1].plane.ZatPoint(viewx, viewy);
|
||||
else
|
||||
lightbottom = viewsector->floorplane.ZatPoint(viewx, viewy);
|
||||
|
||||
if (lightbottom < viewz)
|
||||
{
|
||||
// 3d floor 'fog' is rendered as a blending value
|
||||
PalEntry blendv = lightlist[i].blend;
|
||||
|
||||
// If no alpha is set, use 50%
|
||||
if (blendv.a==0 && blendv!=0) blendv.a=128;
|
||||
newblend = blendv.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const sector_t *s = viewsector->GetHeightSec();
|
||||
if (s != NULL)
|
||||
{
|
||||
|
@ -1162,9 +1189,6 @@ void R_SetupFrame (AActor *actor)
|
|||
if (APART(newblend) == 0 && newblend >= numfakecmaps)
|
||||
newblend = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newblend = 0;
|
||||
}
|
||||
|
||||
// [RH] Don't override testblend unless entering a sector with a
|
||||
|
@ -1361,6 +1385,8 @@ void R_EnterMirror (drawseg_t *ds, int depth)
|
|||
fixed_t startx = viewx;
|
||||
fixed_t starty = viewy;
|
||||
|
||||
CurrentMirror++;
|
||||
|
||||
unsigned int mirrorsAtStart = WallMirrors.Size ();
|
||||
|
||||
vertex_t *v1 = ds->curline->v1;
|
||||
|
@ -1416,6 +1442,7 @@ void R_EnterMirror (drawseg_t *ds, int depth)
|
|||
MirrorFlags = (depth + 1) & 1;
|
||||
|
||||
R_RenderBSPNode (nodes + numnodes - 1);
|
||||
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
||||
|
||||
R_DrawPlanes ();
|
||||
R_DrawSkyBoxes ();
|
||||
|
@ -1486,6 +1513,9 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
|
|||
MaskedCycles.Reset();
|
||||
WallScanCycles.Reset();
|
||||
|
||||
fakeActive = 0; // kg3D - reset fake floor idicator
|
||||
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
||||
|
||||
R_SetupBuffer ();
|
||||
R_SetupFrame (actor);
|
||||
|
||||
|
@ -1540,6 +1570,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines)
|
|||
if (r_polymost < 2)
|
||||
{
|
||||
R_RenderBSPNode (nodes + numnodes - 1); // The head node is the last node output.
|
||||
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
||||
}
|
||||
camera->renderflags = savedflags;
|
||||
WallCycles.Unclock();
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "r_bsp.h"
|
||||
#include "r_plane.h"
|
||||
#include "r_segs.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "v_palette.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -173,6 +174,7 @@ void R_InitPlanes ()
|
|||
|
||||
void R_DeinitPlanes ()
|
||||
{
|
||||
fakeActive = 0;
|
||||
R_ClearPlanes(false);
|
||||
for (visplane_t *pl = freetail; pl != NULL; )
|
||||
{
|
||||
|
@ -467,6 +469,9 @@ void R_ClearPlanes (bool fullclear)
|
|||
{
|
||||
int i, max;
|
||||
|
||||
// kg3D - we can't just clear planes if there are fake planes
|
||||
if(!fullclear && fakeActive) return;
|
||||
|
||||
max = fullclear ? MAXVISPLANES : MAXVISPLANES-1;
|
||||
for (i = 0; i <= max; i++) // new code -- killough
|
||||
for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; )
|
||||
|
@ -560,7 +565,11 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
|
|||
{
|
||||
plane = height;
|
||||
isskybox = false;
|
||||
sky = 0; // not skyflatnum so it can't be a sky
|
||||
// kg3D - hack, store alpha in sky
|
||||
// i know there is ->alpha, but this also allows to identify fake plane
|
||||
// and ->alpha is for stacked sectors
|
||||
if (fake3D & (FAKE3D_FAKEFLOOR|FAKE3D_FAKECEILING)) sky = 0x80000000 | fakeAlpha;
|
||||
else sky = 0; // not skyflatnum so it can't be a sky
|
||||
skybox = NULL;
|
||||
alpha = FRACUNIT;
|
||||
}
|
||||
|
@ -623,7 +632,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
|
|||
xscale == check->xscale &&
|
||||
yscale == check->yscale &&
|
||||
angle == check->angle &&
|
||||
sky == check->sky
|
||||
sky == check->sky &&
|
||||
CurrentMirror == check->CurrentMirror &&
|
||||
MirrorFlags == check->MirrorFlags &&
|
||||
CurrentSkybox == check->CurrentSkybox
|
||||
)
|
||||
{
|
||||
return check;
|
||||
|
@ -652,6 +664,9 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl
|
|||
check->viewz = stacked_viewz;
|
||||
check->viewangle = stacked_angle;
|
||||
check->alpha = alpha;
|
||||
check->CurrentMirror = CurrentMirror;
|
||||
check->MirrorFlags = MirrorFlags;
|
||||
check->CurrentSkybox = CurrentSkybox;
|
||||
|
||||
clearbufshort (check->top, viewwidth, 0x7fff);
|
||||
|
||||
|
@ -737,6 +752,9 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop)
|
|||
new_pl->viewangle = pl->viewangle;
|
||||
new_pl->sky = pl->sky;
|
||||
new_pl->alpha = pl->alpha;
|
||||
new_pl->CurrentMirror = pl->CurrentMirror;
|
||||
new_pl->MirrorFlags = pl->MirrorFlags;
|
||||
new_pl->CurrentSkybox = pl->CurrentSkybox;
|
||||
pl = new_pl;
|
||||
pl->minx = start;
|
||||
pl->maxx = stop;
|
||||
|
@ -969,12 +987,45 @@ void R_DrawPlanes ()
|
|||
{
|
||||
for (pl = visplanes[i]; pl; pl = pl->next)
|
||||
{
|
||||
// kg3D - draw only correct planes
|
||||
if(pl->CurrentMirror != CurrentMirror || pl->CurrentSkybox != CurrentSkybox)
|
||||
continue;
|
||||
// kg3D - draw only real planes now
|
||||
if(pl->sky >= 0) {
|
||||
vpcount++;
|
||||
R_DrawSinglePlane (pl, OPAQUE, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kg3D - draw all visplanes with "height"
|
||||
void R_DrawHeightPlanes(fixed_t height)
|
||||
{
|
||||
visplane_t *pl;
|
||||
int i;
|
||||
|
||||
ds_color = 3;
|
||||
|
||||
for (i = 0; i < MAXVISPLANES; i++)
|
||||
{
|
||||
for (pl = visplanes[i]; pl; pl = pl->next)
|
||||
{
|
||||
// kg3D - draw only correct planes
|
||||
if(pl->CurrentSkybox != CurrentSkybox)
|
||||
continue;
|
||||
if(pl->sky < 0 && pl->height.Zat0() == height) {
|
||||
viewx = pl->viewx;
|
||||
viewy = pl->viewy;
|
||||
viewangle = pl->viewangle;
|
||||
MirrorFlags = pl->MirrorFlags;
|
||||
R_DrawSinglePlane (pl, pl->sky & 0x7FFFFFFF, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_DrawSinglePlane
|
||||
|
@ -1072,6 +1123,8 @@ void R_DrawSkyBoxes ()
|
|||
if (visplanes[MAXVISPLANES] == NULL)
|
||||
return;
|
||||
|
||||
R_3D_EnterSkybox();
|
||||
|
||||
int savedextralight = extralight;
|
||||
fixed_t savedx = viewx;
|
||||
fixed_t savedy = viewy;
|
||||
|
@ -1160,7 +1213,6 @@ void R_DrawSkyBoxes ()
|
|||
|
||||
// Create a drawseg to clip sprites to the sky plane
|
||||
R_CheckDrawSegs ();
|
||||
R_CheckOpenings ((pl->maxx - pl->minx + 1)*2);
|
||||
ds_p->siz1 = INT_MAX;
|
||||
ds_p->siz2 = INT_MAX;
|
||||
ds_p->sz1 = 0;
|
||||
|
@ -1190,6 +1242,7 @@ void R_DrawSkyBoxes ()
|
|||
visplaneStack.Push (pl);
|
||||
|
||||
R_RenderBSPNode (nodes + numnodes - 1);
|
||||
R_3D_ResetClip(); // reset clips (floor/ceiling)
|
||||
R_DrawPlanes ();
|
||||
|
||||
sky->bInSkybox = false;
|
||||
|
@ -1243,8 +1296,13 @@ void R_DrawSkyBoxes ()
|
|||
viewangle = savedangle;
|
||||
R_SetViewAngle ();
|
||||
|
||||
R_3D_LeaveSkybox();
|
||||
|
||||
if(fakeActive) return;
|
||||
|
||||
for (*freehead = visplanes[MAXVISPLANES], visplanes[MAXVISPLANES] = NULL; *freehead; )
|
||||
freehead = &(*freehead)->next;
|
||||
|
||||
}
|
||||
|
||||
ADD_STAT(skyboxes)
|
||||
|
|
|
@ -56,6 +56,11 @@ struct visplane_s
|
|||
angle_t viewangle;
|
||||
fixed_t alpha;
|
||||
|
||||
// kg3D - keep track of mirror and skybox owner
|
||||
int CurrentSkybox;
|
||||
int CurrentMirror; // mirror counter, counts all of them
|
||||
int MirrorFlags; // this is not related to CurrentMirror
|
||||
|
||||
unsigned short *bottom; // [RH] bottom and top arrays are dynamically
|
||||
unsigned short pad; // allocated immediately after the
|
||||
unsigned short top[3]; // visplane.
|
||||
|
|
|
@ -869,7 +869,7 @@ extern FTexture *bottomtexture;
|
|||
extern FTexture *midtexture;
|
||||
extern bool rw_mustmarkfloor, rw_mustmarkceiling;
|
||||
extern void R_NewWall(bool);
|
||||
extern void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el);
|
||||
//extern void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el);
|
||||
extern int doorclosed;
|
||||
extern int viewpitch;
|
||||
#include "p_lnspec.h"
|
||||
|
@ -1408,7 +1408,7 @@ void RP_Subsector (subsector_t *sub)
|
|||
&ceilinglightlevel, false); // killough 4/11/98
|
||||
|
||||
basecolormap = frontsector->ColorMap;
|
||||
R_GetExtraLight (&ceilinglightlevel, frontsector->ceilingplane, frontsector->ExtraLights);
|
||||
//R_GetExtraLight (&ceilinglightlevel, frontsector->ceilingplane, frontsector->ExtraLights);
|
||||
|
||||
// [RH] set foggy flag
|
||||
foggy = level.fadeto || frontsector->ColorMap->Fade || (level.flags & LEVEL_HASFADETABLE);
|
||||
|
@ -1433,7 +1433,7 @@ void RP_Subsector (subsector_t *sub)
|
|||
) : NULL;*/
|
||||
|
||||
basecolormap = frontsector->ColorMap;
|
||||
R_GetExtraLight (&floorlightlevel, frontsector->floorplane, frontsector->ExtraLights);
|
||||
//R_GetExtraLight (&floorlightlevel, frontsector->floorplane, frontsector->ExtraLights);
|
||||
|
||||
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check
|
||||
// killough 3/16/98: add floorlightlevel
|
||||
|
|
735
src/r_segs.cpp
735
src/r_segs.cpp
|
@ -49,6 +49,7 @@
|
|||
#include "r_bsp.h"
|
||||
#include "r_plane.h"
|
||||
#include "r_segs.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "v_palette.h"
|
||||
|
||||
#define WALLYREPEAT 8
|
||||
|
@ -200,12 +201,14 @@ static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FText
|
|||
const FTexture::Span *spans;
|
||||
const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x] >> FRACBITS, &spans);
|
||||
blastfunc (pixels, spans);
|
||||
maskedtexturecol[dc_x] = FIXED_MAX;
|
||||
// maskedtexturecol[dc_x] = FIXED_MAX; // kg3D - seems to be useless
|
||||
}
|
||||
rw_light += rw_lightstep;
|
||||
spryscale += rw_scalestep;
|
||||
}
|
||||
|
||||
void R_RenderFakeWallRange(drawseg_t *ds, int x1, int x2);
|
||||
|
||||
void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
||||
{
|
||||
FTexture *tex;
|
||||
|
@ -213,6 +216,8 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
sector_t tempsec; // killough 4/13/98
|
||||
fixed_t texheight, textop, texheightscale;
|
||||
|
||||
const sector_t *sec;
|
||||
|
||||
sprflipvert = false;
|
||||
|
||||
curline = ds->curline;
|
||||
|
@ -224,7 +229,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
drawmode = R_SetPatchStyle (LegacyRenderStyles[curline->linedef->flags & ML_ADDTRANS ? STYLE_Add : STYLE_Translucent],
|
||||
MIN(curline->linedef->Alpha, FRACUNIT), 0, 0);
|
||||
|
||||
if ((drawmode == DontDraw && !ds->bFogBoundary))
|
||||
if ((drawmode == DontDraw && !ds->bFogBoundary && !ds->bFakeBoundary))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -237,7 +242,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
tex = TexMan(curline->sidedef->GetTexture(side_t::mid));
|
||||
|
||||
// killough 4/13/98: get correct lightlevel for 2s normal textures
|
||||
const sector_t *sec = R_FakeFlat (frontsector, &tempsec, NULL, NULL, false);
|
||||
sec = R_FakeFlat (frontsector, &tempsec, NULL, NULL, false);
|
||||
|
||||
basecolormap = sec->ColorMap; // [RH] Set basecolormap
|
||||
|
||||
|
@ -245,6 +250,23 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
rw_lightstep = ds->lightstep;
|
||||
rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
|
||||
|
||||
if (fixedlightlev < 0)
|
||||
{
|
||||
for (i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (!(fake3D & FAKE3D_CLIPTOP))
|
||||
{
|
||||
sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy);
|
||||
}
|
||||
if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.ZatPoint(viewx, viewy))
|
||||
{
|
||||
basecolormap = frontsector->e->XFloor.lightlist[i].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *frontsector->e->XFloor.lightlist[i].p_lightlevel) + r_actualextralight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mfloorclip = openings + ds->sprbottomclip - ds->x1;
|
||||
mceilingclip = openings + ds->sprtopclip - ds->x1;
|
||||
|
||||
|
@ -257,6 +279,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
goto clearfog;
|
||||
}
|
||||
}
|
||||
if(ds->bFakeBoundary && !(ds->bFakeBoundary & 4) || drawmode == DontDraw) goto clearfog;
|
||||
|
||||
MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1;
|
||||
MaskedScaleY = ds->yrepeat;
|
||||
|
@ -321,13 +344,36 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
goto clearfog;
|
||||
}
|
||||
|
||||
if ((fake3D & FAKE3D_CLIPBOTTOM) && textop <= sclipBottom - viewz)
|
||||
{
|
||||
goto clearfog;
|
||||
}
|
||||
if ((fake3D & FAKE3D_CLIPTOP) && textop - texheight >= sclipTop - viewz)
|
||||
{
|
||||
goto clearfog;
|
||||
}
|
||||
|
||||
WallSZ1 = ds->sz1;
|
||||
WallSZ2 = ds->sz2;
|
||||
WallSX1 = ds->sx1;
|
||||
WallSX2 = ds->sx2;
|
||||
|
||||
if (fake3D & FAKE3D_CLIPTOP)
|
||||
{
|
||||
OWallMost (wallupper, textop < sclipTop - viewz ? textop : sclipTop - viewz);
|
||||
}
|
||||
else
|
||||
{
|
||||
OWallMost (wallupper, textop);
|
||||
}
|
||||
if (fake3D & FAKE3D_CLIPBOTTOM)
|
||||
{
|
||||
OWallMost (walllower, textop - texheight > sclipBottom - viewz ? textop - texheight : sclipBottom - viewz);
|
||||
}
|
||||
else
|
||||
{
|
||||
OWallMost (walllower, textop - texheight);
|
||||
}
|
||||
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
|
@ -386,6 +432,31 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
}
|
||||
else
|
||||
{ // Texture does wrap vertically.
|
||||
WallSZ1 = ds->sz1;
|
||||
WallSZ2 = ds->sz2;
|
||||
WallSX1 = ds->sx1;
|
||||
WallSX2 = ds->sx2;
|
||||
|
||||
if (fake3D & FAKE3D_CLIPTOP)
|
||||
{
|
||||
OWallMost (wallupper, sclipTop - viewz);
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (wallupper[i] < mceilingclip[i])
|
||||
wallupper[i] = mceilingclip[i];
|
||||
}
|
||||
mceilingclip = wallupper;
|
||||
}
|
||||
if (fake3D & FAKE3D_CLIPBOTTOM)
|
||||
{
|
||||
OWallMost (walllower, sclipBottom - viewz);
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (walllower[i] > mfloorclip[i])
|
||||
walllower[i] = mfloorclip[i];
|
||||
}
|
||||
mfloorclip = walllower;
|
||||
}
|
||||
|
||||
rw_offset = 0;
|
||||
rw_pic = tex;
|
||||
|
@ -401,9 +472,508 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
|||
|
||||
clearfog:
|
||||
R_FinishSetPatchStyle ();
|
||||
//if (ds->bFogBoundary)
|
||||
if (ds->bFakeBoundary & 3)
|
||||
{
|
||||
clearbufshort (openings + ds->sprtopclip - ds->x1 + x1, x2-x1+1, viewheight);
|
||||
R_RenderFakeWallRange(ds, x1, x2);
|
||||
}
|
||||
if (fake3D & FAKE3D_REFRESHCLIP)
|
||||
{
|
||||
memcpy(openings + ds->sprtopclip, openings + ds->bkup, (ds->x2-ds->x1+1) * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
clearbufshort(openings + ds->sprtopclip - ds->x1 + x1, x2-x1+1, viewheight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// kg3D - render one fake wall
|
||||
void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover)
|
||||
{
|
||||
int i;
|
||||
fixed_t xscale, yscale;
|
||||
|
||||
fixed_t Alpha = Scale(rover->alpha, OPAQUE, 255);
|
||||
ESPSResult drawmode;
|
||||
drawmode = R_SetPatchStyle (LegacyRenderStyles[rover->flags & FF_ADDITIVETRANS ? STYLE_Add : STYLE_Translucent],
|
||||
Alpha, 0, 0);
|
||||
|
||||
if(drawmode == DontDraw) {
|
||||
R_FinishSetPatchStyle();
|
||||
return;
|
||||
}
|
||||
|
||||
rw_lightstep = ds->lightstep;
|
||||
rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
|
||||
|
||||
mfloorclip = openings + ds->sprbottomclip - ds->x1;
|
||||
mceilingclip = openings + ds->sprtopclip - ds->x1;
|
||||
|
||||
spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
|
||||
rw_scalestep = ds->iscalestep;
|
||||
MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1;
|
||||
|
||||
// find positioning
|
||||
xscale = FixedMul(rw_pic->xScale, sidedef->GetTextureXScale(side_t::mid));
|
||||
yscale = FixedMul(rw_pic->yScale, sidedef->GetTextureYScale(side_t::mid));
|
||||
// encapsulate the lifetime of rowoffset
|
||||
fixed_t rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
|
||||
dc_texturemid = rover->model->GetPlaneTexZ(sector_t::ceiling);
|
||||
rw_offset = curline->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid);
|
||||
if (rowoffset < 0)
|
||||
{
|
||||
rowoffset += rw_pic->GetHeight() << FRACBITS;
|
||||
}
|
||||
if (rw_pic->bWorldPanning)
|
||||
{
|
||||
// rowoffset is added before the MulScale3 so that the masked texture will
|
||||
// still be positioned in world units rather than texels.
|
||||
|
||||
dc_texturemid = MulScale16(dc_texturemid - viewz + rowoffset, yscale);
|
||||
rw_offset = MulScale16 (rw_offset, xscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
// rowoffset is added outside the multiply so that it positions the texture
|
||||
// by texels instead of world units.
|
||||
dc_texturemid = MulScale16(dc_texturemid - viewz, yscale) + rowoffset;
|
||||
}
|
||||
|
||||
if (fixedlightlev >= 0)
|
||||
dc_colormap = basecolormap->Maps + fixedlightlev;
|
||||
else if (fixedcolormap != NULL)
|
||||
dc_colormap = fixedcolormap;
|
||||
|
||||
WallSZ1 = ds->sz1;
|
||||
WallSZ2 = ds->sz2;
|
||||
WallSX1 = ds->sx1;
|
||||
WallSX2 = ds->sx2;
|
||||
WallTX1 = ds->cx;
|
||||
WallTY1 = ds->cy;
|
||||
WallTX2 = WallTX1 + ds->cdx;
|
||||
WallTY2 = WallTY1 + ds->cdy;
|
||||
WallDepthScale = ds->WallDepthScale;
|
||||
WallDepthOrg = ds->WallDepthOrg;
|
||||
WallUoverZorg = ds->WallUoverZorg;
|
||||
WallUoverZstep = ds->WallUoverZstep;
|
||||
WallInvZorg = ds->WallInvZorg;
|
||||
WallInvZstep = ds->WallInvZstep;
|
||||
|
||||
OWallMost(wallupper, sclipTop - viewz);
|
||||
OWallMost(walllower, sclipBottom - viewz);
|
||||
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (wallupper[i] < mceilingclip[i])
|
||||
wallupper[i] = mceilingclip[i];
|
||||
}
|
||||
for (i = x1; i <= x2; i++)
|
||||
{
|
||||
if (walllower[i] > mfloorclip[i])
|
||||
walllower[i] = mfloorclip[i];
|
||||
}
|
||||
|
||||
PrepLWall (lwall, curline->sidedef->TexelLength*xscale);
|
||||
|
||||
if(colfunc == basecolfunc)
|
||||
maskwallscan(x1, x2, wallupper, walllower, MaskedSWall , lwall, yscale);
|
||||
else {
|
||||
transmaskwallscan(x1, x2, wallupper, walllower, MaskedSWall, lwall, yscale);
|
||||
}
|
||||
R_FinishSetPatchStyle();
|
||||
}
|
||||
|
||||
// kg3D - walls of fake floors
|
||||
void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2)
|
||||
{
|
||||
FTexture *const DONT_DRAW = ((FTexture*)(intptr_t)-1);
|
||||
int i,j;
|
||||
F3DFloor *rover, *fover;
|
||||
int passed, last;
|
||||
fixed_t floorheight;
|
||||
fixed_t ceilingheight;
|
||||
|
||||
sprflipvert = false;
|
||||
curline = ds->curline;
|
||||
|
||||
frontsector = curline->frontsector;
|
||||
backsector = curline->backsector;
|
||||
|
||||
if (backsector == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((ds->bFakeBoundary & 3) == 2)
|
||||
{
|
||||
sector_t *sec = backsector;
|
||||
backsector = frontsector;
|
||||
frontsector = sec;
|
||||
}
|
||||
|
||||
floorheight = backsector->CenterFloor();
|
||||
ceilingheight = backsector->CenterCeiling();
|
||||
|
||||
// maybe fix clipheights
|
||||
if (!(fake3D & FAKE3D_CLIPBOTTOM)) sclipBottom = floorheight;
|
||||
if (!(fake3D & FAKE3D_CLIPTOP)) sclipTop = ceilingheight;
|
||||
|
||||
if (fake3D & FAKE3D_DOWN2UP)
|
||||
{ // bottom to viewz
|
||||
last = 0;
|
||||
for (i = backsector->e->XFloor.ffloors.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
rover = backsector->e->XFloor.ffloors[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
|
||||
// visible?
|
||||
passed = 0;
|
||||
if (!(rover->flags & FF_RENDERSIDES) ||
|
||||
rover->top.plane->a || rover->top.plane->b ||
|
||||
rover->bottom.plane->a || rover->bottom.plane->b ||
|
||||
rover->top.plane->Zat0() <= sclipBottom ||
|
||||
rover->bottom.plane->Zat0() >= ceilingheight)
|
||||
{
|
||||
if (!i)
|
||||
{
|
||||
passed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rw_pic = NULL;
|
||||
if (rover->bottom.plane->Zat0() >= sclipTop || passed)
|
||||
{
|
||||
if (last)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// maybe wall from inside rendering?
|
||||
fover = NULL;
|
||||
for (j = frontsector->e->XFloor.ffloors.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
fover = frontsector->e->XFloor.ffloors[j];
|
||||
if (fover->model == rover->model)
|
||||
{ // never
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
if (!(fover->flags & FF_EXISTS)) continue;
|
||||
if (!(fover->flags & FF_RENDERSIDES)) continue;
|
||||
// no sloped walls, it's bugged
|
||||
if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
|
||||
|
||||
// visible?
|
||||
if (fover->top.plane->Zat0() <= sclipBottom) continue; // no
|
||||
if (fover->bottom.plane->Zat0() >= sclipTop)
|
||||
{ // no, last possible
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
// it is, render inside?
|
||||
if (!(fover->flags & (FF_BOTHPLANES|FF_INVERTPLANES)))
|
||||
{ // no
|
||||
fover = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// nothing
|
||||
if (!fover || j == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// correct texture
|
||||
if (fover->flags & rover->flags & FF_SWIMMABLE)
|
||||
{ // don't ever draw (but treat as something has been found)
|
||||
rw_pic = DONT_DRAW;
|
||||
}
|
||||
else if(fover->flags & FF_UPPERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top));
|
||||
}
|
||||
else if(fover->flags & FF_LOWERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid));
|
||||
}
|
||||
}
|
||||
else if (frontsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
// maybe not visible?
|
||||
fover = NULL;
|
||||
for (j = frontsector->e->XFloor.ffloors.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
fover = frontsector->e->XFloor.ffloors[j];
|
||||
if (fover->model == rover->model) // never
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!(fover->flags & FF_EXISTS)) continue;
|
||||
if (!(fover->flags & FF_RENDERSIDES)) continue;
|
||||
// no sloped walls, it's bugged
|
||||
if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
|
||||
|
||||
// visible?
|
||||
if (fover->top.plane->Zat0() <= sclipBottom) continue; // no
|
||||
if (fover->bottom.plane->Zat0() >= sclipTop)
|
||||
{ // visible, last possible
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
if ((fover->flags & FF_SOLID) == (rover->flags & FF_SOLID) &&
|
||||
!(!(fover->flags & FF_SOLID) && (fover->alpha == 255 || rover->alpha == 255))
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (fover->flags & rover->flags & FF_SWIMMABLE)
|
||||
{ // don't ever draw (but treat as something has been found)
|
||||
rw_pic = DONT_DRAW;
|
||||
}
|
||||
fover = NULL; // visible
|
||||
break;
|
||||
}
|
||||
if (fover && j != -1)
|
||||
{
|
||||
fover = NULL;
|
||||
last = 1;
|
||||
continue; // not visible
|
||||
}
|
||||
}
|
||||
if (!rw_pic)
|
||||
{
|
||||
fover = NULL;
|
||||
if (rover->flags & FF_UPPERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top));
|
||||
}
|
||||
else if(rover->flags & FF_LOWERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid));
|
||||
}
|
||||
}
|
||||
// correct colors now
|
||||
basecolormap = frontsector->ColorMap;
|
||||
wallshade = ds->shade;
|
||||
if (fixedlightlev < 0)
|
||||
{
|
||||
if ((ds->bFakeBoundary & 3) == 2)
|
||||
{
|
||||
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
if (sclipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
|
||||
{
|
||||
basecolormap = backsector->e->XFloor.lightlist[j].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *backsector->e->XFloor.lightlist[j].p_lightlevel) + r_actualextralight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
if (sclipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
|
||||
{
|
||||
basecolormap = frontsector->e->XFloor.lightlist[j].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *frontsector->e->XFloor.lightlist[j].p_lightlevel) + r_actualextralight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rw_pic != DONT_DRAW)
|
||||
{
|
||||
R_RenderFakeWall(ds, x1, x2, fover ? fover : rover);
|
||||
}
|
||||
else rw_pic = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // top to viewz
|
||||
for (i = 0; i < (int)backsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
rover = backsector->e->XFloor.ffloors[i];
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
|
||||
// visible?
|
||||
passed = 0;
|
||||
if (!(rover->flags & FF_RENDERSIDES) ||
|
||||
rover->top.plane->a || rover->top.plane->b ||
|
||||
rover->bottom.plane->a || rover->bottom.plane->b ||
|
||||
rover->bottom.plane->Zat0() >= sclipTop ||
|
||||
rover->top.plane->Zat0() <= floorheight)
|
||||
{
|
||||
if (i == backsector->e->XFloor.ffloors.Size() - 1)
|
||||
{
|
||||
passed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
rw_pic = NULL;
|
||||
if (rover->top.plane->Zat0() <= sclipBottom || passed)
|
||||
{ // maybe wall from inside rendering?
|
||||
fover = NULL;
|
||||
for (j = 0; j < (int)frontsector->e->XFloor.ffloors.Size(); j++)
|
||||
{
|
||||
fover = frontsector->e->XFloor.ffloors[j];
|
||||
if (fover->model == rover->model)
|
||||
{ // never
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
if (!(fover->flags & FF_EXISTS)) continue;
|
||||
if (!(fover->flags & FF_RENDERSIDES)) continue;
|
||||
// no sloped walls, it's bugged
|
||||
if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
|
||||
|
||||
// visible?
|
||||
if (fover->bottom.plane->Zat0() >= sclipTop) continue; // no
|
||||
if (fover->top.plane->Zat0() <= sclipBottom)
|
||||
{ // no, last possible
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
// it is, render inside?
|
||||
if (!(fover->flags & (FF_BOTHPLANES|FF_INVERTPLANES)))
|
||||
{ // no
|
||||
fover = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// nothing
|
||||
if (!fover || j == frontsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
// correct texture
|
||||
if (fover->flags & rover->flags & FF_SWIMMABLE)
|
||||
{
|
||||
rw_pic = DONT_DRAW; // don't ever draw (but treat as something has been found)
|
||||
}
|
||||
else if (fover->flags & FF_UPPERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top));
|
||||
}
|
||||
else if (fover->flags & FF_LOWERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid));
|
||||
}
|
||||
}
|
||||
else if (frontsector->e->XFloor.ffloors.Size())
|
||||
{ // maybe not visible?
|
||||
fover = NULL;
|
||||
for (j = 0; j < (int)frontsector->e->XFloor.ffloors.Size(); j++)
|
||||
{
|
||||
fover = frontsector->e->XFloor.ffloors[j];
|
||||
if (fover->model == rover->model)
|
||||
{ // never
|
||||
break;
|
||||
}
|
||||
if (!(fover->flags & FF_EXISTS)) continue;
|
||||
if (!(fover->flags & FF_RENDERSIDES)) continue;
|
||||
// no sloped walls, its bugged
|
||||
if(fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
|
||||
|
||||
// visible?
|
||||
if (fover->bottom.plane->Zat0() >= sclipTop) continue; // no
|
||||
if (fover->top.plane->Zat0() <= sclipBottom)
|
||||
{ // visible, last possible
|
||||
fover = NULL;
|
||||
break;
|
||||
}
|
||||
if ((fover->flags & FF_SOLID) == (rover->flags & FF_SOLID) &&
|
||||
!(!(rover->flags & FF_SOLID) && (fover->alpha == 255 || rover->alpha == 255))
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (fover->flags & rover->flags & FF_SWIMMABLE)
|
||||
{ // don't ever draw (but treat as something has been found)
|
||||
rw_pic = DONT_DRAW;
|
||||
}
|
||||
fover = NULL; // visible
|
||||
break;
|
||||
}
|
||||
if (fover && j != frontsector->e->XFloor.ffloors.Size())
|
||||
{ // not visible
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rw_pic == NULL)
|
||||
{
|
||||
fover = NULL;
|
||||
if (rover->flags & FF_UPPERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top));
|
||||
}
|
||||
else if (rover->flags & FF_LOWERTEXTURE)
|
||||
{
|
||||
rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom));
|
||||
}
|
||||
else
|
||||
{
|
||||
rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid));
|
||||
}
|
||||
}
|
||||
// correct colors now
|
||||
basecolormap = frontsector->ColorMap;
|
||||
wallshade = ds->shade;
|
||||
if (fixedlightlev < 0)
|
||||
{
|
||||
if ((ds->bFakeBoundary & 3) == 2)
|
||||
{
|
||||
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
if (sclipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
|
||||
{
|
||||
basecolormap = backsector->e->XFloor.lightlist[j].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *backsector->e->XFloor.lightlist[j].p_lightlevel) + r_actualextralight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
if(sclipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
|
||||
{
|
||||
basecolormap = frontsector->e->XFloor.lightlist[j].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *frontsector->e->XFloor.lightlist[j].p_lightlevel) + r_actualextralight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rw_pic != DONT_DRAW)
|
||||
{
|
||||
R_RenderFakeWall(ds, x1, x2, fover ? fover : rover);
|
||||
}
|
||||
else
|
||||
{
|
||||
rw_pic = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -586,70 +1156,38 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t
|
|||
|
||||
void wallscan_striped (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat)
|
||||
{
|
||||
bool flooding = false;
|
||||
FDynamicColormap *startcolormap = basecolormap;
|
||||
int startshade = wallshade;
|
||||
bool fogginess = foggy;
|
||||
|
||||
FDynamicColormap *floodcolormap = startcolormap;
|
||||
int floodshade = startshade;
|
||||
bool floodfoggy = foggy;
|
||||
|
||||
short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH];
|
||||
short *up, *down;
|
||||
|
||||
FExtraLight *el = frontsector->ExtraLights;
|
||||
|
||||
up = uwal;
|
||||
down = most1;
|
||||
|
||||
assert(WallSX1 <= x1);
|
||||
assert(WallSX2 > x2);
|
||||
|
||||
for (int i = 0; i < el->NumUsedLights; ++i)
|
||||
// kg3D - fake floors instead of zdoom light list
|
||||
for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++)
|
||||
{
|
||||
if (flooding && !el->Lights[i].bFlooder)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!el->Lights[i].bOverlaps)
|
||||
{
|
||||
int j = WallMost (most3, el->Lights[i].Plane);
|
||||
|
||||
if (j != 3 /*&& (most3[x1] > up[x1] || most3[x2] > up[x2])*/)
|
||||
int j = WallMost (most3, frontsector->e->XFloor.lightlist[i].plane);
|
||||
if (j != 3)
|
||||
{
|
||||
for (int j = x1; j <= x2; ++j)
|
||||
{
|
||||
down[j] = clamp (most3[j], up[j], dwal[j]);
|
||||
}
|
||||
wallscan (x1, x2, up, down, swal, lwal, yrepeat);
|
||||
|
||||
up = down;
|
||||
down = (down == most1) ? most2 : most1;
|
||||
}
|
||||
basecolormap = frontsector->e->XFloor.lightlist[i].extra_colormap;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess,
|
||||
*frontsector->e->XFloor.lightlist[i].p_lightlevel) + r_actualextralight);
|
||||
}
|
||||
|
||||
if (el->Lights[i].Master == NULL)
|
||||
{
|
||||
basecolormap = floodcolormap;
|
||||
wallshade = floodshade;
|
||||
fogginess = floodfoggy;
|
||||
}
|
||||
else
|
||||
{
|
||||
basecolormap = el->Lights[i].Master->ColorMap;
|
||||
fogginess = level.fadeto || basecolormap->Fade;
|
||||
wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess,
|
||||
el->Lights[i].Master->lightlevel) + r_actualextralight);
|
||||
if (el->Lights[i].bFlooder)
|
||||
{
|
||||
floodcolormap = basecolormap;
|
||||
floodshade = wallshade;
|
||||
flooding = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
wallscan (x1, x2, up, dwal, swal, lwal, yrepeat);
|
||||
basecolormap = startcolormap;
|
||||
wallshade = startshade;
|
||||
|
@ -1043,7 +1581,7 @@ void R_RenderSegLoop ()
|
|||
{
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
short top = ceilingclip[x];
|
||||
short top = (fakeFloor && fake3D & 2) ? fakeFloor->ceilingclip[x] : ceilingclip[x];
|
||||
short bottom = MIN (walltop[x], floorclip[x]);
|
||||
if (top < bottom)
|
||||
{
|
||||
|
@ -1059,7 +1597,7 @@ void R_RenderSegLoop ()
|
|||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
short top = MAX (wallbottom[x], ceilingclip[x]);
|
||||
short bottom = floorclip[x];
|
||||
short bottom = (fakeFloor && fake3D & 1) ? fakeFloor->floorclip[x] : floorclip[x];
|
||||
if (top < bottom)
|
||||
{
|
||||
assert (bottom <= viewheight);
|
||||
|
@ -1069,6 +1607,36 @@ void R_RenderSegLoop ()
|
|||
}
|
||||
}
|
||||
|
||||
// kg3D - fake planes clipping
|
||||
if (fake3D & FAKE3D_REFRESHCLIP)
|
||||
{
|
||||
if (fake3D & FAKE3D_DOWN2UP)
|
||||
{
|
||||
memcpy (fakeFloor->floorclip+x1, wallbottom+x1, (x2-x1)*sizeof(short));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
walllower[x] = MIN (MAX (walllower[x], ceilingclip[x]), wallbottom[x]);
|
||||
}
|
||||
memcpy (fakeFloor->floorclip+x1, walllower+x1, (x2-x1)*sizeof(short));
|
||||
}
|
||||
if (fake3D & FAKE3D_16)
|
||||
{
|
||||
memcpy (fakeFloor->ceilingclip+x1, walltop+x1, (x2-x1)*sizeof(short));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = x1; x < x2; ++x)
|
||||
{
|
||||
wallupper[x] = MAX (MIN (wallupper[x], floorclip[x]), walltop[x]);
|
||||
}
|
||||
memcpy (fakeFloor->ceilingclip+x1, wallupper+x1, (x2-x1)*sizeof(short));
|
||||
}
|
||||
}
|
||||
if(fake3D & 7) return;
|
||||
|
||||
// draw the wall tiers
|
||||
if (midtexture)
|
||||
{ // one sided line
|
||||
|
@ -1091,7 +1659,7 @@ void R_RenderSegLoop ()
|
|||
{
|
||||
rw_offset = rw_offset_mid;
|
||||
}
|
||||
if (fixedcolormap != NULL || !frontsector->ExtraLights)
|
||||
if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
|
||||
{
|
||||
wallscan (x1, x2-1, walltop, wallbottom, swall, lwall, yscale);
|
||||
}
|
||||
|
@ -1130,7 +1698,7 @@ void R_RenderSegLoop ()
|
|||
{
|
||||
rw_offset = rw_offset_top;
|
||||
}
|
||||
if (fixedcolormap != NULL || !frontsector->ExtraLights)
|
||||
if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
|
||||
{
|
||||
wallscan (x1, x2-1, walltop, wallupper, swall, lwall, yscale);
|
||||
}
|
||||
|
@ -1172,7 +1740,7 @@ void R_RenderSegLoop ()
|
|||
{
|
||||
rw_offset = rw_offset_bottom;
|
||||
}
|
||||
if (fixedcolormap != NULL || !frontsector->ExtraLights)
|
||||
if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
|
||||
{
|
||||
wallscan (x1, x2-1, walllower, wallbottom, swall, lwall, yscale);
|
||||
}
|
||||
|
@ -1312,6 +1880,10 @@ void R_NewWall (bool needlights)
|
|||
|
||||
|| backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
|
||||
|
||||
// kg3D - add fake lights
|
||||
|| (frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
|| (backsector->e && backsector->e->XFloor.lightlist.Size())
|
||||
|
||||
|| (sidedef->GetTexture(side_t::mid).isValid() &&
|
||||
((linedef->flags & (ML_CLIP_MIDTEX|ML_WRAP_MIDTEX)) ||
|
||||
(sidedef->Flags & (WALLF_CLIP_MIDTEX|WALLF_WRAP_MIDTEX))))
|
||||
|
@ -1344,6 +1916,10 @@ void R_NewWall (bool needlights)
|
|||
|
||||
|| backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
|
||||
|
||||
// kg3D - add fake lights
|
||||
|| (frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
|| (backsector->e && backsector->e->XFloor.lightlist.Size())
|
||||
|
||||
|| (sidedef->GetTexture(side_t::mid).isValid() &&
|
||||
((linedef->flags & (ML_CLIP_MIDTEX|ML_WRAP_MIDTEX)) ||
|
||||
(sidedef->Flags & (WALLF_CLIP_MIDTEX|WALLF_WRAP_MIDTEX))))
|
||||
|
@ -1535,20 +2111,22 @@ void R_CheckDrawSegs ()
|
|||
// R_CheckOpenings
|
||||
//
|
||||
|
||||
void R_CheckOpenings (size_t need)
|
||||
ptrdiff_t R_NewOpening (ptrdiff_t len)
|
||||
{
|
||||
need += lastopening;
|
||||
|
||||
if (need > maxopenings)
|
||||
ptrdiff_t res = lastopening;
|
||||
lastopening += len;
|
||||
if ((size_t)lastopening > maxopenings)
|
||||
{
|
||||
do
|
||||
maxopenings = maxopenings ? maxopenings*2 : 16384;
|
||||
while (need > maxopenings);
|
||||
while ((size_t)lastopening > maxopenings);
|
||||
openings = (short *)M_Realloc (openings, maxopenings * sizeof(*openings));
|
||||
DPrintf ("MaxOpenings increased to %zu\n", maxopenings);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// R_StoreWallRange
|
||||
// A wall segment will be drawn between start and stop pixels (inclusive).
|
||||
|
@ -1556,6 +2134,7 @@ void R_CheckOpenings (size_t need)
|
|||
|
||||
void R_StoreWallRange (int start, int stop)
|
||||
{
|
||||
int i;
|
||||
bool maskedtexture = false;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
|
@ -1583,6 +2162,12 @@ void R_StoreWallRange (int start, int stop)
|
|||
ds_p->cy = WallTY1;
|
||||
ds_p->cdx = WallTX2 - WallTX1;
|
||||
ds_p->cdy = WallTY2 - WallTY1;
|
||||
ds_p->WallDepthScale = WallDepthScale;
|
||||
ds_p->WallDepthOrg = WallDepthOrg;
|
||||
ds_p->WallUoverZorg = WallUoverZorg;
|
||||
ds_p->WallUoverZstep = WallUoverZstep;
|
||||
ds_p->WallInvZorg = WallInvZorg;
|
||||
ds_p->WallInvZstep = WallInvZstep;
|
||||
ds_p->siz1 = (DWORD)DivScale32 (1, WallSZ1) >> 1;
|
||||
ds_p->siz2 = (DWORD)DivScale32 (1, WallSZ2) >> 1;
|
||||
ds_p->x1 = rw_x = start;
|
||||
|
@ -1590,11 +2175,12 @@ void R_StoreWallRange (int start, int stop)
|
|||
ds_p->curline = curline;
|
||||
rw_stopx = stop;
|
||||
ds_p->bFogBoundary = false;
|
||||
ds_p->bFakeBoundary = false;
|
||||
if(fake3D & 7) ds_p->fake = 1;
|
||||
else ds_p->fake = 0;
|
||||
|
||||
// killough 1/6/98, 2/1/98: remove limit on openings
|
||||
R_CheckOpenings ((stop - start)*6);
|
||||
|
||||
ds_p->sprtopclip = ds_p->sprbottomclip = ds_p->maskedtexturecol = ds_p->swall = -1;
|
||||
ds_p->sprtopclip = ds_p->sprbottomclip = ds_p->maskedtexturecol = ds_p->bkup = ds_p->swall = -1;
|
||||
|
||||
if (rw_markmirror)
|
||||
{
|
||||
|
@ -1651,9 +2237,29 @@ void R_StoreWallRange (int start, int stop)
|
|||
}
|
||||
}
|
||||
|
||||
if(!ds_p->fake && backsector->e && backsector->e->XFloor.ffloors.Size()) {
|
||||
for(i = 0; i < (int)backsector->e->XFloor.ffloors.Size(); i++) {
|
||||
F3DFloor *rover = backsector->e->XFloor.ffloors[i];
|
||||
if(rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) {
|
||||
ds_p->bFakeBoundary |= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ds_p->fake && frontsector->e && frontsector->e->XFloor.ffloors.Size()) {
|
||||
for(i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++) {
|
||||
F3DFloor *rover = frontsector->e->XFloor.ffloors[i];
|
||||
if(rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) {
|
||||
ds_p->bFakeBoundary |= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// kg3D - no for fakes
|
||||
if(!ds_p->fake)
|
||||
// allocate space for masked texture tables, if needed
|
||||
// [RH] Don't just allocate the space; fill it in too.
|
||||
if ((TexMan(sidedef->GetTexture(side_t::mid))->UseType != FTexture::TEX_Null || IsFogBoundary (frontsector, backsector)) &&
|
||||
if ((TexMan(sidedef->GetTexture(side_t::mid))->UseType != FTexture::TEX_Null || ds_p->bFakeBoundary || IsFogBoundary (frontsector, backsector)) &&
|
||||
(rw_ceilstat != 12 || !sidedef->GetTexture(side_t::top).isValid()) &&
|
||||
(rw_floorstat != 3 || !sidedef->GetTexture(side_t::bottom).isValid()) &&
|
||||
(WallSZ1 >= TOO_CLOSE_Z && WallSZ2 >= TOO_CLOSE_Z))
|
||||
|
@ -1665,8 +2271,11 @@ void R_StoreWallRange (int start, int stop)
|
|||
maskedtexture = true;
|
||||
|
||||
ds_p->bFogBoundary = IsFogBoundary (frontsector, backsector);
|
||||
if (sidedef->GetTexture(side_t::mid).isValid())
|
||||
if (sidedef->GetTexture(side_t::mid).isValid() || ds_p->bFakeBoundary)
|
||||
{
|
||||
if(sidedef->GetTexture(side_t::mid).isValid())
|
||||
ds_p->bFakeBoundary |= 4; // it is also mid texture
|
||||
|
||||
ds_p->maskedtexturecol = R_NewOpening ((stop - start) * 2);
|
||||
ds_p->swall = R_NewOpening ((stop - start) * 2);
|
||||
|
||||
|
@ -1746,11 +2355,19 @@ void R_StoreWallRange (int start, int stop)
|
|||
|
||||
R_RenderSegLoop ();
|
||||
|
||||
if(fake3D & 7) {
|
||||
ds_p++;
|
||||
return;
|
||||
}
|
||||
|
||||
// save sprite clipping info
|
||||
if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && ds_p->sprtopclip == -1)
|
||||
{
|
||||
ds_p->sprtopclip = R_NewOpening (stop - start);
|
||||
memcpy (openings + ds_p->sprtopclip, &ceilingclip[start], sizeof(short)*(stop-start));
|
||||
// kg3D - backup for mid and fake walls
|
||||
ds_p->bkup = R_NewOpening (stop - start);
|
||||
memcpy (openings + ds_p->bkup, &ceilingclip[start], sizeof(short)*(stop-start));
|
||||
}
|
||||
|
||||
if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && ds_p->sprbottomclip == -1)
|
||||
|
|
|
@ -31,14 +31,8 @@ extern short *openings;
|
|||
extern ptrdiff_t lastopening;
|
||||
extern size_t maxopenings;
|
||||
|
||||
inline ptrdiff_t R_NewOpening (ptrdiff_t len)
|
||||
{
|
||||
ptrdiff_t res = lastopening;
|
||||
lastopening += len;
|
||||
return res;
|
||||
}
|
||||
ptrdiff_t R_NewOpening (ptrdiff_t len);
|
||||
|
||||
void R_CheckOpenings (size_t need);
|
||||
void R_CheckDrawSegs ();
|
||||
|
||||
void R_RenderSegLoop ();
|
||||
|
|
|
@ -86,9 +86,6 @@ extern subsector_t * gamesubsectors;
|
|||
extern int numgamesubsectors;
|
||||
|
||||
|
||||
extern FExtraLight* ExtraLights;
|
||||
extern FLightStack* LightStacks;
|
||||
|
||||
inline FArchive &operator<< (FArchive &arc, sector_t *&sec)
|
||||
{
|
||||
return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
|
||||
|
|
282
src/r_things.cpp
282
src/r_things.cpp
|
@ -56,6 +56,7 @@
|
|||
#include "r_bsp.h"
|
||||
#include "r_plane.h"
|
||||
#include "r_segs.h"
|
||||
#include "r_3dfloors.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_translate.h"
|
||||
|
||||
|
@ -1683,7 +1684,7 @@ void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop
|
|||
// R_ProjectSprite
|
||||
// Generates a vissprite for a thing if it might be visible.
|
||||
//
|
||||
void R_ProjectSprite (AActor *thing, int fakeside)
|
||||
void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling)
|
||||
{
|
||||
fixed_t fx, fy, fz;
|
||||
fixed_t tr_x;
|
||||
|
@ -1978,11 +1979,14 @@ void R_ProjectSprite (AActor *thing, int fakeside)
|
|||
vis->gzb = gzb; // [RH] use gzb, not thing->z
|
||||
vis->gzt = gzt; // killough 3/27/98
|
||||
vis->renderflags = thing->renderflags;
|
||||
if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D
|
||||
vis->RenderStyle = thing->RenderStyle;
|
||||
vis->FillColor = thing->fillcolor;
|
||||
vis->Translation = thing->Translation; // [RH] thing translation table
|
||||
vis->FakeFlatStat = fakeside;
|
||||
vis->alpha = thing->alpha;
|
||||
vis->fakefloor = fakefloor;
|
||||
vis->fakeceiling = fakeceiling;
|
||||
|
||||
if (voxel != NULL)
|
||||
{
|
||||
|
@ -2063,6 +2067,9 @@ void R_ProjectSprite (AActor *thing, int fakeside)
|
|||
void R_AddSprites (sector_t *sec, int lightlevel, int fakeside)
|
||||
{
|
||||
AActor *thing;
|
||||
F3DFloor *rover;
|
||||
F3DFloor *fakeceiling = NULL;
|
||||
F3DFloor *fakefloor = NULL;
|
||||
|
||||
// BSP is traversed by subsector.
|
||||
// A sector might have been split into several
|
||||
|
@ -2079,7 +2086,26 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside)
|
|||
// Handle all things in sector.
|
||||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
R_ProjectSprite (thing, fakeside);
|
||||
// find fake level
|
||||
for(int i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++) {
|
||||
rover = frontsector->e->XFloor.ffloors[i];
|
||||
if(!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES)) continue;
|
||||
if(!(rover->flags & FF_SOLID) || rover->alpha != 255) continue;
|
||||
if(!fakefloor)
|
||||
{
|
||||
if(!(rover->top.plane->a) && !(rover->top.plane->b))
|
||||
{
|
||||
if(rover->top.plane->Zat0() <= thing->z) fakefloor = rover;
|
||||
}
|
||||
}
|
||||
if(!(rover->bottom.plane->a) && !(rover->bottom.plane->b))
|
||||
{
|
||||
if(rover->bottom.plane->Zat0() >= thing->z + thing->height) fakeceiling = rover;
|
||||
}
|
||||
}
|
||||
R_ProjectSprite (thing, fakeside, fakefloor, fakeceiling);
|
||||
fakeceiling = NULL;
|
||||
fakefloor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2307,31 +2333,54 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, fixed_t sx, fixed_
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_DrawPlayerSprites (void)
|
||||
void R_DrawPlayerSprites ()
|
||||
{
|
||||
int i;
|
||||
int lightnum;
|
||||
pspdef_t* psp;
|
||||
sector_t* sec;
|
||||
sector_t* sec = NULL;
|
||||
static sector_t tempsec;
|
||||
int floorlight, ceilinglight;
|
||||
F3DFloor *rover;
|
||||
|
||||
if (!r_drawplayersprites ||
|
||||
!camera->player ||
|
||||
(players[consoleplayer].cheats & CF_CHASECAM))
|
||||
return;
|
||||
|
||||
if(fixedlightlev < 0 && viewsector->e && viewsector->e->XFloor.lightlist.Size()) {
|
||||
for(i = viewsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||
if(viewz <= viewsector->e->XFloor.lightlist[i].plane.Zat0()) {
|
||||
rover = viewsector->e->XFloor.lightlist[i].caster;
|
||||
if(rover) {
|
||||
if(rover->flags & FF_DOUBLESHADOW && viewz <= rover->bottom.plane->Zat0())
|
||||
break;
|
||||
sec = rover->model;
|
||||
if(rover->flags & FF_FADEWALLS)
|
||||
basecolormap = sec->ColorMap;
|
||||
else
|
||||
basecolormap = viewsector->e->XFloor.lightlist[i].extra_colormap;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!sec) {
|
||||
sec = viewsector;
|
||||
basecolormap = sec->ColorMap;
|
||||
}
|
||||
floorlight = ceilinglight = sec->lightlevel;
|
||||
} else {
|
||||
// This used to use camera->Sector but due to interpolation that can be incorrect
|
||||
// when the interpolated viewpoint is in a different sector than the camera.
|
||||
sec = R_FakeFlat (viewsector, &tempsec, &floorlight,
|
||||
&ceilinglight, false);
|
||||
|
||||
// [RH] set foggy flag
|
||||
foggy = (level.fadeto || sec->ColorMap->Fade || (level.flags & LEVEL_HASFADETABLE));
|
||||
r_actualextralight = foggy ? 0 : extralight << 4;
|
||||
|
||||
// [RH] set basecolormap
|
||||
basecolormap = sec->ColorMap;
|
||||
}
|
||||
|
||||
// [RH] set foggy flag
|
||||
foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE));
|
||||
r_actualextralight = foggy ? 0 : extralight << 4;
|
||||
|
||||
// get light level
|
||||
lightnum = ((floorlight + ceilinglight) >> 1) + r_actualextralight;
|
||||
|
@ -2656,10 +2705,16 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
int r1, r2;
|
||||
short topclip, botclip;
|
||||
short *clip1, *clip2;
|
||||
lighttable_t *colormap = spr->colormap;
|
||||
F3DFloor *rover;
|
||||
FDynamicColormap *mybasecolormap;
|
||||
|
||||
// [RH] Check for particles
|
||||
if (!spr->bIsVoxel && spr->pic == NULL)
|
||||
{
|
||||
// kg3D - reject invisible parts
|
||||
if ((fake3D & FAKE3D_CLIPBOTTOM) && spr->gz <= sclipBottom) return;
|
||||
if ((fake3D & FAKE3D_CLIPTOP) && spr->gz >= sclipTop) return;
|
||||
R_DrawParticle (spr);
|
||||
return;
|
||||
}
|
||||
|
@ -2675,6 +2730,93 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
if (spr->sector == NULL)
|
||||
return;
|
||||
|
||||
// kg3D - reject invisible parts
|
||||
if ((fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= sclipBottom) return;
|
||||
if ((fake3D & FAKE3D_CLIPTOP) && spr->gzb >= sclipTop) return;
|
||||
|
||||
// kg3D - correct colors now
|
||||
if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
if (!(fake3D & FAKE3D_CLIPTOP))
|
||||
{
|
||||
sclipTop = spr->sector->ceilingplane.ZatPoint(viewx, viewy);
|
||||
}
|
||||
sector_t *sec = NULL;
|
||||
for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0())
|
||||
{
|
||||
rover = spr->sector->e->XFloor.lightlist[i].caster;
|
||||
if (rover)
|
||||
{
|
||||
if (rover->flags & FF_DOUBLESHADOW && sclipTop <= rover->bottom.plane->Zat0())
|
||||
{
|
||||
break;
|
||||
}
|
||||
sec = rover->model;
|
||||
if (rover->flags & FF_FADEWALLS)
|
||||
{
|
||||
mybasecolormap = sec->ColorMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
mybasecolormap = spr->sector->e->XFloor.lightlist[i].extra_colormap;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// found new values, recalculate
|
||||
if (sec)
|
||||
{
|
||||
INTBOOL invertcolormap = (spr->RenderStyle.Flags & STYLEF_InvertOverlay);
|
||||
|
||||
if (spr->RenderStyle.Flags & STYLEF_InvertSource)
|
||||
{
|
||||
invertcolormap = !invertcolormap;
|
||||
}
|
||||
|
||||
// Sprites that are added to the scene must fade to black.
|
||||
if (spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
|
||||
{
|
||||
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
|
||||
}
|
||||
|
||||
if (spr->RenderStyle.Flags & STYLEF_FadeToBlack)
|
||||
{
|
||||
if (invertcolormap)
|
||||
{ // Fade to white
|
||||
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255,255,255), mybasecolormap->Desaturate);
|
||||
invertcolormap = false;
|
||||
}
|
||||
else
|
||||
{ // Fade to black
|
||||
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0,0,0), mybasecolormap->Desaturate);
|
||||
}
|
||||
}
|
||||
|
||||
// get light level
|
||||
if (invertcolormap)
|
||||
{
|
||||
mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate);
|
||||
}
|
||||
if (fixedlightlev >= 0)
|
||||
{
|
||||
spr->colormap = mybasecolormap->Maps + fixedlightlev;
|
||||
}
|
||||
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
|
||||
{ // full bright
|
||||
spr->colormap = mybasecolormap->Maps;
|
||||
}
|
||||
else
|
||||
{ // diminished light
|
||||
spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight);
|
||||
spr->colormap = mybasecolormap->Maps + (GETPALOOKUP (
|
||||
(fixed_t)DivScale12 (r_SpriteVisibility, spr->depth), spriteshade) << COLORMAPSHIFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Initialize the clipping arrays to their largest possible range
|
||||
// instead of using a special "not clipped" value. This eliminates
|
||||
// visual anomalies when looking down and should be faster, too.
|
||||
|
@ -2752,6 +2894,50 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
}
|
||||
}
|
||||
|
||||
if (fake3D & FAKE3D_CLIPBOTTOM)
|
||||
{
|
||||
if (!spr->bIsVoxel)
|
||||
{
|
||||
fixed_t h = sclipBottom;
|
||||
if (spr->fakefloor)
|
||||
{
|
||||
fixed_t floorz = spr->fakefloor->top.plane->Zat0();
|
||||
if (viewz > floorz && floorz == sclipBottom )
|
||||
{
|
||||
h = spr->fakefloor->bottom.plane->Zat0();
|
||||
}
|
||||
}
|
||||
h = (centeryfrac - FixedMul(h-viewz, scale)) >> FRACBITS;
|
||||
if (h < botclip)
|
||||
{
|
||||
botclip = MAX<short>(0, h);
|
||||
}
|
||||
}
|
||||
hzb = MAX(hzb, sclipBottom);
|
||||
}
|
||||
if (fake3D & FAKE3D_CLIPTOP)
|
||||
{
|
||||
if (!spr->bIsVoxel)
|
||||
{
|
||||
fixed_t h = sclipTop;
|
||||
|
||||
if (spr->fakeceiling != NULL)
|
||||
{
|
||||
fixed_t ceilingz = spr->fakeceiling->bottom.plane->Zat0();
|
||||
if (viewz < ceilingz && ceilingz == sclipTop)
|
||||
{
|
||||
h = spr->fakeceiling->top.plane->Zat0();
|
||||
}
|
||||
}
|
||||
h = (centeryfrac - FixedMul (h-viewz, scale)) >> FRACBITS;
|
||||
if (h > topclip)
|
||||
{
|
||||
topclip = MIN<short>(h, viewheight);
|
||||
}
|
||||
}
|
||||
hzt = MIN(hzt, sclipTop);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// [RH] Sprites that were split by a drawseg should also be clipped
|
||||
// by the sector's floor and ceiling. (Not sure how/if to handle this
|
||||
|
@ -2776,6 +2962,7 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
|
||||
if (topclip >= botclip)
|
||||
{
|
||||
spr->colormap = colormap;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2799,6 +2986,8 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
|
||||
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
||||
{
|
||||
// kg3D - no clipping on fake segs
|
||||
if(ds->fake) continue;
|
||||
// determine if the drawseg obscures the sprite
|
||||
if (ds->x1 > x2 || ds->x2 < x1 ||
|
||||
(!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 &&
|
||||
|
@ -2887,6 +3076,7 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
}
|
||||
if (i == x2)
|
||||
{
|
||||
spr->colormap = colormap;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2894,12 +3084,14 @@ void R_DrawSprite (vissprite_t *spr)
|
|||
int maxvoxely = spr->gzb > hzb ? INT_MAX : (spr->gzt - hzb) / spr->yscale;
|
||||
R_DrawVisVoxel(spr, minvoxely, maxvoxely, cliptop, clipbot);
|
||||
}
|
||||
spr->colormap = colormap;
|
||||
}
|
||||
|
||||
//
|
||||
// R_DrawMasked
|
||||
//
|
||||
void R_DrawMasked (void)
|
||||
// kg3D:
|
||||
// R_DrawMasked contains sorting
|
||||
// original renamed to R_DrawMaskedSingle
|
||||
|
||||
void R_DrawMaskedSingle (bool renew)
|
||||
{
|
||||
drawseg_t *ds;
|
||||
int i;
|
||||
|
@ -2907,7 +3099,6 @@ void R_DrawMasked (void)
|
|||
#if 0
|
||||
R_SplitVisSprites ();
|
||||
#endif
|
||||
R_SortVisSprites (sv_compare, firstvissprite - vissprites);
|
||||
|
||||
for (i = vsprcount; i > 0; i--)
|
||||
{
|
||||
|
@ -2922,14 +3113,75 @@ void R_DrawMasked (void)
|
|||
|
||||
// for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
|
||||
|
||||
if (renew)
|
||||
{
|
||||
fake3D |= FAKE3D_REFRESHCLIP;
|
||||
}
|
||||
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
||||
{
|
||||
// kg3D - no fake segs
|
||||
if (ds->fake) continue;
|
||||
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
|
||||
{
|
||||
R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes
|
||||
|
||||
void R_DrawMasked (void)
|
||||
{
|
||||
R_SortVisSprites (sv_compare, firstvissprite - vissprites);
|
||||
|
||||
if (height_top == NULL)
|
||||
{ // kg3D - no visible 3D floors, normal rendering
|
||||
R_DrawMaskedSingle(false);
|
||||
}
|
||||
else
|
||||
{ // kg3D - correct sorting
|
||||
HeightLevel *hl;
|
||||
|
||||
// ceilings
|
||||
for (hl = height_cur; hl != NULL && hl->height >= viewz; hl = hl->prev)
|
||||
{
|
||||
if (hl->next)
|
||||
{
|
||||
fake3D = FAKE3D_CLIPBOTTOM | FAKE3D_CLIPTOP;
|
||||
sclipTop = hl->next->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
fake3D = FAKE3D_CLIPBOTTOM;
|
||||
}
|
||||
sclipBottom = hl->height;
|
||||
R_DrawMaskedSingle(true);
|
||||
R_DrawHeightPlanes(hl->height);
|
||||
}
|
||||
|
||||
// floors
|
||||
fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP;
|
||||
sclipTop = height_top->height;
|
||||
R_DrawMaskedSingle(true);
|
||||
hl = height_top;
|
||||
for (hl = height_top; hl != NULL && hl->height < viewz; hl = hl->next)
|
||||
{
|
||||
R_DrawHeightPlanes(hl->height);
|
||||
if (hl->next)
|
||||
{
|
||||
fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP | FAKE3D_CLIPBOTTOM;
|
||||
sclipTop = hl->next->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPBOTTOM;
|
||||
}
|
||||
sclipBottom = hl->height;
|
||||
R_DrawMaskedSingle(true);
|
||||
}
|
||||
R_3D_DeleteHeights();
|
||||
fake3D = 0;
|
||||
}
|
||||
// draw the psprites on top of everything but does not draw on side views
|
||||
if (!viewangleoffset)
|
||||
{
|
||||
|
@ -3150,6 +3402,7 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
|
|||
vis->cx = tx;
|
||||
vis->gx = particle->x;
|
||||
vis->gy = particle->y;
|
||||
vis->texturemid = particle->z; // kg3D
|
||||
vis->gzb = y1;
|
||||
vis->gzt = y2;
|
||||
vis->x1 = x1;
|
||||
|
@ -3161,7 +3414,6 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
|
|||
vis->renderflags = particle->trans;
|
||||
vis->FakeFlatStat = fakeside;
|
||||
vis->floorclip = 0;
|
||||
vis->heightsec = heightsec;
|
||||
|
||||
if (fixedlightlev >= 0)
|
||||
{
|
||||
|
@ -3190,6 +3442,8 @@ static void R_DrawMaskedSegsBehindParticle (const vissprite_t *vis)
|
|||
for (unsigned int p = InterestingDrawsegs.Size(); p-- > FirstInterestingDrawseg; )
|
||||
{
|
||||
drawseg_t *ds = &drawsegs[InterestingDrawsegs[p]];
|
||||
// kg3D - no fake segs
|
||||
if(ds->fake) continue;
|
||||
if (ds->x1 >= x2 || ds->x2 < x1)
|
||||
{
|
||||
continue;
|
||||
|
|
|
@ -53,6 +53,12 @@ ACTOR MapSpot 9001
|
|||
RenderStyle None
|
||||
}
|
||||
|
||||
// same with different editor number for Legacy maps -----------------------
|
||||
|
||||
ACTOR FS_Mapspot : Mapspot 5004
|
||||
{
|
||||
}
|
||||
|
||||
// Map spot with gravity ---------------------------------------------------
|
||||
|
||||
ACTOR MapSpotGravity : MapSpot 9013
|
||||
|
|
BIN
wadsrc/static/etc.h.txt
Normal file
BIN
wadsrc/static/etc.h.txt
Normal file
Binary file not shown.
|
@ -920,6 +920,7 @@ OptionMenu MapColorMenu
|
|||
ColorPicker "1-sided walls", "am_wallcolor"
|
||||
ColorPicker "2-sided walls with different floors", "am_fdwallcolor"
|
||||
ColorPicker "2-sided walls with different ceilings", "am_cdwallcolor"
|
||||
ColorPicker "2-sided walls with 3D floors", "am_efwallcolor"
|
||||
ColorPicker "Map grid", "am_gridcolor"
|
||||
ColorPicker "Center point", "am_xhaircolor"
|
||||
ColorPicker "Not-yet-seen walls", "am_notseencolor"
|
||||
|
|
224
wadsrc/static/things.h.txt
Normal file
224
wadsrc/static/things.h.txt
Normal file
|
@ -0,0 +1,224 @@
|
|||
const PLAYER = 0;
|
||||
|
||||
const TROOPER = 1;
|
||||
const SHOTGUY = 2;
|
||||
const ARCHVILE = 3;
|
||||
const REVENANT = 5;
|
||||
const MANCUBUS = 8;
|
||||
const CHAINGUY = 10;
|
||||
const IMP = 11;
|
||||
const DEMON = 12;
|
||||
const SPECTRE = 13;
|
||||
const CACODEMON = 14;
|
||||
const BARONOFHELL = 15;
|
||||
const HELLKNIGHT = 17;
|
||||
const LOSTSOUL = 18;
|
||||
const SPIDERMASTERMIND = 19;
|
||||
const ARACHNOTRON = 20;
|
||||
const CYBERDEMON = 21;
|
||||
const PAINELEMENTAL = 22;
|
||||
const WOLFSS = 23;
|
||||
const KEEN = 24;
|
||||
const BOSSBRAIN = 25;
|
||||
const BOSSSPIT = 26;
|
||||
const BOSSTARGET = 27;
|
||||
|
||||
const REVENANTMISL = 6;
|
||||
const IMPSHOT = 31;
|
||||
const CACOSHOT = 32;
|
||||
const FLYINGROCKET = 33;
|
||||
const FLYINGPLASMA = 34;
|
||||
const FLYINGBFG = 35;
|
||||
const ARACHPLAZ = 36;
|
||||
const MANCUBUSSHOT = 9;
|
||||
const BARONSHOT = 16;
|
||||
const SPAWNSHOT = 28;
|
||||
|
||||
const PUFF = 37;
|
||||
const BLOOD = 38;
|
||||
const TFOG = 39;
|
||||
const IFOG = 40;
|
||||
const TELEPORTMAN = 41;
|
||||
const EXTRABFG = 42;
|
||||
const VILEFIRE = 4;
|
||||
const SMOKE = 7;
|
||||
const SPAWNFIRE = 29;
|
||||
const PARTICLE = 145;
|
||||
|
||||
const GREENARMOR = 43;
|
||||
const BLUEARMOR = 44;
|
||||
const HEALTHPOTION = 45;
|
||||
const ARMORHELMET = 46;
|
||||
const STIMPACK = 53;
|
||||
const MEDIKIT = 54;
|
||||
|
||||
const BLUEKEYCARD = 47;
|
||||
const REDKEYCARD = 48;
|
||||
const YELLOWKEYCARD = 49;
|
||||
const YELLOWSKULLKEY = 50;
|
||||
const REDSKULLKEY = 51;
|
||||
const BLUESKULLKEY = 52;
|
||||
|
||||
const SUPERCHARGE = 55;
|
||||
const INVULNERABILITY = 56;
|
||||
const BESERKPACK = 57;
|
||||
const INVISIBILITY = 58;
|
||||
const RADSUIT = 59;
|
||||
const AUTOMAP = 60;
|
||||
const LITEAMP = 61;
|
||||
const MEGASPHERE = 62;
|
||||
|
||||
const CLIP = 63;
|
||||
const BULLETBOX = 64;
|
||||
const ROCKET = 65;
|
||||
const ROCKETBOX = 66;
|
||||
const ECELL = 67;
|
||||
const ECELLPACK = 68;
|
||||
const SHELLS = 69;
|
||||
const SHELLBOX = 70;
|
||||
const BACKPACK = 71;
|
||||
|
||||
const BFG = 72;
|
||||
const CHAINGUN = 73;
|
||||
const CHAINSAW = 74;
|
||||
const RLAUNCHER = 75;
|
||||
const PLASMAGUN = 76;
|
||||
const SHOTGUN = 77;
|
||||
const SUPERSHOTGUN = 78;
|
||||
|
||||
const BARREL = 30;
|
||||
const TALLTECHLAMP = 79;
|
||||
const SHORTTECHLAMP = 80;
|
||||
const FLOORLAMP = 81;
|
||||
const TALLGRNPILLAR = 82;
|
||||
const SHRTGRNPILLAR = 83;
|
||||
const TALLREDPILLAR = 84;
|
||||
const SHRTREDPILLAR = 85;
|
||||
const SKULLCOLUMN = 86;
|
||||
const HEARTCOLUMN = 87;
|
||||
const EVILEYE = 88;
|
||||
const SKULLROCK = 89;
|
||||
const GRAYTREE = 90;
|
||||
const TALLBLUFIRESTICK = 91;
|
||||
const TALLGRNFIRESTICK = 92;
|
||||
const TALLREDFIRESTICK = 93;
|
||||
const SHRTBLUFIRESTICK = 94;
|
||||
const SHRTGRNFIRESTICK = 95;
|
||||
const SHRTREDFIRESTICK = 96;
|
||||
const STALAGMITE = 97;
|
||||
const TALLTECHPILLAR = 98;
|
||||
const CANDLE = 99;
|
||||
const CANDELABRA = 100;
|
||||
const TREE = 126;
|
||||
const BURNINGBARREL = 127;
|
||||
|
||||
const TWITCHCORPSE1 = 101;
|
||||
const TWITCHCORPSE2 = 110;
|
||||
const HANGINGMAN1 = 102;
|
||||
const HANGINGMAN2 = 103;
|
||||
const HANGINGMAN3 = 104;
|
||||
const HANGINGMAN4 = 105;
|
||||
const HANGINGMAN5 = 106;
|
||||
const HANGINGMAN6 = 107;
|
||||
const HANGINGMAN7 = 108;
|
||||
const HANGINGMAN8 = 109;
|
||||
const HANGINGMAN9 = 128;
|
||||
const HANGINGMAN10 = 129;
|
||||
const HANGINGMAN11 = 130;
|
||||
const HANGINGMAN12 = 131;
|
||||
const HANGINGMAN13 = 132;
|
||||
const HANGINGMAN14 = 133;
|
||||
|
||||
const DEADCACO = 111;
|
||||
const DEADPLAYER = 112;
|
||||
const DEADTROOPER = 113;
|
||||
const DEADDEMON = 114;
|
||||
const DEADLOSTSOUL = 115;
|
||||
const DEADIMP = 116;
|
||||
const DEADSERGEANT = 117;
|
||||
const SLOP = 118;
|
||||
const SLOP2 = 119;
|
||||
const SKULLPOLE1 = 120;
|
||||
const SKULLPOLE2 = 122;
|
||||
const BLOODPOOL1 = 121;
|
||||
const SKULLPILE = 123;
|
||||
const BLOODPOOL2 = 134;
|
||||
const BLOODPOOL3 = 135;
|
||||
const BLOODPOOL4 = 136;
|
||||
|
||||
const DEADCORPSE1 = 124;
|
||||
const TWITCHCORPSE3 = 125;
|
||||
|
||||
const PUSH = 137;
|
||||
const PULL = 138;
|
||||
const DOGS = 139;
|
||||
const MF_SPECIAL = 0;
|
||||
const MF_SOLID = 1;
|
||||
const MF_SHOOTABLE = 2;
|
||||
const MF_NOSECTOR = 3;
|
||||
const MF_NOBLOCKMAP = 4;
|
||||
|
||||
const MF_AMBUSH = 5;
|
||||
const MF_JUSTHIT = 6;
|
||||
const MF_JUSTATTACKED = 7;
|
||||
const MF_SPAWNCEILING = 8;
|
||||
const MF_NOGRAVITY = 9;
|
||||
|
||||
const MF_DROPOFF = 10;
|
||||
const MF_PICKUP = 11;
|
||||
const MF_NOCLIP = 12;
|
||||
const MF_SLIDE = 13;
|
||||
const MF_FLOAT = 14;
|
||||
const MF_TELEPORT = 15;
|
||||
const MF_MISSILE = 16;
|
||||
const MF_DROPPED = 17;
|
||||
const MF_SHADOW = 18;
|
||||
const MF_NOBLOOD = 19;
|
||||
const MF_CORPSE = 20;
|
||||
const MF_INFLOAT = 21;
|
||||
|
||||
const MF_COUNTKILL = 22;
|
||||
const MF_COUNTITEM = 23;
|
||||
|
||||
const MF_SKULLFLY = 24;
|
||||
|
||||
const MF_NOTDMATCH = 25;
|
||||
|
||||
const MF_TRANSLATION = 26;
|
||||
|
||||
|
||||
const PLASMA_L = 1;
|
||||
const PLASMAEXP_L = 2;
|
||||
const ROCKET_L = 3;
|
||||
const ROCKETEXP_L = 4;
|
||||
const BFG_L = 5;
|
||||
const BFGEXP_L = 6;
|
||||
const BLUETALL_L = 7;
|
||||
const GREENTALL_L = 8;
|
||||
const REDTALL_L = 9;
|
||||
const BLUESMALL_L = 10;
|
||||
const GREENSMALL_L = 11;
|
||||
const REDSMALL_L = 12;
|
||||
const TECHLAMP_L = 13;
|
||||
const TECHLAMP2_L = 14;
|
||||
const COLUMN_L = 15;
|
||||
const CANDLE_L = 16;
|
||||
const CANDLEABRE_L = 17;
|
||||
const REDBALL_L = 18;
|
||||
const GREENBALL_L = 19;
|
||||
const ROCKET2_L = 20;
|
||||
|
||||
const CORONA_TYPE = 0;
|
||||
const CORONA_OFFX = 1;
|
||||
const CORONA_OFFY = 2;
|
||||
const CORONA_COLOR = 3;
|
||||
const CORONA_SIZE = 4;
|
||||
|
||||
const LIGHT_COLOR = 5;
|
||||
const LIGHT_RADIUS = 6;
|
||||
const UNDEFINED_SPR = 0;
|
||||
const CORONA_SPR = 1;
|
||||
const DYNLIGHT_SPR = 2;
|
||||
const LIGHT_SPR = 3;
|
||||
const ROCKET_SPR = 19;
|
||||
|
|
@ -275,12 +275,21 @@ include "xlat/defines.i"
|
|||
|
||||
/****** MBF linetypes ******/
|
||||
|
||||
270 = WALK|REP, FS_Execute(tag)
|
||||
271 = 0, Static_Init (tag, Init_TransferSky, 0)
|
||||
272 = 0, Static_Init (tag, Init_TransferSky, 1)
|
||||
|
||||
/****** Legacy linetype ******/
|
||||
|
||||
/****** Legacy linetypes ******/
|
||||
273 = WALK|REP, FS_Execute(tag, 1)
|
||||
274 = WALK, FS_Execute(tag)
|
||||
275 = WALK, FS_Execute(tag, 1)
|
||||
276 = USE|REP, FS_Execute(tag)
|
||||
277 = USE, FS_Execute(tag)
|
||||
278 = SHOOT|REP, FS_Execute(tag)
|
||||
279 = SHOOT, FS_Execute(tag)
|
||||
280 = 0, Transfer_Heights (tag, 12)
|
||||
281 = 0, Sector_Set3DFloor(tag, 1, 0, 255)
|
||||
282 = 0, Static_Init(tag, 1)
|
||||
|
||||
// No, I haven't actually looked at these in Legacy. But these look like they
|
||||
// should give results equivalent to hardware Legacy rendering.
|
||||
|
@ -289,12 +298,18 @@ include "xlat/defines.i"
|
|||
286 = 0, TranslucentLine (lineid, 48, 0)
|
||||
287 = 0, TranslucentLine (lineid, 128, 1)
|
||||
|
||||
281 = 0, ExtraFloor_LightOnly (tag, 0) // thick extra floor
|
||||
301 = 0, ExtraFloor_LightOnly (tag, 1) // thick water
|
||||
302 = 0, ExtraFloor_LightOnly (tag, 1) // fog
|
||||
303 = 0, ExtraFloor_LightOnly (tag, 0) // light
|
||||
304 = 0, ExtraFloor_LightOnly (tag, 1) // opaque water
|
||||
305 = 0, ExtraFloor_LightOnly (tag, 1) // light block
|
||||
288 = 0, TranslucentLine(lineid, 255, 0)
|
||||
289 = 0, Sector_Set3DFloor(tag, 1, 1, 255)
|
||||
|
||||
300 = 0, Sector_Set3DFloor(tag, 1, 1, 127)
|
||||
301 = 0, Sector_Set3DFloor(tag, 2, 2, 127)
|
||||
302 = 0, Sector_Set3DFloor(tag, 3, 6, 127)
|
||||
303 = 0, Sector_Set3DFloor(tag, 3)
|
||||
304 = 0, Sector_Set3DFloor(tag, 2, 2, 255)
|
||||
305 = 0, Sector_Set3DFloor(tag, 3, 2)
|
||||
306 = 0, Sector_Set3DFloor(tag, 1)
|
||||
|
||||
332 = 0, Sector_Set3DFloor(tag, 4)
|
||||
|
||||
/****** ZDoom linetypes ******/
|
||||
|
||||
|
@ -327,20 +342,20 @@ include "xlat/defines.i"
|
|||
|
||||
/****** EDGE linetypes ******/
|
||||
|
||||
400 = 0, ExtraFloor_LightOnly (tag, 0) // thick
|
||||
401 = 0, ExtraFloor_LightOnly (tag, 0) // thick, side_upper
|
||||
402 = 0, ExtraFloor_LightOnly (tag, 0) // thick, side_lower
|
||||
403 = 0, ExtraFloor_LightOnly (tag, 2) // opaque liquid, flooder
|
||||
404 = 0, ExtraFloor_LightOnly (tag, 2) // 80% liquid, flooder
|
||||
405 = 0, ExtraFloor_LightOnly (tag, 2) // 60% liquid, flooder
|
||||
406 = 0, ExtraFloor_LightOnly (tag, 2) // 40% liquid, flooder
|
||||
407 = 0, ExtraFloor_LightOnly (tag, 2) // 20% liquid, flooder
|
||||
408 = 0, ExtraFloor_LightOnly (tag, 0) // light
|
||||
413 = 0, ExtraFloor_LightOnly (tag, 0) // thin opaque floor
|
||||
414 = 0, ExtraFloor_LightOnly (tag, 0) // thin 80% floor
|
||||
415 = 0, ExtraFloor_LightOnly (tag, 0) // thin 60% floor
|
||||
416 = 0, ExtraFloor_LightOnly (tag, 0) // thin 40% floor
|
||||
417 = 0, ExtraFloor_LightOnly (tag, 0) // thin 20% floor
|
||||
400 = 0, Sector_Set3DFloor(tag, 1, 0, 255)
|
||||
401 = 0, Sector_Set3DFloor(tag, 1, 16, 255)
|
||||
402 = 0, Sector_Set3DFloor(tag, 1, 32, 255)
|
||||
403 = 0, Sector_Set3DFloor(tag, 2, 2, 255)
|
||||
404 = 0, Sector_Set3DFloor(tag, 2, 2, 204)
|
||||
405 = 0, Sector_Set3DFloor(tag, 2, 2, 153)
|
||||
406 = 0, Sector_Set3DFloor(tag, 2, 2, 102)
|
||||
407 = 0, Sector_Set3DFloor(tag, 2, 2, 51)
|
||||
408 = 0, Sector_Set3DFloor(tag, 2, 2)
|
||||
413 = 0, Sector_Set3DFloor(tag, 1, 8, 255)
|
||||
414 = 0, Sector_Set3DFloor(tag, 1, 8, 204)
|
||||
415 = 0, Sector_Set3DFloor(tag, 1, 8, 153)
|
||||
416 = 0, Sector_Set3DFloor(tag, 1, 8, 102)
|
||||
417 = 0, Sector_Set3DFloor(tag, 1, 8, 51)
|
||||
|
||||
409 = 0, TranslucentLine (lineid, 204) // 80% translucent
|
||||
410 = 0, TranslucentLine (lineid, 153) // 60% translucent
|
||||
|
|
60
zdoom.vcproj
60
zdoom.vcproj
|
@ -2307,6 +2307,10 @@
|
|||
<Filter
|
||||
Name="Render Sources"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\r_3dfloors.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\r_bsp.cpp"
|
||||
>
|
||||
|
@ -2359,6 +2363,10 @@
|
|||
<Filter
|
||||
Name="Render Headers"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\r_3dfloors.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\r_blend.h"
|
||||
>
|
||||
|
@ -3628,6 +3636,58 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="FraggleScript"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_cmd.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_fs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_fspic.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_func.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_load.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_oper.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_parse.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_prepro.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_script.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_script.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_spec.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\fragglescript\t_variable.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue