diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88231fc03..099e9f1ba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ # Core sources set(SRB2_CORE_SOURCES am_map.c + args.c b_bot.c command.c comptime.c @@ -52,6 +53,7 @@ set(SRB2_CORE_SOURCES set(SRB2_CORE_HEADERS am_map.h + args.h b_bot.h byteptr.h command.h diff --git a/src/Makefile b/src/Makefile index 6825d5600..064c6b0be 100644 --- a/src/Makefile +++ b/src/Makefile @@ -626,6 +626,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/lzf.o \ $(OBJDIR)/vid_copy.o \ $(OBJDIR)/b_bot.o \ + $(OBJDIR)/args.o \ $(i_cdmus_o) \ $(i_net_o) \ $(i_system_o) \ diff --git a/src/command.c b/src/command.c index 46709fc67..0af4b9fb2 100644 --- a/src/command.c +++ b/src/command.c @@ -277,7 +277,7 @@ static xcommand_t *com_commands = NULL; // current commands #define MAX_ARGS 80 static size_t com_argc; -static char *com_argv[MAX_ARGS]; +char *com_argv[MAX_ARGS]; static const char *com_null_string = ""; static char *com_args = NULL; // current command args or NULL @@ -327,6 +327,16 @@ const char *COM_Argv(size_t arg) return com_argv[arg]; } +/** Returns all of the console command arguments + * + * \return String pointer to the argv table. + * \sa COM_ArgvList + */ +char **COM_ArgvList(void) +{ + return com_argv; +} + /** Gets all console command arguments. * * \return String pointer to all arguments for the last command. diff --git a/src/command.h b/src/command.h index 3fc39c84a..2276a0ae2 100644 --- a/src/command.h +++ b/src/command.h @@ -33,8 +33,12 @@ typedef void (*com_func_t)(void); void COM_AddCommand(const char *name, com_func_t func); int COM_AddLuaCommand(const char *name); +#define MAX_ARGS 80 +extern char *com_argv[MAX_ARGS]; + size_t COM_Argc(void); const char *COM_Argv(size_t arg); // if argv > argc, returns empty string +char **COM_ArgvList(void); char *COM_Args(void); size_t COM_CheckParm(const char *check); // like M_CheckParm :) size_t COM_CheckPartialParm(const char *check); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index debee58eb..f30cc4f75 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -49,6 +49,7 @@ #include "m_anigif.h" #include "k_kart.h" // SRB2kart #include "y_inter.h" +#include "fastcmp.h" #include "m_perfstats.h" #ifdef NETGAME_DEVMODE @@ -141,6 +142,8 @@ static void Command_SetViews_f(void); static void Command_Addfilelocal(void); static void Command_Addfile(void); +static void Command_Addskins(void); +static void Command_GLocalSkin(void); static void Command_ListWADS_f(void); #ifdef DELFILE static void Command_Delfile(void); @@ -289,6 +292,8 @@ consvar_t cv_skin = {"skin", DEFAULTSKIN, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin_ consvar_t cv_skin2 = {"skin2", DEFAULTSKIN2, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_skin3 = {"skin3", DEFAULTSKIN3, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin3_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_skin4 = {"skin4", DEFAULTSKIN4, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin4_OnChange, 0, NULL, NULL, 0, 0, NULL}; +// haha I've beaten you now, ONLINE +consvar_t cv_localskin = {"internal___localskin", "none", CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_skipmapcheck = {"skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -447,6 +452,7 @@ static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, " consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_forceskin = {"forceskin", "Off", CV_NETVAR|CV_CALL|CV_CHEAT, Forceskin_cons_t, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fakelocalskin = {"fakelocalskin", "None", CV_SAVE, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_downloading = {"downloading", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -468,6 +474,7 @@ consvar_t cv_showping = {"showping", "Always", CV_SAVE, showping_cons_t, NULL, 0 static CV_PossibleValue_t pingmeasurement_cons_t[] = {{0, "Frames"}, {1, "Milliseconds"}, {0, NULL}}; consvar_t cv_pingmeasurement = {"pingmeasurement", "Frames", CV_SAVE, pingmeasurement_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_luaimmersion = {"luaimmersion", "On", CV_SAVE, CV_OnOff, 0, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_minihead = {"smallminimapplayers", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -643,6 +650,8 @@ void D_RegisterServerCommands(void) COM_AddCommand("addfilelocal", Command_Addfilelocal); COM_AddCommand("addfile", Command_Addfile); + COM_AddCommand("addskins", Command_Addskins); + COM_AddCommand("localskin", Command_GLocalSkin); COM_AddCommand("listwad", Command_ListWADS_f); #ifdef DELFILE @@ -777,6 +786,9 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_showping); CV_RegisterVar(&cv_pingmeasurement); + CV_RegisterVar(&cv_luaimmersion); + CV_RegisterVar(&cv_fakelocalskin); + CV_RegisterVar(&cv_minihead); CV_RegisterVar(&cv_showminimapnames); @@ -885,6 +897,7 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_playername); CV_RegisterVar(&cv_playercolor); CV_RegisterVar(&cv_skin); // r_things.c (skin NAME) + CV_RegisterVar(&cv_localskin); // secondary player (splitscreen) CV_RegisterVar(&cv_playername2); CV_RegisterVar(&cv_playercolor2); @@ -4567,7 +4580,7 @@ static void Command_Addfile(void) // Add file on your client directly if it is trivial, or you aren't in a netgame. if (!(netgame || multiplayer) || musiconly) { - P_AddWadFile(fn); + P_AddWadFile(fn, false); return; } @@ -4616,6 +4629,156 @@ static void Command_Addfile(void) SendNetXCmd(XD_ADDFILE, buf, buf_p - buf); } +// i hate myself +static boolean DumbStartsWith(const char *pre, const char *str) +{ + size_t lenpre = strlen(pre), + lenstr = strlen(str); + return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0; +} + +/** Adds something at runtime. + */ +static void +Command_Addskins (void) +{ + if (COM_Argc() > 3) + { + CONS_Printf( + "addskins : Load a skin file.\n"); + return; + } + // no forcing? + /* + if (fasticmp(COM_Argv(2), "-force") || fasticmp(COM_Argv(2), "-f")) { + CONS_Alert(CONS_NOTICE, M_GetText("Adding file %s. May or may not be a skin.\n"), COM_Argv(1)); + P_AddWadFile(COM_Argv(1), 0, true); + } else { + if (DumbStartsWith("KC_", COM_Argv(1))) { + P_AddWadFile(COM_Argv(1), 0, true); + } else if (DumbStartsWith("KCL_", COM_Argv(1))) { + if (!demo.playback) { + CONS_Alert(CONS_ERROR, M_GetText("Cannot add file %s as it is a skin with lua. Include -force or -f to force it to load.\n"), COM_Argv(1)); + return; + } else { + */ + P_AddWadFile(COM_Argv(1), true); + /* + } + } else { + CONS_Alert(CONS_ERROR, M_GetText("Cannot add file %s as it is not a skin.\n"), COM_Argv(1)); + return; + } + } + */ +} + +// args n stuff +#include "args.h" + +static void Command_GLocalSkin (void) +{ + size_t first_option; + size_t option_display; + size_t option_all; + size_t option_player; + + option_player = COM_CheckPartialParm("-p"); + option_display = COM_CheckPartialParm("-d"); + option_all = COM_CheckPartialParm("-a"); + + char* fuck; // local skin name + + if (!( first_option = COM_FirstOption() )) + first_option = COM_Argc(); + + if (first_option < 2) + { + /* holy fucking shit */ + CONS_Printf("localskin [-player ] [-display ] [-all]:\n"); + CONS_Printf(M_GetText("Set a localskin via its internal name (usually printed on the console).\n\n\ +* Using \"-player\" will set a localskin to a specified player.\n\ + Defaults to yourself.\n\ +* Using \"-display\" will set a localskin to the displayed player.\n\ + Defaults to 0, which is the first player displayed.\n\ + Can go up to 3 for splitscreen.\n\ +* Using \"-all\" will set a localskin to ALL players.\n\ +* \"localskin none\" removes the localskin, just like how\n\ + \"forceskin none\" does.\n")); + return; + } + + fuck = ConcatCommandArgv(1, first_option); + + char* player_name = player_names[consoleplayer]; + char* display_num = "0"; + size_t dnum = 0; + + if (option_display) // -display + { + // handle default: 0 + if (COM_Argv(option_display + 1)[0] == "" || COM_Argv(option_display + 1)[0] != "-") + display_num = COM_Argv(option_display + 1); + + if (isdigit(display_num[0]) || display_num == "0") + { + dnum = atoi(display_num); + if (dnum > 3 || dnum < 0) // nuh uh + dnum = 0; + SetLocalPlayerSkin(displayplayers[dnum], fuck, NULL); + + CONS_Printf("Successfully applied localskin to displayed player.\n"); + return; + } + + CONS_Printf("Could not apply localskin.\n"); + + return; + } + else if (option_all) // -all + { + int i; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (!playeringame[i]) + continue; + SetLocalPlayerSkin(i, fuck, NULL); + } + CONS_Printf("Successfully applied localskin to all players.\n"); + + return; + } + else // -player or no other arguments + { + if (option_player) + { + int i; + player_name = COM_Argv(option_player + 1); + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (fasticmp(player_names[i], player_name)) + SetLocalPlayerSkin(i, fuck, NULL); + } + CONS_Printf("Successfully applied localskin to specified player.\n"); + + return; + } + else + { + SetLocalPlayerSkin(consoleplayer, fuck, &cv_localskin); + CONS_Printf("Successfully applied localskin.\n"); + + return; + } + + CONS_Printf("Could not apply localskin.\n"); + + return; + } +} + #ifdef DELFILE /** removes the last added pwad at runtime. * Searches for sounds, maps, music and images to remove @@ -4772,7 +4935,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) ncs = findfile(filename,md5sum,true); - if (ncs != FS_FOUND || !P_AddWadFile(filename)) + if (ncs != FS_FOUND || !P_AddWadFile(filename, false)) { Command_ExitGame_f(); if (ncs == FS_FOUND) @@ -5928,7 +6091,6 @@ static void Command_ListSkins(void) } } - /** Sends a color change for the console player, unless that player is moving. * \sa cv_playercolor, Color2_OnChange, Skin_OnChange * \author Graue diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e999a202e..e2c084e0d 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -21,6 +21,7 @@ extern consvar_t cv_playername; extern consvar_t cv_playercolor; extern consvar_t cv_skin; +extern consvar_t cv_localskin; // secondary splitscreen player extern consvar_t cv_playername2; extern consvar_t cv_playercolor2; @@ -157,6 +158,8 @@ extern consvar_t cv_minihead; extern consvar_t cv_showlapemblem; extern consvar_t cv_showviewpointtext; +extern consvar_t cv_luaimmersion; +extern consvar_t cv_fakelocalskin; extern consvar_t cv_skipmapcheck; diff --git a/src/d_netfil.c b/src/d_netfil.c index 0436f05d3..dbf4e6281 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -513,7 +513,7 @@ INT32 CL_CheckFiles(void) for (i = 0, j = mainwads+1; i < fileneedednum || j < numwadfiles;) { - if (j < numwadfiles && !wadfiles[j]->important) + if (j < numwadfiles && (!wadfiles[j]->important || wadfiles[j]->localfile)) { // Unimportant on our side. still don't care. ++j; diff --git a/src/d_player.h b/src/d_player.h index a12fff93b..c9329fe9c 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -416,6 +416,8 @@ typedef struct player_s UINT8 skincolor; INT32 skin; + INT32 localskin; + boolean skinlocal; UINT32 score; // player score fixed_t dashspeed; // dashing speed diff --git a/src/g_game.c b/src/g_game.c index 01037f3c6..a10f74f43 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -850,6 +850,16 @@ void G_SetGameModified(boolean silent, boolean major) M_EndModeAttackRun(); } +void G_SetWadModified(boolean silent, boolean major, UINT16 wadnum) +{ + // now that we have a wad that is actually well, a gameplay changing mod + // (for later) + wadfiles[wadnum]->majormod = true; + + // set our game to be marked as modified. + G_SetGameModified(silent, major); +} + /** Builds an original game map name from a map number. * The complexity is due to MAPA0-MAPZZ. * @@ -2706,6 +2716,8 @@ void G_PlayerReborn(INT32 player) UINT8 mare; UINT8 skincolor; INT32 skin; + int localskin; + boolean skinlocal; tic_t jointime; UINT8 splitscreenindex; boolean spectator; @@ -2752,6 +2764,8 @@ void G_PlayerReborn(INT32 player) skincolor = players[player].skincolor; skin = players[player].skin; + localskin = players[player].localskin; + skinlocal = players[player].skinlocal; // SRB2kart kartspeed = players[player].kartspeed; kartweight = players[player].kartweight; @@ -2841,6 +2855,8 @@ void G_PlayerReborn(INT32 player) // save player config truth reborn p->skincolor = skincolor; p->skin = skin; + p->localskin = localskin; + p->skinlocal = skinlocal; // SRB2kart p->kartspeed = kartspeed; p->kartweight = kartweight; diff --git a/src/g_game.h b/src/g_game.h index ceb8e1f9f..894b7b289 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -403,6 +403,7 @@ boolean G_GetRetryFlag(void); void G_LoadGameData(void); void G_LoadGameSettings(void); +void G_SetWadModified(boolean silent, boolean major, UINT16 wadnum); void G_SetGameModified(boolean silent, boolean major); void G_SetGamestate(gamestate_t newstate); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 66adf3522..6a346b715 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3930,7 +3930,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) FOutVector baseWallVerts[4]; // This is what the verts should end up as GLPatch_t *gpatch; FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); + const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); extracolormap_t *colormap; FUINT lightlevel; FBITFIELD blend = 0; @@ -3954,7 +3954,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) this_scale = FIXED_TO_FLOAT(spr->mobj->scale); if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); + this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->highresscale); gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); @@ -4276,11 +4276,11 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); + const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); if (spr->mobj) this_scale = FIXED_TO_FLOAT(spr->mobj->scale); if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); + this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->highresscale); if (!spr->mobj) return; @@ -4827,8 +4827,19 @@ void HWR_DrawSprites(void) else if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { + md2_t *md2; + if (spr->mobj->localskin) + { + if (spr->mobj->skinlocal) + md2 = &md2_localplayermodels[(skin_t *)spr->mobj->localskin - localskins]; + else + md2 = &md2_playermodels [(skin_t *)spr->mobj->localskin - skins]; + } + else + md2 = &md2_playermodels[(skin_t *)spr->mobj->skin - skins]; + // 8/1/19: Only don't display player models if no default SPR_PLAY is found. - if (!cv_grmdls.value || ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f)) || spr->mobj->state == &states[S_PLAY_SIGN]) + if (!cv_grmdls.value || ((md2->notfound || md2->scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f)) || spr->mobj->state == &states[S_PLAY_SIGN]) HWR_DrawSprite(spr); else HWR_DrawMD2(spr); @@ -5075,7 +5086,7 @@ void HWR_ProjectSprite(mobj_t *thing) //Fab : 02-08-98: 'skin' override spritedef currently used for skin if (thing->skin && thing->sprite == SPR_PLAY) { - sprdef = &((skin_t *)thing->skin)->spritedef; + sprdef = &((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->spritedef; #ifdef ROTSPRITE sprinfo = &spriteinfo[thing->sprite]; #endif @@ -5150,8 +5161,8 @@ void HWR_ProjectSprite(mobj_t *thing) } } - if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); + if (thing->skin && ((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->flags & SF_HIRES) + this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->highresscale); spr_width = spritecachedinfo[lumpoff].width; spr_height = spritecachedinfo[lumpoff].height; @@ -5310,10 +5321,7 @@ void HWR_ProjectSprite(mobj_t *thing) if (thing->colorized) vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE); else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player! - { - size_t skinnum = (skin_t*)thing->skin-skins; - vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE); - } + vis->colormap = R_GetLocalTranslationColormap(thing->skin, thing->localskin, thing->color, GTC_CACHE, thing->skinlocal); else vis->colormap = R_GetTranslationColormap(TC_DEFAULT, thing->color, GTC_CACHE); } diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index ce7ee8d9f..140c42c1f 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -75,6 +75,7 @@ md2_t md2_models[NUMSPRITES]; md2_t md2_playermodels[MAXSKINS]; +md2_t md2_localplayermodels[MAXSKINS]; /* @@ -487,6 +488,13 @@ void HWR_InitMD2(void) md2_playermodels[s].skin = -1; md2_playermodels[s].notfound = true; md2_playermodels[s].error = false; + + md2_localplayermodels[s].scale = -1.0f; + md2_localplayermodels[s].model = NULL; + md2_localplayermodels[s].grpatch = NULL; + md2_localplayermodels[s].skin = -1; + md2_localplayermodels[s].notfound = true; + md2_localplayermodels[s].error = false; } for (i = 0; i < NUMSPRITES; i++) { @@ -559,11 +567,12 @@ md2found: fclose(f); } -void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup +void HWR_AddPlayerMD2(int skin, boolean local) // For MD2's that were added after startup { FILE *f; char name[20], filename[32]; float scale, offset; + md2_t *md2s; if (nomd2s) return; @@ -585,22 +594,23 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup } } - // Check for any MD2s that match the names of sprite names! + md2s = ( (local) ? md2_localplayermodels : md2_playermodels ); + // Check for any MD2s that match the names of player skins! while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) { - if (stricmp(name, skins[skin].name) == 0) + if (stricmp(name, ( (local) ? localskins : skins )[skin].name) == 0) { - md2_playermodels[skin].skin = skin; - md2_playermodels[skin].scale = scale; - md2_playermodels[skin].offset = offset; - md2_playermodels[skin].notfound = false; - strcpy(md2_playermodels[skin].filename, filename); + md2s[skin].skin = skin; + md2s[skin].scale = scale; + md2s[skin].offset = offset; + md2s[skin].notfound = false; + strcpy(md2s[skin].filename, filename); goto playermd2found; } } //CONS_Printf("MD2 for player skin %s not found\n", skins[skin].name); - md2_playermodels[skin].notfound = true; + md2s[skin].notfound = true; playermd2found: fclose(f); } @@ -1154,6 +1164,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr) { R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp); } + md2_t *md2s; + int skinnum; // Apparently people don't like jump frames like that, so back it goes //if (tics > durs) @@ -1168,13 +1180,33 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // dont forget to enabled the depth test because we can't do this like // before: polygons models are not sorted + + /* fuck you */ + if (spr->mobj->localskin) + { + if (spr->mobj->skinlocal) + { + md2s = md2_localplayermodels; + skinnum = (skin_t *)spr->mobj->localskin - localskins; + } + else + { + md2s = md2_playermodels; + skinnum = (skin_t *)spr->mobj->localskin - skins; + } + } + else + { + md2s = md2_playermodels; + skinnum = (skin_t *)spr->mobj->skin - skins; + } // 1. load model+texture if not already loaded // 2. draw model with correct position, rotation,... - if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && !md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound) // Use the player MD2 list if the mobj has a skin and is using the player sprites + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && !md2s[skinnum].notfound) // Use the player MD2 list if the mobj has a skin and is using the player sprites { - md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins]; - md2->skin = (skin_t*)spr->mobj->skin-skins; + md2 = &md2s[skinnum]; + md2->skin = skinnum; sprinfo = &spriteinfo[spr->mobj->sprite]; } else @@ -1239,7 +1271,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) skinnum = TC_RAINBOW; else { - skinnum = (INT32)((skin_t*)spr->mobj->skin-skins); + skinnum = (INT32)((skin_t*)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ) - ( (spr->mobj->skinlocal) ? localskins : skins )); } } else skinnum = TC_DEFAULT; @@ -1306,7 +1338,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.z = FIXED_TO_FLOAT(interp.z); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - sprdef = &((skin_t *)spr->mobj->skin)->spritedef; + sprdef = &((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->spritedef; else sprdef = &sprites[spr->mobj->sprite]; diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index fab8e6ad9..a6f06428e 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -37,10 +37,11 @@ typedef struct extern md2_t md2_models[NUMSPRITES]; extern md2_t md2_playermodels[MAXSKINS]; +extern md2_t md2_localplayermodels[MAXSKINS]; void HWR_InitMD2(void); void HWR_DrawMD2(gr_vissprite_t *spr); -void HWR_AddPlayerMD2(INT32 skin); +void HWR_AddPlayerMD2(INT32 skin, boolean local); void HWR_AddSpriteMD2(size_t spritenum); #endif // _HW_MD2_H_ diff --git a/src/k_kart.c b/src/k_kart.c index 1ff3f031d..8607b0a31 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -504,7 +504,7 @@ void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) \return void */ -void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) +void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color, boolean local) { INT32 i; INT32 starttranscolor; @@ -540,7 +540,7 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) return; } - starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; + starttranscolor = (skinnum != TC_DEFAULT) ? ( (local) ? localskins : skins )[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; // Fill in the entries of the palette that are fixed for (i = 0; i < starttranscolor; i++) @@ -8098,7 +8098,11 @@ static boolean K_drawKartPositionFaces(void) else colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE); - V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, facerankprefix[players[rankplayer[i]].skin], colormap); + { + player_t *p; + p = &players[rankplayer[i]]; + V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, ( (p->skinlocal) ? localfacerankprefix : facerankprefix )[( (p->localskin) ? p->localskin-1 : p->skin )], colormap); + } #ifdef HAVE_BLUA if (LUA_HudEnabled(hud_battlebumpers)) @@ -8184,7 +8188,11 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I else colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); - V_DrawMappedPatch(x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); + { + player_t *p; + p = &players[tab[i].num]; + V_DrawMappedPatch(x, y-4, 0, ( (p->skinlocal) ? localfacerankprefix : facerankprefix )[( (p->localskin) ? p->localskin-1 : p->skin )], colormap); + } /*if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] > 0) -- not enough space for this { INT32 bumperx = x+19; @@ -8531,7 +8539,7 @@ static void K_drawKartWanted(void) if (players[battlewanted[i]].skincolor) { colormap = R_GetTranslationColormap(TC_RAINBOW, p->skincolor, GTC_CACHE); - V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap); + V_DrawFixedPatch(x<skinlocal) ? localfacewantprefix : facewantprefix )[( (p->localskin) ? p->localskin-1 : p->skin )] : ( (p->skinlocal) ? localfacerankprefix : facerankprefix )[( (p->localskin) ? p->localskin-1 : p->skin )]), colormap); /*if (basey2) // again with 4p stuff V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap);*/ } @@ -8598,6 +8606,7 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat // it, they wouldn't 'spawn' on the top-right side of the HUD. UINT8 skin = 0; + boolean skinlocal = mo->skinlocal; fixed_t amnumxpos, amnumypos; INT32 amxpos, amypos; @@ -8610,7 +8619,7 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat fixed_t xscale, yscale, zoom; if (mo->skin) - skin = ((skin_t*)mo->skin)-skins; + skin = ((skin_t*)( (mo->localskin) ? mo->localskin : mo->skin ))-( (skinlocal) ? localskins : skins ); maxx = maxy = INT32_MAX; minx = miny = INT32_MIN; @@ -8654,20 +8663,26 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat if (encoremode) amnumxpos = -amnumxpos; - amxpos = amnumxpos + ((x + AutomapPic->width/2 - (facemmapprefix[skin]->width/2))<height/2 - (facemmapprefix[skin]->height/2))<width/2 - (( (skinlocal) ? localfacemmapprefix : facemmapprefix )[skin]->width/2))<height/2 - (( (skinlocal) ? localfacemmapprefix : facemmapprefix )[skin]->height/2))<color) // 'default' color - V_DrawSciencePatch(amxpos, amypos, flags, facemmapprefix[skin], FRACUNIT); + V_DrawSciencePatch(amxpos, amypos, flags, ( (skinlocal) ? localfacemmapprefix : facemmapprefix )[skin], FRACUNIT); else { UINT8 *colormap = R_GetTranslationColormap((mo->colorized) ? TC_RAINBOW : skin, mo->color, GTC_CACHE); if (cv_minihead.value == 1) - V_DrawFixedPatch(amxpos + (2 * FRACUNIT), amypos + (2 * FRACUNIT), FRACUNIT/2, flags, facemmapprefix[skin], colormap); + { + colormap = R_GetLocalTranslationColormap(mo->skin, mo->localskin, mo->color, GTC_CACHE, skinlocal); + V_DrawFixedPatch(amxpos + (2 * FRACUNIT), amypos + (2 * FRACUNIT), FRACUNIT/2, flags, ( (skinlocal) ? localfacemmapprefix : facemmapprefix )[skin], colormap); + } else if (cv_minihead.value == 0) - V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap); - + { + colormap = R_GetLocalTranslationColormap(mo->skin, mo->localskin, mo->color, GTC_CACHE, skinlocal); + V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, ( (skinlocal) ? localfacemmapprefix : facemmapprefix )[skin], colormap); + } + if (cv_showminimapnames.value && !(modeattacking || gamestate == GS_TIMEATTACK)) { const char *player_name = va("%c%s", V_GetSkincolorChar(mo->color), player_names[mo->player - players]); diff --git a/src/k_kart.h b/src/k_kart.h index b664f9c33..a7dc591f8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -15,7 +15,7 @@ extern UINT8 colortranslations[MAXTRANSLATIONS][16]; extern const char *KartColor_Names[MAXSKINCOLORS]; extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2]; void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); -void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); +void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color, boolean local); UINT8 K_GetKartColorByName(const char *name); void K_RegisterKartStuff(void); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 91c2158e8..39f9ab0bc 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -19,6 +19,8 @@ #include "p_local.h" #include "g_game.h" #include "p_setup.h" +#include "doomdef.h" +#include "d_netcmd.h" #include "lua_script.h" #include "lua_libs.h" @@ -350,8 +352,14 @@ int mobj_skin_getter(lua_State *L) if (!mo->skin) return 0; - lua_pushstring(L, ((skin_t *)mo->skin)->name); - + if (hud_running && cv_luaimmersion.value) { + if (mo->localskin) // HUD ONLY!!!!!!!!!! + lua_pushstring(L, ((skin_t *)mo->localskin)->name); + else + lua_pushstring(L, ((skin_t *)mo->skin)->name); + } else { + lua_pushstring(L, ((skin_t *)mo->skin)->name); + } return 1; } @@ -363,7 +371,7 @@ int mobj_skin_setter(lua_State *L) char skin[SKINNAMESIZE+1]; // all skin names are limited to this length strlcpy(skin, luaL_checkstring(L, 2), sizeof skin); strlwr(skin); // all skin names are lowercase - for (i = 0; i < numskins; i++) + for (i = 0; i < numskins; i++) { { if (fastcmp(skins[i].name, skin)) { @@ -372,7 +380,9 @@ int mobj_skin_setter(lua_State *L) } } - return luaL_error(L, "mobj.skin '%s' not found!", skin); + } + + return luaL_error(L, "mobj.skin '%s' not found!", skin); } int mobj_color_setter(lua_State *L) diff --git a/src/lua_script.c b/src/lua_script.c index 8f4438732..e0da24b40 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -280,7 +280,7 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) LUA_LoadFile(&f, name); // actually load file! // Okay, we've modified the game beyond the point of no return. - G_SetGameModified(multiplayer, true); + G_SetWadModified(multiplayer, true, wad); free(name); Z_Free(f.data); diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index f44e97afe..e86cd55af 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -166,14 +166,14 @@ static int lib_iterateSkins(lua_State *L) lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) - i = (INT32)(*((skin_t **)luaL_checkudata(L, 1, META_SKIN)) - skins) + 1; + i = (INT32)(*((skin_t **)luaL_checkudata(L, 1, META_SKIN)) - allskins) + 1; else i = 0; // skins are always valid, only added, never removed - if (i < numskins) + if (i < numallskins) { - LUA_PushUserdata(L, &skins[i], META_SKIN); + LUA_PushUserdata(L, &allskins[i], META_SKIN); return 1; } @@ -191,9 +191,9 @@ static int lib_getSkin(lua_State *L) i = luaL_checkinteger(L, 2); if (i < 0 || i >= MAXSKINS) return luaL_error(L, "skins[] index %d out of range (0 - %d)", i, MAXSKINS-1); - if (i >= numskins) + if (i >= numallskins) return 0; - LUA_PushUserdata(L, &skins[i], META_SKIN); + LUA_PushUserdata(L, &allskins[i], META_SKIN); return 1; } @@ -207,10 +207,10 @@ static int lib_getSkin(lua_State *L) } // find skin by name - for (i = 0; i < numskins; i++) - if (fastcmp(skins[i].name, field)) + for (i = 0; i < numallskins; i++) + if (fastcmp(allskins[i].name, field)) { - LUA_PushUserdata(L, &skins[i], META_SKIN); + LUA_PushUserdata(L, &allskins[i], META_SKIN); return 1; } @@ -219,7 +219,7 @@ static int lib_getSkin(lua_State *L) static int lib_numSkins(lua_State *L) { - lua_pushinteger(L, numskins); + lua_pushinteger(L, numallskins); return 1; } diff --git a/src/m_menu.c b/src/m_menu.c index 980a4c694..c99bf003d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -145,6 +145,8 @@ INT32 mapwads[NUMMAPS]; //static char *char_notes = NULL; //static fixed_t char_scroll = 0; +boolean browselocalskins = false; + boolean menuactive = false; boolean fromlevelselect = false; @@ -234,6 +236,8 @@ menu_t SR_MainDef, SR_UnlockChecklistDef; static void M_SinglePlayerMenu(INT32 choice); #endif static void M_Options(INT32 choice); +static void M_LocalSkinMenu(INT32 choice); +static void M_LocalSkinChange(INT32 choice); static void M_Manual(INT32 choice); static void M_SelectableClearMenus(INT32 choice); static void M_Retry(INT32 choice); @@ -336,7 +340,9 @@ menu_t OP_MonitorToggleDef; static void M_ScreenshotOptions(INT32 choice); static void M_EraseData(INT32 choice); +static void M_AddonsInternal(); static void M_Addons(INT32 choice); +static void M_LocalSkins(INT32 choice); static void M_AddonsOptions(INT32 choice); static patch_t *addonsp[NUM_EXT+5]; @@ -350,6 +356,9 @@ menu_t OP_SaturnCreditsDef; // Bird menu_t OP_BirdDef; +// Stuff, yknow. +menu_t OP_ForkedBirdDef; +menu_t OP_LocalSkinDef; menu_t OP_TiltDef; menu_t OP_AdvancedBirdDef; @@ -407,6 +416,7 @@ static void M_DrawConnectMenu(void); #endif static void M_DrawJoystick(void); static void M_DrawSetupMultiPlayerMenu(void); +static void M_DrawLocalSkinMenu(void); // Handling functions #ifndef NONET @@ -627,12 +637,13 @@ typedef enum // --------------------- static menuitem_t MPauseMenu[] = { - {IT_STRING | IT_CALL, NULL, "Addons...", M_Addons, 8}, - {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, - {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, + {IT_STRING | IT_CALL, NULL, "Addons...", M_Addons, 8}, + {IT_STRING | IT_CALL, NULL, "Add local skins...", M_LocalSkins, 16}, + {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 24}, + {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 32}, #ifdef HAVE_DISCORDRPC - {IT_STRING | IT_SUBMENU, NULL, "Ask To Join Requests...", &MISC_DiscordRequestsDef, 24}, + {IT_STRING | IT_SUBMENU, NULL, "Ask To Join Requests...", &MISC_DiscordRequestsDef, 32}, #endif {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus, 40}, @@ -647,15 +658,17 @@ static menuitem_t MPauseMenu[] = {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, {IT_STRING | IT_SUBMENU, NULL, "Enter/Spectate...", &MISC_ChangeSpectateDef,48}, {IT_CALL | IT_STRING, NULL, "Player Setup...", M_SetupMultiPlayer, 56}, // alone - {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, + {IT_CALL | IT_STRING, NULL, "Local Skin...", M_LocalSkinMenu, 64}, // alone + {IT_CALL | IT_STRING, NULL, "Options", M_Options, 72}, - {IT_CALL | IT_STRING, NULL, "Return to Title", M_EndGame, 80}, - {IT_CALL | IT_STRING, NULL, "Quit Game", M_QuitSRB2, 88}, + {IT_CALL | IT_STRING, NULL, "Return to Title", M_EndGame, 88}, + {IT_CALL | IT_STRING, NULL, "Quit Game", M_QuitSRB2, 96}, }; typedef enum { mpause_addons = 0, + mpause_addlocalskins, mpause_scramble, mpause_switchmap, #ifdef HAVE_DISCORDRPC @@ -674,6 +687,7 @@ typedef enum mpause_switchteam, mpause_switchspectate, mpause_psetup, + mpause_localskin, mpause_options, mpause_title, @@ -1128,6 +1142,7 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU|IT_STRING, NULL, "Saturn Options...", &OP_SaturnDef, 140}, {IT_SUBMENU|IT_STRING, NULL, "Bird", &OP_BirdDef, 150}, + {IT_CALL|IT_STRING, NULL, "Fork Options...", M_LocalSkinMenu, 160}, }; static menuitem_t OP_ControlsMenu[] = @@ -1816,6 +1831,17 @@ static menuitem_t OP_BirdMenu[] = {IT_STRING | IT_SUBMENU, NULL, "Advanced Music Options...", &OP_AdvancedBirdDef, 120}, }; +static menuitem_t OP_ForkedBirdMenu[] = +{ + {IT_HEADER, NULL, "Local Skins", NULL, 0}, + {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Local Skin Name", &cv_fakelocalskin, 10}, + {IT_STRING2 | IT_SPACE, NULL, "Set to None for no Local Skin", NULL, 20}, + {IT_STRING | IT_CALL, NULL, "Apply to All Players", M_LocalSkinChange, 140}, + {IT_STRING | IT_CALL, NULL, "Apply to Displaying Player", M_LocalSkinChange, 150}, + {IT_STRING | IT_CALL, NULL, "Apply to Yourself", M_LocalSkinChange, 160}, + {IT_STRING | IT_CVAR, NULL, "Lua Immersion", &cv_luaimmersion, 170}, +}; + static menuitem_t OP_TiltMenu[] = { {IT_STRING | IT_CVAR, NULL, "Camera Tilting", &cv_tilting, 0}, @@ -2379,6 +2405,20 @@ menu_t OP_BirdDef = DEFAULTMENUSTYLE(NULL, OP_BirdMenu, &OP_MainDef, 30, 30); menu_t OP_TiltDef = DEFAULTMENUSTYLE(NULL, OP_TiltMenu, &OP_BirdDef, 30, 60); menu_t OP_AdvancedBirdDef = DEFAULTMENUSTYLE(NULL, OP_AdvancedBirdMenu, &OP_BirdDef, 30, 60); +menu_t OP_ForkedBirdDef = { + NULL, + sizeof(OP_ForkedBirdMenu)/sizeof(menuitem_t), + &OP_MainDef, + OP_ForkedBirdMenu, + M_DrawLocalSkinMenu, + 30, 6, + 0, + NULL +}; + +menu_t OP_LocalSkinDef = DEFAULTMENUSTYLE(NULL, OP_TiltMenu, &OP_ForkedBirdDef, 30, 60); + + // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE // ========================================================================== @@ -3592,14 +3632,16 @@ void M_StartControlPanel(void) // Reset these in case splitscreen messes things up MPauseMenu[mpause_addons].alphaKey = 8; + MPauseMenu[mpause_addlocalskins].alphaKey = 16; MPauseMenu[mpause_scramble].alphaKey = 8; MPauseMenu[mpause_switchmap].alphaKey = 24; MPauseMenu[mpause_switchteam].alphaKey = 48; MPauseMenu[mpause_switchspectate].alphaKey = 48; - MPauseMenu[mpause_options].alphaKey = 64; - MPauseMenu[mpause_title].alphaKey = 80; - MPauseMenu[mpause_quit].alphaKey = 88; + MPauseMenu[mpause_localskin].alphaKey = 64; + MPauseMenu[mpause_options].alphaKey = 72; + MPauseMenu[mpause_title].alphaKey = 88; + MPauseMenu[mpause_quit].alphaKey = 96; Dummymenuplayer_OnChange(); @@ -3622,6 +3664,7 @@ void M_StartControlPanel(void) { MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; MPauseMenu[mpause_switchteam].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_localskin].alphaKey += 8; MPauseMenu[mpause_options].alphaKey += 8; MPauseMenu[mpause_title].alphaKey += 8; MPauseMenu[mpause_quit].alphaKey += 8; @@ -3630,6 +3673,7 @@ void M_StartControlPanel(void) { MPauseMenu[mpause_switchspectate].status = IT_STRING | IT_SUBMENU; MPauseMenu[mpause_switchspectate].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_localskin].alphaKey += 8; MPauseMenu[mpause_options].alphaKey += 8; MPauseMenu[mpause_title].alphaKey += 8; MPauseMenu[mpause_quit].alphaKey += 8; @@ -3640,6 +3684,7 @@ void M_StartControlPanel(void) { MPauseMenu[mpause_psetupsplit3].status = IT_STRING | IT_CALL; + MPauseMenu[mpause_localskin].alphaKey += 8; MPauseMenu[mpause_options].alphaKey += 8; MPauseMenu[mpause_title].alphaKey += 8; MPauseMenu[mpause_quit].alphaKey += 8; @@ -3647,6 +3692,7 @@ void M_StartControlPanel(void) if (splitscreen > 2) { MPauseMenu[mpause_psetupsplit4].status = IT_STRING | IT_CALL; + MPauseMenu[mpause_localskin].alphaKey += 8; MPauseMenu[mpause_options].alphaKey += 8; MPauseMenu[mpause_title].alphaKey += 8; MPauseMenu[mpause_quit].alphaKey += 8; @@ -4287,7 +4333,7 @@ static void M_DrawGenericMenu(void) y += STRINGHEIGHT; break; case IT_STRING2: - V_DrawString(x, y, lowercase, currentMenu->menuitems[i].text); + V_DrawString(((BASEVIDWIDTH - V_StringWidth(currentMenu->menuitems[i].text, 0))>>1), y, 0, currentMenu->menuitems[i].text); /* FALLTHRU */ case IT_DYLITLSPACE: y += SMALLLINEHEIGHT; @@ -5114,12 +5160,10 @@ static void M_AddonsOptions(INT32 choice) #define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make addons!" #define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make addons!" -static void M_Addons(INT32 choice) +static void M_AddonsInternal() { const char *pathname = "."; - (void)choice; - #if 1 if (cv_addons_option.value == 0) pathname = usehome ? srb2home : srb2path; @@ -5180,6 +5224,20 @@ static void M_Addons(INT32 choice) M_SetupNextMenu(&MISC_AddonsDef); } +static void M_Addons(INT32 choice) +{ + (void)choice; + browselocalskins = false; + M_AddonsInternal(); +} + +static void M_LocalSkins(INT32 choice) +{ + (void)choice; + browselocalskins = true; + M_AddonsInternal(); +} + #define width 4 #define vpadding 27 #define h (BASEVIDHEIGHT-(2*vpadding)) @@ -5332,7 +5390,12 @@ static void M_DrawAddons(void) } if (Playing()) - V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); + { + if (browselocalskins) + V_DrawCenteredString(BASEVIDWIDTH/2, 5, V_ALLOWLOWERCASE, "Load \x83local skins\x80 from addons!"); + else + V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); + } else V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)); @@ -5503,6 +5566,14 @@ static boolean M_ChangeStringAddons(INT32 choice) } #undef len +// i hate myself +static boolean DumbStartsWith(const char *pre, const char *str) +{ + size_t lenpre = strlen(pre), + lenstr = strlen(str); + return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0; +} + static void M_HandleAddons(INT32 choice) { boolean exitmenu = false; // exit to previous menu @@ -5621,7 +5692,16 @@ static void M_HandleAddons(INT32 choice) case EXT_KART: #endif case EXT_PK3: - COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + if (browselocalskins) { + if (DumbStartsWith("KC_", dirmenu[dir_on[menudepthleft]]+DIR_STRING)) { + M_StartMessage(va("%c%s\x80\nYou are loading a local skin.\nLocal skins will not be usable\nafter going back from\nthe title screen.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); + COM_BufAddText(va("addskins \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + } + else + S_StartSound(NULL, sfx_s26d); + } + else + COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); break; default: S_StartSound(NULL, sfx_s26d); @@ -11899,6 +11979,133 @@ static void M_DrawHUDOptions(void) V_DrawRightAlignedString(x, y, highlightflags, "("); } +static void M_LocalSkinMenu(INT32 choice) +{ + (void)choice; + + multi_state = &states[mobjinfo[MT_PLAYER].seestate]; + multi_tics = multi_state->tics; + + OP_ForkedBirdDef.prevMenu = currentMenu; + M_SetupNextMenu(&OP_ForkedBirdDef); +} + +static void M_LocalSkinChange(INT32 choice) +{ + (void)choice; + + switch (itemOn) { + case 3: + COM_BufAddText(va("localskin -a %s", cv_fakelocalskin.string)); + break; + case 4: + COM_BufAddText(va("localskin -d 0 %s", cv_fakelocalskin.string)); + break; + case 5: + COM_BufAddText(va("localskin %s", cv_fakelocalskin.string)); + break; + default: + break; + } + S_StartSound(NULL, sfx_s221); +} + +// Display our localskin in our goofy ahhhh local skin menu +static void M_DrawLocalSkinMenu(void) +{ + INT32 mx, my, st, flags = 0; + spritedef_t *sprdef; + spriteframe_t *sprframe; + patch_t *patch; + UINT8 frame; + UINT8 skintodisplay; + UINT32 speenframe; + + mx = OP_ForkedBirdDef.x; + my = OP_ForkedBirdDef.y; + + // use generic drawer for cursor, items and title + M_DrawGenericMenu(); + + #define charw 72 + + // anim the player in the box + if (--multi_tics <= 0) + { + st = multi_state->nextstate; + if (st != S_NULL) + multi_state = &states[st]; + multi_tics = multi_state->tics; + if (multi_tics == -1) + multi_tics = 15; + } + + // skin 0 is default player sprite + if (R_AnySkinAvailable(cv_fakelocalskin.string) != -1) + { + sprdef = &allskins[R_AnySkinAvailable(cv_fakelocalskin.string)].spritedef; + skintodisplay = R_AnySkinAvailable(cv_fakelocalskin.string); + } + else + { + // ATTEMPT TO FIND REAL SKIN + if (R_AnySkinAvailable(cv_skin.string) != -1) + { + sprdef = &allskins[R_AnySkinAvailable(cv_skin.string)].spritedef; + skintodisplay = R_AnySkinAvailable(cv_skin.string); + } else { // STILL NOTHIN? use sonic instead + sprdef = &allskins[0].spritedef; + skintodisplay = 0; + } + } + + if (!sprdef->numframes) // No frames ?? + return; // Can't render! + + frame = multi_state->frame & FF_FRAMEMASK; + if (frame >= sprdef->numframes) // Walking animation missing + frame = 0; // Try to use standing frame + + sprframe = &sprdef->spriteframes[frame]; + + //minenice's speen css, it's a piece of shit but hey + //patch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE); + speenframe = (I_GetTime()*4/TICRATE + 1)%8; + + //this is a very shitty solution for checking if a sprite needs flipping + //but it works + if ((sprframe->lumppat[speenframe] == sprframe->lumppat[8-speenframe]) && (speenframe > 4)) { + flags = V_FLIP; // This sprite is left/right flipped! + } + patch = W_CachePatchNum(sprframe->lumppat[speenframe], PU_CACHE); + + // draw box around guy + V_DrawFill(mx + 220 - (charw/2), my+54, charw, 84, 239); + + // draw player sprite + UINT8 *colormap = R_GetTranslationColormap(skintodisplay, cv_playercolor.value, GTC_MENUCACHE); + colormap = R_GetLocalTranslationColormap(&skins[allskins[skintodisplay].localnum], (allskins[skintodisplay].localskin ? &localskins[allskins[skintodisplay].localnum] : NULL), cv_playercolor.value, GTC_MENUCACHE, allskins[skintodisplay].localskin); + + V_DrawMappedPatch(mx, my+50, 0, W_CachePatchName(allskins[skintodisplay].facewant, PU_CACHE), colormap); + V_DrawMappedPatch(mx+8, my+85, 0, W_CachePatchName(allskins[skintodisplay].facerank, PU_CACHE), colormap); + V_DrawString(mx, my+108, V_ALLOWLOWERCASE, "Character"); + if (strlen(allskins[skintodisplay].realname) > 10) + V_DrawThinString(mx+20, my+118, V_ALLOWLOWERCASE|highlightflags, allskins[skintodisplay].realname); + else + V_DrawString(mx+20, my+118, V_ALLOWLOWERCASE|highlightflags, allskins[skintodisplay].realname); + + if (allskins[skintodisplay].flags & SF_HIRES) + { + V_DrawFixedPatch((mx+220)<fuse = actor->fuse; // Transfer respawn timer remains->threshold = 68; remains->skin = NULL; + remains->localskin = NULL; P_SetTarget(&tmthing, remains); @@ -4167,6 +4168,18 @@ void A_SignPlayer(mobj_t *actor) P_SetTarget(&ov->target, actor); ov->color = actor->target->player->skincolor; ov->skin = &skins[actor->target->player->skin]; + if (actor->target->skinlocal) { + // needs - 1 or else it pukes an error out + // same thing happens on p_mobj.c + ov->localskin = &localskins[actor->target->player->localskin - 1]; + ov->skinlocal = actor->target->skinlocal; + } else { + // needs - 1 or else it pukes an error out + // same thing happens on p_mobj.c + if (actor->target->player->localskin) + ov->localskin = &skins[actor->target->player->localskin - 1]; + ov->skinlocal = actor->target->skinlocal; + } P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN } diff --git a/src/p_mobj.c b/src/p_mobj.c index 8aa726870..204532ea2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10772,6 +10772,16 @@ void P_SpawnPlayer(INT32 playernum) // (usefulness: when body mobj is detached from player (who respawns), // the dead body mobj retains the skin through the 'spritedef' override). mobj->skin = &skins[p->skin]; + if (p->localskin > 0) + { + if (p->skinlocal) + mobj->localskin = &localskins[p->localskin - 1]; + else + mobj->localskin = & skins[p->localskin - 1]; + } + else + mobj->localskin = 0; + mobj->skinlocal = p->skinlocal; mobj->health = p->health; p->playerstate = PST_LIVE; diff --git a/src/p_mobj.h b/src/p_mobj.h index 004a437c4..67a579c11 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -327,6 +327,8 @@ typedef struct mobj_s UINT16 eflags; // extra flags void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin) + void *localskin; + boolean skinlocal; // Player and mobj sprites in multiplayer modes are modified // using an internal color lookup table for re-indexing. UINT8 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation). diff --git a/src/p_setup.c b/src/p_setup.c index f0bf34c9f..ca15e44ba 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3433,7 +3433,7 @@ boolean P_RunSOC(const char *socfilename) lumpnum_t lump; if (strstr(socfilename, ".soc") != NULL) - return P_AddWadFile(socfilename); + return P_AddWadFile(socfilename, false); lump = W_CheckNumForName(socfilename); if (lump == LUMPERROR) @@ -3449,11 +3449,11 @@ boolean P_RunSOC(const char *socfilename) // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps // -boolean P_AddWadFile(const char *wadfilename) +boolean P_AddWadFile(const char *wadfilename, boolean local) { UINT16 wadnum; - if ((wadnum = P_PartialAddWadFile(wadfilename, false)) == UINT16_MAX) + if ((wadnum = P_PartialAddWadFile(wadfilename, local)) == UINT16_MAX) return false; P_MultiSetupWadFiles(true); @@ -3483,7 +3483,7 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local) boolean mapsadded = false; lumpinfo_t *lumpinfo; - if ((numlumps = W_InitFile(wadfilename, local)) == INT16_MAX) + if ((numlumps = W_InitFile(wadfilename, 0, &wadnum, local)) == INT16_MAX) { refreshdirmenu |= REFRESHDIR_NOTLOADED; CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); @@ -3493,6 +3493,11 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local) if (wadfiles[wadnum]->important) partadd_important = true; + + if (local) + wadfiles[wadnum]->localfile = true; + else + wadfiles[wadnum]->localfile = false; // // search for sound replacements @@ -3545,7 +3550,7 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local) // // look for skins // - R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] + R_AddSkins(wadnum, local); // faB: wadfile index in wadfiles[] // // edit music defs diff --git a/src/p_setup.h b/src/p_setup.h index 99269da00..728549943 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -60,7 +60,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_LoadThingsOnly(void); boolean P_SetupLevel(boolean skipprecip); -boolean P_AddWadFile(const char *wadfilename); +boolean P_AddWadFile(const char *wadfilename, boolean local); boolean P_AddWadFileLocal(const char *wadfilename); #ifdef DELFILE boolean P_DelWadFile(void); diff --git a/src/p_user.c b/src/p_user.c index feed77bd7..84445341e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1696,6 +1696,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->fuse = ghost->info->damage; ghost->skin = mobj->skin; + ghost->localskin = mobj->localskin; + ghost->skinlocal = mobj->skinlocal; if (mobj->flags2 & MF2_OBJECTFLIP) ghost->flags |= MF2_OBJECTFLIP; @@ -1737,10 +1739,19 @@ void P_DoPlayerExit(player_t *player) if (P_IsLocalPlayer(player)) { sfxenum_t sfx_id; - if (K_IsPlayerLosing(player)) - sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; - else - sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; + // fix godjjsa win sounds + if (K_IsPlayerLosing(player)) { + if (player->mo->localskin) + sfx_id = ((skin_t *)player->mo->localskin)->soundsid[S_sfx[sfx_klose].skinsound]; + else + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound]; + } + else { + if (player->mo->localskin) + sfx_id = ((skin_t *)player->mo->localskin)->soundsid[S_sfx[sfx_kwin].skinsound]; + else + sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound]; + } S_StartSound(NULL, sfx_id); } else diff --git a/src/r_draw.c b/src/r_draw.c index a29c26a3c..536b478b9 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -18,6 +18,7 @@ #include "doomdef.h" #include "doomstat.h" #include "r_local.h" +#include "r_things.h" #include "st_stuff.h" // need ST_HEIGHT #include "i_video.h" #include "v_video.h" @@ -141,6 +142,7 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define NUM_PALETTE_ENTRIES 256 static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL}; +static UINT8** localtranslationtablecache[MAXSKINS] = {NULL}; // See also the enum skincolors_t @@ -519,29 +521,39 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U \return Colormap. If not cached, caller should Z_Free. */ -UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) +static UINT8* RGetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags, boolean local) { + UINT8 ***tt; UINT8* ret; INT32 skintableindex; - // Adjust if we want the default colormap - if (skinnum == TC_DEFAULT) skintableindex = DEFAULT_TT_CACHE_INDEX; - else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX; - else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX; - else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX; - else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX; - else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX; - else skintableindex = skinnum; + if (local) + { + tt = localtranslationtablecache; + skintableindex = skinnum; + } + else + { + tt = translationtablecache; + // Adjust if we want the default colormap + if (skinnum == TC_DEFAULT) skintableindex = DEFAULT_TT_CACHE_INDEX; + else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX; + else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX; + else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX; + else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX; + else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX; + else skintableindex = skinnum; + } if (flags & GTC_CACHE) { // Allocate table for skin if necessary - if (!translationtablecache[skintableindex]) - translationtablecache[skintableindex] = Z_Calloc(MAXTRANSLATIONS * sizeof(UINT8**), PU_STATIC, NULL); + if (!tt[skintableindex]) + tt[skintableindex] = Z_Calloc(MAXTRANSLATIONS * sizeof(UINT8**), PU_STATIC, NULL); // Get colormap - ret = translationtablecache[skintableindex][color]; + ret = tt[skintableindex][color]; } else ret = NULL; @@ -549,16 +561,29 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) if (!ret) { ret = Z_MallocAlign(NUM_PALETTE_ENTRIES, (flags & GTC_CACHE) ? PU_LEVEL : PU_STATIC, NULL, 8); - K_GenerateKartColormap(ret, skinnum, color); //R_GenerateTranslationColormap(ret, skinnum, color); // SRB2kart + K_GenerateKartColormap(ret, skinnum, color, local); //R_GenerateTranslationColormap(ret, skinnum, color); // SRB2kart // Cache the colormap if desired if (flags & GTC_CACHE) - translationtablecache[skintableindex][color] = ret; + tt[skintableindex][color] = ret; } return ret; } +UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags) +{ + return RGetTranslationColormap(skinnum, color, flags, false); +} + +UINT8* R_GetLocalTranslationColormap(skin_t *skin, skin_t *localskin, skincolors_t color, UINT8 flags, boolean local) +{ + if (localskin) + return RGetTranslationColormap(( localskin - ( (local) ? localskins : skins ) ), color, flags, local); + else + return RGetTranslationColormap(( skin - skins ), color, flags, false); +} + /** \brief Flushes cache of translation colormaps. Flushes cache of translation colormaps, but doesn't actually free the @@ -574,6 +599,10 @@ void R_FlushTranslationColormapCache(void) for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++) if (translationtablecache[i]) memset(translationtablecache[i], 0, MAXTRANSLATIONS * sizeof(UINT8**)); + + for (i = 0; i < (INT32)(sizeof(localtranslationtablecache) / sizeof(localtranslationtablecache[0])); i++) + if (localtranslationtablecache[i]) + memset(localtranslationtablecache[i], 0, MAXTRANSLATIONS * sizeof(UINT8**)); } /* diff --git a/src/r_draw.h b/src/r_draw.h index b6d72fe71..c35c95ea4 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -15,6 +15,7 @@ #define __R_DRAW__ #include "r_defs.h" +#include "r_things.h" // ------------------------------- // COMMON STUFF FOR 8bpp AND 16bpp @@ -115,6 +116,7 @@ extern lumpnum_t viewborderlump[8]; // Initialize color translation tables, for player rendering etc. void R_InitTranslationTables(void); UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags); +UINT8* R_GetLocalTranslationColormap(skin_t *skin, skin_t *localskin, skincolors_t color, UINT8 flags, boolean local); void R_FlushTranslationColormapCache(void); UINT8 R_GetColorByName(const char *name); diff --git a/src/r_things.c b/src/r_things.c index 66c583259..92e31ba98 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -643,7 +643,7 @@ void R_InitSprites(void) // it can be is do before loading config for skin cvar possible value R_InitSkins(); for (i = 0; i < numwadfiles; i++) - R_AddSkins((UINT16)i); + R_AddSkins((UINT16)i, false); // // check if all sprites have frames @@ -872,10 +872,7 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); else if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } + dc_translation = R_GetLocalTranslationColormap(vis->mobj->skin, vis->mobj->localskin, vis->mobj->color, GTC_CACHE, vis->mobj->skinlocal); else // Use the defaults dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); } @@ -893,10 +890,7 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->mobj->colorized) dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); else if (vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } + dc_translation = R_GetLocalTranslationColormap(vis->mobj->skin, vis->mobj->localskin, vis->mobj->color, GTC_CACHE, vis->mobj->skinlocal); else // Use the defaults dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); } @@ -925,7 +919,9 @@ static void R_DrawVisSprite(vissprite_t *vis) frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) + if (vis->mobj->localskin && ((skin_t *)vis->mobj->localskin)->flags & SF_HIRES) + this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->localskin)->highresscale); + else if (vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); if (this_scale <= 0) this_scale = 1; @@ -1274,7 +1270,7 @@ static void R_ProjectSprite(mobj_t *thing) //Fab : 02-08-98: 'skin' override spritedef currently used for skin if (thing->skin && thing->sprite == SPR_PLAY) { - sprdef = &((skin_t *)thing->skin)->spritedef; + sprdef = &((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->spritedef; #ifdef ROTSPRITE sprinfo = &spriteinfo[thing->sprite]; #endif @@ -1348,7 +1344,9 @@ static void R_ProjectSprite(mobj_t *thing) I_Assert(lump < max_spritelumps); - if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) + if (thing->localskin && ((skin_t *)thing->localskin)->flags & SF_HIRES) + this_scale = FixedMul(this_scale, ((skin_t *)thing->localskin)->highresscale); + else if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale); spr_width = spritecachedinfo[lump].width; @@ -2784,6 +2782,8 @@ void R_DrawMasked(void) // ========================================================================== INT32 numskins = 0; +INT32 numallskins = 0; +INT32 numlocalskins = 0; skin_t skins[MAXSKINS]; UINT8 skinstats[9][9][MAXSKINS]; UINT8 skinstatscount[9][9] = { @@ -2798,13 +2798,16 @@ UINT8 skinstatscount[9][9] = { {0, 0, 0, 0, 0, 0, 0, 0, 0} }; UINT8 skinsorted[MAXSKINS]; +skin_t localskins[MAXSKINS]; +skin_t allskins[MAXSKINS*2]; // FIXTHIS: don't work because it must be inistilised before the config load //#define SKINVALUES #ifdef SKINVALUES CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; +CV_PossibleValue_t localskin_cons_t[MAXSKINS+1]; #endif -static void Sk_SetDefaultValue(skin_t *skin) +static void Sk_SetDefaultValue(skin_t *skin, boolean local) { INT32 i; // @@ -2812,7 +2815,7 @@ static void Sk_SetDefaultValue(skin_t *skin) // memset(skin, 0, sizeof (skin_t)); snprintf(skin->name, - sizeof skin->name, "skin %u", (UINT32)(skin-skins)); + sizeof skin->name, "skin %u", (UINT32)(skin-( (local) ? localskins : skins ))); skin->name[sizeof skin->name - 1] = '\0'; skin->wadnum = INT16_MAX; strcpy(skin->sprite, ""); @@ -2853,13 +2856,15 @@ void R_InitSkins(void) { skin_cons_t[i].value = 0; skin_cons_t[i].strvalue = NULL; + localskin_cons_t[i].value = 0; + localskin_cons_t[i].strvalue = NULL; } #endif // skin[0] = Sonic skin skin = &skins[0]; numskins = 1; - Sk_SetDefaultValue(skin); + Sk_SetDefaultValue(skin, false); memset(skinstats, 0, sizeof(skinstats)); memset(skinsorted, 0, sizeof(skinsorted)); @@ -2875,7 +2880,10 @@ void R_InitSkins(void) strncpy(skin->facerank, "PLAYRANK", 9); strncpy(skin->facewant, "PLAYWANT", 9); strncpy(skin->facemmap, "PLAYMMAP", 9); + skin->wadnum = 0; // god what have you brought to this world skin->prefcolor = SKINCOLOR_BLUE; + skin->localskin = false; + skin->localnum = 0; // SRB2kart skin->kartspeed = 8; @@ -2893,8 +2901,12 @@ void R_InitSkins(void) //MD2 for sonic doesn't want to load in Linux. #ifdef HWRENDER if (rendermode == render_opengl) - HWR_AddPlayerMD2(0); + HWR_AddPlayerMD2(0, false); #endif + + // lets set it + allskins[0] = skins[0]; + numallskins = 1; } // returns true if the skin name is found (loaded from pwad) @@ -2911,6 +2923,37 @@ INT32 R_SkinAvailable(const char *name) return -1; } +// returns true if the skin name is found (loaded from pwad) +// warning return -1 if not found +INT32 R_AnySkinAvailable(const char *name) +{ + INT32 i; + + for (i = 0; i < numallskins; i++) + { + if (stricmp(allskins[i].name,name)==0) + return i; + } + return -1; +} + +INT32 R_LocalSkinAvailable(const char *name, boolean local) +{ + INT32 i; + + if (local) + { + for (i = 0; i < numlocalskins; i++) + { + if (stricmp(localskins[i].name,name)==0) + return i; + } + return -1; + } + else + return R_SkinAvailable(name); +} + // network code calls this when a 'skin change' is received boolean SetPlayerSkin(INT32 playernum, const char *skinname) { @@ -2936,6 +2979,67 @@ boolean SetPlayerSkin(INT32 playernum, const char *skinname) return false; } +void SetLocalPlayerSkin(INT32 playernum, const char *skinname, consvar_t *cvar) +{ + player_t *player = &players[playernum]; + INT32 i; + + if (strcasecmp(skinname, "none")) + { + for (i = 0; i < numlocalskins; i++) + { + // search in the skin list + if (stricmp(localskins[i].name, skinname) == 0) + { + player->localskin = 1 + i; + player->skinlocal = true; + if (player->mo) + { + player->mo->localskin = &localskins[i]; + player->mo->skinlocal = true; + } + break; + } + } + for (i = 0; i < numskins; i++) + { + // search in the skin list + if (stricmp(skins[i].name, skinname) == 0) + { + player->localskin = 1 + i; + player->skinlocal = false; + if (player->mo) + { + player->mo->localskin = &skins[i]; + player->mo->skinlocal = false; + } + break; + } + } + } + else + { + player->localskin = 0; + player->skinlocal = false; + if (player->mo) + { + player->mo->localskin = 0; + player->mo->skinlocal = false; + } + } + + if (cvar != NULL) { + if (player->localskin > 0) { + CV_StealthSet(&cv_fakelocalskin, ( (player->skinlocal) ? localskins : skins )[player->localskin - 1].name); + CV_StealthSet(cvar, ( (player->skinlocal) ? localskins : skins )[player->localskin - 1].name); + } + else { + CV_StealthSet(&cv_fakelocalskin, "none"); + CV_StealthSet(cvar, "none"); + } + } +} + // Same as SetPlayerSkin, but uses the skin #. // network code calls this when a 'skin change' is received void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) @@ -3120,7 +3224,7 @@ void sortSkinGrid(void) // // Find skin sprites, sounds & optional status bar face, & add them // -void R_AddSkins(UINT16 wadnum) +void R_AddSkins(UINT16 wadnum, boolean local) { UINT16 lump, lastlump = 0; char *buf; @@ -3140,7 +3244,7 @@ void R_AddSkins(UINT16 wadnum) // advance by default lastlump = lump + 1; - if (numskins >= MAXSKINS) + if (( (local) ? numlocalskins : numskins ) >= MAXSKINS) { CONS_Alert(CONS_WARNING, M_GetText("Unable to add skin, too many characters are loaded (%d maximum)\n"), MAXSKINS); continue; // so we know how many skins couldn't be added @@ -3156,8 +3260,8 @@ void R_AddSkins(UINT16 wadnum) buf2[size] = '\0'; // set defaults - skin = &skins[numskins]; - Sk_SetDefaultValue(skin); + skin = &( (local) ? localskins : skins )[( (local) ? numlocalskins : numskins )]; + Sk_SetDefaultValue(skin, local); skin->wadnum = wadnum; hudname = realname = false; // parse @@ -3181,7 +3285,7 @@ void R_AddSkins(UINT16 wadnum) // the skin name must uniquely identify a single skin // I'm lazy so if name is already used I leave the 'skin x' // default skin name set in Sk_SetDefaultValue - if (R_SkinAvailable(value) == -1) + if (R_LocalSkinAvailable(value, local) == -1) { STRBUFCPY(skin->name, value); strlwr(skin->name); @@ -3191,12 +3295,12 @@ void R_AddSkins(UINT16 wadnum) else { const size_t stringspace = - strlen(value) + sizeof (numskins) + 1; + strlen(value) + sizeof (( (local) ? numlocalskins : numskins )) + 1; char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL); snprintf(value2, stringspace, - "%s%d", value, numskins); + "%s%d", value, ( (local) ? numlocalskins : numskins )); value2[stringspace - 1] = '\0'; - if (R_SkinAvailable(value2) == -1) + if (R_LocalSkinAvailable(value2, local) == -1) { STRBUFCPY(skin->name, value2); @@ -3379,29 +3483,48 @@ next_token: CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); #ifdef SKINVALUES - skin_cons_t[numskins].value = numskins; - skin_cons_t[numskins].strvalue = skin->name; + ( (local) ? localskin_cons_t : skin_cons_t )[( (local) ? numlocalskins : numskins )].value = ( (local) ? numlocalskins : numskins ); + ( (local) ? localskin_cons_t : skin_cons_t )[( (local) ? numlocalskins : numskins )].strvalue = skin->name; #endif // Update the forceskin possiblevalues - Forceskin_cons_t[numskins+1].value = numskins; - Forceskin_cons_t[numskins+1].strvalue = skins[numskins].name; + if (!local) + { + Forceskin_cons_t[numskins+1].value = numskins; + Forceskin_cons_t[numskins+1].strvalue = skins[numskins].name; + } + + skin->localskin = local; + // so we dont have to guess + if (local) + skin->localnum = numlocalskins; + else + skin->localnum = numskins; // add face graphics - ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); + if (local) { + ST_LoadLocalFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numlocalskins); + } else { + ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); + } #ifdef HWRENDER if (rendermode == render_opengl) - HWR_AddPlayerMD2(numskins); + HWR_AddPlayerMD2(( (local) ? numlocalskins : numskins ), local); #endif - skinstats[skin->kartspeed-1][skin->kartweight-1][skinstatscount[skin->kartspeed-1][skin->kartweight-1]] = numskins; - CONS_Debug(DBG_SETUP, M_GetText("Added %d to %d, %d\n"), numskins, skin->kartweight, skin->kartweight); - skinstatscount[skin->kartspeed-1][skin->kartweight-1]++; - CONS_Debug(DBG_SETUP, M_GetText("Incremented %d, %d to %d\n"), skin->kartspeed, skin->kartweight, skinstatscount[skin->kartspeed - 1][skin->kartweight - 1]); + if (!local) { + skinstats[skin->kartspeed-1][skin->kartweight-1][skinstatscount[skin->kartspeed-1][skin->kartweight-1]] = numskins; + CONS_Debug(DBG_SETUP, M_GetText("Added %d to %d, %d\n"), numskins, skin->kartweight, skin->kartweight); + skinstatscount[skin->kartspeed-1][skin->kartweight-1]++; + CONS_Debug(DBG_SETUP, M_GetText("Incremented %d, %d to %d\n"), skin->kartspeed, skin->kartweight, skinstatscount[skin->kartspeed - 1][skin->kartweight - 1]); + + skinsorted[numskins] = numskins; + } + + allskins[numallskins] = ( (local) ? localskins : skins )[( (local) ? numlocalskins : numskins )]; - skinsorted[numskins] = numskins; - - numskins++; + ( (local) ? numlocalskins++ : numskins++ ); + numallskins++; } sortSkinGrid(); diff --git a/src/r_things.h b/src/r_things.h index ab4688f91..833edd5fd 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -97,6 +97,9 @@ typedef struct // specific sounds per skin sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table + + boolean localskin; + INT32 localnum; } skin_t; extern CV_PossibleValue_t Forceskin_cons_t[]; @@ -201,17 +204,24 @@ typedef struct drawnode_s } drawnode_t; extern INT32 numskins; +extern INT32 numlocalskins; +extern INT32 numallskins; extern skin_t skins[MAXSKINS]; extern UINT8 skinstats[9][9][MAXSKINS]; extern UINT8 skinstatscount[9][9]; extern UINT8 skinsorted[MAXSKINS]; void sortSkinGrid(void); +extern skin_t localskins[MAXSKINS]; +extern skin_t allskins[MAXSKINS*2]; boolean SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 +void SetLocalPlayerSkin(INT32 playernum,const char *skinname, consvar_t *cvar); INT32 R_SkinAvailable(const char *name); -void R_AddSkins(UINT16 wadnum); +INT32 R_AnySkinAvailable(const char *name); +INT32 R_LocalSkinAvailable(const char *name, boolean local); +void R_AddSkins(UINT16 wadnum, boolean local); #ifdef DELFILE void R_DelSkins(UINT16 wadnum); diff --git a/src/s_sound.c b/src/s_sound.c index 977d3be55..9afea7bf5 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -578,7 +578,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (sfx->skinsound != -1 && origin && origin->skin) { // redirect player sound to the sound in the skin table - sfx_id = ((skin_t *)origin->skin)->soundsid[sfx->skinsound]; + sfx_id = ((skin_t *)( (origin->localskin) ? origin->localskin : origin->skin ))->soundsid[sfx->skinsound]; sfx = &S_sfx[sfx_id]; } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d08b267f0..e236d1fca 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1297,7 +1297,7 @@ void I_GetEvent(void) break; case SDL_DROPFILE: dropped_filedir = evt.drop.file; - P_AddWadFile(dropped_filedir); + P_AddWadFile(dropped_filedir, false); SDL_free(dropped_filedir); // Free dropped_filedir memory break; case SDL_QUIT: diff --git a/src/st_stuff.c b/src/st_stuff.c index 966a0c9c6..19567b42d 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -58,6 +58,18 @@ patch_t *facerankprefix[MAXSKINS]; // ranking patch_t *facewantprefix[MAXSKINS]; // wanted patch_t *facemmapprefix[MAXSKINS]; // minimap +patch_t *localfacerankprefix[MAXSKINS]; // ranking +patch_t *localfacewantprefix[MAXSKINS]; // wanted +patch_t *localfacemmapprefix[MAXSKINS]; // minimap + +char *facerankprefix_name[MAXSKINS]; // ranking +char *facewantprefix_name[MAXSKINS]; // wanted +char *facemmapprefix_name[MAXSKINS]; // minimap + +char *localfacerankprefix_name[MAXSKINS]; // ranking +char *localfacewantprefix_name[MAXSKINS]; // wanted +char *localfacemmapprefix_name[MAXSKINS]; // minimap + // ------------------------------------------ // status bar overlay // ------------------------------------------ @@ -378,6 +390,25 @@ void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skin facerankprefix[skinnum] = W_CachePatchName(rankstr, PU_HUDGFX); facewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX); facemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX); + + facerankprefix_name[skinnum] = rankstr; + facewantprefix_name[skinnum] = wantstr; + facemmapprefix_name[skinnum] = mmapstr; +} + +void ST_LoadLocalFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skinnum) +{ + localfacerankprefix[skinnum] = W_CachePatchName(rankstr, PU_HUDGFX); + localfacewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX); + localfacemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX); + + localfacerankprefix_name[skinnum] = rankstr; + localfacewantprefix_name[skinnum] = wantstr; + localfacemmapprefix_name[skinnum] = mmapstr; + + //CONS_Printf("Added rank prefix %s\n", rankstr); + //CONS_Printf("Added want prefix %s\n", wantstr); + //CONS_Printf("Added mmap prefix %s\n", mmapstr); } void ST_ReloadSkinFaceGraphics(void) @@ -386,6 +417,10 @@ void ST_ReloadSkinFaceGraphics(void) for (i = 0; i < numskins; i++) ST_LoadFaceGraphics(skins[i].facerank, skins[i].facewant, skins[i].facemmap, i); + + for (i = 0; i < numlocalskins; i++) { + ST_LoadLocalFaceGraphics(localskins[i].facerank, localskins[i].facewant, localskins[i].facemmap, i); + } } static inline void ST_InitData(void) diff --git a/src/st_stuff.h b/src/st_stuff.h index 0f8722720..281b87fb5 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -51,6 +51,7 @@ void ST_LoadGraphics(void); // face load graphics, called when skin changes void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 playernum); +void ST_LoadLocalFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 playernum); void ST_ReloadSkinFaceGraphics(void); #ifdef DELFILE void ST_UnLoadFaceGraphics(INT32 skinnum); @@ -78,6 +79,15 @@ extern patch_t *sboperiod; extern patch_t *facerankprefix[MAXSKINS]; // ranking extern patch_t *facewantprefix[MAXSKINS]; // wanted extern patch_t *facemmapprefix[MAXSKINS]; // minimap +extern patch_t *localfacerankprefix[MAXSKINS]; // ranking +extern patch_t *localfacewantprefix[MAXSKINS]; // wanted +extern patch_t *localfacemmapprefix[MAXSKINS]; // minimap +extern char *facerankprefix_name[MAXSKINS]; // ranking +extern char *facewantprefix_name[MAXSKINS]; // wanted +extern char *facemmapprefix_name[MAXSKINS]; // minimap +extern char *localfacerankprefix_name[MAXSKINS]; // ranking +extern char *localfacewantprefix_name[MAXSKINS]; // wanted +extern char *localfacemmapprefix_name[MAXSKINS]; // minimap extern patch_t *livesback; extern patch_t *ngradeletters[7]; diff --git a/src/w_wad.c b/src/w_wad.c index 31977bea8..a35f8ef3a 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -65,6 +65,7 @@ #include "i_system.h" #include "md5.h" #include "lua_script.h" +#include "st_stuff.h" #ifdef SCANTHINGS #include "p_setup.h" // P_ScanThings #endif @@ -690,7 +691,7 @@ static void W_ReadFileShaders(wadfile_t *wadfile) // // Can now load dehacked files (.soc) // -UINT16 W_InitFile(const char *filename, boolean local) +UINT16 W_InitFile(const char *filename, const char *lumpname, UINT16 *wadnump, boolean local) { FILE *handle; lumpinfo_t *lumpinfo = NULL; @@ -743,10 +744,13 @@ UINT16 W_InitFile(const char *filename, boolean local) { if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) { - CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); - if (handle) - fclose(handle); - return INT16_MAX; + if (!local) { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); + if (handle) + fclose(handle); + return INT16_MAX; + } + CONS_Alert(CONS_WARNING, M_GetText("%s is a local skin that is already loaded\n"), filename); } } #endif @@ -789,6 +793,7 @@ UINT16 W_InitFile(const char *filename, boolean local) fseek(handle, 0, SEEK_END); wadfile->filesize = (unsigned)ftell(handle); wadfile->type = type; + wadfile->majormod = false; // already generated, just copy it over M_Memcpy(&wadfile->md5sum, &md5sum, 16); @@ -898,7 +903,7 @@ INT32 W_InitMultipleFiles(char **filenames, boolean addons) G_SetGameModified(true, false); //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); - rc = W_InitFile(*filenames, false); + rc = W_InitFile(*filenames, 0, 0, false); if (rc == INT16_MAX) CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), *filenames); overallrc &= (rc != INT16_MAX) ? 1 : 0; @@ -1727,7 +1732,9 @@ void *W_CachePatchName(const char *name, INT32 tag) { lumpnum_t num; - num = W_CheckNumForName(name); + const char *finalname = name; + + num = W_CheckNumForName(finalname); if (num == LUMPERROR) return W_CachePatchNum(W_GetNumForName("MISSING"), tag); diff --git a/src/w_wad.h b/src/w_wad.h index 1c6e86c49..b2b518793 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -114,6 +114,8 @@ typedef struct wadfile_s UINT32 filesize; // for network UINT8 md5sum[16]; boolean important; + boolean majormod; + boolean localfile; // only for skins } wadfile_t; #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word @@ -132,7 +134,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors); // // if local is true, it wouldn't check if file adds complex things, therefore // allowing to still join server without the "you have wrong addons loaded" error -UINT16 W_InitFile(const char *filename, boolean local); +UINT16 W_InitFile(const char *filename, const char *lumpname, UINT16 *wadnump, boolean local); #ifdef DELFILE void W_UnloadWadFile(UINT16 num); #endif diff --git a/src/y_inter.c b/src/y_inter.c index 3fb2d3aa3..02b88f834 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -482,7 +482,15 @@ void Y_IntermissionDrawer(void) if (data.match.color[i]) { UINT8 *colormap = R_GetTranslationColormap(*data.match.character[i], *data.match.color[i], GTC_CACHE); - V_DrawMappedPatch(x+16, y-4, 0, facerankprefix[*data.match.character[i]], colormap); + // i fucking hate this i fucking hate this i hate this so much + if (!players[data.match.num[i]].skinlocal) { + if (!players[data.match.num[i]].localskin) + V_DrawMappedPatch(x+16, y-4, 0, facerankprefix[*data.match.character[i]], colormap); + else + V_DrawMappedPatch(x+16, y-4, 0, facerankprefix[players[data.match.num[i]].localskin - 1], colormap); + } else { + V_DrawMappedPatch(x+16, y-4, 0, localfacerankprefix[players[data.match.num[i]].localskin - 1], colormap); + } } if (data.match.num[i] == whiteplayer) @@ -1200,7 +1208,7 @@ void Y_VoteDrawer(void) if (players[i].skincolor) { UINT8 *colormap = R_GetTranslationColormap(players[i].skin, players[i].skincolor, GTC_CACHE); - V_DrawMappedPatch(x+24, y+9, V_SNAPTOLEFT, facerankprefix[players[i].skin], colormap); + V_DrawMappedPatch(x+24, y+9, V_SNAPTOLEFT, (players[i].skinlocal ? localfacerankprefix : facerankprefix)[((players[i].localskin) ? players[i].localskin-1 : players[i].skin)], colormap); } if (!splitscreen && i == consoleplayer)