mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-24 00:02:43 +02:00
Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-debugger
This commit is contained in:
commit
11fd86002b
45 files changed
+805
-110
No files matched your search
@@ -116,14 +116,23 @@ else
|
||||
endif
|
||||
|
||||
VERSION_HASH := $(shell git rev-parse --short HEAD)
|
||||
VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
VERSION_TARGET := $(TARGET_PLATFORM)
|
||||
VERSION_ROMID := $(ROMID)
|
||||
|
||||
ifeq ($(VERSION_BRANCH),)
|
||||
VERSION_BRANCH := port-custom
|
||||
endif
|
||||
ifeq ($(VERSION_BRANCH),HEAD)
|
||||
VERSION_BRANCH := port-custom
|
||||
endif
|
||||
|
||||
DEFINES := \
|
||||
VERSION=$(VERSION) \
|
||||
VERSION_HASH=\"$(VERSION_HASH)\" \
|
||||
VERSION_TARGET=\"$(VERSION_TARGET)\" \
|
||||
VERSION_ROMID=\"$(VERSION_ROMID)\" \
|
||||
VERSION_BRANCH=\"$(VERSION_BRANCH)\" \
|
||||
MATCHING=0 \
|
||||
PAL=$(IS_PAL) \
|
||||
PIRACYCHECKS=0 \
|
||||
@@ -297,6 +306,9 @@ $(G_DIR)/tiles/%.h: $(A_DIR)/tiles/%.json
|
||||
|
||||
$(BIN): $(O_FILES)
|
||||
$(LD) $(COMMON_CFLAGS) $(OPT_LVL) -o $(BIN) $^ $(LDFLAGS)
|
||||
ifneq ($(CV2PDB),)
|
||||
$(CV2PDB) $(BIN)
|
||||
endif
|
||||
|
||||
$(B_DIR)/%.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
|
||||
@@ -30,9 +30,9 @@ There are minor graphics- and gameplay-related issues, and possibly occasional c
|
||||
* fixes for a couple original bugs and crashes;
|
||||
* basic mod support, currently enough to load a few custom levels;
|
||||
* slightly expanded memory heap size;
|
||||
* experimental uncapped framerate support:
|
||||
* experimental high framerate support (up to 240 FPS):
|
||||
* set `Game.TickRateDivisor` to `0` in `pd.ini` to activate;
|
||||
* in practice the game will have issues running faster than ~150 FPS, so use VSync or `Video.FramerateLimit` to cap it.
|
||||
* in practice the game will have issues running faster than ~165 FPS, so use VSync or `Video.FramerateLimit` to cap it.
|
||||
|
||||
Currently only 32-bit platforms are supported, namely x86 Windows and Linux.
|
||||
Note that 32-bit binaries will still work on 64-bit versions of those platforms,
|
||||
@@ -44,6 +44,8 @@ Latest [automatic builds](https://github.com/fgsfdsfgs/perfect_dark/actions) for
|
||||
* [i686-windows](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-windows.zip)
|
||||
* [i686-linux](https://nightly.link/fgsfdsfgs/perfect_dark/workflows/c-cpp/port/pd-i686-linux.zip)
|
||||
|
||||
If you are looking for netplay builds (the `port-net` branch), see [this link](https://github.com/fgsfdsfgs/perfect_dark/blob/port-net/README.md#download).
|
||||
|
||||
## Running
|
||||
|
||||
You must already have a Perfect Dark ROM to run the game, as specified above.
|
||||
@@ -97,7 +99,7 @@ Controls can be rebound in `pd.ini`. Default control scheme is as follows:
|
||||
|
||||
### Linux
|
||||
|
||||
1. Ensure you have gcc, g++ and 32-bit versions of SDL2, libGL and ZLib installed on your system.
|
||||
1. Ensure you have gcc, g++ (version 10.0+) and 32-bit versions of SDL2 (version 2.0.12+), libGL and ZLib installed on your system.
|
||||
* On a 64-bit system you also need to have `gcc-multilib` and `g++-multilib` (or your distro's analogues) installed.
|
||||
2. Run the following command in the `perfect_dark` directory:
|
||||
* On a 64-bit system: ```make -f Makefile.port TARGET_PLATFORM=i686-linux```
|
||||
|
||||
@@ -31,7 +31,7 @@ extern float gfx_current_native_aspect; // The aspect ratio of the above mode
|
||||
extern bool gfx_framebuffers_enabled;
|
||||
|
||||
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name,
|
||||
bool start_in_fullscreen, uint32_t width, uint32_t height,
|
||||
bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height,
|
||||
uint32_t posX, uint32_t posY);
|
||||
void gfx_destroy(void);
|
||||
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
|
||||
|
||||
+11
-17
@@ -396,25 +396,17 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
|
||||
if (cc_features.opt_blur) {
|
||||
// blur filter, used for menu backgrounds
|
||||
// used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it
|
||||
// used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers
|
||||
append_line(fs_buf, &fs_len, R"(
|
||||
const vec4 blurOffsets = vec4(-1.5, -0.5, +0.5, +1.5);
|
||||
const mat4 blurWeights = mat4(
|
||||
0.009947, 0.009641, 0.008778, 0.007509,
|
||||
0.009641, 0.009345, 0.008508, 0.007278,
|
||||
0.008778, 0.008508, 0.007747, 0.006626,
|
||||
0.007509, 0.007278, 0.006626, 0.005668
|
||||
);
|
||||
lowp vec4 hookTexture2D(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {
|
||||
lowp vec4 color = vec4(0.0);
|
||||
lowp float wacc = 0.0;
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
vec2 ofs = vec2(blurOffsets[x], blurOffsets[y]) / texSize;
|
||||
wacc += blurWeights[x][y];
|
||||
color += texture2D(tex, texCoord + ofs) * blurWeights[x][y];
|
||||
}
|
||||
lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) {
|
||||
lowp vec4 cw = vec4(0.0);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
vec2 xy = vec2(float(i & 3), float(i >> 2));
|
||||
lowp float w = 0.009947 - length(xy) * 0.001;
|
||||
cw += vec4(texture2D(t, uv + (vec2(-1.5) + xy) / tsize).rgb * w, w);
|
||||
}
|
||||
return vec4(color.rgb / wacc, 1.0);
|
||||
return vec4(cw.rgb / cw.a, 1.0);
|
||||
})"
|
||||
);
|
||||
} else if (current_filter_mode == FILTER_THREE_POINT) {
|
||||
@@ -589,6 +581,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length);
|
||||
char error_log[1024];
|
||||
glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]);
|
||||
sysLogPrintf(LOG_ERROR, "Failed to compile this vertex shader (ID %llx, %x):\n%s", shader_id0, shader_id1, vs_buf);
|
||||
sysFatalError("Vertex shader compilation failed:\n%s", error_log);
|
||||
}
|
||||
|
||||
@@ -601,6 +594,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
||||
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
|
||||
char error_log[1024];
|
||||
glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]);
|
||||
sysLogPrintf(LOG_ERROR, "Failed to compile this fragment shader (ID %llx, %x):\n%s", shader_id0, shader_id1, fs_buf);
|
||||
sysFatalError("Fragment shader compilation failed:\n%s", error_log);
|
||||
}
|
||||
|
||||
|
||||
@@ -2699,10 +2699,10 @@ extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p
|
||||
}
|
||||
|
||||
extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name,
|
||||
bool start_in_fullscreen, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) {
|
||||
bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) {
|
||||
gfx_wapi = wapi;
|
||||
gfx_rapi = rapi;
|
||||
gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, width, height, posX, posY);
|
||||
gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, start_maximized, width, height, posX, posY);
|
||||
gfx_rapi->init();
|
||||
gfx_rapi->update_framebuffer_parameters(0, width, height, 1, false, true, true, true);
|
||||
gfx_current_dimensions.internal_mul = 1;
|
||||
|
||||
@@ -36,6 +36,7 @@ static bool vsync_enabled = true;
|
||||
static int window_width = DESIRED_SCREEN_WIDTH;
|
||||
static int window_height = DESIRED_SCREEN_HEIGHT;
|
||||
static bool fullscreen_state;
|
||||
static bool maximized_state;
|
||||
static bool is_running = true;
|
||||
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
|
||||
|
||||
@@ -76,6 +77,18 @@ static void set_fullscreen(bool on, bool call_callback) {
|
||||
}
|
||||
}
|
||||
|
||||
static void set_maximize_window(bool on) {
|
||||
if (maximized_state == on) {
|
||||
return;
|
||||
}
|
||||
maximized_state = on;
|
||||
if (on) {
|
||||
SDL_MaximizeWindow(wnd);
|
||||
} else {
|
||||
SDL_RestoreWindow (wnd);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
|
||||
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
|
||||
|
||||
@@ -84,7 +97,7 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
|
||||
*refresh_rate = mode.refresh_rate;
|
||||
}
|
||||
|
||||
static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width,
|
||||
static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width,
|
||||
uint32_t height, int32_t posX, int32_t posY) {
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
@@ -111,6 +124,7 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
|
||||
}
|
||||
|
||||
const Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
|
||||
|
||||
wnd = SDL_CreateWindow(title, posX, posY, window_width, window_height, flags);
|
||||
if (!wnd) {
|
||||
sysFatalError("Could not open SDL window:\n%s", SDL_GetError());
|
||||
@@ -181,6 +195,7 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s
|
||||
}
|
||||
#endif
|
||||
|
||||
set_maximize_window(start_maximized);
|
||||
set_fullscreen(start_in_fullscreen, false);
|
||||
}
|
||||
|
||||
@@ -196,6 +211,10 @@ static void gfx_sdl_set_fullscreen(bool enable) {
|
||||
set_fullscreen(enable, true);
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_maximize_window(bool enable) {
|
||||
set_maximize_window(enable);
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_cursor_visibility(bool visible) {
|
||||
if (visible) {
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
@@ -291,7 +310,7 @@ static void gfx_sdl_set_target_fps(int fps) {
|
||||
}
|
||||
|
||||
static bool gfx_sdl_can_disable_vsync(void) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *gfx_sdl_get_window_handle(void) {
|
||||
@@ -302,9 +321,13 @@ static void gfx_sdl_set_window_title(const char *title) {
|
||||
SDL_SetWindowTitle(wnd, title);
|
||||
}
|
||||
|
||||
static void gfx_sdl_set_swap_interval(int interval) {
|
||||
SDL_GL_SetSwapInterval(interval);
|
||||
vsync_enabled = (interval != 0);
|
||||
static bool gfx_sdl_set_swap_interval(int interval) {
|
||||
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
|
||||
vsync_enabled = success && (interval != 0);
|
||||
if (!success) {
|
||||
sysLogPrintf(LOG_WARNING, "SDL: failed to set vsync %d: %s", interval, SDL_GetError());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_sdl = {
|
||||
@@ -312,6 +335,7 @@ struct GfxWindowManagerAPI gfx_sdl = {
|
||||
gfx_sdl_close,
|
||||
gfx_sdl_set_fullscreen_changed_callback,
|
||||
gfx_sdl_set_fullscreen,
|
||||
gfx_sdl_set_maximize_window,
|
||||
gfx_sdl_get_active_window_refresh_rate,
|
||||
gfx_sdl_set_cursor_visibility,
|
||||
gfx_sdl_get_dimensions,
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
struct GfxWindowManagerAPI {
|
||||
void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, uint32_t width,
|
||||
void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width,
|
||||
uint32_t height, int32_t posX, int32_t posY);
|
||||
void (*close)(void);
|
||||
void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen));
|
||||
void (*set_fullscreen)(bool enable);
|
||||
void (*set_maximize)(bool enable);
|
||||
void (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
|
||||
void (*set_cursor_visibility)(bool visible);
|
||||
void (*get_dimensions)(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY);
|
||||
@@ -22,7 +23,7 @@ struct GfxWindowManagerAPI {
|
||||
bool (*can_disable_vsync)(void);
|
||||
void *(*get_window_handle)(void);
|
||||
void (*set_window_title)(const char *);
|
||||
void (*set_swap_interval)(int);
|
||||
bool (*set_swap_interval)(int);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -24,6 +24,7 @@ u64 sysGetMicroseconds(void);
|
||||
|
||||
void sysFatalError(const char *fmt, ...) __attribute__((noreturn));
|
||||
|
||||
s32 sysLogIsOpen(void);
|
||||
void sysLogPrintf(s32 level, const char *fmt, ...);
|
||||
|
||||
void sysGetExecutablePath(char *outPath, const u32 outLen);
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
#include <PR/ultratypes.h>
|
||||
#include <PR/gbi.h>
|
||||
|
||||
// maximum framerate; if the game runs faster than this, things will break
|
||||
#if PAL
|
||||
#define VIDEO_MAX_FPS 200
|
||||
#else
|
||||
#define VIDEO_MAX_FPS 240
|
||||
#endif
|
||||
|
||||
s32 videoInit(void);
|
||||
void videoStartFrame(void);
|
||||
void videoSubmitCommands(Gfx *cmds);
|
||||
@@ -20,6 +27,8 @@ s32 videoGetWidth(void);
|
||||
s32 videoGetHeight(void);
|
||||
f32 videoGetAspect(void);
|
||||
s32 videoGetFullscreen(void);
|
||||
s32 videoGetMaximizeWindow(void);
|
||||
void videoSetMaximizeWindow(s32 fs);
|
||||
u32 videoGetTextureFilter(void);
|
||||
u32 videoGetTextureFilter2D(void);
|
||||
|
||||
|
||||
+35
-4
@@ -16,6 +16,7 @@ typedef enum {
|
||||
CFG_NONE,
|
||||
CFG_S32,
|
||||
CFG_F32,
|
||||
CFG_U32,
|
||||
CFG_STR
|
||||
} configtype;
|
||||
|
||||
@@ -27,6 +28,7 @@ struct configentry {
|
||||
union {
|
||||
struct { f32 min_f32, max_f32; };
|
||||
struct { s32 min_s32, max_s32; };
|
||||
struct { u32 min_u32, max_u32; };
|
||||
u32 max_str;
|
||||
};
|
||||
} settings[CONFIG_MAX_SETTINGS];
|
||||
@@ -38,11 +40,15 @@ static inline s32 configClampInt(s32 val, s32 min, s32 max)
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline f32 configClampFloat(f32 val, f32 min, f32 max)
|
||||
static inline u32 configClampUInt(u32 val, u32 min, u32 max)
|
||||
{
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline f32 configClampFloat(f32 val, f32 min, f32 max)
|
||||
{
|
||||
return (val < min) ? min : ((val > max) ? max : val);
|
||||
}
|
||||
|
||||
static inline struct configentry *configFindEntry(const char *key)
|
||||
{
|
||||
@@ -101,6 +107,17 @@ void configRegisterInt(const char *key, s32 *var, s32 min, s32 max)
|
||||
}
|
||||
}
|
||||
|
||||
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max)
|
||||
{
|
||||
struct configentry* cfg = configFindOrAddEntry(key);
|
||||
if (cfg) {
|
||||
cfg->type = CFG_U32;
|
||||
cfg->ptr = var;
|
||||
cfg->min_u32 = min;
|
||||
cfg->max_u32 = max;
|
||||
}
|
||||
}
|
||||
|
||||
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max)
|
||||
{
|
||||
struct configentry *cfg = configFindOrAddEntry(key);
|
||||
@@ -129,21 +146,29 @@ static void configSetFromString(const char *key, const char *val)
|
||||
|
||||
s32 tmp_s32;
|
||||
f32 tmp_f32;
|
||||
u32 tmp_u32;
|
||||
switch (cfg->type) {
|
||||
case CFG_S32:
|
||||
tmp_s32 = atoi(val);
|
||||
tmp_s32 = strtol(val, NULL, 0);
|
||||
if (cfg->min_s32 < cfg->max_s32) {
|
||||
tmp_f32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32);
|
||||
tmp_s32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32);
|
||||
}
|
||||
*(s32 *)cfg->ptr = tmp_s32;
|
||||
break;
|
||||
case CFG_F32:
|
||||
tmp_f32 = atof(val);
|
||||
tmp_f32 = strtof(val, NULL);
|
||||
if (cfg->min_f32 < cfg->max_f32) {
|
||||
tmp_f32 = configClampFloat(tmp_f32, cfg->min_f32, cfg->max_f32);
|
||||
}
|
||||
*(f32 *)cfg->ptr = tmp_f32;
|
||||
break;
|
||||
case CFG_U32:
|
||||
tmp_u32 = strtoul(val, NULL, 0);
|
||||
if (cfg->min_u32 < cfg->max_u32) {
|
||||
tmp_u32 = configClampUInt(tmp_u32, cfg->min_u32, cfg->max_u32);
|
||||
}
|
||||
*(u32*)cfg->ptr = tmp_u32;
|
||||
break;
|
||||
case CFG_STR:
|
||||
strncpy(cfg->ptr, val, cfg->max_str ? cfg->max_str - 1 : 4096);
|
||||
break;
|
||||
@@ -167,6 +192,12 @@ static void configSaveEntry(struct configentry *cfg, FILE *f)
|
||||
}
|
||||
fprintf(f, "%s=%f\n", cfg->key + cfg->seclen + 1, *(f32 *)cfg->ptr);
|
||||
break;
|
||||
case CFG_U32:
|
||||
if (cfg->min_u32 < cfg->max_u32) {
|
||||
*(u32*)cfg->ptr = configClampUInt(*(u32*)cfg->ptr, cfg->min_u32, cfg->max_u32);
|
||||
}
|
||||
fprintf(f, "%s=%u\n", cfg->key + cfg->seclen + 1, *(u32 *)cfg->ptr);
|
||||
break;
|
||||
case CFG_STR:
|
||||
fprintf(f, "%s=%s\n", cfg->key + cfg->seclen + 1, (char *)cfg->ptr);
|
||||
break;
|
||||
|
||||
+17
-3
@@ -10,7 +10,8 @@
|
||||
#include "system.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define CRASH_MAX_MSG 4096
|
||||
#define CRASH_LOG_FNAME "pd.crash.log"
|
||||
#define CRASH_MAX_MSG 8192
|
||||
#define CRASH_MAX_SYM 256
|
||||
#define CRASH_MAX_FRAMES 32
|
||||
#define CRASH_MSG(...) \
|
||||
@@ -79,8 +80,8 @@ static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo)
|
||||
if (SymGetLineFromAddr64(process, (uintptr_t)exinfo->ExceptionRecord->ExceptionAddress, &disp, &line)) {
|
||||
CRASH_MSG(": %s:%lu+%lu", line.FileName, line.LineNumber, disp);
|
||||
}
|
||||
CRASH_MSG("\nMODULE: %p\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress));
|
||||
CRASH_MSG("MAIN MODULE: %p\n", crashGetModuleBase(crashInit));
|
||||
CRASH_MSG("\nMODULE: [%p]\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress));
|
||||
CRASH_MSG("MAIN MODULE: [%p]\n", crashGetModuleBase(crashInit));
|
||||
CRASH_MSG("\nBACKTRACE:\n");
|
||||
|
||||
char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)];
|
||||
@@ -99,6 +100,10 @@ static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo)
|
||||
|
||||
if (SymFromAddr(process, stackframe.AddrPC.Offset, &disp64, sym)) {
|
||||
CRASH_MSG(": %s+%llu", sym->Name, disp64);
|
||||
} else if (process, stackframe.AddrPC.Offset) {
|
||||
const uintptr_t modbase = (uintptr_t)crashGetModuleBase((void *)(uintptr_t)stackframe.AddrPC.Offset);
|
||||
const uintptr_t modofs = (uintptr_t)stackframe.AddrPC.Offset - modbase;
|
||||
CRASH_MSG(": [%p]+%p", (void *)modbase, (void *)modofs);
|
||||
}
|
||||
|
||||
if(SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &disp, &line)) {
|
||||
@@ -135,6 +140,15 @@ static long __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
|
||||
|
||||
crashStackTrace(msg, exinfo);
|
||||
|
||||
// open log file for the crash dump if one hasn't been opened yet
|
||||
if (!sysLogIsOpen()) {
|
||||
FILE *f = fopen(CRASH_LOG_FNAME, "wb");
|
||||
if (f) {
|
||||
fprintf(f, "Crash!\n\n%s", msg);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
sysFatalError("Crash!\n\n%s", msg);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
|
||||
@@ -851,6 +851,10 @@ void inputRumble(s32 idx, f32 strength, f32 time)
|
||||
return;
|
||||
}
|
||||
|
||||
if (padsCfg[idx].rumbleScale <= 0.f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (padsCfg[idx].rumbleOn) {
|
||||
strength *= padsCfg[idx].rumbleScale;
|
||||
if (strength <= 0.f) {
|
||||
|
||||
@@ -39,6 +39,8 @@ s32 g_TickRateDiv = 1;
|
||||
|
||||
s32 g_SkipIntro = false;
|
||||
|
||||
s32 g_FileAutoSelect = -1;
|
||||
|
||||
extern s32 g_StageNum;
|
||||
|
||||
s32 bootGetMemSize(void)
|
||||
@@ -143,6 +145,11 @@ int main(int argc, const char **argv)
|
||||
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
|
||||
}
|
||||
|
||||
g_FileAutoSelect = sysArgGetInt("--profile", -1);
|
||||
if (g_FileAutoSelect >= 0) {
|
||||
sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect);
|
||||
}
|
||||
|
||||
mainProc();
|
||||
|
||||
return 0;
|
||||
@@ -156,6 +163,7 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
|
||||
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
|
||||
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
|
||||
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
|
||||
for (s32 j = 0; j < MAX_PLAYERS; ++j) {
|
||||
const s32 i = j + 1;
|
||||
configRegisterFloat(strFmt("Game.Player%d.FovY", i), &g_PlayerExtCfg[j].fovy, 5.f, 175.f);
|
||||
@@ -167,5 +175,8 @@ PD_CONSTRUCTOR static void gameConfigInit(void)
|
||||
configRegisterFloat(strFmt("Game.Player%d.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f);
|
||||
configRegisterInt(strFmt("Game.Player%d.CrouchMode", i), &g_PlayerExtCfg[j].crouchmode, 0, CROUCHMODE_TOGGLE_ANALOG);
|
||||
configRegisterInt(strFmt("Game.Player%d.ExtendedControls", i), &g_PlayerExtCfg[j].extcontrols, 0, 1);
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairColour", i), &g_PlayerExtCfg[j].crosshaircolour, 0, 0xFFFFFFFF);
|
||||
configRegisterUInt(strFmt("Game.Player%d.CrosshairSize", i), &g_PlayerExtCfg[j].crosshairsize, 0, 4);
|
||||
configRegisterInt(strFmt("Game.Player%d.CrosshairHealth", i), &g_PlayerExtCfg[j].crosshairhealth, 0, CROSSHAIR_HEALTH_ON_WHITE);
|
||||
}
|
||||
}
|
||||
@@ -652,6 +652,19 @@ static MenuItemHandlerResult menuhandlerFullScreen(s32 operation, struct menuite
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return videoGetMaximizeWindow();
|
||||
case MENUOP_SET:
|
||||
videoSetMaximizeWindow(data->checkbox.value);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
@@ -678,6 +691,19 @@ static MenuItemHandlerResult menuhandlerTexFilter2D(s32 operation, struct menuit
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerGeMuzzleFlashes(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GET:
|
||||
return g_BgunGeMuzzleFlashes;
|
||||
case MENUOP_SET:
|
||||
g_BgunGeMuzzleFlashes = data->checkbox.value;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCenterHUD(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
@@ -735,6 +761,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
0,
|
||||
menuhandlerFullScreen,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Maximize Window",
|
||||
0,
|
||||
menuhandlerMaximizeWindow,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
@@ -751,6 +785,14 @@ struct menuitem g_ExtendedVideoMenuItems[] = {
|
||||
0,
|
||||
menuhandlerTexFilter2D,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"GE64-style Muzzle Flashes",
|
||||
0,
|
||||
menuhandlerGeMuzzleFlashes,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
@@ -903,6 +945,202 @@ static MenuItemHandlerResult menuhandlerCrosshairSway(s32 operation, struct menu
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairR(s32 operation, struct menuitem* item, union handlerdata* data)
|
||||
{
|
||||
u32 newColor;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 24) & 0xFF;
|
||||
break;
|
||||
|
||||
case MENUOP_SET:
|
||||
newColor = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFFFF) | data->slider.value << 24;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairG(s32 operation, struct menuitem* item, union handlerdata* data)
|
||||
{
|
||||
u32 newColor;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 16) & 0xFF;
|
||||
break;
|
||||
|
||||
case MENUOP_SET:
|
||||
newColor = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFF00FFFF) | data->slider.value << 16;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairB(s32 operation, struct menuitem* item, union handlerdata* data)
|
||||
{
|
||||
u32 newColor;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour >> 8) & 0xFF;
|
||||
break;
|
||||
|
||||
case MENUOP_SET:
|
||||
newColor = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFF00FF) | data->slider.value << 8;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairA(s32 operation, struct menuitem* item, union handlerdata* data)
|
||||
{
|
||||
u32 newColor;
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFF;
|
||||
break;
|
||||
|
||||
case MENUOP_SET:
|
||||
newColor = (g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour & 0xFFFFFF00) | data->slider.value;
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour = newColor;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairColorPreview(s32 operation, struct menuitem* item, union handlerdata* data)
|
||||
{
|
||||
if (operation == MENUOP_GETCOLOUR) {
|
||||
data->label.colour1 = g_PlayerExtCfg[g_ExtMenuPlayer].crosshaircolour;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairSize(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
switch (operation) {
|
||||
case MENUOP_GETSLIDER:
|
||||
data->slider.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshairsize;
|
||||
break;
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshairsize = data->slider.value;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static MenuItemHandlerResult menuhandlerCrosshairHealth(s32 operation, struct menuitem *item, union handlerdata *data)
|
||||
{
|
||||
static const char *opts[] = {
|
||||
"Off",
|
||||
"On (Green)",
|
||||
"On (White)"
|
||||
};
|
||||
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->dropdown.value = ARRAYCOUNT(opts);
|
||||
break;
|
||||
case MENUOP_GETOPTIONTEXT:
|
||||
return (intptr_t)opts[data->dropdown.value];
|
||||
case MENUOP_SET:
|
||||
g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth = data->dropdown.value;
|
||||
break;
|
||||
case MENUOP_GETSELECTEDINDEX:
|
||||
data->dropdown.value = g_PlayerExtCfg[g_ExtMenuPlayer].crosshairhealth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menuitem g_ExtendedGameCrosshairColourMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Red",
|
||||
255,
|
||||
menuhandlerCrosshairR,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Green",
|
||||
255,
|
||||
menuhandlerCrosshairG,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Blue",
|
||||
255,
|
||||
menuhandlerCrosshairB,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Alpha",
|
||||
255,
|
||||
menuhandlerCrosshairA,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_COLORBOX,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
menuhandlerCrosshairColorPreview,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_SELECTABLE_CLOSESDIALOG,
|
||||
L_OPTIONS_213, // "Back"
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
{ MENUITEMTYPE_END },
|
||||
};
|
||||
|
||||
struct menudialogdef g_ExtendedGameCrosshairColourMenuDialog = {
|
||||
MENUDIALOGTYPE_DEFAULT,
|
||||
(uintptr_t)"Crosshair Colour",
|
||||
g_ExtendedGameCrosshairColourMenuItems,
|
||||
NULL,
|
||||
MENUDIALOGFLAG_LITERAL_TEXT,
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct menuitem g_ExtendedGameMenuItems[] = {
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
@@ -928,6 +1166,30 @@ struct menuitem g_ExtendedGameMenuItems[] = {
|
||||
20,
|
||||
menuhandlerCrosshairSway,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SLIDER,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SLIDER_WIDE,
|
||||
(uintptr_t)"Crosshair Size",
|
||||
4,
|
||||
menuhandlerCrosshairSize,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SELECTABLE,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT | MENUITEMFLAG_SELECTABLE_OPENSDIALOG,
|
||||
(uintptr_t)"Crosshair Colour\n",
|
||||
0,
|
||||
(void*)&g_ExtendedGameCrosshairColourMenuDialog,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_DROPDOWN,
|
||||
0,
|
||||
MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Crosshair Colour by Health",
|
||||
0,
|
||||
menuhandlerCrosshairHealth,
|
||||
},
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
|
||||
@@ -105,6 +105,7 @@ bool g_SchedIsFirstTask = true;
|
||||
s32 g_PrevFrameFb = -1;
|
||||
s32 g_BlurFb = -1;
|
||||
s32 g_BlurFbCapTimer = -1;
|
||||
bool g_BlurFbDirty = true;
|
||||
|
||||
void schedSetCrashEnable1(bool enable)
|
||||
{
|
||||
@@ -396,8 +397,12 @@ void schedConsiderScreenshot(void)
|
||||
if (g_BlurFbCapTimer == 0) {
|
||||
videoCopyFramebuffer(g_BlurFb, 0, -1, -1);
|
||||
g_BlurFbCapTimer = -1;
|
||||
g_BlurFbDirty = false;
|
||||
} else if (g_BlurFbCapTimer > 0) {
|
||||
--g_BlurFbCapTimer;
|
||||
} else if (g_BlurFbCapTimer < 0) {
|
||||
// no blur requested this frame, mark blur fb dirty
|
||||
g_BlurFbDirty = true;
|
||||
}
|
||||
|
||||
if (g_MenuData.screenshottimer >= 2) {
|
||||
|
||||
+31
-1
@@ -64,6 +64,13 @@ enum loadsource {
|
||||
SRC_EXTERNAL
|
||||
};
|
||||
|
||||
struct romfilepatch {
|
||||
u32 ofs;
|
||||
u32 len;
|
||||
const char *src;
|
||||
const char *dst;
|
||||
};
|
||||
|
||||
struct romfile {
|
||||
u8 **segstart;
|
||||
u8 **segend;
|
||||
@@ -73,9 +80,21 @@ struct romfile {
|
||||
preprocessfunc preprocess;
|
||||
s32 source; // enum loadsource
|
||||
s32 preprocessed;
|
||||
const struct romfilepatch *patches;
|
||||
u32 numpatches;
|
||||
};
|
||||
|
||||
static struct romfile fileSlots[ROMDATA_MAX_FILES];
|
||||
/* patches for individual files; applied on file load, before preprocFuncs, but */
|
||||
/* after unzip; only applied when loading from a ROM file */
|
||||
static const struct romfilepatch filePatches[] = {
|
||||
/* FILE_USETUPLUE: fixes Jon's double "if what" in Infiltration outro */
|
||||
{ 0x92a2, 1, "\x6c", "\x99" },
|
||||
{ 0x92b0, 1, "\x6c", "\x99" },
|
||||
};
|
||||
|
||||
static struct romfile fileSlots[ROMDATA_MAX_FILES] = {
|
||||
[FILE_USETUPLUE] = { .patches = &filePatches[0], .numpatches = 2 },
|
||||
};
|
||||
|
||||
#define ROMSEG_START(n) _ ## n ## SegmentRomStart
|
||||
#define ROMSEG_END(n) _ ## n ## SegmentRomEnd
|
||||
@@ -409,6 +428,8 @@ u8 *romdataFileLoad(s32 fileNum, u32 *outSize)
|
||||
fileSlots[fileNum].data = out;
|
||||
fileSlots[fileNum].size = size;
|
||||
fileSlots[fileNum].source = SRC_EXTERNAL;
|
||||
// external file; do not apply patches to this
|
||||
fileSlots[fileNum].numpatches = 0;
|
||||
}
|
||||
}
|
||||
// tried and failed, fall back to ROM
|
||||
@@ -435,6 +456,15 @@ void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size)
|
||||
|
||||
if (data && size /* && !fileSlots[fileNum].preprocessed*/) {
|
||||
if (loadType && loadType < (u32)ARRAYCOUNT(filePreprocFuncs) && filePreprocFuncs[loadType]) {
|
||||
// apply patches
|
||||
for (u32 i = 0; i < fileSlots[fileNum].numpatches; ++i) {
|
||||
const struct romfilepatch *p = &fileSlots[fileNum].patches[i];
|
||||
if (!memcmp(data + p->ofs, p->src, p->len)) {
|
||||
memcpy(data + p->ofs, p->dst, p->len);
|
||||
sysLogPrintf(LOG_NOTE, "file %d (%s) patched at offset 0x%x", fileNum, fileSlots[fileNum].name, p->ofs);
|
||||
}
|
||||
}
|
||||
// then preprocess
|
||||
filePreprocFuncs[loadType](data, size);
|
||||
// fileSlots[fileNum].preprocessed = 1;
|
||||
}
|
||||
|
||||
+26
-14
@@ -11,6 +11,7 @@
|
||||
#include "system.h"
|
||||
|
||||
#define LOG_FNAME "pd.log"
|
||||
#define CRASHLOG_FNAME "pd.crash.log"
|
||||
#define USEC_IN_SEC 1000000ULL
|
||||
|
||||
static u64 startTick = 0;
|
||||
@@ -19,6 +20,24 @@ static char logPath[2048];
|
||||
static s32 sysArgc;
|
||||
static const char **sysArgv;
|
||||
|
||||
static inline void sysLogSetPath(const char *fname)
|
||||
{
|
||||
// figure out where the log is and clear it
|
||||
// try working dir first
|
||||
snprintf(logPath, sizeof(logPath), "./%s", fname);
|
||||
FILE *f = fopen(logPath, "wb");
|
||||
if (!f) {
|
||||
// try home dir
|
||||
sysGetHomePath(logPath, sizeof(logPath) - 1);
|
||||
strncat(logPath, "/", sizeof(logPath) - 1);
|
||||
strncat(logPath, fname, sizeof(logPath) - 1);
|
||||
f = fopen(logPath, "wb");
|
||||
}
|
||||
if (f) {
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void sysInitArgs(s32 argc, const char **argv)
|
||||
{
|
||||
sysArgc = argc;
|
||||
@@ -30,23 +49,11 @@ void sysInit(void)
|
||||
startTick = sysGetMicroseconds();
|
||||
|
||||
if (sysArgCheck("--log")) {
|
||||
// figure out where the log is and clear it
|
||||
// try working dir first
|
||||
snprintf(logPath, sizeof(logPath), "./%s", LOG_FNAME);
|
||||
FILE *f = fopen(logPath, "wb");
|
||||
if (!f) {
|
||||
// try home dir
|
||||
sysGetHomePath(logPath, sizeof(logPath) - 1);
|
||||
strncat(logPath, "/" LOG_FNAME, sizeof(logPath) - 1);
|
||||
f = fopen(logPath, "wb");
|
||||
}
|
||||
if (f) {
|
||||
fclose(f);
|
||||
}
|
||||
sysLogSetPath(LOG_FNAME);
|
||||
}
|
||||
|
||||
#ifdef VERSION_HASH
|
||||
sysLogPrintf(LOG_NOTE, "version: " VERSION_HASH " (" VERSION_TARGET ")");
|
||||
sysLogPrintf(LOG_NOTE, "version: " VERSION_BRANCH " " VERSION_HASH " (" VERSION_TARGET ")");
|
||||
#endif
|
||||
|
||||
char timestr[256];
|
||||
@@ -96,6 +103,11 @@ u64 sysGetMicroseconds(void)
|
||||
return ((u64)tv.tv_sec * USEC_IN_SEC + (u64)tv.tv_usec) - startTick;
|
||||
}
|
||||
|
||||
s32 sysLogIsOpen(void)
|
||||
{
|
||||
return (logPath[0] != '\0');
|
||||
}
|
||||
|
||||
void sysLogPrintf(s32 level, const char *fmt, ...)
|
||||
{
|
||||
static const char *prefix[3] = {
|
||||
|
||||
+26
-3
@@ -21,6 +21,7 @@ static s32 vidWidth = 640;
|
||||
static s32 vidHeight = 480;
|
||||
static s32 vidFramebuffers = true;
|
||||
static s32 vidFullscreen = false;
|
||||
static s32 vidMaximize = false;
|
||||
static s32 vidVsync = 1;
|
||||
static s32 vidMSAA = 1;
|
||||
static s32 vidFramerateLimit = 0;
|
||||
@@ -44,9 +45,17 @@ s32 videoInit(void)
|
||||
gfx_framebuffers_enabled = (bool)vidFramebuffers;
|
||||
gfx_msaa_level = vidMSAA;
|
||||
|
||||
gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidWidth, vidHeight, 100, 100);
|
||||
gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100);
|
||||
|
||||
if (!wmAPI->set_swap_interval(vidVsync)) {
|
||||
vidVsync = 0;
|
||||
}
|
||||
|
||||
if (vidVsync == 0 && vidFramerateLimit == 0) {
|
||||
// cap FPS if there's no vsync to prevent the game from exploding
|
||||
vidFramerateLimit = VIDEO_MAX_FPS;
|
||||
}
|
||||
|
||||
wmAPI->set_swap_interval(vidVsync);
|
||||
wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on
|
||||
renderingAPI->set_texture_filter((enum FilteringMode)texFilter);
|
||||
|
||||
@@ -139,6 +148,11 @@ s32 videoGetFullscreen(void)
|
||||
return vidFullscreen;
|
||||
}
|
||||
|
||||
s32 videoGetMaximizeWindow(void)
|
||||
{
|
||||
return vidMaximize;
|
||||
}
|
||||
|
||||
f32 videoGetAspect(void)
|
||||
{
|
||||
return gfx_current_dimensions.aspect_ratio;
|
||||
@@ -168,6 +182,14 @@ void videoSetFullscreen(s32 fs)
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetMaximizeWindow(s32 fs)
|
||||
{
|
||||
if (fs != vidMaximize) {
|
||||
vidMaximize = !!fs;
|
||||
wmAPI->set_maximize(vidMaximize);
|
||||
}
|
||||
}
|
||||
|
||||
void videoSetTextureFilter(u32 filter)
|
||||
{
|
||||
if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT;
|
||||
@@ -224,11 +246,12 @@ void videoFreeCachedTexture(const void *texptr)
|
||||
PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
{
|
||||
configRegisterInt("Video.DefaultFullscreen", &vidFullscreen, 0, 1);
|
||||
configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1);
|
||||
configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767);
|
||||
configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767);
|
||||
configRegisterInt("Video.VSync", &vidVsync, -1, 10);
|
||||
configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1);
|
||||
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, 10000);
|
||||
configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);
|
||||
configRegisterInt("Video.MSAA", &vidMSAA, 1, 16);
|
||||
configRegisterInt("Video.TextureFilter", &texFilter, 0, 2);
|
||||
configRegisterInt("Video.TextureFilter2D", &texFilter2D, 0, 1);
|
||||
|
||||
+9
-21
@@ -90,19 +90,8 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
switch (operation) {
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
// All bots: num bot opponents + all human players
|
||||
s32 count = 0;
|
||||
s32 i;
|
||||
struct chrdata *playerchr = g_Vars.currentplayer->prop->chr;
|
||||
|
||||
for (i = PLAYERCOUNT(); i < g_MpNumChrs; i++) {
|
||||
if (g_MpAllChrPtrs[i]->team != playerchr->team) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
count += PLAYERCOUNT();
|
||||
data->list.value = count;
|
||||
// All bots
|
||||
data->list.value = g_MpNumChrs;
|
||||
} else {
|
||||
// Single bot: All except the bot itself
|
||||
data->list.value = g_MpNumChrs - 1;
|
||||
@@ -125,9 +114,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
chrindex++;
|
||||
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
|
||||
numremaining--;
|
||||
}
|
||||
numremaining--;
|
||||
} else {
|
||||
if (botchr != g_MpAllChrPtrs[chrindex]) {
|
||||
numremaining--;
|
||||
@@ -139,7 +126,9 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
g_AmMenus[g_AmIndex].prevallbots = false;
|
||||
|
||||
for (i = 0; i < g_Vars.currentplayer->numaibuddies; i++) {
|
||||
botApplyAttack(g_MpAllChrPtrs[g_Vars.currentplayer->aibuddynums[i]], g_MpAllChrPtrs[chrindex]->prop);
|
||||
if (g_Vars.currentplayer->aibuddynums[i] != chrindex) {
|
||||
botApplyAttack(g_MpAllChrPtrs[g_Vars.currentplayer->aibuddynums[i]], g_MpAllChrPtrs[chrindex]->prop);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
botApplyAttack(botchr, g_MpAllChrPtrs[chrindex]->prop);
|
||||
@@ -167,9 +156,7 @@ MenuItemHandlerResult amPickTargetMenuList(s32 operation, struct menuitem *item,
|
||||
chrindex++;
|
||||
|
||||
if (g_AmMenus[g_AmIndex].prevallbots) {
|
||||
if (playerchr == g_MpAllChrPtrs[chrindex] || playerchr->team != g_MpAllChrPtrs[chrindex]->team) {
|
||||
numremaining--;
|
||||
}
|
||||
numremaining--;
|
||||
} else {
|
||||
if (botchr != g_MpAllChrPtrs[chrindex]) {
|
||||
numremaining--;
|
||||
@@ -1275,7 +1262,8 @@ Gfx *amRender(Gfx *gdl)
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (PLAYERCOUNT() == 1) {
|
||||
const s32 playercount = PLAYERCOUNT();
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1098,7 +1098,13 @@ void eyespyProcessInput(bool allowbuttons)
|
||||
if (g_Vars.currentplayer->eyespy->bobactive || ABS(g_Vars.currentplayer->eyespy->vel.y) < 0.1f) {
|
||||
g_Vars.currentplayer->eyespy->bobactive = true;
|
||||
g_Vars.currentplayer->eyespy->bobtimer += g_Vars.lvupdate60;
|
||||
#ifdef PLATFORM_N64
|
||||
g_Vars.currentplayer->eyespy->vel.y += 0.025f * g_Vars.currentplayer->eyespy->bobdir;
|
||||
#else
|
||||
// HACK: how do I scale this properly?
|
||||
const f32 scale = (g_Vars.lvupdate60freal <= 1.1f) ? 0.0055f : 0.0125f;
|
||||
g_Vars.currentplayer->eyespy->vel.y += scale * g_Vars.lvupdate60freal * g_Vars.currentplayer->eyespy->bobdir;
|
||||
#endif
|
||||
|
||||
if (g_Vars.currentplayer->eyespy->bobtimer > TICKS(120)) {
|
||||
g_Vars.currentplayer->eyespy->bobtimer = 0;
|
||||
|
||||
+17
-3
@@ -190,6 +190,10 @@ char var800700bc[][10] = {
|
||||
{ 'x','x','x' }, // "xxx"
|
||||
};
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
s32 g_BgunGeMuzzleFlashes = false;
|
||||
#endif
|
||||
|
||||
#if !MATCHING || VERSION >= VERSION_NTSC_1_0
|
||||
void bgunRumble(s32 handnum, s32 weaponnum)
|
||||
{
|
||||
@@ -1911,7 +1915,17 @@ void bgun0f09a6f8(struct handweaponinfo *info, s32 handnum, struct hand *hand, s
|
||||
if (func->flags & FUNCFLAG_NOMUZZLEFLASH) {
|
||||
hand->flashon = false;
|
||||
} else {
|
||||
#ifdef PLATFORM_N64
|
||||
hand->flashon = true;
|
||||
#else
|
||||
if (g_BgunGeMuzzleFlashes) {
|
||||
if (func->type == INVENTORYFUNCTYPE_SHOOT_SINGLE || (hand->shotstotake & 1)) {
|
||||
hand->flashon = true;
|
||||
}
|
||||
} else {
|
||||
hand->flashon = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bgunStartSlide(handnum);
|
||||
@@ -12783,7 +12797,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
gdl = text0f153628(gdl);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
|
||||
}
|
||||
#endif
|
||||
@@ -13037,7 +13051,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL);
|
||||
}
|
||||
#endif
|
||||
@@ -13077,7 +13091,7 @@ Gfx *bgunDrawHud(Gfx *gdl)
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
|
||||
}
|
||||
#endif
|
||||
|
||||
+16
-2
@@ -289,6 +289,14 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
// capture fb at the end of this frame
|
||||
g_BlurFbCapTimer = 0;
|
||||
|
||||
// don't render first blur frame as we haven't captured the fb yet
|
||||
if (g_BlurFbDirty) {
|
||||
return gdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
mainOverrideVariable("sfxxx", &sfxxx);
|
||||
@@ -312,7 +320,6 @@ Gfx *bviewDrawMotionBlur(Gfx *gdl, u32 colour, u32 alpha)
|
||||
viewleft << 2, viewtop << 2, viewleft, viewtop,
|
||||
(viewleft + viewwidth) << 2, (viewtop + viewheight) << 2, viewleft + viewwidth, viewtop + viewheight,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
g_BlurFbCapTimer = 0;
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
@@ -521,6 +528,14 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
|
||||
if (!videoFramebuffersSupported()) {
|
||||
return gdl;
|
||||
}
|
||||
|
||||
// capture fb at the end of this frame
|
||||
g_BlurFbCapTimer = 0;
|
||||
|
||||
// don't render first blur frame as we haven't captured the fb yet
|
||||
if (g_BlurFbDirty) {
|
||||
return gdl;
|
||||
}
|
||||
#endif
|
||||
|
||||
strcpy(var800a41c0, "stretchBlurGfx");
|
||||
@@ -550,7 +565,6 @@ Gfx *bviewDrawZoomBlur(Gfx *gdl, u32 colour, s32 alpha, f32 arg3, f32 arg4)
|
||||
left << 2, top << 2, viewleft, viewtop,
|
||||
right << 2, bottom << 2, viewleft + viewwidth, viewtop + viewheight,
|
||||
0, videoGetNativeWidth(), videoGetNativeHeight());
|
||||
g_BlurFbCapTimer = 0;
|
||||
#endif
|
||||
|
||||
return gdl;
|
||||
|
||||
@@ -260,6 +260,17 @@ void botSpawn(struct chrdata *chr, u8 respawning)
|
||||
chr->aibot->moveratex = 0;
|
||||
chr->aibot->moveratey = 0;
|
||||
func0f02e9a0(chr, 0);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
|
||||
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
|
||||
botinvGiveSingleWeapon(chr, mpweapon->weaponnum);
|
||||
botactGiveAmmoByType(aibot, mpweapon->priammotype - 1, mpweapon->priammoqty / 2);
|
||||
botinvSwitchToWeapon(chr, mpweapon->weaponnum, FUNC_PRIMARY);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2592,6 +2592,16 @@ MenuItemHandlerResult filemgrChooseAgentListMenuHandler(s32 operation, struct me
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_FileAutoSelect >= 0 && g_FileLists[0] && g_FileLists[0]->numfiles > 0) {
|
||||
const u32 tmp = data->list.value;
|
||||
data->list.value = g_FileAutoSelect;
|
||||
g_FileAutoSelect = -1;
|
||||
filemgrChooseAgentListMenuHandler(MENUOP_SET, item, data);
|
||||
data->list.value = tmp;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case MENUOP_GETOPTIONCOUNT:
|
||||
data->list.value = g_FileLists[0]->numfiles + 1;
|
||||
|
||||
@@ -398,9 +398,11 @@ u16 weaponGetFileNum(s32 weaponnum)
|
||||
}
|
||||
|
||||
if (weapon) {
|
||||
#ifdef PLATFORM_N64
|
||||
if (PLAYERCOUNT() >= 2) {
|
||||
return weapon->lo_model;
|
||||
}
|
||||
#endif
|
||||
|
||||
return weapon->hi_model;
|
||||
}
|
||||
|
||||
+4
-3
@@ -190,7 +190,7 @@ Gfx *hudmsgRenderMissionTimer(Gfx *gdl, u32 alpha)
|
||||
y = timery;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (PLAYERCOUNT() < 2) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL);
|
||||
}
|
||||
#endif
|
||||
@@ -282,7 +282,7 @@ Gfx *hudmsgRenderZoomRange(Gfx *gdl, u32 alpha)
|
||||
y2 = y + textheight;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount == 1) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
@@ -1450,7 +1450,8 @@ Gfx *hudmsgsRender(Gfx *gdl)
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount < 2 && msg->state >= HUDMSGSTATE_FADINGIN) {
|
||||
const bool doaspectfix = (playercount < 2) || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL);
|
||||
if (doaspectfix && msg->state >= HUDMSGSTATE_FADINGIN) {
|
||||
if (msg->alignh == HUDMSGALIGN_SCREENLEFT || msg->alignh == HUDMSGALIGN_LEFT) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeL);
|
||||
} else if (msg->alignh == HUDMSGALIGN_RIGHT) {
|
||||
|
||||
@@ -1178,6 +1178,9 @@ bool menuIsItemFocusable(struct menuitem *item, struct menudialog *dialog, s32 a
|
||||
case MENUITEMTYPE_METER:
|
||||
case MENUITEMTYPE_MARQUEE:
|
||||
case MENUITEMTYPE_CONTROLLER:
|
||||
#ifndef PLATFORM_N64
|
||||
case MENUITEMTYPE_COLORBOX:
|
||||
#endif
|
||||
return false;
|
||||
case MENUITEMTYPE_10:
|
||||
case MENUITEMTYPE_14:
|
||||
|
||||
@@ -2109,6 +2109,36 @@ Gfx *menuitemMeterRender(Gfx *gdl, struct menurendercontext *context)
|
||||
return gdl;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
|
||||
// Draws a colored box which fills the background of the menu item.
|
||||
Gfx* menuitemColorBoxRender(Gfx *gdl, struct menurendercontext *context)
|
||||
{
|
||||
u32 width = context->width;
|
||||
u32 height = context->height;
|
||||
u32 colour1;
|
||||
s32 x1;
|
||||
s32 x2;
|
||||
|
||||
x1 = context->x;
|
||||
x2 = x1 + width;
|
||||
|
||||
union handlerdata data;
|
||||
if (context->item->handlervoid) {
|
||||
context->item->handlervoid(MENUOP_GETCOLOUR, context->item, &data);
|
||||
}
|
||||
|
||||
colour1 = data.label.colour1;
|
||||
|
||||
gdl = textSetPrimColour(gdl, colour1);
|
||||
gDPFillRectangleScaled(gdl++, x1, context->y, x2, context->y + height);
|
||||
gdl = text0f153838(gdl);
|
||||
|
||||
return gdl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Gfx *menuitemSelectableRender(Gfx *gdl, struct menurendercontext *context)
|
||||
{
|
||||
u32 leftcolour;
|
||||
@@ -4349,6 +4379,11 @@ Gfx *menuitemRender(Gfx *gdl, struct menurendercontext *context)
|
||||
case MENUITEMTYPE_CAROUSEL: return menuitemCarouselRender(gdl, context);
|
||||
case MENUITEMTYPE_MODEL: return menuitemModelRender(gdl, context);
|
||||
case MENUITEMTYPE_CONTROLLER: return menuitemControllerRender(gdl, context);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
case MENUITEMTYPE_COLORBOX: return menuitemColorBoxRender(gdl, context);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return gdl;
|
||||
|
||||
@@ -122,6 +122,9 @@ struct mpweapon g_MpWeapons[NUM_MPWEAPONS] = {
|
||||
.crosshairsway = 1.f, \
|
||||
.crouchmode = CROUCHMODE_TOGGLE_ANALOG, \
|
||||
.extcontrols = true, \
|
||||
.crosshaircolour = 0x00ff0028, \
|
||||
.crosshairsize = 2, \
|
||||
.crosshairhealth = CROSSHAIR_HEALTH_OFF, \
|
||||
}
|
||||
|
||||
struct extplayerconfig g_PlayerExtCfg[MAX_PLAYERS] = {
|
||||
@@ -2717,6 +2720,11 @@ struct mptrack g_MpTracks[] = {
|
||||
/*0x27*/ { MUSIC_SKEDARRUINS, 120, L_MISC_163, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Ruins"
|
||||
/*0x28*/ { MUSIC_SKEDARRUINS_X, 120, L_MISC_164, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Ruins X"
|
||||
/*0x29*/ { MUSIC_CREDITS, 120, L_MISC_165, SOLOSTAGEINDEX_SKEDARRUINS }, // "End Credits"
|
||||
#if VERSION < VERSION_PAL_BETA
|
||||
/*0x2a*/ { MUSIC_SKEDARRUINS_KING,120, L_MISC_261, SOLOSTAGEINDEX_SKEDARRUINS }, // "Skedar Warrior" (Skedar Leader)
|
||||
#else
|
||||
/*0x2a*/ { MUSIC_SKEDARRUINS_KING,120, L_MISC_041, SOLOSTAGEINDEX_SKEDARRUINS }, // "E R R O R" (can't find a good approximation for Skedar Leader)
|
||||
#endif
|
||||
};
|
||||
|
||||
bool mpIsTrackUnlocked(s32 tracknum)
|
||||
|
||||
@@ -60,6 +60,16 @@ struct menuitem g_CtcOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -55,6 +55,16 @@ struct menuitem g_MpCombatOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_SEPARATOR,
|
||||
0,
|
||||
|
||||
@@ -58,6 +58,16 @@ struct menuitem g_HtmOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
|
||||
@@ -58,6 +58,16 @@ struct menuitem g_HtbOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
@@ -417,7 +427,8 @@ Gfx *htbRenderHud(Gfx *gdl)
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (PLAYERCOUNT() == 1) {
|
||||
const s32 playercount = PLAYERCOUNT();
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -79,6 +79,16 @@ struct menuitem g_KohOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
@@ -583,7 +593,8 @@ Gfx *kohRenderHud(Gfx *gdl)
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (PLAYERCOUNT() == 1) {
|
||||
const s32 playercount = PLAYERCOUNT();
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -56,6 +56,16 @@ struct menuitem g_PacOptionsMenuItems[] = {
|
||||
MPOPTION_NOAUTOAIM,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#ifndef PLATFORM_N64
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
MENUITEMFLAG_LOCKABLEMINOR | MENUITEMFLAG_LITERAL_TEXT,
|
||||
(uintptr_t)"Spawn With Weapon",
|
||||
MPOPTION_SPAWNWITHWEAPON,
|
||||
menuhandlerMpCheckboxOption,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
MENUITEMTYPE_CHECKBOX,
|
||||
0,
|
||||
@@ -312,7 +322,8 @@ Gfx *pacRenderHud(Gfx *gdl)
|
||||
sprintf(text, "%d:%02d", mins, secs);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (PLAYERCOUNT() == 1) {
|
||||
const s32 playercount = PLAYERCOUNT();
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
+15
-2
@@ -1100,8 +1100,21 @@ void playerSpawn(void)
|
||||
g_Vars.currentplayer->prop->chr->blurnumtimesdied = 0;
|
||||
}
|
||||
} else {
|
||||
bgunEquipWeapon2(HAND_LEFT, g_DefaultWeapons[HAND_LEFT]);
|
||||
bgunEquipWeapon2(HAND_RIGHT, g_DefaultWeapons[HAND_RIGHT]);
|
||||
#ifndef PLATFORM_N64
|
||||
if ((g_MpSetup.options & MPOPTION_SPAWNWITHWEAPON)
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_NONE
|
||||
&& g_MpSetup.weapons[0] != MPWEAPON_DISABLED) {
|
||||
struct mpweapon *mpweapon = &g_MpWeapons[g_MpSetup.weapons[0]];
|
||||
invGiveSingleWeapon(mpweapon->weaponnum);
|
||||
bgunEquipWeapon2(HAND_LEFT, WEAPON_NONE);
|
||||
bgunEquipWeapon2(HAND_RIGHT, mpweapon->weaponnum);
|
||||
bgunSetAmmoQuantity(mpweapon->priammotype, mpweapon->priammoqty / 2);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bgunEquipWeapon2(HAND_LEFT, g_DefaultWeapons[HAND_LEFT]);
|
||||
bgunEquipWeapon2(HAND_RIGHT, g_DefaultWeapons[HAND_RIGHT]);
|
||||
}
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
if (g_Vars.currentplayer->model00d4 == NULL
|
||||
|
||||
+1
-1
@@ -20997,7 +20997,7 @@ Gfx *countdownTimerRender(Gfx *gdl)
|
||||
ms = (s32)floorf(value60 * 1.6666666269302f) - mins * 6000 - secs * 100;
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (playercount == 1) {
|
||||
if (playercount < 2 || (playercount == 2 && optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL)) {
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -312,6 +312,11 @@ Gfx *radarRender(Gfx *gdl)
|
||||
} else if (optionsGetScreenSplit() != SCREENSPLIT_VERTICAL && playernum == 1) {
|
||||
g_RadarY -= 8;
|
||||
}
|
||||
#ifndef PLATFORM_N64
|
||||
if (optionsGetScreenSplit() == SCREENSPLIT_HORIZONTAL) {
|
||||
gSPExtraGeometryModeEXT(gdl++, G_ASPECT_MODE_EXT, g_HudAlignModeR);
|
||||
}
|
||||
#endif
|
||||
} else if (playercount >= 3) {
|
||||
if (playernum >= 2) {
|
||||
g_RadarY -= 8;
|
||||
|
||||
+83
-20
@@ -23,9 +23,58 @@
|
||||
#include <math.h>
|
||||
#include "video.h"
|
||||
|
||||
#define SIGHT_COLOUR ((PLAYER_EXTCFG().crosshairhealth >= CROSSHAIR_HEALTH_ON_GREEN) ? sightGetCrosshairHealthColor(g_Vars.currentplayer->bondhealth, g_Vars.currentplayer->prop->chr->cshield * 0.125f) : PLAYER_EXTCFG().crosshaircolour)
|
||||
#define SIGHT_SCALE PLAYER_EXTCFG().crosshairsize
|
||||
|
||||
static u32 sightGetCrosshairHealthColor(float health, float shield)
|
||||
{
|
||||
const float ratio = MAX(0.0f, MIN(health + shield, 2.0f));
|
||||
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
if (ratio < 0.2f) {
|
||||
// Red (critical health level)
|
||||
red = 255;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
} else if (ratio < 0.6f) {
|
||||
// Red-yellow
|
||||
red = 255;
|
||||
green = 255 * ((ratio - 0.2f) / 0.4f);
|
||||
blue = 0;
|
||||
} else if (ratio < 1.0f) {
|
||||
if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) {
|
||||
// Yellow-green
|
||||
red = 255 * ((ratio - 0.6f) / 0.4f);
|
||||
green = 255;
|
||||
blue = 0;
|
||||
} else {
|
||||
// Yellow-white
|
||||
red = 255;
|
||||
green = 255;
|
||||
blue = 255 * ((ratio - 0.6f) / 0.4f);
|
||||
}
|
||||
} else {
|
||||
if (PLAYER_EXTCFG().crosshairhealth == CROSSHAIR_HEALTH_ON_GREEN) {
|
||||
// Green-cyan (overheal via shield)
|
||||
red = 0;
|
||||
green = 255;
|
||||
blue = 255 * (ratio - 1.0f);
|
||||
} else {
|
||||
// White-green (overheal via shield)
|
||||
red = 255 * (2.0f - ratio);
|
||||
green = 255;
|
||||
blue = 255 * (2.0f - ratio);
|
||||
}
|
||||
}
|
||||
|
||||
return (red << 24) + (green << 16) + (blue << 8) + (PLAYER_EXTCFG().crosshaircolour & 0xff);
|
||||
}
|
||||
|
||||
static inline f32 sightGetScaleX(void)
|
||||
{
|
||||
return (videoGetAspect() / (4.f / 3.f));
|
||||
return (videoGetAspect() / SCREEN_ASPECT);
|
||||
}
|
||||
|
||||
static inline s32 sightGetAdjustedX(const f32 x)
|
||||
@@ -36,6 +85,8 @@ static inline s32 sightGetAdjustedX(const f32 x)
|
||||
|
||||
#else
|
||||
|
||||
#define SIGHT_COLOUR 0x00ff0028
|
||||
#define SIGHT_SCALE 2
|
||||
#define sightGetScaleX() 1.f
|
||||
#define sightGetAdjustedX(x) (x)
|
||||
|
||||
@@ -459,7 +510,7 @@ Gfx *sightDrawAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u32 colou
|
||||
s32 viewright = viewleft + viewwidth - 1;
|
||||
s32 viewbottom = viewtop + viewheight - 1;
|
||||
|
||||
gdl = textSetPrimColour(gdl, 0x00ff0028);
|
||||
gdl = textSetPrimColour(gdl, SIGHT_COLOUR);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
x = sightGetAdjustedX(x);
|
||||
@@ -619,7 +670,7 @@ Gfx *sightDrawDelayedAimer(Gfx *gdl, s32 x, s32 y, s32 radius, s32 cornergap, u3
|
||||
boxx = xpos;
|
||||
boxy = ypos;
|
||||
|
||||
gdl = textSetPrimColour(gdl, 0x00ff0028);
|
||||
gdl = textSetPrimColour(gdl, SIGHT_COLOUR);
|
||||
|
||||
// Fill a 3x3 box at the live crosshair
|
||||
gDPHudRectangle(gdl++, x - 1, y - 1, x + 1, y - 1);
|
||||
@@ -677,7 +728,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton)
|
||||
// SIGHTTRACKTYPE_NONE is used for unarmed, but this appears to be
|
||||
// unreachable. The aimer is never drawn when unarmed.
|
||||
if (sighton) {
|
||||
colour = 0x00ff0028;
|
||||
colour = SIGHT_COLOUR;
|
||||
radius = 8;
|
||||
cornergap = 5;
|
||||
gdl = sightDrawAimer(gdl, x, y, radius, cornergap, colour);
|
||||
@@ -687,7 +738,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton)
|
||||
// For most guns, render the aimer if holding R
|
||||
if (sighton) {
|
||||
if (g_Vars.currentplayer->lookingatprop.prop == NULL) {
|
||||
colour = 0x00ff0028;
|
||||
colour = SIGHT_COLOUR;
|
||||
radius = 8;
|
||||
cornergap = 5;
|
||||
} else {
|
||||
@@ -716,7 +767,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton)
|
||||
s32 texty;
|
||||
|
||||
if (g_Vars.currentplayer->lookingatprop.prop == NULL) {
|
||||
colour = 0x00ff0028;
|
||||
colour = SIGHT_COLOUR;
|
||||
radius = 8;
|
||||
cornergap = 5;
|
||||
} else {
|
||||
@@ -761,7 +812,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton)
|
||||
|
||||
if (sighton) {
|
||||
if (g_Vars.currentplayer->lookingatprop.prop == NULL) {
|
||||
colour = 0x00ff0028;
|
||||
colour = SIGHT_COLOUR;
|
||||
radius = 8;
|
||||
cornergap = 5;
|
||||
} else {
|
||||
@@ -832,7 +883,7 @@ Gfx *sightDrawDefault(Gfx *gdl, bool sighton)
|
||||
|
||||
if (sighton) {
|
||||
if (g_Vars.currentplayer->lookingatprop.prop == NULL) {
|
||||
colour = 0x00ff0028;
|
||||
colour = SIGHT_COLOUR;
|
||||
radius = 8;
|
||||
cornergap = 5;
|
||||
} else {
|
||||
@@ -1252,7 +1303,7 @@ Gfx *sightDrawZoom(Gfx *gdl, bool sighton)
|
||||
|
||||
if (showzoomrange) {
|
||||
gdl = text0f153628(gdl);
|
||||
gdl = textSetPrimColour(gdl, 0x00ff0028);
|
||||
gdl = textSetPrimColour(gdl, SIGHT_COLOUR);
|
||||
|
||||
if (frac < 0.2f) {
|
||||
cornerwidth *= 0.2f;
|
||||
@@ -1436,7 +1487,7 @@ Gfx *sightDrawMaian(Gfx *gdl, bool sighton)
|
||||
gSPTri4(gdl++, 0, 4, 5, 5, 3, 6, 7, 6, 1, 4, 7, 2);
|
||||
|
||||
gdl = func0f0d49c8(gdl);
|
||||
gdl = textSetPrimColour(gdl, 0x00ff0028);
|
||||
gdl = textSetPrimColour(gdl, SIGHT_COLOUR);
|
||||
|
||||
// Draw border over inner points
|
||||
gDPHudRectangle(gdl++, x - 4, y - 4, x - 4, y + 4); // left
|
||||
@@ -1464,20 +1515,25 @@ Gfx *sightDrawTarget(Gfx *gdl)
|
||||
mainOverrideVariable("sout", &var80070f9c);
|
||||
mainOverrideVariable("sin", &var80070fa0);
|
||||
|
||||
gdl = textSetPrimColour(gdl, 0x00ff0028);
|
||||
gdl = textSetPrimColour(gdl, SIGHT_COLOUR);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPSetExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
if (SIGHT_SCALE == 0) {
|
||||
// Draw single rectangle to preserve intended opacity
|
||||
gDPHudRectangle(gdl++, x, y, x, y);
|
||||
} else
|
||||
#endif
|
||||
|
||||
gDPHudRectangle(gdl++, x + 2, y + 0, x + 6, y + 0);
|
||||
gDPHudRectangle(gdl++, x + 2, y + 0, x + 4, y + 0);
|
||||
gDPHudRectangle(gdl++, x - 6, y + 0, x - 2, y + 0);
|
||||
gDPHudRectangle(gdl++, x - 4, y + 0, x - 2, y + 0);
|
||||
gDPHudRectangle(gdl++, x + 0, y + 2, x + 0, y + 6);
|
||||
gDPHudRectangle(gdl++, x + 0, y + 2, x + 0, y + 4);
|
||||
gDPHudRectangle(gdl++, x + 0, y - 6, x + 0, y - 2);
|
||||
gDPHudRectangle(gdl++, x + 0, y - 4, x + 0, y - 2);
|
||||
{
|
||||
gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x + 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x + 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x - 3 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x - 2 * SIGHT_SCALE, y + 0 * SIGHT_SCALE, x - 1 * SIGHT_SCALE, y + 0 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 3 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y + 1 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y + 2 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 3 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE);
|
||||
gDPHudRectangle(gdl++, x + 0 * SIGHT_SCALE, y - 2 * SIGHT_SCALE, x + 0 * SIGHT_SCALE, y - 1 * SIGHT_SCALE);
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
gSPClearExtraGeometryModeEXT(gdl++, G_ASPECT_CENTER_EXT);
|
||||
@@ -1526,6 +1582,13 @@ Gfx *sightDraw(Gfx *gdl, bool sighton, s32 sight)
|
||||
sight = SIGHT_DEFAULT;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
if (g_Vars.currentplayer->bondhealth <= 0.0f) {
|
||||
// Hide crosshair during death animation
|
||||
sight = SIGHT_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
sightTick(sighton);
|
||||
|
||||
switch (sight) {
|
||||
|
||||
@@ -139,6 +139,9 @@ void texReset(void)
|
||||
|
||||
// get backend texture settings
|
||||
g_TexFilter2D = videoGetTextureFilter2D() ? G_TF_BILERP : G_TF_POINT;
|
||||
|
||||
// notify blur code that the blur framebuffer is probably full of garbage
|
||||
g_BlurFbDirty = true;
|
||||
#endif
|
||||
|
||||
g_TexWords = mempAlloc(ALIGN16(g_TexNumConfigs * 4), MEMPOOL_STAGE);
|
||||
|
||||
@@ -372,6 +372,8 @@ Gfx *titleRenderLegal(Gfx *gdl)
|
||||
elem->textptr = VERSION_HASH " (" VERSION_TARGET ")";
|
||||
} else if (elem->textid == L_OPTIONS_083) {
|
||||
elem->textptr = VERSION_ROMID;
|
||||
} else if (elem->textid == L_OPTIONS_082) {
|
||||
elem->textptr = "Perfect Dark (" VERSION_BRANCH ")";
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -1692,6 +1692,10 @@
|
||||
#define MENUITEMTYPE_CONTROLLER 0x19
|
||||
#define MENUITEMTYPE_END 0x1a
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
#define MENUITEMTYPE_COLORBOX 0x1b
|
||||
#endif
|
||||
|
||||
#define MENUMODELFLAG_HASSCALE 0x01
|
||||
#define MENUMODELFLAG_HASPOSITION 0x02
|
||||
#define MENUMODELFLAG_HASROTATION 0x04
|
||||
@@ -2885,6 +2889,7 @@
|
||||
#define MPOPTION_HTM_SHOWONRADAR 0x00040000
|
||||
#define MPOPTION_PAC_HIGHLIGHTTARGET 0x00080000
|
||||
#define MPOPTION_PAC_SHOWONRADAR 0x00100000
|
||||
#define MPOPTION_SPAWNWITHWEAPON 0x00200000
|
||||
|
||||
#define MPPAUSEMODE_UNPAUSED 0
|
||||
#define MPPAUSEMODE_PAUSED 1
|
||||
@@ -4714,6 +4719,10 @@ enum weaponnum {
|
||||
#define CROUCHMODE_TOGGLE 2 // press the crouch buttons to toggle stance
|
||||
#define CROUCHMODE_TOGGLE_ANALOG (CROUCHMODE_ANALOG | CROUCHMODE_TOGGLE)
|
||||
|
||||
#define CROSSHAIR_HEALTH_OFF 0
|
||||
#define CROSSHAIR_HEALTH_ON_GREEN 1
|
||||
#define CROSSHAIR_HEALTH_ON_WHITE 2
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -545,8 +545,11 @@ extern u32 g_HudAlignModeR;
|
||||
extern s32 g_PrevFrameFb;
|
||||
extern s32 g_BlurFb;
|
||||
extern s32 g_BlurFbCapTimer;
|
||||
extern bool g_BlurFbDirty;
|
||||
extern s32 g_TickRateDiv;
|
||||
extern s32 g_MusicDisableMpDeath;
|
||||
extern s32 g_BgunGeMuzzleFlashes;
|
||||
extern s32 g_FileAutoSelect;
|
||||
|
||||
#define PLAYER_EXTCFG() g_PlayerExtCfg[g_Vars.currentplayerstats->mpindex & 3]
|
||||
#define PLAYER_DEFAULT_FOV (PLAYER_EXTCFG().fovy)
|
||||
|
||||
@@ -32,6 +32,10 @@ Gfx *menuitemLabelRender(Gfx *gdl, struct menurendercontext *context);
|
||||
|
||||
Gfx *menuitemMeterRender(Gfx *gdl, struct menurendercontext *context);
|
||||
|
||||
#ifndef PLATFORM_N64
|
||||
Gfx *menuitemColorBoxRender(Gfx *gdl, struct menurendercontext *context);
|
||||
#endif
|
||||
|
||||
Gfx *menuitemSelectableRender(Gfx *gdl, struct menurendercontext *context);
|
||||
bool menuitemSelectableTick(struct menuitem *item, struct menuinputs *inputs, u32 tickflags);
|
||||
|
||||
|
||||
@@ -6139,6 +6139,9 @@ struct extplayerconfig {
|
||||
f32 radialmenuspeed;
|
||||
f32 crosshairsway;
|
||||
s32 extcontrols;
|
||||
u32 crosshaircolour;
|
||||
u32 crosshairsize;
|
||||
s32 crosshairhealth;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user