phantasia

Phantasia - 2D SDL3 RPG prototype.
git clone git://git.beep.wimdupont.com/phantasia.git
Log | Files | Refs | README | LICENSE

commit 725cd8c35c7be914c4a27db62336bfd915a00749
parent b50d20aa6344cb845ad21b5fd0cdccc6fca23ecf
Author: beep <beep@wimdupont.com>
Date:   Tue, 27 Oct 2026 10:58:16 +0000

Separate camera state from world simulation

Diffstat:
MREADME.adoc | 7+++++--
MTODO.adoc | 3---
Msrc/engine/area.c | 6++----
Msrc/engine/area.h | 3+--
Msrc/engine/render.c | 55++++++++++++++++++++++++++++++++++---------------------
Msrc/engine/render.h | 11++++++++++-
Msrc/engine/save.c | 8++++----
Msrc/engine/save.h | 2+-
Msrc/engine/world.c | 34+---------------------------------
Msrc/engine/world.h | 9+--------
Msrc/examples/courier.c | 3+--
Msrc/game/main.c | 9+++------
Msrc/game/presentation.c | 4+++-
Msrc/tests/game.c | 7+++----
Msrc/tests/render.c | 46++++++++++++++++++++++++++++++++++++++++++++--
Msrc/tests/smoke.c | 31+++++++++++--------------------
16 files changed, 124 insertions(+), 114 deletions(-)

