diff options
author | Lucas Fryzek <lucas.fryzek@fryzekconcepts.com> | 2025-03-22 13:11:09 +0000 |
---|---|---|
committer | Lucas Fryzek <lucas.fryzek@fryzekconcepts.com> | 2025-03-22 13:11:09 +0000 |
commit | a2b843b05622f540557fc29ab8962a7f64395fb0 (patch) | |
tree | 25f16387585abe0e004b7e98e184cbe9c88ba31c | |
parent | f4e83d48a0e355707dbe6912b4c585436757bb6e (diff) |
Work out more of gathering logic
-rw-r--r-- | main.rhm | 29 | ||||
-rw-r--r-- | world.rhm | 125 |
2 files changed, 108 insertions, 46 deletions
@@ -1,6 +1,7 @@ #lang rhombus/static -import "world.rhm" +import: + "world.rhm" fun test(test_result :: Boolean, test_str :: String): if test_result @@ -16,7 +17,7 @@ fun let wrld = world.World() let chunk = world.Chunk(64, 64, 0, 0) wrld.chunks.add(chunk) -let entity = world.Entity(0, 0, 0, chunk) +let entity = world.EntityPlayer(0, 0, 0, chunk) wrld.entities.add(entity) @@ -36,7 +37,7 @@ reset_entity(entity) test(!entity.move(0, 0), "starting pos") let new_chunk = world.Chunk(64, 64, 1, 0) -chunk.add_neighbour(new_chunk, #'east) +chunk.add_neighbour(new_chunk, world.Direction.east) reset_entity(entity, 63, 0) test(entity.move(64, 0), "cross chunk") test(entity.current_chunk == new_chunk, "changed chunk") @@ -44,12 +45,22 @@ test(entity.current_chunk == new_chunk, "changed chunk") entity.current_chunk := chunk reset_entity(entity, 0, 1) entity.current_chunk.set_tile(0, 1, world.Tile(#'wall_north)) -test(!entity.move(0, 0), "Blocked by wall") -test(entity.move(1,1), "Move by wall") +test(!entity.move(0, 0), "blocked by wall") +test(entity.move(1,1), "move by wall") reset_entity(entity, 0, 0) -let other_ent = world.Entity(1, 1, 1, chunk) -test(entity.gather(other_ent), "Gathering") +let other_ent = world.EntityGatherable(1, 1, 1, chunk) +let gather_result = entity.gather(other_ent) +test(gather_result == world.ActionResponse.ok || gather_result == world.ActionResponse.unsuccessful, "gathering") -//world.entities -//println(@str{Entity is @(entity.x) @(entity.y)}) +reset_entity(other_ent, 2, 2) +entity.timer := 0 +test(entity.gather(other_ent) == world.ActionResponse.invalid, "gather too far away") + +reset_entity(other_ent, 64, 0) +reset_entity(entity, 63, 0) +entity.timer := 0 +let gather_result = entity.gather(other_ent) +test(gather_result == world.ActionResponse.ok || gather_result == world.ActionResponse.unsuccessful, "gather accross chunk") +entity.tick() +test(entity.gather(other_ent) == world.ActionResponse.cooldown, "gather cooldown") @@ -1,11 +1,18 @@ #lang rhombus/static +import rhombus/random export: Chunk Entity + EntityGatherable + EntityPlayer + ActionResponse + Direction World Tile +let rand = random.Random() + enum Direction: north north_east @@ -22,21 +29,21 @@ enum TileType: fun flip_block(block :: maybe(Direction)) :: maybe(Direction): match block - | #'north: #'south - | #'north_east: #'south_west - | #'east: #'west - | #'south_east: #'north_west - | #'south: #'north - | #'south_west: #'north_east - | #'west: #'east - | #'north_west: #'south_east + | Direction.north: Direction.south + | Direction.north_east: Direction.south_west + | Direction.east: Direction.west + | Direction.south_east: Direction.north_west + | Direction.south: Direction.north + | Direction.south_west: Direction.north_east + | Direction.west: Direction.east + | Direction.north_west: Direction.south_east | ~else: #false class Tile(type :: TileType): method get_block() :: maybe(Direction): match type - | #'empty: #false - | #'wall_north: #'north + | TileType.empty: #false + | TileType.wall_north: Direction.north class Chunk(width :: Int, height :: Int, @@ -45,7 +52,7 @@ class Chunk(width :: Int, tiles :: Array.now_of(Tile), neighbours :: MutableMap.now_of(Direction, Chunk)): constructor(width :: Int, height :: Int, offset_x :: Int, offset_y :: Int): - super(width, height, offset_x, offset_y, Array.make(width * height, Tile(#'empty)), MutableMap()) + super(width, height, offset_x, offset_y, Array.make(width * height, Tile(TileType.empty)), MutableMap()) method add_neighbour(chunk :: Chunk, direction :: Direction): neighbours[direction] := chunk @@ -57,6 +64,9 @@ class Chunk(width :: Int, tiles[y * width + x] := tile class Entity(id:: Int, mutable x :: Int, mutable y :: Int, mutable current_chunk :: Chunk): + nonfinal + // Validate that the provided coordinates are within the max distance range of + // entities current coordinates. method validate_dist(x :: Int, y :: Int, max_dist :: Int): let diff_x = math.abs(this.x - x) let diff_y = math.abs(this.y - y) @@ -68,6 +78,8 @@ class Entity(id:: Int, mutable x :: Int, mutable y :: Int, mutable current_chunk let no_movement = diff_x == 0 && diff_y == 0 !no_movement && (diagonal || x_axis || y_axis) + // Validate that the x,y coordinates map to a chunk that is + // near the current coordinates of the entity method validate_chunk(x :: Int, y :: Int) :: maybe(Chunk): let current_chunk = this.current_chunk let local_x = x - current_chunk.offset_x * current_chunk.width @@ -79,32 +91,34 @@ class Entity(id:: Int, mutable x :: Int, mutable y :: Int, mutable current_chunk let inside_x = !(less_x || more_x) let inside_y = !(less_y || more_y) let next_chunk :: maybe(Chunk) = cond - | inside_x && less_y: current_chunk.neighbours.get(#'north, #false) - | more_x && less_y: current_chunk.neighbours.get(#'north_east, #false) - | more_x && inside_y: current_chunk.neighbours.get(#'east, #false) - | more_x && more_y: current_chunk.neighbours.get(#'south_east, #false) - | inside_x && more_y: current_chunk.neighbours.get(#'south, #false) - | less_x && more_y: current_chunk.neighbours.get(#'south_west, #false) - | less_x && inside_y: current_chunk.neighbours.get(#'west, #false) - | less_x && less_y: current_chunk.neighbours.get(#'north_west, #false) + | inside_x && less_y: current_chunk.neighbours.get(Direction.north, #false) + | more_x && less_y: current_chunk.neighbours.get(Direction.north_east, #false) + | more_x && inside_y: current_chunk.neighbours.get(Direction.east, #false) + | more_x && more_y: current_chunk.neighbours.get(Direction.south_east, #false) + | inside_x && more_y: current_chunk.neighbours.get(Direction.south, #false) + | less_x && more_y: current_chunk.neighbours.get(Direction.south_west, #false) + | less_x && inside_y: current_chunk.neighbours.get(Direction.west, #false) + | less_x && less_y: current_chunk.neighbours.get(Direction.north_west, #false) | ~else: current_chunk next_chunk + // Validate that the tile at the coordinates would not block a movement of the entity + // to those coordinates from its current coordinates method validate_move(x :: Int, y :: Int, max_dist :: Int, target_chunk :: Chunk): let current_tile = this.current_chunk.get_tile(this.x, this.y) let target_tile = target_chunk.get_tile(x, y) let diff_x = x - this.x let diff_y = y - this.y let direction = cond - | diff_x == 0 && diff_y < 0: #'north - | diff_x > 0 && diff_y < 0: #'north_east - | diff_x > 0 && diff_y == 0: #'east - | diff_x > 0 && diff_y > 0: #'south_east - | diff_x == 0 && diff_y > 0: #'south - | diff_x < 0 && diff_y > 0: #'south_west - | diff_x < 0 && diff_y == 0: #'west - | diff_x < 0 && diff_y < 0: #'north_west + | diff_x == 0 && diff_y < 0: Direction.north + | diff_x > 0 && diff_y < 0: Direction.north_east + | diff_x > 0 && diff_y == 0: Direction.east + | diff_x > 0 && diff_y > 0: Direction.south_east + | diff_x == 0 && diff_y > 0: Direction.south + | diff_x < 0 && diff_y > 0: Direction.south_west + | diff_x < 0 && diff_y == 0: Direction.west + | diff_x < 0 && diff_y < 0: Direction.north_west let current_block = current_tile.get_block() let target_block = flip_block(target_tile.get_block()) !(direction == current_block || direction == target_block) @@ -123,22 +137,59 @@ class Entity(id:: Int, mutable x :: Int, mutable y :: Int, mutable current_chunk | ~else: #false - method gather(target_entity :: Entity): + + +class EntityGatherable(quantity :: Int, odds :: Real): + extends Entity + + constructor(id :: Int, x :: Int, y :: Int, current_chunk :: Chunk): + super(id, x, y, current_chunk)(10, 1 / 10) + +enum ActionResponse: + ok + unsuccessful + invalid + cooldown + +class EntityPlayer(mutable timer :: Int): + extends Entity + + field max_timer = 4 + + constructor(id :: Int, x :: Int, y :: Int, current_chunk :: Chunk): + super(id, x, y, current_chunk)(0) + + method tick(): + // TODO this "ticks" the entity. Things like healing and other + // stuff should happen within here. In the future we probably + // want to set a state where the player is gathering and in tick + // we calculate the odds that they did gather properly + if timer == 0: + | timer := max_timer + | timer := timer - 1 + + method gather(target_entity :: Entity) :: ActionResponse: let x = target_entity.x let y = target_entity.y let target_chunk = validate_chunk(x, y) - - fun validate_gather_resource() :: Boolean: - // TODO figure out how to implement resource gathering - // it could be better to keep them as a tile and update the - // tile from regular to consumed - #false + let right_type = target_entity is_a EntityGatherable + + fun validate_gather_resource(entity :: EntityGatherable) :: ActionResponse: + // TODO odds should change based on skills of player + // we should also validate player is carrying the right tool + // we should also have the timer count down every tick + // not just inside the gathering call + let roll = rand.random() + if roll < entity.odds: + | ActionResponse.ok + | ActionResponse.unsuccessful cond - | validate_dist(x, y, 1) && target_chunk != #false && validate_gather_resource(): - #true + | timer != 0: ActionResponse.cooldown + | right_type && validate_dist(x, y, 1) && target_chunk != #false: + validate_gather_resource(target_entity) | ~else: - #false + ActionResponse.invalid class World(chunks :: MutableList.now_of(Chunk), entities :: MutableList.now_of(Entity)): |