diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db71b8c39..1d461a820 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -453,8 +453,9 @@ if(${SRB2_CONFIG_HAVE_DISCORDRPC}) if(${DISCORDRPC_FOUND}) set(SRB2_HAVE_DISCORDRPC ON) add_definitions(-DHAVE_DISCORDRPC) - set(SRB2_DISCORDRPC_SOURCES discord.c) - set(SRB2_DISCORDRPC_HEADERS discord.h) + add_definitions(-DUSE_STUN) + set(SRB2_DISCORDRPC_SOURCES discord.c stun.c) + set(SRB2_DISCORDRPC_HEADERS discord.h stun.h) prepend_sources(SRB2_DISCORDRPC_SOURCES) prepend_sources(SRB2_DISCORDRPC_HEADERS) source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS}) diff --git a/src/Makefile b/src/Makefile index b9a653eef..de857fd1d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -393,8 +393,8 @@ endif ifdef HAVE_DISCORDRPC LIBS+=-ldiscord-rpc -CFLAGS+=-DHAVE_DISCORDRPC -OBJS+=$(OBJDIR)/discord.o +CFLAGS+=-DHAVE_DISCORDRPC -DUSE_STUN +OBJS+=$(OBJDIR)/discord.o $(OBJDIR)/stun.o endif include blua/Makefile.cfg diff --git a/src/command.h b/src/command.h index 851688b6c..44d5e50b3 100644 --- a/src/command.h +++ b/src/command.h @@ -35,7 +35,7 @@ enum /* Command buffer flags. */ enum { - COM_SAFE = 1, + COM_SAFE = 0x01, }; typedef void (*com_func_t)(void); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d7f4af80c..43bb54538 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2356,7 +2356,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) cl_mode = CL_CHECKFILES; } else + { cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } return true; } @@ -3583,6 +3586,76 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } } +#ifdef HAVE_CURL +/** Add a login for HTTP downloads. If the + * user/password is missing, remove it. + * + * \sa Command_list_http_logins + */ +static void Command_set_http_login (void) +{ + HTTP_login *login; + HTTP_login **prev_next; + + if (COM_Argc() < 2) + { + CONS_Printf( + "set_http_login [user:password]: Set or remove a login to " + "authenticate HTTP downloads.\n" + ); + return; + } + + login = CURLGetLogin(COM_Argv(1), &prev_next); + + if (COM_Argc() == 2) + { + if (login) + { + (*prev_next) = login->next; + CONS_Printf("Login for '%s' removed.\n", login->url); + Z_Free(login); + } + } + else + { + if (login) + Z_Free(login->auth); + else + { + login = ZZ_Alloc(sizeof *login); + login->url = Z_StrDup(COM_Argv(1)); + } + + login->auth = Z_StrDup(COM_Argv(2)); + + login->next = curl_logins; + curl_logins = login; + } +} + +/** List logins for HTTP downloads. + * + * \sa Command_set_http_login + */ +static void Command_list_http_logins (void) +{ + HTTP_login *login; + + for ( + login = curl_logins; + login; + login = login->next + ){ + CONS_Printf( + "'%s' -> '%s'\n", + login->url, + login->auth + ); + } +} +#endif/*HAVE_CURL*/ + static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3658,6 +3731,10 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); +#ifdef HAVE_CURL + COM_AddCommand("set_http_login", Command_set_http_login); + COM_AddCommand("list_http_logins", Command_list_http_logins); +#endif #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); @@ -5495,7 +5572,10 @@ static void CL_SendClientCmd(void) boolean mis = false; if (lowest_lag && ( gametic % lowest_lag )) + { + cl_packetmissed = true; return; + } netbuffer->packettype = PT_CLIENTCMD; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 4adfda142..c5f69d9df 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -37,7 +37,7 @@ applications may follow different packet versions. // be transmitted. // Networking and tick handling related. -#define BACKUPTICS 32 +#define BACKUPTICS 1024 #define TICQUEUE 512 // more than enough for most timeouts.... #define MAXTEXTCMD 256 // @@ -571,6 +571,7 @@ extern INT32 mapchangepending; // Points inside doomcom extern doomdata_t *netbuffer; +extern consvar_t cv_stunserver; extern consvar_t cv_httpsource; extern consvar_t cv_showjoinaddress; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d31e9537e..6ce0b6df9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -748,6 +748,10 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_dummyconsvar); +#ifdef USE_STUN + CV_RegisterVar(&cv_stunserver); +#endif + CV_RegisterVar(&cv_discordinvites); RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo); } diff --git a/src/d_netfil.c b/src/d_netfil.c index 5ca99508a..3307d00e9 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -138,6 +138,7 @@ static UINT32 curl_origfilesize; static UINT32 curl_origtotalfilesize; static char *curl_realname = NULL; fileneeded_t *curl_curfile = NULL; +HTTP_login *curl_logins; #endif luafiletransfer_t *luafiletransfers = NULL; @@ -476,10 +477,10 @@ INT32 CL_CheckFiles(void) for (i = 0; i < fileneedednum; i++) { - if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_FALLBACK) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK) downloadrequired = true; - if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND) + if (fileneeded[i].status != FS_OPEN) filestoload++; if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics @@ -1646,6 +1647,8 @@ int curlprogress_callback(void *clientp, double dltotal, double dlnow, double ul void CURLPrepareFile(const char* url, int dfilenum) { + HTTP_login *login; + #ifdef PARANOIA if (M_CheckParm("-nodownload")) I_Error("Attempted to download files in -nodownload mode"); @@ -1674,6 +1677,14 @@ void CURLPrepareFile(const char* url, int dfilenum) curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("SRB2Kart/v%d.%d", VERSION, SUBVERSION)); // Set user agent as some servers won't accept invalid user agents. + // Authenticate if the user so wishes + login = CURLGetLogin(url, NULL); + + if (login) + { + curl_easy_setopt(http_handle, CURLOPT_USERPWD, login->auth); + } + // Follow a redirect request, if sent by the server. curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L); @@ -1775,4 +1786,27 @@ void CURLGetFile(void) curl_global_cleanup(); } } + +HTTP_login * +CURLGetLogin (const char *url, HTTP_login ***return_prev_next) +{ + HTTP_login * login; + HTTP_login ** prev_next; + + for ( + prev_next = &curl_logins; + ( login = (*prev_next)); + prev_next = &login->next + ){ + if (strcmp(login->url, url) == 0) + { + if (return_prev_next) + (*return_prev_next) = prev_next; + + return login; + } + } + + return NULL; +} #endif diff --git a/src/d_netfil.h b/src/d_netfil.h index 31f9bc507..20a49f498 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -72,6 +72,16 @@ extern UINT32 totalfilesrequestedsize; extern boolean curl_failedwebdownload; extern boolean curl_running; extern INT32 curl_transfers; + +typedef struct HTTP_login HTTP_login; + +extern struct HTTP_login +{ + char * url; + char * auth; + HTTP_login * next; +} +*curl_logins; #endif UINT8 *PutFileNeeded(UINT16 firstfile); @@ -151,6 +161,7 @@ size_t nameonlylength(const char *s); #ifdef HAVE_CURL void CURLPrepareFile(const char* url, int dfilenum); void CURLGetFile(void); +HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next); #endif #endif // __D_NETFIL__ diff --git a/src/dehacked.c b/src/dehacked.c index cbff0adce..49b34e8bc 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9351,6 +9351,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_WATERTRAILUNDERLAY7", "S_WATERTRAILUNDERLAY8", + "S_SPINDASHDUST", + "S_SPINDASHWIND", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -10423,6 +10426,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_WATERTRAIL", "MT_WATERTRAILUNDERLAY", + "MT_SPINDASHDUST", + "MT_SPINDASHWIND", + "MT_PAPERITEMSPOT", #ifdef SEENAMES diff --git a/src/discord.c b/src/discord.c index 42b4d91e4..652303f65 100644 --- a/src/discord.c +++ b/src/discord.c @@ -12,9 +12,7 @@ #ifdef HAVE_DISCORDRPC -#ifdef HAVE_CURL -#include -#endif // HAVE_CURL +#include #include "i_system.h" #include "d_clisrv.h" @@ -27,6 +25,8 @@ #include "mserv.h" // cv_advertise #include "z_zone.h" #include "byteptr.h" +#include "stun.h" +#include "i_tcp.h" // current_port #include "discord.h" #include "doomdef.h" @@ -45,16 +45,7 @@ struct discordInfo_s discordInfo; discordRequest_t *discordRequestList = NULL; -#ifdef HAVE_CURL -struct SelfIPbuffer -{ - CURL *curl; - char *pointer; - size_t length; -}; - static char self_ip[IP_SIZE]; -#endif // HAVE_CURL /*-------------------------------------------------- static char *DRPC_XORIPString(const char *input) @@ -335,39 +326,23 @@ void DRPC_Init(void) DRPC_UpdatePresence(); } -#ifdef HAVE_CURL /*-------------------------------------------------- - static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata) + static void DRPC_GotServerIP(UINT32 address) - Writing function for use with curl. Only intended to be used with simple text. + Callback triggered by successful STUN response. Input Arguments:- - s - Data to write - size - Always 1. - n - Length of data - userdata - Passed in from CURLOPT_WRITEDATA, intended to be SelfIPbuffer + address - IPv4 address of this machine, in network byte order. Return:- - Number of bytes wrote in this pass. + None --------------------------------------------------*/ -static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata) +static void DRPC_GotServerIP(UINT32 address) { - struct SelfIPbuffer *buffer; - size_t newlength; - - buffer = userdata; - - newlength = buffer->length + size*n; - buffer->pointer = realloc(buffer->pointer, newlength+1); - - memcpy(buffer->pointer + buffer->length, s, size*n); - - buffer->pointer[newlength] = '\0'; - buffer->length = newlength; - - return size*n; + const unsigned char * p = (const unsigned char *)&address; + sprintf(self_ip, "%u.%u.%u.%u:%u", p[0], p[1], p[2], p[3], current_port); + DRPC_UpdatePresence(); } -#endif // HAVE_CURL /*-------------------------------------------------- static const char *DRPC_GetServerIP(void) @@ -387,64 +362,21 @@ static const char *DRPC_GetServerIP(void) { // We're not the server, so we could successfully get the IP! // No need to do anything else :) - return address; + sprintf(self_ip, "%s:%u", address, current_port); + return self_ip; } } -#ifdef HAVE_CURL - // This is a little bit goofy, but - // there's practically no good way to get your own public IP address, - // so we've gotta break out curl for this :V - if (!self_ip[0]) - { - CURL *curl; - - curl_global_init(CURL_GLOBAL_ALL); - curl = curl_easy_init(); - - if (curl) - { - // The API to get your public IP address from. - // Picked because it's stupid simple and it's been up for a long time. - const char *api = "http://ip4only.me/api/"; - - struct SelfIPbuffer buffer; - CURLcode success; - - buffer.length = 0; - buffer.pointer = malloc(buffer.length+1); - buffer.pointer[0] = '\0'; - - curl_easy_setopt(curl, CURLOPT_URL, api); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DRPC_WriteServerIP); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); - - success = curl_easy_perform(curl); - - if (success == CURLE_OK) - { - char *tmp; - tmp = strtok(buffer.pointer, ","); - - if (!strcmp(tmp, "IPv4")) // ensure correct type of IP - { - tmp = strtok(NULL, ","); - strncpy(self_ip, tmp, IP_SIZE); // Yay, we have the IP :) - } - } - - free(buffer.pointer); - curl_easy_cleanup(curl); - } - - curl_global_cleanup(); - } - if (self_ip[0]) + { return self_ip; + } else -#endif // HAVE_CURL - return NULL; // Could not get your IP for whatever reason, so we cannot do Discord invites + { + // There happens to be a good way to get it after all! :D + STUN_bind(DRPC_GotServerIP); + return NULL; + } } /*-------------------------------------------------- @@ -510,19 +442,6 @@ void DRPC_UpdatePresence(void) // Server info if (netgame) { - if (cv_advertise.value) - { - discordPresence.state = "Public"; - } - else - { - discordPresence.state = "Private"; - } - - discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! - discordPresence.partySize = D_NumPlayers(); // Players in server - discordPresence.partyMax = discordInfo.maxPlayers; // Max players - if (DRPC_InvitesAreAllowed() == true) { const char *join; @@ -536,7 +455,24 @@ void DRPC_UpdatePresence(void) joinSecretSet = true; } + else + { + return; + } } + + if (cv_advertise.value) + { + discordPresence.state = "Public"; + } + else + { + discordPresence.state = "Private"; + } + + discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field! + discordPresence.partySize = D_NumPlayers(); // Players in server + discordPresence.partyMax = discordInfo.maxPlayers; // Max players } else { diff --git a/src/g_demo.c b/src/g_demo.c index 50c53d1c3..7c2f9f25c 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -318,10 +318,6 @@ void G_ReadDemoExtraData(void) playeringame[p] = true; G_AddPlayer(p); players[p].spectator = true; - - // There's likely an off-by-one error in timing recording or playback of joins. This hacks around it so I don't have to find out where that is. \o/ - if (oldcmd[p].forwardmove) - P_RandomByte(); } else { diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index bc7a673b7..5f1d3e74f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3617,9 +3617,9 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; GLPatch_t *gpatch; FOutVector shadowVerts[4]; @@ -3637,6 +3637,21 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) fixed_t slopez; pslope_t *groundslope; + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + groundz = R_GetShadowZ(thing, &groundslope); floordiff = abs((flip < 0 ? thing->height : 0) + thingzpos - groundz); @@ -4867,9 +4882,9 @@ static void HWR_AddSprites(sector_t *sec) // BP why not use xtoviexangle/viewangletox like in bsp ?.... static void HWR_ProjectSprite(mobj_t *thing) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; gl_vissprite_t *vis; float tr_x, tr_y; @@ -4907,6 +4922,21 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + dispoffset = thing->info->dispoffset; this_scale = FIXED_TO_FLOAT(thing->scale); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9896eb458..f68771a1b 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1340,9 +1340,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // Look at HWR_ProjectSprite for more { - const fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff; - const fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff; - const fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff; + fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff; + fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff; + fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff; GLPatch_t *gpatch; INT32 durs = spr->mobj->state->tics; @@ -1358,6 +1358,21 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) INT32 mod; float finalscale; + // hitlag vibrating + if (spr->mobj->hitlag > 0) + { + fixed_t mul = spr->mobj->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(spr->mobj->momx, mul); + thingypos += FixedMul(spr->mobj->momy, mul); + thingzpos += FixedMul(spr->mobj->momz, mul); + } + // Apparently people don't like jump frames like that, so back it goes //if (tics > durs) //durs = tics; diff --git a/src/i_tcp.c b/src/i_tcp.c index 5180869a5..a9ffe5f3b 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -152,6 +152,7 @@ static UINT8 UPNP_support = TRUE; #include "d_netfil.h" #include "i_tcp.h" #include "m_argv.h" +#include "stun.h" #include "doomstat.h" @@ -575,6 +576,13 @@ static boolean SOCK_Get(void) (void *)&fromaddress, &fromlen); if (c != ERRSOCKET) { +#ifdef USE_STUN + if (STUN_got_response(doomcom->data, c)) + { + return false; + } +#endif + // find remote node number for (j = 1; j <= MAXNETNODES; j++) //include LAN { diff --git a/src/info.c b/src/info.c index 1b9f58220..5409bf41a 100644 --- a/src/info.c +++ b/src/info.c @@ -738,6 +738,9 @@ char sprnames[NUMSPRITES + 1][5] = "DBCL", // Drift boost clip "DBNC", // Drift boost clip's sparks "DBST", // Drift boost plume + + "SDDS", // Spindash dust + "SDWN", // Spindash wind }; char spr2names[NUMPLAYERSPRITES][5] = @@ -5064,6 +5067,9 @@ state_t states[NUMSTATES] = {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|14, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY7 {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|15, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY8 + {SPR_SDDS, FF_ANIMATE, 9, {NULL}, 9, 1, S_NULL}, // S_SPINDASHDUST + {SPR_SDWN, FF_ANIMATE|FF_PAPERSPRITE, 18, {NULL}, 9, 2, S_NULL}, // S_SPINDASHWIND + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -8415,7 +8421,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 25*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_YELLOWSPRING2 // raisestate }, @@ -8442,7 +8448,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 40*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_REDSPRING2 // raisestate }, @@ -8469,7 +8475,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 64*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_BLUESPRING2 // raisestate }, @@ -8496,7 +8502,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 15*FRACUNIT, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_GREYSPRING2 // raisestate }, @@ -8523,7 +8529,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 25*FRACUNIT, // mass 25*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_YDIAG2 // raisestate }, @@ -8550,7 +8556,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 40*FRACUNIT, // mass 40*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_RDIAG2 // raisestate }, @@ -8577,7 +8583,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 64*FRACUNIT, // mass 64*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_BDIAG2 // raisestate }, @@ -8604,7 +8610,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 15*FRACUNIT, // mass 15*FRACUNIT, // damage sfx_None, // activesound - MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_GDIAG2 // raisestate }, @@ -28503,6 +28509,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SPINDASHDUST + -1, // doomednum + S_SPINDASHDUST, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 12*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_SPINDASHWIND + -1, // doomednum + S_SPINDASHWIND, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 12*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_PAPERITEMSPOT -1, // doomednum S_INVISIBLE, // spawnstate diff --git a/src/info.h b/src/info.h index bb8e067be..483706c90 100644 --- a/src/info.h +++ b/src/info.h @@ -1010,6 +1010,9 @@ typedef enum sprite SPR_DBNC, // Drift boost clip's sparks SPR_DBST, // Drift boost plume + SPR_SDDS, // Spindash dust + SPR_SDWN, // Spindash wind + SPR_FIRSTFREESLOT, SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1, NUMSPRITES @@ -5219,6 +5222,9 @@ typedef enum state S_WATERTRAILUNDERLAY7, S_WATERTRAILUNDERLAY8, + S_SPINDASHDUST, + S_SPINDASHWIND, + #ifdef SEENAMES S_NAMECHECK, #endif @@ -6311,6 +6317,9 @@ typedef enum mobj_type MT_WATERTRAIL, MT_WATERTRAILUNDERLAY, + MT_SPINDASHDUST, + MT_SPINDASHWIND, + MT_PAPERITEMSPOT, #ifdef SEENAMES diff --git a/src/k_collide.c b/src/k_collide.c index 34c0e2b59..5f1008d1f 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -30,7 +30,8 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing] && (t1->type == MT_ORBINAUT_SHIELD || t1->type == MT_JAWZ_SHIELD)) + if ((t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) + && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_JAWZ_DUD)) return true; if (t2->player->kartstuff[k_hyudorotimer]) @@ -57,11 +58,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) || t2->type == MT_BALLHOG) { // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -93,11 +89,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) if (damageitem) { // This Item Damage - if (t1->eflags & MFE_VERTICALFLIP) - t1->z -= t1->height; - else - t1->z += t1->height; - S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); @@ -132,7 +123,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; // Banana snipe! @@ -146,7 +137,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) } else { - // Player Damage P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); } @@ -158,11 +148,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) || t2->type == MT_BALLHOG) { // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -183,11 +168,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (damageitem) { // This Item Damage - if (t1->eflags & MFE_VERTICALFLIP) - t1->z -= t1->height; - else - t1->z += t1->height; - S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); @@ -286,15 +266,19 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; // Bomb punting if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4]) || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13])) + { P_KillMobj(t1, t2, t2, DMG_NORMAL); + } else + { K_PuntMine(t1, t2); + } } else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) @@ -303,11 +287,6 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2) P_KillMobj(t1, t2, t2, DMG_NORMAL); // Other Item Damage - if (t2->eflags & MFE_VERTICALFLIP) - t2->z -= t2->height; - else - t2->z += t2->height; - S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); @@ -329,10 +308,17 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2) { if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; - P_DamageMobj(t2, t1, t1->target, 1, (t1->state == &states[S_MINEEXPLOSION1]) ? DMG_EXPLODE : DMG_NORMAL); + if (t1->state == &states[S_MINEEXPLOSION1]) + { + P_DamageMobj(t2, t1, t1->target, 1, DMG_EXPLODE); + } + else + { + P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); + } } else if (t2->flags & MF_SHOOTABLE) { @@ -350,14 +336,16 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) if (t2->player) { - if (t2->player->powers[pw_flashing]) + if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0) return true; S_StartSound(NULL, sfx_bsnipe); // let all players hear it. + HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[t2->player-players])); I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[t2->player-players]); + P_DamageMobj(t2, t1, t1->target, 1, DMG_INSTAKILL); P_KillMobj(t1, t2, t2, DMG_NORMAL); } diff --git a/src/k_kart.c b/src/k_kart.c index 29dfe1d67..ecdb32f5d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1461,8 +1461,8 @@ static void K_UpdateDraft(player_t *player) continue; #ifndef EASYDRAFTTEST - yourangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - theirangle = R_PointToAngle2(0, 0, players[i].mo->momx, players[i].mo->momy); + yourangle = K_MomentumAngle(player->mo); + theirangle = K_MomentumAngle(players[i].mo); diff = R_PointToAngle2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y) - yourangle; if (diff > ANGLE_180) @@ -2019,7 +2019,7 @@ void K_PlayPowerGloatSound(mobj_t *source) void K_MomentumToFacing(player_t *player) { - angle_t dangle = player->mo->angle - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + angle_t dangle = player->mo->angle - K_MomentumAngle(player->mo); if (dangle > ANGLE_180) dangle = InvAngle(dangle); @@ -2048,7 +2048,7 @@ static fixed_t K_FlameShieldDashVar(INT32 val) return (3*FRACUNIT/4) + (((val * FRACUNIT) / TICRATE) / 2); } -tic_t K_GetSpindashChargeTime(player_t *player) +INT16 K_GetSpindashChargeTime(player_t *player) { // more charge time for higher speed // Tails = 2s, Mighty = 3s, Fang = 4s, Metal = 4s @@ -2366,6 +2366,83 @@ fixed_t K_3dKartMovement(player_t *player) return finalspeed; } +angle_t K_MomentumAngle(mobj_t *mo) +{ + if (mo->momx || mo->momy) + { + return R_PointToAngle2(0, 0, mo->momx, mo->momy); + } + else + { + return mo->angle; // default to facing angle, rather than 0 + } +} + +void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics) +{ + boolean mo1valid = (mo1 && !P_MobjWasRemoved(mo1)); + boolean mo2valid = (mo2 && !P_MobjWasRemoved(mo2)); + + INT32 tics1 = tics; + INT32 tics2 = tics; + + if (mo1valid == true && mo2valid == true) + { + const fixed_t ticaddfactor = mapobjectscale * 8; + const INT32 mintics = tics; + + const fixed_t mo1speed = FixedHypot(FixedHypot(mo1->momx, mo1->momy), mo1->momz); + const fixed_t mo2speed = FixedHypot(FixedHypot(mo2->momx, mo2->momy), mo2->momz); + const fixed_t speeddiff = mo2speed - mo1speed; + + const fixed_t scalediff = mo2->scale - mo1->scale; + + const angle_t mo1angle = K_MomentumAngle(mo1); + const angle_t mo2angle = K_MomentumAngle(mo2); + + angle_t anglediff = mo1angle - mo2angle; + fixed_t anglemul = FRACUNIT; + + if (anglediff > ANGLE_180) + { + anglediff = InvAngle(anglediff); + } + + anglemul = FRACUNIT + (AngleFixed(anglediff) / 180); // x1.0 at 0, x1.5 at 90, x2.0 at 180 + + /* + CONS_Printf("anglemul: %f\n", FIXED_TO_FLOAT(anglemul)); + CONS_Printf("speeddiff: %f\n", FIXED_TO_FLOAT(speeddiff)); + CONS_Printf("scalediff: %f\n", FIXED_TO_FLOAT(scalediff)); + */ + + tics1 += FixedMul(speeddiff, FixedMul(anglemul, FRACUNIT + scalediff)) / ticaddfactor; + tics2 += FixedMul(-speeddiff, FixedMul(anglemul, FRACUNIT - scalediff)) / ticaddfactor; + + if (tics1 < mintics) + { + tics1 = mintics; + } + + if (tics2 < mintics) + { + tics2 = mintics; + } + } + + //CONS_Printf("tics1: %d, tics2: %d\n", tics1, tics2); + + if (mo1valid == true) + { + mo1->hitlag += tics1; + } + + if (mo2valid == true) + { + mo2->hitlag += tics2; + } +} + void K_DoInstashield(player_t *player) { mobj_t *layera; @@ -2755,7 +2832,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) if (!bombflashtimer && P_CheckSight(p->mo, source)) { bombflashtimer = TICRATE*2; - P_FlashPal(p, 1, 1); + P_FlashPal(p, PAL_WHITE, 1); } break; // we can break right now because quakes are global to all split players somehow. } @@ -3150,7 +3227,7 @@ static void K_SpawnAIZDust(player_t *player) if (player->speed <= K_GetKartSpeed(player, false)) return; - travelangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + travelangle = K_MomentumAngle(player->mo); //S_StartSound(player->mo, sfx_s3k47); { @@ -3194,7 +3271,7 @@ void K_SpawnBoostTrail(player_t *player) if (player->kartstuff[k_drift] != 0) travelangle = player->mo->angle; else - travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); + travelangle = K_MomentumAngle(player->mo); for (i = 0; i < 2; i++) { @@ -3286,7 +3363,7 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) mo->z, MT_WIPEOUTTRAIL); P_SetTarget(&dust->target, mo); - dust->angle = R_PointToAngle2(0,0,mo->momx,mo->momy); + dust->angle = K_MomentumAngle(mo); dust->destscale = mo->scale; P_SetScale(dust, mo->scale); K_FlipFromObject(dust, mo); @@ -3419,7 +3496,7 @@ void K_DriftDustHandling(mobj_t *spawner) if (P_AproxDistance(spawner->momx, spawner->momy) < 5*spawner->scale) return; - anglediff = abs((signed)(spawner->angle - R_PointToAngle2(0, 0, spawner->momx, spawner->momy))); + anglediff = abs((signed)(spawner->angle - K_MomentumAngle(spawner))); } if (anglediff > ANGLE_180) @@ -3721,7 +3798,7 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map void K_PuntMine(mobj_t *thismine, mobj_t *punter) { - angle_t fa = R_PointToAngle2(0, 0, punter->momx, punter->momy) >> ANGLETOFINESHIFT; + angle_t fa = K_MomentumAngle(punter) >> ANGLETOFINESHIFT; fixed_t z = 30*mapobjectscale + punter->momz; fixed_t spd; mobj_t *mine; @@ -3758,6 +3835,9 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) if (!mine || P_MobjWasRemoved(mine)) return; + if (mine->threshold > 0 || mine->hitlag > 0) + return; + spd = (82 + ((gamespeed-1) * 14))*mapobjectscale; // Avg Speed is 41 in Normal mine->flags |= MF_NOCLIPTHING; @@ -3767,6 +3847,8 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) mine->extravalue1 = 0; mine->reactiontime = mine->info->reactiontime; + K_SetHitLagForObjects(punter, mine, 5); + mine->momx = punter->momx + FixedMul(FINECOSINE(fa), spd); mine->momy = punter->momy + FixedMul(FINESINE(fa), spd); mine->momz = P_MobjFlip(mine) * z; @@ -5492,7 +5574,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) MT_FASTLINE); P_SetTarget(&fast->target, player->mo); - fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + fast->angle = K_MomentumAngle(player->mo); fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*player->mo->momz/4; @@ -6052,18 +6134,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) { boolean finishlinehack = false; angle_t playerangle = player->mo->angle; - angle_t momangle = player->mo->angle; + angle_t momangle = K_MomentumAngle(player->mo); angle_t angletowaypoint = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->mobj->x, waypoint->mobj->y); angle_t angledelta = ANGLE_MAX; angle_t momdelta = ANGLE_MAX; - if (player->mo->momx != 0 || player->mo->momy != 0) - { - // Defaults to facing angle if you're not moving. - momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - } - angledelta = playerangle - angletowaypoint; if (angledelta > ANGLE_180) { @@ -6561,7 +6637,7 @@ static void K_KartDrift(player_t *player, boolean onground) { if (player->kartstuff[k_driftcharge] < 0 || player->kartstuff[k_driftcharge] >= dsone) { - angle_t pushdir = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + angle_t pushdir = K_MomentumAngle(player->mo); S_StartSound(player->mo, sfx_s23c); //K_SpawnDashDustRelease(player); @@ -6943,10 +7019,67 @@ boolean K_PlayerEBrake(player_t *player) && player->powers[pw_nocontrol] == 0; } +static void K_KartSpindashDust(mobj_t *parent) +{ + fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); + INT32 i; + + for (i = 0; i < 2; i++) + { + fixed_t hmomentum = P_RandomRange(6, 12) * parent->scale; + fixed_t vmomentum = P_RandomRange(2, 6) * parent->scale; + + angle_t ang = parent->player->drawangle + ANGLE_180; + SINT8 flip = 1; + + mobj_t *dust; + + if (i & 1) + ang -= ANGLE_45; + else + ang += ANGLE_45; + + dust = P_SpawnMobjFromMobj(parent, + FixedMul(rad, FINECOSINE(ang >> ANGLETOFINESHIFT)), + FixedMul(rad, FINESINE(ang >> ANGLETOFINESHIFT)), + 0, MT_SPINDASHDUST + ); + flip = P_MobjFlip(dust); + + dust->momx = FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); + dust->momy = FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); + dust->momz = vmomentum * flip; + } +} + +static void K_KartSpindashWind(mobj_t *parent) +{ + mobj_t *wind = P_SpawnMobjFromMobj(parent, + P_RandomRange(-36,36) * FRACUNIT, + P_RandomRange(-36,36) * FRACUNIT, + FixedDiv(parent->height / 2, parent->scale) + (P_RandomRange(-20,20) * FRACUNIT), + MT_SPINDASHWIND + ); + + P_SetTarget(&wind->target, parent); + + if (parent->momx || parent->momy) + wind->angle = R_PointToAngle2(0, 0, parent->momx, parent->momy); + else + wind->angle = parent->player->drawangle; + + wind->momx = 3 * parent->momx / 4; + wind->momy = 3 * parent->momy / 4; + wind->momz = 3 * parent->momz / 4; + + K_MatchGenericExtraFlags(wind, parent); +} + static void K_KartSpindash(player_t *player) { - const tic_t MAXCHARGETIME = K_GetSpindashChargeTime(player); + const INT16 MAXCHARGETIME = K_GetSpindashChargeTime(player); ticcmd_t *cmd = &player->cmd; + boolean spawnWind = (leveltime % 2 == 0); if (player->kartstuff[k_spindash] > 0 && (cmd->buttons & (BT_DRIFT|BT_BRAKE)) != (BT_DRIFT|BT_BRAKE)) { @@ -6961,7 +7094,7 @@ static void K_KartSpindash(player_t *player) mobj_t *grease; grease = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_TIREGREASE); P_SetTarget(&grease->target, player->mo); - grease->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + grease->angle = K_MomentumAngle(player->mo); grease->extravalue1 = i; } } @@ -6972,6 +7105,17 @@ static void K_KartSpindash(player_t *player) S_StartSound(player->mo, sfx_s23c); } + + if ((player->kartstuff[k_spindashboost] > 0) && (spawnWind == true)) + { + K_KartSpindashWind(player->mo); + } + + if (player->kartstuff[k_spindashboost] > (TICRATE/2)) + { + K_KartSpindashDust(player->mo); + } + if (K_PlayerEBrake(player) == false) { player->kartstuff[k_spindash] = 0; @@ -6986,26 +7130,36 @@ static void K_KartSpindash(player_t *player) if ((cmd->buttons & (BT_DRIFT|BT_BRAKE)) == (BT_DRIFT|BT_BRAKE)) { INT16 chargetime = MAXCHARGETIME - ++player->kartstuff[k_spindash]; + boolean spawnOldEffect = true; + + if (chargetime <= (MAXCHARGETIME / 2)) + { + K_KartSpindashDust(player->mo); + spawnOldEffect = false; + } + + if (chargetime <= (MAXCHARGETIME / 4) && spawnWind == true) + { + K_KartSpindashWind(player->mo); + } + if (chargetime > 0) { UINT16 soundcharge = 0; UINT8 add = 0; + while ((soundcharge += ++add) < chargetime); + if (soundcharge == chargetime) { - K_SpawnDashDustRelease(player); + if (spawnOldEffect == true) + K_SpawnDashDustRelease(player); S_StartSound(player->mo, sfx_s3kab); } } else if (chargetime < -TICRATE) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); - else { - if (player->kartstuff[k_spindash] % 4 == 0) - { - K_SpawnDashDustRelease(player); - K_FlameDashLeftoverSmoke(player->mo); - } + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); } } } @@ -7599,7 +7753,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (!onground) { P_Thrust( - player->mo, R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), + player->mo, K_MomentumAngle(player->mo), FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed)) ); } diff --git a/src/k_kart.h b/src/k_kart.h index 034b13e58..ce3300b52 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -39,6 +39,8 @@ void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); +angle_t K_MomentumAngle(mobj_t *mo); +void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics); void K_DoInstashield(player_t *player); void K_BattleHitPlayer(player_t *player, player_t *victim, UINT8 points, boolean reducewanted); void K_RemoveBumper(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 amount, boolean force); @@ -78,7 +80,7 @@ void K_StripItems(player_t *player); void K_StripOther(player_t *player); void K_MomentumToFacing(player_t *player); boolean K_ApplyOffroad(player_t *player); -tic_t K_GetSpindashChargeTime(player_t *player); +INT16 K_GetSpindashChargeTime(player_t *player); fixed_t K_GetSpindashChargeSpeed(player_t *player); fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed); fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 4535d3e43..a9d09dd58 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -387,7 +387,8 @@ static int lib_pAproxDistance(lua_State *L) fixed_t dx = luaL_checkfixed(L, 1); fixed_t dy = luaL_checkfixed(L, 2); //HUDSAFE - lua_pushfixed(L, P_AproxDistance(dx, dy)); + LUA_Deprecated(L, "P_AproxDistance", "FixedHypot"); + lua_pushfixed(L, FixedHypot(dx, dy)); return 1; } diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 2ef17841f..6e3a3d331 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -536,7 +536,6 @@ static luaL_Reg lib[] = { {"CV_StealthSet", lib_cvStealthSet}, {"CV_AddValue", lib_cvAddValue}, {"CONS_Printf", lib_consPrintf}, - {"CV_FindVar", lib_cvFindVar}, {NULL, NULL} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index d99d70327..915863626 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -109,10 +109,10 @@ void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player qui boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. +boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. void LUAh_IntermissionThinker(void); // Hook for Y_Ticker -void LUAh_VoteThinker(void); // Hook for Y_VoteTicker +void LUAh_VoteThinker(void); // Hook for Y_VoteTicker #define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities @@ -128,4 +128,3 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_ #define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing void LUAh_GameQuit(void); // Hook for game quitting -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index f37fb93dc..a299f9c83 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -95,7 +95,8 @@ enum mobj_e { mobj_whiteshadow, mobj_sprxoff, mobj_spryoff, - mobj_sprzoff + mobj_sprzoff, + mobj_hitlag }; static const char *const mobj_opt[] = { @@ -170,6 +171,7 @@ static const char *const mobj_opt[] = { "sprxoff", "spryoff", "sprzoff", + "hitlag", NULL}; #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) @@ -430,6 +432,9 @@ static int mobj_get(lua_State *L) case mobj_sprzoff: lua_pushfixed(L, mo->sprzoff); break; + case mobj_hitlag: + lua_pushinteger(L, mo->hitlag); + break; default: // extra custom variables in Lua memory lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); @@ -787,6 +792,9 @@ static int mobj_set(lua_State *L) case mobj_sprzoff: mo->sprzoff = luaL_checkfixed(L, 3); break; + case mobj_hitlag: + mo->hitlag = luaL_checkinteger(L, 3); + break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c84bd694b..a190d9710 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -26,25 +26,35 @@ static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; + if (lua_gettop(L) < 2) { //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do end'."); lua_pushcfunction(L, lib_iteratePlayers); return 1; } + lua_settop(L, 2); lua_remove(L, 1); // state is unused. + if (!lua_isnil(L, 1)) i = (INT32)(*((player_t **)luaL_checkudata(L, 1, META_PLAYER)) - players); - for (i++; i < MAXPLAYERS; i++) + + i++; + + if (i == serverplayer) + { + return LUA_PushServerPlayer(L); + } + + for (; i < MAXPLAYERS; i++) { if (!playeringame[i]) continue; - if (!players[i].mo) - continue; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } + return 0; } @@ -57,10 +67,10 @@ static int lib_getPlayer(lua_State *L) lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXPLAYERS) return luaL_error(L, "players[] index %d out of range (0 - %d)", i, MAXPLAYERS-1); + if (i == serverplayer) + return LUA_PushServerPlayer(L); if (!playeringame[i]) return 0; - if (!players[i].mo) - return 0; LUA_PushUserdata(L, &players[i], META_PLAYER); return 1; } @@ -121,8 +131,6 @@ static int lib_iterateDisplayplayers(lua_State *L) if (i > splitscreen || !playeringame[displayplayers[i]]) return 0; // Stop! There are no more players for us to go through. There will never be a player gap in displayplayers. - if (!players[displayplayers[i]].mo) - continue; LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); lua_pushinteger(L, i); // push this to recall what number we were on for the next function call. I suppose this also means you can retrieve the splitscreen player number with 'for p, n in displayplayers.iterate'! return 2; @@ -143,8 +151,6 @@ static int lib_getDisplayplayers(lua_State *L) return 0; if (!playeringame[displayplayers[i]]) return 0; - if (!players[displayplayers[i]].mo) - return 0; LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER); return 1; } @@ -182,17 +188,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, true); else if (fastcmp(field,"name")) lua_pushstring(L, player_names[plr-players]); - else if (fastcmp(field,"realmo")) - LUA_PushUserdata(L, plr->mo, META_MOBJ); - // Kept for backward-compatibility - // Should be fixed to work like "realmo" later else if (fastcmp(field,"mo")) - { - if (plr->spectator) - lua_pushnil(L); - else - LUA_PushUserdata(L, plr->mo, META_MOBJ); - } + LUA_PushUserdata(L, plr->mo, META_MOBJ); else if (fastcmp(field,"cmd")) LUA_PushUserdata(L, &plr->cmd, META_TICCMD); else if (fastcmp(field,"playerstate")) @@ -449,7 +446,7 @@ static int player_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter player_t in BuildCMD code!"); - if (fastcmp(field,"mo") || fastcmp(field,"realmo")) { + if (fastcmp(field,"mo")) { mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); plr->mo->player = NULL; // remove player pointer from old mobj (newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj diff --git a/src/lua_script.c b/src/lua_script.c index 0b964e5ea..291a1936c 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -731,6 +731,14 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta) lua_remove(L, -2); // remove LREG_VALID } +int LUA_PushServerPlayer(lua_State *L) +{ + if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer]) + return 0; + LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); + return 1; +} + // When userdata is freed, use this function to remove it from Lua. void LUA_InvalidateUserdata(void *data) { diff --git a/src/lua_script.h b/src/lua_script.h index cf4efcccd..d90b5ef63 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -49,6 +49,7 @@ void LUA_DumpFile(const char *filename); fixed_t LUA_EvalMath(const char *word); void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); void LUA_PushUserdata(lua_State *L, void *data, const char *meta); +int LUA_PushServerPlayer(lua_State *L); void LUA_InvalidateUserdata(void *data); void LUA_InvalidateLevel(void); void LUA_InvalidateMapthings(void); diff --git a/src/m_fixed.c b/src/m_fixed.c index eb10fd5f8..09d6936f2 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -18,8 +18,10 @@ #define HAVE_SQRTF #endif #endif + #include "doomdef.h" #include "m_fixed.h" +#include "tables.h" // ANGLETOFINESHIFT #ifdef __USE_C_FIXEDMUL__ @@ -105,20 +107,34 @@ fixed_t FixedSqrt(fixed_t x) fixed_t FixedHypot(fixed_t x, fixed_t y) { - fixed_t ax, yx, yx2, yx1; - if (abs(y) > abs(x)) // |y|>|x| + // Moved the code from R_PointToDist2 to here, + // since R_PointToDist2 did the same thing, + // except less prone to overflowing. + + angle_t angle; + fixed_t dist; + + x = abs(x); + y = abs(y); + + if (y > x) { - ax = abs(y); // |y| => ax - yx = FixedDiv(x, y); // (x/y) + fixed_t temp; + + temp = x; + x = y; + y = temp; } - else // |x|>|y| - { - ax = abs(x); // |x| => ax - yx = FixedDiv(y, x); // (x/y) - } - yx2 = FixedMul(yx, yx); // (x/y)^2 - yx1 = FixedSqrt(1 * FRACUNIT + yx2); // (1 + (x/y)^2)^1/2 - return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2) + + if (!y) + return x; + + angle = (tantoangle[FixedDiv(y, x)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT; + + // use as cosine + dist = FixedDiv(x, FINESINE(angle)); + + return dist; } vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y) diff --git a/src/m_swap.h b/src/m_swap.h index b44d6de8c..faa54e0b2 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2018 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -14,30 +14,34 @@ #ifndef __M_SWAP__ #define __M_SWAP__ -// Endianess handling. -// WAD files are stored little endian. #include "endian.h" -// Little to big endian +#define SWAP_SHORT(x) ((INT16)(\ +(((UINT16)(x) & (UINT16)0x00ffU) << 8) \ +| \ +(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ + +#define SWAP_LONG(x) ((INT32)(\ +(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ +| \ +(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ +| \ +(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ +| \ +(((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) + +// Endianess handling. +// WAD files are stored little endian. #ifdef SRB2_BIG_ENDIAN - - #define SHORT(x) ((INT16)(\ - (((UINT16)(x) & (UINT16)0x00ffU) << 8) \ - | \ - (((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ - - #define LONG(x) ((INT32)(\ - (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ - | \ - (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ - | \ - (((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ - | \ - (((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) - +#define SHORT SWAP_SHORT +#define LONG SWAP_LONG +#define MSBF_SHORT(x) ((INT16)(x)) +#define MSBF_LONG(x) ((INT32)(x)) #else - #define SHORT(x) ((INT16)(x)) - #define LONG(x) ((INT32)(x)) +#define SHORT(x) ((INT16)(x)) +#define LONG(x) ((INT32)(x)) +#define MSBF_SHORT SWAP_SHORT +#define MSBF_LONG SWAP_LONG #endif // Big to little endian diff --git a/src/p_enemy.c b/src/p_enemy.c index 790144caa..dfb45fc07 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4457,6 +4457,9 @@ void A_GrenadeRing(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; + if (actor->hitlag > 0) + return; + if (actor->state == &states[S_SSMINE_DEPLOY8]) explodedist = (3*explodedist)/2; @@ -4524,6 +4527,9 @@ void A_SSMineExplode(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; + if (actor->hitlag > 0) + return; + type = (mobjtype_t)locvar1; // Use blockmap to check for nearby shootables @@ -8757,7 +8763,7 @@ void A_JawzChase(mobj_t *actor) if (!actor->tracer) { - actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + actor->angle = K_MomentumAngle(actor); } P_Thrust(actor, actor->angle, thrustamount); @@ -8887,7 +8893,7 @@ static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) if (mo->eflags & MFE_VERTICALFLIP) sz = mo->ceilingz; - travelangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + travelangle = K_MomentumAngle(mo); if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) { newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); @@ -8917,7 +8923,7 @@ static void SpawnSPBSpeedLines(mobj_t *actor) MT_FASTLINE); P_SetTarget(&fast->target, actor); - fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + fast->angle = K_MomentumAngle(actor); fast->color = SKINCOLOR_RED; fast->colorized = true; K_MatchGenericExtraFlags(fast, actor); diff --git a/src/p_inter.c b/src/p_inter.c index 276bb46fe..9b71eac0d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -452,6 +452,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->threshold > 0) return; + if (toucher->hitlag > 0) + return; + player->powers[pw_emeralds] |= special->extravalue1; K_CheckEmeralds(player); break; @@ -1101,6 +1104,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; + //K_SetHitLagForObjects(target, inflictor, 15); + // SRB2kart // I wish I knew a better way to do this if (target->target && target->target->player && target->target->player->mo) @@ -1672,8 +1677,10 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } -static boolean P_KillPlayer(player_t *player, UINT8 type) +static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type) { + (void)source; + if (player->exiting) { player->mo->destscale = 1; @@ -1694,6 +1701,7 @@ static boolean P_KillPlayer(player_t *player, UINT8 type) } K_DropEmeraldsFromPlayer(player, player->powers[pw_emeralds]); + K_SetHitLagForObjects(player->mo, inflictor, 15); player->pflags &= ~PF_SLIDING; player->powers[pw_carry] = CR_NONE; @@ -1783,6 +1791,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player_t *player; boolean force = false; + INT32 laglength = 10; + if (objectplacing) return false; @@ -1790,13 +1800,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Spectator handling - if (multiplayer) - { - if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) - return false; + if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) + return false; - if (source && source->player && source->player->spectator) - return false; + if (source && source->player && source->player->spectator) + return false; + + if (((damagetype & DMG_TYPEMASK) == DMG_STING) + || ((inflictor && !P_MobjWasRemoved(inflictor)) && inflictor->type == MT_BANANA && inflictor->health <= 1)) + { + laglength = 5; } // Everything above here can't be forced. @@ -1860,7 +1873,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Instant-Death if ((damagetype & DMG_DEATHMASK)) { - if (!P_KillPlayer(player, damagetype)) + if (!P_KillPlayer(player, inflictor, source, damagetype)) return false; } else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) @@ -1994,6 +2007,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } player->kartstuff[k_instashield] = 15; + K_SetHitLagForObjects(target, inflictor, laglength); return true; } } @@ -2015,12 +2029,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (source && source->player && target) G_GhostAddHit((INT32) (source->player - players), target); + K_SetHitLagForObjects(target, inflictor, laglength); + if (target->health <= 0) { P_KillMobj(target, inflictor, source, damagetype); return true; } + //K_SetHitLagForObjects(target, inflictor, laglength); + if (player) P_ResetPlayer(target->player); else diff --git a/src/p_map.c b/src/p_map.c index 7a0958f7f..84cd5c970 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -357,7 +357,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) mobj_t *grease; grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE); P_SetTarget(&grease->target, object); - grease->angle = R_PointToAngle2(0, 0, object->momx, object->momy); + grease->angle = K_MomentumAngle(object); grease->extravalue1 = i; } } @@ -1217,19 +1217,31 @@ static boolean PIT_CheckThing(mobj_t *thing) if (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam) { if (tmthing->scale > thing->scale + (mapobjectscale/8)) // SRB2kart - Handle squishes first! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SQUISH); + } else if (thing->scale > tmthing->scale + (mapobjectscale/8)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_SQUISH); + } else if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) // SRB2kart - Then invincibility! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT); + } else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); + } else if ((tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) && !(thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) // SRB2kart - Then flame shield! + { P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT); + } else if ((thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) && !(tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) + { P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); + } } } @@ -2468,6 +2480,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (radius < mapobjectscale) radius = mapobjectscale; + if (thing->hitlag > 0) + { + // Do not move during hitlag + return false; + } + do { if (thing->flags & MF_NOCLIP) { tryx = x; diff --git a/src/p_maputl.c b/src/p_maputl.c index 10115e4a1..9131c24bb 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -24,19 +24,6 @@ #include "p_slopes.h" #include "z_zone.h" -// -// P_AproxDistance -// Gives an estimation of distance (not exact) -// -fixed_t P_AproxDistance(fixed_t dx, fixed_t dy) -{ - dx = abs(dx); - dy = abs(dy); - if (dx < dy) - return dx + dy - (dx>>1); - return dx + dy - (dy>>1); -} - // // P_ClosestPointOnLine // Finds the closest point on a given line to the supplied point diff --git a/src/p_maputl.h b/src/p_maputl.h index 9349d0e53..ce4509ca9 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -41,7 +41,7 @@ typedef boolean (*traverser_t)(intercept_t *in); boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, INT32 pflags, traverser_t ptrav); -FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); +#define P_AproxDistance(dx, dy) FixedHypot(dx, dy) void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result); void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *line, vector3_t *result); INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line); diff --git a/src/p_mobj.c b/src/p_mobj.c index dd8aef239..42bbecb1e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1616,8 +1616,10 @@ void P_XYMovement(mobj_t *mo) relation = transferslope->xydirection - R_PointToAngle2(0, 0, mo->momx, mo->momy); else // Give it for free, I guess. relation = ANGLE_90; + transfermomz = FixedMul(transfermomz, abs(FINESINE((relation >> ANGLETOFINESHIFT) & FINEMASK))); + if (P_MobjFlip(mo)*(transfermomz - mo->momz) > 2*FRACUNIT) // Do the actual launch! { mo->momz = transfermomz; @@ -1692,7 +1694,7 @@ void P_XYMovement(mobj_t *mo) if (oldslope != mo->standingslope) { // First, compare different slopes angle_t oldangle, newangle; - angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + angle_t moveangle = K_MomentumAngle(mo); oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT)); @@ -1724,7 +1726,7 @@ void P_XYMovement(mobj_t *mo) P_SlopeLaunch(mo); } } else if (moved && mo->standingslope && predictedz) { - angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + angle_t moveangle = K_MomentumAngle(mo); angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); /*CONS_Printf("flat to angle %f - predicted z of %f\n", @@ -4882,8 +4884,6 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj) mobj->angle += mobj->movedir; } - - mobj->angle += (angle_t)mobj->movecount; } return true; @@ -5624,6 +5624,9 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (mobj->tics > 0) mobj->drawflags ^= MFD_DONTDRAW; break; + case MT_SPINDASHWIND: + mobj->drawflags ^= MFD_DONTDRAW; + break; case MT_VWREF: case MT_VWREB: { @@ -6140,7 +6143,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) frictionsafety = FRACUNIT; } - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + mobj->angle = K_MomentumAngle(mobj); if (mobj->health <= 5) { INT32 i; @@ -6245,7 +6248,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) thrustamount = beatfriction + FixedDiv(mobj->movefactor - currentspeed, frictionsafety); } - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + mobj->angle = K_MomentumAngle(mobj); P_Thrust(mobj, mobj->angle, thrustamount); if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true)) @@ -6412,7 +6415,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) //mobj->angle = mobj->target->angle; { - angle_t angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); + angle_t angle = K_MomentumAngle(mobj->target); fixed_t nudge; mobj->angle = angle; @@ -6680,7 +6683,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { const angle_t off = FixedAngle(40*FRACUNIT); - angle_t ang = mobj->target->angle; + angle_t ang = K_MomentumAngle(mobj->target); fixed_t z; UINT8 trans = (mobj->target->player->kartstuff[k_tiregrease] * (NUMTRANSMAPS+1)) / greasetics; @@ -6693,9 +6696,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->eflags & MFE_VERTICALFLIP) z += mobj->target->height; - if (mobj->target->momx || mobj->target->momy) - ang = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); - if (mobj->extravalue1) ang = (signed)(ang - off); else @@ -6990,10 +6990,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } P_TeleportMove(mobj, destx, desty, mobj->target->z); - if (mobj->target->momx || mobj->target->momy) - mobj->angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); - else - mobj->angle = mobj->target->angle; + mobj->angle = K_MomentumAngle(mobj->target); if (underlayst != S_NULL) { @@ -7870,7 +7867,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->momx = (23*mobj->momx)/24; mobj->momy = (23*mobj->momy)/24; - mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); + mobj->angle = K_MomentumAngle(mobj); if ((mobj->z - mobj->floorz) < (24*mobj->scale) && (leveltime % 3 != 0)) { @@ -8424,6 +8421,13 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); + // Don't run any thinker code while in hitlag + if (mobj->hitlag > 0) + { + mobj->hitlag--; + return; + } + mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL); tmfloorthing = tmhitthing = NULL; @@ -9027,6 +9031,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->colorized = false; + mobj->hitlag = 0; + // Set shadowscale here, before spawn hook so that Lua can change it P_DefaultMobjShadowScale(mobj); @@ -11617,8 +11623,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean static void P_SetAmbush(mobj_t *mobj) { - if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) - mobj->angle += ANGLE_22h; + if (mobj->flags & MF_SPRING) + { + // gravity toggle + mobj->flags ^= MF_NOGRAVITY; + } if (mobj->flags & MF_NIGHTSITEM) { @@ -11647,9 +11656,6 @@ static void P_SetAmbush(mobj_t *mobj) static void P_SetObjectSpecial(mobj_t *mobj) { - if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) - mobj->flags |= MF_NOGRAVITY; - if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) { // flag for strong/weak random boxes diff --git a/src/p_mobj.h b/src/p_mobj.h index 5c205a758..97ef7c874 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -422,6 +422,8 @@ typedef struct mobj_s fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision + INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 6733fca79..7975a22f1 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -876,6 +876,10 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy) for (; mo; mo = mo->bnext) { + // lastlook is used by the SPB to determine targets, do not let it affect it + if (mo->type == MT_SPB) + continue; + if (mo->lastlook == pomovecount) continue; @@ -1106,6 +1110,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, for (; mo; mo = mo->bnext) { + // lastlook is used by the SPB to determine targets, do not let it affect it + if (mo->type == MT_SPB) + continue; + if (mo->lastlook == pomovecount) continue; diff --git a/src/p_saveg.c b/src/p_saveg.c index 36230cc78..1b02f39a7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1379,9 +1379,10 @@ typedef enum MD2_ROLLANGLE = 1<<14, MD2_SHADOWSCALE = 1<<15, MD2_DRAWFLAGS = 1<<16, - MD2_WAYPOINTCAP = 1<<17, - MD2_KITEMCAP = 1<<18, - MD2_ITNEXT = 1<<19, + MD2_HITLAG = 1<<17, + MD2_WAYPOINTCAP = 1<<18, + MD2_KITEMCAP = 1<<19, + MD2_ITNEXT = 1<<20, } mobj_diff2_t; typedef enum @@ -1596,6 +1597,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SHADOWSCALE; if (mobj->drawflags) diff2 |= MD2_DRAWFLAGS; + if (mobj->hitlag) + diff2 |= MD2_HITLAG; if (mobj == waypointcap) diff2 |= MD2_WAYPOINTCAP; if (mobj == kitemcap) @@ -1760,6 +1763,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT16(save_p, df); } + if (diff2 & MD2_HITLAG) + WRITEINT32(save_p, mobj->hitlag); WRITEUINT32(save_p, mobj->mobjnum); } @@ -2824,6 +2829,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) } if (diff2 & MD2_DRAWFLAGS) mobj->drawflags = READUINT16(save_p); + if (diff2 & MD2_HITLAG) + mobj->hitlag = READINT32(save_p); if (diff & MD_REDFLAG) { diff --git a/src/p_spec.c b/src/p_spec.c index f95bbd39d..926e0478e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4602,8 +4602,7 @@ DoneSection2: { const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 + angle_t pushangle = K_MomentumAngle(player->mo); if (player->mo->eflags & MFE_SPRUNG) break; @@ -4625,8 +4624,7 @@ DoneSection2: const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; const fixed_t maxspeed = 28*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 + angle_t pushangle = K_MomentumAngle(player->mo); if (player->mo->eflags & MFE_SPRUNG) break; @@ -4673,7 +4671,7 @@ DoneSection2: } lineangle = K_ReflectAngle( - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), lineangle, + K_MomentumAngle(player->mo), lineangle, playerspeed, linespeed ); diff --git a/src/p_user.c b/src/p_user.c index 45c297da9..37e923c4d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2265,7 +2265,7 @@ void P_MovePlayer(player_t *player) if (trailScale > 0) { - const angle_t forwardangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + const angle_t forwardangle = K_MomentumAngle(player->mo); const fixed_t playerVisualRadius = player->mo->radius + 8*FRACUNIT; const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); @@ -4065,7 +4065,7 @@ static void P_HandleFollower(player_t *player) player->follower->drawflags |= MFD_DONTDRAW; if (player->speed && (player->follower->momx || player->follower->momy)) - player->follower->angle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy); + player->follower->angle = K_MomentumAngle(player->follower); // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. // Make sure the follower itself is also moving however, otherwise we'll be facing angle 0 @@ -4211,6 +4211,11 @@ void P_PlayerThink(player_t *player) } #endif + if (player->mo->hitlag > 0) + { + return; + } + if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj)) { P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid @@ -4297,6 +4302,7 @@ void P_PlayerThink(player_t *player) if (player->playerstate == PST_DEAD) { + LUAh_PlayerThink(player); return; } } diff --git a/src/r_main.c b/src/r_main.c index 8e05b8d27..835ed26f7 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -368,29 +368,7 @@ angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) { - angle_t angle; - fixed_t dx, dy, dist; - - dx = abs(px1 - px2); - dy = abs(py1 - py2); - - if (dy > dx) - { - fixed_t temp; - - temp = dx; - dx = dy; - dy = temp; - } - if (!dy) - return dx; - - angle = (tantoangle[FixedDiv(dy, dx)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT; - - // use as cosine - dist = FixedDiv(dx, FINESINE(angle)); - - return dist; + return FixedHypot(px1 - px2, py1 - py2); } // Little extra utility. Works in the same way as R_PointToAngle2 diff --git a/src/r_things.c b/src/r_things.c index fd200cf87..9788d916b 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1074,14 +1074,6 @@ static void R_SplitSprite(vissprite_t *sprite) sprite->sz = cutfrac; newsprite->szt = (INT16)(sprite->sz - 1); - if (testheight < sprite->pzt && testheight > sprite->pz) - sprite->pz = newsprite->pzt = testheight; - else - { - newsprite->pz = newsprite->gz; - newsprite->pzt = newsprite->gzt; - } - newsprite->szt -= 8; newsprite->cut |= SC_TOP; @@ -1238,6 +1230,32 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) return groundz; } +static void R_SetSpritePlaneHeights(vissprite_t *vis) +{ + ffloor_t *rover; + + fixed_t top; + fixed_t bot; + + vis->pt = vis->sector->floorheight; + vis->pb = vis->sector->ceilingheight; + + for (rover = vis->sector->ffloors; rover; rover = rover->next) + { + if (rover->flags & FF_EXISTS) + { + top = P_GetFFloorTopZAt (rover, vis->gx, vis->gy); + bot = P_GetFFloorBottomZAt (rover, vis->gx, vis->gy); + + if (top <= vis->gzt && top > vis->pt) + vis->pt = top; + + if (bot >= vis->gz && bot < vis->pb) + vis->pb = bot; + } + } +} + static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz) { vissprite_t *shadow; @@ -1305,16 +1323,12 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->patch = patch; shadow->heightsec = vis->heightsec; - shadow->thingheight = FRACUNIT; - shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0); - shadow->pzt = shadow->pz + shadow->thingheight; - shadow->mobjflags = 0; shadow->sortscale = vis->sortscale; shadow->dispoffset = vis->dispoffset - 5; shadow->gx = thing->x; shadow->gy = thing->y; - shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + SHORT(patch->height) * shadowyscale / 2; + shadow->gzt = groundz + SHORT(patch->height) * shadowyscale / 2; shadow->gz = shadow->gzt - SHORT(patch->height) * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) @@ -1330,6 +1344,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000 shadow->scale = FixedMul(yscale, shadowyscale); shadow->sector = vis->sector; + shadow->pt = vis->pt; + shadow->pb = vis->pb; shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS); shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS); shadow->cut = SC_ISSCALED|SC_SHADOW; //check this @@ -1387,9 +1403,9 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, // static void R_ProjectSprite(mobj_t *thing) { - const fixed_t thingxpos = thing->x + thing->sprxoff; - const fixed_t thingypos = thing->y + thing->spryoff; - const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t thingxpos = thing->x + thing->sprxoff; + fixed_t thingypos = thing->y + thing->spryoff; + fixed_t thingzpos = thing->z + thing->sprzoff; mobj_t *oldthing = thing; @@ -1448,6 +1464,21 @@ static void R_ProjectSprite(mobj_t *thing) INT32 rollangle = 0; #endif + // hitlag vibrating + if (thing->hitlag > 0) + { + fixed_t mul = thing->hitlag * (FRACUNIT / 10); + + if (leveltime & 1) + { + mul = -mul; + } + + thingxpos += FixedMul(thing->momx, mul); + thingypos += FixedMul(thing->momy, mul); + thingzpos += FixedMul(thing->momz, mul); + } + // transform the origin point tr_x = thingxpos - viewx; tr_y = thingypos - viewy; @@ -1812,9 +1843,6 @@ static void R_ProjectSprite(mobj_t *thing) vis->gy = thingypos; vis->gz = gz; vis->gzt = gzt; - vis->thingheight = thing->height; - vis->pz = thingzpos; - vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = scalestep; vis->paperoffset = paperoffset; @@ -1832,6 +1860,9 @@ static void R_ProjectSprite(mobj_t *thing) vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); + + R_SetSpritePlaneHeights(vis); + vis->cut = cut; if (thing->subsector->sector->numlights) vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; @@ -2032,9 +2063,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; - vis->thingheight = 4*FRACUNIT; - vis->pz = thing->z; - vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; vis->paperdistance = 0; @@ -2049,6 +2077,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS); + R_SetSpritePlaneHeights(vis); + iscale = FixedDiv(FRACUNIT, xscale); vis->startfrac = 0; @@ -2425,19 +2455,15 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height); planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); - if (rover->mobjflags & MF_NOCLIPHEIGHT) + // bird: if any part of the sprite peeks in front the plane + if (planecameraz < viewz) { - //Objects with NOCLIPHEIGHT can appear halfway in. - if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz) + if (rover->pt >= planeobjectz && rover->gzt >= planeobjectz) continue; } - else + else if (planecameraz > viewz) { - if (planecameraz < viewz && rover->pz >= planeobjectz) - continue; - if (planecameraz > viewz && rover->pzt <= planeobjectz) + if (rover->pb <= planeobjectz && rover->gz <= planeobjectz) continue; } diff --git a/src/r_things.h b/src/r_things.h index b6e8a1d9d..f95cd5c9e 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -138,8 +138,7 @@ typedef struct vissprite_s INT32 x1, x2; fixed_t gx, gy; // for line side calculation - fixed_t gz, gzt; // global bottom/top for silhouette clipping - fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors + fixed_t gz, gzt; // global bottom/top for silhouette clipping and sorting with 3D floors fixed_t startfrac; // horizontal position of x1 fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW @@ -171,8 +170,8 @@ typedef struct vissprite_s fixed_t xscale; // Precalculated top and bottom screen coords for the sprite. - fixed_t thingheight; // The actual height of the thing (for 3D floors) sector_t *sector; // The sector containing the thing. + fixed_t pt, pb; // plane heights, also for sorting against 3D floors INT16 sz, szt; spritecut_e cut; diff --git a/src/s_sound.c b/src/s_sound.c index a7d45e160..7c9abbf32 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2336,7 +2336,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) S_InitMusicVolume(); // switch between digi and sequence volume if (S_MusicNotInFocus()) - S_PauseAudio(); + I_SetMusicVolume(0); return true; } @@ -2780,9 +2780,9 @@ static void PlayMusicIfUnfocused_OnChange(void) if (window_notinfocus) { if (cv_playmusicifunfocused.value) - I_PauseSong(); + I_SetMusicVolume(0); else - I_ResumeSong(); + S_InitMusicVolume(); } } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 5a9db4963..5e28e8643 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -651,7 +651,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) window_notinfocus = false; if (!paused) - S_ResumeAudio(); //resume it + S_InitMusicVolume(); if (cv_gamesounds.value) S_EnableSound(); @@ -670,7 +670,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) // Tell game we lost focus, pause music window_notinfocus = true; if (!cv_playmusicifunfocused.value) - I_PauseSong(); + I_SetMusicVolume(0); if (!cv_playsoundifunfocused.value) S_DisableSound(); diff --git a/src/stun.c b/src/stun.c new file mode 100644 index 000000000..722d32906 --- /dev/null +++ b/src/stun.c @@ -0,0 +1,235 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file stun.c +/// \brief RFC 5389 client implementation to fetch external IP address. + +/* https://tools.ietf.org/html/rfc5389 */ + +#if defined (__linux__) +#include +#elif defined (_WIN32) +#define _CRT_RAND_S +#elif defined (__APPLE__) +#include +#else +#error "Need CSPRNG." +#endif + +#include "doomdef.h" +#include "d_clisrv.h" +#include "command.h" +#include "i_net.h" +#include "stun.h" + +/* https://gist.github.com/zziuni/3741933 */ +/* I can only trust google to keep their shit up :y */ +consvar_t cv_stunserver = CVAR_INIT ( + "stunserver", "stun.l.google.com:19302", CV_SAVE, NULL, NULL +); + +static stun_callback_t stun_callback; + +/* 18.4 STUN UDP and TCP Port Numbers */ + +#define STUN_PORT "3478" + +/* 6. STUN Message Structure */ + +#define BIND_REQUEST 0x0001 +#define BIND_RESPONSE 0x0101 + +static const UINT32 MAGIC_COOKIE = MSBF_LONG (0x2112A442); + +static char transaction_id[12]; + +/* 18.2 STUN Attribute Registry */ + +#define XOR_MAPPED_ADDRESS 0x0020 + +/* 15.1 MAPPED-ADDRESS */ + +#define STUN_IPV4 0x01 + +static SINT8 +STUN_node (void) +{ + SINT8 node; + + char * const colon = strchr(cv_stunserver.zstring, ':'); + + const char * const host = cv_stunserver.zstring; + const char * const port = &colon[1]; + + I_Assert(I_NetMakeNodewPort != NULL); + + if (colon != NULL) + { + *colon = '\0'; + + node = I_NetMakeNodewPort(host, port); + + *colon = ':'; + } + else + { + node = I_NetMakeNodewPort(host, STUN_PORT); + } + + return node; +} + +static void +csprng +( + void * const buffer, + const size_t size +){ +#if defined (_WIN32) + size_t o; + + for (o = 0; o < size; o += sizeof (unsigned int)) + { + rand_s((unsigned int *)&((char *)buffer)[o]); + } +#elif defined (__linux__) + getrandom(buffer, size, 0U); +#elif defined (__APPLE__) + CCRandomGenerateBytes(buffer, size); +#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) + arc4random_buf(buffer, size); +#endif +} + +void +STUN_bind (stun_callback_t callback) +{ + /* 6. STUN Message Structure */ + + const UINT16 type = MSBF_SHORT (BIND_REQUEST); + + const SINT8 node = STUN_node(); + + doomcom->remotenode = node; + doomcom->datalength = 20; + + csprng(transaction_id, 12U); + + memcpy(&doomcom->data[0], &type, 2U); + memset(&doomcom->data[2], 0, 2U); + memcpy(&doomcom->data[4], &MAGIC_COOKIE, 4U); + memcpy(&doomcom->data[8], transaction_id, 12U); + + stun_callback = callback; + + I_NetSend(); + Net_CloseConnection(node);/* will handle response at I_NetGet */ +} + +static size_t +STUN_xor_mapped_address (const char * const value) +{ + const UINT32 xaddr = *(const UINT32 *)&value[4]; + const UINT32 addr = xaddr ^ MAGIC_COOKIE; + + (*stun_callback)(addr); + + return 0U; +} + +static size_t +align4 (size_t n) +{ + return n + n % 4U; +} + +static size_t +STUN_parse_attribute (const char * const attribute) +{ + /* 15. STUN Attributes */ + const UINT16 type = MSBF_SHORT (*(const UINT16 *)&attribute[0]); + const UINT16 length = MSBF_SHORT (*(const UINT16 *)&attribute[2]); + + /* 15.2 XOR-MAPPED-ADDRESS */ + if ( + type == XOR_MAPPED_ADDRESS && + length == 8U && + (unsigned char)attribute[5] == STUN_IPV4 + ){ + return STUN_xor_mapped_address(&attribute[4]); + } + + return align4(4U + length); +} + +boolean +STUN_got_response +( + const char * const buffer, + const size_t size +){ + const char * const end = &buffer[size]; + + const char * p = &buffer[20]; + + UINT16 type; + UINT16 length; + + /* + Check for STUN response. + + Header is 20 bytes. + XOR-MAPPED-ADDRESS attribute is required. + Each attribute has a 2 byte header. + The XOR-MAPPED-ADDRESS attribute also has a 8 byte value. + This totals 10 bytes for the attribute. + */ + + if (size < 30U || stun_callback == NULL) + { + return false; + } + + /* 6. STUN Message Structure */ + + if ( + *(const UINT32 *)&buffer[4] == MAGIC_COOKIE && + memcmp(&buffer[8], transaction_id, 12U) == 0 + ){ + type = MSBF_SHORT (*(const UINT16 *)&buffer[0]); + length = MSBF_SHORT (*(const UINT16 *)&buffer[2]); + + if ( + (type >> 14) == 0U && + (length & 0x02) == 0U && + (20U + length) <= size + ){ + if (type == BIND_RESPONSE) + { + do + { + length = STUN_parse_attribute(p); + + if (length == 0U) + { + break; + } + + p += length; + } + while (p < end) ; + } + + stun_callback = NULL; + + return true; + } + } + + return false; +} diff --git a/src/stun.h b/src/stun.h new file mode 100644 index 000000000..de23aeb42 --- /dev/null +++ b/src/stun.h @@ -0,0 +1,20 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file stun.h +/// \brief RFC 5389 client implementation to fetch external IP address. + +#ifndef KART_STUN_H +#define KART_STUN_H + +typedef void (*stun_callback_t)(UINT32 address); + +void STUN_bind (stun_callback_t); +boolean STUN_got_response (const char * const buffer, const size_t size); + +#endif/*KART_STUN_H*/