diff --git a/src/doomdata.h b/src/doomdata.h index ef08ecaba..f3342e0cd 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -153,30 +153,30 @@ enum // Transfers FOF properties. ML_TFERLINE = 0x00008000, - - // Special action is repeatable. - ML_REPEATSPECIAL = 0x00010000, }; enum { + // Special action is repeatable. + SPAC_REPEATSPECIAL = 0x00000001, + // Activates when crossed by a player. - SPAC_CROSS = 0x00000001, + SPAC_CROSS = 0x00000002, // Activates when crossed by an enemy. - SPAC_CROSSMONSTER = 0x00000002, + SPAC_CROSSMONSTER = 0x00000004, // Activates when crossed by a projectile. - SPAC_CROSSMISSILE = 0x00000004, + SPAC_CROSSMISSILE = 0x00000008, // Activates when bumped by a player. - SPAC_PUSH = 0x00000008, + SPAC_PUSH = 0x00000010, // Activates when bumped by an enemy. - SPAC_PUSHMONSTER = 0x00000010, + SPAC_PUSHMONSTER = 0x00000020, // Activates when bumped by a missile. - SPAC_IMPACT = 0x00000020, + SPAC_IMPACT = 0x00000040, }; // Sector definition, from editing. diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 971834a8b..09cab84f1 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -204,6 +204,9 @@ static const struct { {META_LINEARGS, "line_t.args"}, {META_LINESTRINGARGS, "line_t.stringargs"}, + {META_SECTORARGS, "sector_t.args"}, + {META_SECTORSTRINGARGS, "sector_t.stringargs"}, + {META_THINGARGS, "mapthing.args"}, {META_THINGSTRINGARGS, "mapthing.stringargs"}, #ifdef HAVE_LUA_SEGS diff --git a/src/lua_libs.h b/src/lua_libs.h index 265cf8bc8..2d32a9eb5 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -77,6 +77,8 @@ extern lua_State *gL; #define META_SIDENUM "LINE_T*SIDENUM" #define META_LINEARGS "LINE_T*ARGS" #define META_LINESTRINGARGS "LINE_T*STRINGARGS" +#define META_SECTORARGS "SECTOR_T*ARGS" +#define META_SECTORSTRINGARGS "SECTOR_T*STRINGARGS" #define META_THINGARGS "MAPTHING_T*ARGS" #define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS" #define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES" diff --git a/src/lua_maplib.c b/src/lua_maplib.c index d7492c466..a9353be0f 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -56,6 +56,10 @@ enum sector_e { sector_triggerer, sector_friction, sector_gravity, + sector_action, + sector_args, + sector_stringargs, + sector_activation, }; static const char *const sector_opt[] = { @@ -86,6 +90,10 @@ static const char *const sector_opt[] = { "triggerer", "friction", "gravity", + "action", + "args" + "stringargs", + "activation", NULL}; enum subsector_e { @@ -592,6 +600,42 @@ static int sectorlines_num(lua_State *L) // sector_t // ////////////// +// args, i -> args[i] +static int sectorargs_get(lua_State *L) +{ + INT32 *args = *((INT32**)luaL_checkudata(L, 1, META_SECTORARGS)); + int i = luaL_checkinteger(L, 2); + if (i < 0 || i >= NUMSECTORARGS) + return luaL_error(L, LUA_QL("sector_t.args") " index cannot be %d", i); + lua_pushinteger(L, args[i]); + return 1; +} + +// #args -> NUMSECTORARGS +static int sectorargs_len(lua_State* L) +{ + lua_pushinteger(L, NUMSECTORARGS); + return 1; +} + +// stringargs, i -> stringargs[i] +static int sectorstringargs_get(lua_State *L) +{ + char **stringargs = *((char***)luaL_checkudata(L, 1, META_SECTORSTRINGARGS)); + int i = luaL_checkinteger(L, 2); + if (i < 0 || i >= NUMSECTORSTRINGARGS) + return luaL_error(L, LUA_QL("line_t.stringargs") " index cannot be %d", i); + lua_pushstring(L, stringargs[i]); + return 1; +} + +// #stringargs -> NUMLINESTRINGARGS +static int sectorstringargs_len(lua_State *L) +{ + lua_pushinteger(L, NUMSECTORSTRINGARGS); + return 1; +} + static int sector_get(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); @@ -710,6 +754,18 @@ static int sector_get(lua_State *L) case sector_gravity: // gravity lua_pushfixed(L, sector->gravity); return 1; + case sector_action: // action + lua_pushinteger(L, (INT16)sector->action); + return 1; + case sector_args: + LUA_PushUserdata(L, sector->args, META_SECTORARGS); + return 1; + case sector_stringargs: + LUA_PushUserdata(L, sector->stringargs, META_SECTORSTRINGARGS); + return 1; + case sector_activation: // activation + lua_pushinteger(L, sector->activation); + return 1; } return 0; } @@ -738,6 +794,8 @@ static int sector_set(lua_State *L) case sector_fslope: // f_slope case sector_cslope: // c_slope case sector_friction: // friction + case sector_args: // args + case sector_stringargs: // stringargs default: return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); case sector_floorheight: { // floorheight @@ -816,6 +874,12 @@ static int sector_set(lua_State *L) case sector_gravity: sector->gravity = luaL_checkfixed(L, 3); break; + case sector_action: + sector->action = (INT16)luaL_checkinteger(L, 3); + break; + case sector_activation: + sector->activation = luaL_checkinteger(L, 3); + break; } return 0; } @@ -2570,6 +2634,22 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + luaL_newmetatable(L, META_SECTORARGS); + lua_pushcfunction(L, sectorargs_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, sectorargs_len); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + + luaL_newmetatable(L, META_SECTORSTRINGARGS); + lua_pushcfunction(L, sectorstringargs_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, sectorstringargs_len); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + luaL_newmetatable(L, META_SUBSECTOR); lua_pushcfunction(L, subsector_get); lua_setfield(L, -2, "__index"); diff --git a/src/p_mobj.c b/src/p_mobj.c index 183f292c4..870aa77c6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9810,6 +9810,9 @@ void P_MobjThinker(mobj_t *mobj) P_SetTarget(&tm.floorthing, NULL); P_SetTarget(&tm.hitthing, NULL); + // Check for sector special actions + P_CheckMobjTouchingSectorActions(mobj); + // Sector flag MSF_TRIGGERLINE_MOBJ allows ANY mobj to trigger a linedef exec P_CheckMobjTrigger(mobj, false); diff --git a/src/p_saveg.c b/src/p_saveg.c index 319916f98..47a85c3df 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1099,8 +1099,40 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save) //diff4 flags #define SD_DAMAGETYPE 0x01 #define SD_TRIGGERTAG 0x02 -#define SD_TRIGGERER 0x04 -#define SD_GRAVITY 0x08 +#define SD_TRIGGERER 0x04 +#define SD_GRAVITY 0x08 +#define SD_ACTION 0x10 +#define SD_ARGS 0x20 +#define SD_STRINGARGS 0x40 +#define SD_DIFF5 0x80 + +//diff5 flags +#define SD_ACTIVATION 0x01 + +static boolean P_SectorArgsEqual(const sector_t *sc, const sector_t *spawnsc) +{ + UINT8 i; + for (i = 0; i < NUMSECTORARGS; i++) + if (sc->args[i] != spawnsc->args[i]) + return false; + + return true; +} + +static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawnsc) +{ + UINT8 i; + for (i = 0; i < NUMSECTORSTRINGARGS; i++) + { + if (!sc->stringargs[i]) + return !spawnsc->stringargs[i]; + + if (strcmp(sc->stringargs[i], spawnsc->stringargs[i])) + return false; + } + + return true; +} #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 @@ -1124,7 +1156,7 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save) // diff3 flags #define LD_ACTIVATION 0x01 -static boolean P_AreArgsEqual(const line_t *li, const line_t *spawnli) +static boolean P_LineArgsEqual(const line_t *li, const line_t *spawnli) { UINT8 i; for (i = 0; i < NUMLINEARGS; i++) @@ -1134,7 +1166,7 @@ static boolean P_AreArgsEqual(const line_t *li, const line_t *spawnli) return true; } -static boolean P_AreStringArgsEqual(const line_t *li, const line_t *spawnli) +static boolean P_LineStringArgsEqual(const line_t *li, const line_t *spawnli) { UINT8 i; for (i = 0; i < NUMLINESTRINGARGS; i++) @@ -1243,11 +1275,11 @@ static void ArchiveSectors(savebuffer_t *save) size_t i, j; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; - UINT8 diff, diff2, diff3, diff4; + UINT8 diff, diff2, diff3, diff4, diff5; for (i = 0; i < numsectors; i++, ss++, spawnss++) { - diff = diff2 = diff3 = diff4 = 0; + diff = diff2 = diff3 = diff4 = diff5 = 0; if (ss->floorheight != spawnss->floorheight) diff |= SD_FLOORHT; if (ss->ceilingheight != spawnss->ceilingheight) @@ -1303,9 +1335,21 @@ static void ArchiveSectors(savebuffer_t *save) if (ss->gravity != spawnss->gravity) diff4 |= SD_GRAVITY; + if (ss->action != spawnss->action) + diff4 |= SD_ACTION; + if (!P_SectorArgsEqual(ss, spawnss)) + diff4 |= SD_ARGS; + if (!P_SectorStringArgsEqual(ss, spawnss)) + diff4 |= SD_STRINGARGS; + if (ss->activation != spawnss->activation) + diff5 |= SD_ACTIVATION; + if (ss->ffloors && CheckFFloorDiff(ss)) diff |= SD_FFLOORS; + if (diff5) + diff4 |= SD_DIFF5; + if (diff4) diff3 |= SD_DIFF4; @@ -1383,6 +1427,35 @@ static void ArchiveSectors(savebuffer_t *save) WRITEUINT8(save->p, ss->triggerer); if (diff4 & SD_GRAVITY) WRITEFIXED(save->p, ss->gravity); + + if (diff4 & SD_ACTION) + WRITEINT16(save->p, ss->action); + if (diff4 & SD_ARGS) + { + for (j = 0; j < NUMSECTORARGS; j++) + WRITEINT32(save->p, ss->args[j]); + } + if (diff4 & SD_STRINGARGS) + { + for (j = 0; j < NUMSECTORSTRINGARGS; j++) + { + size_t len, k; + + if (!ss->stringargs[j]) + { + WRITEINT32(save->p, 0); + continue; + } + + len = strlen(ss->stringargs[j]); + WRITEINT32(save->p, len); + for (k = 0; k < len; k++) + WRITECHAR(save->p, ss->stringargs[j][k]); + } + } + if (diff5 & SD_ACTIVATION) + WRITEUINT32(save->p, ss->activation); + if (diff & SD_FFLOORS) ArchiveFFloors(save, ss); } @@ -1394,7 +1467,7 @@ static void ArchiveSectors(savebuffer_t *save) static void UnArchiveSectors(savebuffer_t *save) { UINT16 i, j; - UINT8 diff, diff2, diff3, diff4; + UINT8 diff, diff2, diff3, diff4, diff5; for (;;) { i = READUINT16(save->p); @@ -1419,6 +1492,11 @@ static void UnArchiveSectors(savebuffer_t *save) else diff4 = 0; + if (diff4 & SD_DIFF5) + diff5 = READUINT8(save->p); + else + diff5 = 0; + if (diff & SD_FLOORHT) sectors[i].floorheight = READFIXED(save->p); if (diff & SD_CEILHT) @@ -1504,6 +1582,36 @@ static void UnArchiveSectors(savebuffer_t *save) if (diff4 & SD_GRAVITY) sectors[i].gravity = READFIXED(save->p); + if (diff4 & SD_ACTION) + sectors[i].action = READINT16(save->p); + if (diff4 & SD_ARGS) + { + for (j = 0; j < NUMSECTORARGS; j++) + sectors[i].args[j] = READINT32(save->p); + } + if (diff4 & SD_STRINGARGS) + { + for (j = 0; j < NUMLINESTRINGARGS; j++) + { + size_t len = READINT32(save->p); + size_t k; + + if (!len) + { + Z_Free(sectors[i].stringargs[j]); + sectors[i].stringargs[j] = NULL; + continue; + } + + sectors[i].stringargs[j] = Z_Realloc(sectors[i].stringargs[j], len + 1, PU_LEVEL, NULL); + for (k = 0; k < len; k++) + sectors[i].stringargs[j][k] = READCHAR(save->p); + sectors[i].stringargs[j][len] = '\0'; + } + } + if (diff5 & SD_ACTIVATION) + sectors[i].activation = READUINT32(save->p); + if (diff & SD_FFLOORS) UnArchiveFFloors(save, §ors[i]); } @@ -1531,10 +1639,10 @@ static void ArchiveLines(savebuffer_t *save) if (spawnli->special == 321 || spawnli->special == 322) // only reason li->callcount would be non-zero is if either of these are involved diff |= LD_CLLCOUNT; - if (!P_AreArgsEqual(li, spawnli)) + if (!P_LineArgsEqual(li, spawnli)) diff2 |= LD_ARGS; - if (!P_AreStringArgsEqual(li, spawnli)) + if (!P_LineStringArgsEqual(li, spawnli)) diff2 |= LD_STRINGARGS; if (li->executordelay != spawnli->executordelay) diff --git a/src/p_setup.c b/src/p_setup.c index 1fe9e2f12..2bb1f40b5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -870,6 +870,11 @@ static void P_LoadSectors(UINT8 *data) ss->friction = ORIG_FRICTION; + ss->action = 0; + memset(ss->args, 0, NUMLINEARGS*sizeof(*ss->args)); + memset(ss->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ss->stringargs)); + ss->activation = 0; + P_InitializeSector(ss); } } @@ -980,6 +985,7 @@ static void P_LoadLinedefs(UINT8 *data) memset(ld->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ld->stringargs)); ld->alpha = FRACUNIT; ld->executordelay = 0; + ld->activation = 0; P_SetLinedefV1(i, SHORT(mld->v1)); P_SetLinedefV2(i, SHORT(mld->v2)); @@ -1216,6 +1222,7 @@ static void P_LoadThings(UINT8 *data) mt->scale = mapobjectscale; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); + mt->special = 0; mt->pitch = mt->roll = 0; mt->type &= 4095; @@ -1530,6 +1537,43 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char sectors[i].triggertag = atol(val); else if (fastcmp(param, "triggerer")) sectors[i].triggerer = atol(val); + else if (fastcmp(param, "action")) + sectors[i].action = atol(val); + else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9) + { + size_t argnum = atol(param + 9); + if (argnum >= NUMSECTORSTRINGARGS) + return; + sectors[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL); + M_Memcpy(sectors[i].stringargs[argnum], val, strlen(val) + 1); + } + else if (fastncmp(param, "arg", 3) && strlen(param) > 3) + { + size_t argnum = atol(param + 3); + if (argnum >= NUMSECTORARGS) + return; + sectors[i].args[argnum] = atol(val); + } + else if (fastcmp(param, "repeatspecial") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_REPEATSPECIAL; + else if (fastcmp(param, "playerenter") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_ENTER; + else if (fastcmp(param, "playerfloor") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_FLOOR; + else if (fastcmp(param, "playerceiling") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_CEILING; + else if (fastcmp(param, "monsterenter") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_ENTERMONSTER; + else if (fastcmp(param, "monsterfloor") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_FLOORMONSTER; + else if (fastcmp(param, "monsterceiling") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_CEILINGMONSTER; + else if (fastcmp(param, "missileenter") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_ENTERMISSILE; + else if (fastcmp(param, "missilefloor") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_FLOORMISSILE; + else if (fastcmp(param, "missileceiling") && fastcmp("true", val)) + sectors[i].activation |= SECSPAC_CEILINGMISSILE; } static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val) @@ -1642,9 +1686,9 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char lines[i].flags |= ML_NOTBOUNCY; else if (fastcmp(param, "transfer") && fastcmp("true", val)) lines[i].flags |= ML_TFERLINE; - else if (fastcmp(param, "repeatspecial") && fastcmp("true", val)) - lines[i].flags |= ML_REPEATSPECIAL; // Activation flags + else if (fastcmp(param, "repeatspecial") && fastcmp("true", val)) + lines[i].activation |= SPAC_REPEATSPECIAL; else if (fastcmp(param, "playercross") && fastcmp("true", val)) lines[i].activation |= SPAC_CROSS; else if (fastcmp(param, "monstercross") && fastcmp("true", val)) @@ -2219,7 +2263,7 @@ static void P_WriteTextmap(void) fprintf(f, "notbouncy = true;\n"); if (wlines[i].flags & ML_TFERLINE) fprintf(f, "transfer = true;\n"); - if (wlines[i].flags & ML_REPEATSPECIAL) + if (wlines[i].activation & SPAC_REPEATSPECIAL) fprintf(f, "repeatspecial = true;\n"); if (wlines[i].activation & SPAC_CROSS) fprintf(f, "playercross = true;\n"); @@ -2403,6 +2447,34 @@ static void P_WriteTextmap(void) fprintf(f, "triggertag = %d;\n", wsectors[i].triggertag); if (wsectors[i].triggerer != 0) fprintf(f, "triggerer = %d;\n", wsectors[i].triggerer); + if (wsectors[i].action != 0) + fprintf(f, "action = %d;\n", wsectors[i].action); + for (j = 0; j < NUMSECTORARGS; j++) + if (wsectors[i].args[j] != 0) + fprintf(f, "arg%s = %d;\n", sizeu1(j), wsectors[i].args[j]); + for (j = 0; j < NUMSECTORSTRINGARGS; j++) + if (wsectors[i].stringargs[j]) + fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), wsectors[i].stringargs[j]); + if (wsectors[i].activation & SECSPAC_REPEATSPECIAL) + fprintf(f, "repeatspecial = true;\n"); + if (wsectors[i].activation & SECSPAC_ENTER) + fprintf(f, "playerenter = true;\n"); + if (wsectors[i].activation & SECSPAC_FLOOR) + fprintf(f, "playerfloor = true;\n"); + if (wsectors[i].activation & SECSPAC_CEILING) + fprintf(f, "playerceiling = true;\n"); + if (wsectors[i].activation & SECSPAC_ENTERMONSTER) + fprintf(f, "monsterenter = true;\n"); + if (wsectors[i].activation & SECSPAC_FLOORMONSTER) + fprintf(f, "monsterfloor = true;\n"); + if (wsectors[i].activation & SECSPAC_CEILINGMONSTER) + fprintf(f, "monsterceiling = true;\n"); + if (wsectors[i].activation & SECSPAC_ENTERMISSILE) + fprintf(f, "missileenter = true;\n"); + if (wsectors[i].activation & SECSPAC_FLOORMISSILE) + fprintf(f, "missilefloor = true;\n"); + if (wsectors[i].activation & SECSPAC_CEILINGMISSILE) + fprintf(f, "missileceiling = true;\n"); fprintf(f, "}\n"); fprintf(f, "\n"); } @@ -2497,6 +2569,11 @@ static void P_LoadTextmap(void) sc->friction = ORIG_FRICTION; + sc->action = 0; + memset(sc->args, 0, NUMSECTORARGS*sizeof(*sc->args)); + memset(sc->stringargs, 0x00, NUMSECTORSTRINGARGS*sizeof(*sc->stringargs)); + sc->activation = 0; + textmap_colormap.used = false; textmap_colormap.lightcolor = 0; textmap_colormap.lightalpha = 25; @@ -2549,6 +2626,8 @@ static void P_LoadTextmap(void) ld->sidenum[0] = 0xffff; ld->sidenum[1] = 0xffff; + ld->activation = 0; + TextmapParse(linesPos[i], i, ParseTextmapLinedefParameter); if (!ld->v1) @@ -2593,6 +2672,7 @@ static void P_LoadTextmap(void) mt->scale = mapobjectscale; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); + mt->special = 0; mt->mobj = NULL; TextmapParse(mapthingsPos[i], i, ParseTextmapThingParameter); @@ -5843,14 +5923,12 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].blendmode = AST_FOG; break; case 2001: //Finish line - lines[i].activation |= SPAC_CROSS; - lines[i].flags |= ML_REPEATSPECIAL; + lines[i].activation |= (SPAC_CROSS|SPAC_REPEATSPECIAL); if (lines[i].flags & ML_NOCLIMB) lines[i].args[0] |= TMCFF_FLIP; break; case 2003: //Respawn line - lines[i].activation |= SPAC_CROSS; - lines[i].flags |= ML_REPEATSPECIAL; + lines[i].activation |= (SPAC_CROSS|SPAC_REPEATSPECIAL); if (lines[i].flags & ML_NOCLIMB) lines[i].args[0] |= TMCRF_FRONTONLY; break; diff --git a/src/p_spec.c b/src/p_spec.c index 938c20123..0a80f52f1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2101,7 +2101,7 @@ static void K_HandleLapDecrement(player_t *player) static void P_LineSpecialWasActivated(line_t *line) { - if (!(line->flags & ML_REPEATSPECIAL)) + if (!(line->activation & SPAC_REPEATSPECIAL)) { line->special = 0; } @@ -5410,6 +5410,260 @@ void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable) P_CheckMobjSectorTrigger(mobj, originalsector); } +static void P_SectorActionWasActivated(sector_t *sec) +{ + if ((sec->activation & SECSPAC_REPEATSPECIAL) == 0) + { + sec->action = 0; + } +} + +static boolean P_AllowSpecialEnter(sector_t *sec, mobj_t *thing) +{ + if (thing->player != NULL) + { + return !!(sec->activation & SECSPAC_ENTER); + } + else if ((thing->flags & (MF_ENEMY|MF_BOSS)) != 0) + { + return !!(sec->activation & SECSPAC_ENTERMONSTER); + } + else if (K_IsMissileOrKartItem(thing) == true) + { + return !!(sec->activation & SECSPAC_ENTERMISSILE); + } + + // No activation flags for you. + return false; +} + +static boolean P_AllowSpecialFloor(sector_t *sec, mobj_t *thing) +{ + if (thing->player != NULL) + { + return !!(sec->activation & SECSPAC_FLOOR); + } + else if ((thing->flags & (MF_ENEMY|MF_BOSS)) != 0) + { + return !!(sec->activation & SECSPAC_FLOORMONSTER); + } + else if (K_IsMissileOrKartItem(thing) == true) + { + return !!(sec->activation & SECSPAC_FLOORMISSILE); + } + + // No activation flags for you. + return false; +} + +static boolean P_AllowSpecialCeiling(sector_t *sec, mobj_t *thing) +{ + if (thing->player != NULL) + { + return !!(sec->activation & SECSPAC_CEILING); + } + else if ((thing->flags & (MF_ENEMY|MF_BOSS)) != 0) + { + return !!(sec->activation & SECSPAC_CEILINGMONSTER); + } + else if (K_IsMissileOrKartItem(thing) == true) + { + return !!(sec->activation & SECSPAC_CEILINGMISSILE); + } + + // No activation flags for you. + return false; +} + +static void P_CheckMobj3DFloorAction(mobj_t *mo, sector_t *sec) +{ + sector_t *originalsector = mo->subsector->sector; + ffloor_t *rover; + sector_t *roversec; + + activator_t *activator = NULL; + boolean result = false; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + roversec = rover->master->frontsector; + + if (P_CanActivateSpecial(roversec->action) == false) + { + // No special to even activate. + continue; + } + + if (P_AllowSpecialEnter(roversec, mo) == false) + { + boolean floor = false; + boolean ceiling = false; + + if (P_AllowSpecialFloor(roversec, mo) == true) + { + floor = (P_GetMobjFeet(mo) == P_GetSpecialTopZ(mo, roversec, roversec)); + } + + if (P_AllowSpecialCeiling(roversec, mo) == true) + { + ceiling = (P_GetMobjHead(mo) == P_GetSpecialBottomZ(mo, roversec, roversec)); + } + + if (floor == false && ceiling == false) + { + continue; + } + } + + activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); + I_Assert(activator != NULL); + + P_SetTarget(&activator->mo, mo); + activator->sector = roversec; + + result = P_ProcessSpecial(activator, roversec->action, roversec->args, roversec->stringargs); + Z_Free(activator); + + if (result == true) + { + P_SectorActionWasActivated(roversec); + } + + if TELEPORTED(mo) return; + } +} + +static void P_CheckMobjPolyobjAction(mobj_t *mo) +{ + sector_t *originalsector = mo->subsector->sector; + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; + + activator_t *activator = NULL; + boolean result = false; + + for (po = mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) + { + polysec = po->lines[0]->backsector; + + touching = P_MobjTouchingPolyobj(po, mo); + inside = P_MobjInsidePolyobj(po, mo); + + if (!(inside || touching)) + continue; + + if (P_CanActivateSpecial(polysec->action) == false) + { + // No special to even activate. + continue; + } + + if (P_AllowSpecialEnter(polysec, mo) == false) + { + boolean floor = false; + boolean ceiling = false; + + if (P_AllowSpecialFloor(polysec, mo) == true) + { + floor = (P_GetMobjFeet(mo) == P_GetSpecialTopZ(mo, polysec, polysec)); + } + + if (P_AllowSpecialCeiling(polysec, mo) == true) + { + ceiling = (P_GetMobjHead(mo) == P_GetSpecialBottomZ(mo, polysec, polysec)); + } + + if (floor == false && ceiling == false) + { + continue; + } + } + + activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); + I_Assert(activator != NULL); + + P_SetTarget(&activator->mo, mo); + activator->sector = polysec; + + result = P_ProcessSpecial(activator, polysec->action, polysec->args, polysec->stringargs); + Z_Free(activator); + + if (result == true) + { + P_SectorActionWasActivated(polysec); + } + + if TELEPORTED(mo) return; + } +} + +static void P_CheckMobjSectorAction(mobj_t *mo, sector_t *sec) +{ + activator_t *activator = NULL; + boolean result = false; + + if (P_CanActivateSpecial(sec->action) == false) + { + // No special to even activate. + return; + } + + if (P_AllowSpecialEnter(sec, mo) == false) + { + boolean floor = false; + boolean ceiling = false; + + if (P_AllowSpecialFloor(sec, mo) == true) + { + floor = (P_GetMobjFeet(mo) == P_GetSpecialBottomZ(mo, sec, sec)); + } + + if (P_AllowSpecialCeiling(sec, mo) == true) + { + ceiling = (P_GetMobjHead(mo) == P_GetSpecialTopZ(mo, sec, sec)); + } + + if (floor == false && ceiling == false) + { + return; + } + } + + activator = Z_Calloc(sizeof(activator_t), PU_LEVEL, NULL); + I_Assert(activator != NULL); + + P_SetTarget(&activator->mo, mo); + activator->sector = sec; + + result = P_ProcessSpecial(activator, sec->action, sec->args, sec->stringargs); + Z_Free(activator); + + if (result == true) + { + P_SectorActionWasActivated(sec); + } +} + +void P_CheckMobjTouchingSectorActions(mobj_t *mobj) +{ + sector_t *originalsector; + + if (!mobj->subsector) + return; + + originalsector = mobj->subsector->sector; + + P_CheckMobj3DFloorAction(mobj, originalsector); + if TELEPORTED(mobj) return; + + P_CheckMobjPolyobjAction(mobj); + if TELEPORTED(mobj) return; + + P_CheckMobjSectorAction(mobj, originalsector); +} + #undef TELEPORTED /** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up. diff --git a/src/p_spec.h b/src/p_spec.h index c8f5721e2..6ccb328cd 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -547,6 +547,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag); void P_PlayerInSpecialSector(player_t *player); void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable); +void P_CheckMobjTouchingSectorActions(mobj_t *mobj); sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline); boolean P_IsPlayerValid(size_t playernum); boolean P_CanPlayerTrigger(size_t playernum); diff --git a/src/r_defs.h b/src/r_defs.h index e5c6ea834..84b4e4993 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -371,6 +371,39 @@ typedef enum SSF_ZOOMTUBEEND = 1<<16, } sectorspecialflags_t; +typedef enum +{ + // Special action is repeatable. + SECSPAC_REPEATSPECIAL = 0x00000001, + + // When a player enters this sector. + SECSPAC_ENTER = 0x00000002, + + // When a player touches the floor of this sector. + SECSPAC_FLOOR = 0x00000004, + + // When a player touches the ceiling of this sector. + SECSPAC_CEILING = 0x00000008, + + // When an enemy enters this sector. + SECSPAC_ENTERMONSTER = 0x00000010, + + // When an enemy touches the floor of this sector. + SECSPAC_FLOORMONSTER = 0x00000020, + + // When an enemy touches the ceiling of this sector. + SECSPAC_CEILINGMONSTER = 0x00000040, + + // When a projectile enters this sector. + SECSPAC_ENTERMISSILE = 0x00000080, + + // When a projectile touches the floor of this sector. + SECSPAC_FLOORMISSILE = 0x00000100, + + // When a projectile touches the ceiling of this sector. + SECSPAC_CEILINGMISSILE = 0x00000200, +} sectoractionflags_t; + typedef enum { SD_NONE = 0, @@ -396,6 +429,9 @@ typedef enum CRUMBLE_RESTORE, // Crumble thinker is about to restore to original position } crumblestate_t; +#define NUMSECTORARGS 10 +#define NUMSECTORSTRINGARGS 2 + // // The SECTORS record, at runtime. // Stores things/mobjs. @@ -500,6 +536,12 @@ struct sector_t // colormap structure extracolormap_t *spawn_extra_colormap; + + // Action specials + INT16 action; + INT32 args[NUMSECTORARGS]; + char *stringargs[NUMSECTORSTRINGARGS]; + sectoractionflags_t activation; }; //