diff --git a/README.adoc b/README.adoc @@ -69,8 +69,11 @@ Interactions and presentation events are handled after each simulation tick. Identical input per tick and random seeds reproduce simulation within the same build; this does not promise identical results across platforms. -Camera state and compile-time simulation configuration still belong to the -existing engine; this is an incremental separation, not a general-purpose SDK. +Camera state belongs to presentation. World drawing accepts a caller-supplied +camera, and player following reads the world without changing simulation. World +startup and save loading are independent of viewport dimensions. Compile-time +simulation configuration remains in the engine; this is an incremental +separation, not a general-purpose SDK. For the current implementation, start with `src/engine/*.h` for the engine's public data types and operations, `src/game/content.c` for a concrete game setup, diff --git a/TODO.adoc b/TODO.adoc @@ -8,9 +8,6 @@ that improve the game or demonstrate reuse over speculative framework features. The shared engine library, independent Parcel Run example, SDL-independent game flow and media interfaces, and fixed simulation ticks provide the foundation. -* Separate camera state from `PhWorld` and remove viewport parameters from world - startup and save loading. Simulation and persistence should not depend on how - the world is viewed. * Validate content catalogs and map references before play. Report broken IDs, destinations, and definitions early, with enough context to fix the data. * Add a small debug overlay for collision bounds, AI destinations, frame timings, diff --git a/src/engine/area.c b/src/engine/area.c @@ -38,8 +38,7 @@ ph_area_catalog_load(PhArea *area, const PhAreaCatalog *catalog, int area_id) } int -ph_world_start(PhWorld *world, const PhWorldSetup *setup, - float viewport_w, float viewport_h) +ph_world_start(PhWorld *world, const PhWorldSetup *setup) { PhArea area; int player = -1; @@ -49,8 +48,7 @@ ph_world_start(PhWorld *world, const PhWorldSetup *setup, (setup->equipment_count && !setup->equipment) || ph_area_catalog_load(&area, setup->areas, setup->start_area_id) < 0) return -1; - if (ph_world_init(world, area, setup->start_area_id, setup->content, - viewport_w, viewport_h) < 0) { + if (ph_world_init(world, area, setup->start_area_id, setup->content) < 0) { ph_area_free(&area); return -1; } diff --git a/src/engine/area.h b/src/engine/area.h @@ -49,8 +49,7 @@ const PhAreaDef *ph_area_catalog_area(const PhAreaCatalog *catalog, int area_id) const PhMarkerDef *ph_area_catalog_marker(const PhAreaCatalog *catalog, int area_id, unsigned char symbol); int ph_area_catalog_load(PhArea *area, const PhAreaCatalog *catalog, int area_id); -int ph_world_start(PhWorld *world, const PhWorldSetup *setup, - float viewport_w, float viewport_h); +int ph_world_start(PhWorld *world, const PhWorldSetup *setup); int ph_world_prepare_area(PhWorld *world, const PhArea *area, const PhAreaCatalog *catalog, int area_id, int *player); int ph_world_capture_area(PhWorld *world); diff --git a/src/engine/render.c b/src/engine/render.c @@ -4,6 +4,19 @@ #include "config.h" +void +ph_camera_follow_player(PhCamera *camera, const PhWorld *world) +{ + const PhEntity *player = ph_world_player(world); + float max_x = fmaxf(0.0f, world->area.width * PH_TILE_SIZE - camera->viewport_w); + float max_y = fmaxf(0.0f, world->area.height * PH_TILE_SIZE - camera->viewport_h); + + camera->pos.x = player ? fminf(max_x, + fmaxf(0.0f, player->pos.x - camera->viewport_w * 0.5f)) : 0.0f; + camera->pos.y = player ? fminf(max_y, + fmaxf(0.0f, player->pos.y - camera->viewport_h * 0.5f)) : 0.0f; +} + static float ph_world_pixel(float position, float camera) { @@ -39,22 +52,22 @@ ph_render_entity_frame(const PhEntityDef *def, const PhEntity *entity, } static void -ph_draw_area(PhRenderer *renderer, const PhWorld *world) +ph_draw_area(PhRenderer *renderer, const PhWorld *world, const PhCamera *camera) { int tx; int ty; - for (ty = (int)(world->camera.pos.y / PH_TILE_SIZE); + for (ty = (int)(camera->pos.y / PH_TILE_SIZE); ty < world->area.height && (float)(ty * PH_TILE_SIZE) < - world->camera.pos.y + world->camera.viewport_h; ++ty) { - for (tx = (int)(world->camera.pos.x / PH_TILE_SIZE); + camera->pos.y + camera->viewport_h; ++ty) { + for (tx = (int)(camera->pos.x / PH_TILE_SIZE); tx < world->area.width && (float)(tx * PH_TILE_SIZE) < - world->camera.pos.x + world->camera.viewport_w; ++tx) { + camera->pos.x + camera->viewport_w; ++tx) { const PhTileDef *def = ph_area_tile_def(&world->area, tx, ty); int asset_id; PhRect rect = { - .x = ph_world_pixel((float)(tx * PH_TILE_SIZE), world->camera.pos.x), - .y = ph_world_pixel((float)(ty * PH_TILE_SIZE), world->camera.pos.y), + .x = ph_world_pixel((float)(tx * PH_TILE_SIZE), camera->pos.x), + .y = ph_world_pixel((float)(ty * PH_TILE_SIZE), camera->pos.y), .w = (float)PH_TILE_SIZE, .h = (float)PH_TILE_SIZE, }; @@ -131,7 +144,7 @@ ph_draw_area(PhRenderer *renderer, const PhWorld *world) } static void -ph_draw_items(PhRenderer *renderer, const PhWorld *world) +ph_draw_items(PhRenderer *renderer, const PhWorld *world, const PhCamera *camera) { int i; @@ -145,17 +158,17 @@ ph_draw_items(PhRenderer *renderer, const PhWorld *world) continue; } - rect.x = ph_world_pixel(drop->pos.x, world->camera.pos.x) - 3.0f; - rect.y = ph_world_pixel(drop->pos.y, world->camera.pos.y) - 3.0f; + rect.x = ph_world_pixel(drop->pos.x, camera->pos.x) - 3.0f; + rect.y = ph_world_pixel(drop->pos.y, camera->pos.y) - 3.0f; rect.w = 6.0f; rect.h = 6.0f; if (def) asset_id = def->asset_id; if (ph_render_has_asset(renderer, asset_id) && def->sprite_tile_x >= 0 && def->sprite_tile_y >= 0) { - rect.x = ph_world_pixel(drop->pos.x, world->camera.pos.x) - + rect.x = ph_world_pixel(drop->pos.x, camera->pos.x) - PH_TILE_SIZE * 0.5f; - rect.y = ph_world_pixel(drop->pos.y, world->camera.pos.y) - + rect.y = ph_world_pixel(drop->pos.y, camera->pos.y) - PH_TILE_SIZE * 0.5f; rect.w = PH_TILE_SIZE; rect.h = PH_TILE_SIZE; @@ -169,7 +182,7 @@ ph_draw_items(PhRenderer *renderer, const PhWorld *world) } static void -ph_draw_entities(PhRenderer *renderer, const PhWorld *world) +ph_draw_entities(PhRenderer *renderer, const PhWorld *world, const PhCamera *camera) { int i; @@ -191,17 +204,17 @@ ph_draw_entities(PhRenderer *renderer, const PhWorld *world) if (ph_render_has_asset(renderer, asset_id) && sprite_tile_x >= 0 && sprite_tile_y >= 0) { - rect.x = ph_world_pixel(entity->pos.x, world->camera.pos.x) - + rect.x = ph_world_pixel(entity->pos.x, camera->pos.x) - PH_TILE_SIZE * 0.5f; - rect.y = ph_world_pixel(entity->pos.y, world->camera.pos.y) - + rect.y = ph_world_pixel(entity->pos.y, camera->pos.y) - PH_TILE_SIZE * 0.75f; rect.w = PH_TILE_SIZE; rect.h = PH_TILE_SIZE; ph_render_sprite(renderer, asset_id, sprite_tile_x, sprite_tile_y, rect, flip); } else { - rect.x = ph_world_pixel(entity->pos.x, world->camera.pos.x) - 7.0f; - rect.y = ph_world_pixel(entity->pos.y, world->camera.pos.y) - 12.0f; + rect.x = ph_world_pixel(entity->pos.x, camera->pos.x) - 7.0f; + rect.y = ph_world_pixel(entity->pos.y, camera->pos.y) - 12.0f; rect.w = 14.0f; rect.h = 18.0f; @@ -217,9 +230,9 @@ ph_draw_entities(PhRenderer *renderer, const PhWorld *world) void ph_render_world(PhRenderer *renderer, - const PhWorld *world) + const PhWorld *world, const PhCamera *camera) { - ph_draw_area(renderer, world); - ph_draw_items(renderer, world); - ph_draw_entities(renderer, world); + ph_draw_area(renderer, world, camera); + ph_draw_items(renderer, world, camera); + ph_draw_entities(renderer, world, camera); } diff --git a/src/engine/render.h b/src/engine/render.h @@ -6,6 +6,12 @@ enum { PH_MAX_ASSETS = 32, PH_RENDER_FONT_W = 8 }; +typedef struct { + PhVec2 pos; + float viewport_w; + float viewport_h; +} PhCamera; + typedef struct PhRenderer PhRenderer; typedef struct { float x, y, w, h; } PhRect; typedef struct { unsigned char r, g, b, a; } PhColor; @@ -28,6 +34,9 @@ void ph_render_sprite(PhRenderer *renderer, int asset_id, int sprite_tile_x, int sprite_tile_y, PhRect dst, PhFlip flip); void ph_render_entity_frame(const PhEntityDef *def, const PhEntity *entity, int *sprite_tile_x, int *sprite_tile_y, PhFlip *flip); -void ph_render_world(PhRenderer *renderer, const PhWorld *world); +/* Updates only the caller-owned camera; a missing player resets it to origin. */ +void ph_camera_follow_player(PhCamera *camera, const PhWorld *world); +void ph_render_world(PhRenderer *renderer, const PhWorld *world, + const PhCamera *camera); #endif diff --git a/src/engine/save.c b/src/engine/save.c @@ -228,7 +228,7 @@ ph_area_known(const PhAreaCatalog *catalog, int area_id) static int ph_load_stream(FILE *fp, PhWorld *world, const PhWorldSetup *setup, - PhSpellBook *spells, float viewport_w, float viewport_h) + PhSpellBook *spells) { uint32_t magic; uint32_t version; @@ -245,7 +245,7 @@ ph_load_stream(FILE *fp, PhWorld *world, const PhWorldSetup *setup, ph_read_int(fp, &area_id) < 0 || !ph_area_known(setup->areas, area_id) || ph_read_entity(fp, &player, area_id) < 0 || ph_area_catalog_load(&area, setup->areas, area_id) < 0) return -1; - if (ph_world_init(world, area, area_id, setup->content, viewport_w, viewport_h) < 0) { + if (ph_world_init(world, area, area_id, setup->content) < 0) { ph_area_free(&area); return -1; } @@ -328,7 +328,7 @@ fail: int ph_save_load(const char *path, PhWorld *world, const PhWorldSetup *setup, - PhSpellBook *spells, float viewport_w, float viewport_h) + PhSpellBook *spells) { FILE *fp; int result; @@ -336,7 +336,7 @@ ph_save_load(const char *path, PhWorld *world, const PhWorldSetup *setup, if (!path || !world || !setup || !setup->areas || !spells) return -1; fp = fopen(path, "rb"); if (!fp) return errno == ENOENT ? 0 : -1; - result = ph_load_stream(fp, world, setup, spells, viewport_w, viewport_h); + result = ph_load_stream(fp, world, setup, spells); if (fclose(fp) != 0) { if (result == 0) ph_world_destroy(world); result = -1; diff --git a/src/engine/save.h b/src/engine/save.h @@ -9,6 +9,6 @@ enum { PH_SAVE_VERSION = 1 }; int ph_save_write(const char *path, PhWorld *world, const PhSpellBook *spells); /* Returns 1 when loaded, 0 when no save exists, and -1 for an invalid save. */ int ph_save_load(const char *path, PhWorld *world, const PhWorldSetup *setup, - PhSpellBook *spells, float viewport_w, float viewport_h); + PhSpellBook *spells); #endif diff --git a/src/engine/world.c b/src/engine/world.c @@ -35,14 +35,6 @@ typedef struct { uint32_t tile_y; } PhMapMarker; -static float -ph_clampf(float value, float min, float max) -{ - if (value < min) return min; - if (value > max) return max; - return value; -} - static int ph_clampi(int value, int min, int max) { @@ -86,25 +78,6 @@ ph_item_def_index(const PhWorld *world, int item_id) return -1; } -static void -ph_camera_follow_player(PhWorld *world) -{ - const PhEntity *player; - float max_x; - float max_y; - - player = ph_world_player(world); - if (!player) return; - - max_x = (float)(world->area.width * PH_TILE_SIZE) - world->camera.viewport_w; - max_y = (float)(world->area.height * PH_TILE_SIZE) - world->camera.viewport_h; - if (max_x < 0.0f) max_x = 0.0f; - if (max_y < 0.0f) max_y = 0.0f; - - world->camera.pos.x = ph_clampf(player->pos.x - world->camera.viewport_w * 0.5f, 0.0f, max_x); - world->camera.pos.y = ph_clampf(player->pos.y - world->camera.viewport_h * 0.5f, 0.0f, max_y); -} - static int ph_position_blocked(const PhWorld *world, PhVec2 pos) { @@ -483,7 +456,7 @@ ph_world_update_actors(PhWorld *world, float dt) int ph_world_init(PhWorld *world, PhArea area, int area_id, - PhWorldCatalog content, float viewport_w, float viewport_h) + PhWorldCatalog content) { if (content.entity_count < 0 || content.entity_count > PH_MAX_ENTITY_TYPES || content.item_count < 0 || content.item_count > PH_MAX_ITEM_TYPES || @@ -493,8 +466,6 @@ ph_world_init(PhWorld *world, PhArea area, int area_id, world->area = area; world->area_id = area_id; world->content = content; - world->camera.viewport_w = viewport_w; - world->camera.viewport_h = viewport_h; world->player_index = -1; world->encounter_index = -1; world->rng_state = 0x5048414eu; @@ -517,7 +488,6 @@ ph_world_enter_area(PhWorld *world, PhArea area, int area_id, PhVec2 player_pos) player->area_id = area_id; player->pos = player->motion.target = player->behavior.home = player_pos; player->motion.moving = 0; - ph_camera_follow_player(world); } int @@ -705,7 +675,6 @@ ph_world_set_player(PhWorld *world, int entity_index) { if (entity_index >= 0 && entity_index < world->entity_count) { world->player_index = entity_index; - ph_camera_follow_player(world); } } @@ -991,7 +960,6 @@ ph_world_tick(PhWorld *world, PhInput input, float dt) } ph_world_update_actors(world, dt); - ph_camera_follow_player(world); } int diff --git a/src/engine/world.h b/src/engine/world.h @@ -228,14 +228,7 @@ typedef struct { } PhArea; typedef struct { - PhVec2 pos; - float viewport_w; - float viewport_h; -} PhCamera; - -typedef struct { PhArea area; - PhCamera camera; PhWorldCatalog content; PhEntity entities[PH_MAX_ENTITIES]; PhGroundItem ground_items[PH_MAX_GROUND_ITEMS]; @@ -268,7 +261,7 @@ void ph_area_free(PhArea *area); void ph_world_destroy(PhWorld *world); int ph_world_init(PhWorld *world, PhArea area, int area_id, - PhWorldCatalog content, float viewport_w, float viewport_h); + PhWorldCatalog content); void ph_world_enter_area(PhWorld *world, PhArea area, int area_id, PhVec2 player_pos); int ph_world_spawn_entity(PhWorld *world, int type_id, PhVec2 pos, diff --git a/src/examples/courier.c b/src/examples/courier.c @@ -90,8 +90,7 @@ main(int argc, char **argv) /* Runtime maps store tile catalog indices, not source symbols. */ for (i = 0; i < WIDTH * HEIGHT; ++i) map[i] = map[i] == '#' ? 0 : map[i] == 'D' ? 2 : 1; - if (ph_world_init(&world, area, 1, content, WIDTH * PH_TILE_SIZE, - HEIGHT * PH_TILE_SIZE) < 0) return 1; + if (ph_world_init(&world, area, 1, content) < 0) return 1; key = ph_world_spawn_entity(&world, COURIER, (PhVec2){ PH_TILE_CENTER(1), PH_TILE_CENTER(1) }, 0, 1); if (key < 0) goto fail; diff --git a/src/game/main.c b/src/game/main.c @@ -175,14 +175,12 @@ ph_run_game(void) fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); return 1; } - save_status = ph_save_load(PH_SAVE_PATH, &world, &ph_game_world, &spells, - (float)PH_VIEW_W, (float)PH_VIEW_H); + save_status = ph_save_load(PH_SAVE_PATH, &world, &ph_game_world, &spells); if (save_status < 0) { fprintf(stderr, "save is invalid; starting a new game\n"); spells = ph_player_spellbook; } - if (save_status <= 0 && ph_world_start(&world, &ph_game_world, - (float)PH_VIEW_W, (float)PH_VIEW_H) < 0) { + if (save_status <= 0 && ph_world_start(&world, &ph_game_world) < 0) { SDL_Quit(); return 1; } @@ -232,8 +230,7 @@ ph_run_game(void) if (request & PH_GAME_REQUEST_NEW) { ph_world_destroy(&world); spells = ph_player_spellbook; - if (ph_world_start(&world, &ph_game_world, - (float)PH_VIEW_W, (float)PH_VIEW_H) < 0) running = 0; + if (ph_world_start(&world, &ph_game_world) < 0) running = 0; else { remove(PH_SAVE_PATH); context.menu = PH_MENU_NONE; diff --git a/src/game/presentation.c b/src/game/presentation.c @@ -713,6 +713,7 @@ ph_present_frame(PhRenderer *renderer, const PhWorld *world = context->world; const PhBattle *battle = context->battle; PhGameMode game = *context->mode; + PhCamera camera = { .viewport_w = PH_VIEW_W, .viewport_h = PH_VIEW_H }; if (game == PH_GAME_BATTLE) { ph_draw_battle(renderer, world, battle); @@ -731,7 +732,8 @@ ph_present_frame(PhRenderer *renderer, ph_render_color(renderer, (PhColor){ PH_CLEAR_COLOR }); ph_render_clear(renderer); - ph_render_world(renderer, world); + ph_camera_follow_player(&camera, world); + ph_render_world(renderer, world, &camera); if (context->menu == PH_MENU_CHARACTER) { ph_draw_character_sheet(renderer, world, labels); } else if (context->menu == PH_MENU_INVENTORY) { diff --git a/src/tests/game.c b/src/tests/game.c @@ -43,7 +43,7 @@ ph_timing_smoke(void) PhGameContext context = { .world = &world, .mode = &mode }; uint64_t previous = 0; - if (ph_world_init(&world, area, 1, catalog, 320, 128) < 0) return 1; + if (ph_world_init(&world, area, 1, catalog) < 0) return 1; if (ph_world_spawn_entity(&world, 1, (PhVec2){ 24, 24 }, 0, 1) < 0 || ph_world_spawn_entity(&world, 2, (PhVec2){ 200, 88 }, 4, 1) < 0) return 1; ph_world_set_player(&world, 0); @@ -104,7 +104,7 @@ main(void) if (!mkdtemp(directory)) return 1; snprintf(save_path, sizeof(save_path), "%s/checkpoint.sav", directory); snprintf(temp_path, sizeof(temp_path), "%s.tmp", save_path); - CHECK(ph_world_start(&world, &ph_game_world, PH_VIEW_W, PH_VIEW_H) == 0); + CHECK(ph_world_start(&world, &ph_game_world) == 0); player = &world.entities[world.player_index]; position = player->pos; ph_game_update(&game, (PhInput){ .move_x = 1 }, 0.05f, save_path); @@ -176,8 +176,7 @@ main(void) world.encounter_index = enemy; ph_game_update(&game, (PhInput){ 0 }, 0.0f, save_path); CHECK(mode == PH_GAME_TRANSITION && world.combat_active); - CHECK(ph_save_load(save_path, &loaded, &ph_game_world, &loaded_spells, - PH_VIEW_W, PH_VIEW_H) == 1); + CHECK(ph_save_load(save_path, &loaded, &ph_game_world, &loaded_spells) == 1); CHECK(!loaded.combat_active); ph_game_update(&game, (PhInput){ 0 }, PH_BATTLE_TRANSITION_SECONDS, save_path); CHECK(mode == PH_GAME_BATTLE); diff --git a/src/tests/render.c b/src/tests/render.c @@ -8,12 +8,51 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include "config.h" #if PH_USE_SDL static int +ph_camera_smoke(void) +{ + PhWorld world = { .area = { .width = 40, .height = 30 }, + .player_index = 0, .entity_count = 1 }; + PhWorld before; + PhCamera camera = { .viewport_w = 320, .viewport_h = 240 }; + PhCamera other = { .viewport_w = 160, .viewport_h = 120 }; + + world.entities[0].active = 1; + world.entities[0].pos = (PhVec2){ 300, 220 }; + memcpy(&before, &world, sizeof(world)); + ph_camera_follow_player(&camera, &world); + ph_camera_follow_player(&other, &world); + if (camera.pos.x != 140 || camera.pos.y != 100 || + other.pos.x != 220 || other.pos.y != 160 || + memcmp(&before, &world, sizeof(world))) return 1; + world.entities[0].pos = (PhVec2){ 639, 479 }; + ph_camera_follow_player(&camera, &world); + if (camera.pos.x != 320 || camera.pos.y != 240) return 1; + world.entities[0].pos = (PhVec2){ 8, 8 }; + ph_camera_follow_player(&camera, &world); + if (camera.pos.x != 0 || camera.pos.y != 0) return 1; + world.entities[0].pos = (PhVec2){ 300, 220 }; + camera.viewport_w = 800; + camera.viewport_h = 600; + ph_camera_follow_player(&camera, &world); + if (camera.pos.x != 0 || camera.pos.y != 0) return 1; + /* A smaller area must discard the previous area's scroll immediately. */ + world.area.width = world.area.height = 4; + ph_camera_follow_player(&other, &world); + if (other.pos.x != 0 || other.pos.y != 0) return 1; + world.player_index = -1; + camera.pos = (PhVec2){ 100, 100 }; + ph_camera_follow_player(&camera, &world); + return camera.pos.x != 0 || camera.pos.y != 0; +} + +static int ph_pixel_is(SDL_Surface *surface, int x, int y, PhColor color) { Uint8 r, g, b, a; @@ -178,8 +217,11 @@ main(void) } result = ph_media_smoke(target, surface); - if (ph_world_start(&world, &ph_game_world, - (float)PH_VIEW_W, (float)PH_VIEW_H) < 0) { + if (ph_camera_smoke()) { + fprintf(stderr, "camera smoke test failed\n"); + result = 1; + } + if (ph_world_start(&world, &ph_game_world) < 0) { SDL_DestroyRenderer(target); SDL_DestroySurface(surface); SDL_Quit(); diff --git a/src/tests/smoke.c b/src/tests/smoke.c @@ -63,7 +63,7 @@ ph_area_catalog_test(void) int entity_count; int item_count; - if (ph_world_init(&world, area, 7, content, 32.0f, 32.0f) < 0 || + if (ph_world_init(&world, area, 7, content) < 0 || ph_world_prepare_area(&world, &area, &catalog, 7, &player) < 0) return 1; if (player < 0 || world.entity_count != 2 || world.ground_item_count != 1 || @@ -126,9 +126,7 @@ ph_movement_test(int open, int blocked) for (x = 0; x < area.width; ++x) if (!x || !y || x == area.width - 1 || y == area.height - 1) tiles[y * area.width + x] = (unsigned char)blocked; - if (ph_world_init(&world, area, 1, content, - (float)(area.width * PH_TILE_SIZE), - (float)(area.height * PH_TILE_SIZE)) < 0 || + if (ph_world_init(&world, area, 1, content) < 0 || (player_index = ph_world_spawn_entity(&world, 1, player_start, 0, 1)) < 0 || (mob_index = ph_world_spawn_entity(&world, 2, mob_start, TERRITORY, 1)) < 0) return 1; @@ -208,7 +206,7 @@ ph_area_state_scaling_test(void) int i; int result = 1; - if (ph_world_init(&world, area, 1, content, 32.0f, 32.0f) < 0 || + if (ph_world_init(&world, area, 1, content) < 0 || (player = ph_world_spawn_entity(&world, 1, (PhVec2){ 0 }, 0, 1)) < 0) return 1; ph_world_set_player(&world, player); @@ -248,7 +246,7 @@ ph_flash_delay_test(void) int cast; int expected_next; - if (ph_world_init(&world, area, 1, content, 32.0f, 32.0f) < 0 || + if (ph_world_init(&world, area, 1, content) < 0 || (player = ph_world_spawn_entity(&world, 1, (PhVec2){ 0 }, 0, 1)) < 0 || (enemy = ph_world_spawn_entity(&world, 2, (PhVec2){ 16, 0 }, 0, 1)) < 0) return 1; @@ -337,9 +335,7 @@ ph_logic_test(int open, int blocked) memset(tiles, blocked, sizeof(tiles)); tiles[ROW * area.width + LEFT_COL] = (unsigned char)open; tiles[ROW * area.width + RIGHT_COL] = (unsigned char)open; - if (ph_world_init(&world, area, 1, content, - (float)(area.width * PH_TILE_SIZE), - (float)(area.height * PH_TILE_SIZE)) < 0 || + if (ph_world_init(&world, area, 1, content) < 0 || (player_index = ph_world_spawn_entity(&world, 1, player_start, 0, 1)) < 0 || (enemy_index = ph_world_spawn_entity(&world, 4, enemy_start, 0, 1)) < 0 || ph_world_drop_item(&world, 1, player_start, 1, 1) < 0 || @@ -366,7 +362,6 @@ ph_logic_test(int open, int blocked) if (!player || (int)(player->pos.x / PH_TILE_SIZE) != RIGHT_COL || (int)(player->pos.y / PH_TILE_SIZE) != ROW || player->motion.facing_x != 0 || player->motion.facing_y != 1 || - world.camera.pos.x != 0.0f || world.camera.pos.y != 0.0f || ph_world_item_amount(&world, 1) != 0 || ph_world_item_amount(&world, 2) != 0 || ph_world_item_amount(&world, 3) != 1 || player->vitals.hp != 4 || @@ -469,7 +464,7 @@ ph_area_shop_test(void) int i; unsigned int events; - if (ph_world_start(&world, &ph_game_world, 320.0f, 240.0f) < 0) return 1; + if (ph_world_start(&world, &ph_game_world) < 0) return 1; player = &world.entities[world.player_index]; potion = ph_world_item_def(&world, PH_ITEM_HEALING_POTION); ether = ph_world_item_def(&world, PH_ITEM_ETHER); @@ -638,9 +633,8 @@ ph_save_test(void) remove(path); remove("obj/test-save.phsave.tmp"); - if (ph_save_load(path, &loaded, &ph_game_world, &loaded_spells, - 320.0f, 240.0f) != 0 || - ph_world_start(&world, &ph_game_world, 320.0f, 240.0f) < 0) return 1; + if (ph_save_load(path, &loaded, &ph_game_world, &loaded_spells) != 0 || + ph_world_start(&world, &ph_game_world) < 0) return 1; player = &world.entities[world.player_index]; player->vitals.hp = 23; player->xp = 91; @@ -650,8 +644,7 @@ ph_save_test(void) if (ph_enter_portal(&world, PH_AREA_STONEHOLLOW) != 1 || world.entity_count != 1) goto done_world; if (ph_save_write(path, &world, &spells) < 0) goto done_world; - if (ph_save_load(path, &loaded, &ph_game_world, &loaded_spells, - 320.0f, 240.0f) != 1) { + if (ph_save_load(path, &loaded, &ph_game_world, &loaded_spells) != 1) { fprintf(stderr, "save round trip failed to load\n"); goto done_world; } @@ -678,8 +671,7 @@ ph_save_test(void) ph_battle_begin(&checkpoint_battle, &loaded, 1, loaded_spells); --loaded.entities[1].vitals.hp; if (ph_save_write(path, &loaded, &loaded_spells) != -1 || - ph_save_load(path, &checkpoint, &ph_game_world, &loaded_spells, - 320.0f, 240.0f) != 1) goto done_loaded; + ph_save_load(path, &checkpoint, &ph_game_world, &loaded_spells) != 1) goto done_loaded; if (checkpoint.entity_count != 2 || checkpoint.entities[1].vitals.hp != enemy_hp) { ph_world_destroy(&checkpoint); @@ -694,8 +686,7 @@ ph_save_test(void) goto done_loaded; } if (fclose(corrupt) != 0) goto done_loaded; - if (ph_save_load(path, &(PhWorld){ 0 }, &ph_game_world, &loaded_spells, - 320.0f, 240.0f) != -1) goto done_loaded; + if (ph_save_load(path, &(PhWorld){ 0 }, &ph_game_world, &loaded_spells) != -1) goto done_loaded; result = 0; done_loaded: