Compare commits

...
53 Commits
Author SHA1 Message Date
indev 2800685cfc Merge branch 'Saturn-Next' into emotes 2025-07-01 20:15:44 +03:00
sphere c479d9d706 Merge branch 'allowdesync' into 'next'
Add a console variable that will allow individual demos to desync....

See merge request STJr/SRB2!2361
2025-07-01 19:06:10 +02:00
Alug 338fbfbeaf whoops those are demo related lol 2025-07-01 19:06:07 +02:00
Alug 5ca12bb421 split replay stuff into g_demo 2025-07-01 18:48:46 +02:00
Alug 6c94e0c9bf conflict moment 2025-07-01 18:29:45 +02:00
Alug 83d0f6bb50 move kart hud stuff into k_hud
hope i got everything lol
2025-07-01 18:27:39 +02:00
Alug 7e06fc986f this is INT32 so cast to that lel 2025-07-01 15:26:21 +02:00
Alug 3f5328371a put interp distance stuff into a function
just some code dupe cleanup
also account for c++ so we can use the same macro lel
2025-07-01 15:26:18 +02:00
Alug 148fcc8dab friendship with constexpr started 2025-07-01 15:26:02 +02:00
Alug 72a67d306f slightly cleanup addline stuff
no clue why i just didnt do this before lel
2025-07-01 15:25:57 +02:00
Alug 0dcdcc3da1 fix hw_main compiler warning 2025-07-01 15:25:53 +02:00
Alug 729c60c9b0 thanks michaelsoft very cool 2025-07-01 15:25:26 +02:00
Alug 1b418caf6b ceepeepeefy hw_main, abuse templates for portal stuff
no idea if this is faster at all lmao
2025-07-01 15:25:23 +02:00
Alug d275db9bb4 turn TC_ stuff into enum 2025-07-01 15:25:14 +02:00
Alug 21cfd7c361 Merge pull request #186 from Indev450/softwarecrap
Give the software renderer some love!
2025-07-01 15:21:48 +02:00
indev 5d8bb3223f No need for this now 2025-07-01 15:25:48 +03:00
indev 5e1f943a38 Merge branch 'Saturn-Next' into emotes 2025-07-01 15:24:42 +03:00
Alug 612431c1f1 dont define min and max with c++ 2025-07-01 14:22:49 +02:00
indev fca7b4a837 Use std::min 2025-07-01 15:15:36 +03:00
indev d2bab80b29 Add emote suggestions and autocompletion 2025-06-30 16:43:14 +03:00
Alug 78ab90c1a6 "restrict" macro for c++
since it does not have it, use __restrict instead
2025-06-30 12:54:15 +03:00
indev 102e944fd5 Preview emotes in chat input 2025-06-30 00:28:14 +03:00
Alug 04385d9700 add "songcredits" to saturn hud menu
since we have a new style for this now, want to have it in the menu instead
2025-06-29 12:02:11 +02:00
Alug 7ef2da5922 tiny cleanup hw_batching 2025-06-29 11:44:12 +02:00
Alug 5638709670 some cleanup k_kart
perhaps we could also move the saturn stuff into arrays, those massive walls of variables are kinda ugly lel
2025-06-29 11:44:04 +02:00
indev 9bd4a933cf Check if text is inside chat log box for emotes 2025-06-29 00:30:24 +03:00
indev e233635783 huh? 2025-06-29 00:05:25 +03:00
indev da24ba20c7 Fix emotes having not enough 'background' rendered :chonkbunckle: 2025-06-28 22:39:44 +03:00
indev 74bdabc636 Load emotes from base wads too at boot (so it loads ones from -file wads) 2025-06-28 22:31:33 +03:00
indev 4b129314d3 Right that got removed in the end :chonkbunckle: 2025-06-28 21:04:09 +03:00
indev 3a55972997 Initial emote support 2025-06-28 21:03:15 +03:00
Alug 6e04e4171e fix the goddamn boolean 2025-06-28 19:21:45 +03:00
indev db67176eca Revert "Replace '\' symbols with '\\' in comptime.sh"
This reverts commit 0b7a4ff4e0.
2025-06-26 22:50:59 +03:00
indev 0b7a4ff4e0 Replace '\' symbols with '\\' in comptime.sh 2025-06-26 21:18:22 +03:00
Alug 02feb3ad5c Merge pull request #177 from Indev450/votebgstuff
Cleanup Votescreen stuff
2025-06-25 13:24:48 +02:00
Alug 49f13d2a59 Merge pull request #176 from Indev450/luamusicdef
Expose musicdefs to lua
2025-06-25 13:24:37 +02:00
indev 8fb1775606 Forgot MusicCredit hook 2025-05-31 19:15:04 +03:00
indev fab7635373 Add musicdef lua stuff into LUASTUFF.md 2025-05-31 19:10:58 +03:00
indev b29ca13916 Add musicdefs table into lua 2025-05-31 18:54:07 +03:00
Alug e13ba89f1a use memcmp during startup map check
prob not faster just looks a bit better tbh
2025-05-31 17:20:38 +02:00
indev 68ae880979 Change the way how musicdefs are stored (preparing for exposing them to lua) 2025-05-31 18:04:08 +03:00
Alug d8b2134aef dont let dedi cache vote patches lol 2025-05-31 15:32:57 +02:00
Alug c168832f8e forgor to remove this 2025-05-31 15:32:53 +02:00
Alug 448a603a56 dont let dedi free votepatches lel 2025-05-31 15:32:42 +02:00
Alug 2a95201c6d free votepatches also in ogl not just software 2025-05-31 15:32:39 +02:00
Alug a73de55f96 also put votescreen patches into votescreen struct
+ more cleanup
2025-05-31 15:32:34 +02:00
Alug e4a4496be6 rename luaVoteScreen to luaPrefix + make it static buffer
since its effectively just a prefix,
2025-05-31 15:32:18 +02:00
Alug a8f3a8dfb0 fix oopsie that caused use after free 2025-05-31 15:32:14 +02:00
Alug e19b9d1c60 fix smol mistake votescreen check 2025-05-31 15:32:11 +02:00
Alug e28ec4e7cb unnest loop stuff in P_PartialAddWadFile
may speed this up ever so slightly since we dont need to go through all wad lumps 3 times per call anymore
2025-05-31 15:31:58 +02:00
Alug d0f09b467b Put votescreen background stuff into a struct
+ some refactoring and renaming

- removed some unused and redundant variables
- renamed some variables

turns out the lua votescreens always used the animated votescreen drawer, so i renamed it to lua votescreen drawer
2025-05-31 15:30:50 +02:00
indev 359befd857 Add MusicCredit lua hook 2025-05-28 23:27:30 +03:00
indev 279dfcafc4 Expose S_FindMusicCredit and musiccredit_t to lua 2025-05-28 22:10:25 +03:00
53 changed files with 10938 additions and 9785 deletions

No files matched your search

