diff --git a/doc/manual/1up.png b/doc/manual/1up.png deleted file mode 100644 index d8617cb8..00000000 Binary files a/doc/manual/1up.png and /dev/null differ diff --git a/doc/manual/RNGA0000.png b/doc/manual/RNGA0000.png deleted file mode 100644 index 78f98625..00000000 Binary files a/doc/manual/RNGA0000.png and /dev/null differ diff --git a/doc/manual/RNGB0000.png b/doc/manual/RNGB0000.png deleted file mode 100644 index 71a9c51b..00000000 Binary files a/doc/manual/RNGB0000.png and /dev/null differ diff --git a/doc/manual/RNGE0000.png b/doc/manual/RNGE0000.png deleted file mode 100644 index 960b9c3b..00000000 Binary files a/doc/manual/RNGE0000.png and /dev/null differ diff --git a/doc/manual/RNGG0000.png b/doc/manual/RNGG0000.png deleted file mode 100644 index 38c552fc..00000000 Binary files a/doc/manual/RNGG0000.png and /dev/null differ diff --git a/doc/manual/RNGR0000.png b/doc/manual/RNGR0000.png deleted file mode 100644 index ad9c5c07..00000000 Binary files a/doc/manual/RNGR0000.png and /dev/null differ diff --git a/doc/manual/RNGS0000.png b/doc/manual/RNGS0000.png deleted file mode 100644 index bbcb6636..00000000 Binary files a/doc/manual/RNGS0000.png and /dev/null differ diff --git a/doc/manual/Ring0000.png b/doc/manual/Ring0000.png deleted file mode 100644 index 730f6f59..00000000 Binary files a/doc/manual/Ring0000.png and /dev/null differ diff --git a/doc/manual/acz.png b/doc/manual/acz.png deleted file mode 100644 index f8d98a65..00000000 Binary files a/doc/manual/acz.png and /dev/null differ diff --git a/doc/manual/airspin.png b/doc/manual/airspin.png deleted file mode 100644 index 943ee546..00000000 Binary files a/doc/manual/airspin.png and /dev/null differ diff --git a/doc/manual/attack.png b/doc/manual/attack.png deleted file mode 100644 index 3f3e48fd..00000000 Binary files a/doc/manual/attack.png and /dev/null differ diff --git a/doc/manual/blue_monitor.png b/doc/manual/blue_monitor.png deleted file mode 100644 index f6d01f80..00000000 Binary files a/doc/manual/blue_monitor.png and /dev/null differ diff --git a/doc/manual/blue_ring.png b/doc/manual/blue_ring.png deleted file mode 100644 index 8ffd4b38..00000000 Binary files a/doc/manual/blue_ring.png and /dev/null differ diff --git a/doc/manual/bshield.png b/doc/manual/bshield.png deleted file mode 100644 index 01f16a3a..00000000 Binary files a/doc/manual/bshield.png and /dev/null differ diff --git a/doc/manual/cez.png b/doc/manual/cez.png deleted file mode 100644 index 34848023..00000000 Binary files a/doc/manual/cez.png and /dev/null differ diff --git a/doc/manual/controls.png b/doc/manual/controls.png deleted file mode 100644 index 8422625a..00000000 Binary files a/doc/manual/controls.png and /dev/null differ diff --git a/doc/manual/conveyor.png b/doc/manual/conveyor.png deleted file mode 100644 index 871549aa..00000000 Binary files a/doc/manual/conveyor.png and /dev/null differ diff --git a/doc/manual/coop.png b/doc/manual/coop.png deleted file mode 100644 index b1ed48b0..00000000 Binary files a/doc/manual/coop.png and /dev/null differ diff --git a/doc/manual/crusher.png b/doc/manual/crusher.png deleted file mode 100644 index 42859e61..00000000 Binary files a/doc/manual/crusher.png and /dev/null differ diff --git a/doc/manual/ctf.png b/doc/manual/ctf.png deleted file mode 100644 index 24712f65..00000000 Binary files a/doc/manual/ctf.png and /dev/null differ diff --git a/doc/manual/dsz.png b/doc/manual/dsz.png deleted file mode 100644 index cc062bf8..00000000 Binary files a/doc/manual/dsz.png and /dev/null differ diff --git a/doc/manual/eggbox.png b/doc/manual/eggbox.png deleted file mode 100644 index a45ead1b..00000000 Binary files a/doc/manual/eggbox.png and /dev/null differ diff --git a/doc/manual/eggman.png b/doc/manual/eggman.png deleted file mode 100644 index 3ee0a0d2..00000000 Binary files a/doc/manual/eggman.png and /dev/null differ diff --git a/doc/manual/emblem.png b/doc/manual/emblem.png deleted file mode 100644 index 0aa63b65..00000000 Binary files a/doc/manual/emblem.png and /dev/null differ diff --git a/doc/manual/fan.png b/doc/manual/fan.png deleted file mode 100644 index 74e4a17d..00000000 Binary files a/doc/manual/fan.png and /dev/null differ diff --git a/doc/manual/gfz.png b/doc/manual/gfz.png deleted file mode 100644 index 6530f1a9..00000000 Binary files a/doc/manual/gfz.png and /dev/null differ diff --git a/doc/manual/gshield.png b/doc/manual/gshield.png deleted file mode 100644 index 225f1a76..00000000 Binary files a/doc/manual/gshield.png and /dev/null differ diff --git a/doc/manual/invc.png b/doc/manual/invc.png deleted file mode 100644 index f0e7a634..00000000 Binary files a/doc/manual/invc.png and /dev/null differ diff --git a/doc/manual/knuckles.png b/doc/manual/knuckles.png deleted file mode 100644 index 4fef38b5..00000000 Binary files a/doc/manual/knuckles.png and /dev/null differ diff --git a/doc/manual/koneup.png b/doc/manual/koneup.png deleted file mode 100644 index cda5b1b8..00000000 Binary files a/doc/manual/koneup.png and /dev/null differ diff --git a/doc/manual/manual.htm b/doc/manual/manual.htm index bdf4d2a9..3fea1b66 100644 --- a/doc/manual/manual.htm +++ b/doc/manual/manual.htm @@ -13,7 +13,7 @@ doc = doc || document; // from http://stackoverflow.com/questions/1145850/get-height-of-entire-document-with-javascript var body = doc.body, html = doc.documentElement; - var height = Math.max( body.scrollHeight, body.offsetHeight, + var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); return height; } @@ -65,4 +65,4 @@

