diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3347091a3..8a04bcca7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -81,7 +81,7 @@ boolean server = true; // true or false but !server == client #define client (!server) boolean nodownload = false; -static boolean serverrunning = false; +boolean serverrunning = false; INT32 serverplayer = 0; char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) diff --git a/src/d_net.h b/src/d_net.h index eb657eec1..e9b2f5dbf 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -41,6 +41,8 @@ extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if a extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game +extern boolean serverrunning; + INT32 Net_GetFreeAcks(boolean urgent); void Net_AckTicker(void); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bd7f16228..7def24de5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -73,6 +73,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum); static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum); static void Got_PickVotecmd(UINT8 **cp, INT32 playernum); +static void Got_GiveItemcmd(UINT8 **cp, INT32 playernum); static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum); #ifdef DELFILE static void Got_Delfilecmd(UINT8 **cp, INT32 playernum); @@ -203,6 +204,8 @@ static void Command_Archivetest_f(void); #endif #endif +static void Command_KartGiveItem_f(void); + // ========================================================================= // CLIENT VARIABLES // ========================================================================= @@ -393,10 +396,24 @@ consvar_t cv_karteliminatelast = {"karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT consvar_t cv_kartusepwrlv = {"kartusepwrlv", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t kartdebugitem_cons_t[] = {{-1, "MIN"}, {NUMKARTITEMS-1, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t kartdebugitem_cons_t[] = +{ +#define FOREACH( name, n ) { n, #name } + KART_ITEM_ITERATOR, +#undef FOREACH + {0} +}; consvar_t cv_kartdebugitem = {"kartdebugitem", "0", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugitem_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; consvar_t cv_kartdebugamount = {"kartdebugamount", "1", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugamount_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartallowgiveitem = {"kartallowgiveitem", +#ifdef DEVELOP + "Yes", +#else + "No", +#endif + CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL +}; consvar_t cv_kartdebugshrink = {"kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -527,6 +544,11 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "PICKVOTE", "REMOVEPLAYER", "POWERLEVEL", + "PARTYINVITE", + "ACCEPTPARTYINVITE", + "LEAVEPARTY", + "CANCELPARTYINVITE", + "GIVEITEM", #ifdef HAVE_BLUA "LUACMD", "LUAVAR" @@ -587,6 +609,8 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_MODIFYVOTE, Got_ModifyVotecmd); RegisterNetXCmd(XD_PICKVOTE, Got_PickVotecmd); + RegisterNetXCmd(XD_GIVEITEM, Got_GiveItemcmd); + // Remote Administration CV_RegisterVar(&cv_dummyjoinpassword); COM_AddCommand("joinpassword", Command_ChangeJoinPassword_f); @@ -645,6 +669,8 @@ void D_RegisterServerCommands(void) #endif #endif + COM_AddCommand("kartgiveitem", Command_KartGiveItem_f); + // for master server connection AddMServCommands(); @@ -1034,6 +1060,13 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_soundtest); + CV_RegisterVar(&cv_invincmusicfade); + CV_RegisterVar(&cv_growmusicfade); + + CV_RegisterVar(&cv_resetspecialmusic); + + CV_RegisterVar(&cv_resume); + // ingame object placing COM_AddCommand("objectplace", Command_ObjectPlace_f); COM_AddCommand("writethings", Command_Writethings_f); @@ -5719,6 +5752,41 @@ static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) Y_SetupVoteFinish(pick, level); } +static void Got_GiveItemcmd(UINT8 **cp, INT32 playernum) +{ + int item; + int amt; + + INT32 *kartstuff; + + item = READSINT8 (*cp); + amt = READUINT8 (*cp); + + if ( + ( netgame && ! cv_kartallowgiveitem.value ) || + ( item < KITEM_SAD || item >= NUMKARTITEMS ) + ) + { + CONS_Alert(CONS_WARNING, + M_GetText ("Illegal give item received from %s\n"), + player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + kartstuff = players[playernum].kartstuff; + + kartstuff[k_itemtype] = item; + kartstuff[k_itemamount] = amt; +} + /** Prints the number of displayplayers[0]. * * \todo Possibly remove this; it was useful for debugging at one point. @@ -5904,6 +5972,80 @@ static void Command_Archivetest_f(void) #endif #endif +/** Give yourself an, optional quantity or one of, an item. + * + * \sa cv_kartallowgiveitem +*/ +static void Command_KartGiveItem_f(void) +{ + char buf[2]; + + int ac; + const char *name; + int item; + + const char * str; + + int i; + + /* Allow always in local games. */ + if (! netgame || cv_kartallowgiveitem.value) + { + ac = COM_Argc(); + if (ac < 2) + { + CONS_Printf( +"kartgiveitem [amount]: Give yourself an item\n" + ); + } + else + { + item = NUMKARTITEMS; + + name = COM_Argv(1); + + if (isdigit(*name) || *name == '-') + { + item = atoi(name); + } + else + { + for (i = 0; ( str = kartdebugitem_cons_t[i].strvalue ); ++i) + { + if (strcasecmp(name, str) == 0) + { + item = kartdebugitem_cons_t[i].value; + break; + } + } + } + + if (item < NUMKARTITEMS) + { + buf[0] = item; + + if (ac > 2) + buf[1] = atoi(COM_Argv(2)); + else + buf[1] = 1;/* default to one quantity */ + + SendNetXCmd(XD_GIVEITEM, buf, 2); + } + else + { + CONS_Alert(CONS_WARNING, + "No item matches '%s'\n", + name); + } + } + } + else + { + CONS_Alert(CONS_NOTICE, + "The server does not allow this.\n"); + } +} + /** Makes a change to ::cv_forceskin take effect immediately. * * \sa Command_SetForcedSkin_f, cv_forceskin, forcedskin diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 81854bc71..293590220 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -126,7 +126,7 @@ extern consvar_t cv_kartusepwrlv; extern consvar_t cv_votetime; -extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; +extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartallowgiveitem, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes, cv_kartdebugcolorize; extern consvar_t cv_kartdebugwaypoints; @@ -187,9 +187,10 @@ typedef enum XD_ACCEPTPARTYINVITE, // 28 XD_LEAVEPARTY, // 29 XD_CANCELPARTYINVITE, // 30 + XD_GIVEITEM, // 31 #ifdef HAVE_BLUA - XD_LUACMD, // 31 - XD_LUAVAR, // 32 + XD_LUACMD, // 32 + XD_LUAVAR, // 33 #endif MAXNETXCMD } netxcmd_t; diff --git a/src/d_player.h b/src/d_player.h index 2465b90ef..18874b7b7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -200,29 +200,39 @@ typedef enum NUMPOWERS } powertype_t; +/* +To use: #define FOREACH( name, number ) +Do with it whatever you want. +Run this macro, then #undef FOREACH afterward +*/ +#define KART_ITEM_ITERATOR \ + FOREACH (SAD, -1),\ + FOREACH (NONE, 0),\ + FOREACH (SNEAKER, 1),\ + FOREACH (ROCKETSNEAKER, 2),\ + FOREACH (INVINCIBILITY, 3),\ + FOREACH (BANANA, 4),\ + FOREACH (EGGMAN, 5),\ + FOREACH (ORBINAUT, 6),\ + FOREACH (JAWZ, 7),\ + FOREACH (MINE, 8),\ + FOREACH (BALLHOG, 9),\ + FOREACH (SPB, 10),\ + FOREACH (GROW, 11),\ + FOREACH (SHRINK, 12),\ + FOREACH (THUNDERSHIELD, 13),\ + FOREACH (BUBBLESHIELD, 14),\ + FOREACH (FLAMESHIELD, 15),\ + FOREACH (HYUDORO, 16),\ + FOREACH (POGOSPRING, 17),\ + FOREACH (SUPERRING, 18),\ + FOREACH (KITCHENSINK, 19) + typedef enum { - KITEM_SAD = -1, - KITEM_NONE = 0, - KITEM_SNEAKER, - KITEM_ROCKETSNEAKER, - KITEM_INVINCIBILITY, - KITEM_BANANA, - KITEM_EGGMAN, - KITEM_ORBINAUT, - KITEM_JAWZ, - KITEM_MINE, - KITEM_BALLHOG, - KITEM_SPB, - KITEM_GROW, - KITEM_SHRINK, - KITEM_THUNDERSHIELD, - KITEM_BUBBLESHIELD, - KITEM_FLAMESHIELD, - KITEM_HYUDORO, - KITEM_POGOSPRING, - KITEM_SUPERRING, - KITEM_KITCHENSINK, +#define FOREACH( name, n ) KITEM_ ## name = n + KART_ITEM_ITERATOR, +#undef FOREACH NUMKARTITEMS, diff --git a/src/dehacked.c b/src/dehacked.c index 8507a1b03..db94c5227 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9115,27 +9115,9 @@ struct { // SRB2Kart // kartitems_t - {"KITEM_SAD",KITEM_SAD}, // Actual items (can be set for k_itemtype) - {"KITEM_NONE",KITEM_NONE}, - {"KITEM_SNEAKER",KITEM_SNEAKER}, - {"KITEM_ROCKETSNEAKER",KITEM_ROCKETSNEAKER}, - {"KITEM_INVINCIBILITY",KITEM_INVINCIBILITY}, - {"KITEM_BANANA",KITEM_BANANA}, - {"KITEM_EGGMAN",KITEM_EGGMAN}, - {"KITEM_ORBINAUT",KITEM_ORBINAUT}, - {"KITEM_JAWZ",KITEM_JAWZ}, - {"KITEM_MINE",KITEM_MINE}, - {"KITEM_BALLHOG",KITEM_BALLHOG}, - {"KITEM_SPB",KITEM_SPB}, - {"KITEM_GROW",KITEM_GROW}, - {"KITEM_SHRINK",KITEM_SHRINK}, - {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, - {"KITEM_BUBBLESHIELD",KITEM_BUBBLESHIELD}, - {"KITEM_FLAMESHIELD",KITEM_FLAMESHIELD}, - {"KITEM_HYUDORO",KITEM_HYUDORO}, - {"KITEM_POGOSPRING",KITEM_POGOSPRING}, - {"KITEM_SUPERRING",KITEM_SUPERRING}, - {"KITEM_KITCHENSINK",KITEM_KITCHENSINK}, +#define FOREACH( name, n ) { #name, KITEM_ ## name } + KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype) +#undef FOREACH {"NUMKARTITEMS",NUMKARTITEMS}, {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) {"KRITEM_TRIPLEBANANA",KRITEM_TRIPLEBANANA}, diff --git a/src/doomstat.h b/src/doomstat.h index 952586231..9464385ea 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -34,6 +34,7 @@ extern INT16 gamemap; extern char mapmusname[7]; extern UINT16 mapmusflags; extern UINT32 mapmusposition; +extern UINT32 mapmusresume; #define MUSIC_TRACKMASK 0x0FFF // ----************ #define MUSIC_RELOADRESET 0x8000 // *--------------- #define MUSIC_FORCERESET 0x4000 // -*-------------- diff --git a/src/g_game.c b/src/g_game.c index 684e73492..a97143d21 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -81,6 +81,7 @@ static void G_DoStartVote(void); char mapmusname[7]; // Music name UINT16 mapmusflags; // Track and reset bit UINT32 mapmusposition; // Position to jump to +UINT32 mapmusresume; INT16 gamemap = 1; INT16 maptol; @@ -526,6 +527,12 @@ consvar_t cv_fireaxis4 = {"joyaxis4_fire", "Z-Axis", CV_SAVE, joyaxis_cons_t, NU consvar_t cv_driftaxis4 = {"joyaxis4_drift", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_deadzone4 = {"joy4_deadzone", "0.5", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_invincmusicfade = {"invincmusicfade", "300", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_growmusicfade = {"growmusicfade", "500", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_resetspecialmusic = {"resetspecialmusic", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_resume = {"resume", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; #if MAXPLAYERS > 16 #error "please update player_name table using the new value for MAXPLAYERS" @@ -2742,11 +2749,13 @@ void G_PlayerReborn(INT32 player) mapmusname[6] = 0; mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); mapmusposition = mapheaderinfo[gamemap-1]->muspos; + mapmusresume = 0; songcredit = true; } } P_RestoreMusic(p); + if (songcredit) S_ShowMusicCredit(); diff --git a/src/g_game.h b/src/g_game.h index 08af3a2b5..2a517777a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -118,6 +118,13 @@ extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4,cv_deadzone4; extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff; +extern consvar_t cv_invincmusicfade; +extern consvar_t cv_growmusicfade; + +extern consvar_t cv_resetspecialmusic; + +extern consvar_t cv_resume; + typedef enum { AXISNONE = 0, diff --git a/src/i_sound.h b/src/i_sound.h index 9a5c2930a..93e3f6dd0 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -158,6 +158,9 @@ UINT32 I_GetSongLoopPoint(void); boolean I_SetSongPosition(UINT32 position); UINT32 I_GetSongPosition(void); +void I_UpdateSongLagThreshold (void); +void I_UpdateSongLagConditions (void); + /// ------------------------ // MUSIC PLAYBACK /// ------------------------ diff --git a/src/i_tcp.c b/src/i_tcp.c index f58aa22bc..1f1cf4f22 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -246,7 +246,8 @@ static size_t numbans = 0; static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? static boolean init_tcp_driver = false; -static char port_name[8] = DEFAULTPORT; +static const char *serverport_name = DEFAULTPORT; +static const char *clientport_name;/* any port */ #ifndef NONET @@ -924,6 +925,7 @@ static boolean UDP_Socket(void) #ifdef HAVE_IPV6 const INT32 b_ipv6 = M_CheckParm("-ipv6"); #endif + const char *serv; for (s = 0; s < mysocketses; s++) @@ -939,11 +941,16 @@ static boolean UDP_Socket(void) hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; + if (serverrunning) + serv = serverport_name; + else + serv = clientport_name; + if (M_CheckParm("-bindaddr")) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -964,7 +971,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("0.0.0.0", port_name, &hints, &ai); + gaie = I_getaddrinfo("0.0.0.0", serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -979,8 +986,8 @@ static boolean UDP_Socket(void) #ifdef HAVE_MINIUPNPC if (UPNP_support) { - I_UPnP_rem(port_name, "UDP"); - I_UPnP_add(NULL, port_name, "UDP"); + I_UPnP_rem(serverport_name, "UDP"); + I_UPnP_add(NULL, serverport_name, "UDP"); } #endif } @@ -997,7 +1004,7 @@ static boolean UDP_Socket(void) { while (M_IsNextParm()) { - gaie = I_getaddrinfo(M_GetNextParm(), port_name, &hints, &ai); + gaie = I_getaddrinfo(M_GetNextParm(), serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -1018,7 +1025,7 @@ static boolean UDP_Socket(void) } else { - gaie = I_getaddrinfo("::", port_name, &hints, &ai); + gaie = I_getaddrinfo("::", serv, &hints, &ai); if (gaie == 0) { runp = ai; @@ -1475,15 +1482,19 @@ boolean I_InitTcpNetwork(void) if (!I_InitTcpDriver()) return false; - if (M_CheckParm("-port")) + if (M_CheckParm("-port") || M_CheckParm("-serverport")) // Combined -udpport and -clientport into -port // As it was really redundant having two seperate parms that does the same thing + /* Sorry Steel, I'm adding these back. But -udpport is a stupid name. */ { - if (M_IsNextParm()) - strcpy(port_name, M_GetNextParm()); - else - strcpy(port_name, "0"); + /* + If it's NULL, that's okay! Because then + we'll get a random port from getaddrinfo. + */ + serverport_name = M_GetNextParm(); } + if (M_CheckParm("-clientport")) + clientport_name = M_GetNextParm(); // parse network game options, if (M_CheckParm("-server") || dedicated) diff --git a/src/k_collide.c b/src/k_collide.c index f13ba3423..1921e3d38 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -15,6 +15,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) { boolean damageitem = false; + boolean sprung = false; if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) return true; @@ -81,7 +82,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) else if (t2->flags & MF_SPRING && (t1->type != MT_ORBINAUT_SHIELD && t1->type != MT_JAWZ_SHIELD)) { // Let thrown items hit springs! - P_DoSpring(t2, t1); + sprung = P_DoSpring(t2, t1); } else if (t2->flags & MF_SHOOTABLE) { @@ -105,6 +106,11 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y)+ANGLE_90, 16*FRACUNIT); } + if (sprung) + { + return false; + } + return true; } diff --git a/src/k_kart.c b/src/k_kart.c index e7faed5b0..2a672af13 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -629,6 +629,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugitem); CV_RegisterVar(&cv_kartdebugamount); CV_RegisterVar(&cv_kartdebugshrink); + CV_RegisterVar(&cv_kartallowgiveitem); CV_RegisterVar(&cv_kartdebugdistribution); CV_RegisterVar(&cv_kartdebughuddrop); CV_RegisterVar(&cv_kartdebugwaypoints); @@ -4780,6 +4781,10 @@ void K_DropHnextList(player_t *player, boolean keepshields) orbit = false; type = MT_EGGMANITEM; break; + // intentionally do nothing + case MT_ROCKETSNEAKER: + case MT_SINK_SHIELD: + return; default: continue; } @@ -6717,54 +6722,65 @@ boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y) // turndir is the direction the controls are telling us to turn, -1 if turning right and 1 if turning left static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer) { - INT16 basedrift, driftangle; + INT16 basedrift, driftadjust; fixed_t driftweight = player->kartweight*14; // 12 - // If they aren't drifting or on the ground this doesn't apply if (player->kartstuff[k_drift] == 0 || !P_IsObjectOnGround(player->mo)) + { + // If they aren't drifting or on the ground, this doesn't apply return 0; + } if (player->kartstuff[k_driftend] != 0) - return -266*player->kartstuff[k_drift]; // Drift has ended and we are tweaking their angle back a bit + { + // Drift has ended and we are tweaking their angle back a bit + return -266*player->kartstuff[k_drift]; + } - //basedrift = 90*player->kartstuff[k_drift]; // 450 - //basedrift = 93*player->kartstuff[k_drift] - driftweight*3*player->kartstuff[k_drift]/10; // 447 - 303 - basedrift = 83*player->kartstuff[k_drift] - (driftweight - 14)*player->kartstuff[k_drift]/5; // 415 - 303 - driftangle = abs((252 - driftweight)*player->kartstuff[k_drift]/5); + basedrift = (83 * player->kartstuff[k_drift]) - (((driftweight - 14) * player->kartstuff[k_drift]) / 5); // 415 - 303 + driftadjust = abs((252 - driftweight) * player->kartstuff[k_drift] / 5); if (player->kartstuff[k_tiregrease] > 0) // Buff drift-steering while in greasemode + { basedrift += (basedrift / greasetics) * player->kartstuff[k_tiregrease]; + } - return basedrift + FixedMul(driftangle, countersteer); + return basedrift + (FixedMul(driftadjust * FRACUNIT, countersteer) / FRACUNIT); } INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) { - fixed_t p_maxspeed = FixedMul(K_GetKartSpeed(player, false), 3*FRACUNIT); - fixed_t adjustangle = FixedDiv((p_maxspeed>>16) - (player->speed>>16), (p_maxspeed>>16) + player->kartweight); + fixed_t p_maxspeed = K_GetKartSpeed(player, false); + fixed_t p_speed = min(player->speed, (p_maxspeed * 2)); + fixed_t weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT)); if (player->spectator) + { return turnvalue; + } if (player->kartstuff[k_drift] != 0 && P_IsObjectOnGround(player->mo)) { + fixed_t countersteer = FixedDiv(turnvalue*FRACUNIT, KART_FULLTURN*FRACUNIT); + // If we're drifting we have a completely different turning value - if (player->kartstuff[k_driftend] == 0) + + if (player->kartstuff[k_driftend] != 0) { - // 800 is the max set in g_game.c with angleturn - fixed_t countersteer = FixedDiv(turnvalue*FRACUNIT, 800*FRACUNIT); - turnvalue = K_GetKartDriftValue(player, countersteer); + countersteer = FRACUNIT; } - else - turnvalue = (INT16)(turnvalue + K_GetKartDriftValue(player, FRACUNIT)); + + turnvalue = K_GetKartDriftValue(player, countersteer); return turnvalue; } - turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning - if (EITHERSNEAKER(player) || player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_growshrinktimer] > 0) - turnvalue = FixedMul(turnvalue, (5*FRACUNIT)/4); + { + turnvalue = 5*turnvalue/4; + } + + turnvalue = FixedMul(turnvalue * FRACUNIT, weightadjust) / FRACUNIT; // Weight has a small effect on turning return turnvalue; } @@ -7349,9 +7365,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetScale(overlay, player->mo->scale); } player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds + if (P_IsDisplayPlayer(player)) + S_ChangeMusicSpecial("kinvnc"); + else + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kinvnc)); P_RestoreMusic(player); - if (!P_IsDisplayPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); K_PlayPowerGloatSound(player->mo); player->kartstuff[k_itemamount]--; } @@ -7551,9 +7569,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (cv_kartdebugshrink.value && !modeattacking && !player->bot) player->mo->destscale = (6*player->mo->destscale)/8; player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds - P_RestoreMusic(player); - if (!P_IsDisplayPlayer(player)) + if (P_IsDisplayPlayer(player)) + S_ChangeMusicSpecial("kgrow"); + else S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); + P_RestoreMusic(player); S_StartSound(player->mo, sfx_kc5a); } player->kartstuff[k_itemamount]--; diff --git a/src/p_mobj.c b/src/p_mobj.c index 2838e9388..499ff4ff3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8981,13 +8981,39 @@ void P_MobjThinker(mobj_t *mobj) { if (ticstilimpact <= 8) { - newskin = ((skin_t*)mobj->target->skin)-skins; + newskin = mobj->target->player->skin; newcolor = mobj->target->player->skincolor; } else { - newskin = leveltime % numskins; - newcolor = skins[newskin].prefcolor; + UINT8 plist[MAXPLAYERS]; + UINT8 plistlen = 0; + UINT8 i; + + memset(plist, 0, sizeof(plist)); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + { + plist[plistlen] = i; + plistlen++; + } + } + + if (plistlen <= 1) + { + // Default to the winner + newskin = mobj->target->player->skin; + newcolor = mobj->target->player->skincolor; + } + else + { + // Pick another player in the server! + player_t *p = &players[plist[P_RandomKey(plistlen)]]; + newskin = p->skin; + newcolor = p->skincolor; + } } } } diff --git a/src/p_spec.c b/src/p_spec.c index ad711fb8b..a3ed2ad57 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2518,6 +2518,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) mapmusflags |= MUSIC_FORCERESET; mapmusposition = position; + mapmusresume = 0; S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position, !(line->flags & ML_EFFECT2) ? prefadems : 0, @@ -4096,25 +4097,11 @@ DoneSection2: lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y); - player->mo->angle = lineangle; - // SRB2Kart: Scale the speed you get from them! // This is scaled differently from other horizontal speed boosts from stuff like springs, because of how this is used for some ramp jumps. if (player->mo->scale > mapobjectscale) linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale)); - if (!demo.playback) - { - if (player == &players[consoleplayer]) - localangle[0] = player->mo->angle; - else if (player == &players[displayplayers[1]]) - localangle[1] = player->mo->angle; - else if (player == &players[displayplayers[2]]) - localangle[2] = player->mo->angle; - else if (player == &players[displayplayers[3]]) - localangle[3] = player->mo->angle; - } - if (!(lines[i].flags & ML_EFFECT4)) { P_UnsetThingPosition(player->mo); @@ -4131,11 +4118,9 @@ DoneSection2: P_SetThingPosition(player->mo); } - P_InstaThrust(player->mo, player->mo->angle, linespeed); + P_InstaThrust(player->mo, lineangle, linespeed); player->kartstuff[k_dashpadcooldown] = TICRATE/3; - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; player->kartstuff[k_pogospring] = 0; S_StartSound(player->mo, sfx_spdpad); diff --git a/src/p_user.c b/src/p_user.c index 5358df1fe..54e2350b6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1188,6 +1188,8 @@ boolean P_EndingMusic(player_t *player) // void P_RestoreMusic(player_t *player) { + UINT32 position; + if (!P_IsLocalPlayer(player)) // Only applies to a local player return; @@ -1244,10 +1246,16 @@ void P_RestoreMusic(player_t *player) // Item - Grow if (wantedmus == 2) + { S_ChangeMusicInternal("kgrow", true); + S_SetRestoreMusicFadeInCvar(&cv_growmusicfade); + } // Item - Invincibility else if (wantedmus == 1) + { S_ChangeMusicInternal("kinvnc", true); + S_SetRestoreMusicFadeInCvar(&cv_invincmusicfade); + } else { #if 0 @@ -1256,7 +1264,15 @@ void P_RestoreMusic(player_t *player) if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value)) S_SpeedMusic(1.2f); #endif - S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); + if (mapmusresume && cv_resume.value) + position = mapmusresume; + else + position = mapmusposition; + + S_ChangeMusicEx(mapmusname, mapmusflags, true, position, 0, + S_GetRestoreMusicFadeIn()); + S_ClearRestoreMusicFadeInCvar(); + mapmusresume = 0; } } } @@ -7168,6 +7184,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall UINT8 timeover; mobj_t *mo; fixed_t f1, f2; + fixed_t speed; #ifndef NOCLIPCAM boolean cameranoclip; subsector_t *newsubsec; @@ -7402,8 +7419,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // sets ideal cam pos dist = camdist; - if (player->speed > K_GetKartSpeed(player, false)) - dist += 4*(player->speed - K_GetKartSpeed(player, false)); + /* player->speed subtracts conveyors, janks up the camera */ + speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + + if (speed > K_GetKartSpeed(player, false)) + dist += 4*(speed - K_GetKartSpeed(player, false)); dist += abs(thiscam->momz)/4; if (player->karthud[khud_boostcam]) diff --git a/src/s_sound.c b/src/s_sound.c index 82435d3dc..28ceff30e 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -120,6 +120,16 @@ consvar_t cv_gamesounds = {"sounds", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, consvar_t cv_playmusicifunfocused = {"playmusicifunfocused", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, PlayMusicIfUnfocused_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_playsoundifunfocused = {"playsoundsifunfocused", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, PlaySoundIfUnfocused_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t music_resync_threshold_cons_t[] = { + {0, "MIN"}, + {1000, "MAX"}, + + {0} +}; +consvar_t cv_music_resync_threshold = {"music_resync_threshold", "100", CV_SAVE|CV_CALL, music_resync_threshold_cons_t, I_UpdateSongLagThreshold, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_music_resync_powerups_only = {"music_resync_powerups_only", "No", CV_SAVE|CV_CALL, CV_YesNo, I_UpdateSongLagConditions, 0, NULL, NULL, 0, 0, NULL}; + #define S_MAX_VOLUME 127 // when to clip out sounds @@ -283,6 +293,9 @@ void S_RegisterSoundStuff(void) CV_RegisterVar(&cv_playmusicifunfocused); CV_RegisterVar(&cv_playsoundifunfocused); + CV_RegisterVar(&cv_music_resync_threshold); + CV_RegisterVar(&cv_music_resync_powerups_only); + COM_AddCommand("tunes", Command_Tunes_f); COM_AddCommand("restartaudio", Command_RestartAudio_f); @@ -1550,6 +1563,8 @@ static char music_name[7]; // up to 6-character name static void *music_data; static UINT16 music_flags; static boolean music_looping; +static consvar_t *music_refade_cv; +static int music_usage; static char queue_name[7]; static UINT16 queue_flags; @@ -1933,6 +1948,9 @@ static void S_UnloadMusic(void) music_name[0] = 0; music_flags = 0; music_looping = false; + + music_refade_cv = 0; + music_usage = 0; } static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) @@ -1940,6 +1958,8 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) if (S_MusicDisabled()) return false; + I_UpdateSongLagConditions(); + if ((!fadeinms && !I_PlaySong(looping)) || (fadeinms && !I_FadeInPlaySong(fadeinms, looping))) { @@ -2050,6 +2070,15 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 } } +void +S_ChangeMusicSpecial (const char *mmusic) +{ + if (cv_resetspecialmusic.value) + S_ChangeMusic(mmusic, MUSIC_FORCERESET, true); + else + S_ChangeMusicInternal(mmusic, true); +} + void S_StopMusic(void) { if (!I_SongPlaying() @@ -2057,6 +2086,9 @@ void S_StopMusic(void) || demo.title) // SRB2Kart: Demos don't interrupt title screen music return; + if (strcasecmp(music_name, mapmusname) == 0) + mapmusresume = I_GetSongPosition(); + if (I_SongPaused()) I_ResumeSong(); @@ -2154,6 +2186,34 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume) } } +void +S_SetRestoreMusicFadeInCvar (consvar_t *cv) +{ + music_refade_cv = cv; +} + +int +S_GetRestoreMusicFadeIn (void) +{ + if (music_refade_cv) + return music_refade_cv->value; + else + return 0; +} + +void +S_SetMusicUsage (int type) +{ + music_usage = type; + I_UpdateSongLagConditions(); +} + +int +S_MusicUsage (void) +{ + return music_usage; +} + /// ------------------------ /// Music Fading /// ------------------------ @@ -2198,6 +2258,7 @@ void S_Start(void) mapmusname[6] = 0; mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); mapmusposition = mapheaderinfo[gamemap-1]->muspos; + mapmusresume = 0; } //if (cv_resetmusic.value) // Starting ambience should always be restarted @@ -2272,6 +2333,7 @@ static void Command_Tunes_f(void) mapmusname[6] = 0; mapmusflags = (track & MUSIC_TRACKMASK); mapmusposition = position; + mapmusresume = 0; S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); diff --git a/src/s_sound.h b/src/s_sound.h index 2a904faff..0aa93c623 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -36,6 +36,9 @@ extern consvar_t cv_gamesounds; extern consvar_t cv_playmusicifunfocused; extern consvar_t cv_playsoundifunfocused; +extern consvar_t cv_music_resync_threshold; +extern consvar_t cv_music_resync_powerups_only; + #ifdef SNDSERV extern consvar_t sndserver_cmd, sndserver_arg; #endif @@ -176,6 +179,11 @@ UINT32 S_GetMusicPosition(void); // Music Playback // +enum +{ + MUS_SPECIAL = 1,/* powerups--invincibility, grow */ +}; + // Start music track, arbitrary, given its name, and set whether looping // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet @@ -184,6 +192,16 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 #define S_ChangeMusicInternal(a,b) S_ChangeMusicEx(a,0,b,0,0,0) #define S_ChangeMusic(a,b,c) S_ChangeMusicEx(a,b,c,0,0,0) +void S_ChangeMusicSpecial (const char *mmusic); + +void S_SetRestoreMusicFadeInCvar (consvar_t *cvar); +#define S_ClearRestoreMusicFadeInCvar() \ + S_SetRestoreMusicFadeInCvar(0) +int S_GetRestoreMusicFadeIn (void); + +void S_SetMusicUsage (int type); +int S_MusicUsage (void); + // Stops the music. void S_StopMusic(void); diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 1617da2a3..77fcc0914 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -13,6 +13,12 @@ #if defined(HAVE_SDL) && defined(HAVE_MIXER) && SOUND==SOUND_MIXER +/* +Just for hu_stopped. I promise I didn't +write netcode into the sound code, OKAY? +*/ +#include "../d_clisrv.h" + #include "../sounds.h" #include "../s_sound.h" #include "../i_sound.h" @@ -74,12 +80,17 @@ UINT8 sound_started = false; +static UINT32 stutter_threshold_user; +static UINT32 stutter_threshold; + static Mix_Music *music; static UINT8 music_volume, sfx_volume, internal_volume; static float loop_point; static float song_length; // length in seconds static boolean songpaused; +static UINT32 music_end_bytes; static UINT32 music_bytes; +static UINT32 music_stutter_bytes; static boolean is_looping; // fading @@ -101,6 +112,8 @@ static void var_cleanup(void) loop_point = song_length =\ music_bytes = fading_source = fading_target =\ fading_timer = fading_duration = 0; + music_end_bytes = 0; + music_stutter_bytes = 0; songpaused = is_looping =\ is_fading = false; @@ -552,6 +565,35 @@ static void do_fading_callback(void) /// Music Hooks /// ------------------------ +static void +Countstutter (int len) +{ + UINT32 bytes; + + if (hu_stopped) + { + music_stutter_bytes += len; + } + else if (stutter_threshold) + { + if (music_stutter_bytes >= stutter_threshold) + { + /* + This would be after looping. If we're too near to the start of the + file, subtracting the delta will just underflow. + */ + if (music_stutter_bytes > music_bytes) + { + /* We already know where the end is because we looped. */ + bytes = ( music_end_bytes - ( music_stutter_bytes - music_bytes )); + } + else + bytes = ( music_bytes - music_stutter_bytes ); + I_SetSongPosition((int)( bytes/4/44100.0*1000 )); + } + } +} + static void count_music_bytes(int chan, void *stream, int len, void *udata) { (void)chan; @@ -561,12 +603,16 @@ static void count_music_bytes(int chan, void *stream, int len, void *udata) if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID) return; music_bytes += len; + + if (gamestate == GS_LEVEL) + Countstutter(len); } static void music_loop(void) { if (is_looping) { + music_end_bytes = music_bytes; Mix_PlayMusic(music, 0); Mix_SetMusicPosition(loop_point); music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) @@ -848,6 +894,8 @@ boolean I_SetSongPosition(UINT32 position) // NOT if position input is greater than song length. music_bytes = 0; + music_stutter_bytes = 0; + return true; } } @@ -892,6 +940,22 @@ UINT32 I_GetSongPosition(void) // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 } +void +I_UpdateSongLagThreshold (void) +{ + stutter_threshold_user = cv_music_resync_threshold.value/1000.0*(4*44100); + I_UpdateSongLagConditions(); +} + +void +I_UpdateSongLagConditions (void) +{ + if (! cv_music_resync_powerups_only.value || S_MusicUsage() == MUS_SPECIAL) + stutter_threshold = stutter_threshold_user; + else + stutter_threshold = 0; +} + /// ------------------------ /// Music Playback /// ------------------------