Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions runtime/cosmetic_colour.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,15 @@ void col_format(const CosColour *c, char *out, size_t n) {
else snprintf(out, n, "%s", g_col_names[c->pick >= 0 && c->pick < N_COL ? c->pick : 0]);
}

int (*g_col_seed_pick)(int slot, uint32_t *rgb);

static int seed_pick(const CosColour *c, int slot, uint32_t *rgb) {
(void)c; // (the seed's colour wins over the player's: the Cosmetics tab is locked while it's played)
if (!g_col_seed_pick) return COL_DEFAULT;
uint32_t v = 0;
int p = g_col_seed_pick(slot, &v);
if (p > COL_DEFAULT && p < COL_RANDOM) v = g_col_rgb[p];
else if (p != COL_CUSTOM) return COL_DEFAULT;
if (rgb) *rgb = v & 0xFFFFFF;
return p;
}

bool col_seed_rgb(const CosColour *c, int slot, uint32_t *rgb) { return seed_pick(c, slot, rgb) != COL_DEFAULT; }

int col_pick(const CosColour *c, int slot) {
int p = seed_pick(c, slot, NULL);
return p ? p : c->pick;
}
void (*g_col_seed_check)(void);

bool col_target(const CosColour *c, int slot, uint32_t *rgb) {
static int picks[COL_SLOTS];
static unsigned seed;
static time_t checked;
if (slot < 0 || slot >= COL_SLOTS) return false;
if (col_seed_rgb(c, slot, rgb)) return true; // (the seed's colour, if it has its own)
time_t now = time(NULL);
if (g_col_seed_check && now != checked) checked = now, g_col_seed_check(); // (a new seed's own set: once a second)
if (c->pick != COL_RANDOM) picks[slot] = 0;
if (c->pick == COL_CUSTOM) { *rgb = c->rgb & 0xFFFFFF; return true; }
if (c->pick == COL_RANDOM) {
Expand Down
11 changes: 3 additions & 8 deletions runtime/cosmetic_colour.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@ extern const uint32_t g_col_rgb[N_COL]; // the named colours' targets (0 for De
void col_parse(CosColour *c, const char *val);
// c -> its larecomp.ini value (name, or #RRGGBB for Custom)
void col_format(const CosColour *c, char *out, size_t n);
// The randomizer seed's own cosmetics (seed option "Random cosmetics", runtime/cosmetics_seed.c): the colour row `slot`
// takes whatever the player chose: a palette colour, or COL_CUSTOM with *rgb (0: none - vanilla, or a seed without the
// option). NULL until set.
extern int (*g_col_seed_pick)(int slot, uint32_t *rgb);
// The seed's own colour for row `slot` (0xRRGGBB); false: none
bool col_seed_rgb(const CosColour *c, int slot, uint32_t *rgb);
// The palette colour row `slot` shows: the seed's, else the player's choice
int col_pick(const CosColour *c, int slot);
// The randomizer seed's own cosmetics (seed option "Random cosmetics", runtime/cosmetics_seed.c): looks for a newly
// played seed's set and copies it into the rows once. NULL until set.
extern void (*g_col_seed_check)(void);
// The colour row `slot` should show now (0xRRGGBB); false: Default (the game's own look).
bool col_target(const CosColour *c, int slot, uint32_t *rgb);
// HSV (hue in turns, saturation, value: 0..1) of 0xRRGGBB
Expand Down
44 changes: 29 additions & 15 deletions runtime/cosmetics_seed.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// made with it has its own set, picked from its seed (the same every time it's played): a fully random colour (any
// hue, saturation and brightness) for each of the tunic, hearts, hair, skin, shield, leaves, grass, sand, water,
// fences, walls and houses, enemy colours "per seed" and a weather (clear, rain, snow or storm: runtime/nvn/weather.c;
// the screen filter stays off: it isn't a colour). Only while that seed is being played (never in vanilla), over
// whatever the player chose: the Cosmetics tab is locked meanwhile (the player's own choices stay saved, and are back
// in another seed or vanilla).
// the screen filter off: it isn't a colour). The first time such a seed is played its set is copied into the Cosmetics
// tab's rows (g_settings.cosmetics_seed remembers which seed did it), and from then on they are the player's own to
// change; the tab's "Seed's look" copies them in again.
#include <pthread.h>
#include <stdio.h>
#include <string.h>
Expand Down Expand Up @@ -60,31 +60,45 @@ static void refresh_locked(void) {
LOG("[cosmetics] seed's own cosmetics (%s)\n", dir);
}

static int seed_pick(int slot, uint32_t *rgb) {
pthread_mutex_lock(&g_lock);
// The seed's set -> the Cosmetics tab's rows (the weather's 0..3 are WEATHER_OFF..WEATHER_STORM)
static void apply_locked(void) {
CosColour *rows[COL_SLOTS] = {&g_settings.tunic, &g_settings.hearts, &g_settings.hair, &g_settings.skin,
&g_settings.shield, &g_settings.leaves, &g_settings.grass, &g_settings.sand,
&g_settings.water, &g_settings.fences, &g_settings.walls, &g_settings.houses};
for (int slot = 0; slot < COL_SLOTS; slot++) rows[slot]->pick = COL_CUSTOM, rows[slot]->rgb = g_rgb[slot];
g_settings.enemy_colours = 1;
g_settings.screen_filter = 0;
g_settings.weather = g_weather;
snprintf(g_settings.cosmetics_seed, sizeof g_settings.cosmetics_seed, "%s", g_dir);
LOG("[cosmetics] the seed's own cosmetics copied into the Cosmetics tab (%s)\n", g_dir);
}

static void check_locked(void) {
refresh_locked();
int p = g_on && slot >= 0 && slot < COL_SLOTS ? COL_CUSTOM : COL_DEFAULT;
if (p) *rgb = g_rgb[slot];
if (g_on && strcmp(g_settings.cosmetics_seed, g_dir)) apply_locked(); // (a seed played for the first time)
}

static void check(void) {
pthread_mutex_lock(&g_lock);
check_locked();
pthread_mutex_unlock(&g_lock);
return p;
}

// The seed has its own cosmetics (the Cosmetics tab is locked; enemy colours "per seed", no screen filter)
// The seed being played (or PLAY's, on the start screen) has its own cosmetics
bool cosmetics_seed_on(void) {
pthread_mutex_lock(&g_lock);
refresh_locked();
check_locked();
bool on = g_on;
pthread_mutex_unlock(&g_lock);
return on;
}

// The seed's own weather (0 clear, 1 rain, 2 snow, 3 storm), over the Weather row; 0 without one
int cosmetics_seed_weather(void) {
// "Seed's look": its set into the rows again
void cosmetics_seed_apply(void) {
pthread_mutex_lock(&g_lock);
refresh_locked();
int w = g_on ? g_weather : 0;
if (g_on) apply_locked();
pthread_mutex_unlock(&g_lock);
return w;
}

__attribute__((constructor)) static void install(void) { g_col_seed_pick = seed_pick; }
__attribute__((constructor)) static void install(void) { g_col_seed_check = check; }
3 changes: 1 addition & 2 deletions runtime/nvn/recolour_enemies.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ static uint32_t seed_seed(void) { // Per seed: the randomizer seed's name (vani
}

static bool tint(int cls, float t[8]) {
extern bool cosmetics_seed_on(void); // (a seed with its own cosmetics has them per seed)
int mode = cosmetics_seed_on() ? 1 : g_settings.enemy_colours;
int mode = g_settings.enemy_colours;
if (mode <= 0 || mode >= N_ENEMY_COLOUR_MODES || cls < E_BASE || cls >= E_BASE + N_SPECIES) return false;
uint32_t h = mix32((mode == 2 ? load_seed() : seed_seed()) ^ (uint32_t)(cls - E_BASE) * 0x27D4EB2Fu);
float shift = 0.12f + (h >> 8) / 16777216.0f * 0.76f; // (12-88% of the wheel: always clearly another colour)
Expand Down
5 changes: 2 additions & 3 deletions runtime/nvn/screen_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@

enum { SCREEN_FILTER_OFF, SCREEN_FILTER_GB, SCREEN_FILTER_GBC, SCREEN_FILTER_GRAY };

// pf for the present shader (x: the mode; off in a seed with its own cosmetics)
extern bool cosmetics_seed_on(void); // runtime/cosmetics_seed.c
// pf for the present shader (x: the mode)
static inline void screen_filter_params(float pf[4]) {
pf[0] = cosmetics_seed_on() ? 0 : (float)g_settings.screen_filter;
pf[0] = (float)g_settings.screen_filter;
pf[1] = pf[2] = pf[3] = 0;
}

Expand Down
8 changes: 0 additions & 8 deletions runtime/nvn/weather.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#include "../settings.h"

extern int game_in_play(void); // runtime/hle/warp.c
extern int cosmetics_seed_weather(void); // runtime/cosmetics_seed.c
extern bool cosmetics_seed_on(void);
extern bool widescreen_frame_boxed(uint64_t frame); // runtime/hle/widescreen.c (indoors: the interior backdrop)
extern void input_rumble_pulse(uint16_t lo, uint16_t hi, uint32_t ms); // runtime/hle/input.c

Expand Down Expand Up @@ -61,12 +59,6 @@ static bool g_outdoors;

int weather_current(void) {
if (weather_cycle_on()) return weather_cycle_kind(NULL);
static int seed_on, seed_w;
static uint64_t at; // (the seed's pick: looked up once a second, it only changes with the seed)
uint64_t now = (uint64_t)time(NULL);
if (now != at) at = now, seed_on = cosmetics_seed_on(), seed_w = cosmetics_seed_weather();
if (seed_on && env_weather() < 0) return seed_w; // (a seed with its own cosmetics: its weather, over the setting -
// the row is locked)
int s = setting();
return s == WEATHER_RANDOM ? g_random : s;
}
Expand Down
5 changes: 5 additions & 0 deletions runtime/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ void settings_load(void) {
strlcpy(g_settings.rando_seed, val, sizeof g_settings.rando_seed);
continue;
}
if (!strcmp(key, "cosmetics_seed")) {
strlcpy(g_settings.cosmetics_seed, val, sizeof g_settings.cosmetics_seed);
continue;
}
if (fields != 2) continue;
if (!strcmp(key, "aspect")) g_settings.aspect = !strcmp(val, "original") ? ASPECT_ORIGINAL : ASPECT_UNLOCKED;
else if (!strcmp(key, "fullscreen")) g_settings.fullscreen = atoi(val) != 0;
Expand Down Expand Up @@ -360,6 +364,7 @@ void settings_save(void) {
fprintf(f, "enemy_colours = %s\n", k_enemy_colour_keys[g_settings.enemy_colours]);
fprintf(f, "screen_filter = %s\n", k_screen_filter_keys[g_settings.screen_filter]);
fprintf(f, "weather = %s\n", k_weather_keys[g_settings.weather]);
if (g_settings.cosmetics_seed[0]) fprintf(f, "cosmetics_seed = %s\n", g_settings.cosmetics_seed);
bind_settings_save(f);
fprintf(f, "rando_seed = %s\n", g_settings.rando_seed);
if (g_settings.rando_options[0]) fprintf(f, "rando_options = %s\n", g_settings.rando_options);
Expand Down
1 change: 1 addition & 0 deletions runtime/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ typedef struct {
int enemy_colours; // 0 Off, 1 Random per seed, 2 Random every load (runtime/nvn/recolour_enemies.c)
int screen_filter; // 0 Off, 1 Game Boy, 2 Game Boy Color, 3 Grayscale (runtime/nvn/screen_filter.h)
int weather; // WEATHER_* (runtime/nvn/weather.h): rain / snow / storm / blizzard on the overworld, looks only
char cosmetics_seed[300]; // the seed folder whose own cosmetics were last copied into the rows (cosmetics_seed.c)
// speedrun (Gameplay tab; runtime/hle/run_timer.c, runtime/livesplit.c)
bool timer; // the in-game run timer in the corner (game time: level loads don't count)
int timer_pos; // TIMER_POS_*: which bottom corner it sits in
Expand Down
14 changes: 8 additions & 6 deletions runtime/ui/lang/de.inc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
{"Controllers keep working while another window is in front. macOS may ask for Input Monitoring permission.", "Controller funktionieren weiter, wenn ein anderes Fenster im Vordergrund ist. macOS fragt eventuell nach der Berechtigung für Eingabeüberwachung."},
{"Movement", "Bewegung"},
{"Nothing", "Nichts"},
{"Items", "Items"},
{"What the D-pad does in play.", "Was das Steuerkreuz im Spiel tut."},
{"360-degree movement", "360-Grad-Bewegung"},
{"Link walks in the exact direction of the stick instead of snapping to 8 directions.", "Link läuft genau in Stick-Richtung, statt nur in 8 Richtungen."},
Expand Down Expand Up @@ -262,7 +263,6 @@
{"Rooster", "Gockel"},
{"Choose", "Wählen"},
{"Tunics", "Gewänder"},
{"Keys", "Schlüssel"},
// runtime/ui/item_names.h
{"Sword", "Schwert"},
{"Noble Sword", "Cocolint-Schwert"},
Expand Down Expand Up @@ -509,11 +509,12 @@
{"Turns off the tilt-shift blur at the top and bottom of the screen.", "Schaltet die Tilt-Shift-Unschärfe am oberen und unteren Bildrand ab."},
{"Hide Hero Mode icon", "Heldenmodus-Symbol aus"},
{"Hides the Hero Mode emblem in the corner of the screen while playing a Hero Mode file.", "Blendet das Heldenmodus-Emblem in der Bildschirmecke aus, wenn du einen Spielstand im Heldenmodus spielst."},
{"This seed picked your look. Commit to it!", "Dieser Seed hat deinen Look gewählt. Steh dazu!"},
{"Randomize all", "Alles zufällig"},
{"Picks a random color for everything below.", "Wählt für alles unten eine zufällige Farbe."},
{"Default all", "Alles Standard"},
{"Puts everything on this page back to the game's normal look.", "Setzt alles auf dieser Seite auf den normalen Look des Spiels zurück."},
{"Seed's look", "Look des Seeds"},
{"Puts everything on this page back to this seed's look.", "Setzt alles auf dieser Seite auf den Look dieses Seeds zurück."},
{"Colors", "Farben"},
{"Tunic color", "Gewandfarbe"},
{"Link's tunic color.", "Die Farbe von Links Gewand."},
Expand Down Expand Up @@ -548,12 +549,12 @@
{"House color", "Hausfarbe"},
{"The roofs of the village houses.", "Die Dächer der Häuser im Dorf."},
{"Enemies", "Gegner"},
{"Seed", "Seed"},
{"Enemy colors", "Gegnerfarben"},
{"Gives each kind of enemy a new color. Enemies whose color shows how strong they are keep theirs.", "Gibt jeder Gegnerart eine neue Farbe. Gegner, deren Farbe ihre Stärke zeigt, behalten ihre."},
{"Screen", "Bildschirm"},
{"Screen filter", "Bildfilter"},
{"Puts a filter over the whole screen, HUD included.", "Legt einen Filter über den ganzen Bildschirm, samt HUD."},
{"Seed", "Seed"},
{"Weather", "Wetter"},
{"This seed picked the weather. Commit to it!", "Dieser Seed hat das Wetter gewählt. Steh dazu!"},
{"Rain, snow, a storm or a blizzard on the overworld.", "Regen, Schnee, Gewitter oder Schneesturm in der Oberwelt."},
Expand Down Expand Up @@ -594,7 +595,6 @@
{"%.0f fps", "%.0f FPS"},
// runtime/ui/option_rows.mm
{"On", "An"},
{"Seed: %s", "Seed: %s"},
{"Custom color", "Eigene Farbe"},
{"Pick any color by hue, saturation and brightness.", "Wähle eine beliebige Farbe nach Farbton, Sättigung und Helligkeit."},
{"Done", "Fertig"},
Expand Down Expand Up @@ -630,7 +630,6 @@
{"Seeds", "Seeds"},
{"Presets", "Presets"},
{"Goal", "Ziel"},
{"Items", "Items"},
{"Extra checks", "Extra-Checks"},
{"World", "Welt"},
{"Enemies & bosses", "Gegner & Bosse"},
Expand Down Expand Up @@ -1206,7 +1205,6 @@
{"Trap!", "Falle!"},
{"Frog Song of Soul", "Krötenrap"},
{"Chamber Stone", "Kammerstein"},
{"shared", "geteilt"},
{"Beach chest", "Truhe am Strand"},
{"Taltal entrance chest", "Taltal, Truhe am Eingang"},
{"Taltal east left chest", "Taltal Ost, linke Truhe"},
Expand Down Expand Up @@ -1496,6 +1494,10 @@
{", ", ", "},
{": ", ": "},
// not used any more
{"Keys", "Schlüssel"},
{"This seed picked your look. Commit to it!", "Dieser Seed hat deinen Look gewählt. Steh dazu!"},
{"Seed: %s", "Seed: %s"},
{"shared", "geteilt"},
{"Marin is an item in the pool, and the desert is blocked without her.", "Marin ist ein Item im Pool, und ohne sie ist die Wüste versperrt."},
{"boss cutscenes", "Boss-Sequenzen"},
{"extended consumable drop", "mehr Verbrauchs-Drops"},
Expand Down
14 changes: 8 additions & 6 deletions runtime/ui/lang/es.inc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
{"Controllers keep working while another window is in front. macOS may ask for Input Monitoring permission.", "Los mandos siguen funcionando aunque haya otra ventana delante. macOS puede pedirte permiso de monitorización de entrada."},
{"Movement", "Movimiento"},
{"Nothing", "Nada"},
{"Items", "Objetos"},
{"What the D-pad does in play.", "Lo que hace la cruceta al jugar."},
{"360-degree movement", "Movimiento 360°"},
{"Link walks in the exact direction of the stick instead of snapping to 8 directions.", "Link camina en la dirección exacta de la palanca en vez de limitarse a 8 direcciones."},
Expand Down Expand Up @@ -262,7 +263,6 @@
{"Rooster", "Cuco"},
{"Choose", "Elegir"},
{"Tunics", "Ropas"},
{"Keys", "Llaves"},
// runtime/ui/item_names.h
{"Sword", "Espada"},
{"Noble Sword", "Espada de Koholint"},
Expand Down Expand Up @@ -509,11 +509,12 @@
{"Turns off the tilt-shift blur at the top and bottom of the screen.", "Quita el desenfoque de efecto maqueta de la parte superior e inferior de la pantalla."},
{"Hide Hero Mode icon", "Ocultar icono modo Héroe"},
{"Hides the Hero Mode emblem in the corner of the screen while playing a Hero Mode file.", "Oculta el emblema del modo Héroe en la esquina de la pantalla al jugar una partida en modo Héroe."},
{"This seed picked your look. Commit to it!", "Esta semilla ha elegido tu aspecto. ¡Acéptalo!"},
{"Randomize all", "Todo aleatorio"},
{"Picks a random color for everything below.", "Elige un color aleatorio para todo lo de abajo."},
{"Default all", "Restablecer todo"},
{"Puts everything on this page back to the game's normal look.", "Devuelve todo lo de esta página al aspecto normal del juego."},
{"Seed's look", "Aspecto de la semilla"},
{"Puts everything on this page back to this seed's look.", "Devuelve todo lo de esta página al aspecto de esta semilla."},
{"Colors", "Colores"},
{"Tunic color", "Color de ropas"},
{"Link's tunic color.", "El color de las ropas de Link."},
Expand Down Expand Up @@ -548,12 +549,12 @@
{"House color", "Color de casas"},
{"The roofs of the village houses.", "Los tejados de las casas de la aldea."},
{"Enemies", "Enemigos"},
{"Seed", "Semilla"},
{"Enemy colors", "Color de enemigos"},
{"Gives each kind of enemy a new color. Enemies whose color shows how strong they are keep theirs.", "Da un color nuevo a cada tipo de enemigo. Los enemigos cuyo color indica su fuerza conservan el suyo."},
{"Screen", "Pantalla"},
{"Screen filter", "Filtro de pantalla"},
{"Puts a filter over the whole screen, HUD included.", "Pone un filtro sobre toda la pantalla, HUD incluido."},
{"Seed", "Semilla"},
{"Weather", "Clima"},
{"This seed picked the weather. Commit to it!", "Esta semilla ha elegido el clima. ¡Acéptalo!"},
{"Rain, snow, a storm or a blizzard on the overworld.", "Lluvia, nieve, tormenta o ventisca en el mundo exterior."},
Expand Down Expand Up @@ -594,7 +595,6 @@
{"%.0f fps", "%.0f fps"},
// runtime/ui/option_rows.mm
{"On", "Activado"},
{"Seed: %s", "Semilla: %s"},
{"Custom color", "Color personalizado"},
{"Pick any color by hue, saturation and brightness.", "Elige cualquier color por tono, saturación y brillo."},
{"Done", "Listo"},
Expand Down Expand Up @@ -630,7 +630,6 @@
{"Seeds", "Semillas"},
{"Presets", "Preajustes"},
{"Goal", "Objetivo"},
{"Items", "Objetos"},
{"Extra checks", "Ubicaciones extra"},
{"World", "Mundo"},
{"Enemies & bosses", "Enemigos y jefes"},
Expand Down Expand Up @@ -1206,7 +1205,6 @@
{"Trap!", "¡Trampa!"},
{"Frog Song of Soul", "Canción vital de las ranas"},
{"Chamber Stone", "Piedra saliza"},
{"shared", "compartida"},
{"Beach chest", "Cofre de la playa"},
{"Taltal entrance chest", "Cofre de la entrada de Tal Tal"},
{"Taltal east left chest", "Cofre izquierdo del este de Tal Tal"},
Expand Down Expand Up @@ -1496,6 +1494,10 @@
{", ", ", "},
{": ", ": "},
// not used any more
{"Keys", "Llaves"},
{"This seed picked your look. Commit to it!", "Esta semilla ha elegido tu aspecto. ¡Acéptalo!"},
{"Seed: %s", "Semilla: %s"},
{"shared", "compartida"},
{"Marin is an item in the pool, and the desert is blocked without her.", "Marin es un objeto de la reserva, y el desierto está bloqueado sin ella."},
{"boss cutscenes", "escenas de jefes"},
{"extended consumable drop", "más consumibles"},
Expand Down
Loading
Loading