+31
View File
@@ -161,6 +161,37 @@ Duration is in milliseconds and is optional to set, default value is 84ms.
Exactly same as P_CheckSight but uses cheaper algorithm, useful for things like nametags. Doesn't work exactly
like P_CheckSight so don't use it for anything gameplay-related.
## musicdef_t
Userdata structure representing a musicdef. Fields:
`musicdef.name` - song identifier ("kmap01" for example).
`musicdef.usage`, `musicdef.source` - fields from vanilla MUSICDEFS lump.
`musicdef.filename` - unused for now.
`musicdef.title`, `musicdef.alttitle`, `musicdef.authors` - fields from MUSCINFO lump.
`#musicdef` - returns integer id for musicdef (which can be used as index in `musicdefs`).
All fields are read-only.
## S_FindMusicCredit(name)
Returns musicdef corresponding to music with given identifier. For example, `S_FindMusicCredit("kmap01")` will return
musicdef for green hills music.
## musicdefs
Global table for all musicdefs, similar to mobjinfo, states, etc. Can take either integer indices,
from `0` to `#musicdefs-1`, or string indices (which is equal to calling `S_FindMusicCredit`).
## addHook("MusicCredit", function(musicdef))
Hook is called whenever `S_ShowMusicCredit` (either from game or mod) is called. Takes musicdef as only argument, returning true
will overwrite vanilla behavior (not show music credit), can be used to implement custom music credit pop-ups.
# Other changes
## P_PlayRinglossSound(source, damager)
+3
View File
@@ -13,6 +13,7 @@ f_finale.c
f_wipe.c
filesrch.c
g_game.c
g_demo.c
g_input.c
hu_stuff.c
i_tcp.c
@@ -28,6 +29,7 @@ m_cond.c
m_fixed.c
m_menu.c
m_textinput.c
m_emotes.cpp
m_misc.c
m_perfstats.c
m_queue.c
@@ -78,6 +80,7 @@ p_tick.c
p_user.c
k_director.c
k_kart.c
k_hud.c
k_stats.c
lua_baselib.c
lua_blockmaplib.c
+26 -22
View File
@@ -40,6 +40,7 @@
#include "g_game.h"
#include "g_input.h"
#include "hu_stuff.h"
#include "m_emotes.h"
#include "i_sound.h"
#include "i_system.h"
#include "i_time.h"
@@ -72,6 +73,7 @@
#include "d_protocol.h"
#include "m_perfstats.h"
#include "k_kart.h"
#include "k_hud.h"
#include "core/memory.h"
@@ -1242,32 +1244,32 @@ static boolean AddIWAD(void)
}
// extra graphic patches for saturn specific thingies
boolean found_extra_kart = false;
boolean found_extra_kart = false;
boolean found_extra2_kart = false;
boolean found_extra3_kart = false;
boolean xtra_speedo = false; // extra speedometer check
boolean xtra_speedo_clr = false; // extra speedometer colour check
boolean xtra_speedo3 = false; // 80x 11 extra speedometer check
boolean xtra_speedo_clr3 = false; // 80x 11 extra speedometer colour check
boolean achi_speedo = false; // achiiro speedometer check
boolean achi_speedo_clr = false; // extra speedometer colour check
boolean dial_speedo = false; // dial speedometer check
boolean dial_speedo_clr = false; // dial speedometer colour check
boolean kartz_speedo = false; // kartZ speedo
boolean xtra_speedo = false; // extra speedometer check
boolean xtra_speedo_clr = false; // extra speedometer colour check
boolean xtra_speedo3 = false; // 80x 11 extra speedometer check
boolean xtra_speedo_clr3 = false; // 80x 11 extra speedometer colour check
boolean achi_speedo = false; // achiiro speedometer check
boolean achi_speedo_clr = false; // extra speedometer colour check
boolean dial_speedo = false; // dial speedometer check
boolean dial_speedo_clr = false; // dial speedometer colour check
boolean kartz_speedo = false; // kartZ speedo
boolean kartz_speedo_smol = false; // kartZ speedo but smol
boolean clr_hud = false; // colour hud check
boolean clr_hud = false; // colour hud check
boolean driftgaugegfx_clr = false; // driftgauge colour check
boolean big_lap = false; // bigger lap counter
boolean big_lap_color = false; // bigger lap counter but colour
boolean statdp = false; // stat display for extended player setup
boolean nametaggfx = false; // Nametag stuffs
boolean driftgaugegfx = false; // Driftgauge stuffs
boolean multiitem_icon = false; // Extra icons for Sneakers, Banana and Jawz
boolean joystickicon = false; // Extra icons for the joystick input display
boolean minidoticon = false; // Dot graphic for minimap player angle display
boolean minilighticon = false; // mkwii-style minimap headlight
boolean big_lap = false; // bigger lap counter
boolean big_lap_color = false; // bigger lap counter but colour
boolean statdp = false; // stat display for extended player setup
boolean nametaggfx = false; // Nametag stuffs
boolean driftgaugegfx = false; // Driftgauge stuffs
boolean multiitem_icon = false; // Extra icons for Sneakers, Banana and Jawz
boolean joystickicon = false; // Extra icons for the joystick input display
boolean minidoticon = false; // Dot graphic for minimap player angle display
boolean minilighticon = false; // mkwii-style minimap headlight
//
static void IdentifyVersion(void)
@@ -1840,7 +1842,7 @@ void D_SRB2Main(void)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
if (memcmp(name, "MAP", 3) == 0) // Ignore the headers
{
INT16 num;
if (name[5] != '\0')
@@ -1870,7 +1872,7 @@ void D_SRB2Main(void)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
if (memcmp(name, "MAP", 3) == 0) // Ignore the headers
{
INT16 num;
if (name[5] != '\0')
@@ -2023,6 +2025,8 @@ void D_SRB2Main(void)
S_InitMusicDefs();
M_InitEmotes();
CONS_Printf("ST_Init(): Init status bar.\n");
ST_Init();
+5
View File
@@ -21,6 +21,7 @@
#include "i_system.h"
#include "g_game.h"
#include "hu_stuff.h"
#include "m_emotes.h"
#include "g_input.h"
#include "m_menu.h"
#include "r_local.h"
@@ -912,6 +913,8 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_keyboardlayout);
CV_RegisterVar(&cv_emotes);
// time attack ghost options are also saved to config
CV_RegisterVar(&cv_ghost_besttime);
CV_RegisterVar(&cv_ghost_bestlap);
@@ -1048,7 +1051,9 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_verticallook[i]);
}
CV_RegisterVar(&cv_resyncdemo);
CV_RegisterVar(&cv_demodateformat);
CV_RegisterVar(&cv_showspecstuff);
// ingame object placing
+4070
View File
File diff suppressed because it is too large. Load diff
+191
View File
@@ -0,0 +1,191 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file g_demo.h
/// \brief Demo recording and playback
#ifndef __G_DEMO__
#define __G_DEMO__
#ifdef __cplusplus
extern "C" {
#endif
#include "doomdef.h"
#include "doomstat.h"
#include "d_event.h"
#include "p_saveg.h"
#include "m_textinput.h"
extern savebuffer_t demobuf;
// demoplaying back and demo recording
extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_maxdemosize, cv_demochangemap;
extern consvar_t cv_demodateformat;
extern consvar_t cv_resyncdemo;
// Publicly-accessible demo vars
struct demovars_s {
char titlename[65];
textinput_t titlenameinput;
boolean recording, playback, timing;
UINT16 version; // Current file format of the demo being played
boolean title; // Title Screen demo can be cancelled by any key
boolean rewinding; // Rewind in progress
boolean loadfiles, ignorefiles; // Demo file loading options
boolean fromtitle; // SRB2Kart: Don't stop the music
boolean inreplayhut; // Go back to replayhut after demos
boolean quitafterplaying; // quit after playing a demo from cmdline
boolean deferstart; // don't start playing demo right away
tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going
enum {
DSM_NOTSAVING,
DSM_WILLAUTOSAVE,
DSM_TITLEENTRY,
DSM_WILLSAVE,
DSM_SAVED
} savemode;
};
extern struct demovars_s demo;
typedef enum {
MD_NOTLOADED,
MD_LOADED,
MD_SUBDIR,
MD_OUTDATED,
MD_INVALID
} menudemotype_e;
typedef struct menudemo_s {
char filepath[256];
menudemotype_e type;
char title[65]; // Null-terminated for string prints
char date[11]; // date when replay was recorded
char version[12]; // combined version and subversion
UINT16 map;
UINT8 addonstatus; // What do we need to do addon-wise to play this demo?
UINT8 gametype;
UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;
struct {
UINT8 ranking;
char name[17];
UINT8 skin, color;
UINT32 timeorscore;
} standings[MAXPLAYERS];
} menudemo_t;
extern mobj_t *metalplayback;
// Only called by startup code.
void G_RecordDemo(const char *name);
void G_RecordMetal(void);
void G_BeginRecording(void);
void G_BeginMetal(void);
// Only called by shutdown code.
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val);
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
UINT8 G_CmpDemoTime(char *oldname, char *newname);
void G_LoadDemoInfo(menudemo_t *pdemo);
void G_LoadDemoTitle(menudemo_t *pdemo); // For use in replay search feature
void G_DeferedPlayDemo(const char *demo);
typedef enum
{
GHC_NORMAL = 0,
GHC_SUPER,
GHC_FIREFLOWER,
GHC_INVINCIBLE
} ghostcolor_t;
extern UINT8 demo_extradata[MAXPLAYERS];
extern UINT8 demo_writerng;
#define DXD_RESPAWN 0x01 // "respawn" command in console
#define DXD_SKIN 0x02 // skin changed
#define DXD_NAME 0x04 // name changed
#define DXD_COLOR 0x08 // color changed
#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game
#define DXD_PST_PLAYING 0x01
#define DXD_PST_SPECTATING 0x02
#define DXD_PST_LEFT 0x03
// Record/playback tics
void G_ReadDemoExtraData(void);
void G_WriteDemoExtraData(void);
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_GhostAddThok(INT32 playernum);
void G_GhostAddSpin(INT32 playernum);
void G_GhostAddRev(INT32 playernum);
void G_GhostAddColor(INT32 playernum, ghostcolor_t color);
void G_GhostAddFlip(INT32 playernum);
void G_GhostAddScale(INT32 playernum, fixed_t scale);
void G_GhostAddHit(INT32 playernum, mobj_t *victim);
void G_WriteAllGhostTics(void);
void G_WriteGhostTic(mobj_t *ghost, INT32 playernum);
void G_ConsAllGhostTics(void);
void G_ConsGhostTic(INT32 playernum);
void G_GhostTicker(void);
void G_InitDemoRewind(void);
void G_StoreRewindInfo(void);
void G_PreviewRewind(tic_t previewtime);
void G_ConfirmRewind(tic_t rewindtime);
void G_ReadMetalTic(mobj_t *metal);
void G_WriteMetalTic(mobj_t *metal);
void G_SaveMetal(UINT8 **buffer);
void G_LoadMetal(UINT8 **buffer);
// Your naming conventions are stupid and useless.
// There is no conflict here.
typedef struct demoghost {
UINT8 checksum[16];
UINT8 *buffer, *p, color;
UINT16 version;
mobj_t oldmo, *mo;
struct demoghost *next;
} demoghost;
extern demoghost *ghosts;
// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's.
#define DFILE_ERROR_NOTLOADED 0x01 // Files are not loaded, but can be without a restart.
#define DFILE_ERROR_OUTOFORDER 0x02 // Files are loaded, but out of order.
#define DFILE_ERROR_INCOMPLETEOUTOFORDER 0x03 // Some files are loaded out of order, but others are not.
#define DFILE_ERROR_CANNOTLOAD 0x04 // Files are missing and cannot be loaded.
#define DFILE_ERROR_EXTRAFILES 0x05 // Extra files outside of the replay's file list are loaded.
void G_ResetDemoRecording(void);
void G_DoPlayDemo(char *defdemoname);
void G_TimeDemo(const char *name);
void G_AddGhost(char *defdemoname);
void G_UpdateStaffGhostName(lumpnum_t l);
void G_DoPlayMetal(void);
void G_DoneLevelLoad(void);
void G_StopMetalDemo(void);
ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void);
void G_StopDemo(void);
boolean G_CheckDemoStatus(void);
void G_SaveDemo(void);
boolean G_DemoTitleResponder(event_t *ev);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __G_DEMO__
-4008
View File
File diff suppressed because it is too large. Load diff
+1 -164
View File
@@ -21,6 +21,7 @@ extern "C" {
#include "doomdef.h"
#include "doomstat.h"
#include "d_event.h"
#include "g_demo.h"
#include "p_saveg.h"
#include "m_textinput.h"
@@ -38,75 +39,6 @@ extern INT32 player_name_changes[MAXPLAYERS];
extern player_t players[MAXPLAYERS];
extern boolean playeringame[MAXPLAYERS];
extern savebuffer_t demobuf;
// ======================================
// DEMO playback/recording related stuff.
// ======================================
// demoplaying back and demo recording
extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_maxdemosize, cv_demochangemap;
extern consvar_t cv_demodateformat;
// Publicly-accessible demo vars
struct demovars_s {
char titlename[65];
textinput_t titlenameinput;
boolean recording, playback, timing;
UINT16 version; // Current file format of the demo being played
boolean title; // Title Screen demo can be cancelled by any key
boolean rewinding; // Rewind in progress
boolean loadfiles, ignorefiles; // Demo file loading options
boolean fromtitle; // SRB2Kart: Don't stop the music
boolean inreplayhut; // Go back to replayhut after demos
boolean quitafterplaying; // quit after playing a demo from cmdline
boolean deferstart; // don't start playing demo right away
tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going
enum {
DSM_NOTSAVING,
DSM_WILLAUTOSAVE,
DSM_TITLEENTRY,
DSM_WILLSAVE,
DSM_SAVED
} savemode;
};
extern struct demovars_s demo;
typedef enum {
MD_NOTLOADED,
MD_LOADED,
MD_SUBDIR,
MD_OUTDATED,
MD_INVALID
} menudemotype_e;
typedef struct menudemo_s {
char filepath[256];
menudemotype_e type;
char title[65]; // Null-terminated for string prints
char date[11]; // date when replay was recorded
char version[12]; // combined version and subversion
UINT16 map;
UINT8 addonstatus; // What do we need to do addon-wise to play this demo?
UINT8 gametype;
UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;
struct {
UINT8 ranking;
char name[17];
UINT8 skin, color;
UINT32 timeorscore;
} standings[MAXPLAYERS];
} menudemo_t;
extern mobj_t *metalplayback;
// gametic at level start
extern tic_t levelstarttic;
@@ -290,10 +222,6 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost);
void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar,
UINT8 ssplayers, boolean FLS);
void G_LoadDemoInfo(menudemo_t *pdemo);
void G_LoadDemoTitle(menudemo_t *pdemo); // For use in replay search feature
void G_DeferedPlayDemo(const char *demo);
// Can be called by the startup code or M_Responder, calls P_SetupLevel.
void G_LoadGame(UINT32 slot, INT16 mapoverride);
@@ -301,97 +229,6 @@ void G_SaveGameData(boolean force);
void G_SaveGame(UINT32 slot);
// Only called by startup code.
void G_RecordDemo(const char *name);
void G_RecordMetal(void);
void G_BeginRecording(void);
void G_BeginMetal(void);
// Only called by shutdown code.
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val);
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
UINT8 G_CmpDemoTime(char *oldname, char *newname);
typedef enum
{
GHC_NORMAL = 0,
GHC_SUPER,
GHC_FIREFLOWER,
GHC_INVINCIBLE
} ghostcolor_t;
extern UINT8 demo_extradata[MAXPLAYERS];
extern UINT8 demo_writerng;
#define DXD_RESPAWN 0x01 // "respawn" command in console
#define DXD_SKIN 0x02 // skin changed
#define DXD_NAME 0x04 // name changed
#define DXD_COLOR 0x08 // color changed
#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game
#define DXD_PST_PLAYING 0x01
#define DXD_PST_SPECTATING 0x02
#define DXD_PST_LEFT 0x03
// Record/playback tics
void G_ReadDemoExtraData(void);
void G_WriteDemoExtraData(void);
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_GhostAddThok(INT32 playernum);
void G_GhostAddSpin(INT32 playernum);
void G_GhostAddRev(INT32 playernum);
void G_GhostAddColor(INT32 playernum, ghostcolor_t color);
void G_GhostAddFlip(INT32 playernum);
void G_GhostAddScale(INT32 playernum, fixed_t scale);
void G_GhostAddHit(INT32 playernum, mobj_t *victim);
void G_WriteAllGhostTics(void);
void G_WriteGhostTic(mobj_t *ghost, INT32 playernum);
void G_ConsAllGhostTics(void);
void G_ConsGhostTic(INT32 playernum);
void G_GhostTicker(void);
void G_InitDemoRewind(void);
void G_StoreRewindInfo(void);
void G_PreviewRewind(tic_t previewtime);
void G_ConfirmRewind(tic_t rewindtime);
void G_ReadMetalTic(mobj_t *metal);
void G_WriteMetalTic(mobj_t *metal);
void G_SaveMetal(UINT8 **buffer);
void G_LoadMetal(UINT8 **buffer);
// Your naming conventions are stupid and useless.
// There is no conflict here.
typedef struct demoghost {
UINT8 checksum[16];
UINT8 *buffer, *p, color;
UINT16 version;
mobj_t oldmo, *mo;
struct demoghost *next;
} demoghost;
extern demoghost *ghosts;
// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's.
#define DFILE_ERROR_NOTLOADED 0x01 // Files are not loaded, but can be without a restart.
#define DFILE_ERROR_OUTOFORDER 0x02 // Files are loaded, but out of order.
#define DFILE_ERROR_INCOMPLETEOUTOFORDER 0x03 // Some files are loaded out of order, but others are not.
#define DFILE_ERROR_CANNOTLOAD 0x04 // Files are missing and cannot be loaded.
#define DFILE_ERROR_EXTRAFILES 0x05 // Extra files outside of the replay's file list are loaded.
void G_ResetDemoRecording(void);
void G_DoPlayDemo(char *defdemoname);
void G_TimeDemo(const char *name);
void G_AddGhost(char *defdemoname);
void G_UpdateStaffGhostName(lumpnum_t l);
void G_DoPlayMetal(void);
void G_DoneLevelLoad(void);
void G_StopMetalDemo(void);
ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void);
void G_StopDemo(void);
boolean G_CheckDemoStatus(void);
void G_SaveDemo(void);
boolean G_DemoTitleResponder(event_t *ev);
#define G_GametypeHasTeams() (G_IsGameType(GT_TEAMMATCH) || G_IsGameType(GT_CTF))
#define G_BattleGametype() (G_IsGameType(GT_MATCH))
#define G_RaceGametype() (G_IsGameType(GT_RACE))
+1 -1
View File
@@ -1,6 +1,6 @@
hw_bsp.c
hw_draw.c
hw_main.c
hw_main.cpp
hw_clip.c
hw_md2.c
hw_cache.c
+52 -51
View File
@@ -25,22 +25,23 @@ GLMipmap_t *current_texture = NULL;
boolean currently_batching = false;
FOutVector* finalVertexArray = NULL;// contains subset of sorted vertices and texture coordinates to be sent to gpu
FOutVector* finalVertexArray = NULL;// contains subset of sorted vertices and texture coordinates to be sent to gpu
UINT32* finalVertexIndexArray = NULL;// contains indexes for glDrawElements, taking into account fan->triangles conversion
// NOTE have this alloced as 3x finalVertexArray size
int finalVertexArrayAllocSize = 65536;
//GLubyte* colorArray = NULL;// contains color data to be sent to gpu, if needed
//int colorArrayAllocSize = 65536;
// not gonna use this for now, just sort by color and change state when it changes
// later maybe when using vertex attributes if it's needed
PolygonArrayEntry* polygonArray = NULL;// contains the polygon data from DrawPolygon, waiting to be processed
int polygonArraySize = 0;
PolygonArrayEntry **polygonArraySorted = NULL;// contains sorted pointers to polygonArray
PolygonArrayEntry* polygonArray = NULL ;// contains the polygon data from DrawPolygon, waiting to be processed
PolygonArrayEntry **polygonArraySorted = NULL; // contains sorted pointers to polygonArray
int polygonArraySize = 0;
int polygonArrayAllocSize = 65536;
FOutVector* unsortedVertexArray = NULL;// contains unsorted vertices and texture coordinates from DrawPolygon
int unsortedVertexArraySize = 0;
FOutVector* unsortedVertexArray = NULL; // contains unsorted vertices and texture coordinates from DrawPolygon
int unsortedVertexArraySize = 0;
int unsortedVertexArrayAllocSize = 65536;
// Enables batching mode. HWR_ProcessPolygon will collect polygons instead of passing them directly to the rendering backend.
@@ -55,11 +56,11 @@ void HWR_StartBatching(void)
// init arrays if that has not been done yet
if (!finalVertexArray)
{
finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector));
finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector));
finalVertexIndexArray = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32));
polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry));
polygonArraySorted = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry *));
unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector));
polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry));
polygonArraySorted = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry *));
unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector));
}
currently_batching = true;
@@ -131,13 +132,13 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt
static int comparePolygons(const void *p1, const void *p2)
{
const PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1;
const PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2;
int diff;
INT64 diff64;
const PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1;
const PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2;
int shader1 = (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) ? -1 : poly1->shader;
int shader2 = (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) ? -1 : poly2->shader;
const int shader1 = (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) ? -1 : poly1->shader;
const int shader2 = (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) ? -1 : poly2->shader;
// skywalls and horizon lines must retain their order for horizon lines to work
if (shader1 == -1 && shader2 == -1)
@@ -173,13 +174,13 @@ static int comparePolygons(const void *p1, const void *p2)
static int comparePolygonsNoShaders(const void *p1, const void *p2)
{
PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1;
PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2;
int diff;
INT64 diff64;
const PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1;
const PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2;
GLMipmap_t *texture1 = (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) ? NULL : poly1->texture;
GLMipmap_t *texture2 = (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) ? NULL : poly2->texture;
const GLMipmap_t *texture1 = (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) ? NULL : poly1->texture;
const GLMipmap_t *texture2 = (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) ? NULL : poly2->texture;
// skywalls and horizon lines must retain their order for horizon lines to work
if (!texture1 && !texture2)
@@ -203,17 +204,16 @@ static int comparePolygonsNoShaders(const void *p1, const void *p2)
// the rendering backend to draw them.
void HWR_RenderBatches(void)
{
int finalVertexWritePos = 0;// position in finalVertexArray
int finalIndexWritePos = 0;// position in finalVertexIndexArray
int polygonReadPos = 0;// position in polygonArraySorted
int finalVertexWritePos = 0; // position in finalVertexArray
int finalIndexWritePos = 0; // position in finalVertexIndexArray
int polygonReadPos = 0; // position in polygonArraySorted
int currentShader;
int nextShader = 0;
GLMipmap_t *currentTexture = NULL;
GLMipmap_t *nextTexture = NULL;
FBITFIELD currentPolyFlags = 0;
FBITFIELD nextPolyFlags = 0;
GLMipmap_t *currentTexture = NULL;
GLMipmap_t *nextTexture = NULL;
FBITFIELD currentPolyFlags = 0;
FBITFIELD nextPolyFlags = 0;
FSurfaceInfo currentSurfaceInfo;
FSurfaceInfo nextSurfaceInfo;
@@ -224,8 +224,8 @@ void HWR_RenderBatches(void)
I_Error("HWR_RenderBatches called without starting batching");
}
nextSurfaceInfo.LightInfo.fade_end = 0;
nextSurfaceInfo.LightInfo.fade_start = 0;
nextSurfaceInfo.LightInfo.fade_end = 0;
nextSurfaceInfo.LightInfo.fade_start = 0;
nextSurfaceInfo.LightInfo.light_level = 0;
nextSurfaceInfo.LightInfo.directional = false;
@@ -243,7 +243,7 @@ void HWR_RenderBatches(void)
ps_hw_numpolys.value.i = polygonArraySize;
ps_hw_numcalls.value.i = ps_hw_numverts.value.i = 0;
ps_hw_numshaders.value.i = ps_hw_numtextures.value.i
= ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1;
= ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1;
// init polygonArraySorted
for (i = 0; i < polygonArraySize; i++)
@@ -253,10 +253,7 @@ void HWR_RenderBatches(void)
// sort polygons
PS_START_TIMING(ps_hw_batchsorttime);
if (cv_glshaders.value && gl_shadersavailable)
qs22j(polygonArraySorted, polygonArraySize, sizeof(PolygonArrayEntry *), comparePolygons);
else
qs22j(polygonArraySorted, polygonArraySize, sizeof(PolygonArrayEntry *), comparePolygonsNoShaders);
qs22j(polygonArraySorted, polygonArraySize, sizeof(PolygonArrayEntry *), (HWR_UseShader() ? comparePolygons : comparePolygonsNoShaders));
PS_STOP_TIMING(ps_hw_batchsorttime);
// sort order
@@ -268,16 +265,16 @@ void HWR_RenderBatches(void)
PS_START_TIMING(ps_hw_batchdrawtime);
currentShader = polygonArraySorted[0]->shader;
currentTexture = polygonArraySorted[0]->texture;
currentPolyFlags = polygonArraySorted[0]->polyFlags;
currentShader = polygonArraySorted[0]->shader;
currentTexture = polygonArraySorted[0]->texture;
currentPolyFlags = polygonArraySorted[0]->polyFlags;
currentSurfaceInfo = polygonArraySorted[0]->surf;
// For now, will sort and track the colors. Vertex attributes could be used instead of uniforms
// and a color array could replace the color calls.
// set state for first batch
if (cv_glshaders.value && gl_shadersavailable)
if (HWR_UseShader())
{
GL_SetShader(currentShader);
}
@@ -302,16 +299,17 @@ void HWR_RenderBatches(void)
// steps:
// write vertices
// check for changes or end, otherwise go back to writing
// changes will affect the next vars and the change bools
// end could set flag for stopping
// changes will affect the next vars and the change bools
// end could set flag for stopping
// execute draw call
// could check ending flag here
// change states according to next vars and change bools, updating the current vars and reseting the bools
// reset write pos
// repeat loop
PolygonArrayEntry *entry = polygonArraySorted[polygonReadPos++];
int numVerts = entry->numVerts;
const PolygonArrayEntry *entry = polygonArraySorted[polygonReadPos++];
const int numVerts = entry->numVerts;
// before writing, check if there is enough room
// using 'while' instead of 'if' here makes sure that there will *always* be enough room.
// probably never will this loop run more than once though
@@ -323,13 +321,15 @@ void HWR_RenderBatches(void)
// going from fans to triangles increases vertex count to 3x
finalVertexIndexArray = realloc(finalVertexIndexArray, finalVertexArrayAllocSize * 3 * sizeof(UINT32));
}
// write the vertices of the polygon
memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[entry->vertsIndex],
numVerts * sizeof(FOutVector));
memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[entry->vertsIndex], numVerts * sizeof(FOutVector));
// write the indexes, pointing to the fan vertexes but in triangles format
firstIndex = finalVertexWritePos;
lastIndex = finalVertexWritePos + numVerts;
finalVertexWritePos += 2;
while (finalVertexWritePos < lastIndex)
{
finalVertexIndexArray[finalIndexWritePos++] = firstIndex;
@@ -344,16 +344,16 @@ void HWR_RenderBatches(void)
else
{
// check if a state change is required, set the change bools and next vars
PolygonArrayEntry *nextEntry = polygonArraySorted[polygonReadPos];
nextShader = nextEntry->shader;
nextTexture = nextEntry->texture;
nextPolyFlags = nextEntry->polyFlags;
const PolygonArrayEntry *nextEntry = polygonArraySorted[polygonReadPos];
nextShader = nextEntry->shader;
nextTexture = nextEntry->texture;
nextPolyFlags = nextEntry->polyFlags;
nextSurfaceInfo = nextEntry->surf;
if (nextPolyFlags & PF_NoTexture)
nextTexture = 0;
if (currentShader != nextShader && cv_glshaders.value && gl_shadersavailable)
if (currentShader != nextShader && HWR_UseShader())
{
changeState = true;
changeShader = true;
@@ -371,7 +371,7 @@ void HWR_RenderBatches(void)
changePolyFlags = true;
}
if (cv_glshaders.value && gl_shadersavailable)
if (HWR_UseShader())
{
if (currentSurfaceInfo.PolyColor.rgba != nextSurfaceInfo.PolyColor.rgba ||
currentSurfaceInfo.TintColor.rgba != nextSurfaceInfo.TintColor.rgba ||
@@ -404,7 +404,7 @@ void HWR_RenderBatches(void)
ps_hw_numverts.value.i += finalIndexWritePos;
// reset write positions
finalVertexWritePos = 0;
finalIndexWritePos = 0;
finalIndexWritePos = 0;
}
else
continue;
@@ -450,9 +450,10 @@ void HWR_RenderBatches(void)
ps_hw_numcolors.value.i++;
}
// and that should be it?
}
// and that should be it?
}
// reset the arrays (set sizes to 0)
polygonArraySize = 0;
unsortedVertexArraySize = 0;
+8
View File
@@ -13,6 +13,10 @@
#ifndef __HWR_BATCHING_H__
#define __HWR_BATCHING_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "hw_defs.h"
#include "hw_data.h"
#include "hw_gl.h"
@@ -36,4 +40,8 @@ void HWR_SetCurrentTexture(GLMipmap_t *texture);
void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags, int shader, boolean horizonSpecial);
void HWR_RenderBatches(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+4 -3
View File
@@ -371,12 +371,13 @@ static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly)
line_t *line = lseg->linedef;
// portal check
if (!gl_maphasportals && line->special == 40 && lseg->side == 0)
if (!gl_maphasportals && line->special == PORTALSPECIAL && lseg->side == 0)
{
// Find the other side!
INT32 line2 = P_FindSpecialLineFromTag(40, line->tag, -1);
INT32 line2 = P_FindSpecialLineFromTag(PORTALSPECIAL, line->tag, -1);
if (line == &lines[line2])
line2 = P_FindSpecialLineFromTag(40, line->tag, line2);
line2 = P_FindSpecialLineFromTag(PORTALSPECIAL, line->tag, line2);
if (line2 >= 0) // found it!
gl_maphasportals = 1;
}
+8
View File
@@ -7,6 +7,10 @@
*
*/
#ifdef __cplusplus
extern "C" {
#endif
// OpenGL BSP clipping
#include "../doomdef.h"
#include "../tables.h"
@@ -22,3 +26,7 @@ angle_t gld_FrustumAngle(angle_t tiltangle);
void gld_FrustumSetup(void);
boolean gld_SphereInFrustum(float x, float y, float z, float radius);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
+8
View File
@@ -13,6 +13,10 @@
#ifndef __HWR_GL_H__
#define __HWR_GL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "../screen.h"
#include "hw_data.h"
@@ -76,4 +80,8 @@ UINT32 GL_CreateLightTable(RGBA_t *hw_lighttable);
void GL_ClearLightTables(void);
void GL_SetScreenPalette(RGBA_t *palette);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __HWR_GL_H__
+8
View File
@@ -14,6 +14,10 @@
#ifndef _HWR_GLOB_H_
#define _HWR_GLOB_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "hw_defs.h"
#include "../m_misc.h"
#include "../r_defs.h"
@@ -109,4 +113,8 @@ const char *HWR_GetShaderName(INT32 shader);
extern customshaderxlat_t shaderxlat[];
#ifdef __cplusplus
} // extern "C"
#endif
#endif //_HW_GLOB_
File diff suppressed because it is too large. Load diff
+5 -4
View File
@@ -20,6 +20,10 @@
#ifndef __HWR_MAIN_H__
#define __HWR_MAIN_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "hw_gl.h"
#include "hw_glob.h"
#include "hw_data.h"
@@ -34,10 +38,6 @@
#define GLENCORE
#ifdef __cplusplus
extern "C" {
#endif
// Startup & Shutdown the hardware mode renderer
void HWR_Startup(void);
void HWR_Shutdown(void);
@@ -110,6 +110,7 @@ void HWR_AddCommands(void);
void HWR_RenderPlayerView(void);
void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, player_t *player, int stencil_level, boolean allow_portals);
void HWR_RenderPortalViewpoint(gl_portal_t *rootportal, const float fpov, player_t *player, int stencil_level, boolean allow_portals);
void HWR_ClearSkyDome(void);
void HWR_BuildSkyDome(void);
+1 -1
View File
@@ -1187,7 +1187,7 @@ void HWR_DrawMD2(gl_vissprite_t *spr)
spriteinfo_t *sprinfo;
interpmobjstate_t interp;
if (R_UsingFrameInterpolation() && !paused && (!cv_maxinterpdist.value || R_QuickCamDist(spr->mobj->x, spr->mobj->y) < cv_maxinterpdist.value))
if (R_UsingFrameInterpolation() && !paused && R_CheckInterpDist(spr->mobj))
{
R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp);
}
+1 -1
View File
@@ -169,7 +169,7 @@ void HWR_RenderPortal(gl_portal_t* portal, gl_portal_t* rootportal, const float
// go to portal frame lmao
HWR_PortalFrame(portal);
// call HWR_RenderViewpoint
HWR_RenderViewpoint(portal, fpov, player, stencil_level + 1, true);
HWR_RenderPortalViewpoint(portal, fpov, player, stencil_level + 1, true);
// return to current frame
if (rootportal)
HWR_PortalFrame(rootportal);
+8
View File
@@ -14,6 +14,10 @@
#ifndef __HW_PORTAL__
#define __HW_PORTAL__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HWRENDER
#include "../doomstat.h"
@@ -77,5 +81,9 @@ void HWR_FreePortalList(gl_portallist_t portallist);
boolean HWR_PortalCheckPointSide(fixed_t x, fixed_t y);
boolean HWR_PortalCheckBBox(const fixed_t *bspcoord);
#endif
#ifdef __cplusplus
}// extern "C"
#endif
#endif
+8
View File
@@ -20,6 +20,10 @@
#ifndef _R_OPENGL_H_
#define _R_OPENGL_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_SDL
#define _MATH_DEFINES_DEFINED
@@ -143,4 +147,8 @@ typedef enum
GLF_NOTEXENV = 0x02,
} oglflags_t;
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+101 -18
View File
@@ -17,6 +17,7 @@
#include "m_menu.h" // gametype_cons_t
#include "m_cond.h" // emblems
#include "m_emotes.h"
#include "d_clisrv.h"
@@ -49,6 +50,7 @@
#include "s_sound.h" // song credits
#include "k_kart.h"
#include "k_hud.h"
#include "m_textinput.h"
@@ -93,6 +95,9 @@ static textinput_t w_chat;
static boolean headsupactive = false;
boolean hu_showscores; // draw rankings
static char hu_tick;
static tic_t hu_emoteanim = 0;
#define MAXEMOTESUGGESTIONS 8
static emote_t *emote_suggestions[MAXEMOTESUGGESTIONS] = {0};
static huddrawlist_h luahuddrawlist_scores;
@@ -259,8 +264,6 @@ INT32 HU_FallBackFrSpecialLetter(INT32 key)
}
}
static char cechotext[1024];
static tic_t cechotimer = 0;
static tic_t cechoduration = 5*TICRATE;
@@ -1104,6 +1107,7 @@ void HU_Ticker(void)
return;
hu_tick++;
hu_emoteanim++;
hu_tick &= 7; // currently only to blink chat input cursor
if (PLAYER1INPUTDOWN(gc_scores))
@@ -1368,7 +1372,7 @@ boolean HU_Responder(event_t *ev)
&& ev->data1 != gamecontrol[0][gc_talkkey][1]))
return false;
M_TextInputHandle(&w_chat, c);
M_TextInputHandleEmotes(&w_chat, c, emote_suggestions, MAXEMOTESUGGESTIONS);
if (c == KEY_ENTER)
{
@@ -1408,6 +1412,8 @@ boolean HU_Responder(event_t *ev)
#ifndef NONET
#define HU_DrawEmote(x, y, emote, flags) M_DrawEmote((x), (y), (emote), hu_emoteanim, (flags))
// Precompile a wordwrapped string to any given width.
// This is a muuuch better method than V_WORDWRAP.
// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
@@ -1419,6 +1425,8 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
size_t slen;
char *newstring = Z_StrDup(string);
INT32 spacewidth = (vid.width < 640) ? 8 : 4, charwidth = (vid.width < 640) ? 8 : 4;
emote_t *emote = NULL;
int emotelen = 0;
slen = strlen(string);
x = 0;
@@ -1440,7 +1448,12 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
c = toupper(c);
c -= HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
if ((emote = M_VerifyEmote(string+i, &emotelen)))
{
chw = EMOTEWIDTH;
i += emotelen-1; // Will be incremented on next loop iteration, hence -1
}
else if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
{
chw = spacewidth;
lastusablespace = i;
@@ -1462,7 +1475,6 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
return newstring;
}
// 30/7/18: chaty is now the distance at which the lowest point of the chat will be drawn if that makes any sense.
INT16 chatx = 13, chaty = 169; // let's use this as our coordinates, shh
@@ -1495,6 +1507,8 @@ static void HU_drawMiniChat(void)
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]);
size_t j = 0;
INT32 linescount = 0;
emote_t *emote = NULL;
int emotelen = 0;
while(msg[j]) // iterate through msg
{
@@ -1519,6 +1533,11 @@ static void HU_drawMiniChat(void)
++j;
}
else if ((emote = M_VerifyEmote(msg+j, &emotelen)))
{
dx += EMOTEWIDTH - charwidth;
j += emotelen;
}
else
{
j++;
@@ -1564,6 +1583,8 @@ static void HU_drawMiniChat(void)
size_t j = 0;
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL;
emote_t *emote = NULL;
int emotelen = 0;
while(msg[j]) // iterate through msg
{
@@ -1590,6 +1611,16 @@ static void HU_drawMiniChat(void)
++j;
}
else if ((emote = M_VerifyEmote(msg+j, &emotelen)))
{
if (cv_chatbacktint.value) // on request of wolfy
V_DrawFillConsoleMap(x + dx + 2, y+dy, EMOTEWIDTH, charheight, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
HU_DrawEmote(x+dx+2, y+dy, emote, V_SNAPTOBOTTOM|V_SNAPTOLEFT|transflag);
dx += EMOTEWIDTH - charwidth;
j += emotelen;
}
else
{
if (cv_chatbacktint.value) // on request of wolfy
@@ -1667,6 +1698,9 @@ static void HU_drawChatLog(INT32 offset)
INT32 j = 0;
char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it.
UINT8 *colormap = NULL;
emote_t *emote = NULL;
int emotelen = 0;
while(msg[j]) // iterate through msg
{
if (msg[j] < HU_FONTSTART) // don't draw
@@ -1688,6 +1722,15 @@ static void HU_drawChatLog(INT32 offset)
++j;
}
else if ((emote = M_VerifyEmote(msg+j, &emotelen)))
{
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
{
HU_DrawEmote(x+dx+2, y+dy, emote, V_SNAPTOBOTTOM|V_SNAPTOLEFT);
dx += EMOTEWIDTH - charwidth;
}
j += emotelen;
}
else
{
if ((y+dy+2 >= chat_topy) && (y+dy < (chat_bottomy)))
@@ -1813,7 +1856,7 @@ static void HU_DrawChat(void)
typelines = 1;
if ((w_chat.cursor == 0 || w_chat.length == 0) && hu_tick < 4)
V_DrawChatCharacter(chatx+2+c+charwidth*w_chat.cursor, y+1, '_'|V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL);
V_DrawChatCharacter(chatx+2+c, y+1, '_'|V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL);
if (w_chat.select != w_chat.cursor)
{
@@ -1824,30 +1867,40 @@ static void HU_DrawChat(void)
while (w_chat_buf[i])
{
boolean skippedline = false;
if (w_chat.cursor == (i+1))
emote_t *emote = NULL;
int emotelen = 0;
int drawwidth = charwidth; // if we've drawn emote, selection needs to account for that
if ((emote = M_VerifyEmote(w_chat_buf+i, &emotelen)))
{
HU_DrawEmote(chatx + c + 2, y-1, emote, V_SNAPTOBOTTOM|V_SNAPTOLEFT|t);
c += EMOTEWIDTH - charwidth;
i += emotelen-1;
drawwidth = EMOTEWIDTH;
}
else if (w_chat_buf[i] >= HU_FONTSTART) //Hurdler: isn't it better like that?
V_DrawChatCharacter(chatx + c + 2, y, w_chat_buf[i] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, !cv_allcaps.value, NULL);
// Draw selection
if (i >= select_start && i < select_end)
V_DrawFill(chatx + c + 2 - (drawwidth-charwidth), y-1, drawwidth, charheight, 103|V_TRANSLUCENT|V_SNAPTOBOTTOM|V_SNAPTOLEFT|t);
++i;
if (w_chat.cursor == i)
{
INT32 cursorx = (c+charwidth < boxw-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down.
INT32 cursory = (cursorx != chatx+1) ? (y) : (y+charheight);
if (hu_tick < 4)
V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL);
if (cursorx == chatx+1 && saylen == i) // a weirdo hack
if (cursorx == chatx+1 && saylen == i-1) // a weirdo hack
{
typelines += 1;
skippedline = true;
}
}
//Hurdler: isn't it better like that?
if (w_chat_buf[i] >= HU_FONTSTART)
V_DrawChatCharacter(chatx + c + 2, y, w_chat_buf[i] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, !cv_allcaps.value, NULL);
// Draw selection
if (i >= select_start && i < select_end)
V_DrawFill(chatx + c + 2, y-1, charwidth, charheight, 103|V_TRANSLUCENT|V_SNAPTOBOTTOM|V_SNAPTOLEFT|t);
++i;
c += charwidth;
if (c > boxw-(charwidth*2) && !skippedline)
{
@@ -1857,6 +1910,36 @@ static void HU_DrawChat(void)
}
}
if (emote_suggestions[0])
{
// A bit of copy-paste from /pm code :p
INT32 suggesty = chaty - charheight - 1;
size_t longest_suggestion_length = 0;
for (i = 0; i < MAXEMOTESUGGESTIONS && emote_suggestions[i]; ++i)
{
longest_suggestion_length = max(longest_suggestion_length, strlen(emote_suggestions[i]->name));
}
#ifdef NETSPLITSCREEN
if (splitscreen)
{
suggesty -= BASEVIDHEIGHT/2;
if (splitscreen > 1)
suggesty += 16;
}
else
#endif
suggesty -= (cv_kartspeedometer.value ? 16 : 0);
for (i = 0; i < MAXEMOTESUGGESTIONS && emote_suggestions[i]; ++i)
{
V_DrawFillConsoleMap(chatx + boxw + 2, suggesty - (7*i), (longest_suggestion_length+2)*4 + EMOTEWIDTH, 6, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT);
V_DrawSmallString(chatx + boxw + 4 + EMOTEWIDTH, suggesty - (7*i), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, va(":%s:", emote_suggestions[i]->name));
HU_DrawEmote(chatx + boxw + 2, suggesty - i*7, emote_suggestions[i], V_SNAPTOBOTTOM|V_SNAPTOLEFT);
}
}
// handle /pm list. It's messy, horrible and I don't care.
if (strnicmp(w_chat_buf, "/pm", 3) == 0 && vid.width >= 400 && !teamtalk) // 320x200 unsupported kthxbai
{
+4788
View File
File diff suppressed because it is too large. Load diff
+81
View File
@@ -0,0 +1,81 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_hud.h
/// \brief HUD drawing functions exclusive to Kart
#ifndef __K_HUD__
#define __K_HUD__
#ifdef __cplusplus
extern "C" {
#endif
#include "doomdef.h"
#include "d_player.h" // Need for player_t
#include "command.h"
#include "r_defs.h"
UINT8 K_GetHudColor(void);
boolean K_UseColorHud(void);
boolean K_UseHighResPortraits(void);
patch_t *K_GetFacePrefix(player_t *player, INT32 skinnum);
void K_RegisterKartHudStuff(void);
extern consvar_t cv_colorizedhud,
cv_colorizeditembox,
cv_colorizedhudcolor;
extern consvar_t cv_darkitembox;
extern consvar_t cv_biglaps;
extern consvar_t cv_highresportrait;
extern consvar_t cv_stat_xoffset, cv_stat_yoffset;
extern consvar_t cv_showstats;
extern consvar_t cv_fancyroulette;
extern consvar_t cv_showlaptimes;
extern consvar_t cv_battlespeedo;
extern consvar_t cv_multiitemicon;
extern consvar_t cv_huditemamount;
#define NUMSPEEDOSTUFF 8
extern CV_PossibleValue_t speedo_cons_t[NUMSPEEDOSTUFF];
#define NUMDGAUGESTUFF 6
extern CV_PossibleValue_t driftgaugestyle_cons_t[NUMDGAUGESTUFF];
#define NUMINPUTDISPLAYSTUFF 5
extern CV_PossibleValue_t inputdisplay_cons_t[NUMINPUTDISPLAYSTUFF];
#define NUMMINIMAPDOTSTUFF 5
extern CV_PossibleValue_t minimapdot_cons_t[NUMMINIMAPDOTSTUFF];
const char *K_GetItemPatch(UINT8 item, boolean tiny);
INT32 K_calcSplitFlags(INT32 snapflags);
void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(UINT32 flashtime);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
typedef struct
{
INT32 x;
INT32 y;
INT32 flags;
} drawinfo_t;
patch_t *K_getItemBoxPatch(boolean small, boolean dark);
patch_t *K_getItemMulPatch(boolean small);
void K_getItemBoxDrawinfo(drawinfo_t *out);
INT32 K_getMinimapTrans(void);
void K_getLapsDrawinfo(drawinfo_t *out);
void K_getMinimapDrawinfo(drawinfo_t *out);
#ifdef __cplusplus
} // extern "C"
#endif
// =========================================================================
#endif // __K_HUD__
+33 -4758
View File
File diff suppressed because it is too large. Load diff
+2 -45
View File
@@ -22,9 +22,6 @@ 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, boolean local);
UINT8 K_GetKartColorByName(const char *name);
UINT8 K_GetHudColor(void);
boolean K_UseColorHud(void);
boolean K_UseHighResPortraits(void);
void K_RegisterServerKartStuff(void);
void K_RegisterClientKartStuff(void);
@@ -33,30 +30,11 @@ extern consvar_t cv_coloredspeedlines, cv_coloredsneakertrail;
extern consvar_t cv_bananajitter;
extern consvar_t cv_bananthrowroll;
extern consvar_t cv_airsparks;
extern consvar_t cv_colorizedhud, cv_colorizeditembox, cv_colorizedhudcolor;
extern consvar_t cv_darkitembox;
extern consvar_t cv_biglaps;
extern consvar_t cv_highresportrait;
extern consvar_t cv_stat_xoffset, cv_stat_yoffset;
extern consvar_t cv_showstats;
extern consvar_t cv_fancyroulette;
extern consvar_t cv_showlaptimes;
extern consvar_t cv_battlespeedo;
extern consvar_t cv_multiitemicon;
extern consvar_t cv_huditemamount;
#define NUMSPEEDOSTUFF 8
extern CV_PossibleValue_t speedo_cons_t[NUMSPEEDOSTUFF];
#define NUMDGAUGESTUFF 6
extern CV_PossibleValue_t driftgaugestyle_cons_t[NUMDGAUGESTUFF];
#define NUMINPUTDISPLAYSTUFF 5
extern CV_PossibleValue_t inputdisplay_cons_t[NUMINPUTDISPLAYSTUFF];
#define NUMMINIMAPDOTSTUFF 5
extern CV_PossibleValue_t minimapdot_cons_t[NUMMINIMAPDOTSTUFF];
boolean K_IsPlayerLosing(player_t *player);
boolean K_IsPlayerWanted(player_t *player);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush);
INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb);
void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid);
void K_FlipFromObject(mobj_t *mo, mobj_t *master);
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master);
@@ -115,27 +93,6 @@ void K_PlayOvertakeSound(mobj_t *source);
void K_PlayHitEmSound(mobj_t *source, mobj_t *victim);
void K_PlayPowerGloatSound(mobj_t *source);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
INT32 K_calcSplitFlags(INT32 snapflags);
void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(UINT32 flashtime);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
typedef struct
{
INT32 x;
INT32 y;
INT32 flags;
} drawinfo_t;
patch_t *K_getItemBoxPatch(boolean small, boolean dark);
patch_t *K_getItemMulPatch(boolean small);
void K_getItemBoxDrawinfo(drawinfo_t *out);
INT32 K_getMinimapTrans(void);
void K_getLapsDrawinfo(drawinfo_t *out);
void K_getMinimapDrawinfo(drawinfo_t *out);
#ifdef __cplusplus
} // extern "C"
#endif
+1
View File
@@ -25,6 +25,7 @@
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
#include "k_kart.h" // SRB2Kart
#include "k_hud.h" // SRB2Kart
#include "d_netcmd.h" // IsPlayerAdmin
#include "d_main.h"
+2
View File
@@ -55,6 +55,7 @@
X (PlayerQuit),\
X (PlayerThink),/* P_PlayerThink */\
X (MusicChange),\
X (MusicCredit),\
X (ShouldSpin),/*SRB2KART*/\
X (ShouldExplode),/*SRB2KART*/\
X (ShouldSquish),/*SRB2KART*/\
@@ -130,6 +131,7 @@ int LUA_HookPlayerCanDamage(player_t *, mobj_t *);
void LUA_HookPlayerQuit(player_t *, int);
int LUA_HookPlayerCmd(player_t *, ticcmd_t *);
int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
int LUA_HookMusicCredit(musicdef_t *musicdef);
int LUA_HookShouldSpin(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Should player be spun out?
int LUA_HookShouldExplode(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Should player be exploded?
+12
View File
@@ -1066,6 +1066,18 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
return hook.status;
}
int LUA_HookMusicCredit(musicdef_t *musicdef)
{
Hook_State hook;
if (prepare_hook(&hook, 0, HOOK(MusicCredit)))
{
LUA_PushUserdata(gL, musicdef, META_MUSICDEF);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
static int kartdamage_hook
(
player_t *player,
+5 -16
View File
@@ -24,6 +24,7 @@
#include "w_wad.h"
#include "z_zone.h"
#include "k_kart.h"
#include "k_hud.h" // SRB2kart
#include "lua_script.h"
#include "lua_libs.h"
@@ -1260,15 +1261,10 @@ extern int lib_hudadd(lua_State *L);
static int lib_hudsetvotebackground(lua_State *L)
{
memset(VoteScreen.luaPrefix, 0, sizeof(VoteScreen.luaPrefix));
if (lua_isnoneornil(L, 1))
{
if (luaVoteScreen)
{
free(luaVoteScreen);
}
luaVoteScreen = NULL;
return 0;
}
@@ -1279,15 +1275,8 @@ static int lib_hudsetvotebackground(lua_State *L)
return luaL_argerror(L, 1, "prefix should 4 characters wide");
}
if (!luaVoteScreen)
{
luaVoteScreen = (char*)malloc(5);
luaVoteScreen[4] = 0;
}
strncpy(luaVoteScreen, prefix, 4);
strupr(luaVoteScreen);
strncpy(VoteScreen.luaPrefix, prefix, 4);
strupr(VoteScreen.luaPrefix);
return 0;
}
+130
View File
@@ -16,6 +16,7 @@
#include "dehacked.h"
#include "p_mobj.h"
#include "p_local.h"
#include "s_sound.h"
#include "z_zone.h"
#include "lua_script.h"
@@ -1072,6 +1073,109 @@ static int sfxinfo_num(lua_State *L)
return 1;
}
enum musicdef_e {
musicdef_name = 0,
musicdef_usage,
musicdef_source,
musicdef_filename,
musicdef_title,
musicdef_alttitle,
musicdef_authors,
};
const char *const musicdef_opt[] = {
"name",
"usage",
"source",
"filename",
"title",
"alttitle",
"authors",
NULL
};
static int musicdef_fields_ref = LUA_NOREF;
static int lib_sFindMusicCredit(lua_State *L)
{
const char *name = luaL_checkstring(L, 1);
LUA_PushUserdata(L, S_FindMusicCredit(name), META_MUSICDEF);
return 1;
}
static int lib_getMusicDef(lua_State *L)
{
musicdef_t *def = NULL;
if (lua_isnumber(L, 2))
def = S_GetMusicCredit(lua_tonumber(L, 2));
else if (lua_isstring(L, 2))
def = S_FindMusicCredit(lua_tostring(L, 2));
else
return luaL_error(L, "musicdefs index must be number or string (got %s)", luaL_typename(L, 2));
LUA_PushUserdata(L, def, META_MUSICDEF);
return 1;
}
static int lib_setMusicDef(lua_State *L)
{
return luaL_error(L, "musicdefs is read only");
}
static int lib_musicdefslen(lua_State *L)
{
lua_pushinteger(L, nummusicdefs);
return 1;
}
static int musicdef_get(lua_State *L)
{
musicdef_t *musicdef = *((musicdef_t **)luaL_checkudata(L, 1, META_MUSICDEF));
enum musicdef_e field = Lua_optoption(L, 2, -1, musicdef_fields_ref);
I_Assert(musicdef != NULL);
switch (field)
{
case musicdef_name:
lua_pushstring(L, musicdef->name);
return 1;
case musicdef_usage:
lua_pushstring(L, musicdef->usage);
return 1;
case musicdef_source:
lua_pushstring(L, musicdef->source);
return 1;
case musicdef_filename:
lua_pushstring(L, musicdef->filename);
return 1;
case musicdef_title:
lua_pushstring(L, musicdef->title);
return 1;
case musicdef_alttitle:
lua_pushstring(L, musicdef->alttitle);
return 1;
case musicdef_authors:
lua_pushstring(L, musicdef->authors);
return 1;
default:
return luaL_error(L, LUA_QL("musicdef_t") " has no field named " LUA_QS, lua_tostring(L, 2));
}
return 0;
}
static int musicdef_num(lua_State *L)
{
musicdef_t *musicdef = *((musicdef_t **)luaL_checkudata(L, 1, META_MUSICDEF));
I_Assert(musicdef != NULL);
lua_pushinteger(L, musicdef->num);
return 1;
}
//////////////////////////////
//
// Now push all these functions into the Lua state!
@@ -1126,6 +1230,18 @@ int LUA_InfoLib(lua_State *L)
sfxinfo_fields_ref = Lua_CreateFieldTable(L, sfxinfo_opt);
luaL_newmetatable(L, META_MUSICDEF);
lua_pushcfunction(L, musicdef_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, musicdef_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
musicdef_fields_ref = Lua_CreateFieldTable(L, musicdef_opt);
lua_register(L, "S_FindMusicCredit", lib_sFindMusicCredit);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getSprname);
@@ -1176,5 +1292,19 @@ int LUA_InfoLib(lua_State *L)
lua_pushvalue(L, -1);
lua_setglobal(L, "S_sfx");
lua_setglobal(L, "sfxinfo");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getMusicDef);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_setMusicDef);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, lib_musicdefslen);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "musicdefs");
return 0;
}
+5 -1
View File
@@ -10,6 +10,9 @@
/// \file lua_libs.h
/// \brief libraries for Lua scripting
#include "doomtype.h"
#include "blua/lua.h"
extern lua_State *gL;
#define LREG_VALID "VALID_USERDATA"
@@ -20,6 +23,7 @@ extern lua_State *gL;
#define META_STATE "STATE_T*"
#define META_MOBJINFO "MOBJINFO_T*"
#define META_SFXINFO "SFXINFO_T*"
#define META_MUSICDEF "MUSICDEF_T*"
#define META_MOBJ "MOBJ_T*"
#define META_MAPTHING "MAPTHING_T*"
@@ -68,4 +72,4 @@ int LUA_SkinLib(lua_State *L);
int LUA_ThinkerLib(lua_State *L);
int LUA_MapLib(lua_State *L);
int LUA_BlockmapLib(lua_State *L);
int LUA_HudLib(lua_State *L);
int LUA_HudLib(lua_State *L);
+262
View File
@@ -0,0 +1,262 @@
#include <map>
#include <string>
#include <sstream>
#include <cstring>
#include "m_emotes.h"
extern "C" {
#include "w_wad.h"
#include "z_zone.h"
#include "hu_stuff.h"
#include "v_video.h"
}
consvar_t cv_emotes = {"emotes", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};;
static std::map<std::string, emote_t> emotes;
// TODO - Would be really nice to generalize soc-like file parsing and not reimplement it 100 times :)))))
void M_LoadEmotes(UINT16 wadnum)
{
UINT16 lumpnum = W_CheckNumForNamePwad("EMOTES", wadnum, 0);
if (lumpnum == INT16_MAX)
return;
char *lump = static_cast<char*>(W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE));
size_t size = W_LumpLengthPwad(wadnum, lumpnum);
std::istringstream file(std::string(lump, size));
std::string line;
emote_t *emote = nullptr;
std::string emote_name;
// Just smol lambda to remove all the trailing chars we might not want
auto trim = [](std::string &str) {
str.erase(0, str.find_first_not_of(" \t\n\r\f\v"));
str.erase(str.find_last_not_of(" \t\n\r\f\v")+1);
};
int numemotes = 0;
int linenum = 0;
while (std::getline(file, line))
{
++linenum;
trim(line);
if (line.empty())
continue;
size_t split = line.find('=');
// Didn't find the =, means we're about to parse `Emote <name>`
if (split == line.npos)
{
split = line.find(' ');
if (split == line.npos)
{
CONS_Alert(CONS_WARNING, "EMOTES: Unrecognized line. (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
continue;
}
if (strnicmp(line.c_str(), "emote", 5))
{
CONS_Alert(CONS_WARNING, "EMOTES: 'Emote' expected. (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
continue;
}
emote_name = line.substr(split+1);
if (emote_name.find_first_of(" \t\n\r\f\v:") != emote_name.npos)
{
CONS_Alert(CONS_WARNING, "EMOTES: Emote name cannot contain spaces or ':' symbols. (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
continue;
}
if (emote_name.size() > MAXEMOTENAME)
{
CONS_Alert(CONS_WARNING, "EMOTES: Emote name is too long, truncating. (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
emote_name = emote_name.substr(0, MAXEMOTENAME);
}
emote = &emotes[emote_name];
strlcpy(emote->name, emote_name.c_str(), MAXEMOTENAME);
emote->timeperframe = 1;
emote->numframes = 0;
std::memset(emote->frames, 0, sizeof(emote->frames));
++numemotes;
}
else if (emote)
{
std::string field = line.substr(0, split);
std::string value = line.substr(split+1);
trim(field);
trim(value);
if (stricmp(field.c_str(), "frames") == 0)
{
UINT8 numframes = 0;
auto copy_frame = [&] {
if (numframes == MAXEMOTEFRAMES)
{
CONS_Alert(CONS_WARNING, "EMOTES: Too many frames. (file %s, line %d)", wadfiles[wadnum]->filename, linenum);
return false;
}
size_t list_split = value.find(',');
std::string framelumpname = value.substr(0, list_split);
trim(framelumpname);
if (list_split == value.npos)
value = "";
else
value = value.substr(list_split+1, value.npos);
// End of list of frames
if (framelumpname.size() == 0)
return false;
if (framelumpname.size() > 8)
{
CONS_Alert(CONS_WARNING, "EMOTES: Frame %d name is too long. (file %s, line %d)", numframes, wadfiles[wadnum]->filename, linenum);
framelumpname = framelumpname.substr(0, 8);
}
std::strncpy(emote->frames[numframes], framelumpname.c_str(), framelumpname.size()+1);
++numframes;
return true;
};
while (copy_frame()) {}
if (numframes == 0)
{
CONS_Alert(CONS_WARNING, "EMOTES: Expected list of frames. (file %s, line %d)", wadfiles[wadnum]->filename, linenum);
}
emote->numframes = numframes;
}
else if (stricmp(field.c_str(), "timeperframe") == 0)
{
emote->timeperframe = std::stoi(value);
if (emote->timeperframe <= 0)
{
emote->timeperframe = 1;
CONS_Alert(CONS_WARNING, "EMOTES: Bad value for 'timeperframe'. (file %s, line %d)", wadfiles[wadnum]->filename, linenum);
}
}
else
{
CONS_Alert(CONS_WARNING, "EMOTES: Unrecognized field '%s'. (file %s, line %d)", field.c_str(), wadfiles[wadnum]->filename, linenum);
}
}
else
{
CONS_Alert(CONS_WARNING, "EMOTES: Unrecognized line. (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum);
}
}
CONS_Printf("Added %d emotes\n", numemotes);
}
void M_InitEmotes(void)
{
UINT16 i;
for (i = 0; i < numwadfiles; i++)
M_LoadEmotes(i);
}
emote_t *M_FindEmote(const char *name, int len, int skip)
{
if (!cv_emotes.value)
return nullptr;
char query[MAXEMOTENAME+1] = {0};
std::strncpy(query, name, std::min(len, MAXEMOTENAME));
for (auto &pair: emotes)
{
if (pair.first.rfind(query, 0, std::min(len, MAXEMOTENAME)) != 0)
continue;
if (skip > 0)
{
--skip;
continue;
}
return &pair.second;
}
return nullptr;
}
emote_t *M_VerifyEmote(const char *name, int *emotelen)
{
if (*name != ':')
return nullptr;
if (!cv_emotes.value)
return nullptr;
const char *p = name+1; // skip ':'
emote_t *match = nullptr;
while (*p && (p - name) < MAXEMOTENAME)
{
if (*p == ':')
{
std::string checkname = std::string(name+1, (p-name)-1);
auto it = emotes.find(checkname);
if (it != emotes.end())
match = &it->second;
break;
}
++p;
}
if (match && emotelen)
*emotelen = p-name+1;
return match;
}
void M_DrawEmote(INT32 x, INT32 y, emote_t *emote, tic_t anim, INT32 flags)
{
if (emote->numframes == 0)
return;
const char *lumpname = emote->frames[(anim/emote->timeperframe) % emote->numframes];
patch_t *emotepatch = (patch_t*)W_CachePatchName(lumpname, PU_CACHE);
const int CHARHEIGHT = 6;
fixed_t scale = FRACUNIT;
x *= FRACUNIT;
y *= FRACUNIT;
if (emotepatch->width > EMOTEWIDTH)
scale = (FRACUNIT/emotepatch->width)*EMOTEWIDTH;
else if (emotepatch->width < EMOTEWIDTH)
x += (EMOTEWIDTH-emotepatch->width)*FRACUNIT/2;
y -= (scale*emotepatch->height-CHARHEIGHT*FRACUNIT)/2;
V_DrawFixedPatch(x, y, scale, flags, emotepatch, NULL);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef __M_EMOTES__
#define __M_EMOTES__
#ifdef __cplusplus
extern "C" {
#endif
#include "doomdef.h"
#include "command.h"
extern consvar_t cv_emotes;
#define MAXEMOTENAME 32
#define MAXEMOTEFRAMES 32
#define EMOTEWIDTH 6
typedef struct emote_s {
char name[MAXEMOTENAME+1];
char frames[MAXEMOTEFRAMES][9];
UINT8 numframes;
tic_t timeperframe;
} emote_t;
// Reads and adds emotes from EMOTES lump, with syntax similar to soc
void M_LoadEmotes(UINT16 wadnum);
// Load emotes from all base wads
void M_InitEmotes(void);
// Finds first matching emote, ignoring first few matches
emote_t *M_FindEmote(const char *name, int len, int skips);
// If first character is not ':', instantly returns null
// Starts from ':' character, goes until it finds ':' or end of string
// If end of string is found, or closing ':' is found but resulting emote name doesn't exist,
// it returns null, otherwise it returns emote and stores into *emotelen how much characters
// needs to be skipped to get past emote name
emote_t *M_VerifyEmote(const char *name, int *emotelen);
// Draw the emote, anim should be some kind of timer ticking every game tic
// for animated emotes
void M_DrawEmote(INT32 x, INT32 y, emote_t *emote, tic_t anim, INT32 flags);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __M_EMOTES__
+8
View File
@@ -15,6 +15,10 @@
#ifndef __M_FIXED__
#define __M_FIXED__
#ifdef __cplusplus
extern "C" {
#endif
#include "doomtype.h"
#ifdef __GNUC__
#include <stdlib.h>
@@ -370,4 +374,8 @@ void FM_MultMatrix(matrix_t *dest, const matrix_t *multme);
void FM_Translate(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
void FM_Scale(matrix_t *dest, fixed_t x, fixed_t y, fixed_t z);
#ifdef __cplusplus
} // extern "C"
#endif
#endif //m_fixed.h
+48 -45
View File
@@ -70,6 +70,7 @@
#include "st_stuff.h"
#include "i_sound.h"
#include "k_kart.h" // SRB2kart
#include "k_hud.h" // SRB2kart
#include "k_stats.h" // SRB2kart
#include "d_player.h" // KITEM_ constants
@@ -2323,44 +2324,46 @@ static menuitem_t OP_SaturnHudMenu[] =
{
{IT_HEADER, NULL, "Saturn Hud Options", NULL, 0},
{IT_STRING | IT_CVAR, NULL, "Speedometer Style", &cv_newspeedometer, 10},
{IT_STRING | IT_CVAR, NULL, "Battle Speedometer", &cv_battlespeedo, 15},
{IT_STRING|IT_CVAR, NULL, "Speedometer Style", &cv_newspeedometer, 10},
{IT_STRING|IT_CVAR, NULL, "Battle Speedometer", &cv_battlespeedo, 15},
{IT_STRING | IT_CVAR, NULL, "Colourized HUD", &cv_colorizedhud, 25},
{IT_STRING | IT_CVAR, NULL, "Colourized Itembox", &cv_colorizeditembox, 30},
{IT_STRING | IT_CVAR, NULL, "Colourized HUD Color", &cv_colorizedhudcolor, 35},
{IT_STRING|IT_CVAR, NULL, "Colourized HUD", &cv_colorizedhud, 25},
{IT_STRING|IT_CVAR, NULL, "Colourized Itembox", &cv_colorizeditembox, 30},
{IT_STRING|IT_CVAR, NULL, "Colourized HUD Color", &cv_colorizedhudcolor, 35},
{IT_STRING | IT_CVAR, NULL, "Input Display", &cv_showinput, 45},
{IT_STRING|IT_CVAR, NULL, "Input Display", &cv_showinput, 45},
{IT_STRING | IT_CVAR, NULL, "Stat Display", &cv_showstats, 55},
{IT_STRING|IT_CVAR, NULL, "Stat Display", &cv_showstats, 55},
{IT_STRING | IT_CVAR, NULL, "Higher Resolution Portraits", &cv_highresportrait, 65},
{IT_STRING|IT_CVAR, NULL, "Higher Resolution Portraits", &cv_highresportrait, 65},
{IT_STRING | IT_CVAR, NULL, "Small Positionnumber", &cv_smallposnum, 75},
{IT_STRING | IT_CVAR, NULL, "Positionnumber Animation", &cv_posanim, 80},
{IT_STRING|IT_CVAR, NULL, "Small Positionnumber", &cv_smallposnum, 75},
{IT_STRING|IT_CVAR, NULL, "Positionnumber Animation", &cv_posanim, 80},
{IT_STRING | IT_CVAR, NULL, "Flash Lap Times", &cv_showlaptimes, 90},
{IT_STRING|IT_CVAR, NULL, "Flash Lap Times", &cv_showlaptimes, 90},
{IT_STRING | IT_CVAR, NULL, "Multi-Item icons", &cv_multiitemicon, 100},
{IT_STRING | IT_CVAR, NULL, "Item Amount Number", &cv_huditemamount, 105},
{IT_STRING | IT_CVAR, NULL, "Animated Roulette", &cv_fancyroulette, 110},
{IT_STRING|IT_CVAR, NULL, "Multi-Item icons", &cv_multiitemicon, 100},
{IT_STRING|IT_CVAR, NULL, "Item Amount Number", &cv_huditemamount, 105},
{IT_STRING|IT_CVAR, NULL, "Animated Roulette", &cv_fancyroulette, 110},
{IT_STRING | IT_CVAR, NULL, "Show Lap Emblem", &cv_showlapemblem, 120},
{IT_STRING | IT_CVAR, NULL, "Show Cecho Messages", &cv_cechotoggle, 125},
{IT_STRING|IT_CVAR, NULL, "Show Lap Emblem", &cv_showlapemblem, 120},
{IT_STRING|IT_CVAR, NULL, "Show Cecho Messages", &cv_cechotoggle, 125},
{IT_STRING | IT_CVAR, NULL, "Show Names on Minimap", &cv_showminimapnames, 135},
{IT_STRING | IT_CVAR, NULL, "Small Minimap Players", &cv_minihead, 140},
{IT_STRING | IT_CVAR, NULL, "Spin Minimap Icons", &cv_spinoutroll, 145},
{IT_STRING | IT_CVAR, NULL, "Player Angle Visual", &cv_showminimapangle, 150},
{IT_STRING|IT_CVAR, NULL, "Show Names on Minimap", &cv_showminimapnames, 135},
{IT_STRING|IT_CVAR, NULL, "Small Minimap Players", &cv_minihead, 140},
{IT_STRING|IT_CVAR, NULL, "Spin Minimap Icons", &cv_spinoutroll, 145},
{IT_STRING|IT_CVAR, NULL, "Player Angle Visual", &cv_showminimapangle, 150},
{IT_STRING | IT_CVAR, NULL, "Beta Intermissionscreen", &cv_betainterscreen, 160},
{IT_STRING|IT_CVAR, NULL, "Music Credits", &cv_songcredits, 160},
{IT_STRING | IT_CVAR, NULL, "Show Director Prompt", &cv_showdirectorhud, 170},
{IT_STRING|IT_CVAR, NULL, "Beta Intermissionscreen", &cv_betainterscreen, 170},
{IT_STRING | IT_SUBMENU, NULL, "Nametags...", &OP_NametagDef, 180},
{IT_STRING | IT_SUBMENU, NULL, "Driftgauge...", &OP_DriftGaugeDef, 185},
{IT_STRING|IT_CVAR, NULL, "Show Director Prompt", &cv_showdirectorhud, 180},
{IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 195},
{IT_STRING|IT_SUBMENU, NULL, "Nametags...", &OP_NametagDef, 190},
{IT_STRING|IT_SUBMENU, NULL, "Driftgauge...", &OP_DriftGaugeDef, 195},
{IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 205},
};
static const char* OP_SaturnHudTooltips[] =
@@ -2386,6 +2389,7 @@ static const char* OP_SaturnHudTooltips[] =
"Minimize the player icons on the minimap.",
"Erratically rotate player icons during spinouts.",
"Visualize the player facing angle.",
"Show the Music Credits and which style.",
"Make the Intermission screen look like in beta versions of Kart!\nEither with background or just the rest.",
"Show the Director Toggle prompt when spectating.",
"Nametag Options.",
@@ -2416,6 +2420,7 @@ enum
sh_smallmap,
sh_iconspinout,
sh_minidot,
sh_songcred,
sh_betainter,
sh_directorhud,
sh_nametagmen,
@@ -8477,7 +8482,7 @@ static void M_MusicTest(INT32 choice)
{
(void)choice;
if (!S_PrepareSoundTest())
if (!nummusicdefs)
{
M_StartMessage(M_GetText("No selectable tracks found.\n"),NULL,MM_NOTHING);
return;
@@ -8556,33 +8561,33 @@ static void M_DrawMusicTest(void)
{
INT32 t, b, q, m = 128;
if (numsoundtestdefs <= 8)
if (nummusicdefs <= 8)
{
t = 0;
b = numsoundtestdefs - 1;
b = nummusicdefs - 1;
i = 0;
}
else
{
q = m;
m = (5*m)/numsoundtestdefs;
m = (5*m)/nummusicdefs;
if (st_sel < 3)
{
t = 0;
b = 7;
i = 0;
}
else if (st_sel >= numsoundtestdefs-4)
else if (st_sel >= nummusicdefs-4)
{
t = numsoundtestdefs - 8;
b = numsoundtestdefs - 1;
t = nummusicdefs - 8;
b = nummusicdefs - 1;
i = q-m;
}
else
{
t = st_sel - 3;
b = st_sel + 4;
i = (t * (q-m))/(numsoundtestdefs - 8);
i = (t * (q-m))/(nummusicdefs - 8);
}
}
@@ -8591,7 +8596,7 @@ static void M_DrawMusicTest(void)
if (t != 0)
V_DrawString(20+280+4, 60+4 - (skullAnimCounter/5), V_YELLOWMAP, "\x1A");
if (b != numsoundtestdefs - 1)
if (b != nummusicdefs - 1)
V_DrawString(20+280+4, 60+128-12 + (skullAnimCounter/5), V_YELLOWMAP, "\x1B");
x = 24;
@@ -8605,8 +8610,9 @@ static void M_DrawMusicTest(void)
V_DrawFill(20, y-4, 280-1, 16, 237);
{
const musicdef_t *def = S_GetMusicCredit(t);
const size_t MAXLENGTH = 34;
const char *songname = soundtestdefs[t]->title[0] ? soundtestdefs[t]->title : soundtestdefs[t]->source;
const char *songname = def->title[0] ? def->title : def->source;
size_t namelength = strlen(songname);
@@ -8619,7 +8625,7 @@ static void M_DrawMusicTest(void)
buf[MAXLENGTH] = 0;
V_DrawString(x, y, (t == st_sel ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE|V_MONOSPACE, buf);
if (curplaying == soundtestdefs[t])
if (curplaying == def)
{
V_DrawFill(20+280-9, y-4, 8, 16, 230);
}
@@ -8637,7 +8643,7 @@ static void M_HandleMusicTest(INT32 choice)
switch (choice)
{
case KEY_DOWNARROW:
if (st_sel++ >= numsoundtestdefs-1)
if (st_sel++ >= nummusicdefs-1)
st_sel = 0;
{
S_StartSound(NULL, sfx_menu1);
@@ -8646,18 +8652,18 @@ static void M_HandleMusicTest(INT32 choice)
break;
case KEY_UPARROW:
if (!st_sel--)
st_sel = numsoundtestdefs-1;
st_sel = nummusicdefs-1;
{
S_StartSound(NULL, sfx_menu1);
}
st_musictime = 0;
break;
case KEY_PGDN:
if (st_sel < numsoundtestdefs-1)
if (st_sel < nummusicdefs-1)
{
st_sel += 3;
if (st_sel >= numsoundtestdefs-1)
st_sel = numsoundtestdefs-1;
if (st_sel >= nummusicdefs-1)
st_sel = nummusicdefs-1;
S_StartSound(NULL, sfx_menu1);
}
st_musictime = 0;
@@ -8691,7 +8697,7 @@ static void M_HandleMusicTest(INT32 choice)
case KEY_ENTER:
S_StopSounds();
S_StopMusic();
curplaying = soundtestdefs[st_sel];
curplaying = S_GetMusicCredit(st_sel);
S_ChangeMusicInternal(curplaying->name, true);
break;
@@ -8700,9 +8706,6 @@ static void M_HandleMusicTest(INT32 choice)
}
if (exitmenu)
{
Z_Free(soundtestdefs);
soundtestdefs = NULL;
if (currentMenu->prevMenu)
M_SetupNextMenu(currentMenu->prevMenu);
else
+169 -5
View File
@@ -130,6 +130,82 @@ static void M_TextInputPaste(textinput_t *input)
M_TextInputAddString(input, paste);
}
static void M_TextInputLeft(textinput_t *input, boolean emotes)
{
// Just do it simple way if possible
if (!emotes || input->cursor < 2 || input->buffer[input->cursor-1] != ':')
{
if (input->cursor != 0)
--input->cursor;
return;
}
// Otherwise we need to check if we have to skip emote
size_t start = input->cursor-2;
while (input->buffer[start] != ':')
{
// We reached start of string and didn't find ':' symbol, thats definitely not an emote
// so just do it simple way
if (start == 0)
{
M_TextInputLeft(input, false);
return;
}
--start;
}
int emotelen = 0;
if (M_VerifyEmote(input->buffer+start, &emotelen))
input->cursor -= emotelen; // also skip the :
else
M_TextInputLeft(input, false); // Not a valid emote, do the simple thing
}
static void M_TextInputRight(textinput_t *input, boolean emotes)
{
// Just do it simple way if possible
if (!emotes || input->cursor == input->length || input->buffer[input->cursor] != ':')
{
if (input->cursor < input->length)
++input->cursor;
return;
}
int emotelen = 0;
if (M_VerifyEmote(input->buffer+input->cursor, &emotelen))
input->cursor += emotelen; // Also skip the :
else
M_TextInputRight(input, false); // Not a valid emote, do the simple thing
}
// Check if we're inside a valid emote
static boolean M_TextInputCheckEmote(textinput_t *input)
{
int start = input->cursor;
// Definitely not an emote
if (start == 0)
return false;
// Might be closing :, need to skip it just in case
if (input->buffer[start] == ':')
--start;
while (input->buffer[start] != ':')
{
// No ':' found, definitely not inside emote
if (start == 0)
return false;
--start;
}
// Found what may be emote start, now we can check
return M_VerifyEmote(input->buffer+start, NULL) != NULL;
}
void M_TextInputInit(textinput_t *input, char *buffer, size_t buffer_size)
{
input->buffer = buffer;
@@ -156,7 +232,7 @@ void M_TextInputSetString(textinput_t *input, const char *c)
input->cursor = input->select = input->length = strlen(c);
}
boolean M_TextInputHandle(textinput_t *input, INT32 key)
static boolean M_TextInputHandleBase(textinput_t *input, INT32 key, boolean emotes)
{
if (key == KEY_LSHIFT || key == KEY_RSHIFT
|| key == KEY_LCTRL || key == KEY_RCTRL
@@ -241,16 +317,14 @@ boolean M_TextInputHandle(textinput_t *input, INT32 key)
if (key == KEY_LEFTARROW)
{
if (input->cursor != 0)
--input->cursor;
M_TextInputLeft(input, emotes);
if (!shiftdown)
input->select = input->cursor;
return true;
}
else if (key == KEY_RIGHTARROW)
{
if (input->cursor < input->length)
++input->cursor;
M_TextInputRight(input, emotes);
if (!shiftdown)
input->select = input->cursor;
return true;
@@ -320,6 +394,96 @@ boolean M_TextInputHandle(textinput_t *input, INT32 key)
return true;
}
// Just an alias, more or less
boolean M_TextInputHandle(textinput_t *input, INT32 key)
{
return M_TextInputHandleBase(input, key, false);
}
boolean M_TextInputHandleEmotes(textinput_t *input, INT32 key, emote_t *suggestions[], int maxsuggestions)
{
boolean ret = M_TextInputHandleBase(input, key, true);
// After this handled key we ended up inside an emote, lets fix that
if (M_TextInputCheckEmote(input))
M_TextInputToWordEnd(input, !shiftdown);
// Always clear the first entry
suggestions[0] = NULL;
// For autocomplete
int emotestart = 0;
// Try find suggestions for emote names
for (int i = input->cursor-1; i >= 0 && input->cursor-i <= MAXEMOTENAME; --i)
{
// Space can't be part of emote name
if (isspace(input->buffer[i]))
break;
// Found a :, try suggest emotes
if (input->buffer[i] == ':')
{
emotestart = i+1;
// ...But only if we typed at least something
if ((int)input->cursor-(i-1) < 3)
break;
for (int skip = 0; skip < maxsuggestions; ++skip)
{
suggestions[skip] = M_FindEmote(input->buffer+i+1, input->cursor-i-1, skip);
// No more suggestions
if (!suggestions[skip])
break;
}
// In any case, we found what we wanted, can exit the loop now
break;
}
}
// If we suggest emotes, try autocomplete
if (key == '\t' && suggestions[0])
{
int pos = (input->cursor-emotestart);
boolean autocomplete = true;
while (autocomplete)
{
// Check if current character matches for all suggestions
char c = suggestions[0]->name[pos];
// End of string reached
if (!c)
break;
for (int i = 1; i < maxsuggestions && suggestions[i]; ++i)
{
if (suggestions[i]->name[pos] != c)
{
autocomplete = false;
break;
}
}
++pos;
if (autocomplete)
M_TextInputAddChar(input, c);
}
// This was the only suggestion, finish autocomplete with a ':' and clear suggestions
if (maxsuggestions == 1 || !suggestions[1])
{
M_TextInputAddChar(input, ':');
suggestions[0] = NULL;
}
}
return ret;
}
void M_DrawTextInputScroll(INT32 x, INT32 y, textinput_t *input, INT32 flags, INT32 MAXINPUTWIDTH)
{
if (renderisnewtic)
+5
View File
@@ -2,6 +2,7 @@
#define __M_TEXTINPUT__
#include "doomtype.h"
#include "m_emotes.h" // M_VerifyEmote, M_FindEmote
typedef struct textinput_s {
size_t cursor;
@@ -22,6 +23,10 @@ void M_TextInputSetString(textinput_t *input, const char *c);
boolean M_TextInputHandle(textinput_t *input, INT32 key);
// Does everything same as M_TextInputHandle, but also handles emotes in input string
// If currently typing something that looks like an existing emote, return suggestions for it
boolean M_TextInputHandleEmotes(textinput_t *input, INT32 key, emote_t *suggestions[], int maxsuggestions);
#define M_DrawTextInput(x, y, input, flags) M_DrawTextInputScroll((x), (y), (input), (flags), ((input)->buffer_size-1)*8)
void M_DrawTextInputScroll(INT32 x, INT32 y, textinput_t *input, INT32 flags, INT32 MAXINPUTWIDTH);
+144 -106
View File
@@ -34,6 +34,7 @@
#include "r_fps.h" // R_ResetViewInterpolation in level load
#include "s_sound.h"
#include "m_emotes.h"
#include "st_stuff.h"
#include "w_wad.h"
#include "z_zone.h"
@@ -67,6 +68,8 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "y_inter.h"
#if !defined (UNDER_CE)
#include <time.h>
#endif
@@ -3131,11 +3134,128 @@ boolean P_AddWadFile(const char *wadfilename, boolean local)
return true;
}
// check for replacement votescreen backgrounds
boolean wideracereplaced = false;
boolean racereplaced = false;
boolean widebattlereplaced = false;
boolean battlereplaced = false;
static size_t sreplaces = 0, mreplaces = 0, digmreplaces = 0;
//
// search for sound replacements
//
static boolean P_CheckSoundReplacements(UINT16 wadnum, char *name, size_t i)
{
size_t j;
lumpnum_t lumpnum = (i|(wadnum<<16));
if (name[0] == 'D')
{
if (name[1] == 'S')
{
for (j = 1; j < NUMSFX; j++)
{
if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6)
&& (S_sfx[j].lumpnum != lumpnum) && (S_sfx[j].lumpnum != LUMPERROR))
{
// the sound will be reloaded when needed,
// since sfx->data will be NULL
CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name);
I_FreeSfx(&S_sfx[j]);
// Re-cache it
if (S_PrecacheSound())
S_sfx[j].data = I_GetSfx(&S_sfx[j]);
sreplaces++;
return true;
}
}
}
else if (name[1] == '_')
{
CONS_Debug(DBG_SETUP, "Music %.8s ignored\n", name);
mreplaces++;
return true;
}
}
else if (name[0] == 'O' && name[1] == '_')
{
CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name);
digmreplaces++;
return true;
}
return false;
}
//
// search for maps
//
static boolean P_CheckMapReplacements(char *name)
{
if (memcmp(name, "MAP", 3) == 0) // Ignore the headers
{
INT16 num;
if (name[5] != '\0')
return false;
num = (INT16)M_MapNumber(name[3], name[4]);
// we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant
if (num <= NUMMAPS && mapheaderinfo[num-1])
{
if (mapheaderinfo[num-1]->menuflags & LF2_EXISTSHACK)
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
mapheaderinfo[num-1]->menuflags |= LF2_EXISTSHACK;
}
if (num == gamemap)
partadd_replacescurrentmap = true;
CONS_Printf("%s\n", name);
return true;
}
return false;
}
//
// check for non Lua votescreen replacements
//
static boolean P_CheckVoteReplacements(char *name)
{
// widescreen patch Race
if (!VoteScreen.replaced.widerace && !memcmp(name, "INTERSCW", 8))
{
VoteScreen.replaced.widerace = true;
return false;
}
if (!VoteScreen.replaced.race && !memcmp(name, "INTERSCR", 8))
{
VoteScreen.replaced.race = true;
return false;
}
// widescreen patch Battle
if (!VoteScreen.replaced.widebattle && !memcmp(name, "BATTLSCW", 8))
{
VoteScreen.replaced.widebattle = true;
return false;
}
if (!VoteScreen.replaced.battle && !memcmp(name, "BATTLSCR", 8))
{
VoteScreen.replaced.battle = true;
return false;
}
if (VoteScreen.replaced.widerace && VoteScreen.replaced.race
&& VoteScreen.replaced.widebattle && VoteScreen.replaced.battle)
{
return true;
}
return false;
}
//
// Add a WAD file and do the per-WAD setup stages.
@@ -3143,12 +3263,15 @@ boolean battlereplaced = false;
//
UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local)
{
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
size_t i;
UINT16 numlumps, wadnum;
char *name;
boolean mapsadded = false;
static boolean allvotereplaced = false;
lumpinfo_t *lumpinfo;
sreplaces = mreplaces = digmreplaces = 0;
if ((numlumps = W_InitFile(wadfilename, local)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
@@ -3163,46 +3286,24 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local)
wadfiles[wadnum]->localfile = local;
//
// search for sound replacements
//
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
lumpnum_t lumpnum = i|(wadnum<<16);
if (name[0] == 'D')
if (P_CheckSoundReplacements(wadnum, name, i))
continue;
if (P_CheckMapReplacements(name))
{
if (name[1] == 'S') for (j = 1; j < NUMSFX; j++)
{
if (S_sfx[j].name && !strnicmp(S_sfx[j].name, name + 2, 6) && S_sfx[j].lumpnum != lumpnum && S_sfx[j].lumpnum != LUMPERROR)
{
// the sound will be reloaded when needed,
// since sfx->data will be NULL
CONS_Debug(DBG_SETUP, "Sound %.8s replaced\n", name);
I_FreeSfx(&S_sfx[j]);
// Re-cache it
if (S_PrecacheSound())
S_sfx[j].data = I_GetSfx(&S_sfx[j]);
sreplaces++;
}
}
else if (name[1] == '_')
{
CONS_Debug(DBG_SETUP, "Music %.8s ignored\n", name);
mreplaces++;
}
}
else if (name[0] == 'O' && name[1] == '_')
{
CONS_Debug(DBG_SETUP, "Music %.8s replaced\n", name);
digmreplaces++;
mapsadded = true;
continue;
}
if (!allvotereplaced && P_CheckVoteReplacements(name))
allvotereplaced = true;
}
if (!devparm && sreplaces)
CONS_Printf(M_GetText("%s sounds replaced\n"), sizeu1(sreplaces));
if (!devparm && mreplaces)
@@ -3210,6 +3311,9 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local)
if (!devparm && digmreplaces)
CONS_Printf(M_GetText("%s digital musics replaced\n"), sizeu1(digmreplaces));
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
//
// search for sprite replacements
//
@@ -3235,79 +3339,13 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local)
S_LoadMusicDefs(wadnum);
//
// search for maps
// look for emotes
//
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
{
INT16 num;
if (name[5]!='\0')
continue;
num = (INT16)M_MapNumber(name[3], name[4]);
// we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant
if (num <= NUMMAPS && mapheaderinfo[num-1])
{
if (mapheaderinfo[num-1]->menuflags & LF2_EXISTSHACK)
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
mapheaderinfo[num-1]->menuflags |= LF2_EXISTSHACK;
}
if (num == gamemap)
partadd_replacescurrentmap = true;
CONS_Printf("%s\n", name);
mapsadded = true;
}
}
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
M_LoadEmotes(wadnum);
// TODO: Experimental SPRTINFO support, test first
R_LoadSpriteInfoLumps(wadnum, wadfiles[wadnum]->numlumps);
//
// check for votescreen replacements
//
if (!wideracereplaced && !racereplaced && !widebattlereplaced && !battlereplaced)
{
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
// widescreen patch Race
if (!wideracereplaced && !strncmp(name, "INTERSCW", 8))
{
wideracereplaced = true;
continue;
}
if (!racereplaced && !strncmp(name, "INTERSCR", 8))
{
racereplaced = true;
continue;
}
// widescreen patch Battle
if (!widebattlereplaced && !strncmp(name, "BATTLSCW", 8))
{
widebattlereplaced = true;
continue;
}
if (!battlereplaced && !strncmp(name, "BATTLSCR", 8))
{
battlereplaced = true;
continue;
}
}
}
refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_GAMEDATA to disappear the next frame, but it's a bit too dangerous for that...
partadd_stage = 0;
return wadnum;
-5
View File
@@ -73,11 +73,6 @@ void HWR_LoadLevel(boolean reloadinggamestate);
boolean P_AddWadFile(const char *wadfilename, boolean local);
extern boolean wideracereplaced;
extern boolean racereplaced;
extern boolean widebattlereplaced;
extern boolean battlereplaced;
// WARNING: The following functions should be grouped as follows:
// any amount of PartialAdds followed by MultiSetups until returned true,
// as soon as possible.
+3 -3
View File
@@ -385,15 +385,15 @@ static void R_AddLine(seg_t *line)
backsector = line->backsector;
// Portal line
if (line->linedef->special == 40 && line->side == 0)
if (line->linedef->special == PORTALSPECIAL && line->side == 0)
{
if (portalrender < cv_maxportals.value)
{
// Find the other side!
INT32 line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, -1);
INT32 line2 = P_FindSpecialLineFromTag(PORTALSPECIAL, line->linedef->tag, -1);
if (line->linedef == &lines[line2])
line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2);
line2 = P_FindSpecialLineFromTag(PORTALSPECIAL, line->linedef->tag, line2);
if (line2 >= 0) // found it!
{
+1
View File
@@ -420,6 +420,7 @@ typedef enum
} slopetype_t;
#define HORIZONSPECIAL 41
#define PORTALSPECIAL 40
typedef struct line_s
{
+9 -6
View File
@@ -179,12 +179,15 @@ extern lumpnum_t viewborderlump[8];
#define GTC_MENUCACHE GTC_CACHE
//@TODO Add a separate caching mechanism for menu colormaps distinct from in-level GTC_CACHE. For now this is still preferable to memory leaks...
#define TC_DEFAULT -1
#define TC_BOSS -2
#define TC_METALSONIC -3 // For Metal Sonic battle
#define TC_ALLWHITE -4 // For Cy-Brak-demon
#define TC_RAINBOW -5 // For invincibility power
#define TC_BLINK -6 // For item blinking
enum
{
TC_BLINK = -6, // For item blinking, according to kart
TC_RAINBOW, // For single colour
TC_ALLWHITE, // For Cy-Brak-demon
TC_METALSONIC, // For Metal Sonic battle
TC_BOSS,
TC_DEFAULT
};
// Initialize color translation tables, for player rendering etc.
UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags);
+16 -17
View File
@@ -1164,8 +1164,6 @@ fixed_t R_GetSpriteDirectionalLighting(angle_t angle)
return extralight;
}
#define std_R_QuickCamDist(x, y) std::max(abs(((x)>>FRACBITS) - (viewx>>FRACBITS)), abs(((y)>>FRACBITS) - (viewy>>FRACBITS)))
//
// R_ProjectSprite
// Generates a vissprite for a thing
@@ -1206,7 +1204,6 @@ static void R_ProjectSprite(mobj_t *thing)
//SoM: 3/17/2000
fixed_t gz, gzt;
INT32 heightsec, phs;
INT32 dist = -1;
INT32 light = 0;
lighttable_t **lights_array = spritelights;
fixed_t this_scale;
@@ -1233,14 +1230,11 @@ static void R_ProjectSprite(mobj_t *thing)
const boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored);
const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
if (cv_maxinterpdist.value)
dist = std_R_QuickCamDist(thing->x, thing->y);
// uncapped/interpolation
interpmobjstate_t interp = {};
// do interpolation
if (R_UsingFrameInterpolation() && !paused && (!cv_maxinterpdist.value || dist < cv_maxinterpdist.value))
if (R_UsingFrameInterpolation() && !paused && R_CheckInterpDist(oldthing))
{
R_InterpolateMobjState(oldthing, rendertimefrac, &interp);
}
@@ -1862,25 +1856,20 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
fixed_t gz, gzt;
fixed_t this_scale;
INT32 dist = 1;
if (!thing || thing->subsector == NULL)
return;
if (cv_maxinterpdist.value)
dist = std_R_QuickCamDist(thing->x, thing->y);
// uncapped/interpolation
interpmobjstate_t interp = {};
// okay... this is a hack, but weather isn't networked, so it should be ok
if (!P_PrecipThinker(thing))
{
return;
}
// uncapped/interpolation
interpmobjstate_t interp = {};
// do interpolation
if (R_UsingFrameInterpolation() && !paused && (!cv_maxinterpdist.value || dist < cv_maxinterpdist.value))
if (R_UsingFrameInterpolation() && !paused && R_CheckInterpDist((mobj_t*)thing))
{
R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp);
}
@@ -2919,7 +2908,7 @@ boolean R_ThingVisible (mobj_t *thing)
if (splitscreen)
{
if ((viewssnum == 0 && (thing->eflags & MFE_DRAWONLYFORP1))
if ((viewssnum == 0 && (thing->eflags & MFE_DRAWONLYFORP1))
|| (viewssnum == 1 && (thing->eflags & MFE_DRAWONLYFORP2))
|| (viewssnum == 2 && (thing->eflags & MFE_DRAWONLYFORP2))
|| (viewssnum == 3 && (thing->eflags & MFE_DRAWONLYFORP4)))
@@ -2942,6 +2931,16 @@ boolean R_ThingWithinDist(mobj_t *thing, INT32 limit_dist)
return true;
}
boolean R_CheckInterpDist(mobj_t *thing)
{
if (!cv_maxinterpdist.value)
return true;
const INT32 dist = R_QuickCamDist(thing->x, thing->y);
return (dist < cv_maxinterpdist.value);
}
boolean R_ThingIsFullBright(mobj_t *thing)
{
return ((thing->frame & FF_BRIGHTMASK) == FF_FULLBRIGHT);
+6
View File
@@ -39,7 +39,12 @@ extern "C" {
// as an non-fixed-point integer.
// It is very rough, tho it is used only for optimizing out unnecessary
// interpolation, so it is kinda ok on big distances.
#ifdef __cplusplus
#define R_QuickCamDist(x, y) std::max(std::abs(((x)>>FRACBITS) - (viewx>>FRACBITS)), std::abs(((y)>>FRACBITS) - (viewy>>FRACBITS)))
#else
#define R_QuickCamDist(x, y) max(abs(((x)>>FRACBITS) - (viewx>>FRACBITS)), abs(((y)>>FRACBITS) - (viewy>>FRACBITS)))
#endif
// Constant arrays used for psprite clipping
// and initializing clipping.
@@ -84,6 +89,7 @@ void R_DrawMasked(maskcount_t* masks, INT32 nummasks);
boolean R_ThingVisible(mobj_t *thing);
boolean R_ThingWithinDist(mobj_t *thing, INT32 limit_dist);
boolean R_CheckInterpDist(mobj_t *thing);
boolean R_ThingIsFullBright(mobj_t *thing);
boolean R_ThingIsSemiBright(mobj_t *thing);
+58 -43
View File
@@ -32,6 +32,7 @@
#include "m_menu.h" // bird music stuff
#include "lua_hook.h" // MusicChange hook
#include "lua_hud.h" // LUA_HudEnabled(hud_musiccredit)
static boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch, sfxinfo_t *sfxinfo);
static void SetChannelsNum(void);
@@ -1202,8 +1203,58 @@ static consvar_t *music_refade_cv;
/// Music Definitions
/// ------------------------
musicdef_t *musicdefstart = NULL; // First music definition
struct cursongcredit cursongcredit; // Currently displayed song credit info
// Similar system to vissprite allocation. Exists so external pointers to musicdefs are not invalidated
// when allocating more space for musicdefs
#define MUSICDEFCHUNKBITS 6
#define MUSICDEFSPERCHUNK (1 << MUSICDEFCHUNKBITS)
#define MUSICDEFINDEXMASK (MUSICDEFSPERCHUNK - 1)
static musicdef_t **musicdefs = NULL;
static INT32 numchunks = 0;
INT32 nummusicdefs = 0;
//
// S_GetMusicCredit
//
// Return music credit with given index.
//
musicdef_t *S_GetMusicCredit(INT32 i)
{
if (i < 0 || i >= nummusicdefs)
return NULL;
INT32 chunk = i >> MUSICDEFCHUNKBITS;
i &= MUSICDEFINDEXMASK;
return &musicdefs[chunk][i];
}
//
// S_AddMusicCredit
//
// Return new music credit, allocates memory for it if needed.
//
static musicdef_t *S_AddMusicCredit(void)
{
INT32 chunk = nummusicdefs >> MUSICDEFCHUNKBITS;
INT32 i = nummusicdefs & MUSICDEFINDEXMASK;
// Allocate new chunk if needed. Other chunks stay valid
if (chunk == numchunks)
{
++numchunks;
musicdefs = (musicdef_t**)Z_Realloc(musicdefs, sizeof(musicdef_t*)*numchunks, PU_STATIC, NULL);
musicdefs[chunk] = Z_Calloc(sizeof(musicdef_t)*MUSICDEFSPERCHUNK, PU_STATIC, NULL);
}
// Store "id" of new musicdef (mostly exists only for lua)
musicdefs[chunk][i].num = nummusicdefs;
++nummusicdefs;
return &musicdefs[chunk][i];
}
struct cursongcredit cursongcredit = {0}; // Currently displayed song credit info
static boolean
ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp)
@@ -1231,14 +1282,11 @@ ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp)
// Nothing found, add to the end.
if (!def)
{
def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL);
def = S_AddMusicCredit();
STRBUFCPY(def->name, value);
strlwr(def->name);
def->hash = quickncasehash (def->name, 6);
def->next = musicdefstart;
musicdefstart = def;
}
(*defp) = def;
@@ -1423,8 +1471,10 @@ musicdef_t *S_FindMusicCredit(const char *musname)
UINT32 hash = quickncasehash (musname, 6);
musicdef_t *def;
for (def = musicdefstart; def; def = def->next)
for (INT32 i = 0; i < nummusicdefs; ++i)
{
def = S_GetMusicCredit(i);
if (hash != def->hash)
continue;
if (stricmp(def->name, musname))
@@ -1457,7 +1507,7 @@ void S_ShowSpecifiedMusicCredit(const char *musname)
def = S_FindMusicCredit(musname);
if (def)
if (def && !LUA_HookMusicCredit(def))
{
cursongcredit.def = def;
cursongcredit.anim = 5*TICRATE;
@@ -1476,41 +1526,6 @@ void S_ShowMusicCredit(void)
S_ShowSpecifiedMusicCredit(music.name);
}
musicdef_t **soundtestdefs = NULL;
INT32 numsoundtestdefs = 0;
//
// S_PrepareSoundTest
//
// Prepare sound test. What am I, your butler?
//
boolean S_PrepareSoundTest(void)
{
musicdef_t *def;
INT32 pos = numsoundtestdefs = 0;
for (def = musicdefstart; def; def = def->next)
{
numsoundtestdefs++;
}
if (!numsoundtestdefs)
return false;
if (soundtestdefs)
Z_Free(soundtestdefs);
if (!(soundtestdefs = Z_Malloc(numsoundtestdefs*sizeof(musicdef_t *), PU_STATIC, NULL)))
I_Error("S_PrepareSoundTest(): could not allocate soundtestdefs.");
for (def = musicdefstart; def /*&& i < numsoundtestdefs*/; def = def->next)
{
soundtestdefs[pos++] = def;
}
return true;
}
/// ------------------------
/// Music Status
/// ------------------------
+3 -8
View File
@@ -182,14 +182,9 @@ typedef struct musicdef_s
char alttitle[256];
char authors[256];
boolean use_info;
struct musicdef_s *next;
size_t num;
} musicdef_t;
extern musicdef_t *musicdefstart;
extern musicdef_t **soundtestdefs;
extern INT32 numsoundtestdefs;
extern UINT8 soundtestpage;
extern struct cursongcredit
{
musicdef_t *def;
@@ -198,18 +193,18 @@ extern struct cursongcredit
UINT8 trans;
} cursongcredit;
extern INT32 nummusicdefs;
void S_LoadMusicDefs(UINT16 wadnum);
void S_InitMusicDefs(void);
void S_LoadMTDefs(UINT16 wadnum);
void S_InitMTDefs(void);
musicdef_t *S_GetMusicCredit(INT32 i);
musicdef_t *S_FindMusicCredit(const char *musname);
void S_ShowSpecifiedMusicCredit(const char *musname);
void S_ShowMusicCredit(void);
void S_ResetMusicCredit(void);
boolean S_PrepareSoundTest(void);
//
// Music Seeking
//
+1
View File
@@ -180,6 +180,7 @@ static char returnWadPath[256];
#include "../screen.h" //vid.WndParent
#include "../d_net.h"
#include "../g_game.h"
#include "../g_demo.h"
#include "../filesrch.h"
#include "../z_zone.h" // Z_Free
#include "endtxt.h"
+1
View File
@@ -34,6 +34,7 @@
#include "i_time.h"
#include "k_kart.h" // SRB2kart
#include "k_hud.h"
//random index
#include "m_random.h"
+8
View File
@@ -14,6 +14,10 @@
#ifndef __STSTUFF_H__
#define __STSTUFF_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "doomtype.h"
#include "d_event.h"
#include "d_player.h"
@@ -142,4 +146,8 @@ extern UINT16 objectsdrawn;
extern consvar_t cv_lessflicker;
extern consvar_t cv_stagetitle;
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+1
View File
@@ -65,6 +65,7 @@
#include "st_stuff.h"
#include "m_misc.h" // M_MapNumber
#include "p_setup.h" // P_PartialAddFile mayb
#include "k_hud.h"
#ifdef HWRENDER
#include "r_data.h"
+146 -133
View File
@@ -40,6 +40,7 @@
#include "m_random.h" // M_RandomKey
#include "g_input.h" // PLAYER1INPUTDOWN
#include "k_kart.h" // colortranslations
#include "k_hud.h"
#include "console.h" // cons_menuhighlight
#include "lua_hook.h" // IntermissionThinker hook
#include "lua_hud.h" // intermission hud hook
@@ -57,30 +58,15 @@ typedef struct
static y_data_t data;
// graphics
static patch_t *bgpatch = NULL; // INTERSCR
static patch_t *widebgpatch = NULL; // INTERSCW
static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK
static INT32 timer;
static INT32 intertic;
static INT32 endtic = -1;
static INT32 sorttic = -1;
patch_t *animVoteFramesPatches = NULL;
// VEXTRN - Vote (V) Extra (EXT) Race (R) Normal (N - Normal sized patch)
// VEXTBN - Vote (V) Extra (EXT) Battle (B) Normal (N - Normal sized patch)
// VEXTBW - Vote (V) Extra (EXT) Battle (B) Normal (W - Wide patch used in software)
// VEXTRW - Vote (V) Extra (EXT) Race (R) Normal (W - Wide patch used in software)
char animPrefix[] = "INTSC";
char animWidePrefix[] = "INTSW";
char *luaVoteScreen = NULL;
INT32 currentAnimFrame = 0;
static INT32 foundAnimVoteFrames = 0;
static INT32 foundAnimVoteWideFrames = 0;
intertype_t intertype = int_none;
static huddrawlist_h luahuddrawlist_intermission = NULL;
@@ -118,17 +104,13 @@ typedef struct
boolean loaded;
} y_voteclient;
// votescreen stuff
votescreen_t VoteScreen = {0};
static y_votelvlinfo levelinfo[5];
static y_voteclient voteclient;
static INT32 votetic;
static INT32 voteendtic = -1;
static patch_t *cursor = NULL;
static patch_t *cursor1 = NULL;
static patch_t *cursor2 = NULL;
static patch_t *cursor3 = NULL;
static patch_t *cursor4 = NULL;
static patch_t *randomlvl = NULL;
static patch_t *rubyicon = NULL;
static void Y_UnloadVoteData(void);
@@ -287,49 +269,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
}
}
//
// Y_AnimatedVoteScreenCheck
//
// Check if the lumps exist (checking for VEXTR(N|W)xx for race and VEXTRB(N|W)xx for battle)
static void Y_AnimatedVoteScreenCheck(void)
{
char tmpPrefix[] = "INTS";
if (luaVoteScreen)
strncpy(tmpPrefix, luaVoteScreen, 4);
else if (G_BattleGametype())
strcpy(tmpPrefix, "BTLS");
strncpy(animPrefix, tmpPrefix, 4);
animPrefix[4] = 'C';
strncpy(animWidePrefix, tmpPrefix, 4);
animWidePrefix[4] = 'W';
foundAnimVoteFrames = foundAnimVoteWideFrames = 0;
currentAnimFrame = 0;
INT32 i = 1;
for (;;)
{
boolean normalLumpExists = W_LumpExists(va("%sC%d", tmpPrefix, i));
boolean wideLumpExists = W_LumpExists(va("%sW%d", tmpPrefix, i));
if (normalLumpExists || wideLumpExists)
{
if (normalLumpExists)
foundAnimVoteFrames++;
if (wideLumpExists)
foundAnimVoteWideFrames++;
}
else // If we don't find at least frame 1 (e.g VEXTRN1), let's just stop looking
break;
i++;
}
}
// Y_PlayerStandingsDrawer
//
// Handles drawing the center-of-screen player standings.
@@ -863,7 +802,8 @@ void Y_StartIntermission(void)
//
void Y_EndIntermission(void)
{
Y_UnloadData();
if (!dedicated)
Y_UnloadData();
endtic = -1;
sorttic = -1;
@@ -881,28 +821,72 @@ static void Y_FollowIntermission(void)
G_AfterIntermission();
}
#define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL;
#define UNLOAD(x) {if ((x) != NULL) {Patch_Free(x);} x = NULL;}
//
// Y_UnloadData
//
static void Y_UnloadData(void)
{
// In hardware mode, don't Z_ChangeTag a pointer returned by W_CachePatchName().
// It doesn't work and is unnecessary.
if (rendermode != render_soft)
return;
// unload the background patches
UNLOAD(bgpatch);
UNLOAD(widebgpatch);
UNLOAD(VoteScreen.bgpatch);
UNLOAD(VoteScreen.widebgpatch);
UNLOAD(bgtile);
//UNLOAD(interpic);
}
// SRB2Kart: Voting!
static void Y_DrawVoteBackground(patch_t *patch)
//
// Y_VoteScreenCheck
//
static void Y_VoteScreenCheck(void)
{
strcpy(VoteScreen.Prefix, "INTS");
if (VoteScreen.luaPrefix[0] != 0)
strlcpy(VoteScreen.Prefix, VoteScreen.luaPrefix, sizeof(VoteScreen.Prefix));
else if (G_BattleGametype())
strcpy(VoteScreen.Prefix, "BTLS");
VoteScreen.foundLuaVoteFrames = VoteScreen.foundLuaVoteWideFrames = 0;
VoteScreen.currentAnimFrame = 0;
INT32 i = 1;
// check for lua vote background replacements
for (;;)
{
// Check if the lumps exist (checking for VEXTR(N|W)xx for race and VEXTRB(N|W)xx for battle)
boolean normalLumpExists = W_LumpExists(va("%sC%d", VoteScreen.Prefix, i));
boolean wideLumpExists = W_LumpExists(va("%sW%d", VoteScreen.Prefix, i));
if (normalLumpExists || wideLumpExists)
{
if (normalLumpExists)
VoteScreen.foundLuaVoteFrames++;
if (wideLumpExists)
VoteScreen.foundLuaVoteWideFrames++;
}
else // If we don't find at least frame 1 (e.g VEXTRN1), let's just stop looking
break;
i++;
}
// non lua vote background handling
boolean prefbattletype = ((votelevels[0][1] & ~0x80) == GT_MATCH);
VoteScreen.widebgpatch = W_CachePatchName((prefbattletype ? "BATTLSCW" : "INTERSCW"), PU_PATCH);
VoteScreen.bgpatch = W_CachePatchName((prefbattletype ? "BATTLSCR" : "INTERSCR"), PU_PATCH);
}
//
// Y_VoteBackgroundDrawer
//
// Determines which patch drawer to use for scaling
//
static void Y_VoteBackgroundDrawer(patch_t *patch)
{
switch (cv_votebgscaling.value)
{
@@ -924,57 +908,74 @@ static void Y_DrawVoteBackground(patch_t *patch)
}
}
// Y_DrawAnimatedVoteScreenPatch
//
// Draw animated patch based on frame counter on vote screen
// Y_DrawLuaVoteScreenPatch
//
static void Y_DrawAnimatedVoteScreenPatch(boolean widePatch)
// Handles votebackgrounds set by "setVoteBackground"
// Aswell as animated patches
//
static void Y_DrawLuaVoteScreenPatch(boolean widePatch)
{
INT32 nextframe = 0;
patch_t *votebg = NULL;
char tempAnimPrefix[7];
const INT32 tempFoundAnimVoteFrames = ((widePatch ? foundAnimVoteWideFrames : foundAnimVoteFrames) - 1);
char tempPrefix[6];
const INT32 tempfoundAnimLuaVoteFrames = ((widePatch ? VoteScreen.foundLuaVoteWideFrames : VoteScreen.foundLuaVoteFrames) - 1);
strcpy(tempAnimPrefix, (widePatch ? animWidePrefix : animPrefix));
strcpy(tempPrefix, va("%s%s", VoteScreen.Prefix, (widePatch ? "W" : "C")));
// Draw non animated patch
if (!tempfoundAnimLuaVoteFrames)
{
votebg = W_CachePatchName(va("%s1", tempPrefix), PU_PATCH);
Y_VoteBackgroundDrawer(votebg);
return;
}
// Draw animated patch based on frame counter on vote screen
// Just in case someone provides LESS widescreen frames than normal frames or vice versa, reset the frame counter to 0
if (currentAnimFrame > tempFoundAnimVoteFrames)
currentAnimFrame = 0;
if (VoteScreen.currentAnimFrame > tempfoundAnimLuaVoteFrames)
VoteScreen.currentAnimFrame = 0;
nextframe = (currentAnimFrame + 1);
nextframe = (VoteScreen.currentAnimFrame + 1);
votebg = W_CachePatchName(va("%s%d", (widePatch ? animWidePrefix : animPrefix), nextframe), PU_PATCH);
votebg = W_CachePatchName(va("%s%d", tempPrefix, nextframe), PU_PATCH);
Y_DrawVoteBackground(votebg);
Y_VoteBackgroundDrawer(votebg);
if (renderisnewtic && (votetic % 2 == 0) && !paused)
currentAnimFrame = (nextframe > tempFoundAnimVoteFrames) ? 0 : nextframe;
VoteScreen.currentAnimFrame = (nextframe > tempfoundAnimLuaVoteFrames) ? 0 : nextframe;
}
//
// Y_DrawVoteScreenPatch
//
static void Y_DrawVoteScreenPatch(void)
{
patch_t *votebg = NULL;
const boolean widescreen = (vid.width / vid.dupx > 320);
if (foundAnimVoteWideFrames || foundAnimVoteFrames)
if (VoteScreen.foundLuaVoteWideFrames || VoteScreen.foundLuaVoteFrames)
{
Y_DrawAnimatedVoteScreenPatch((foundAnimVoteWideFrames && widescreen));
Y_DrawLuaVoteScreenPatch(((widescreen && VoteScreen.foundLuaVoteWideFrames) || !VoteScreen.foundLuaVoteFrames));
return;
}
votebg = bgpatch; // non widescreen patch
// non widescreen patch
votebg = VoteScreen.bgpatch;
UINT8 prefgametype = (votelevels[0][1] & ~0x80);
const boolean widebgreplaced = (prefgametype == GT_MATCH) ? widebattlereplaced : wideracereplaced;
const boolean bgreplaced = (prefgametype == GT_MATCH) ? battlereplaced : racereplaced;
const boolean widebgreplaced = (prefgametype == GT_MATCH) ? VoteScreen.replaced.widebattle : VoteScreen.replaced.widerace;
const boolean bgreplaced = (prefgametype == GT_MATCH) ? VoteScreen.replaced.battle : VoteScreen.replaced.race;
// we check a bunch of stuff to always have a "valid" fallback
if ((widescreen && (widebgreplaced || !bgreplaced))
|| (!widescreen && (widebgreplaced && !bgreplaced)))
{
votebg = widebgpatch;
votebg = VoteScreen.widebgpatch; // widescreen patch
}
Y_DrawVoteBackground(votebg);
Y_VoteBackgroundDrawer(votebg);
}
//
@@ -1037,7 +1038,7 @@ void Y_VoteDrawer(void)
if (i == 3)
{
str = "RANDOM";
pic = randomlvl;
pic = VoteScreen.randomlvl;
}
else
{
@@ -1061,7 +1062,7 @@ void Y_VoteDrawer(void)
if (!splitscreen)
{
thiscurs = cursor;
thiscurs = VoteScreen.cursor[0];
p = consoleplayer;
color = levelinfo[i].gtc;
colormap = NULL;
@@ -1071,19 +1072,19 @@ void Y_VoteDrawer(void)
switch (j)
{
case 1:
thiscurs = cursor2;
thiscurs = VoteScreen.cursor[2];
p = displayplayers[1];
break;
case 2:
thiscurs = cursor3;
thiscurs = VoteScreen.cursor[3];
p = displayplayers[2];
break;
case 3:
thiscurs = cursor4;
thiscurs = VoteScreen.cursor[4];
p = displayplayers[3];
break;
default:
thiscurs = cursor1;
thiscurs = VoteScreen.cursor[1];
p = displayplayers[0];
break;
}
@@ -1111,7 +1112,7 @@ void Y_VoteDrawer(void)
else
{
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, V_FLIP|V_SNAPTORIGHT, pic, 0);
V_DrawFixedPatch((BASEVIDWIDTH-60)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, V_SNAPTORIGHT, rubyicon, NULL);
V_DrawFixedPatch((BASEVIDWIDTH-60)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, V_SNAPTORIGHT, VoteScreen.rubyicon, NULL);
}
V_DrawRightAlignedThinString(BASEVIDWIDTH-21, 40+y, V_SNAPTORIGHT|V_6WIDTHSPACE, str);
@@ -1135,7 +1136,7 @@ void Y_VoteDrawer(void)
else
{
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, y<<FRACBITS, FRACUNIT/4, V_FLIP|V_SNAPTORIGHT, pic, 0);
V_DrawFixedPatch((BASEVIDWIDTH-40)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTORIGHT, rubyicon, NULL);
V_DrawFixedPatch((BASEVIDWIDTH-40)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTORIGHT, VoteScreen.rubyicon, NULL);
}
if (levelinfo[i].gts)
@@ -1164,13 +1165,13 @@ void Y_VoteDrawer(void)
patch_t *pic;
if (votes[i] >= 3 && (i != pickedvote || voteendtic == -1))
pic = randomlvl;
pic = VoteScreen.randomlvl;
else
pic = levelinfo[votes[i]].pic;
if (!timer && i == voteclient.ranim)
{
V_DrawScaledPatch(x-18, y+9, V_SNAPTOLEFT, cursor);
V_DrawScaledPatch(x-18, y+9, V_SNAPTOLEFT, VoteScreen.cursor[0]);
if (voteendtic != -1 && !(votetic % 4))
V_DrawFill(x-1, y-1, 42, 27, 120|V_SNAPTOLEFT);
else
@@ -1182,7 +1183,7 @@ void Y_VoteDrawer(void)
else
{
V_DrawFixedPatch((x+40)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, V_SNAPTOLEFT|V_FLIP, pic, 0);
V_DrawFixedPatch((x+20)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTOLEFT, rubyicon, NULL);
V_DrawFixedPatch((x+20)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTOLEFT, VoteScreen.rubyicon, NULL);
}
if (levelinfo[votes[i]].gts)
@@ -1471,10 +1472,28 @@ void Y_VoteTicker(void)
//
// MK online style voting screen, appears after intermission
//
static void Y_InitVoteDrawing(void)
{
if (dedicated)
return;
// setup the background patches
Y_VoteScreenCheck();
VoteScreen.cursor[0] = W_CachePatchName("M_CURSOR", PU_PATCH);
VoteScreen.cursor[1] = W_CachePatchName("P1CURSOR", PU_PATCH);
VoteScreen.cursor[2] = W_CachePatchName("P2CURSOR", PU_PATCH);
VoteScreen.cursor[3] = W_CachePatchName("P3CURSOR", PU_PATCH);
VoteScreen.cursor[4] = W_CachePatchName("P4CURSOR", PU_PATCH);
VoteScreen.randomlvl = W_CachePatchName("RANDOMLV", PU_PATCH);
VoteScreen.rubyicon = W_CachePatchName("RUBYICON", PU_PATCH);
}
void Y_StartVote(void)
{
INT32 i = 0;
UINT8 prefgametype = (votelevels[0][1] & ~0x80);
votetic = -1;
@@ -1483,17 +1502,8 @@ void Y_StartVote(void)
I_Error("voteendtic is dirty");
#endif
Y_AnimatedVoteScreenCheck();
widebgpatch = W_CachePatchName(((prefgametype == GT_MATCH) ? "BATTLSCW" : "INTERSCW"), PU_PATCH);
bgpatch = W_CachePatchName(((prefgametype == GT_MATCH) ? "BATTLSCR" : "INTERSCR"), PU_PATCH);
cursor = W_CachePatchName("M_CURSOR", PU_PATCH);
cursor1 = W_CachePatchName("P1CURSOR", PU_PATCH);
cursor2 = W_CachePatchName("P2CURSOR", PU_PATCH);
cursor3 = W_CachePatchName("P3CURSOR", PU_PATCH);
cursor4 = W_CachePatchName("P4CURSOR", PU_PATCH);
randomlvl = W_CachePatchName("RANDOMLV", PU_PATCH);
rubyicon = W_CachePatchName("RUBYICON", PU_PATCH);
// cache vote patches
Y_InitVoteDrawing();
timer = cv_votetime.value*TICRATE;
pickedvote = -1;
@@ -1559,11 +1569,14 @@ void Y_StartVote(void)
levelinfo[i].gts = NULL;
// set up the pic
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(votelevels[i][0]+1)));
if (lumpnum != LUMPERROR)
levelinfo[i].pic = W_CachePatchName(va("%sP", G_BuildMapName(votelevels[i][0]+1)), PU_PATCH);
else
levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_PATCH);
if (!dedicated)
{
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(votelevels[i][0]+1)));
if (lumpnum != LUMPERROR)
levelinfo[i].pic = W_CachePatchName(va("%sP", G_BuildMapName(votelevels[i][0]+1)), PU_PATCH);
else
levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_PATCH);
}
}
voteclient.loaded = true;
@@ -1588,18 +1601,18 @@ static void Y_UnloadVoteData(void)
{
voteclient.loaded = false;
if (rendermode != render_soft)
if (dedicated)
return;
UNLOAD(widebgpatch);
UNLOAD(bgpatch);
UNLOAD(cursor);
UNLOAD(cursor1);
UNLOAD(cursor2);
UNLOAD(cursor3);
UNLOAD(cursor4);
UNLOAD(randomlvl);
UNLOAD(rubyicon);
UNLOAD(VoteScreen.widebgpatch);
UNLOAD(VoteScreen.bgpatch);
UNLOAD(VoteScreen.cursor[0]);
UNLOAD(VoteScreen.cursor[1]);
UNLOAD(VoteScreen.cursor[2]);
UNLOAD(VoteScreen.cursor[3]);
UNLOAD(VoteScreen.cursor[4]);
UNLOAD(VoteScreen.randomlvl);
UNLOAD(VoteScreen.rubyicon);
UNLOAD(levelinfo[3].pic);
UNLOAD(levelinfo[2].pic);
+34 -1
View File
@@ -10,7 +10,6 @@
/// \brief Tally screens, or "Intermissions" as they were formally called in Doom
extern boolean usebuffer;
extern char *luaVoteScreen;
void Y_IntermissionDrawer(void);
void Y_Ticker(void);
@@ -55,3 +54,37 @@ typedef enum
int_classicrace, // Competition
} intertype_t;
extern intertype_t intertype;
// Votescreen stuff
typedef struct
{
boolean race; // non lua race patch replaced
boolean widerace; // non lua widescreen race patch replaced
boolean battle; // non lua battle patch replaced
boolean widebattle; // non lua widescreen battle patch replaced
} votereplace_t;
// VEXTRN - Vote (V) Extra (EXT) Race (R) Normal (N - Normal sized patch)
// VEXTRW - Vote (V) Extra (EXT) Race (R) Normal (W - Wide patch)
// VEXTBN - Vote (V) Extra (EXT) Battle (B) Normal (N - Normal sized patch)
// VEXTBW - Vote (V) Extra (EXT) Battle (B) Normal (W - Wide patch)
typedef struct
{
char Prefix[5]; // Race = INTSX, Battle = BTLSX
char luaPrefix[5]; // prefix for lua votescreens
INT32 currentAnimFrame; // current animated background frame
INT32 foundLuaVoteFrames; // normal lua patch frames
INT32 foundLuaVoteWideFrames; // widescreen lua patch frames
votereplace_t replaced; // checks which non lua patch has been replaced
patch_t *bgpatch; // votebackground patch
patch_t *widebgpatch; // wide votebackground patch
patch_t *cursor[5]; // cursor patches
patch_t *randomlvl; // randomlevel patch
patch_t *rubyicon; // encore ruby patch
} votescreen_t;
extern votescreen_t VoteScreen;