diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-16 07:08:55 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-16 07:08:55 +0800 |
| commit | 1c1c2aa89920ffcf4d80a29c12a9999188adbaac (patch) | |
| tree | fcfac42e390af8b284924fa79615dddb008241a0 | |
| parent | 85c684cefcb133ce5025f991077b2d9f9bc9ec64 (diff) | |
add random fights to rmfield
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | kon/konrmfield.c | 62 | ||||
| -rw-r--r-- | kon/konrmfield.h | 11 |
3 files changed, 72 insertions, 3 deletions
@@ -55,7 +55,7 @@ The engine modules are a `.h` and a `.c` pair, they depend on each other a bit, | rmmap | the const data shapes mzmap writes for RPG Maker maps, events, pages and tilesets, which page an event shows, reading a tile, and walking: passability, terrain tags, regions | | rmtile | where the pieces of an RPG Maker tile are on its sheet: autotile shapes for floors, walls and waterfalls, animation frames (adds rmmap) | | rmdraw | draws an RPG Maker map from its tileset sheets: layers, shadows, tiles that go above the actors, looping maps (adds rmmap, rmtile) | -| rmfield | the player and the events of an RPG Maker map walking around it: steps at the speed of the character, wandering and routes, what blocks what, what starts an event by touch, action or autorun, and the script commands for moving characters, map transfers and self switches (adds rmmap) | +| rmfield | the player and the events of an RPG Maker map walking around it: steps at the speed of the character, wandering and routes, what blocks what, what starts an event by touch, action or autorun, random fights by steps and regions, and the script commands for moving characters, map transfers and self switches (adds rmmap) | | sound | RPG Maker style audio channels: BGM, BGS, ME and SE, fades, a saved BGM, loop points (adds audio) | | model | glTF models and animation, converted to my own `.kmdl` format | | ui | immediate mode ui | diff --git a/kon/konrmfield.c b/kon/konrmfield.c index 92401de..f4c741d 100644 --- a/kon/konrmfield.c +++ b/kon/konrmfield.c @@ -51,6 +51,9 @@ static int roll(kon_rmField_t *field, int n) return n > 0 ? (int)(field->seed % (uint32_t)n) : 0; } +static void makeEncounterCount(kon_rmField_t *field); +static int canEncounter(const kon_rmField_t *field); + static int dirX(int dir) { return dir == 6 ? 1 : dir == 4 ? -1 : 0; @@ -466,6 +469,7 @@ int kon_rmFieldInit(kon_rmField_t *field, const kon_rmMap_t *map, const kon_rmTi chars[KON_RM_PLAYER].active = 1; chars[KON_RM_PLAYER].trigger = 0; kon_rmFieldRefresh(field); + makeEncounterCount(field); return 0; } @@ -565,7 +569,11 @@ void kon_rmFieldUpdate(kon_rmField_t *field) if (e->active && e->trigger == 3 && !field->busy) start(field, i); } - if (wasMoving && !moving(p) && !field->busy) startAt(field, p->x, p->y, 0x06, 0); + if (wasMoving && !moving(p) && !field->busy && startAt(field, p->x, p->y, 0x06, 0) == 0 && canEncounter(field)) { + int progress = kon_rmHasFlag(field->map, field->tileset, p->x, p->y, KON_RM_FLAG_BUSH) ? 4 : 2; + + field->encounterCount -= field->encounterHalf ? progress / 2 : progress; + } } /*** the player ***/ @@ -602,6 +610,58 @@ int kon_rmFieldAction(kon_rmField_t *field) return n > 0; } +/*** fights ***/ + +static void makeEncounterCount(kon_rmField_t *field) +{ + int n = field->map->encounterStep; + + if (n < 0) n = 0; + if (n > 100000) n = 100000; + field->encounterCount = (roll(field, n) + roll(field, n) + 1) * 2; +} + +static int canEncounter(const kon_rmField_t *field) +{ + return !field->encounterNone && !field->chars[KON_RM_PLAYER].routeForced; +} + +int kon_rmFieldEncounter(kon_rmField_t *field) +{ + const kon_rmMap_t *map; + long long sum = 0, value; + int i, region; + + if (!field || !field->chars || field->busy || field->encounterCount > 0) return 0; + map = field->map; + makeEncounterCount(field); + if (!canEncounter(field) || !map->encounters) return 0; + region = kon_rmRegion(map, field->chars[KON_RM_PLAYER].x, field->chars[KON_RM_PLAYER].y); + for (i = 0; i < map->encounterCount; i++) { + const kon_rmEncounter_t *e = &map->encounters[i]; + int k, inRegion = e->regionCount <= 0; + + for (k = 0; k < e->regionCount && e->regions; k++) { + if (e->regions[k] == region) inRegion = 1; + } + if (inRegion && e->weight > 0) sum += e->weight; + } + if (sum <= 0) return 0; + value = roll(field, sum > 2147483647 ? 2147483647 : (int)sum); + for (i = 0; i < map->encounterCount; i++) { + const kon_rmEncounter_t *e = &map->encounters[i]; + int k, inRegion = e->regionCount <= 0; + + for (k = 0; k < e->regionCount && e->regions; k++) { + if (e->regions[k] == region) inRegion = 1; + } + if (!inRegion || e->weight <= 0) continue; + value -= e->weight; + if (value < 0) return e->troopId > 0 ? e->troopId : 0; + } + return 0; +} + /*** events that start ***/ int kon_rmFieldNextStart(kon_rmField_t *field, int *eventId, int *pageIndex) diff --git a/kon/konrmfield.h b/kon/konrmfield.h index d2b358f..17a44fd 100644 --- a/kon/konrmfield.h +++ b/kon/konrmfield.h @@ -76,10 +76,12 @@ typedef struct kon_rmField { int count; uint32_t seed; int busy; /* set it while a script that stops the player is running */ - int steps; /* the steps of the player, count them for encounters and take them back to 0 */ + int steps; /* the steps of the player so far, for the game to use as it likes */ int thisEvent; /* the id of the event whose script is running, for the commands that mean "this event". set it before you run one */ int waitIndex; /* the character a script waits for, -1 for none */ int transferPending; + int encounterCount; /* what is left until the next fight, in halves of a step */ + int encounterHalf, encounterNone; /* set them to halve the steps that count, or to stop fights altogether */ kon_rmTransfer_t transfer; /* both can stay NULL. the first is how a route that turns a switch on or off reaches your game, the second says whether @@ -111,6 +113,13 @@ int kon_rmFieldPlayerStep(kon_rmField_t *field, int dir, int dash); /* the action button: an event on the player's tile or in front of it, or behind a counter. returns 1 when one starts */ int kon_rmFieldAction(kon_rmField_t *field); +/*** fights ***/ + +/* the random fights of the map: every step of the player counts down, a bush counts twice, and when it runs out a troop is picked + from the map's list by weight, only the ones whose regions include the one the player stands in. returns the troop id once, + or 0 for no fight. call it when no script is running. nothing starts while the player is walking a forced route */ +int kon_rmFieldEncounter(kon_rmField_t *field); + /*** events that start ***/ /* the next event that wants its script to run, lowest first: the touched or talked to, and the autorun ones. call it when no |