- \ No newline at end of file + diff --git a/doc/manual/match.png b/doc/manual/match.png deleted file mode 100644 index a89bf8d5..00000000 Binary files a/doc/manual/match.png and /dev/null differ diff --git a/doc/manual/metal.png b/doc/manual/metal.png deleted file mode 100644 index 6fc385c4..00000000 Binary files a/doc/manual/metal.png and /dev/null differ diff --git a/doc/manual/mixup.png b/doc/manual/mixup.png deleted file mode 100644 index fc26fed1..00000000 Binary files a/doc/manual/mixup.png and /dev/null differ diff --git a/doc/manual/pit.png b/doc/manual/pit.png deleted file mode 100644 index 5accda68..00000000 Binary files a/doc/manual/pit.png and /dev/null differ diff --git a/doc/manual/platform.png b/doc/manual/platform.png deleted file mode 100644 index c0e4c499..00000000 Binary files a/doc/manual/platform.png and /dev/null differ diff --git a/doc/manual/race.png b/doc/manual/race.png deleted file mode 100644 index 66ebf9c6..00000000 Binary files a/doc/manual/race.png and /dev/null differ diff --git a/doc/manual/random.png b/doc/manual/random.png deleted file mode 100644 index 303ad5b5..00000000 Binary files a/doc/manual/random.png and /dev/null differ diff --git a/doc/manual/recycler.png b/doc/manual/recycler.png deleted file mode 100644 index 12e0343f..00000000 Binary files a/doc/manual/recycler.png and /dev/null differ diff --git a/doc/manual/red_monitor.png b/doc/manual/red_monitor.png deleted file mode 100644 index 8ceae6ef..00000000 Binary files a/doc/manual/red_monitor.png and /dev/null differ diff --git a/doc/manual/red_ring.png b/doc/manual/red_ring.png deleted file mode 100644 index c3dcdd4c..00000000 Binary files a/doc/manual/red_ring.png and /dev/null differ diff --git a/doc/manual/ring.png b/doc/manual/ring.png deleted file mode 100644 index 6f7c54f0..00000000 Binary files a/doc/manual/ring.png and /dev/null differ diff --git a/doc/manual/rshield.png b/doc/manual/rshield.png deleted file mode 100644 index 7a346cab..00000000 Binary files a/doc/manual/rshield.png and /dev/null differ diff --git a/doc/manual/rvz.png b/doc/manual/rvz.png deleted file mode 100644 index e20c5dc1..00000000 Binary files a/doc/manual/rvz.png and /dev/null differ diff --git a/doc/manual/shoes.png b/doc/manual/shoes.png deleted file mode 100644 index 5667f546..00000000 Binary files a/doc/manual/shoes.png and /dev/null differ diff --git a/doc/manual/slime.png b/doc/manual/slime.png deleted file mode 100644 index 857f98fd..00000000 Binary files a/doc/manual/slime.png and /dev/null differ diff --git a/doc/manual/soneup.png b/doc/manual/soneup.png deleted file mode 100644 index f9f869f0..00000000 Binary files a/doc/manual/soneup.png and /dev/null differ diff --git a/doc/manual/spring1.png b/doc/manual/spring1.png deleted file mode 100644 index 8a222f37..00000000 Binary files a/doc/manual/spring1.png and /dev/null differ diff --git a/doc/manual/spring2.png b/doc/manual/spring2.png deleted file mode 100644 index 4e7b1a05..00000000 Binary files a/doc/manual/spring2.png and /dev/null differ diff --git a/doc/manual/spring3.png b/doc/manual/spring3.png deleted file mode 100644 index c7b88b88..00000000 Binary files a/doc/manual/spring3.png and /dev/null differ diff --git a/doc/manual/spring4.png b/doc/manual/spring4.png deleted file mode 100644 index d1691926..00000000 Binary files a/doc/manual/spring4.png and /dev/null differ diff --git a/doc/manual/spring5.png b/doc/manual/spring5.png deleted file mode 100644 index 0eedf4a6..00000000 Binary files a/doc/manual/spring5.png and /dev/null differ diff --git a/doc/manual/spring6.png b/doc/manual/spring6.png deleted file mode 100644 index 012b7bc2..00000000 Binary files a/doc/manual/spring6.png and /dev/null differ diff --git a/doc/manual/spring7.png b/doc/manual/spring7.png deleted file mode 100644 index 98c88bcd..00000000 Binary files a/doc/manual/spring7.png and /dev/null differ diff --git a/doc/manual/spring8.png b/doc/manual/spring8.png deleted file mode 100644 index ec552eeb..00000000 Binary files a/doc/manual/spring8.png and /dev/null differ diff --git a/doc/manual/stats_lives.png b/doc/manual/stats_lives.png deleted file mode 100644 index ec137139..00000000 Binary files a/doc/manual/stats_lives.png and /dev/null differ diff --git a/doc/manual/stats_rings.png b/doc/manual/stats_rings.png deleted file mode 100644 index 5b807403..00000000 Binary files a/doc/manual/stats_rings.png and /dev/null differ diff --git a/doc/manual/tag.png b/doc/manual/tag.png deleted file mode 100644 index 72954b2b..00000000 Binary files a/doc/manual/tag.png and /dev/null differ diff --git a/doc/manual/tailsfly.png b/doc/manual/tailsfly.png deleted file mode 100644 index 7628128d..00000000 Binary files a/doc/manual/tailsfly.png and /dev/null differ diff --git a/doc/manual/thanks.png b/doc/manual/thanks.png deleted file mode 100644 index 8cb0ad11..00000000 Binary files a/doc/manual/thanks.png and /dev/null differ diff --git a/doc/manual/thz.png b/doc/manual/thz.png deleted file mode 100644 index f4db3c59..00000000 Binary files a/doc/manual/thz.png and /dev/null differ diff --git a/doc/manual/title.png b/doc/manual/title.png deleted file mode 100644 index e4ea963a..00000000 Binary files a/doc/manual/title.png and /dev/null differ diff --git a/doc/manual/token.png b/doc/manual/token.png deleted file mode 100644 index 0e821ce3..00000000 Binary files a/doc/manual/token.png and /dev/null differ diff --git a/doc/manual/toneup.png b/doc/manual/toneup.png deleted file mode 100644 index 42597329..00000000 Binary files a/doc/manual/toneup.png and /dev/null differ diff --git a/doc/manual/unknown.png b/doc/manual/unknown.png deleted file mode 100644 index a59a6c76..00000000 Binary files a/doc/manual/unknown.png and /dev/null differ diff --git a/doc/manual/water.png b/doc/manual/water.png deleted file mode 100644 index 2d5d607e..00000000 Binary files a/doc/manual/water.png and /dev/null differ diff --git a/doc/manual/wpnpanel_auto.png b/doc/manual/wpnpanel_auto.png deleted file mode 100644 index af71f98b..00000000 Binary files a/doc/manual/wpnpanel_auto.png and /dev/null differ diff --git a/doc/manual/wpnpanel_bounce.png b/doc/manual/wpnpanel_bounce.png deleted file mode 100644 index 606b3598..00000000 Binary files a/doc/manual/wpnpanel_bounce.png and /dev/null differ diff --git a/doc/manual/wpnpanel_explosion.png b/doc/manual/wpnpanel_explosion.png deleted file mode 100644 index f3bd45de..00000000 Binary files a/doc/manual/wpnpanel_explosion.png and /dev/null differ diff --git a/doc/manual/wpnpanel_grenade.png b/doc/manual/wpnpanel_grenade.png deleted file mode 100644 index f0e18fa0..00000000 Binary files a/doc/manual/wpnpanel_grenade.png and /dev/null differ diff --git a/doc/manual/wpnpanel_rail.png b/doc/manual/wpnpanel_rail.png deleted file mode 100644 index bf082236..00000000 Binary files a/doc/manual/wpnpanel_rail.png and /dev/null differ diff --git a/doc/manual/wpnpanel_scatter.png b/doc/manual/wpnpanel_scatter.png deleted file mode 100644 index 497f1abe..00000000 Binary files a/doc/manual/wpnpanel_scatter.png and /dev/null differ diff --git a/doc/manual/wshield.png b/doc/manual/wshield.png deleted file mode 100644 index 20e3cf34..00000000 Binary files a/doc/manual/wshield.png and /dev/null differ diff --git a/doc/manual/yshield.png b/doc/manual/yshield.png deleted file mode 100644 index 6271eab9..00000000 Binary files a/doc/manual/yshield.png and /dev/null differ diff --git a/readme.txt b/readme.txt index f96d3823..8a09f0bc 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -Here it is! SRB2 v2.1.11 source code! +Here it is! SRB2 v2.1.12 source code! (why do we keep the version number up to date when everything else in this file is hilariously old? - Inuyasha) diff --git a/src/blua/lapi.c b/src/blua/lapi.c index 2d837057..73fbbf56 100644 --- a/src/blua/lapi.c +++ b/src/blua/lapi.c @@ -319,21 +319,6 @@ LUA_API lua_Number lua_tonumber (lua_State *L, int idx) { return 0; } - -LUA_API lua_Integer lua_tointeger (lua_State *L, int idx) { - TValue n; - const TValue *o = index2adr(L, idx); - if (tonumber(o, &n)) { - lua_Integer res; - lua_Number num = nvalue(o); - lua_number2integer(res, num); - return res; - } - else - return 0; -} - - LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2adr(L, idx); return !l_isfalse(o); @@ -446,14 +431,6 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { } -LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { - lua_lock(L); - setnvalue(L->top, cast_num(n)); - api_incr_top(L); - lua_unlock(L); -} - - LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t len) { lua_lock(L); luaC_checkGC(L); diff --git a/src/blua/lauxlib.c b/src/blua/lauxlib.c index c43cefd1..db7d9d0d 100644 --- a/src/blua/lauxlib.c +++ b/src/blua/lauxlib.c @@ -186,20 +186,6 @@ LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { } -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { - lua_Integer d = lua_tointeger(L, narg); - if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */ - tag_error(L, narg, LUA_TNUMBER); - return d; -} - - -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, - lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, narg, def); -} - - LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return 0; diff --git a/src/blua/lauxlib.h b/src/blua/lauxlib.h index 03204105..c5ea45a1 100644 --- a/src/blua/lauxlib.h +++ b/src/blua/lauxlib.h @@ -54,9 +54,8 @@ LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, - lua_Integer def); +#define luaL_checkinteger luaL_checknumber +#define luaL_optinteger luaL_optnumber LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); diff --git a/src/blua/lua.h b/src/blua/lua.h index a945fcb5..4e26c2a7 100644 --- a/src/blua/lua.h +++ b/src/blua/lua.h @@ -100,7 +100,7 @@ typedef LUA_NUMBER lua_Number; /* type for integer functions */ -typedef LUA_INTEGER lua_Integer; +#define lua_Integer lua_Number @@ -144,7 +144,7 @@ LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); -LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +#define lua_tointeger lua_tonumber LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_objlen) (lua_State *L, int idx); @@ -159,7 +159,7 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); */ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +#define lua_pushinteger lua_pushnumber LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); LUA_API void (lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, diff --git a/src/blua/lvm.c b/src/blua/lvm.c index 17764846..a921d443 100644 --- a/src/blua/lvm.c +++ b/src/blua/lvm.c @@ -323,7 +323,7 @@ static void Arith (lua_State *L, StkId ra, TValue *rb, case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: if (nc == 0) { lua_pushliteral(L, "divide by zero error"); lua_error(L); } else setnvalue(ra, luai_numdiv(nb, nc)); break; - case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TM_MOD: if (nc == 0) { lua_pushliteral(L, "modulo by zero error"); lua_error(L); } else setnvalue(ra, luai_nummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; case TM_AND: setnvalue(ra, luai_numand(nb, nc)); break; @@ -494,7 +494,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { if (nc == 0) { lua_pushliteral(L, "divide by zero error"); lua_error(L); - } + } else setnvalue(ra, luai_numdiv(nb, nc)); } @@ -503,7 +503,19 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_MOD: { - arith_op(luai_nummod, TM_MOD); + TValue *rb = RKB(i); + TValue *rc = RKC(i); + if (ttisnumber(rb) && ttisnumber(rc)) { + lua_Number nb = nvalue(rb), nc = nvalue(rc); + if (nc == 0) { + lua_pushliteral(L, "modulo by zero error"); + lua_error(L); + } + else + setnvalue(ra, luai_nummod(nb, nc)); + } + else + Protect(Arith(L, ra, rb, rc, TM_MOD)); continue; } case OP_POW: { diff --git a/src/command.c b/src/command.c index baf97cbd..09588eb8 100644 --- a/src/command.c +++ b/src/command.c @@ -1055,9 +1055,22 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (var->PossibleValue) { - INT32 v = atoi(valstr); - if (!v && valstr[0] != '0') - v = INT32_MIN; // Invalid integer trigger + INT32 v; + + if (var->flags & CV_FLOAT) + { + double d = atof(valstr); + if (!d && valstr[0] != '0') + v = INT32_MIN; + else + v = (INT32)(d * FRACUNIT); + } + else + { + v = atoi(valstr); + if (!v && valstr[0] != '0') + v = INT32_MIN; // Invalid integer trigger + } if (var->PossibleValue[0].strvalue && !stricmp(var->PossibleValue[0].strvalue, "MIN")) // bounded cvar { @@ -1134,13 +1147,13 @@ found: var->string = var->zstring = Z_StrDup(valstr); - if (var->flags & CV_FLOAT) + if (override) + var->value = overrideval; + else if (var->flags & CV_FLOAT) { double d = atof(var->string); var->value = (INT32)(d * FRACUNIT); } - else if (override) - var->value = overrideval; else var->value = atoi(var->string); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 659dac1d..e24a1426 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2921,6 +2921,12 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) displayplayer = newplayernum; secondarydisplayplayer = newplayernum; DEBFILE("spawning me\n"); + // Apply player flags as soon as possible! + players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE); + if (cv_flipcam.value) + players[newplayernum].pflags |= PF_FLIPCAM; + if (cv_analog.value) + players[newplayernum].pflags |= PF_ANALOGMODE; } else { @@ -2928,6 +2934,12 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) DEBFILE("spawning my brother\n"); if (botingame) players[newplayernum].bot = 1; + // Same goes for player 2 when relevant + players[newplayernum].pflags &= ~(/*PF_FLIPCAM|*/PF_ANALOGMODE); + //if (cv_flipcam2.value) + //players[newplayernum].pflags |= PF_FLIPCAM; + if (cv_analog2.value) + players[newplayernum].pflags |= PF_ANALOGMODE; } D_SendPlayerConfig(); addedtogame = true; diff --git a/src/d_main.c b/src/d_main.c index bf1bc733..4cea94a8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1087,14 +1087,14 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#if 1 // md5s last updated 8/05/14 +#if 1 // md5s last updated 11/10/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad W_VerifyFileMD5(1, "f39b6c849295e3c81875726e8cc0e2c7"); // zones.dta W_VerifyFileMD5(2, "cfca0f1c73023cbbd8f844f45480f799"); // player.dta W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta - W_VerifyFileMD5(4, "3d6cfc185fd7c195eb934ce593b0248f"); // patch.dta + W_VerifyFileMD5(4, "a45cc59d13dce924f2112b3e4201d0ae"); // patch.dta // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5e81a5a5..377da843 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -164,6 +164,7 @@ static void Command_Archivetest_f(void); // ========================================================================= void SendWeaponPref(void); +void SendWeaponPref2(void); static CV_PossibleValue_t usemouse_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Force"}, {0, NULL}}; #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) @@ -1345,26 +1346,34 @@ void SendWeaponPref(void) XBOXSTATIC UINT8 buf[1]; buf[0] = 0; - if (cv_flipcam.value) + if (players[consoleplayer].pflags & PF_FLIPCAM) buf[0] |= 1; + if (players[consoleplayer].pflags & PF_ANALOGMODE) + buf[0] |= 2; SendNetXCmd(XD_WEAPONPREF, buf, 1); +} - if (splitscreen) - { - buf[0] = 0; - if (cv_flipcam2.value) - buf[0] |= 1; - SendNetXCmd2(XD_WEAPONPREF, buf, 1); - } +void SendWeaponPref2(void) +{ + XBOXSTATIC UINT8 buf[1]; + + buf[0] = 0; + if (players[secondarydisplayplayer].pflags & PF_FLIPCAM) + buf[0] |= 1; + if (players[secondarydisplayplayer].pflags & PF_ANALOGMODE) + buf[0] |= 2; + SendNetXCmd2(XD_WEAPONPREF, buf, 1); } static void Got_WeaponPref(UINT8 **cp,INT32 playernum) { UINT8 prefs = READUINT8(*cp); + + players[playernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE); if (prefs & 1) players[playernum].pflags |= PF_FLIPCAM; - else - players[playernum].pflags &= ~PF_FLIPCAM; + if (prefs & 2) + players[playernum].pflags |= PF_ANALOGMODE; } void D_SendPlayerConfig(void) @@ -1373,6 +1382,8 @@ void D_SendPlayerConfig(void) if (splitscreen || botingame) SendNameAndColor2(); SendWeaponPref(); + if (splitscreen) + SendWeaponPref2(); } // Only works for displayplayer, sorry! @@ -1798,7 +1809,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (demorecording) // Okay, level loaded, character spawned and skinned, G_BeginRecording(); // I AM NOW READY TO RECORD. demo_start = true; - metal_start = true; } static void Command_Pause(void) diff --git a/src/d_player.h b/src/d_player.h index b0484f0a..b9fcdef7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -151,6 +151,7 @@ typedef enum /*** misc ***/ PF_FORCESTRAFE = 1<<29, // Turning inputs are translated into strafing inputs + PF_ANALOGMODE = 1<<30, // Analog mode? // free: 1<<30 and 1<<31 } pflags_t; diff --git a/src/dehacked.c b/src/dehacked.c index 334179ac..ccb7248e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7273,6 +7273,7 @@ static const char *const PLAYERFLAG_LIST[] = { /*** misc ***/ "FORCESTRAFE", // Translate turn inputs into strafe inputs + "ANALOGMODE", // Analog mode? NULL // stop loop here. }; diff --git a/src/doomdef.h b/src/doomdef.h index a978e047..a9e18eaf 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -144,8 +144,8 @@ extern FILE *logstream; #define VERSIONSTRING "Trunk" #else #define VERSION 201 // Game version -#define SUBVERSION 11 // more precise version number -#define VERSIONSTRING "v2.1.11" +#define SUBVERSION 12 // more precise version number +#define VERSIONSTRING "v2.1.12" #endif // Modification options @@ -428,9 +428,8 @@ extern const char *compdate, *comptime, *comprevision; // Compile them at your own risk! /// Max recursive portal renders -/// \note sadly some additional work will need to be done -/// before anything > 1 will function correctly -#define PORTAL_LIMIT 1 +/// \note obsoleted by cv_maxportals +//#define PORTAL_LIMIT 8 /// Fun experimental slope stuff! //#define SLOPENESS @@ -453,7 +452,7 @@ extern const char *compdate, *comptime, *comprevision; //#define CHAOSISNOTDEADYET /// Polyobject fake flat code -//#define POLYOBJECTS_PLANES +#define POLYOBJECTS_PLANES /// Blue spheres for future use. /// \todo Remove this define. @@ -493,4 +492,7 @@ extern const char *compdate, *comptime, *comprevision; #define CLIENT_LOADINGSCREEN #endif +/// Experimental tweaks to analog mode. (Needs a lot of work before it's ready for primetime.) +//#define REDSANALOG + #endif // __DOOMDEF__ diff --git a/src/doomstat.h b/src/doomstat.h index 3cf70e46..b05b3833 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -165,7 +165,6 @@ extern cutscene_t *cutscenes[128]; // For the Custom Exit linedef. extern INT16 nextmapoverride; -extern INT32 nextmapgametype; extern boolean skipstats; extern UINT32 totalrings; // Total # of rings in a level diff --git a/src/f_finale.c b/src/f_finale.c index 103c7df3..f541995d 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -958,29 +958,30 @@ boolean F_IntroResponder(event_t *event) // CREDITS // ========= static const char *credits[] = { - "\1Sonic Team Junior", - "\1Staff", + "\1Sonic Robo Blast II", + "\1Credits", "", "\1Game Design", - "\"SSNTails\"", "Ben \"Mystic\" Geyer", + "\"SSNTails\"", "Johnny \"Sonikku\" Wallbank", "", "\1Programming", - "\"SSNTails\"", "Alam \"GBC\" Arias", "Logan \"GBA\" Arias", + "Tim \"RedEnchilada\" Bordelon", "Callum Dickinson", "Scott \"Graue\" Feeney", "Nathan \"Jazz\" Giroux", "Thomas \"Shadow Hog\" Igoe", "\"Monster\" Iestyn Jealous", + "Ronald \"Furyhunter\" Kinard", // The SDL2 port "John \"JTE\" Muniz", + "\"SSNTails\"", "Matthew \"Inuyasha\" Walsh", "", "\1Programming", "\1Assistance", - "Tim \"RedEnchilada\" Bordelon", "Andrew \"orospakr\" Clunis", "Gregor \"Oogaland\" Dick", "Julio \"Chaos Zero 64\" Guir", @@ -993,7 +994,6 @@ static const char *credits[] = { "Ben \"Cue\" Woodford", "", "\1Sprite Artists", - "\"SSNTails\"", "Odi \"Iceman404\" Atunzu", "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Jim \"MotorRoach\" DeMello", @@ -1001,6 +1001,7 @@ static const char *credits[] = { "Sherman \"CoatRack\" DesJardins", "Andrew \"Senku Niola\" Moran", "David \"Instant Sonic\" Spencer Jr.", + "\"SSNTails\"", "", "\1Texture Artists", "Ryan \"Blaze Hedgehog\" Bloom", @@ -1010,8 +1011,6 @@ static const char *credits[] = { "", "\1Music and Sound", "\1Production", - "\"SSNTails\"", - "Michael \"Spazzo\" Antonakes", "Malcolm \"RedXVI\" Brown", "David \"Bulmybag\" Bulmer", "Paul \"Boinciel\" Clempson", @@ -1021,12 +1020,12 @@ static const char *credits[] = { "Jarel \"Arrow\" Jones", "Stefan \"Stuf\" Rimalia", "Shane Strife", + "\"Spazzo\"", "David \"Big Wave Dave\" Spencer Sr.", "David \"Instant Sonic\" Spencer Jr.", + "\"SSNTails\"", "", "\1Level Design", - "\"SSNTails\"", - "Michael \"Spazzo\" Antonakes", "Matthew \"Fawfulfan\" Chapman", "Paul \"Boinciel\" Clempson", "Desmond \"Blade\" DesJardins", @@ -1038,12 +1037,22 @@ static const char *credits[] = { "Thomas \"Shadow Hog\" Igoe", "Erik \"Torgo\" Nielsen", "Wessel \"Spherallic\" Smit", + "\"Spazzo\"", + "\"SSNTails\"", "Rob Tisdell", "Jarrett \"JEV3\" Voight", "Johnny \"Sonikku\" Wallbank", "Matthew \"Inuyasha\" Walsh", "Marco \"Digiku\" Zafra", "", + "\1Boss Design", + "Ben \"Mystic\" Geyer", + "Thomas \"Shadow Hog\" Igoe", + "John \"JTE\" Muniz", + "Samuel \"Prime 2.0\" Peters", + "\"SSNTails\"", + "Johnny \"Sonikku\" Wallbank", + "", "\1Testing", "Hank \"FuriousFox\" Brannock", "Cody \"SRB2 Playah\" Koester", @@ -1060,9 +1069,12 @@ static const char *credits[] = { "Alex \"MistaED\" Fuller", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Randy Heit ()", // For his MSPaint sprite that we nicked -#if 0 // (don't take your anger out on me anymore, ok, JTE...?) - "Abigail \"Raspberry\" Fox", // (Inuyasha's girlfriend. >_> <_< >_>) -#endif + "", + "\1Produced By", + "Sonic Team Junior", + "", + "\1Published By", + "A 28K dialup modem", "", "\1Thank you", "\1for playing!", diff --git a/src/g_game.c b/src/g_game.c index 21112ca3..50f30dfc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -131,7 +131,6 @@ boolean countdowntimeup = false; cutscene_t *cutscenes[128]; INT16 nextmapoverride; -INT32 nextmapgametype; boolean skipstats; // Pointers to each CTF flag @@ -244,7 +243,6 @@ mobj_t *metalplayback; static UINT8 *metalbuffer = NULL; static UINT8 *metal_p; static UINT16 metalversion; -boolean metal_start; // extra data stuff (events registered this frame while recording) static struct { @@ -283,6 +281,8 @@ static void UserAnalog_OnChange(void); static void UserAnalog2_OnChange(void); static void Analog_OnChange(void); static void Analog2_OnChange(void); +void SendWeaponPref(void); +void SendWeaponPref2(void); static CV_PossibleValue_t crosshair_cons_t[] = {{0, "Off"}, {1, "Cross"}, {2, "Angle"}, {3, "Point"}, {0, NULL}}; static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"}, @@ -595,14 +595,18 @@ void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare) void G_SetNightsRecords(void) { INT32 i; + UINT32 totalscore = 0; + tic_t totaltime = 0; + + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath; + char lastdemo[256], bestdemo[256]; if (!ntemprecords.nummares) return; // Set overall { - UINT32 totalscore = 0; - tic_t totaltime = 0; UINT8 totalrank = 0, realrank = 0; for (i = 1; i <= ntemprecords.nummares; ++i) @@ -648,6 +652,50 @@ void G_SetNightsRecords(void) memset(&ntemprecords, 0, sizeof(nightsdata_t)); + // Save demo! + bestdemo[255] = '\0'; + lastdemo[255] = '\0'; + G_SetDemoTime(totaltime, totalscore, 0); + G_CheckDemoStatus(); + + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + + if ((gpath = malloc(glen)) == NULL) + I_Error("Out of memory for replay filepath\n"); + + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + snprintf(lastdemo, 255, "%s-last.lmp", gpath); + + if (FIL_FileExists(lastdemo)) + { + UINT8 *buf; + size_t len = FIL_ReadFile(lastdemo, &buf); + + snprintf(bestdemo, 255, "%s-time-best.lmp", gpath); + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) + { // Better time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + } + + snprintf(bestdemo, 255, "%s-score-best.lmp", gpath); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) + { // Better score, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); + } + + //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); + + Z_Free(buf); + } + free(gpath); + // If the mare count changed, this will update the score display CV_AddValue(&cv_nextmap, 1); CV_AddValue(&cv_nextmap, -1); @@ -909,6 +957,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // these ones used for multiple conditions boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove; player_t *player = &players[consoleplayer]; + camera_t *thiscam = &camera; static INT32 turnheld; // for accelerative turning static boolean keyboard_look; // true if lookup/down using keyboard @@ -1172,8 +1221,16 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) cmd->forwardmove = (SINT8)(cmd->forwardmove + forward); cmd->sidemove = (SINT8)(cmd->sidemove + side); - localangle += (cmd->angleturn<<16); - cmd->angleturn = (INT16)(localangle >> 16); + if (cv_analog.value) { + cmd->angleturn = (INT16)(thiscam->angle >> 16); + if (player->awayviewtics) + cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); + } + else + { + localangle += (cmd->angleturn<<16); + cmd->angleturn = (INT16)(localangle >> 16); + } //Reset away view if a command is given. if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) @@ -1190,6 +1247,7 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) // these ones used for multiple conditions boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove; player_t *player = &players[secondarydisplayplayer]; + camera_t *thiscam = (player->bot == 2 ? &camera : &camera2); static INT32 turnheld; // for accelerative turning static boolean keyboard_look; // true if lookup/down using keyboard @@ -1463,8 +1521,16 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) } } - localangle2 += (cmd->angleturn<<16); - cmd->angleturn = (INT16)(localangle2 >> 16); + if (cv_analog2.value) { + cmd->angleturn = (INT16)(thiscam->angle >> 16); + if (player->awayviewtics) + cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); + } + else + { + localangle2 += (cmd->angleturn<<16); + cmd->angleturn = (INT16)(localangle2 >> 16); + } } // User has designated that they want @@ -1497,25 +1563,45 @@ static void Analog_OnChange(void) if (leveltime > 1) CV_SetValue(&cv_cam_dist, 128); - if (netgame) - CV_StealthSetValue(&cv_analog, 0); - else if (cv_analog.value || demoplayback) + if (cv_analog.value || demoplayback) CV_SetValue(&cv_cam_dist, 192); + + if (!cv_chasecam.value && cv_analog.value) { + CV_SetValue(&cv_analog, 0); + return; + } + + if (cv_analog.value) + players[consoleplayer].pflags |= PF_ANALOGMODE; + else + players[consoleplayer].pflags &= ~PF_ANALOGMODE; + + SendWeaponPref(); } static void Analog2_OnChange(void) { - if (!splitscreen || !cv_cam2_dist.string) + if (!(splitscreen || botingame) || !cv_cam2_dist.string) return; // cameras are not initialized at this point if (leveltime > 1) CV_SetValue(&cv_cam2_dist, 128); - if (netgame) - CV_StealthSetValue(&cv_analog2, 0); - else if (cv_analog2.value) + if (cv_analog2.value) CV_SetValue(&cv_cam2_dist, 192); + + if (!cv_chasecam2.value && cv_analog2.value) { + CV_SetValue(&cv_analog2, 0); + return; + } + + if (cv_analog2.value) + players[secondarydisplayplayer].pflags |= PF_ANALOGMODE; + else + players[secondarydisplayplayer].pflags &= ~PF_ANALOGMODE; + + SendWeaponPref2(); } // @@ -1999,7 +2085,7 @@ void G_PlayerReborn(INT32 player) exiting = players[player].exiting; jointime = players[player].jointime; spectator = players[player].spectator; - pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED)); + pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_ANALOGMODE)); // As long as we're not in multiplayer, carry over cheatcodes from map to map if (!(netgame || multiplayer)) @@ -2838,23 +2924,12 @@ static void G_DoWorldDone(void) { if (server) { - INT32 nextgametype; - - // for custom exit (linetype 2) that changes gametype - if (nextmapgametype != -1) - nextgametype = nextmapgametype; - else - { - // use current gametype by default - nextgametype = gametype; - } - - if (gametype == GT_COOP && nextgametype == GT_COOP) + if (gametype == GT_COOP) // don't reset player between maps - D_MapChange(nextmap+1, nextgametype, ultimatemode, false, 0, false, false); + D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false); else // resetplayer in match/chaos/tag/CTF/race for more equality - D_MapChange(nextmap+1, nextgametype, ultimatemode, true, 0, false, false); + D_MapChange(nextmap+1, gametype, ultimatemode, true, 0, false, false); } gameaction = ga_nothing; @@ -3618,6 +3693,7 @@ static ticcmd_t oldcmd; // Not used for Metal Sonic #define GZT_SPRITE 0x10 // Animation frame #define GZT_EXTRA 0x20 +#define GZT_NIGHTS 0x40 // NiGHTS Mode stuff! // GZT_EXTRA flags #define EZT_THOK 0x01 // Spawned a thok object @@ -3632,6 +3708,21 @@ static ticcmd_t oldcmd; static mobj_t oldmetal, oldghost; +void G_SaveMetal(UINT8 **buffer) +{ + I_Assert(buffer != NULL && *buffer != NULL); + + WRITEUINT32(*buffer, metal_p - metalbuffer); +} + +void G_LoadMetal(UINT8 **buffer) +{ + I_Assert(buffer != NULL && *buffer != NULL); + + G_DoPlayMetal(); + metal_p = metalbuffer + READUINT32(*buffer); +} + ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) { return M_Memcpy(dest, src, n*sizeof(*src)); @@ -3814,6 +3905,13 @@ void G_WriteGhostTic(mobj_t *ghost) if (!(demoflags & DF_GHOST)) return; // No ghost data to write. + if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer) + { + // We're talking about the NiGHTS thing, not the normal platforming thing! + ziptic |= GZT_NIGHTS; + ghost = ghost->tracer; + } + ziptic_p = demo_p++; // the ziptic, written at the end of this function #define MAXMOM (0xFFFF<<8) @@ -3875,10 +3973,7 @@ void G_WriteGhostTic(mobj_t *ghost) } // Store the sprite frame. - if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer) - frame = ghost->tracer->frame & 0xFF; // get frame from NiGHTS tracer - else - frame = ghost->frame & 0xFF; // get frame from player + frame = ghost->frame & 0xFF; if (frame != oldghost.frame) { oldghost.frame = frame; @@ -3887,10 +3982,7 @@ void G_WriteGhostTic(mobj_t *ghost) } // Check for sprite set changes - if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer) - sprite = ghost->tracer->sprite; // get sprite from NiGHTS tracer - else - sprite = ghost->sprite; // get sprite from player + sprite = ghost->sprite; if (sprite != oldghost.sprite) { oldghost.sprite = sprite; @@ -3957,12 +4049,16 @@ void G_ConsGhostTic(void) { UINT8 ziptic; UINT16 px,py,pz,gx,gy,gz; + mobj_t *testmo; + boolean nightsfail = false; if (!demo_p || !demo_start) return; if (!(demoflags & DF_GHOST)) return; // No ghost data to use. + testmo = players[0].mo; + // Grab ghost data. ziptic = READUINT8(demo_p); if (ziptic & GZT_XYZ) @@ -3988,6 +4084,12 @@ void G_ConsGhostTic(void) demo_p++; if (ziptic & GZT_SPRITE) demo_p++; + if(ziptic & GZT_NIGHTS) { + if (!testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer) + nightsfail = true; + else + testmo = testmo->tracer; + } if (ziptic & GZT_EXTRA) { // But wait, there's more! @@ -4029,7 +4131,12 @@ void G_ConsGhostTic(void) mobj = NULL; // wasn't this one, keep searching. } if (mobj && mobj->health != health) // Wasn't damaged?! This is desync! Fix it! + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); + demosynced = false; P_DamageMobj(mobj, players[0].mo, players[0].mo, 1); + } } } if (ziptic & EZT_SPRITE) @@ -4037,24 +4144,24 @@ void G_ConsGhostTic(void) } // Re-synchronise - px = players[0].mo->x>>FRACBITS; - py = players[0].mo->y>>FRACBITS; - pz = players[0].mo->z>>FRACBITS; + px = testmo->x>>FRACBITS; + py = testmo->y>>FRACBITS; + pz = testmo->z>>FRACBITS; gx = oldghost.x>>FRACBITS; gy = oldghost.y>>FRACBITS; gz = oldghost.z>>FRACBITS; - if (px != gx || py != gy || pz != gz) + if (nightsfail || px != gx || py != gy || pz != gz) { if (demosynced) CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); demosynced = false; - P_UnsetThingPosition(players[0].mo); - players[0].mo->x = oldghost.x; - players[0].mo->y = oldghost.y; - P_SetThingPosition(players[0].mo); - players[0].mo->z = oldghost.z; + P_UnsetThingPosition(testmo); + testmo->x = oldghost.x; + testmo->y = oldghost.y; + P_SetThingPosition(testmo); + testmo->z = oldghost.z; } if (*demo_p == DEMOMARKER) @@ -4272,7 +4379,7 @@ void G_ReadMetalTic(mobj_t *metal) UINT16 speed; UINT8 statetype; - if (!metal_p || !metal_start) + if (!metal_p) return; ziptic = READUINT8(metal_p); @@ -4517,11 +4624,7 @@ void G_BeginRecording(void) memset(name,0,sizeof(name)); demo_p = demobuffer; - demoflags = DF_GHOST; - if (modeattacking == ATTACKING_RECORD) - demoflags |= DF_RECORDATTACK; - else if (modeattacking == ATTACKING_NIGHTS) - demoflags |= DF_NIGHTSATTACK; + demoflags = DF_GHOST|(modeattacking<frontsector->floorheight); + if (cullheight->flags & ML_NOCLIMB) // Group culling + { + if (!viewcullheight) + return false; + + // Make sure this is part of the same group + if (viewcullheight->frontsector == cullheight->frontsector) + { + // OK, we can cull + if (vz > cullplane && toph < cullplane) // Cull if below plane + return true; + + if (bottomh > cullplane && vz <= cullplane) // Cull if above plane + return true; + } + } + else // Quick culling + { + if (vz > cullplane && toph < cullplane) // Cull if below plane + return true; + + if (bottomh > cullplane && vz <= cullplane) // Cull if above plane + return true; + } + + return false; +} + // -----------------+ // HWR_DrawSprite : Draw flat sprites // : (monsters, bonuses, weapons, lights, ...) @@ -4607,29 +4647,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->cullheight) { - float cullplane = FIXED_TO_FLOAT(thing->subsector->sector->cullheight->frontsector->floorheight); - if (thing->subsector->sector->cullheight->flags & ML_NOCLIMB) // Group culling - { - // Make sure this is part of the same group - if (viewsector->cullheight && viewsector->cullheight->frontsector - == thing->subsector->sector->cullheight->frontsector) - { - // OK, we can cull - if (gr_viewz > cullplane && gzt < cullplane) // Cull if below plane - return; - - if (gz > cullplane && gr_viewz <= cullplane) // Cull if above plane - return; - } - } - else // Quick culling - { - if (gr_viewz > cullplane && gzt < cullplane) // Cull if below plane - return; - - if (gz > cullplane && gr_viewz <= cullplane) // Cull if above plane - return; - } + if (HWR_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, gr_viewz, gz, gzt)) + return; } heightsec = thing->subsector->sector->heightsec; @@ -4795,6 +4814,8 @@ static void HWR_DrawSkyBackground(player_t *player) FOutVector v[4]; angle_t angle; float dimensionmultiply; + float aspectratio; + float angleturn; // 3--2 // | /| @@ -4830,9 +4851,9 @@ static void HWR_DrawSkyBackground(player_t *player) // Y angle = aimingangle; - float aspectratio = (float)vid.width/(float)vid.height; + aspectratio = (float)vid.width/(float)vid.height; dimensionmultiply = ((float)textures[skytexture]->height/(128.0f*aspectratio)); - float angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; + angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply; // Middle of the sky should always be at angle 0 // need to keep correct aspect ratio with X diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 0f0f7e01..631bb665 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -399,10 +399,10 @@ static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; #ifndef MINI_GL_COMPATIBILITY /* 1.3 functions for multitexturing */ -typedef void (APIENTRY *PFNGLACTIVETEXTUREPROC) (GLenum); -static PFNGLACTIVETEXTUREPROC pglActiveTexture; -typedef void (APIENTRY *PFNGLMULTITEXCOORD2FPROC) (GLenum, GLfloat, GLfloat); -static PFNGLMULTITEXCOORD2FPROC pglMultiTexCoord2f; +typedef void (APIENTRY *PFNglActiveTexture) (GLenum); +static PFNglActiveTexture pglActiveTexture; +typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); +static PFNglMultiTexCoord2f pglMultiTexCoord2f; #endif #endif @@ -526,21 +526,18 @@ boolean SetupGLFunc13(void) #ifdef STATIC_OPENGL gl13 = true; #else - const char *glversion = (const char *)pglGetString(GL_VERSION); - UINT32 majorversion = 0, minorversion = 0; - - if (glversion != NULL && sscanf(glversion, "%u.%u", &majorversion, &minorversion) == 2) // There is a version number I can identify + if (isExtAvailable("GL_ARB_multitexture", gl_extensions)) { - if (majorversion > 1 || (majorversion == 1 && minorversion >= 3)) // Version of OpenGL is equal to or greater than 1.3 - { - // Get the functions - pglActiveTexture = GetGLFunc("glActiveTexture"); - pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2f"); + // Get the functions + pglActiveTexture = GetGLFunc("glActiveTextureARB"); + pglMultiTexCoord2f = GetGLFunc("glMultiTexCoord2fARB"); + + gl13 = true; // This is now true, so the new fade mask stuff can be done, if OpenGL version is less than 1.3, it still uses the old fade stuff. + DBG_Printf("GL_ARB_multitexture support: enabled\n"); - if (pglMultiTexCoord2f) - gl13 = true; // This is now true, so the new fade mask stuff can be done, if OpenGL version is less than 1.3, it still uses the old fade stuff. - } } + else + DBG_Printf("GL_ARB_multitexture support: disabled\n"); #undef GETOPENGLFUNC #endif diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a6c6dbe0..80e30beb 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1028,20 +1028,26 @@ UINT16 hu_demorings; static void HU_DrawDemoInfo(void) { V_DrawString(4, 188-24, V_YELLOWMAP, va(M_GetText("%s's replay"), player_names[0])); - V_DrawString(4, 188-16, V_YELLOWMAP|V_MONOSPACE, "SCORE:"); - V_DrawRightAlignedString(120, 188-16, V_MONOSPACE, va("%d", hu_demoscore)); + if (modeattacking) + { + V_DrawString(4, 188-16, V_YELLOWMAP|V_MONOSPACE, "SCORE:"); + V_DrawRightAlignedString(120, 188-16, V_MONOSPACE, va("%d", hu_demoscore)); - V_DrawString(4, 188- 8, V_YELLOWMAP|V_MONOSPACE, "TIME:"); - if (hu_demotime != UINT32_MAX) - V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, va("%i:%02i.%02i", - G_TicsToMinutes(hu_demotime,true), - G_TicsToSeconds(hu_demotime), - G_TicsToCentiseconds(hu_demotime))); - else - V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, "--:--.--"); + V_DrawString(4, 188- 8, V_YELLOWMAP|V_MONOSPACE, "TIME:"); + if (hu_demotime != UINT32_MAX) + V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, va("%i:%02i.%02i", + G_TicsToMinutes(hu_demotime,true), + G_TicsToSeconds(hu_demotime), + G_TicsToCentiseconds(hu_demotime))); + else + V_DrawRightAlignedString(120, 188- 8, V_MONOSPACE, "--:--.--"); - V_DrawString(4, 188 , V_YELLOWMAP|V_MONOSPACE, "RINGS:"); - V_DrawRightAlignedString(120, 188 , V_MONOSPACE, va("%d", hu_demorings)); + if (modeattacking == ATTACKING_RECORD) + { + V_DrawString(4, 188 , V_YELLOWMAP|V_MONOSPACE, "RINGS:"); + V_DrawRightAlignedString(120, 188 , V_MONOSPACE, va("%d", hu_demorings)); + } + } } // Heads up displays drawer, call each frame diff --git a/src/info.c b/src/info.c index a15646f0..c8f754b5 100644 --- a/src/info.c +++ b/src/info.c @@ -570,7 +570,7 @@ state_t states[NUMSTATES] = {SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE14}, // S_EGGMOBILE3_DIE13 {SPR_EGGO, 9, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE3_DIE14 {SPR_EGGO, 10, 5, {NULL}, 0, 0, S_EGGMOBILE3_FLEE2}, // S_EGGMOBILE3_FLEE1 - {SPR_EGGO, 11, 5, {A_BossScream}, 0, 0, S_EGGMOBILE3_FLEE1}, // S_EGGMOBILE3_FLEE2 + {SPR_EGGO, 11, 5, {NULL}, 0, 0, S_EGGMOBILE3_FLEE1}, // S_EGGMOBILE3_FLEE2 // Boss 3 Propeller {SPR_PRPL, 0, 1, {NULL}, 0, 0, S_PROPELLER2}, // S_PROPELLER1 @@ -3349,7 +3349,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // seesound 2*TICRATE, // reactiontime sfx_None, // attacksound - S_CCOMMAND1, // painstate + S_CCOMMAND3, // painstate 200, // painchance sfx_dmpain, // painsound S_NULL, // meleestate @@ -13452,7 +13452,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13479,7 +13479,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13506,7 +13506,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13533,7 +13533,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13560,7 +13560,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13587,7 +13587,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13614,7 +13614,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13641,7 +13641,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13668,7 +13668,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13695,7 +13695,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13722,7 +13722,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13749,7 +13749,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13776,7 +13776,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13803,7 +13803,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13830,7 +13830,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -13857,7 +13857,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6124b349..ad5d740f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1744,7 +1744,26 @@ static int lib_gDoReborn(lua_State *L) static int lib_gExitLevel(lua_State *L) { + int n = lua_gettop(L); // Num arguments NOHUD + + // LUA EXTENSION: Custom exit like support + // Supported: + // G_ExitLevel(); [no modifications] + // G_ExitLevel(int) [nextmap override only] + // G_ExitLevel(bool) [skipstats only] + // G_ExitLevel(int, bool) [both of the above] + if (n >= 1) + { + if (lua_isnumber(L, 1) || n >= 2) + { + nextmapoverride = (INT16)luaL_checknumber(L, 1); + lua_pop(L, 1); // pop nextmapoverride; skipstats now 1 if available + } + skipstats = lua_optboolean(L, 1); + } + // --- + G_ExitLevel(); return 0; } diff --git a/src/lua_hook.h b/src/lua_hook.h index 85d00533..fae3bb7e 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -71,7 +71,7 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source); // Ho #define LUAh_JumpSpinSpecial(player) LUAh_PlayerHook(player, hook_JumpSpinSpecial) // Hook for P_DoJumpStuff (Spin button effect (mid-air)) boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name -boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo); // Hook for linedef executors +boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 4e9328e1..532726ac 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -873,7 +873,7 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) } // Hook for linedef executors -boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo) +boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) return false; @@ -898,7 +898,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo) LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_Call(gL, 2); // pops hook function, line, mo + LUA_PushUserdata(gL, sector, META_SECTOR); + LUA_Call(gL, 3); // pops hook function, line, mo, sector lua_pop(gL, -1); lua_gc(gL, LUA_GCSTEP, 1); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 6800a2f9..19390d50 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -13,6 +13,7 @@ #include "doomdef.h" #ifdef HAVE_BLUA #include "r_defs.h" +#include "r_local.h" #include "st_stuff.h" // hudinfo[] #include "g_game.h" #include "p_local.h" // camera_t @@ -222,6 +223,11 @@ static int hudinfo_num(lua_State *L) return 1; } +static int colormap_get(lua_State *L) +{ + return luaL_error(L, "colormap is not a struct."); +} + static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); @@ -352,7 +358,7 @@ static int libd_draw(lua_State *L) patch = *((patch_t **)luaL_checkudata(L, 3, META_PATCH)); flags = luaL_optinteger(L, 4, 0); if (!lua_isnoneornil(L, 5)) - colormap = luaL_checkudata(L, 5, META_COLORMAP); + colormap = *((UINT8 **)luaL_checkudata(L, 5, META_COLORMAP)); flags &= ~V_PARAMMASK; // Don't let crashes happen. @@ -374,7 +380,7 @@ static int libd_drawScaled(lua_State *L) patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); flags = luaL_optinteger(L, 5, 0); if (!lua_isnoneornil(L, 6)) - colormap = luaL_checkudata(L, 6, META_COLORMAP); + colormap = *((UINT8 **)luaL_checkudata(L, 6, META_COLORMAP)); flags &= ~V_PARAMMASK; // Don't let crashes happen. @@ -490,6 +496,35 @@ static int libd_stringWidth(lua_State *L) return 1; } +static int libd_getColormap(lua_State *L) +{ + INT32 skinnum = TC_DEFAULT; + skincolors_t color = luaL_optinteger(L, 2, 0); + UINT8* colormap = NULL; + //HUDSAFE + if (lua_isnoneornil(L, 1)) + ; // defaults to TC_DEFAULT + else if (lua_type(L, 1) == LUA_TNUMBER) // skin number + { + skinnum = (INT32)luaL_checkinteger(L, 1); + if (skinnum < TC_ALLWHITE || skinnum >= MAXSKINS) + return luaL_error(L, "argument #1 is out of range"); + } + else // skin name + { + const char *skinname = luaL_checkstring(L, 1); + INT32 i = R_SkinAvailable(skinname); + if (i != -1) // if -1, just default to TC_DEFAULT as above + skinnum = i; + } + + // all was successful above, now we generate the colormap at last! + + colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); + LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! + return 1; +} + static luaL_Reg lib_draw[] = { {"patchExists", libd_patchExists}, {"cachePatch", libd_cachePatch}, @@ -500,6 +535,7 @@ static luaL_Reg lib_draw[] = { {"drawFill", libd_drawFill}, {"drawString", libd_drawString}, {"stringWidth", libd_stringWidth}, + {"getColormap", libd_getColormap}, {NULL, NULL} }; @@ -592,6 +628,11 @@ int LUA_HudLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "hudinfo"); + luaL_newmetatable(L, META_COLORMAP); + lua_pushcfunction(L, colormap_get); + lua_setfield(L, -2, "__index"); + lua_pop(L,1); + luaL_newmetatable(L, META_PATCH); lua_pushcfunction(L, patch_get); lua_setfield(L, -2, "__index"); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 3209fc53..80f66ed6 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -89,7 +89,8 @@ enum line_e { line_validcount, line_firsttag, line_nexttag, - line_text + line_text, + line_callcount }; static const char *const line_opt[] = { @@ -111,6 +112,7 @@ static const char *const line_opt[] = { "firsttag", "nexttag", "text", + "callcount", NULL}; enum side_e { @@ -574,6 +576,9 @@ static int line_get(lua_State *L) case line_text: lua_pushstring(L, line->text); return 1; + case line_callcount: + lua_pushinteger(L, line->callcount); + return 1; } return 0; } @@ -1033,7 +1038,7 @@ static int ffloor_set(lua_State *L) boolean flag; fixed_t lastpos = *ffloor->topheight; sector_t *sector = §ors[ffloor->secnum]; - sector->floorheight = (fixed_t)luaL_checkinteger(L, 3); + sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { @@ -1052,7 +1057,7 @@ static int ffloor_set(lua_State *L) boolean flag; fixed_t lastpos = *ffloor->bottomheight; sector_t *sector = §ors[ffloor->secnum]; - sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3); + sector->floorheight = (fixed_t)luaL_checkinteger(L, 3); flag = P_CheckSector(sector, true); if (flag && sector->numattached) { diff --git a/src/m_menu.c b/src/m_menu.c index 830b2644..b8be38e8 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -250,7 +250,8 @@ static void M_ModeAttackEndGame(INT32 choice); static void M_SetGuestReplay(INT32 choice); static void M_ChoosePlayer(INT32 choice); menu_t SP_GameStatsDef, SP_LevelStatsDef; -static menu_t SP_TimeAttackDef, SP_NightsAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; +static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; +static menu_t SP_NightsAttackDef, SP_NightsReplayDef, SP_NightsGuestReplayDef, SP_NightsGhostDef; // Multiplayer #ifndef NONET @@ -733,6 +734,17 @@ static menuitem_t SP_ReplayMenu[] = {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 50} }; +static menuitem_t SP_NightsReplayMenu[] = +{ + {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Score", M_ReplayTimeAttack, 8}, + {IT_WHITESTRING|IT_CALL, NULL, "Replay Best Time", M_ReplayTimeAttack,16}, + + {IT_WHITESTRING|IT_CALL, NULL, "Replay Last", M_ReplayTimeAttack,29}, + {IT_WHITESTRING|IT_CALL, NULL, "Replay Guest", M_ReplayTimeAttack,37}, + + {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} +}; + static menuitem_t SP_GuestReplayMenu[] = { {IT_WHITESTRING|IT_CALL, NULL, "Save Best Score as Guest", M_SetGuestReplay, 0}, @@ -745,6 +757,17 @@ static menuitem_t SP_GuestReplayMenu[] = {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 50} }; +static menuitem_t SP_NightsGuestReplayMenu[] = +{ + {IT_WHITESTRING|IT_CALL, NULL, "Save Best Score as Guest", M_SetGuestReplay, 8}, + {IT_WHITESTRING|IT_CALL, NULL, "Save Best Time as Guest", M_SetGuestReplay,16}, + {IT_WHITESTRING|IT_CALL, NULL, "Save Last as Guest", M_SetGuestReplay,24}, + + {IT_WHITESTRING|IT_CALL, NULL, "Delete Guest Replay", M_SetGuestReplay,37}, + + {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} +}; + static menuitem_t SP_GhostMenu[] = { {IT_STRING|IT_CVAR, NULL, "Best Score", &cv_ghost_bestscore, 0}, @@ -757,18 +780,37 @@ static menuitem_t SP_GhostMenu[] = {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_TimeAttackDef, 50} }; +static menuitem_t SP_NightsGhostMenu[] = +{ + {IT_STRING|IT_CVAR, NULL, "Best Score", &cv_ghost_bestscore, 8}, + {IT_STRING|IT_CVAR, NULL, "Best Time", &cv_ghost_besttime, 16}, + {IT_STRING|IT_CVAR, NULL, "Last", &cv_ghost_last, 24}, + + {IT_STRING|IT_CVAR, NULL, "Guest", &cv_ghost_guest, 37}, + + {IT_WHITESTRING|IT_SUBMENU, NULL, "Back", &SP_NightsAttackDef, 50} +}; + // Single Player Nights Attack static menuitem_t SP_NightsAttackMenu[] = { {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 44}, - {IT_STRING|IT_CVAR, NULL, "Show Records For", &cv_dummymares, 60}, - {IT_WHITESTRING|IT_CALL, NULL, "Start", M_ChooseNightsAttack, 130}, + {IT_STRING|IT_CVAR, NULL, "Show Records For", &cv_dummymares, 54}, + + {IT_DISABLED, NULL, "Guest Option...", &SP_NightsGuestReplayDef, 108}, + {IT_DISABLED, NULL, "Replay...", &SP_NightsReplayDef, 118}, + {IT_DISABLED, NULL, "Ghosts...", &SP_NightsGhostDef, 128}, + {IT_WHITESTRING|IT_CALL, NULL, "Start", M_ChooseNightsAttack, 138}, }; enum { nalevel, narecords, + + naguest, + nareplay, + naghost, nastart }; @@ -1515,6 +1557,40 @@ static menu_t SP_NightsAttackDef = 0, NULL }; +static menu_t SP_NightsReplayDef = +{ + "M_NIGHTS", + sizeof(SP_NightsReplayMenu)/sizeof(menuitem_t), + &SP_NightsAttackDef, + SP_NightsReplayMenu, + M_DrawNightsAttackMenu, + 32, 120, + 0, + NULL +}; +static menu_t SP_NightsGuestReplayDef = +{ + "M_NIGHTS", + sizeof(SP_NightsGuestReplayMenu)/sizeof(menuitem_t), + &SP_NightsAttackDef, + SP_NightsGuestReplayMenu, + M_DrawNightsAttackMenu, + 32, 120, + 0, + NULL +}; +static menu_t SP_NightsGhostDef = +{ + "M_NIGHTS", + sizeof(SP_NightsGhostMenu)/sizeof(menuitem_t), + &SP_NightsAttackDef, + SP_NightsGhostMenu, + M_DrawNightsAttackMenu, + 32, 120, + 0, + NULL +}; + menu_t SP_PlayerDef = { @@ -1682,7 +1758,7 @@ static void Nextmap_OnChange(void) char *leveltitle; char tabase[256]; short i; - boolean active = false; + boolean active; // Update the string in the consvar. Z_Free(cv_nextmap.zstring); @@ -1697,9 +1773,53 @@ static void Nextmap_OnChange(void) SP_NightsAttackMenu[narecords].status = IT_DISABLED; else SP_NightsAttackMenu[narecords].status = IT_STRING|IT_CVAR; + + // Do the replay things. + active = false; + SP_NightsAttackMenu[naguest].status = IT_DISABLED; + SP_NightsAttackMenu[nareplay].status = IT_DISABLED; + SP_NightsAttackMenu[naghost].status = IT_DISABLED; + + // Check if file exists, if not, disable REPLAY option + sprintf(tabase,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s",srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); + for (i = 0; i < 4; i++) { + SP_NightsReplayMenu[i].status = IT_DISABLED; + SP_NightsGuestReplayMenu[i].status = IT_DISABLED; + } + if (FIL_FileExists(va("%s-score-best.lmp", tabase))) { + SP_NightsReplayMenu[0].status = IT_WHITESTRING|IT_CALL; + SP_NightsGuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL; + active = true; + } + if (FIL_FileExists(va("%s-time-best.lmp", tabase))) { + SP_NightsReplayMenu[1].status = IT_WHITESTRING|IT_CALL; + SP_NightsGuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL; + active = true; + } + if (FIL_FileExists(va("%s-last.lmp", tabase))) { + SP_NightsReplayMenu[2].status = IT_WHITESTRING|IT_CALL; + SP_NightsGuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL; + active = true; + } + if (FIL_FileExists(va("%s-guest.lmp", tabase))) { + SP_NightsReplayMenu[3].status = IT_WHITESTRING|IT_CALL; + SP_NightsGuestReplayMenu[3].status = IT_WHITESTRING|IT_CALL; + active = true; + } + if (active) { + SP_NightsAttackMenu[naguest].status = IT_WHITESTRING|IT_SUBMENU; + SP_NightsAttackMenu[nareplay].status = IT_WHITESTRING|IT_SUBMENU; + SP_NightsAttackMenu[naghost].status = IT_WHITESTRING|IT_SUBMENU; + } + else if(itemOn == nareplay) // Reset lastOn so replay isn't still selected when not available. + { + currentMenu->lastOn = itemOn; + itemOn = nastart; + } } else if (currentMenu == &SP_TimeAttackDef) { + active = false; SP_TimeAttackMenu[taguest].status = IT_DISABLED; SP_TimeAttackMenu[tareplay].status = IT_DISABLED; SP_TimeAttackMenu[taghost].status = IT_DISABLED; @@ -5287,54 +5407,69 @@ void M_DrawNightsAttackMenu(void) if (P_HasGrades(cv_nextmap.value, 0)) V_DrawScaledPatch(200, 28 + 8, 0, ngradeletters[bestoverall]); - if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) + if (currentMenu == &SP_NightsAttackDef) { - V_DrawString(160-88, 130, V_YELLOWMAP, "BEST GRADE:"); - V_DrawSmallScaledPatch(160 + 86 - (ngradeletters[bestgrade]->width/2), - 130 + 8 - (ngradeletters[bestgrade]->height/2), - 0, ngradeletters[bestgrade]); - } - - if (!bestscore) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%u", bestscore); - - V_DrawString(160 - 88, 140, V_YELLOWMAP, "BEST SCORE:"); - V_DrawRightAlignedString(160 + 88, 140, V_ALLOWLOWERCASE, beststr); - - if (besttime == UINT32_MAX) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(besttime, true), - G_TicsToSeconds(besttime), - G_TicsToCentiseconds(besttime)); - - V_DrawString(160-88, 150, V_YELLOWMAP, "BEST TIME:"); - V_DrawRightAlignedString(160+88, 150, V_ALLOWLOWERCASE, beststr); - - if (cv_dummymares.value == 0) { - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) + if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) { - switch (em->type) - { - case ET_NGRADE: yHeight = 130; break; - case ET_NTIME: yHeight = 150; break; - default: - goto skipThisOne; - } - - if (em->collected) - V_DrawSmallMappedPatch(160+88, yHeight, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); - else - V_DrawSmallScaledPatch(160+88, yHeight, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); + V_DrawString(160-88, 112, V_YELLOWMAP, "BEST GRADE:"); + V_DrawSmallScaledPatch(160 + 86 - (ngradeletters[bestgrade]->width/2), + 112 + 8 - (ngradeletters[bestgrade]->height/2), + 0, ngradeletters[bestgrade]); } + + if (!bestscore) + sprintf(beststr, "(none)"); + else + sprintf(beststr, "%u", bestscore); + + V_DrawString(160 - 88, 122, V_YELLOWMAP, "BEST SCORE:"); + V_DrawRightAlignedString(160 + 88, 122, V_ALLOWLOWERCASE, beststr); + + if (besttime == UINT32_MAX) + sprintf(beststr, "(none)"); + else + sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(besttime, true), + G_TicsToSeconds(besttime), + G_TicsToCentiseconds(besttime)); + + V_DrawString(160-88, 132, V_YELLOWMAP, "BEST TIME:"); + V_DrawRightAlignedString(160+88, 132, V_ALLOWLOWERCASE, beststr); + + if (cv_dummymares.value == 0) { + // Draw record emblems. + em = M_GetLevelEmblems(cv_nextmap.value); + while (em) + { + switch (em->type) + { + case ET_NGRADE: yHeight = 112; break; + case ET_NTIME: yHeight = 132; break; + default: + goto skipThisOne; + } + + if (em->collected) + V_DrawSmallMappedPatch(160+88, yHeight, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); + else + V_DrawSmallScaledPatch(160+88, yHeight, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + + skipThisOne: + em = M_GetLevelEmblems(-1); + } + } + } + // ALWAYS DRAW level name even when not on this menu! + else + { + consvar_t *ncv; + INT32 x = SP_NightsAttackDef.x; + INT32 y = SP_NightsAttackDef.y; + + ncv = (consvar_t *)SP_NightsAttackMenu[0].itemaction; + V_DrawString(x, y + SP_NightsAttackMenu[0].alphaKey, V_TRANSLUCENT, SP_NightsAttackMenu[0].text); + V_DrawString(BASEVIDWIDTH - x - V_StringWidth(ncv->string, 0), + y + SP_NightsAttackMenu[0].alphaKey, V_YELLOWMAP|V_TRANSLUCENT, ncv->string); } } } @@ -5368,16 +5503,25 @@ static void M_NightsAttack(INT32 choice) } // Player has selected the "START" from the nights attack screen -// (no demo recording yet) static void M_ChooseNightsAttack(INT32 choice) { + char nameofdemo[256]; (void)choice; emeralds = 0; M_ClearMenus(true); modeattacking = ATTACKING_NIGHTS; - // Demos and NiGHTS don't play well together - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), false, false); + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + + snprintf(nameofdemo, sizeof nameofdemo, "replay"PATHSEP"%s"PATHSEP"%s-last", timeattackfolder, G_BuildMapName(cv_nextmap.value)); + + if (!cv_autorecord.value) + remove(va("%s"PATHSEP"%s.lmp", srb2home, nameofdemo)); + else + G_RecordDemo(nameofdemo); + + G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, false, false); } // Player has selected the "START" from the time attack screen @@ -5415,28 +5559,50 @@ static void M_ReplayTimeAttack(INT32 choice) M_ClearMenus(true); modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows - switch(choice) { - default: - case 0: // best score - which = "score-best"; - break; - case 1: // best time - which = "time-best"; - break; - case 2: // best rings - which = "rings-best"; - break; - case 3: // last - which = "last"; - break; - case 4: // guest - // srb2/replay/main/map01-guest.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); - return; + if (currentMenu == &SP_ReplayDef) + { + switch(choice) { + default: + case 0: // best score + which = "score-best"; + break; + case 1: // best time + which = "time-best"; + break; + case 2: // best rings + which = "rings-best"; + break; + case 3: // last + which = "last"; + break; + case 4: // guest + // srb2/replay/main/map01-guest.lmp + G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); + return; + } + // srb2/replay/main/map01-sonic-time-best.lmp + G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); + } + else if (currentMenu == &SP_NightsReplayDef) + { + switch(choice) { + default: + case 0: // best score + which = "score-best"; + break; + case 1: // best time + which = "time-best"; + break; + case 2: // last + which = "last"; + break; + case 3: // guest + which = "guest"; + break; + } + // srb2/replay/main/map01-score-best.lmp + G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); } - - // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); } static void M_EraseGuest(INT32 choice) @@ -5445,17 +5611,24 @@ static void M_EraseGuest(INT32 choice) (void)choice; if (FIL_FileExists(rguest)) remove(rguest); - M_SetupNextMenu(&SP_TimeAttackDef); + if (currentMenu == &SP_NightsGuestReplayDef) + M_SetupNextMenu(&SP_NightsAttackDef); + else + M_SetupNextMenu(&SP_TimeAttackDef); CV_AddValue(&cv_nextmap, -1); CV_AddValue(&cv_nextmap, 1); M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING); } -static void M_OverwriteGuest(const char *which) +static void M_OverwriteGuest(const char *which, boolean nights) { char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); UINT8 *buf; - size_t len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); + size_t len; + if (!nights) + len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); + else + len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which), &buf); if (!len) { return; } @@ -5465,7 +5638,10 @@ static void M_OverwriteGuest(const char *which) } FIL_WriteFile(rguest, buf, len); Z_Free(rguest); - M_SetupNextMenu(&SP_TimeAttackDef); + if (currentMenu == &SP_NightsGuestReplayDef) + M_SetupNextMenu(&SP_NightsAttackDef); + else + M_SetupNextMenu(&SP_TimeAttackDef); CV_AddValue(&cv_nextmap, -1); CV_AddValue(&cv_nextmap, 1); M_StartMessage(M_GetText("Guest replay data saved.\n"),NULL,MM_NOTHING); @@ -5474,30 +5650,32 @@ static void M_OverwriteGuest(const char *which) static void M_OverwriteGuest_Time(INT32 choice) { (void)choice; - M_OverwriteGuest("time-best"); + M_OverwriteGuest("time-best", currentMenu == &SP_NightsGuestReplayDef); } static void M_OverwriteGuest_Score(INT32 choice) { (void)choice; - M_OverwriteGuest("score-best"); + M_OverwriteGuest("score-best", currentMenu == &SP_NightsGuestReplayDef); } static void M_OverwriteGuest_Rings(INT32 choice) { (void)choice; - M_OverwriteGuest("rings-best"); + M_OverwriteGuest("rings-best", false); } static void M_OverwriteGuest_Last(INT32 choice) { (void)choice; - M_OverwriteGuest("last"); + M_OverwriteGuest("last", currentMenu == &SP_NightsGuestReplayDef); } static void M_SetGuestReplay(INT32 choice) { void (*which)(INT32); + if (currentMenu == &SP_NightsGuestReplayDef && choice >= 2) + choice++; // skip best rings switch(choice) { case 0: // best score @@ -5526,51 +5704,39 @@ static void M_SetGuestReplay(INT32 choice) static void M_ModeAttackRetry(INT32 choice) { (void)choice; - if (modeattacking == ATTACKING_RECORD) // Cancel recording - { - G_CheckDemoStatus(); + G_CheckDemoStatus(); // Cancel recording + if (modeattacking == ATTACKING_RECORD) M_ChooseTimeAttack(0); - } else if (modeattacking == ATTACKING_NIGHTS) - { - // No demos to cancel M_ChooseNightsAttack(0); - } } static void M_ModeAttackEndGame(INT32 choice) { (void)choice; - if (modeattacking == ATTACKING_RECORD) // Cancel recording + G_CheckDemoStatus(); // Cancel recording + + if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) + Command_ExitGame_f(); + + M_StartControlPanel(); + switch(modeattacking) { - G_CheckDemoStatus(); - - if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) - Command_ExitGame_f(); - - M_StartControlPanel(); + default: + case ATTACKING_RECORD: currentMenu = &SP_TimeAttackDef; - itemOn = currentMenu->lastOn; - modeattacking = ATTACKING_NONE; - G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusic(mus_racent, true); - // Update replay availability. - CV_AddValue(&cv_nextmap, 1); - CV_AddValue(&cv_nextmap, -1); - } - else if (modeattacking == ATTACKING_NIGHTS) - { - // No demos to cancel - if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) - Command_ExitGame_f(); - - M_StartControlPanel(); + break; + case ATTACKING_NIGHTS: currentMenu = &SP_NightsAttackDef; - itemOn = currentMenu->lastOn; - modeattacking = ATTACKING_NONE; - G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusic(mus_racent, true); + break; } + itemOn = currentMenu->lastOn; + G_SetGamestate(GS_TIMEATTACK); + modeattacking = ATTACKING_NONE; + S_ChangeMusic(mus_racent, true); + // Update replay availability. + CV_AddValue(&cv_nextmap, 1); + CV_AddValue(&cv_nextmap, -1); } // ======== diff --git a/src/m_random.c b/src/m_random.c index ddf5e135..fce65b88 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -131,7 +131,9 @@ INT32 P_RandomKeyD(const char *rfile, INT32 rline, INT32 a) { CONS_Printf("P_RandomKey() at: %sp %d\n", rfile, rline); #endif - return (INT32)(((P_Random()|(P_Random() << 8))/65536.0f)*a); + INT32 prandom = P_Random(); // note: forcing explicit function call order + prandom |= P_Random() << 8; // (function call order is not strictly defined) + return (INT32)((prandom/65536.0f)*a); } /** Provides a random number in between a specific range. @@ -148,7 +150,9 @@ INT32 P_RandomRangeD(const char *rfile, INT32 rline, INT32 a, INT32 b) { CONS_Printf("P_RandomRange() at: %sp %d\n", rfile, rline); #endif - return (INT32)(((P_Random()|(P_Random() << 8))/65536.0f)*(b-a+1))+a; + INT32 prandom = P_Random(); // note: forcing explicit function call order + prandom |= P_Random() << 8; // (function call order is not strictly defined) + return (INT32)((prandom/65536.0f)*(b-a+1))+a; } /** Provides a random byte without saving what the seed would be. diff --git a/src/p_enemy.c b/src/p_enemy.c index 2a8280f1..54e15112 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2089,7 +2089,7 @@ void A_Boss1Laser(mobj_t *actor) actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); if (mobjinfo[locvar1].seesound) S_StartSound(actor, mobjinfo[locvar1].seesound); - if (!(actor->spawnpoint->options & MTF_AMBUSH)) + if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) { point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); point->fuse = actor->tics+1; @@ -2097,10 +2097,10 @@ void A_Boss1Laser(mobj_t *actor) P_SetTarget(&actor->target, point); } } - else if (actor->target && !(actor->spawnpoint->options & MTF_AMBUSH)) + else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); - if (actor->spawnpoint->options & MTF_AMBUSH) + if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); else angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); @@ -9608,10 +9608,6 @@ void A_TrapShot(mobj_t *actor) missile->momz = FixedMul(FINESINE(vertang>>ANGLETOFINESHIFT), speed); } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// TODO: Test the HELL out of these, then remove these annoying lines that are only here to remind you of that -SH // -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Function: A_VileTarget // // Description: Spawns an object directly on the target, and sets this object as the actor's tracer. diff --git a/src/p_floor.c b/src/p_floor.c index 6d28175e..f798174a 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1242,11 +1242,8 @@ void T_FloatSector(levelspecthink_t *floater) if (actionsector) { - boolean tofloat = false; - boolean floatanyway = false; // Ignore the crumblestate setting. - fixed_t waterheight = actionsector->floorheight - 512*FRACUNIT; - - waterheight = P_SectorCheckWater(actionsector, floater->sector); // find the highest suitable water block around + //boolean floatanyway = false; // Ignore the crumblestate setting. + fixed_t waterheight = P_SectorCheckWater(actionsector, floater->sector); // find the highest suitable water block around if (waterheight == cheeseheight) // same height, no floating needed ; @@ -1254,10 +1251,8 @@ void T_FloatSector(levelspecthink_t *floater) ; else if (floater->sector->ceilingheight == actionsector->ceilingheight && waterheight > cheeseheight) // too high ; - else // we have something to float in! Or we're for some reason above the ground, let's fall anyway - tofloat = true; - - if (tofloat && (floater->sector->crumblestate == 0 || floater->sector->crumblestate >= 3 || floatanyway)) + // we have something to float in! Or we're for some reason above the ground, let's fall anyway + else if (floater->sector->crumblestate == 0 || floater->sector->crumblestate >= 3/* || floatanyway*/) EV_BounceSector(floater->sector, FRACUNIT, floater->sourceline); P_RecalcPrecipInSector(actionsector); @@ -2252,6 +2247,9 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. // Makes much more sense doing it this way, honestly. P_RunTriggerLinedef(eachtime->sourceline, players[affectPlayer].mo, sec); + + if (!eachtime->sourceline->special) // this happens only for "Trigger on X calls" linedefs + P_RemoveThinker(&eachtime->thinker); } } @@ -2852,30 +2850,33 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) fixed_t topy, bottomy; fixed_t topz; fixed_t a, b, c; + mobjtype_t type = MT_ROCKCRUMBLE1; + + // If the control sector has a special + // of Section3:7-15, use the custom debris. + if (GETSECSPECIAL(rover->master->frontsector->special, 3) >= 8) + type = MT_ROCKCRUMBLE1+(GETSECSPECIAL(rover->master->frontsector->special, 3)-7); // soundorg z height never gets set normally, so MEH. sec->soundorg.z = sec->floorheight; S_StartSound(&sec->soundorg, sfx_crumbl); - // Find the leftmost vertex in the subsector. + // Find the outermost vertexes in the subsector for (i = 0; i < sec->linecount; i++) + { + // Find the leftmost vertex in the subsector. if ((sec->lines[i]->v1->x < sec->lines[leftmostvertex]->v1->x)) leftmostvertex = i; - - // Find the rightmost vertex in the subsector. - for (i = 0; i < sec->linecount; i++) + // Find the rightmost vertex in the subsector. if ((sec->lines[i]->v1->x > sec->lines[rightmostvertex]->v1->x)) rightmostvertex = i; - - // Find the topmost vertex in the subsector. - for (i = 0; i < sec->linecount; i++) + // Find the topmost vertex in the subsector. if ((sec->lines[i]->v1->y > sec->lines[topmostvertex]->v1->y)) topmostvertex = i; - - // Find the bottommost vertex in the subsector. - for (i = 0; i < sec->linecount; i++) + // Find the bottommost vertex in the subsector. if ((sec->lines[i]->v1->y < sec->lines[bottommostvertex]->v1->y)) bottommostvertex = i; + } leftx = sec->lines[leftmostvertex]->v1->x+(16<lines[rightmostvertex]->v1->x; @@ -2892,13 +2893,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) mobj_t *spawned = NULL; for (c = topz; c > *rover->bottomheight; c -= (32<master->frontsector->special, 3) >= 8) - spawned = P_SpawnMobj(a, b, c, MT_ROCKCRUMBLE1+(GETSECSPECIAL(rover->master->frontsector->special, 3)-7)); - else - spawned = P_SpawnMobj(a, b, c, MT_ROCKCRUMBLE1); - + spawned = P_SpawnMobj(a, b, c, type); spawned->fuse = 3*TICRATE; } } diff --git a/src/p_local.h b/src/p_local.h index f5c765fe..9f8918cd 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -373,6 +373,10 @@ void P_DoNightsScore(player_t *player); extern INT32 ceilmovesound; +// Factor to scale scrolling effect into mobj-carrying properties = 3/32. +// (This is so scrolling floors and objects on them can move at same speed.) +#define CARRYFACTOR ((3*FRACUNIT)/32) + void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, INT16 starpostx, INT16 starposty, INT16 starpostz, INT32 starpostnum, tic_t starposttime, angle_t starpostangle, diff --git a/src/p_map.c b/src/p_map.c index be59af0a..62cbf7b7 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -211,12 +211,160 @@ void P_DoSpring(mobj_t *spring, mobj_t *object) } } +static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) +{ + player_t *p = object->player; // will be NULL if not a player + fixed_t zdist; // distance between bottoms + fixed_t speed = spring->info->mass; // conveniently, both fans and gas jets use this for the vertical thrust + SINT8 flipval = P_MobjFlip(spring); // virtually everything here centers around the thruster's gravity, not the object's! + + if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain! + return; + + // is object below thruster's position? if not, calculate distance between their bottoms + if (spring->eflags & MFE_VERTICALFLIP) + { + if (object->z + object->height > spring->z + spring->height) + return; + zdist = (spring->z + spring->height) - (object->z + object->height); + } + else + { + if (object->z < spring->z) + return; + zdist = object->z - spring->z; + } + + switch (spring->type) + { + case MT_FAN: // fan + if (zdist > (spring->health << FRACBITS)) // max z distance determined by health (set by map thing angle) + break; + if (flipval*object->momz >= FixedMul(speed, spring->scale)) // if object's already moving faster than your best, don't bother + break; + if (p && (p->climbing || p->pflags & PF_GLIDING)) // doesn't affect Knux when he's using his abilities! + break; + + object->momz += flipval*FixedMul(speed/4, spring->scale); + + // limit the speed if too high + if (flipval*object->momz > FixedMul(speed, spring->scale)) + object->momz = flipval*FixedMul(speed, spring->scale); + + if (p && !p->powers[pw_tailsfly]) // doesn't reset anim for Tails' flight + { + P_ResetPlayer(p); + if (p->panim != PA_FALL) + P_SetPlayerMobjState(object, S_PLAY_FALL1); + } + break; + case MT_STEAM: // Steam + if (zdist > FixedMul(16*FRACUNIT, spring->scale)) + break; + if (spring->state != &states[S_STEAM1]) // Only when it bursts + break; + + object->momz = flipval*FixedMul(speed, FixedSqrt(FixedMul(spring->scale, object->scale))); // scale the speed with both objects' scales, just like with springs! + + if (p) + { + P_ResetPlayer(p); + if (p->panim != PA_FALL) + P_SetPlayerMobjState(object, S_PLAY_FALL1); + } + break; + default: + break; + } +} + +static void P_DoTailsCarry(player_t *sonic, player_t *tails) +{ + INT32 p; + fixed_t zdist; // z distance between the two players' bottoms + + if ((tails->pflags & PF_CARRIED) && tails->mo->tracer == sonic->mo) + return; + if ((sonic->pflags & PF_CARRIED) && sonic->mo->tracer == tails->mo) + return; + + if (!tails->powers[pw_tailsfly] && !(tails->charability == CA_FLY && (tails->mo->state >= &states[S_PLAY_SPC1] && tails->mo->state <= &states[S_PLAY_SPC4]))) + return; + + if (tails->bot == 1) + return; + + if (sonic->pflags & PF_NIGHTSMODE) + return; + + if (sonic->mo->tracer && sonic->mo->tracer->type == MT_TUBEWAYPOINT + && !(sonic->pflags & PF_ROPEHANG)) + return; // don't steal players from zoomtubes! + + if ((sonic->mo->eflags & MFE_VERTICALFLIP) != (tails->mo->eflags & MFE_VERTICALFLIP)) + return; // Both should be in same gravity + + if (tails->mo->eflags & MFE_VERTICALFLIP) + { + if (tails->mo->ceilingz - (tails->mo->z + tails->mo->height) < sonic->mo->height-FixedMul(2*FRACUNIT, sonic->mo->scale)) + return; + } + else if (tails->mo->z - tails->mo->floorz < sonic->mo->height-FixedMul(2*FRACUNIT, sonic->mo->scale)) + return; // No room to pick up this guy! + + // Search in case another player is already being carried by this fox. + for (p = 0; p < MAXPLAYERS; p++) + if (playeringame[p] && players[p].mo + && players[p].pflags & PF_CARRIED && players[p].mo->tracer == tails->mo) + return; + + if (tails->mo->eflags & MFE_VERTICALFLIP) + zdist = (sonic->mo->z + sonic->mo->height) - (tails->mo->z + tails->mo->height); + else + zdist = tails->mo->z - sonic->mo->z; + + if (zdist <= sonic->mo->height + FixedMul(FRACUNIT, sonic->mo->scale) + && zdist > sonic->mo->height*2/3 + && P_MobjFlip(tails->mo)*sonic->mo->momz <= 0) + { + // Why block opposing teams from tailsflying each other? + // Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows. + /* + if (gametype == GT_RACE || gametype == GT_COMPETITION + || (netgame && (tails->spectator || sonic->spectator)) + || (G_TagGametype() && (!(tails->pflags & PF_TAGIT) != !(sonic->pflags & PF_TAGIT))) + || (gametype == GT_MATCH) + || (G_GametypeHasTeams() && tails->ctfteam != sonic->ctfteam)) + sonic->pflags &= ~PF_CARRIED; */ + if (tails->spectator || sonic->spectator) + sonic->pflags &= ~PF_CARRIED; + else + { + if (sonic-players == consoleplayer && botingame) + CV_SetValue(&cv_analog2, false); + P_ResetPlayer(sonic); + P_SetTarget(&sonic->mo->tracer, tails->mo); + sonic->pflags |= PF_CARRIED; + S_StartSound(sonic->mo, sfx_s3k4a); + P_UnsetThingPosition(sonic->mo); + sonic->mo->x = tails->mo->x; + sonic->mo->y = tails->mo->y; + P_SetThingPosition(sonic->mo); + } + } + else { + if (sonic-players == consoleplayer && botingame) + CV_SetValue(&cv_analog2, true); + sonic->pflags &= ~PF_CARRIED; + } +} + // // PIT_CheckThing // static boolean PIT_CheckThing(mobj_t *thing) { - fixed_t blockdist, topz, tmtopz; + fixed_t blockdist; // don't clip against self tmsprung = false; @@ -662,103 +810,17 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->flags & MF_PUSHABLE) { - if (tmthing->eflags & MFE_VERTICALFLIP) - { - if (thing->z + thing->height <= tmthing->z + tmthing->height) - { - switch (tmthing->type) - { - case MT_FAN: // fan - if (thing->z + thing->height >= tmthing->z + tmthing->height - (tmthing->health << FRACBITS) && thing->momz > -FixedMul(tmthing->info->mass, tmthing->scale)) - { - thing->momz -= FixedMul(tmthing->info->mass/4, tmthing->scale); - - if (thing->momz < -FixedMul(tmthing->info->mass, tmthing->scale)) - thing->momz = -FixedMul(tmthing->info->mass, tmthing->scale); - } - break; - case MT_STEAM: // Steam - if (tmthing->state == &states[S_STEAM1] && thing->z + thing->height >= tmthing->z + tmthing->height - FixedMul(16*FRACUNIT, tmthing->scale)) // Only when it bursts - thing->momz = -FixedMul(tmthing->info->mass, FixedSqrt(FixedMul(tmthing->scale, thing->scale))); - break; - default: - break; - } - } - } - else - { - if (thing->z >= tmthing->z) - { - switch (tmthing->type) - { - case MT_FAN: // fan - if (thing->z <= tmthing->z + (tmthing->health << FRACBITS) && thing->momz < FixedMul(tmthing->info->mass, tmthing->scale)) - { - thing->momz += FixedMul(tmthing->info->mass/4, tmthing->scale); - - if (thing->momz > FixedMul(tmthing->info->mass, tmthing->scale)) - thing->momz = FixedMul(tmthing->info->mass, tmthing->scale); - } - break; - case MT_STEAM: // Steam - if (tmthing->state == &states[S_STEAM1] && thing->z <= tmthing->z + FixedMul(16*FRACUNIT, tmthing->scale)) // Only when it bursts - thing->momz = FixedMul(tmthing->info->mass, FixedSqrt(FixedMul(tmthing->scale, thing->scale))); - break; - default: - break; - } - } - } + if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) + P_DoFanAndGasJet(tmthing, thing); } if (tmthing->flags & MF_PUSHABLE) { - if ((thing->eflags & MFE_VERTICALFLIP) && tmthing->z + tmthing->height <= thing->z + thing->height) - { - switch (thing->type) - { - case MT_FAN: // fan - if (tmthing->z + tmthing->height >= thing->z + thing->height - (thing->health << FRACBITS) && tmthing->momz > -FixedMul(thing->info->mass, thing->scale)) - { - tmthing->momz -= FixedMul(thing->info->mass/4, thing->scale); - - if (tmthing->momz < -FixedMul(thing->info->mass, thing->scale)) - tmthing->momz = -FixedMul(thing->info->mass, thing->scale); - } - break; - case MT_STEAM: // Steam - if (thing->state == &states[S_STEAM1] && tmthing->z + tmthing->height >= thing->z + thing->height - FixedMul(16*FRACUNIT, thing->scale)) // Only when it bursts - tmthing->momz = -FixedMul(thing->info->mass, FixedSqrt(FixedMul(thing->scale, tmthing->scale))); - break; - default: - break; - } - } - else if (!(thing->eflags & MFE_VERTICALFLIP) && tmthing->z >= thing->z) - { - switch (thing->type) - { - case MT_FAN: // fan - if (tmthing->z <= thing->z + (thing->health << FRACBITS) && tmthing->momz < FixedMul(thing->info->mass, thing->scale)) - { - tmthing->momz += FixedMul(thing->info->mass/4, thing->scale); - - if (tmthing->momz > FixedMul(thing->info->mass, thing->scale)) - tmthing->momz = FixedMul(thing->info->mass, thing->scale); - } - break; - case MT_STEAM: // Steam - if (thing->state == &states[S_STEAM1] && tmthing->z <= thing->z + FixedMul(16*FRACUNIT, thing->scale)) // Only when it bursts - tmthing->momz = FixedMul(thing->info->mass, FixedSqrt(FixedMul(thing->scale, tmthing->scale))); - break; - default: - break; - } - } + if (thing->type == MT_FAN || thing->type == MT_STEAM) + P_DoFanAndGasJet(thing, tmthing); if ((!(thing->eflags & MFE_VERTICALFLIP) && (tmthing->z <= (thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) && (tmthing->z + tmthing->height) >= thing->z)) - || ((thing->eflags & MFE_VERTICALFLIP) && (tmthing->z + tmthing->height >= (thing->z - FixedMul(FRACUNIT, thing->scale)) && tmthing->z <= (thing->z + thing->height)))) + || ((thing->eflags & MFE_VERTICALFLIP) && (tmthing->z + tmthing->height >= (thing->z - FixedMul(FRACUNIT, thing->scale)) && tmthing->z <= (thing->z + thing->height)))) { if (thing->flags & MF_SPRING) { @@ -799,78 +861,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { if (tmthing->player && thing->player) { - if ((tmthing->player->pflags & PF_CARRIED) && tmthing->tracer == thing) - return true; - else if ((thing->player->pflags & PF_CARRIED) && thing->tracer == tmthing) - return true; - else if (tmthing->player->powers[pw_tailsfly] - || (tmthing->player->charability == CA_FLY && (tmthing->state >= &states[S_PLAY_SPC1] && tmthing->state <= &states[S_PLAY_SPC4]))) - { - INT32 p; - - if (tmthing->player->bot == 1) - return true; - - if (thing->player->pflags & PF_NIGHTSMODE) - return true; - - if (thing->tracer && thing->tracer->type == MT_TUBEWAYPOINT - && !(thing->player->pflags & PF_ROPEHANG)) - return true; // don't steal players from zoomtubes! - - if ((thing->eflags & MFE_VERTICALFLIP) != (tmthing->eflags & MFE_VERTICALFLIP)) - return true; // Both should be in same gravity - - if ((tmthing->eflags & MFE_VERTICALFLIP) - && tmthing->ceilingz - (tmthing->z + tmthing->height) < thing->height-FixedMul(2*FRACUNIT, thing->scale)) - return true; - else if (tmthing->z - tmthing->floorz < thing->height-FixedMul(2*FRACUNIT, thing->scale)) - return true; // No room to pick up this guy! - - // Search in case another player is already being carried by this fox. - for (p = 0; p < MAXPLAYERS; p++) - if (playeringame[p] && players[p].mo - && players[p].pflags & PF_CARRIED && players[p].mo->tracer == tmthing) - return true; - - if ((!(tmthing->eflags & MFE_VERTICALFLIP) && (tmthing->z <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) - && tmthing->z > thing->z + thing->height*2/3 - && thing->momz <= 0) - || ((tmthing->eflags & MFE_VERTICALFLIP) && (tmthing->z + tmthing->height >= thing->z - FixedMul(FRACUNIT, thing->scale)) - && tmthing->z + tmthing->height < thing->z + thing->height - thing->height*2/3 - && thing->momz >= 0)) - { - // Why block opposing teams from tailsflying each other? - // Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows. - /* - if (gametype == GT_RACE || gametype == GT_COMPETITION - || (netgame && (tmthing->player->spectator || thing->player->spectator)) - || (G_TagGametype() && (!(tmthing->player->pflags & PF_TAGIT) != !(thing->player->pflags & PF_TAGIT))) - || (gametype == GT_MATCH) - || (G_GametypeHasTeams() && tmthing->player->ctfteam != thing->player->ctfteam)) - thing->player->pflags &= ~PF_CARRIED; */ - if (tmthing->player->spectator || thing->player->spectator) - thing->player->pflags &= ~PF_CARRIED; - else - { - if (thing->player-players == consoleplayer && botingame) - CV_SetValue(&cv_analog2, false); - P_ResetPlayer(thing->player); - P_SetTarget(&thing->tracer, tmthing); - thing->player->pflags |= PF_CARRIED; - S_StartSound(thing, sfx_s3k4a); - P_UnsetThingPosition(thing); - thing->x = tmthing->x; - thing->y = tmthing->y; - P_SetThingPosition(thing); - } - } - else { - if (thing->player-players == consoleplayer && botingame) - CV_SetValue(&cv_analog2, true); - thing->player->pflags &= ~PF_CARRIED; - } - } + P_DoTailsCarry(thing->player, tmthing->player); return true; } } @@ -882,114 +873,33 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->player) { - if (tmthing->eflags & MFE_VERTICALFLIP) //doesn't matter what gravity player's following! Just do your stuff in YOUR direction only + // Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only + if (tmthing->eflags & MFE_VERTICALFLIP + && (tmthing->z + tmthing->height + tmthing->momz > thing->z + || tmthing->z + tmthing->height + tmthing->momz >= thing->z + thing->height)) + ; + else if (!(tmthing->eflags & MFE_VERTICALFLIP) + && (tmthing->z + tmthing->momz > thing->z + thing->height + || tmthing->z + tmthing->momz <= thing->z)) + ; + else if (P_IsObjectOnGround(thing) + && !P_IsObjectOnGround(tmthing) // Don't crush if the monitor is on the ground... + && (tmthing->flags & MF_SOLID)) { - // Objects kill you if it falls from above. - if (tmthing->z + tmthing->height + tmthing->momz >= thing->z - && tmthing->z + tmthing->height + tmthing->momz < thing->z + thing->height - && P_IsObjectOnGround(thing) - && !P_IsObjectOnGround(tmthing) // Don't crush if the monitor is on the ground... - && (tmthing->flags & MF_SOLID)) + if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE)) { - if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE)) - { - if (thing != tmthing->target) - P_DamageMobj(thing, tmthing, tmthing->target, 10000); + // Objects kill you if it falls from above. + if (thing != tmthing->target) + P_DamageMobj(thing, tmthing, tmthing->target, 10000); - tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! - // The tmthing->target allows the pusher of the object - // to get the point if he topples it on an opponent. - } - } - - if (thing->z + thing->height <= tmthing->z + tmthing->height && !(thing->state == &states[thing->info->painstate])) // Stuff where da player don't gotta move - { - switch (tmthing->type) - { - case MT_FAN: // fan - if (thing->z + thing->height >= tmthing->z + tmthing->height - (tmthing->health << FRACBITS) && thing->momz > -FixedMul(tmthing->info->mass, tmthing->scale) && !(thing->player->climbing || (thing->player->pflags & PF_GLIDING))) - { - thing->momz -= FixedMul(tmthing->info->mass/4, tmthing->scale); - - if (thing->momz < -FixedMul(tmthing->info->mass, tmthing->scale)) - thing->momz = -FixedMul(tmthing->info->mass, tmthing->scale); - - if (!thing->player->powers[pw_tailsfly]) - { - P_ResetPlayer(thing->player); - if (thing->player->panim != PA_FALL) - P_SetPlayerMobjState(thing, S_PLAY_FALL1); - } - } - break; - case MT_STEAM: // Steam - if (tmthing->state == &states[S_STEAM1] && thing->z + thing->height >= tmthing->z + tmthing->height - FixedMul(16*FRACUNIT, tmthing->scale)) // Only when it bursts - { - thing->momz = -FixedMul(tmthing->info->mass, FixedSqrt(FixedMul(tmthing->scale, thing->scale))); - P_ResetPlayer(thing->player); - if (thing->player->panim != PA_FALL) - P_SetPlayerMobjState(thing, S_PLAY_FALL1); - } - break; - default: - break; - } + tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! + // The tmthing->target allows the pusher of the object + // to get the point if he topples it on an opponent. } } - else - { - // Objects kill you if it falls from above. - if (tmthing->z + tmthing->momz <= thing->z + thing->height - && tmthing->z + tmthing->momz > thing->z - && P_IsObjectOnGround(thing) - && !P_IsObjectOnGround(tmthing) // Don't crush if the monitor is on the ground... - && (tmthing->flags & MF_SOLID)) - { - if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE)) - { - if (thing != tmthing->target) - P_DamageMobj(thing, tmthing, tmthing->target, 10000); - tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! - // The tmthing->target allows the pusher of the object - // to get the point if he topples it on an opponent. - } - } - - if (thing->z >= tmthing->z && !(thing->state == &states[thing->info->painstate])) // Stuff where da player don't gotta move - { - switch (tmthing->type) - { - case MT_FAN: // fan - if (thing->z <= tmthing->z + (tmthing->health << FRACBITS) && thing->momz < FixedMul(tmthing->info->mass, tmthing->scale) && !(thing->player->climbing || (thing->player->pflags & PF_GLIDING))) - { - thing->momz += FixedMul(tmthing->info->mass/4, tmthing->scale); - - if (thing->momz > FixedMul(tmthing->info->mass, tmthing->scale)) - thing->momz = FixedMul(tmthing->info->mass, tmthing->scale); - - if (!thing->player->powers[pw_tailsfly]) - { - P_ResetPlayer(thing->player); - if (thing->player->panim != PA_FALL) - P_SetPlayerMobjState(thing, S_PLAY_FALL1); - } - } - break; - case MT_STEAM: // Steam - if (tmthing->state == &states[S_STEAM1] && thing->z <= tmthing->z + FixedMul(16*FRACUNIT, tmthing->scale)) // Only when it bursts - { - thing->momz = FixedMul(tmthing->info->mass, FixedSqrt(FixedMul(tmthing->scale, thing->scale))); - P_ResetPlayer(thing->player); - if (thing->player->panim != PA_FALL) - P_SetPlayerMobjState(thing, S_PLAY_FALL1); - } - break; - default: - break; - } - } - } + if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) + P_DoFanAndGasJet(tmthing, thing); } if (tmthing->player) // Is the moving/interacting object the player? @@ -997,72 +907,8 @@ static boolean PIT_CheckThing(mobj_t *thing) if (!tmthing->health) return true; - if ((thing->eflags & MFE_VERTICALFLIP) && tmthing->z + tmthing->height <= thing->z + thing->height && !(tmthing->state == &states[tmthing->info->painstate])) - { - switch (thing->type) - { - case MT_FAN: // fan - if (tmthing->z + tmthing->height >= thing->z + thing->height - (thing->health << FRACBITS) && tmthing->momz > -FixedMul(thing->info->mass, thing->scale) && !(tmthing->player->climbing || (tmthing->player->pflags & PF_GLIDING))) - { - tmthing->momz -= FixedMul(thing->info->mass/4, thing->scale); - - if (tmthing->momz < -FixedMul(thing->info->mass, thing->scale)) - tmthing->momz = -FixedMul(thing->info->mass, thing->scale); - - if (!tmthing->player->powers[pw_tailsfly]) - { - P_ResetPlayer(tmthing->player); - if (tmthing->player->panim != PA_FALL) - P_SetPlayerMobjState(tmthing, S_PLAY_FALL1); - } - } - break; - case MT_STEAM: // Steam - if (thing->state == &states[S_STEAM1] && tmthing->z + tmthing->height >= thing->z + thing->height - FixedMul(16*FRACUNIT, thing->scale)) // Only when it bursts - { - tmthing->momz = -FixedMul(thing->info->mass, FixedSqrt(FixedMul(thing->scale, tmthing->scale))); - P_ResetPlayer(tmthing->player); - if (tmthing->player->panim != PA_FALL) - P_SetPlayerMobjState(tmthing, S_PLAY_FALL1); - } - break; - default: - break; - } - } - else if (!(thing->eflags & MFE_VERTICALFLIP) && tmthing->z >= thing->z && !(tmthing->state == &states[tmthing->info->painstate])) - { - switch (thing->type) - { - case MT_FAN: // fan - if (tmthing->z <= thing->z + (thing->health << FRACBITS) && tmthing->momz < FixedMul(thing->info->mass, thing->scale) && !(tmthing->player->climbing || (tmthing->player->pflags & PF_GLIDING))) - { - tmthing->momz += FixedMul(thing->info->mass/4, thing->scale); - - if (tmthing->momz > FixedMul(thing->info->mass, thing->scale)) - tmthing->momz = FixedMul(thing->info->mass, thing->scale); - - if (!tmthing->player->powers[pw_tailsfly]) - { - P_ResetPlayer(tmthing->player); - if (tmthing->player->panim != PA_FALL) - P_SetPlayerMobjState(tmthing, S_PLAY_FALL1); - } - } - break; - case MT_STEAM: // Steam - if (thing->state == &states[S_STEAM1] && tmthing->z <= thing->z + FixedMul(16*FRACUNIT, thing->scale)) // Only when it bursts - { - tmthing->momz = FixedMul(thing->info->mass, FixedSqrt(FixedMul(thing->scale, tmthing->scale))); - P_ResetPlayer(tmthing->player); - if (tmthing->player->panim != PA_FALL) - P_SetPlayerMobjState(tmthing, S_PLAY_FALL1); - } - break; - default: - break; - } - } + if (thing->type == MT_FAN || thing->type == MT_STEAM) + P_DoFanAndGasJet(thing, tmthing); // Are you touching the side of the object you're interacting with? if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height @@ -1104,6 +950,8 @@ static boolean PIT_CheckThing(mobj_t *thing) else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID && (tmthing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) { + fixed_t topz, tmtopz; + if (tmthing->eflags & MFE_VERTICALFLIP) { // pass under @@ -1415,8 +1263,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) ; else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)) ; - else if (!((((rover->flags & FF_BLOCKPLAYER) && thing->player) - || ((rover->flags & FF_BLOCKOTHERS) && !thing->player)) + else if (!((rover->flags & FF_BLOCKPLAYER && thing->player) + || (rover->flags & FF_BLOCKOTHERS && !thing->player) || rover->flags & FF_QUICKSAND)) continue; @@ -1450,16 +1298,21 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) } } + // The bounding box is extended by MAXRADIUS + // because mobj_ts are grouped into mapblocks + // based on their origin point, and can overlap + // into adjacent blocks by up to MAXRADIUS units. + + xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + #ifdef POLYOBJECTS // Check polyobjects and see if tmfloorz/tmceilingz need to be altered { validcount++; - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - for (by = yl; by <= yh; by++) for (bx = xl; bx <= xh; bx++) { @@ -1533,15 +1386,6 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) return true; // Check things first, possibly picking things up. - // The bounding box is extended by MAXRADIUS - // because mobj_ts are grouped into mapblocks - // based on their origin point, and can overlap - // into adjacent blocks by up to MAXRADIUS units. - - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; // MF_NOCLIPTHING: used by camera to not be blocked by things if (!(thing->flags & MF_NOCLIPTHING)) @@ -1671,16 +1515,21 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) } } + // The bounding box is extended by MAXRADIUS + // because mobj_ts are grouped into mapblocks + // based on their origin point, and can overlap + // into adjacent blocks by up to MAXRADIUS units. + + xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + #ifdef POLYOBJECTS // Check polyobjects and see if tmfloorz/tmceilingz need to be altered { validcount++; - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; - for (by = yl; by <= yh; by++) for (bx = xl; bx <= xh; bx++) { @@ -1749,18 +1598,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) } #endif - // Check things. - // The bounding box is extended by MAXRADIUS - // because mobj_ts are grouped into mapblocks - // based on their origin point, and can overlap - // into adjacent blocks by up to MAXRADIUS units. - // check lines - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; - for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) if (!P_BlockLinesIterator(bx, by, PIT_CheckCameraLine)) diff --git a/src/p_maputl.c b/src/p_maputl.c index d46080ab..48dd54e8 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -538,8 +538,14 @@ void P_LineOpening(line_t *linedef) // Check for frontsector's fake floors for (rover = front->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) - || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; + if (!(rover->flags & FF_EXISTS)) + continue; + + if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover))) + ; + else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player) + || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) + continue; delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); @@ -564,8 +570,14 @@ void P_LineOpening(line_t *linedef) // Check for backsectors fake floors for (rover = back->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) - || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; + if (!(rover->flags & FF_EXISTS)) + continue; + + if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover))) + ; + else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player) + || (rover->flags & FF_BLOCKOTHERS && !tmthing->player))) + continue; delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); diff --git a/src/p_mobj.c b/src/p_mobj.c index 1ee30fbc..e85e25b0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2030,6 +2030,7 @@ static void P_PlayerZMovement(mobj_t *mo) // Check if we're on a polyobject // that triggers a linedef executor. msecnode_t *node; + boolean stopmovecut = false; for (node = mo->touching_sectorlist; node; node = node->m_snext) { @@ -2051,6 +2052,18 @@ static void P_PlayerZMovement(mobj_t *mo) while(po) { + if (!P_MobjInsidePolyobj(po, mo)) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + polysec = po->lines[0]->backsector; + + // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red + if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && (po->flags & POF_SOLID) && po->thinker) + stopmovecut = true; + if (!(po->flags & POF_LDEXEC) || !(po->flags & POF_SOLID)) { @@ -2058,14 +2071,7 @@ static void P_PlayerZMovement(mobj_t *mo) continue; } - if (!P_MobjInsidePolyobj(po, mo)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - // We're inside it! Yess... - polysec = po->lines[0]->backsector; if (mo->z == polysec->ceilingheight) { @@ -2080,6 +2086,8 @@ static void P_PlayerZMovement(mobj_t *mo) } } } + + if (!stopmovecut) #endif // Cut momentum in half when you hit the ground and @@ -5761,6 +5769,29 @@ void P_MobjThinker(mobj_t *mobj) case MT_SEED: mobj->momz = mobj->info->speed; break; + case MT_ROCKCRUMBLE1: + case MT_ROCKCRUMBLE2: + case MT_ROCKCRUMBLE3: + case MT_ROCKCRUMBLE4: + case MT_ROCKCRUMBLE5: + case MT_ROCKCRUMBLE6: + case MT_ROCKCRUMBLE7: + case MT_ROCKCRUMBLE8: + case MT_ROCKCRUMBLE9: + case MT_ROCKCRUMBLE10: + case MT_ROCKCRUMBLE11: + case MT_ROCKCRUMBLE12: + case MT_ROCKCRUMBLE13: + case MT_ROCKCRUMBLE14: + case MT_ROCKCRUMBLE15: + case MT_ROCKCRUMBLE16: + if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) + && mobj->state != &states[mobj->info->deathstate]) + { + P_SetMobjState(mobj, mobj->info->deathstate); + return; + } + break; default: if (mobj->fuse) { // Scenery object fuse! Very basic! @@ -5951,29 +5982,6 @@ void P_MobjThinker(mobj_t *mobj) } else switch (mobj->type) { - case MT_ROCKCRUMBLE1: - case MT_ROCKCRUMBLE2: - case MT_ROCKCRUMBLE3: - case MT_ROCKCRUMBLE4: - case MT_ROCKCRUMBLE5: - case MT_ROCKCRUMBLE6: - case MT_ROCKCRUMBLE7: - case MT_ROCKCRUMBLE8: - case MT_ROCKCRUMBLE9: - case MT_ROCKCRUMBLE10: - case MT_ROCKCRUMBLE11: - case MT_ROCKCRUMBLE12: - case MT_ROCKCRUMBLE13: - case MT_ROCKCRUMBLE14: - case MT_ROCKCRUMBLE15: - case MT_ROCKCRUMBLE16: - if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) - && mobj->state != &states[mobj->info->deathstate]) - { - P_SetMobjState(mobj, mobj->info->deathstate); - return; - } - break; case MT_EMERALDSPAWN: if (mobj->threshold) { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index b6d7caa9..9c955c97 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -142,6 +142,16 @@ FUNCINLINE static ATTRINLINE void Polyobj_vecSub2(vertex_t *dst, vertex_t *v1, v dst->y = v1->y - v2->y; } +// Add the polyobject's thinker to the thinker list +// Unlike P_AddThinker, this adds it to the front of the list instead of the back, so that carrying physics can work right. -Red +FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th) +{ + thinkercap.next->prev = th; + th->next = thinkercap.next; + th->prev = &thinkercap; + thinkercap.next = th; +} + // // P_PointInsidePolyobj // @@ -573,7 +583,7 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) // set to default thrust; may be modified by attached thinkers // TODO: support customized thrust? po->thrust = FRACUNIT; - po->flags = 0; + po->spawnflags = po->flags = 0; // 1. Search segs for "line start" special with tag matching this // polyobject's id number. If found, iterate through segs which @@ -613,6 +623,8 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) if (seg->linedef->flags & ML_NOCLIMB) // Has a linedef executor po->flags |= POF_LDEXEC; + po->spawnflags = po->flags; // save original flags to reference later for netgames! + Polyobj_findSegs(po, seg); po->parent = parentID; if (po->parent == po->id) // do not allow a self-reference @@ -966,6 +978,38 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) } } +// +// Polyobj_slideThing +// +// Moves an object resting on top of a polyobject by (x, y). Template function to make alteration easier. +// +static void Polyobj_slideThing(mobj_t *mo, fixed_t dx, fixed_t dy) +{ + if (mo->player) { // Do something similar to conveyor movement. -Red + mo->player->cmomx += dx; + mo->player->cmomy += dy; + + dx = FixedMul(dx, CARRYFACTOR); + dy = FixedMul(dy, CARRYFACTOR); + + mo->player->cmomx -= dx; + mo->player->cmomy -= dy; + + if (mo->player->pflags & PF_SPINNING && (mo->player->rmomx || mo->player->rmomy) && !(mo->player->pflags & PF_STARTDASH)) { +#define SPINMULT 5184 // Consider this a substitute for properly calculating FRACUNIT-friction. I'm tired. -Red + dx = FixedMul(dx, SPINMULT); + dy = FixedMul(dy, SPINMULT); +#undef SPINMULT + } + + mo->momx += dx; + mo->momy += dy; + + mo->player->onconveyor = 1; + } else + P_TryMove(mo, mo->x+dx, mo->y+dy, true); +} + // // Polyobj_carryThings // @@ -1015,7 +1059,7 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) if (!P_MobjInsidePolyobj(po, mo)) continue; - P_TryMove(mo, mo->x+dx, mo->y+dy, true); + Polyobj_slideThing(mo, dx, dy); } } } @@ -1206,12 +1250,91 @@ static void Polyobj_rotateLine(line_t *ld) } } +// +// Polyobj_rotateThings +// +// Causes objects resting on top of the rotating polyobject to 'ride' with its movement. +// +static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta, UINT8 turnthings) +{ + static INT32 pomovecount = 10000; + INT32 x, y; + + pomovecount++; + + if (!(po->flags & POF_SOLID)) + return; + + for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) + { + for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) + { + mobj_t *mo; + + if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) + continue; + + mo = blocklinks[y * bmapwidth + x]; + + for (; mo; mo = mo->bnext) + { + if (mo->lastlook == pomovecount) + continue; + + mo->lastlook = pomovecount; + + // always push players even if not solid + if (!((mo->flags & MF_SOLID) || mo->player)) + continue; + + if (mo->flags & MF_NOCLIP) + continue; + + if ((mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height != po->lines[0]->backsector->floorheight) + continue; + + if (!(mo->eflags & MFE_VERTICALFLIP) && mo->z != po->lines[0]->backsector->ceilingheight) + continue; + + if (!P_MobjInsidePolyobj(po, mo)) + continue; + + { + fixed_t newxoff, newyoff; + angle_t angletoobj = R_PointToAngle2(origin.x, origin.y, mo->x, mo->y); + fixed_t disttoobj = R_PointToDist2(origin.x, origin.y, mo->x, mo->y); + + if (mo->player) // Hack to fix players sliding off of spinning polys -Red + { + disttoobj = FixedMul(disttoobj, 0xfe40); + } + + angletoobj += delta; + angletoobj >>= ANGLETOFINESHIFT; + newxoff = FixedMul(FINECOSINE(angletoobj), disttoobj); + newyoff = FixedMul(FINESINE(angletoobj), disttoobj); + + Polyobj_slideThing(mo, origin.x+newxoff-mo->x, origin.y+newyoff-mo->y); + + if (turnthings == 2 || (turnthings == 1 && !mo->player)) { + mo->angle += delta; + if (mo->player == &players[consoleplayer]) + localangle = mo->angle; + else if (mo->player == &players[secondarydisplayplayer]) + localangle2 = mo->angle; + } + } + } + } + } +} + // // Polyobj_rotate // // Rotates a polyobject around its start point. // -static boolean Polyobj_rotate(polyobj_t *po, angle_t delta) +static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings) { size_t i; angle_t angle; @@ -1247,6 +1370,8 @@ static boolean Polyobj_rotate(polyobj_t *po, angle_t delta) for (i = 0; i < po->numLines; ++i) hitflags |= Polyobj_clipThings(po, po->lines[i]); + Polyobj_rotateThings(po, origin, delta, turnthings); + if (hitflags & 2) { // reset vertices to previous positions @@ -1466,7 +1591,7 @@ void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y) fixed_t dx, dy; // first, rotate to the saved angle - Polyobj_rotate(po, angle); + Polyobj_rotate(po, angle, false); // determine component distances to translate dx = x - po->spawnSpot.x; @@ -1513,7 +1638,7 @@ void T_PolyObjRotate(polyrotate_t *th) // rotate by 'speed' angle per frame // if distance == -1, this polyobject rotates perpetually - if (Polyobj_rotate(po, th->speed) && th->distance != -1) + if (Polyobj_rotate(po, th->speed, th->turnobjs) && th->distance != -1) { INT32 avel = abs(th->speed); @@ -1551,8 +1676,21 @@ void T_PolyObjRotate(polyrotate_t *th) FUNCINLINE static ATTRINLINE void Polyobj_componentSpeed(INT32 resVel, INT32 angle, fixed_t *xVel, fixed_t *yVel) { - *xVel = FixedMul(resVel, FINECOSINE(angle)); - *yVel = FixedMul(resVel, FINESINE(angle)); + if (angle == 0) + { + *xVel = resVel; + *yVel = 0; + } + else if (angle == (INT32)(ANGLE_90>>ANGLETOFINESHIFT)) + { + *xVel = 0; + *yVel = resVel; + } + else + { + *xVel = FixedMul(resVel, FINECOSINE(angle)); + *yVel = FixedMul(resVel, FINESINE(angle)); + } } void T_PolyObjMove(polymove_t *th) @@ -1694,15 +1832,16 @@ void T_PolyObjWaypoint(polywaypoint_t *th) if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(target->x - adjustx - momx, target->y - adjusty - momy), target->z - adjustz - momz)>>FRACBITS) { // If further away, set XYZ of polyobject to waypoint location - fixed_t amtx, amty; + fixed_t amtx, amty, amtz; + fixed_t diffz; amtx = (target->x - th->diffx) - po->centerPt.x; amty = (target->y - th->diffy) - po->centerPt.y; Polyobj_moveXY(po, amtx, amty); // TODO: use T_MovePlane - amtx = (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2; - po->lines[0]->backsector->floorheight = target->z - amtx; - po->lines[0]->backsector->ceilingheight = target->z + amtx; - + amtz = (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2; + diffz = po->lines[0]->backsector->floorheight - (target->z - amtz); + po->lines[0]->backsector->floorheight = target->z - amtz; + po->lines[0]->backsector->ceilingheight = target->z + amtz; // Apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -1712,9 +1851,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th) Polyobj_moveXY(po, amtx, amty); // TODO: use T_MovePlane - amtx = (po->lines[0]->backsector->ceilingheight - po->lines[0]->backsector->floorheight)/2; - po->lines[0]->backsector->floorheight = target->z - amtx; - po->lines[0]->backsector->ceilingheight = target->z + amtx; + po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did + po->lines[0]->backsector->ceilingheight += diffz; } po = oldpo; @@ -2035,7 +2173,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th) // rotate by 'speed' angle per frame // if distance == -1, this polyobject rotates perpetually - if (Polyobj_rotate(po, th->speed) && th->distance != -1) + if (Polyobj_rotate(po, th->speed, false) && th->distance != -1) { INT32 avel = abs(th->speed); @@ -2091,6 +2229,46 @@ void T_PolyDoorSwing(polyswingdoor_t *th) } } +// T_PolyObjDisplace: shift a polyobject based on a control sector's heights. -Red +void T_PolyObjDisplace(polydisplace_t *th) +{ + polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); + fixed_t newheights, delta; + fixed_t dx, dy; + + if (!po) +#ifdef RANGECHECK + I_Error("T_PolyDoorSwing: thinker has invalid id %d\n", th->polyObjNum); +#else + { + CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum); + P_RemoveThinkerDelayed(&th->thinker); + return; + } +#endif + + // check for displacement due to override and reattach when possible + if (po->thinker == NULL) + { + po->thinker = &th->thinker; + + // reset polyobject's thrust + po->thrust = FRACUNIT; + } + + newheights = th->controlSector->floorheight+th->controlSector->ceilingheight; + delta = newheights-th->oldHeights; + + if (!delta) + return; + + dx = FixedMul(th->dx, delta); + dy = FixedMul(th->dy, delta); + + if (Polyobj_moveXY(po, dx, dy)) + th->oldHeights = newheights; +} + static inline INT32 Polyobj_AngSpeed(INT32 speed) { return (speed*ANG1)>>3; // no FixedAngle() @@ -2122,7 +2300,7 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata) // create a new thinker th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotate; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); po->thinker = &th->thinker; // set fields @@ -2149,10 +2327,15 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata) oldpo = po; + th->turnobjs = prdata->turnobjs; + // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) + { + prdata->polyObjNum = po->id; // change id to match child polyobject's EV_DoPolyObjRotate(prdata); + } // action was successful return 1; @@ -2182,7 +2365,7 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata) // create a new thinker th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyObjMove; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); po->thinker = &th->thinker; // set fields @@ -2208,7 +2391,10 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata) // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) + { + pmdata->polyObjNum = po->id; // change id to match child polyobject's EV_DoPolyObjMove(pmdata); + } // action was successful return 1; @@ -2240,7 +2426,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) // create a new thinker th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyObjWaypoint; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); po->thinker = &th->thinker; // set fields @@ -2382,7 +2568,7 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata) // allocate and add a new slide door thinker th = Z_Malloc(sizeof(polyslidedoor_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSlide; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); // point the polyobject to this thinker po->thinker = &th->thinker; @@ -2430,7 +2616,7 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata) // allocate and add a new swing door thinker th = Z_Malloc(sizeof(polyswingdoor_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSwing; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); // point the polyobject to this thinker po->thinker = &th->thinker; @@ -2492,6 +2678,52 @@ INT32 EV_DoPolyDoor(polydoordata_t *doordata) return 1; } +INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata) +{ + polyobj_t *po; + polyobj_t *oldpo; + polydisplace_t *th; + INT32 start; + + if (!(po = Polyobj_GetForNum(prdata->polyObjNum))) + { + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjRotate: bad polyobj %d\n", prdata->polyObjNum); + return 0; + } + + // don't allow line actions to affect bad polyobjects + if (po->isBad) + return 0; + + // create a new thinker + th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL); + th->thinker.function.acp1 = (actionf_p1)T_PolyObjDisplace; + PolyObj_AddThinker(&th->thinker); + po->thinker = &th->thinker; + + // set fields + th->polyObjNum = prdata->polyObjNum; + + th->controlSector = prdata->controlSector; + th->oldHeights = th->controlSector->floorheight+th->controlSector->ceilingheight; + + th->dx = prdata->dx; + th->dy = prdata->dy; + + oldpo = po; + + // apply action to mirroring polyobjects as well + start = 0; + while ((po = Polyobj_GetChild(oldpo, &start))) + { + prdata->polyObjNum = po->id; // change id to match child polyobject's + EV_DoPolyObjDisplace(prdata); + } + + // action was successful + return 1; +} + void T_PolyObjFlag(polymove_t *th) { polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); @@ -2567,7 +2799,7 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) // create a new thinker th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL); th->thinker.function.acp1 = (actionf_p1)T_PolyObjFlag; - P_AddThinker(&th->thinker); + PolyObj_AddThinker(&th->thinker); po->thinker = &th->thinker; // set fields @@ -2586,7 +2818,10 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata) // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) + { + pfdata->tag = po->id; EV_DoPolyObjFlag(pfdata); + } // action was successful return 1; diff --git a/src/p_polyobj.h b/src/p_polyobj.h index 4e21f4a8..71cf965e 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -99,6 +99,9 @@ typedef struct polyobj_s UINT8 isBad; // a bad polyobject: should not be rendered/manipulated INT32 translucency; // index to translucency tables + + // these are saved for netgames, so do not let Lua touch these! + INT32 spawnflags; // Flags the polyobject originally spawned with } polyobj_t; // @@ -122,6 +125,7 @@ typedef struct polyrotate_s INT32 polyObjNum; // numeric id of polyobject (avoid C pointers here) INT32 speed; // speed of movement per frame INT32 distance; // distance to move + UINT8 turnobjs; // turn objects? 0=no, 1=everything but players, 2=everything } polyrotate_t; typedef struct polymove_s @@ -189,6 +193,17 @@ typedef struct polyswingdoor_s UINT8 closing; // if true, is closing } polyswingdoor_t; +typedef struct polydisplace_s +{ + thinker_t thinker; // must be first + + INT32 polyObjNum; + struct sector_s *controlSector; + fixed_t dx; + fixed_t dy; + fixed_t oldHeights; +} polydisplace_t; + // // Line Activation Data Structures // @@ -199,7 +214,8 @@ typedef struct polyrotdata_s INT32 direction; // direction of rotation INT32 speed; // angular speed INT32 distance; // distance to move - UINT8 overRide; // if true, will override any action on the object + UINT8 turnobjs; // rotate objects being carried? + UINT8 overRide; // if true, will override any action on the object } polyrotdata_t; typedef struct polymovedata_s @@ -208,7 +224,7 @@ typedef struct polymovedata_s fixed_t distance; // distance to move fixed_t speed; // linear speed angle_t angle; // angle of movement - UINT8 overRide; // if true, will override any action on the object + UINT8 overRide; // if true, will override any action on the object } polymovedata_t; typedef struct polywaypointdata_s @@ -239,6 +255,14 @@ typedef struct polydoordata_s INT32 delay; // delay time after opening } polydoordata_t; +typedef struct polydisplacedata_s +{ + INT32 polyObjNum; + struct sector_s *controlSector; + fixed_t dx; + fixed_t dy; +} polydisplacedata_t; + // // Functions // @@ -258,12 +282,14 @@ void T_PolyObjMove (polymove_t *); void T_PolyObjWaypoint (polywaypoint_t *); void T_PolyDoorSlide(polyslidedoor_t *); void T_PolyDoorSwing(polyswingdoor_t *); +void T_PolyObjDisplace (polydisplace_t *); void T_PolyObjFlag (polymove_t *); INT32 EV_DoPolyDoor(polydoordata_t *); INT32 EV_DoPolyObjMove(polymovedata_t *); INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *); INT32 EV_DoPolyObjRotate(polyrotdata_t *); +INT32 EV_DoPolyObjDisplace(polydisplacedata_t *); INT32 EV_DoPolyObjFlag(struct line_s *); diff --git a/src/p_saveg.c b/src/p_saveg.c index 3392d1e2..bf64d9a2 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -143,13 +143,13 @@ static inline void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashcount); WRITEUINT32(save_p, players[i].score); - WRITEINT32(save_p, players[i].dashspeed); + WRITEFIXED(save_p, players[i].dashspeed); WRITEINT32(save_p, players[i].dashtime); WRITESINT8(save_p, players[i].lives); WRITESINT8(save_p, players[i].continues); WRITESINT8(save_p, players[i].xtralife); WRITEUINT8(save_p, players[i].gotcontinue); - WRITEINT32(save_p, players[i].speed); + WRITEFIXED(save_p, players[i].speed); WRITEUINT8(save_p, players[i].jumping); WRITEUINT8(save_p, players[i].secondjump); WRITEUINT8(save_p, players[i].fly1); @@ -172,8 +172,8 @@ static inline void P_NetArchivePlayers(void) ///////////////////// // Race Mode Stuff // ///////////////////// - WRITEINT32(save_p, players[i].numboxes); - WRITEINT32(save_p, players[i].totalring); + WRITEINT16(save_p, players[i].numboxes); + WRITEINT16(save_p, players[i].totalring); WRITEUINT32(save_p, players[i].realtime); WRITEUINT8(save_p, players[i].laps); @@ -211,7 +211,7 @@ static inline void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].marebegunat); WRITEUINT32(save_p, players[i].startedtime); WRITEUINT32(save_p, players[i].finishedtime); - WRITEUINT16(save_p, players[i].finishedrings); + WRITEINT16(save_p, players[i].finishedrings); WRITEUINT32(save_p, players[i].marescore); WRITEUINT32(save_p, players[i].lastmarescore); WRITEUINT8(save_p, players[i].lastmare); @@ -318,13 +318,13 @@ static inline void P_NetUnArchivePlayers(void) players[i].flashcount = READUINT16(save_p); players[i].score = READUINT32(save_p); - players[i].dashspeed = READINT32(save_p); // dashing speed + players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].dashtime = READINT32(save_p); // dashing speed players[i].lives = READSINT8(save_p); players[i].continues = READSINT8(save_p); // continues that player has acquired players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter players[i].gotcontinue = READUINT8(save_p); // got continue from stage - players[i].speed = READINT32(save_p); // Player's speed (distance formula of MOMX and MOMY values) + players[i].speed = READFIXED(save_p); // Player's speed (distance formula of MOMX and MOMY values) players[i].jumping = READUINT8(save_p); // Jump counter players[i].secondjump = READUINT8(save_p); players[i].fly1 = READUINT8(save_p); // Tails flying @@ -347,8 +347,8 @@ static inline void P_NetUnArchivePlayers(void) ///////////////////// // Race Mode Stuff // ///////////////////// - players[i].numboxes = READINT32(save_p); // Number of item boxes obtained for Race Mode - players[i].totalring = READINT32(save_p); // Total number of rings obtained for Race Mode + players[i].numboxes = READINT16(save_p); // Number of item boxes obtained for Race Mode + players[i].totalring = READINT16(save_p); // Total number of rings obtained for Race Mode players[i].realtime = READUINT32(save_p); // integer replacement for leveltime players[i].laps = READUINT8(save_p); // Number of laps (optional) @@ -386,7 +386,7 @@ static inline void P_NetUnArchivePlayers(void) players[i].marebegunat = READUINT32(save_p); players[i].startedtime = READUINT32(save_p); players[i].finishedtime = READUINT32(save_p); - players[i].finishedrings = READUINT16(save_p); + players[i].finishedrings = READINT16(save_p); players[i].marescore = READUINT32(save_p); players[i].lastmarescore = READUINT32(save_p); players[i].lastmare = READUINT8(save_p); @@ -447,6 +447,7 @@ static inline void P_NetUnArchivePlayers(void) #define SD_LIGHT 0x10 #define SD_SPECIAL 0x20 #define SD_DIFF2 0x40 +#define SD_FFLOORS 0x80 // diff2 flags #define SD_FXOFFS 0x01 @@ -459,6 +460,7 @@ static inline void P_NetUnArchivePlayers(void) #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 +#define LD_CLLCOUNT 0x04 #define LD_S1TEXOFF 0x08 #define LD_S1TOPTEX 0x10 #define LD_S1BOTTEX 0x20 @@ -515,23 +517,37 @@ static void P_NetArchiveWorld(void) if (ss->special != SHORT(ms->special)) diff |= SD_SPECIAL; - /// \todo this makes Flat Alignment (linetype 7) increase the savegame size! - if (ss->floor_xoffs != 0) + if (ss->floor_xoffs != ss->spawn_flr_xoffs) diff2 |= SD_FXOFFS; - if (ss->floor_yoffs != 0) + if (ss->floor_yoffs != ss->spawn_flr_yoffs) diff2 |= SD_FYOFFS; - if (ss->ceiling_xoffs != 0) + if (ss->ceiling_xoffs != ss->spawn_ceil_xoffs) diff2 |= SD_CXOFFS; - if (ss->ceiling_yoffs != 0) + if (ss->ceiling_yoffs != ss->spawn_ceil_yoffs) diff2 |= SD_CYOFFS; - if (ss->floorpic_angle != 0) + if (ss->floorpic_angle != ss->spawn_flrpic_angle) diff2 |= SD_FLOORANG; - if (ss->ceilingpic_angle != 0) + if (ss->ceilingpic_angle != ss->spawn_flrpic_angle) diff2 |= SD_CEILANG; if (ss->tag != SHORT(ms->tag)) diff2 |= SD_TAG; + // Check if any of the sector's FOFs differ from how they spawned + if (ss->ffloors) + { + ffloor_t *rover; + for (rover = ss->ffloors; rover; rover = rover->next) + { + if (rover->flags != rover->spawnflags + || rover->alpha != rover->spawnalpha) + { + diff |= SD_FFLOORS; // we found an FOF that changed! + break; // don't bother checking for more, we do that later + } + } + } + if (diff2) diff |= SD_DIFF2; @@ -573,6 +589,35 @@ static void P_NetArchiveWorld(void) WRITEANGLE(put, ss->floorpic_angle); if (diff2 & SD_CEILANG) WRITEANGLE(put, ss->ceilingpic_angle); + + // Special case: save the stats of all modified ffloors along with their ffloor "number"s + // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed + if (diff & SD_FFLOORS) + { + size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc + ffloor_t *rover; + UINT8 fflr_diff; + for (rover = ss->ffloors; rover; rover = rover->next) + { + fflr_diff = 0; // reset diff flags + if (rover->flags != rover->spawnflags) + fflr_diff |= 1; + if (rover->alpha != rover->spawnalpha) + fflr_diff |= 2; + + if (fflr_diff) + { + WRITEUINT16(put, j); // save ffloor "number" + WRITEUINT8(put, fflr_diff); + if (fflr_diff & 1) + WRITEUINT16(put, rover->flags); + if (fflr_diff & 2) + WRITEINT16(put, rover->alpha); + } + j++; + } + WRITEUINT16(put, 0xffff); + } } } @@ -588,6 +633,9 @@ static void P_NetArchiveWorld(void) if (li->special != SHORT(mld->special)) diff |= LD_SPECIAL; + if (mld->special == 321 || mld->special == 322) // only reason li->callcount would be non-zero is if either of these are involved + diff |= LD_CLLCOUNT; + if (li->sidenum[0] != 0xffff) { si = &sides[li->sidenum[0]]; @@ -633,6 +681,8 @@ static void P_NetArchiveWorld(void) WRITEINT16(put, li->flags); if (diff & LD_SPECIAL) WRITEINT16(put, li->special); + if (diff & LD_CLLCOUNT) + WRITEINT16(put, li->callcount); si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) @@ -732,6 +782,46 @@ static void P_NetUnArchiveWorld(void) sectors[i].floorpic_angle = READANGLE(get); if (diff2 & SD_CEILANG) sectors[i].ceilingpic_angle = READANGLE(get); + + if (diff & SD_FFLOORS) + { + UINT16 j = 0; // number of current ffloor in loop + UINT16 fflr_i; // saved ffloor "number" of next modified ffloor + UINT16 fflr_diff; // saved ffloor diff + ffloor_t *rover; + + rover = sectors[i].ffloors; + if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case... + I_Error("Sector does not have any ffloors!"); + + fflr_i = READUINT16(get); // get first modified ffloor's number ready + for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here? + { + if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already + break; + // should NEVER need to be checked + //if (rover == NULL) + //break; + if (j != fflr_i) // this ffloor was not modified + { + j++; + rover = rover->next; + continue; + } + + fflr_diff = READUINT8(get); + + if (fflr_diff & 1) + rover->flags = READUINT16(get); + if (fflr_diff & 2) + rover->alpha = READINT16(get); + + fflr_i = READUINT16(get); // get next ffloor "number" ready + + j++; + rover = rover->next; + } + } } for (;;) @@ -754,6 +844,8 @@ static void P_NetUnArchiveWorld(void) li->flags = READINT16(get); if (diff & LD_SPECIAL) li->special = READINT16(get); + if (diff & LD_CLLCOUNT) + li->callcount = READINT16(get); si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) @@ -869,6 +961,7 @@ typedef enum tc_polyslidedoor, tc_polyswingdoor, tc_polyflag, + tc_polydisplace, #endif tc_end } specials_e; @@ -1149,6 +1242,7 @@ static void SaveExecutorThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, type); WRITEUINT32(save_p, SaveLine(ht->line)); WRITEUINT32(save_p, SaveMobjnum(ht->caller)); + WRITEUINT32(save_p, SaveSector(ht->sector)); WRITEINT32(save_p, ht->timer); } @@ -1269,6 +1363,17 @@ static void SavePolyswingdoorThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->closing); } +static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type) +{ + const polydisplace_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEINT32(save_p, ht->polyObjNum); + WRITEUINT32(save_p, SaveSector(ht->controlSector)); + WRITEFIXED(save_p, ht->dx); + WRITEFIXED(save_p, ht->dy); + WRITEFIXED(save_p, ht->oldHeights); +} + #endif /* // @@ -1696,6 +1801,11 @@ static void P_NetArchiveThinkers(void) SavePolymoveThinker(th, tc_polyflag); continue; } + else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace) + { + SavePolydisplaceThinker(th, tc_polydisplace); + continue; + } #endif #ifdef PARANOIA else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection @@ -2057,6 +2167,7 @@ static inline void LoadExecutorThinker(actionf_p1 thinker) ht->thinker.function.acp1 = thinker; ht->line = LoadLine(READUINT32(save_p)); ht->caller = LoadMobj(READUINT32(save_p)); + ht->sector = LoadSector(READUINT32(save_p)); ht->timer = READINT32(save_p); P_AddThinker(&ht->thinker); } @@ -2183,6 +2294,23 @@ static inline void LoadPolyswingdoorThinker(actionf_p1 thinker) ht->closing = READUINT8(save_p); P_AddThinker(&ht->thinker); } + +// +// LoadPolydisplaceThinker +// +// Loads a polydisplace_t thinker +// +static inline void LoadPolydisplaceThinker(actionf_p1 thinker) +{ + polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->polyObjNum = READINT32(save_p); + ht->controlSector = LoadSector(READUINT32(save_p)); + ht->dx = READFIXED(save_p); + ht->dy = READFIXED(save_p); + ht->oldHeights = READFIXED(save_p); + P_AddThinker(&ht->thinker); +} #endif /* @@ -2574,9 +2702,14 @@ static void P_NetUnArchiveThinkers(void) case tc_polyswingdoor: LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing); break; + case tc_polyflag: LoadPolymoveThinker((actionf_p1)T_PolyObjFlag); break; + + case tc_polydisplace: + LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace); + break; #endif case tc_scroll: LoadScrollThinker((actionf_p1)T_Scroll); @@ -2617,13 +2750,29 @@ static void P_NetUnArchiveThinkers(void) // haleyjd 03/26/06: PolyObject saving code // #ifdef POLYOBJECTS +#define PD_FLAGS 0x01 +#define PD_TRANS 0x02 + static inline void P_ArchivePolyObj(polyobj_t *po) { + UINT8 diff = 0; WRITEINT32(save_p, po->id); WRITEANGLE(save_p, po->angle); WRITEFIXED(save_p, po->spawnSpot.x); WRITEFIXED(save_p, po->spawnSpot.y); + + if (po->flags != po->spawnflags) + diff |= PD_FLAGS; + if (po->translucency != 0) + diff |= PD_TRANS; + + WRITEUINT8(save_p, diff); + + if (diff & PD_FLAGS) + WRITEINT32(save_p, po->flags); + if (diff & PD_TRANS) + WRITEINT32(save_p, po->translucency); } static inline void P_UnArchivePolyObj(polyobj_t *po) @@ -2631,6 +2780,7 @@ static inline void P_UnArchivePolyObj(polyobj_t *po) INT32 id; UINT32 angle; fixed_t x, y; + UINT8 diff; // nullify all polyobject thinker pointers; // the thinkers themselves will fight over who gets the field @@ -2644,6 +2794,13 @@ static inline void P_UnArchivePolyObj(polyobj_t *po) x = READFIXED(save_p); y = READFIXED(save_p); + diff = READUINT8(save_p); + + if (diff & PD_FLAGS) + po->flags = READINT32(save_p); + if (diff & PD_TRANS) + po->translucency = READINT32(save_p); + // if the object is bad or isn't in the id hash, we can do nothing more // with it, so return now if (po->isBad || po != Polyobj_GetForNum(id)) @@ -2812,6 +2969,14 @@ static inline void P_NetArchiveSpecials(void) // Current global weather type WRITEUINT8(save_p, globalweather); + + if (metalplayback) // Is metal sonic running? + { + WRITEUINT8(save_p, 0x01); + G_SaveMetal(&save_p); + } + else + WRITEUINT8(save_p, 0x00); } // @@ -2851,6 +3016,9 @@ static void P_NetUnArchiveSpecials(void) if (curWeather != PRECIP_NONE) P_SwitchWeather(globalweather); } + + if (READUINT8(save_p) == 0x01) // metal sonic + G_LoadMetal(&save_p); } // ======================================================================= diff --git a/src/p_setup.c b/src/p_setup.c index b3e85966..ca78db05 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -642,7 +642,9 @@ static void P_LoadSectors(lumpnum_t lumpnum) ss->extra_colormap = NULL; ss->floor_xoffs = ss->ceiling_xoffs = ss->floor_yoffs = ss->ceiling_yoffs = 0; + ss->spawn_flr_xoffs = ss->spawn_ceil_xoffs = ss->spawn_flr_yoffs = ss->spawn_ceil_yoffs = 0; ss->floorpic_angle = ss->ceilingpic_angle = 0; + ss->spawn_flrpic_angle = ss->spawn_ceilpic_angle = 0; ss->bottommap = ss->midmap = ss->topmap = -1; ss->gravity = NULL; ss->cullheight = NULL; @@ -1139,6 +1141,7 @@ static void P_LoadLineDefs(lumpnum_t lumpnum) ld->frontsector = ld->backsector = NULL; ld->validcount = 0; ld->firsttag = ld->nexttag = -1; + ld->callcount = 0; // killough 11/98: fix common wad errors (missing sidedefs): if (ld->sidenum[0] == 0xffff) @@ -1380,7 +1383,6 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) { col = msd->bottomtexture; - sec->extra_colormap->fadergba = (HEX2INT(col[1]) << 4) + (HEX2INT(col[2]) << 0) + (HEX2INT(col[3]) << 12) + (HEX2INT(col[4]) << 8) + @@ -1393,7 +1395,7 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) sec->extra_colormap->fadergba += (25 << 24); } else - sec->extra_colormap->fadergba = 0x19000000; + sec->extra_colormap->fadergba = 0x19000000; // default alpha, (25 << 24) #undef ALPHA2INT #undef HEX2INT } @@ -2341,6 +2343,35 @@ static void P_LoadRecordGhosts(void) free(gpath); } +static void P_LoadNightsGhosts(void) +{ + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath = malloc(glen); + + if (!gpath) + return; + + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + + // Best Score ghost + if (cv_ghost_bestscore.value && FIL_FileExists(va("%s-score-best.lmp", gpath))) + G_AddGhost(va("%s-score-best.lmp", gpath)); + + // Best Time ghost + if (cv_ghost_besttime.value && FIL_FileExists(va("%s-time-best.lmp", gpath))) + G_AddGhost(va("%s-time-best.lmp", gpath)); + + // Last ghost + if (cv_ghost_last.value && FIL_FileExists(va("%s-last.lmp", gpath))) + G_AddGhost(va("%s-last.lmp", gpath)); + + // Guest ghost + if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) + G_AddGhost(va("%s-guest.lmp", gpath)); + + free(gpath); +} + /** Loads a level from a lump or external wad. * * \param skipprecip If true, don't spawn precipitation. @@ -2602,6 +2633,8 @@ boolean P_SetupLevel(boolean skipprecip) if (modeattacking == ATTACKING_RECORD && !demoplayback) P_LoadRecordGhosts(); + else if (modeattacking == ATTACKING_NIGHTS && !demoplayback) + P_LoadNightsGhosts(); if (G_TagGametype()) { @@ -2750,7 +2783,6 @@ boolean P_SetupLevel(boolean skipprecip) R_PrecacheLevel(); nextmapoverride = 0; - nextmapgametype = -1; skipstats = false; if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) diff --git a/src/p_spec.c b/src/p_spec.c index 3c9af246..323b93c6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -50,10 +50,6 @@ mobj_t *skyboxmo[2]; // Amount (dx, dy) vector linedef is shifted right to get scroll amount #define SCROLL_SHIFT 5 -// Factor to scale scrolling effect into mobj-carrying properties = 3/32. -// (This is so scrolling floors and objects on them can move at same speed.) -#define CARRYFACTOR ((3*FRACUNIT)/32) - /** Animated texture descriptor * This keeps track of an animated texture or an animated flat. * \sa P_UpdateSpecials, P_InitPicAnims, animdef_t @@ -107,7 +103,7 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline); static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline); static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec); static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers); -static void P_ProcessLineSpecial(line_t *line, mobj_t *mo); +static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec); static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer); static void P_AddSpikeThinker(sector_t *sec, INT32 referrer); @@ -1388,9 +1384,34 @@ static boolean PolyRotate(line_t *line) // Polyobj_OR types have override set to true prd.overRide = (line->special == 485 || line->special == 487); + if (line->flags & ML_NOCLIMB) + prd.turnobjs = 0; + else if (line->flags & ML_EFFECT4) + prd.turnobjs = 2; + else + prd.turnobjs = 1; + return EV_DoPolyObjRotate(&prd); } +// +// PolyDisplace +// +// Parses arguments for parameterized polyobject move-by-sector-heights specials +// +static boolean PolyDisplace(line_t *line) +{ + polydisplacedata_t pdd; + + pdd.polyObjNum = line->tag; + + pdd.controlSector = line->frontsector; + pdd.dx = line->dx>>8; + pdd.dy = line->dy>>8; + + return EV_DoPolyObjDisplace(&pdd); +} + #endif // ifdef POLYOBJECTS /** Changes a sector's tag. @@ -1512,13 +1533,13 @@ void T_ExecutorDelay(executor_t *e) { if (e->caller && P_MobjWasRemoved(e->caller)) // If the mobj died while we were delaying P_SetTarget(&e->caller, NULL); // Call with no mobj! - P_ProcessLineSpecial(e->line, e->caller); + P_ProcessLineSpecial(e->line, e->caller, e->sector); P_SetTarget(&e->caller, NULL); // Let the mobj know it can be removed now. P_RemoveThinker(&e->thinker); } } -static void P_AddExecutorDelay(line_t *line, mobj_t *mobj) +static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector) { executor_t *e; @@ -1529,13 +1550,12 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj) e->thinker.function.acp1 = (actionf_p1)T_ExecutorDelay; e->line = line; + e->sector = sector; e->timer = (line->backsector->ceilingheight>>FRACBITS)+(line->backsector->floorheight>>FRACBITS); P_SetTarget(&e->caller, mobj); // Use P_SetTarget to make sure the mobj doesn't get freed while we're delaying. P_AddThinker(&e->thinker); } -static sector_t *triplinecaller; - /** Used by P_LinedefExecute to check a trigger linedef's conditions * The linedef executor specials in the trigger linedef's sector are run if all conditions are met. * Return false cancels P_LinedefExecute, this happens if a condition is not met. @@ -1672,7 +1692,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller // If we were not triggered by a sector type especially for the purpose, // a Linedef Executor linedef trigger is not handling sector triggers properly, return. - else if ((!GETSECSPECIAL(caller->special, 2) || GETSECSPECIAL(caller->special, 2) > 7) && (specialtype > 320)) + else if ((!GETSECSPECIAL(caller->special, 2) || GETSECSPECIAL(caller->special, 2) > 7) && (specialtype > 322)) { CONS_Alert(CONS_WARNING, M_GetText("Linedef executor trigger isn't handling sector triggers properly!\nspecialtype = %d, if you are not a dev, report this warning instance\nalong with the wad that caused it!\n"), @@ -1737,6 +1757,15 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller return false; } break; + case 321: // continuous + case 322: // each time + // decrement calls left before triggering + if (triggerline->callcount > 0) + { + if (--triggerline->callcount > 0) + return false; + } + break; default: break; } @@ -1745,7 +1774,6 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller // Processing linedef specials // ///////////////////////////////// - triplinecaller = caller; ctlsector = triggerline->frontsector; sectori = (size_t)(ctlsector - sectors); linecnt = ctlsector->linecount; @@ -1757,9 +1785,9 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller && ctlsector->lines[i]->special < 500) { if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) - P_AddExecutorDelay(ctlsector->lines[i], actor); + P_AddExecutorDelay(ctlsector->lines[i], actor, caller); else - P_ProcessLineSpecial(ctlsector->lines[i], actor); + P_ProcessLineSpecial(ctlsector->lines[i], actor, caller); } } else // walk around the sector in a defined order @@ -1845,13 +1873,17 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller && ctlsector->lines[i]->special < 500) { if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) - P_AddExecutorDelay(ctlsector->lines[i], actor); + P_AddExecutorDelay(ctlsector->lines[i], actor, caller); else - P_ProcessLineSpecial(ctlsector->lines[i], actor); + P_ProcessLineSpecial(ctlsector->lines[i], actor, caller); } } } + // "Trigger on X calls" linedefs reset if noclimb is set + if ((specialtype == 321 || specialtype == 322) && triggerline->flags & ML_NOCLIMB) + triggerline->callcount = sides[triggerline->sidenum[0]].textureoffset>>FRACBITS; + else // These special types work only once if (specialtype == 302 // Once || specialtype == 304 // Ring count - Once @@ -1860,6 +1892,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller || specialtype == 315 // No of pushables - Once || specialtype == 318 // Unlockable trigger - Once || specialtype == 320 // Unlockable - Once + || specialtype == 321 || specialtype == 322 // Trigger on X calls - Continuous + Each Time || specialtype == 399) // Level Load triggerline->special = 0; // Clear it out @@ -1899,7 +1932,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) || lines[masterline].special == 301 // Each time || lines[masterline].special == 306 // Character ability - Each time || lines[masterline].special == 310 // CTF Red team - Each time - || lines[masterline].special == 312) // CTF Blue team - Each time + || lines[masterline].special == 312 // CTF Blue team - Each time + || lines[masterline].special == 322) // Trigger on X calls - Each Time continue; if (lines[masterline].special < 300 @@ -2149,22 +2183,20 @@ static mobj_t *P_GetObjectTypeInSectorNum(mobjtype_t type, size_t s) } /** Processes the line special triggered by an object. - * The external variable ::triplinecaller points to the sector in which the - * action was initiated; it can be NULL. Because of the A_LinedefExecute() - * action, even if non-NULL, this sector might not have the same tag as the - * linedef executor, and it might not have the linedef executor sector type. * * \param line Line with the special command on it. * \param mo mobj that triggered the line. Must be valid and non-NULL. - * \todo Get rid of the secret parameter and make ::triplinecaller actually get - * passed to the function. + * \param callsec sector in which action was initiated; this can be NULL. + * Because of the A_LinedefExecute() action, even if non-NULL, + * this sector might not have the same tag as the linedef executor, + * and it might not have the linedef executor sector type. * \todo Handle mo being NULL gracefully. T_MoveFloor() and T_MoveCeiling() * don't have an object to pass. * \todo Split up into multiple functions. * \sa P_LinedefExecute * \author Graue */ -static void P_ProcessLineSpecial(line_t *line, mobj_t *mo) +static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 secnum = -1; mobj_t *bot = NULL; @@ -2365,7 +2397,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo) if (musicnum >= NUMMUSIC || musicnum == mus_None) S_StopMusic(); else - S_ChangeMusic(mapmusic, !(line->flags & ML_NOCLIMB)); + S_ChangeMusic(mapmusic, !(line->flags & ML_EFFECT4)); // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. // if (mapmusic & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. @@ -2431,8 +2463,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo) else if (line->flags & ML_BLOCKMONSTERS) { // play the sound from calling sector's soundorg - if (triplinecaller) - S_StartSound(&triplinecaller->soundorg, sfxnum); + if (callsec) + S_StartSound(&callsec->soundorg, sfxnum); else if (mo) S_StartSound(&mo->subsector->sector->soundorg, sfxnum); } @@ -2976,7 +3008,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo) case 443: // Calls a named Lua function #ifdef HAVE_BLUA - LUAh_LinedefExecute(line, mo); + LUAh_LinedefExecute(line, mo, callsec); #else CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n"); #endif @@ -3392,9 +3424,9 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar static inline boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) { if (mo->eflags & MFE_VERTICALFLIP) - return (mo->z+mo->height == sec->ceilingheight); + return (mo->z+mo->height == sec->ceilingheight && sec->flags & SF_FLIPSPECIAL_CEILING); else - return (mo->z == sec->floorheight); + return (mo->z == sec->floorheight && sec->flags & SF_FLIPSPECIAL_FLOOR); } /** Applies a sector special to a player. @@ -3715,15 +3747,6 @@ DoneSection2: if (lines[lineindex].flags & ML_NOCLIMB) skipstats = true; - - // change the gametype using front x offset if passuse flag is given - // ...but not in single player! - if (multiplayer && lines[lineindex].flags & ML_EFFECT4) - { - INT32 xofs = sides[lines[lineindex].sidenum[0]].textureoffset; - if (xofs >= 0 && xofs < NUMGAMETYPES) - nextmapgametype = xofs; - } } } break; @@ -4861,7 +4884,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if ((flags & FF_SOLID) && (master->flags & ML_EFFECT2)) // Block all BUT player flags &= ~FF_BLOCKPLAYER; - ffloor->flags = flags; + ffloor->spawnflags = ffloor->flags = flags; ffloor->master = master; ffloor->norender = INFTICS; @@ -4927,6 +4950,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f else ffloor->alpha = 0xff; + ffloor->spawnalpha = ffloor->alpha; // save for netgames + if (flags & FF_QUICKSAND) CheckForQuicksand = true; @@ -5607,13 +5632,13 @@ void P_SpawnSpecials(INT32 fromnetsave) if (!(lines[i].flags & ML_EFFECT5)) // Align floor unless ALLTRIGGER flag is set { for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); + sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); } if (!(lines[i].flags & ML_BOUNCY)) // Align ceiling unless BOUNCY flag is set { for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); + sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); } } else // Do offsets @@ -5624,6 +5649,9 @@ void P_SpawnSpecials(INT32 fromnetsave) { sectors[s].floor_xoffs += lines[i].dx; sectors[s].floor_yoffs += lines[i].dy; + // saved for netgames + sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs; + sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs; } } @@ -5633,6 +5661,9 @@ void P_SpawnSpecials(INT32 fromnetsave) { sectors[s].ceiling_xoffs += lines[i].dx; sectors[s].ceiling_yoffs += lines[i].dy; + // saved for netgames + sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs; + sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs; } } } @@ -6305,6 +6336,20 @@ void P_SpawnSpecials(INT32 fromnetsave) case 320: break; + // Trigger on X calls + case 321: + case 322: + if (lines[i].flags & ML_NOCLIMB && sides[lines[i].sidenum[0]].rowoffset > 0) // optional "starting" count + lines[i].callcount = sides[lines[i].sidenum[0]].rowoffset>>FRACBITS; + else + lines[i].callcount = sides[lines[i].sidenum[0]].textureoffset>>FRACBITS; + if (lines[i].special == 322) // Each time + { + sec = sides[*lines[i].sidenum].sector - sectors; + P_AddEachTimeThinker(§ors[sec], &lines[i]); + } + break; + case 399: // Linedef execute on map load // This is handled in P_RunLevelLoadExecutors. break; @@ -6444,6 +6489,10 @@ void P_SpawnSpecials(INT32 fromnetsave) case 30: // Polyobj_Flag EV_DoPolyObjFlag(&lines[i]); break; + + case 31: // Polyobj_Displace + PolyDisplace(&lines[i]); + break; } } #endif @@ -6476,6 +6525,47 @@ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinker P_SpawnScrollers */ +// helper function for T_Scroll +static void P_DoScrollMove(mobj_t *thing, fixed_t dx, fixed_t dy, INT32 exclusive) +{ + fixed_t fuckaj = 0; // Nov 05 14:12:08 <+MonsterIestyn> I've heard of explicitly defined variables but this is ridiculous + if (thing->player) + { + if (!(dx | dy)) + { + thing->player->cmomx = 0; + thing->player->cmomy = 0; + } + else + { + thing->player->cmomx += dx; + thing->player->cmomy += dy; + thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); + thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); + } + } + + if (thing->player && (thing->player->pflags & PF_SPINNING) && (thing->player->rmomx || thing->player->rmomy) && !(thing->player->pflags & PF_STARTDASH)) + fuckaj = FixedDiv(549*ORIG_FRICTION,500*FRACUNIT); + else if (thing->friction != ORIG_FRICTION) + fuckaj = thing->friction; + + if (fuckaj) { + // refactor thrust for new friction + dx = FixedDiv(dx, CARRYFACTOR); + dy = FixedDiv(dy, CARRYFACTOR); + + dx = FixedMul(dx, FRACUNIT-fuckaj); + dy = FixedMul(dy, FRACUNIT-fuckaj); + } + + thing->momx += dx; + thing->momy += dy; + + if (exclusive) + thing->flags2 |= MF2_PUSHED; +} + /** Processes an active scroller. * This function, with the help of r_plane.c and r_bsp.c, supports generalized * scrolling floors and walls, with optional mobj-carrying properties, e.g. @@ -6585,26 +6675,7 @@ void T_Scroll(scroll_t *s) { // Move objects only if on floor // non-floating, and clipped. - thing->momx += dx; - thing->momy += dy; - if (thing->player) - { - if (!(dx | dy)) - { - thing->player->cmomx = 0; - thing->player->cmomy = 0; - } - else - { - thing->player->cmomx += dx; - thing->player->cmomy += dy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - - if (s->exclusive) - thing->flags2 |= MF2_PUSHED; + P_DoScrollMove(thing, dx, dy, s->exclusive); } } // end of for loop through touching_thinglist } // end of loop through sectors @@ -6619,31 +6690,12 @@ void T_Scroll(scroll_t *s) if (thing->flags2 & MF2_PUSHED) continue; - if (!((thing = node->m_thing)->flags & MF_NOCLIP) && + if (!(thing->flags & MF_NOCLIP) && (!(thing->flags & MF_NOGRAVITY || thing->z > height))) { // Move objects only if on floor or underwater, // non-floating, and clipped. - thing->momx += dx; - thing->momy += dy; - if (thing->player) - { - if (!(dx | dy)) - { - thing->player->cmomx = 0; - thing->player->cmomy = 0; - } - else - { - thing->player->cmomx += dx; - thing->player->cmomy += dy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - - if (s->exclusive) - thing->flags2 |= MF2_PUSHED; + P_DoScrollMove(thing, dx, dy, s->exclusive); } } } @@ -6682,26 +6734,7 @@ void T_Scroll(scroll_t *s) { // Move objects only if on floor or underwater, // non-floating, and clipped. - thing->momx += dx; - thing->momy += dy; - if (thing->player) - { - if (!(dx | dy)) - { - thing->player->cmomx = 0; - thing->player->cmomy = 0; - } - else - { - thing->player->cmomx += dx; - thing->player->cmomy += dy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - - if (s->exclusive) - thing->flags2 |= MF2_PUSHED; + P_DoScrollMove(thing, dx, dy, s->exclusive); } } // end of for loop through touching_thinglist } // end of loop through sectors @@ -6716,31 +6749,12 @@ void T_Scroll(scroll_t *s) if (thing->flags2 & MF2_PUSHED) continue; - if (!((thing = node->m_thing)->flags & MF_NOCLIP) && + if (!(thing->flags & MF_NOCLIP) && (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height < height))) { // Move objects only if on floor or underwater, // non-floating, and clipped. - thing->momx += dx; - thing->momy += dy; - if (thing->player) - { - if (!(dx | dy)) - { - thing->player->cmomx = 0; - thing->player->cmomy = 0; - } - else - { - thing->player->cmomx += dx; - thing->player->cmomy += dy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - - if (s->exclusive) - thing->flags2 |= MF2_PUSHED; + P_DoScrollMove(thing, dx, dy, s->exclusive); } } } @@ -7440,16 +7454,16 @@ void T_Pusher(pusher_t *p) thing = node->m_thing; if (thing->flags & (MF_NOGRAVITY | MF_NOCLIP) && !(thing->type == MT_SMALLBUBBLE - || thing->type == MT_MEDIUMBUBBLE - || thing->type == MT_EXTRALARGEBUBBLE)) + || thing->type == MT_MEDIUMBUBBLE + || thing->type == MT_EXTRALARGEBUBBLE)) continue; if (!(thing->flags & MF_PUSHABLE) && !(thing->type == MT_PLAYER - || thing->type == MT_SMALLBUBBLE - || thing->type == MT_MEDIUMBUBBLE - || thing->type == MT_EXTRALARGEBUBBLE - || thing->type == MT_LITTLETUMBLEWEED - || thing->type == MT_BIGTUMBLEWEED)) + || thing->type == MT_SMALLBUBBLE + || thing->type == MT_MEDIUMBUBBLE + || thing->type == MT_EXTRALARGEBUBBLE + || thing->type == MT_LITTLETUMBLEWEED + || thing->type == MT_BIGTUMBLEWEED)) continue; if (thing->flags2 & MF2_PUSHED) diff --git a/src/p_spec.h b/src/p_spec.h index 04152f68..7b6a5655 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -347,6 +347,7 @@ typedef struct thinker_t thinker; // Thinker for linedef executor delay line_t *line; // Pointer to line that is waiting. mobj_t *caller; // Pointer to calling mobj + sector_t *sector; // Pointer to triggering sector INT32 timer; // Delay timer } executor_t; diff --git a/src/p_tick.c b/src/p_tick.c index 9a0f8016..3b7d3683 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -523,19 +523,20 @@ static inline void P_DoTagStuff(void) //increment survivor scores if (leveltime % TICRATE == 0 && leveltime > (hidetime * TICRATE)) { - INT32 spectators = 0; + INT32 participants = 0; - for (i=0; i < MAXPLAYERS; i++) //count spectators to subtract from the player count. + for (i=0; i < MAXPLAYERS; i++) { - if (players[i].spectator) - spectators++; + if (playeringame[i] && !players[i].spectator) + participants++; } for (i=0; i < MAXPLAYERS; i++) { - if (!(players[i].pflags & PF_TAGIT) && !(players[i].pflags & PF_TAGGED) - && !players[i].spectator && playeringame[i] && players[i].playerstate == PST_LIVE) - P_AddPlayerScore(&players[i], (D_NumPlayers() - spectators) / 2); //points given is the number of participating players divided by two. + if (playeringame[i] && !players[i].spectator && players[i].playerstate == PST_LIVE + && !(players[i].pflags & (PF_TAGIT|PF_TAGGED))) + //points given is the number of participating players divided by two. + P_AddPlayerScore(&players[i], participants/2); } } } @@ -691,7 +692,7 @@ void P_Ticker(boolean run) G_WriteGhostTic(players[consoleplayer].mo); if (demoplayback) // Use Ghost data for consistency checks. G_ConsGhostTic(); - if (modeattacking == ATTACKING_RECORD) + if (modeattacking) G_GhostTicker(); } diff --git a/src/p_user.c b/src/p_user.c index a31666c9..3c2d34a6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -660,6 +660,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->mo->tracer->destscale = player->mo->scale; P_SetScale(player->mo->tracer, player->mo->scale); player->mo->tracer->eflags = (player->mo->tracer->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + player->mo->height = player->mo->tracer->height; } player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_THOKKED|PF_SPINNING|PF_DRILLING); @@ -3998,10 +3999,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) static boolean P_AnalogMove(player_t *player) { - if (netgame) - return false; - return ((player == &players[consoleplayer] && cv_analog.value) - || (player == &players[secondarydisplayplayer] && cv_analog2.value)); + return player->pflags & PF_ANALOGMODE; } // @@ -4124,7 +4122,11 @@ static void P_2dMovement(player_t *player) } else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4) + else if (player->onconveyor != 2 && player->onconveyor != 4 +#ifdef POLYOBJECTS + && player->onconveyor != 1 +#endif + ) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; @@ -4264,22 +4266,16 @@ static void P_3dMovement(player_t *player) fixed_t movepushforward = 0, movepushside = 0; INT32 mforward = 0, mbackward = 0; angle_t dangle; // replaces old quadrants bits - camera_t *thiscam; fixed_t normalspd = FixedMul(player->normalspeed, player->mo->scale); boolean analogmove = false; #ifndef OLD_MOVEMENT_CODE fixed_t oldMagnitude, newMagnitude; // Get the old momentum; this will be needed at the end of the function! -SH - oldMagnitude = R_PointToDist2(player->mo->momx, player->mo->momy, 0, 0); + oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); #endif - if (splitscreen && player == &players[secondarydisplayplayer]) - thiscam = &camera2; - else - thiscam = &camera; - - analogmove = (P_AnalogMove(player) && thiscam->chase); + analogmove = P_AnalogMove(player); cmd = &player->cmd; @@ -4306,16 +4302,13 @@ static void P_3dMovement(player_t *player) if (analogmove) { - if (player->awayviewtics) - movepushangle = player->awayviewmobj->angle; - else - movepushangle = thiscam->angle; + movepushangle = (cmd->angleturn<<16 /* not FRACBITS */); } else { movepushangle = player->mo->angle; } - movepushsideangle = movepushangle-ANGLE_90; + movepushsideangle = movepushangle-ANGLE_90; // cmomx/cmomy stands for the conveyor belt speed. if (player->onconveyor == 2) // Wind/Current @@ -4326,7 +4319,11 @@ static void P_3dMovement(player_t *player) } else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4) + else if (player->onconveyor != 2 && player->onconveyor != 4 +#ifdef POLYOBJECTS + && player->onconveyor != 1 +#endif + ) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; @@ -4482,8 +4479,6 @@ static void P_3dMovement(player_t *player) if (!(player->pflags & PF_GLIDING || player->exiting || P_PlayerInPain(player))) { angle_t controldirection; - fixed_t tempx = 0, tempy = 0; - angle_t tempangle; #ifdef OLD_MOVEMENT_CODE angle_t controlplayerdirection; boolean cforward; // controls pointing forward from the player @@ -4494,17 +4489,8 @@ static void P_3dMovement(player_t *player) #endif // Calculate the angle at which the controls are pointing // to figure out the proper mforward and mbackward. - tempangle = movepushangle; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->forwardmove*FRACUNIT,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->forwardmove*FRACUNIT,FINESINE(tempangle)); - - tempangle = movepushsideangle; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->sidemove*FRACUNIT,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->sidemove*FRACUNIT,FINESINE(tempangle)); - - controldirection = R_PointToAngle2(0, 0, tempx, tempy); + // (Why was it so complicated before? ~Red) + controldirection = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+movepushangle; #ifdef OLD_MOVEMENT_CODE controlplayerdirection = player->mo->angle; @@ -4624,22 +4610,27 @@ static void P_3dMovement(player_t *player) // If "no" to 2, normalize to topspeed, so we can't suddenly run faster than it of our own accord. // If "no" to 1, we're not reaching any limits yet, so ignore this entirely! // -Shadow Hog - newMagnitude = R_PointToDist2(player->mo->momx, player->mo->momy, 0, 0); + newMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0); if (newMagnitude > topspeed) { + fixed_t tempmomx, tempmomy; if (oldMagnitude > topspeed) { if (newMagnitude > oldMagnitude) { - player->mo->momx = FixedMul(FixedDiv(player->mo->momx, newMagnitude), oldMagnitude); - player->mo->momy = FixedMul(FixedDiv(player->mo->momy, newMagnitude), oldMagnitude); + tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), oldMagnitude); + tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), oldMagnitude); + player->mo->momx = tempmomx + player->cmomx; + player->mo->momy = tempmomy + player->cmomy; } // else do nothing } else { - player->mo->momx = FixedMul(FixedDiv(player->mo->momx, newMagnitude), topspeed); - player->mo->momy = FixedMul(FixedDiv(player->mo->momy, newMagnitude), topspeed); + tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), topspeed); + tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), topspeed); + player->mo->momx = tempmomx + player->cmomx; + player->mo->momy = tempmomy + player->cmomy; } } #endif @@ -6060,6 +6051,7 @@ static void P_SkidStuff(player_t *player) particle->eflags |= player->mo->eflags & MFE_VERTICALFLIP; P_SetScale(particle, player->mo->scale >> 2); particle->destscale = player->mo->scale << 2; + particle->scalespeed = FixedMul(particle->scalespeed, player->mo->scale); // scale the scaling speed! P_SetObjectMomZ(particle, FRACUNIT, false); S_StartSound(player->mo, sfx_s3k7e); // the proper "Knuckles eats dirt" sfx. } @@ -6080,6 +6072,7 @@ static void P_SkidStuff(player_t *player) particle->eflags |= player->mo->eflags & MFE_VERTICALFLIP; P_SetScale(particle, player->mo->scale >> 2); particle->destscale = player->mo->scale << 2; + particle->scalespeed = FixedMul(particle->scalespeed, player->mo->scale); // scale the scaling speed! P_SetObjectMomZ(particle, FRACUNIT, false); } } @@ -6120,17 +6113,11 @@ static void P_MovePlayer(player_t *player) ticcmd_t *cmd; INT32 i; - camera_t *thiscam; fixed_t runspd; if (countdowntimeup) return; - if (splitscreen && player == &players[secondarydisplayplayer]) - thiscam = &camera2; - else - thiscam = &camera; - if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9]) { player->mo->momx = player->mo->momy = player->mo->momz = 0; @@ -6256,7 +6243,7 @@ static void P_MovePlayer(player_t *player) P_2dMovement(player); else { - if (!player->climbing && (!P_AnalogMove(player) || player->pflags & PF_SPINNING)) + if (!player->climbing && (!P_AnalogMove(player))) player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */); ticruned++; @@ -6572,31 +6559,45 @@ static void P_MovePlayer(player_t *player) ////////////////// // This really looks like it should be moved to P_3dMovement. -Red - if (P_AnalogMove(player) && thiscam->chase + if (P_AnalogMove(player) && (cmd->forwardmove != 0 || cmd->sidemove != 0) && !player->climbing && !twodlevel && !(player->mo->flags2 & MF2_TWOD)) { // If travelling slow enough, face the way the controls // point and not your direction of movement. if (player->speed < FixedMul(5*FRACUNIT, player->mo->scale) || player->pflags & PF_GLIDING || !onground) { - fixed_t tempx = 0, tempy = 0; angle_t tempangle; - if (player->awayviewtics) - tempangle = player->awayviewmobj->angle; - else - tempangle = thiscam->angle; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->forwardmove*FRACUNIT,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->forwardmove*FRACUNIT,FINESINE(tempangle)); + tempangle = (cmd->angleturn << 16); - tempangle <<= ANGLETOFINESHIFT; - tempangle -= ANGLE_90; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->sidemove*FRACUNIT,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->sidemove*FRACUNIT,FINESINE(tempangle)); +#ifdef REDSANALOG // Ease to it. Chillax. ~Red + tempangle += R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT); + { + fixed_t tweenvalue = max(abs(cmd->forwardmove), abs(cmd->sidemove)); - player->mo->angle = R_PointToAngle2(0, 0, tempx, tempy); + if (tweenvalue < 10 && (cmd->buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) { + tempangle = (cmd->angleturn << 16); + tweenvalue = 16; + } + + tweenvalue *= tweenvalue*tweenvalue*1536; + + //if (player->pflags & PF_GLIDING) + //tweenvalue >>= 1; + + tempangle -= player->mo->angle; + + if (tempangle < ANGLE_180 && tempangle > tweenvalue) + player->mo->angle += tweenvalue; + else if (tempangle >= ANGLE_180 && InvAngle(tempangle) > tweenvalue) + player->mo->angle -= tweenvalue; + else + player->mo->angle += tempangle; + } +#else + // Less math this way ~Red + player->mo->angle = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+tempangle; +#endif } // Otherwise, face the direction you're travelling. else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_ROLL @@ -7559,19 +7560,20 @@ static void CV_CamRotate2_OnChange(void) CV_SetValue(&cv_cam2_rotate, cv_cam2_rotate.value % 360); } +static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0, NULL}}; static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {45, "MAX"}, {0, NULL}}; static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}}; consvar_t cv_cam_dist = {"cam_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_height = {"cam_height", "20", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam_speed = {"cam_speed", "0.25", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_speed = {"cam_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_dist = {"cam2_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_height = {"cam2_height", "20", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_speed = {"cam2_speed", "0.25", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_speed = {"cam2_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -7724,6 +7726,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camheight = FixedMul(cv_cam2_height.value, mo->scale); } +#ifdef REDSANALOG + if (P_AnalogMove(player) && (player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)) { + camstill = true; + + if (camspeed < 4*FRACUNIT/5) + camspeed = 4*FRACUNIT/5; + } +#endif // REDSANALOG + if (mo->eflags & MFE_VERTICALFLIP) camheight += thiscam->height; @@ -7772,6 +7783,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (!objectplacing && !(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->pflags & PF_NIGHTSMODE)) { +#ifdef REDSANALOG + if ((player->cmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT)); else +#endif if (player->cmd.buttons & BT_CAMLEFT) { if (thiscam == &camera) @@ -8569,6 +8583,9 @@ void P_PlayerThink(player_t *player) // check water content, set stuff in mobj P_MobjCheckWater(player->mo); +#ifdef POLYOBJECTS + if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) +#endif player->onconveyor = 0; // check special sectors : damage & secrets @@ -8707,6 +8724,11 @@ void P_PlayerThink(player_t *player) if (!player->mo) return; // P_MovePlayer removed player->mo. +#ifdef POLYOBJECTS + if (player->onconveyor == 1) + player->cmomy = player->cmomx = 0; +#endif + P_DoSuperStuff(player); P_CheckSneakerAndLivesTimer(player); P_DoBubbleBreath(player); // Spawn Sonic's bubbles diff --git a/src/r_bsp.c b/src/r_bsp.c index 5a90f1fc..e5e0942e 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -192,6 +192,14 @@ void R_ClearClipSegs(void) solidsegs[1].last = 0x7fffffff; newend = solidsegs + 2; } +void R_PortalClearClipSegs(INT32 start, INT32 end) +{ + solidsegs[0].first = -0x7fffffff; + solidsegs[0].last = start-1; + solidsegs[1].first = end; + solidsegs[1].last = 0x7fffffff; + newend = solidsegs + 2; +} // R_DoorClosed @@ -423,9 +431,9 @@ static void R_AddLine(seg_t *line) backsector = line->backsector; // Portal line - if (line->linedef->special == 40) + if (line->linedef->special == 40 && P_PointOnLineSide(viewx, viewy, line->linedef) == 0) { - if (portalrender < PORTAL_LIMIT) + if (portalrender < cv_maxportals.value) { // Find the other side! INT32 line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, -1); @@ -433,8 +441,9 @@ static void R_AddLine(seg_t *line) line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2); if (line2 >= 0) // found it! { - R_AddPortal(line->linedef-lines, line2); // Remember the lines for later rendering - return; // Don't fill in that space now! + R_AddPortal(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering + //return; // Don't fill in that space now! + goto clipsolid; } } // Recursed TOO FAR (viewing a portal within a portal) @@ -683,6 +692,33 @@ void R_SortPolyObjects(subsector_t *sub) } } +// +// R_PolysegCompare +// +// Callback for qsort to sort the segs of a polyobject. Returns such that the +// closer one is sorted first. I sure hope this doesn't break anything. -Red +// +static int R_PolysegCompare(const void *p1, const void *p2) +{ + const seg_t *seg1 = *(const seg_t * const *)p1; + const seg_t *seg2 = *(const seg_t * const *)p2; + fixed_t dist1, dist2; + + // TODO might be a better way to get distance? +#define vxdist(v) FixedMul(R_PointToDist(v->x, v->y), FINECOSINE((R_PointToAngle(v->x, v->y)-viewangle)>>ANGLETOFINESHIFT))+0xFFFFFFF + + dist1 = min(vxdist(seg1->v1), vxdist(seg1->v2)); + dist2 = min(vxdist(seg2->v1), vxdist(seg2->v2)); + + if (dist1 == dist2) { // Segs connect toward the front, so use the back verts to determine order! + dist1 = max(vxdist(seg1->v1), vxdist(seg1->v2)); + dist2 = max(vxdist(seg2->v1), vxdist(seg2->v2)); + } +#undef vxdist + + return dist1-dist2; +} + // // R_AddPolyObjects // @@ -709,6 +745,7 @@ static void R_AddPolyObjects(subsector_t *sub) // render polyobjects for (i = 0; i < numpolys; ++i) { + qsort(po_ptrs[i]->segs, po_ptrs[i]->segCount, sizeof(seg_t *), R_PolysegCompare); for (j = 0; j < po_ptrs[i]->segCount; ++j) R_AddLine(po_ptrs[i]->segs[j]); } @@ -809,43 +846,10 @@ static void R_Subsector(size_t num) if (frontsector->cullheight) { - if (frontsector->cullheight->flags & ML_NOCLIMB) // Group culling + if (R_DoCulling(frontsector->cullheight, viewsector->cullheight, viewz, *rover->bottomheight, *rover->topheight)) { - // Make sure this is part of the same group - if (viewsector->cullheight && viewsector->cullheight->frontsector - == frontsector->cullheight->frontsector) - { - // OK, we can cull - if (viewz > frontsector->cullheight->frontsector->floorheight - && *rover->topheight < frontsector->cullheight->frontsector->floorheight) // Cull if below plane - { - rover->norender = leveltime; - continue; - } - - if (*rover->bottomheight > frontsector->cullheight->frontsector->floorheight - && viewz <= frontsector->cullheight->frontsector->floorheight) // Cull if above plane - { - rover->norender = leveltime; - continue; - } - } - } - else // Quick culling - { - if (viewz > frontsector->cullheight->frontsector->floorheight - && *rover->topheight < frontsector->cullheight->frontsector->floorheight) // Cull if below plane - { - rover->norender = leveltime; - continue; - } - - if (*rover->bottomheight > frontsector->cullheight->frontsector->floorheight - && viewz <= frontsector->cullheight->frontsector->floorheight) // Cull if above plane - { - rover->norender = leveltime; - continue; - } + rover->norender = leveltime; + continue; } } @@ -909,15 +913,28 @@ static void R_Subsector(size_t num) && polysec->floorheight >= frontsector->floorheight && (viewz < polysec->floorheight)) { + fixed_t xoff, yoff; + xoff = polysec->floor_xoffs; + yoff = polysec->floor_yoffs; + + if (po->angle != 0) { + angle_t fineshift = po->angle >> ANGLETOFINESHIFT; + + xoff -= FixedMul(FINECOSINE(fineshift), po->centerPt.x)+FixedMul(FINESINE(fineshift), po->centerPt.y); + yoff -= FixedMul(FINESINE(fineshift), po->centerPt.x)-FixedMul(FINECOSINE(fineshift), po->centerPt.y); + } else { + xoff -= po->centerPt.x; + yoff += po->centerPt.y; + } + light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); light = 0; ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, - polysec->lightlevel, polysec->floor_xoffs, - polysec->floor_yoffs, - polysec->floorpic_angle, + polysec->lightlevel, xoff, yoff, + polysec->floorpic_angle-po->angle, NULL, NULL); - ffloor[numffloors].plane->polyobj = true; + ffloor[numffloors].plane->polyobj = po; ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].polyobj = po; @@ -934,12 +951,27 @@ static void R_Subsector(size_t num) && polysec->ceilingheight <= frontsector->ceilingheight && (viewz > polysec->ceilingheight)) { + fixed_t xoff, yoff; + xoff = polysec->ceiling_xoffs; + yoff = polysec->ceiling_yoffs; + + if (po->angle != 0) { + angle_t fineshift = po->angle >> ANGLETOFINESHIFT; + + xoff -= FixedMul(FINECOSINE(fineshift), po->centerPt.x)+FixedMul(FINESINE(fineshift), po->centerPt.y); + yoff -= FixedMul(FINESINE(fineshift), po->centerPt.x)-FixedMul(FINECOSINE(fineshift), po->centerPt.y); + } else { + xoff -= po->centerPt.x; + yoff += po->centerPt.y; + } + light = R_GetPlaneLight(frontsector, polysec->ceilingheight, viewz < polysec->ceilingheight); light = 0; ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, - polysec->lightlevel, polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle, + polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle, NULL, NULL); - ffloor[numffloors].plane->polyobj = true; + ffloor[numffloors].plane->polyobj = po; + ffloor[numffloors].polyobj = po; ffloor[numffloors].height = polysec->ceilingheight; // ffloor[numffloors].ffloor = rover; @@ -1147,5 +1179,14 @@ void R_RenderBSPNode(INT32 bspnum) bspnum = bsp->children[side^1]; } + + // PORTAL CULLING + if (portalcullsector) { + sector_t *sect = subsectors[bspnum & ~NF_SUBSECTOR].sector; + if (sect != portalcullsector) + return; + portalcullsector = NULL; + } + R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); } diff --git a/src/r_bsp.h b/src/r_bsp.h index a765b656..20a80d89 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -37,9 +37,10 @@ typedef void (*drawfunc_t)(INT32 start, INT32 stop); // BSP? void R_ClearClipSegs(void); +void R_PortalClearClipSegs(INT32 start, INT32 end); void R_ClearDrawSegs(void); void R_RenderBSPNode(INT32 bspnum); -void R_AddPortal(INT32 line1, INT32 line2); +void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2); #ifdef POLYOBJECTS void R_SortPolyObjects(subsector_t *sub); diff --git a/src/r_defs.h b/src/r_defs.h index 5a5eaf97..7f8bd7e1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -167,6 +167,10 @@ typedef struct ffloor_s INT32 lastlight; INT32 alpha; tic_t norender; // for culling + + // these are saved for netgames, so do not let Lua touch these! + ffloortype_e spawnflags; // flags the 3D floor spawned with + INT32 spawnalpha; // alpha the 3D floor spawned with } ffloor_t; @@ -332,6 +336,16 @@ typedef struct sector_s // list of precipitation mobjs in sector precipmobj_t *preciplist; struct mprecipsecnode_s *touching_preciplist; + + // these are saved for netgames, so do not let Lua touch these! + + // offsets sector spawned with (via linedef type 7) + fixed_t spawn_flr_xoffs, spawn_flr_yoffs; + fixed_t spawn_ceil_xoffs, spawn_ceil_yoffs; + + // flag angles sector spawned with (via linedef type 7) + angle_t spawn_flrpic_angle; + angle_t spawn_ceilpic_angle; } sector_t; // @@ -381,6 +395,7 @@ typedef struct line_s #endif char *text; // a concatination of all front and back texture names, for linedef specials that require a string. + INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 } line_t; // diff --git a/src/r_main.c b/src/r_main.c index 231dfe29..f2c641f6 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -73,14 +73,29 @@ player_t *viewplayer; // PORTALS! // You can thank and/or curse JTE for these. UINT8 portalrender; +sector_t *portalcullsector; typedef struct portal_pair { INT32 line1; INT32 line2; UINT8 pass; struct portal_pair *next; + + fixed_t viewx; + fixed_t viewy; + fixed_t viewz; + angle_t viewangle; + + INT32 start; + INT32 end; + INT16 *ceilingclip; + INT16 *floorclip; + fixed_t *frontscale; + size_t seg; } portal_pair; portal_pair *portal_base, *portal_cap; +line_t *portalclipline; +INT32 portalclipstart, portalclipend; // // precalculated math tables @@ -123,17 +138,21 @@ static CV_PossibleValue_t drawdist_cons_t[] = { {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}}; static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}}; static void ChaseCam_OnChange(void); static void ChaseCam2_OnChange(void); +static void FlipCam_OnChange(void); +static void FlipCam2_OnChange(void); void SendWeaponPref(void); +void SendWeaponPref2(void); consvar_t cv_tailspickup = {"tailspickup", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam = {"chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, SendWeaponPref, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, SendWeaponPref, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -151,6 +170,8 @@ consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensit // Okay, whoever said homremoval causes a performance hit should be shot. consvar_t cv_homremoval = {"homremoval", "No", CV_SAVE, homremoval_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + void SplitScreen_OnChange(void) { if (!cv_debug && netgame) @@ -207,6 +228,26 @@ static void ChaseCam2_OnChange(void) CV_SetValue(&cv_analog2, 1); } +static void FlipCam_OnChange(void) +{ + if (cv_flipcam.value) + players[consoleplayer].pflags |= PF_FLIPCAM; + else + players[consoleplayer].pflags &= ~PF_FLIPCAM; + + SendWeaponPref(); +} + +static void FlipCam2_OnChange(void) +{ + if (cv_flipcam2.value) + players[secondarydisplayplayer].pflags |= PF_FLIPCAM; + else + players[secondarydisplayplayer].pflags &= ~PF_FLIPCAM; + + SendWeaponPref2(); +} + // // R_PointOnSide // Traverse BSP (sub) tree, @@ -425,6 +466,47 @@ fixed_t R_ScaleFromGlobalAngle(angle_t visangle) return 64*FRACUNIT; } +// +// R_DoCulling +// Checks viewz and top/bottom heights of an item against culling planes +// Returns true if the item is to be culled, i.e it shouldn't be drawn! +// if ML_NOCLIMB is set, the camera view is required to be in the same area for culling to occur +boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph) +{ + fixed_t cullplane; + + if (!cullheight) + return false; + + cullplane = cullheight->frontsector->floorheight; + if (cullheight->flags & ML_NOCLIMB) // Group culling + { + if (!viewcullheight) + return false; + + // Make sure this is part of the same group + if (viewcullheight->frontsector == cullheight->frontsector) + { + // OK, we can cull + if (vz > cullplane && toph < cullplane) // Cull if below plane + return true; + + if (bottomh > cullplane && vz <= cullplane) // Cull if above plane + return true; + } + } + else // Quick culling + { + if (vz > cullplane && toph < cullplane) // Cull if below plane + return true; + + if (bottomh > cullplane && vz <= cullplane) // Cull if above plane + return true; + } + + return false; +} + // // R_InitTextureMapping // @@ -1070,7 +1152,9 @@ void R_SetupFrame(player_t *player, boolean skybox) centeryfrac = centery<dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); #endif - R_SetupFrame(player, false); + //R_SetupFrame(player, false); + viewx = portal->viewx; + viewy = portal->viewy; + viewz = portal->viewz; + + viewangle = portal->viewangle; + viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); + viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + + portalcullsector = dest->frontsector; + viewsector = dest->frontsector; + portalclipline = dest; + portalclipstart = portal->start; + portalclipend = portal->end; // Offset the portal view by the linedef centers @@ -1090,6 +1187,9 @@ static void R_PortalFrame(player_t *player, line_t *start, line_t *dest) dest_c.x = (dest->v1->x + dest->v2->x) / 2; dest_c.y = (dest->v1->y + dest->v2->y) / 2; + // Heights! + viewz += dest->frontsector->floorheight - start->frontsector->floorheight; + // calculate the difference in position and rotation! #ifdef ANGLED_PORTALS if (dangle == 0) @@ -1104,22 +1204,51 @@ static void R_PortalFrame(player_t *player, line_t *start, line_t *dest) viewangle += dangle; viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - CONS_Printf("dangle == %u\n", AngleFixed(dangle)>>FRACBITS); + //CONS_Printf("dangle == %u\n", AngleFixed(dangle)>>FRACBITS); // ???? - viewx = dest_c.x - viewx; - viewy = dest_c.y - viewy; + { + fixed_t disttopoint; + angle_t angtopoint; + + disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); + angtopoint += dangle; + + viewx = dest_c.x+FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + viewy = dest_c.y+FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + } #endif } -void R_AddPortal(INT32 line1, INT32 line2) +void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2) { portal_pair *portal = Z_Malloc(sizeof(portal_pair), PU_LEVEL, NULL); + INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); + INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1), PU_LEVEL, NULL); + fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1), PU_LEVEL, NULL); + portal->line1 = line1; portal->line2 = line2; portal->pass = portalrender+1; portal->next = NULL; + R_PortalStoreClipValues(x1, x2, ceilingclipsave, floorclipsave, frontscalesave); + + portal->ceilingclip = ceilingclipsave; + portal->floorclip = floorclipsave; + portal->frontscale = frontscalesave; + + portal->start = x1; + portal->end = x2; + + portal->seg = ds_p-drawsegs; + + portal->viewx = viewx; + portal->viewy = viewy; + portal->viewz = viewz; + portal->viewangle = viewangle; + if (!portal_base) { portal_base = portal; @@ -1203,6 +1332,7 @@ void R_RenderPlayerView(player_t *player) ProfZeroTimer(); #endif R_RenderBSPNode((INT32)numnodes - 1); + R_ClipSprites(); #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add @@ -1211,6 +1341,41 @@ void R_RenderPlayerView(player_t *player) #endif //profile stuff --------------------------------------------------------- + // PORTAL RENDERING + for(portal = portal_base; portal; portal = portal_base) + { + // render the portal + CONS_Debug(DBG_RENDER, "Rendering portal from line %d to %d\n", portal->line1, portal->line2); + portalrender = portal->pass; + + R_PortalFrame(&lines[portal->line1], &lines[portal->line2], portal); + + R_PortalClearClipSegs(portal->start, portal->end); + + R_PortalRestoreClipValues(portal->start, portal->end, portal->ceilingclip, portal->floorclip, portal->frontscale); + + validcount++; + + if (portal->seg) + { + // Push the portal's old drawseg out of the way so it isn't interfering with sprite clipping. -Red + drawseg_t *seg = drawsegs+portal->seg; + seg->scale1 = 0; + seg->scale2 = 0; + } + + R_RenderBSPNode((INT32)numnodes - 1); + R_ClipSprites(); + //R_DrawPlanes(); + //R_DrawMasked(); + + // okay done. free it. + portalcullsector = NULL; // Just in case... + portal_base = portal->next; + Z_Free(portal); + } + // END PORTAL RENDERING + R_DrawPlanes(); #ifdef FLOORSPLATS R_DrawVisibleFloorSplats(); @@ -1219,24 +1384,6 @@ void R_RenderPlayerView(player_t *player) // And now 3D floors/sides! R_DrawMasked(); - // PORTAL RENDERING - for(portal = portal_base; portal; portal = portal_base) - { - // render the portal - CONS_Debug(DBG_RENDER, "Rendering portal from line %d to %d\n", portal->line1, portal->line2); - portalrender = portal->pass; - R_PortalFrame(player, &lines[portal->line1], &lines[portal->line2]); - validcount++; - R_RenderBSPNode((INT32)numnodes - 1); - R_DrawPlanes(); - R_DrawMasked(); - - // okay done. free it. - portal_base = portal->next; - Z_Free(portal); - } - // END PORTAL RENDERING - // Check for new console commands. NetUpdate(); } @@ -1286,6 +1433,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_showhud); CV_RegisterVar(&cv_translucenthud); + CV_RegisterVar(&cv_maxportals); + // Default viewheight is changeable, // initialized to standard viewheight CV_RegisterVar(&cv_viewheight); diff --git a/src/r_main.h b/src/r_main.h index a367960c..0d3f2def 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -77,6 +77,8 @@ fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); +boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); + // // REFRESH - the actual rendering functions. // diff --git a/src/r_plane.c b/src/r_plane.c index 7e1764fc..dcff25c1 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -106,6 +106,50 @@ void R_InitPlanes(void) // FIXME: unused } +// R_PortalStoreClipValues +// Saves clipping values for later. -Red +void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale) +{ + INT32 i; + for (i = 0; i < end-start; i++) + { + *ceil = ceilingclip[start+i]; + ceil++; + *floor = floorclip[start+i]; + floor++; + *scale = frontscale[start+i]; + scale++; + } +} + +// R_PortalRestoreClipValues +// Inverse of the above. Restores the old value! +void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale) +{ + INT32 i; + for (i = 0; i < end-start; i++) + { + ceilingclip[start+i] = *ceil; + ceil++; + floorclip[start+i] = *floor; + floor++; + frontscale[start+i] = *scale; + scale++; + } + + // HACKS FOLLOW + for (i = 0; i < start; i++) + { + floorclip[i] = -1; + ceilingclip[i] = (INT16)viewheight; + } + for (i = end; i < vid.width; i++) + { + floorclip[i] = -1; + ceilingclip[i] = (INT16)viewheight; + } +} + //profile stuff --------------------------------------------------------- //#define TIMING @@ -409,6 +453,10 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, for (check = visplanes[hash]; check; check = check->next) { +#ifdef POLYOBJECTS_PLANES + if (check->polyobj && pfloor) + continue; +#endif if (height == check->height && picnum == check->picnum && lightlevel == check->lightlevel && xoff == check->xoffs && yoff == check->yoffs @@ -434,6 +482,9 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, check->viewz = viewz; check->viewangle = viewangle + plangle; check->plangle = plangle; +#ifdef POLYOBJECTS_PLANES + check->polyobj = NULL; +#endif memset(check->top, 0xff, sizeof (check->top)); memset(check->bottom, 0x00, sizeof (check->bottom)); @@ -590,6 +641,7 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2) void R_DrawPlanes(void) { visplane_t *pl; + angle_t skyviewangle = viewangle; // the flat angle itself can mess with viewangle, so do your own angle instead! INT32 x; INT32 angle; INT32 i; @@ -628,7 +680,7 @@ void R_DrawPlanes(void) if (dc_yl <= dc_yh) { - angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; + angle = (skyviewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; dc_x = x; dc_source = R_GetColumn(skytexture, @@ -666,6 +718,42 @@ void R_DrawSinglePlane(visplane_t *pl) itswater = false; #endif spanfunc = basespanfunc; + +#ifdef POLYOBJECTS_PLANES + if (pl->polyobj && pl->polyobj->translucency != 0) { + spanfunc = R_DrawTranslucentSpan_8; + + // Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red) + if (pl->polyobj->translucency >= 10) + return; // Don't even draw it + else if (pl->polyobj->translucency == 9) + ds_transmap = ((tr_trans90)<polyobj->translucency == 8) + ds_transmap = ((tr_trans80)<polyobj->translucency == 7) + ds_transmap = ((tr_trans70)<polyobj->translucency == 6) + ds_transmap = ((tr_trans60)<polyobj->translucency == 5) + ds_transmap = ((tr_trans50)<polyobj->translucency == 4) + ds_transmap = ((tr_trans40)<polyobj->translucency == 3) + ds_transmap = ((tr_trans30)<polyobj->translucency == 2) + ds_transmap = ((tr_trans20)<polyobj->translucency == 1) + ds_transmap = ((tr_trans10)<extra_colormap && pl->extra_colormap->fog) + light = (pl->lightlevel >> LIGHTSEGSHIFT); + else + light = LIGHTLEVELS-1; + + } else +#endif if (pl->ffloor) { // Don't draw planes that shouldn't be drawn. diff --git a/src/r_plane.h b/src/r_plane.h index 1f046588..f3a7f573 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -59,7 +59,7 @@ typedef struct visplane_s struct ffloor_s *ffloor; #ifdef POLYOBJECTS_PLANES - boolean polyobj; + polyobj_t *polyobj; #endif } visplane_t; @@ -83,6 +83,8 @@ extern fixed_t *yslope; extern fixed_t distscale[MAXVIDWIDTH]; void R_InitPlanes(void); +void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); +void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); void R_ClearPlanes(void); void R_MapPlane(INT32 y, INT32 x1, INT32 x2); diff --git a/src/r_segs.c b/src/r_segs.c index 1070bff7..c73cfdf9 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -589,7 +589,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // draw the texture col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); -#ifdef POLYOBJECTS_PLANES +//#ifdef POLYOBJECTS_PLANES +#if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES)) { fixed_t my_topscreen; @@ -611,7 +612,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) for (i = 0; i < numffloors; i++) { - if (!ffloor[i].polyobj) + if (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg) continue; if (ffloor[i].height < viewz) @@ -650,6 +651,15 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) colfunc = wallcolfunc; } +// Loop through R_DrawMaskedColumn calls +static void R_DrawRepeatMaskedColumn(column_t *col) +{ + do { + R_DrawMaskedColumn(col); + sprtopscreen += dc_texheight*spryscale; + } while (sprtopscreen < sprbotscreen); +} + // // R_RenderThickSideRange // Renders all the thick sides in the given range. @@ -836,7 +846,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // are not stored per-column with post info anymore in Doom Legacy if (textures[texnum]->holes) - colfunc_2s = R_DrawMaskedColumn; //render the usual 2sided single-patch packed texture + colfunc_2s = R_DrawRepeatMaskedColumn; //render the usual 2sided single-patch packed texture else { colfunc_2s = R_Render2sidedMultiPatchColumn; //render multipatch with no holes (no post_t info) @@ -1120,8 +1130,16 @@ static void R_RenderSegLoop (void) for (i = 0; i < numffloors; i++) { #ifdef POLYOBJECTS_PLANES - if (curline->polyseg && !ffloor[i].polyobj) - continue; + //if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)) + //continue; // Causes issues with FOF planes in The Wall -Red + + // FIXME hack to fix planes disappearing when a seg goes behind the camera. This NEEDS to be changed to be done properly. -Red + if (curline->polyseg) { + if (ffloor[i].plane->minx > rw_x) + ffloor[i].plane->minx = rw_x; + else if (ffloor[i].plane->maxx < rw_x) + ffloor[i].plane->maxx = rw_x; + } #endif if (ffloor[i].height < viewz) @@ -1135,6 +1153,13 @@ static void R_RenderSegLoop (void) if (bottom_w > bottom) bottom_w = bottom; +#ifdef POLYOBJECTS_PLANES + // Polyobject-specific hack to fix plane leaking -Red + if (curline->polyseg && ffloor[i].polyobj && ffloor[i].polyobj == curline->polyseg && top_w >= bottom_w) { + ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF; + } else +#endif + if (top_w <= bottom_w) { ffloor[i].plane->top[rw_x] = (INT16)top_w; @@ -1152,6 +1177,13 @@ static void R_RenderSegLoop (void) if (bottom_w > bottom) bottom_w = bottom; +#ifdef POLYOBJECTS_PLANES + // Polyobject-specific hack to fix plane leaking -Red + if (curline->polyseg && ffloor[i].polyobj && ffloor[i].polyobj == curline->polyseg && top_w >= bottom_w) { + ffloor[i].plane->top[rw_x] = ffloor[i].plane->bottom[rw_x] = 0xFFFF; + } else +#endif + if (top_w <= bottom_w) { ffloor[i].plane->top[rw_x] = (INT16)top_w; @@ -1327,9 +1359,9 @@ static void R_RenderSegLoop (void) for (i = 0; i < numffloors; i++) { -#ifdef POLYOBJECTS_PLANES - if (curline->polyseg && !ffloor[i].polyobj) - continue; +#if 0 //#ifdef POLYOBJECTS_PLANES + if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)) + continue; // Causes issues with FOF planes in The Wall -Red #endif ffloor[i].f_frac += ffloor[i].f_step; @@ -1339,9 +1371,9 @@ static void R_RenderSegLoop (void) { INT32 y_w; -#ifdef POLYOBJECTS_PLANES - if (curline->polyseg && !ffloor[i].polyobj) - continue; +#if 0 //#ifdef POLYOBJECTS_PLANES + if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)) + continue; // Causes issues with FOF planes in The Wall -Red #endif y_w = ffloor[i].b_frac >> HEIGHTBITS; @@ -1488,9 +1520,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (i = 0; i < numffloors; i++) { -#ifdef POLYOBJECTS_PLANES - if (ds_p->curline->polyseg && !ffloor[i].polyobj) - continue; +#if 0 //#ifdef POLYOBJECTS_PLANES + if (ds_p->curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != ds_p->curline->polyseg)) + continue; // Causes issues with FOF planes in The Wall -Red #endif ffloor[i].f_pos = ffloor[i].height - viewz; } @@ -1989,8 +2021,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (i = 0; i < numffloors; i++) { -// if (curline->polyseg && !ffloor[i].polyobj) -// continue; +#if 0 //#ifdef POLYOBJECTS_PLANES + if (curline->polyseg && (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)) + continue; // Causes issues with FOF planes in The Wall -Red +#endif ffloor[i].f_pos >>= 4; ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); diff --git a/src/r_state.h b/src/r_state.h index aec0a648..dc1ed931 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -88,8 +88,12 @@ extern boolean viewsky, skyVisible; extern sector_t *viewsector; extern player_t *viewplayer; extern UINT8 portalrender; +extern sector_t *portalcullsector; +extern line_t *portalclipline; +extern INT32 portalclipstart, portalclipend; extern consvar_t cv_allowmlook; +extern consvar_t cv_maxportals; extern angle_t clipangle; extern angle_t doubleclipangle; diff --git a/src/r_things.c b/src/r_things.c index c0f33daf..6372ddb4 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -489,6 +489,7 @@ void R_DelSpriteDefs(UINT16 wadnum) // GAME FUNCTIONS // static UINT32 visspritecount; +static UINT32 clippedvissprites; static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; @@ -546,7 +547,7 @@ void R_InitSprites(void) // void R_ClearSprites(void) { - visspritecount = 0; + visspritecount = clippedvissprites = 0; } static inline void R_ResetVisSpriteChunks(void) @@ -608,8 +609,7 @@ void R_DrawMaskedColumn(column_t *column) topdelta += prevdelta; prevdelta = topdelta; topscreen = sprtopscreen + spryscale*topdelta; - bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length - : sprbotscreen + spryscale*column->length; + bottomscreen = topscreen + spryscale*column->length; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; @@ -1157,6 +1157,16 @@ static void R_ProjectSprite(mobj_t *thing) if (x2 < 0) return; + // PORTAL SPRITE CLIPPING + if (portalrender) + { + if (x2 < portalclipstart || x1 > portalclipend) + return; + + if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) + return; + } + //SoM: 3/17/2000: Disregard sprites that are out of view.. if (thing->eflags & MFE_VERTICALFLIP) { @@ -1174,29 +1184,8 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->cullheight) { - fixed_t cullplane = thing->subsector->sector->cullheight->frontsector->floorheight; - if (thing->subsector->sector->cullheight->flags & ML_NOCLIMB) // Group culling - { - // Make sure this is part of the same group - if (viewsector->cullheight && viewsector->cullheight->frontsector - == thing->subsector->sector->cullheight->frontsector) - { - // OK, we can cull - if (viewz > cullplane && gzt < cullplane) // Cull if below plane - return; - - if (gz > cullplane && viewz <= cullplane) // Cull if above plane - return; - } - } - else // Quick culling - { - if (viewz > cullplane && gzt < cullplane) // Cull if below plane - return; - - if (gz > cullplane && viewz <= cullplane) // Cull if above plane - return; - } + if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) + return; } if (thing->subsector->sector->numlights) @@ -1258,6 +1247,16 @@ static void R_ProjectSprite(mobj_t *thing) vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + + // PORTAL SEMI-CLIPPING + if (portalrender) + { + if (vis->x1 < portalclipstart) + vis->x1 = portalclipstart; + if (vis->x2 > portalclipend) + vis->x2 = portalclipend; + } + vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); @@ -1350,7 +1349,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t iscale; //SoM: 3/17/2000 - fixed_t gzt; + fixed_t gz ,gzt; // transform the origin point tr_x = thing->x - viewx; @@ -1417,33 +1416,24 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (x2 < 0) return; + // PORTAL SPRITE CLIPPING + if (portalrender) + { + if (x2 < portalclipstart || x1 > portalclipend) + return; + + if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) + return; + } + //SoM: 3/17/2000: Disregard sprites that are out of view.. gzt = thing->z + spritecachedinfo[lump].topoffset; + gz = gzt - spritecachedinfo[lump].height; if (thing->subsector->sector->cullheight) { - if (thing->subsector->sector->cullheight->flags & ML_NOCLIMB) // Group culling - { - // Make sure this is part of the same group - if (viewsector->cullheight && viewsector->cullheight->frontsector - == thing->subsector->sector->cullheight->frontsector) - { - // OK, we can cull - if (viewz > thing->subsector->sector->cullheight->frontsector->floorheight - && gzt < thing->subsector->sector->cullheight->frontsector->floorheight) // Cull if below plane - return; - else if (gzt - spritecachedinfo[lump].height > thing->subsector->sector->cullheight->frontsector->floorheight) // Cull if above plane - return; - } - } - else // Quick culling - { - if (viewz > thing->subsector->sector->cullheight->frontsector->floorheight - && gzt < thing->subsector->sector->cullheight->frontsector->floorheight) // Cull if below plane - return; - else if (gzt - spritecachedinfo[lump].height > thing->subsector->sector->cullheight->frontsector->floorheight) // Cull if above plane - return; - } + if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) + return; } // quick check for possible overflows @@ -1454,13 +1444,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; } - // store information in a vissprite vis = R_NewVisSprite(); vis->scale = yscale; //<gx = thing->x; vis->gy = thing->y; - vis->gz = gzt - spritecachedinfo[lump].height; + vis->gz = gz; vis->gzt = gzt; vis->thingheight = 4*FRACUNIT; vis->pz = thing->z; @@ -1469,6 +1458,16 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + + // PORTAL SEMI-CLIPPING + if (portalrender) + { + if (vis->x1 < portalclipstart) + vis->x1 = portalclipstart; + if (vis->x2 > portalclipend) + vis->x2 = portalclipend; + } + vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); @@ -1830,6 +1829,20 @@ static void R_CreateDrawNodes(void) } else if (r2->seg) { +#ifdef POLYOBJECTS_PLANES + if (r2->seg->curline->polyseg && rover->mobj && P_MobjInsidePolyobj(r2->seg->curline->polyseg, rover->mobj)) { + // Determine if we need to sort in front of the polyobj, based on the planes. This fixes the issue where + // polyobject planes render above the object standing on them. (A bit hacky... but it works.) -Red + mobj_t *mo = rover->mobj; + sector_t *po = r2->seg->curline->backsector; + + if (po->ceilingheight < viewz && mo->z+mo->height > po->ceilingheight) + continue; + + if (po->floorheight > viewz && mo->z < po->floorheight) + continue; + } +#endif if (rover->x1 > r2->seg->x2 || rover->x2 < r2->seg->x1) continue; @@ -1937,297 +1950,201 @@ void R_InitDrawNodes(void) // don't draw the part of sprites hidden under the console static void R_DrawSprite(vissprite_t *spr) { - drawseg_t *ds; - INT16 clipbot[MAXVIDWIDTH]; - INT16 cliptop[MAXVIDWIDTH]; - INT32 x; - INT32 r1; - INT32 r2; - fixed_t scale; - fixed_t lowscale; - INT32 silhouette; - - memset(clipbot,0x00,sizeof (clipbot)); - memset(cliptop,0x00,sizeof (cliptop)); - for (x = spr->x1; x <= spr->x2; x++) - clipbot[x] = cliptop[x] = -2; - - // Scan drawsegs from end to start for obscuring segs. - // The first drawseg that has a greater scale - // is the clip seg. - //SoM: 4/8/2000: - // Pointer check was originally nonportable - // and buggy, by going past LEFT end of array: - - // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > drawsegs ;) - { - // determine if the drawseg obscures the sprite - if (ds->x1 > spr->x2 || - ds->x2 < spr->x1 || - (!ds->silhouette - && !ds->maskedtexturecol)) - { - // does not cover sprite - continue; - } - - r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; - r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; - - if (ds->scale1 > ds->scale2) - { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; - } - - if (scale < spr->scale || - (lowscale < spr->scale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ - // seg is behind sprite - continue; - } - - // clip this piece of the sprite - silhouette = ds->silhouette; - - if (spr->gz >= ds->bsilheight) - silhouette &= ~SIL_BOTTOM; - - if (spr->gzt <= ds->tsilheight) - silhouette &= ~SIL_TOP; - - if (silhouette == 1) - { - // bottom sil - for (x = r1; x <= r2; x++) - if (clipbot[x] == -2) - clipbot[x] = ds->sprbottomclip[x]; - } - else if (silhouette == 2) - { - // top sil - for (x = r1; x <= r2; x++) - if (cliptop[x] == -2) - cliptop[x] = ds->sprtopclip[x]; - } - else if (silhouette == 3) - { - // both - for (x = r1; x <= r2; x++) - { - if (clipbot[x] == -2) - clipbot[x] = ds->sprbottomclip[x]; - if (cliptop[x] == -2) - cliptop[x] = ds->sprtopclip[x]; - } - } - } - //SoM: 3/17/2000: Clip sprites in water. - if (spr->heightsec != -1) // only things in specially marked sectors - { - fixed_t mh, h; - INT32 phs = viewplayer->mo->subsector->sector->heightsec; - if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->scale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (clipbot[x] == -2 || h < clipbot[x]) - clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (cliptop[x] == -2 || h > cliptop[x]) - cliptop[x] = (INT16)h; - } - } - - if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (phs != -1 && viewz >= sectors[phs].ceilingheight) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (clipbot[x] == -2 || h < clipbot[x]) - clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (cliptop[x] == -2 || h > cliptop[x]) - cliptop[x] = (INT16)h; - } - } - } - if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) - { - for (x = spr->x1; x <= spr->x2; x++) - { - if (cliptop[x] == -2 || spr->szt > cliptop[x]) - cliptop[x] = spr->szt; - - if (clipbot[x] == -2 || spr->sz < clipbot[x]) - clipbot[x] = spr->sz; - } - } - else if (spr->cut & SC_TOP) - { - for (x = spr->x1; x <= spr->x2; x++) - { - if (cliptop[x] == -2 || spr->szt > cliptop[x]) - cliptop[x] = spr->szt; - } - } - else if (spr->cut & SC_BOTTOM) - { - for (x = spr->x1; x <= spr->x2; x++) - { - if (clipbot[x] == -2 || spr->sz < clipbot[x]) - clipbot[x] = spr->sz; - } - } - - // all clipping has been performed, so draw the sprite - - // check for unclipped columns - for (x = spr->x1; x <= spr->x2; x++) - { - if (clipbot[x] == -2) - clipbot[x] = (INT16)viewheight; - - if (cliptop[x] == -2) - //Fab : 26-04-98: was -1, now clips against console bottom - cliptop[x] = (INT16)con_clipviewtop; - } - - mfloorclip = clipbot; - mceilingclip = cliptop; + mfloorclip = spr->clipbot; + mceilingclip = spr->cliptop; R_DrawVisSprite(spr); } // Special drawer for precipitation sprites Tails 08-18-2002 static void R_DrawPrecipitationSprite(vissprite_t *spr) { - drawseg_t *ds; - INT16 clipbot[MAXVIDWIDTH]; - INT16 cliptop[MAXVIDWIDTH]; - INT32 x; - INT32 r1; - INT32 r2; - fixed_t scale; - fixed_t lowscale; - INT32 silhouette; + mfloorclip = spr->clipbot; + mceilingclip = spr->cliptop; + R_DrawPrecipitationVisSprite(spr); +} - memset(clipbot,0x00,sizeof (clipbot)); - memset(cliptop,0x00,sizeof (cliptop)); - for (x = spr->x1; x <= spr->x2; x++) - clipbot[x] = cliptop[x] = -2; - - // Scan drawsegs from end to start for obscuring segs. - // The first drawseg that has a greater scale - // is the clip seg. - //SoM: 4/8/2000: - // Pointer check was originally nonportable - // and buggy, by going past LEFT end of array: - - // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > drawsegs ;) +// R_ClipSprites +// Clips vissprites without drawing, so that portals can work. -Red +void R_ClipSprites(void) +{ + vissprite_t *spr; + for (;clippedvissprites < visspritecount; clippedvissprites++) { - // determine if the drawseg obscures the sprite - if (ds->x1 > spr->x2 || - ds->x2 < spr->x1 || - (!ds->silhouette && - !ds->maskedtexturecol)) - { - // does not cover sprite - continue; - } + drawseg_t *ds; + INT32 x; + INT32 r1; + INT32 r2; + fixed_t scale; + fixed_t lowscale; + INT32 silhouette; - r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; - r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + spr = R_GetVisSprite(clippedvissprites); - if (ds->scale1 > ds->scale2) - { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; - } + for (x = spr->x1; x <= spr->x2; x++) + spr->clipbot[x] = spr->cliptop[x] = -2; - if (scale < spr->scale || - (lowscale < spr->scale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange(ds, r1, r2);*/ - // seg is behind sprite - continue; - } + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale + // is the clip seg. + //SoM: 4/8/2000: + // Pointer check was originally nonportable + // and buggy, by going past LEFT end of array: - // clip this piece of the sprite - silhouette = ds->silhouette; - - if (silhouette == 1) + // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code + for (ds = ds_p; ds-- > drawsegs ;) { - // bottom sil - for (x = r1; x <= r2; x++) - if (clipbot[x] == -2) - clipbot[x] = ds->sprbottomclip[x]; - } - else if (silhouette == 2) - { - // top sil - for (x = r1; x <= r2; x++) - if (cliptop[x] == -2) - cliptop[x] = ds->sprtopclip[x]; - } - else if (silhouette == 3) - { - // both - for (x = r1; x <= r2; x++) + // determine if the drawseg obscures the sprite + if (ds->x1 > spr->x2 || + ds->x2 < spr->x1 || + (!ds->silhouette + && !ds->maskedtexturecol)) { - if (clipbot[x] == -2) - clipbot[x] = ds->sprbottomclip[x]; - if (cliptop[x] == -2) - cliptop[x] = ds->sprtopclip[x]; + // does not cover sprite + continue; + } + + r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; + r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + + if (ds->scale1 > ds->scale2) + { + lowscale = ds->scale2; + scale = ds->scale1; + } + else + { + lowscale = ds->scale1; + scale = ds->scale2; + } + + if (scale < spr->scale || + (lowscale < spr->scale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + // masked mid texture? + /*if (ds->maskedtexturecol) + R_RenderMaskedSegRange (ds, r1, r2);*/ + // seg is behind sprite + continue; + } + + // clip this piece of the sprite + silhouette = ds->silhouette; + + if (spr->gz >= ds->bsilheight) + silhouette &= ~SIL_BOTTOM; + + if (spr->gzt <= ds->tsilheight) + silhouette &= ~SIL_TOP; + + if (silhouette == 1) + { + // bottom sil + for (x = r1; x <= r2; x++) + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + } + else if (silhouette == 2) + { + // top sil + for (x = r1; x <= r2; x++) + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } + else if (silhouette == 3) + { + // both + for (x = r1; x <= r2; x++) + { + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } } } + //SoM: 3/17/2000: Clip sprites in water. + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t mh, h; + INT32 phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh -= viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x = spr->x1; x <= spr->x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; + } + else // clip top + { + for (x = spr->x1; x <= spr->x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; + } + } + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x = spr->x1; x <= spr->x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; + } + else // clip top + { + for (x = spr->x1; x <= spr->x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; + } + } + } + if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) + { + for (x = spr->x1; x <= spr->x2; x++) + { + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; + + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; + } + } + else if (spr->cut & SC_TOP) + { + for (x = spr->x1; x <= spr->x2; x++) + { + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; + } + } + else if (spr->cut & SC_BOTTOM) + { + for (x = spr->x1; x <= spr->x2; x++) + { + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; + } + } + + // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? + + // check for unclipped columns + for (x = spr->x1; x <= spr->x2; x++) + { + if (spr->clipbot[x] == -2) + spr->clipbot[x] = (INT16)viewheight; + + if (spr->cliptop[x] == -2) + //Fab : 26-04-98: was -1, now clips against console bottom + spr->cliptop[x] = (INT16)con_clipviewtop; + } } - - // all clipping has been performed, so draw the sprite - - // check for unclipped columns - for (x = spr->x1; x <= spr->x2; x++) - { - if (clipbot[x] == -2) - clipbot[x] = (INT16)viewheight; - - if (cliptop[x] == -2) - //Fab : 26-04-98: was -1, now clips against console bottom - cliptop[x] = (INT16)con_clipviewtop; - } - - mfloorclip = clipbot; - mceilingclip = cliptop; - R_DrawPrecipitationVisSprite(spr); } // diff --git a/src/r_things.h b/src/r_things.h index 226b8e47..5a7036c6 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -54,6 +54,7 @@ void R_DelSpriteDefs(UINT16 wadnum); void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); +void R_ClipSprites(void); void R_DrawMasked(void); // ----------- @@ -156,6 +157,8 @@ typedef struct vissprite_s spritecut_e cut; + INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; + boolean precip; boolean vflip; // Flip vertically boolean isScaled; diff --git a/src/s_sound.c b/src/s_sound.c index b48b60a0..14a8cc42 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -192,10 +192,9 @@ static INT32 S_getChannel(const void *origin, sfxinfo_t *sfxinfo) S_StopChannel(cnum); break; } - else if (origin && channels[cnum].origin == origin && ((channels[cnum].sfxinfo == sfxinfo) - || (channels[cnum].sfxinfo->name != sfxinfo->name - && channels[cnum].sfxinfo->pitch == 1 && sfxinfo->pitch == 1 - && channels[cnum].sfxinfo->pitch == sfxinfo->pitch))) + else if (origin && channels[cnum].origin == origin + && channels[cnum].sfxinfo->name != sfxinfo->name + && channels[cnum].sfxinfo->pitch == SF_TOTALLYSINGLE && sfxinfo->pitch == SF_TOTALLYSINGLE) { S_StopChannel(cnum); break; diff --git a/src/sdl/i_cdmus.c b/src/sdl/i_cdmus.c index fc35eb9c..f3f70366 100644 --- a/src/sdl/i_cdmus.c +++ b/src/sdl/i_cdmus.c @@ -35,4 +35,3 @@ boolean I_SetVolumeCD(int volume) (void)volume; return false; } - diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 336a57ea..a59db26c 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -835,7 +835,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) event.data2 = (evt.xrel) * (wwidth / realwidth); event.data3 = -evt.yrel * (wheight / realheight); } - + event.type = ev_mouse; if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window) @@ -1853,12 +1853,12 @@ void I_StartupGraphics(void) // Fury: we do window initialization after GL setup to allow // SDL_GL_LoadLibrary to work well on Windows - + // Create window //Impl_CreateWindow(USE_FULLSCREEN); //Impl_SetWindowName("SRB2"); VID_SetMode(VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT)); - + vid.buffer = NULL; // For software mode vid.width = BASEVIDWIDTH; // Default size for startup vid.height = BASEVIDHEIGHT; // BitsPerPixel is the SDL interface's diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index c34690b3..a205d30c 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.11; + CURRENT_PROJECT_VERSION = 2.1.12; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.11; + CURRENT_PROJECT_VERSION = 2.1.12; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/sdl12/SRB2CE/cehelp.c b/src/sdl12/SRB2CE/cehelp.c index b9fafd04..7c5efdee 100644 --- a/src/sdl12/SRB2CE/cehelp.c +++ b/src/sdl12/SRB2CE/cehelp.c @@ -444,4 +444,3 @@ VOID WINAPI OutputDebugStringA( OutputDebugStringW(lpOutputStringW); } - diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index c34690b3..a205d30c 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.11; + CURRENT_PROJECT_VERSION = 2.1.12; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.11; + CURRENT_PROJECT_VERSION = 2.1.12; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/sounds.c b/src/sounds.c index c03d6cea..1ec86e7b 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1375,7 +1375,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k64", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Blue Spheres {"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, diff --git a/src/st_stuff.c b/src/st_stuff.c index ae8c2f50..0d0cb1ae 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -461,6 +461,19 @@ static INT32 STRINGY(INT32 y) return y; } +static INT32 SPLITFLAGS(INT32 f) +{ + // Pass this V_SNAPTO(TOP|BOTTOM) and it'll trim them to account for splitscreen! -Red + if (splitscreen) + { + if (stplyr != &players[displayplayer]) + f &= ~V_SNAPTOTOP; + else + f &= ~V_SNAPTOBOTTOM; + } + return f; +} + static INT32 SCX(INT32 x) { return FixedInt(FixedMul(x<width); const UINT8 *colormap; - a &= V_ALPHAMASK; + // I want my V_SNAPTOx flags. :< -Red + //a &= V_ALPHAMASK; if (colornum == 0) colormap = colormaps; @@ -520,8 +534,8 @@ static void ST_DrawNightsOverlayNum(INT32 x /* right border */, INT32 y, INT32 a // draw the number do { - x -= (w * vid.dupx); - V_DrawTranslucentMappedPatch(x, y, V_NOSCALESTART|a, numpat[num % 10], colormap); + x -= w; + V_DrawTranslucentMappedPatch(x, y, a, numpat[num % 10], colormap); num /= 10; } while (num); @@ -924,7 +938,7 @@ static void ST_drawNightsRecords(void) V_DrawString(BASEVIDWIDTH/2 - 48, STRINGY(148), aflag, "BONUS:"); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(140), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 48, STRINGY(148), V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); - ST_DrawNightsOverlayNum(SCX(BASEVIDWIDTH/2 + 48), SCY(160), aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_STEELBLUE); + ST_DrawNightsOverlayNum(BASEVIDWIDTH/2 + 48, STRINGY(160), aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_STEELBLUE); // If new record, say so! if (!(netgame || multiplayer) && G_GetBestNightsScore(gamemap, stplyr->lastmare + 1) <= stplyr->lastmarescore) @@ -936,10 +950,10 @@ static void ST_drawNightsRecords(void) if (P_HasGrades(gamemap, stplyr->lastmare + 1)) { if (aflag) - V_DrawTranslucentPatch(SCX(BASEVIDWIDTH/2 + 60), SCY(160), V_NOSCALESTART|aflag, + V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), aflag, ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); else - V_DrawScaledPatch(SCX(BASEVIDWIDTH/2 + 60), SCY(160), V_NOSCALESTART, + V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, STRINGY(160), 0, ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]); } } @@ -986,14 +1000,14 @@ static void ST_drawNiGHTSHUD(void) if (splitscreen) { - ST_DrawNightsOverlayNum(SCX(256), SCY(160), linktrans, (stplyr->linkcount-1), nightsnum, colornum); - V_DrawTranslucentMappedPatch(SCX(264), SCY(160), V_NOSCALESTART|linktrans, nightslink, + ST_DrawNightsOverlayNum(256, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT|linktrans, (stplyr->linkcount-1), nightsnum, colornum); + V_DrawTranslucentMappedPatch(264, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT|linktrans, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } else { - ST_DrawNightsOverlayNum(SCX(160), SCY(160), linktrans, (stplyr->linkcount-1), nightsnum, colornum); - V_DrawTranslucentMappedPatch(SCX(168), SCY(160), V_NOSCALESTART|linktrans, nightslink, + ST_DrawNightsOverlayNum(160, 160, V_SNAPTOBOTTOM|linktrans, (stplyr->linkcount-1), nightsnum, colornum); + V_DrawTranslucentMappedPatch(168, 160, V_SNAPTOBOTTOM|linktrans, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } } @@ -1004,28 +1018,28 @@ static void ST_drawNiGHTSHUD(void) { INT32 offs = 10 - (stplyr->linktimer - (2*TICRATE - 9)); INT32 ghosttrans = offs << V_ALPHASHIFT; - ST_DrawNightsOverlayNum(SCX(160), SCY(160)+(offs*2), ghosttrans, (stplyr->linkcount-2), + ST_DrawNightsOverlayNum(160, STRINGY(160+offs), SPLITFLAGS(V_SNAPTOBOTTOM)|ghosttrans, (stplyr->linkcount-2), nightsnum, colornum); } #endif if (splitscreen) { - ST_DrawNightsOverlayNum(SCX(256), SCY(160), 0, (stplyr->linkcount-1), nightsnum, colornum); - V_DrawMappedPatch(SCX(264), SCY(160), V_NOSCALESTART, nightslink, + ST_DrawNightsOverlayNum(256, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT, (stplyr->linkcount-1), nightsnum, colornum); + V_DrawMappedPatch(264, STRINGY(152), SPLITFLAGS(V_SNAPTOBOTTOM)|V_SNAPTORIGHT, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } else { - ST_DrawNightsOverlayNum(SCX(160), SCY(160), 0, (stplyr->linkcount-1), nightsnum, colornum); - V_DrawMappedPatch(SCX(168), SCY(160), V_NOSCALESTART, nightslink, + ST_DrawNightsOverlayNum(160, 160, V_SNAPTOBOTTOM, (stplyr->linkcount-1), nightsnum, colornum); + V_DrawMappedPatch(168, 160, V_SNAPTOBOTTOM, nightslink, colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE)); } } // Show remaining link time left in debug if (cv_debug & DBG_NIGHTSBASIC) - V_DrawCenteredString(SCX(BASEVIDWIDTH/2), SCY(180), V_NOSCALESTART, va("End in %d.%02d", stplyr->linktimer/TICRATE, G_TicsToCentiseconds(stplyr->linktimer))); + V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_SNAPTOBOTTOM, va("End in %d.%02d", stplyr->linktimer/TICRATE, G_TicsToCentiseconds(stplyr->linktimer))); } // Drill meter @@ -1039,7 +1053,7 @@ static void ST_drawNiGHTSHUD(void) INT32 dfill; UINT8 fillpatch; - if (splitscreen) + if (splitscreen || nosshack) { locx = 110; locy = 188; @@ -1057,25 +1071,25 @@ static void ST_drawNiGHTSHUD(void) fillpatch = 0; if (splitscreen) - { // Dirty hack because V_SNAPTOBOTTOM doesn't have a way to account for splitscreen, but better than overlapping bars. - V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_HUDTRANS, drillbar); + { // 11-5-14 Replaced the old hack with a slightly better hack. -Red + V_DrawScaledPatch(locx, STRINGY(locy)-3, SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_HUDTRANS, drillfill[fillpatch]); + V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), SPLITFLAGS(V_SNAPTOBOTTOM)|V_HUDTRANS, drillfill[fillpatch]); } else if (nosshack) { // Even dirtier hack-of-a-hack to draw seperate drill meters in splitscreen special stages but nothing else. splitscreen = true; - V_DrawScaledPatch(SCX(locx), SCY(locy), V_NOSCALESTART|V_HUDTRANS, drillbar); + V_DrawScaledPatch(locx, STRINGY(locy)-3, V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(SCX(locx + 2 + dfill), SCY(locy + 3), V_NOSCALESTART|V_HUDTRANS, drillfill[fillpatch]); + V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_HUDTRANS, drillfill[fillpatch]); stplyr = &players[secondarydisplayplayer]; if (stplyr->pflags & PF_DRILLING) fillpatch = (stplyr->drillmeter & 1) + 1; else fillpatch = 0; - V_DrawScaledPatch(locx, locy, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); + V_DrawScaledPatch(locx, STRINGY(locy-3), V_SNAPTOBOTTOM|V_HUDTRANS, drillbar); for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill) - V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); + V_DrawScaledPatch(locx + 2 + dfill, STRINGY(locy + 3), V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]); stplyr = &players[displayplayer]; splitscreen = false; } @@ -1206,7 +1220,7 @@ static void ST_drawNiGHTSHUD(void) #endif ) { - ST_DrawNightsOverlayNum(SCX(304), SCY(16), 0, stplyr->marescore, nightsnum, SKINCOLOR_STEELBLUE); + ST_DrawNightsOverlayNum(304, STRINGY(16), SPLITFLAGS(V_SNAPTOTOP)|V_SNAPTORIGHT, stplyr->marescore, nightsnum, SKINCOLOR_STEELBLUE); } if (!stplyr->exiting @@ -1219,19 +1233,22 @@ static void ST_drawNiGHTSHUD(void) if (modeattacking == ATTACKING_NIGHTS) { INT32 maretime = max(stplyr->realtime - stplyr->marebegunat, 0); + fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20); - ST_DrawOverlayPatch(SCX(298), SCY(180), W_CachePatchName("NGRTIMER", PU_HUDGFX)); - ST_DrawPaddedOverlayNum(SCX(298), SCY(180), G_TicsToCentiseconds(maretime), 2); - ST_DrawOverlayPatch(SCX(274), SCY(180), sboperiod); +#define ASSISHHUDFIX(n) (n*vid.dupx) + ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(22), cornery, W_CachePatchName("NGRTIMER", PU_HUDGFX)); + ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(22), cornery, G_TicsToCentiseconds(maretime), 2); + ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(46), cornery, sboperiod); if (maretime < 60*TICRATE) - ST_DrawOverlayNum(SCX(274), SCY(180), G_TicsToSeconds(maretime)); + ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime)); else { - ST_DrawPaddedOverlayNum(SCX(274), SCY(180), G_TicsToSeconds(maretime), 2); - ST_DrawOverlayPatch(SCX(250), SCY(180), sbocolon); - ST_DrawOverlayNum(SCX(250), SCY(180), G_TicsToMinutes(maretime, true)); + ST_DrawPaddedOverlayNum(cornerx-ASSISHHUDFIX(46), cornery, G_TicsToSeconds(maretime), 2); + ST_DrawOverlayPatch(cornerx-ASSISHHUDFIX(70), cornery, sbocolon); + ST_DrawOverlayNum(cornerx-ASSISHHUDFIX(70), cornery, G_TicsToMinutes(maretime, true)); } } +#undef ASSISHHUDFIX } // Ideya time remaining @@ -1267,22 +1284,22 @@ static void ST_drawNiGHTSHUD(void) } if (realnightstime < 10) - numbersize = SCX(16)/2; + numbersize = 16/2; else if (realnightstime < 100) - numbersize = SCX(32)/2; + numbersize = 32/2; else - numbersize = SCX(48)/2; + numbersize = 48/2; if (realnightstime < 10) - ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), 0, realnightstime, + ST_DrawNightsOverlayNum(160 + numbersize, STRINGY(12), SPLITFLAGS(V_SNAPTOTOP), realnightstime, nightsnum, SKINCOLOR_RED); else - ST_DrawNightsOverlayNum(SCX(160) + numbersize, SCY(12), 0, realnightstime, + ST_DrawNightsOverlayNum(160 + numbersize, STRINGY(12), SPLITFLAGS(V_SNAPTOTOP), realnightstime, nightsnum, SKINCOLOR_SUPER4); // Show exact time in debug if (cv_debug & DBG_NIGHTSBASIC) - V_DrawString(SCX(160) + numbersize + 8, SCY(24), V_NOSCALESTART|((realnightstime < 10) ? V_REDMAP : V_YELLOWMAP), va("%02d", G_TicsToCentiseconds(stplyr->nightstime))); + V_DrawString(160 + numbersize + 8, 24, V_SNAPTOTOP|((realnightstime < 10) ? V_REDMAP : V_YELLOWMAP), va("%02d", G_TicsToCentiseconds(stplyr->nightstime))); } // Show pickup durations diff --git a/src/v_video.c b/src/v_video.c index 926107ff..64bf825b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -484,7 +484,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t INT32 topdelta, prevdelta = -1; if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) continue; - if (x > vid.width) // don't draw off the right of the screen (WRAP PREVENTION) + if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); @@ -596,7 +596,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ INT32 topdelta, prevdelta = -1; if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) continue; - if (x > vid.width) // don't draw off the right of the screen (WRAP PREVENTION) + if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); @@ -1609,7 +1609,7 @@ INT32 V_CreditStringWidth(const char *string) { c = toupper(string[i]) - CRED_FONTSTART; if (c < 0 || c >= CRED_FONTSIZE) - w += 8; + w += 16; else w += SHORT(cred_font[c]->width); } diff --git a/src/w_wad.c b/src/w_wad.c index b09236a2..adcbb481 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -418,6 +418,7 @@ UINT16 W_LoadWadFile(const char *filename) free(fileinfov); } +#ifndef NOMD5 // // w-waiiiit! // Let's not add a wad file if the MD5 matches @@ -433,6 +434,7 @@ UINT16 W_LoadWadFile(const char *filename) return INT16_MAX; } } +#endif // // link wad file to search files diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg index b989923f..c369651b 100644 --- a/src/win32/Makefile.cfg +++ b/src/win32/Makefile.cfg @@ -53,9 +53,9 @@ endif # name of the exefile ifdef SDL - EXENAME?=srb2sdl2.exe -else EXENAME?=srb2win.exe +else + EXENAME?=srb2dd.exe endif ifdef SDL diff --git a/src/y_inter.c b/src/y_inter.c index 35ecf62a..498afa7c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -770,11 +770,12 @@ void Y_Ticker(void) } // -// Y_UpdateReplays +// Y_UpdateRecordReplays // -// Update replay files/data, etc +// Update replay files/data, etc. for Record Attack +// See G_SetNightsRecords for NiGHTS Attack. // -static void Y_UpdateReplays(void) +static void Y_UpdateRecordReplays(void) { const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; char *gpath; @@ -962,7 +963,7 @@ void Y_StartIntermission(void) mapvisited[gamemap-1] |= MV_PERFECT; if (modeattacking == ATTACKING_RECORD) - Y_UpdateReplays(); + Y_UpdateRecordReplays(); } for (i = 0; i < 4; ++i)