diff options
author | Lucas Fryzek <lucas.fryzek@fryzekconcepts.com> | 2025-03-22 15:38:40 +0000 |
---|---|---|
committer | Lucas Fryzek <lucas.fryzek@fryzekconcepts.com> | 2025-03-22 15:38:40 +0000 |
commit | cb01f1f6f930cee6529e51dc3d29945edaa9d95a (patch) | |
tree | a1151eacb471430ccae1a35aba18da2a742d0cf2 | |
parent | a2b843b05622f540557fc29ab8962a7f64395fb0 (diff) |
Split up files
-rw-r--r-- | chunk.rhm | 58 | ||||
-rw-r--r-- | entity.rhm | 148 | ||||
-rw-r--r-- | world.rhm | 191 |
3 files changed, 213 insertions, 184 deletions
diff --git a/chunk.rhm b/chunk.rhm new file mode 100644 index 0000000..3ded42d --- /dev/null +++ b/chunk.rhm @@ -0,0 +1,58 @@ +#lang rhombus/static + +export: + Direction + TileType + Tile + Chunk + flip_block + +enum Direction: + north + north_east + east + south_east + south + south_west + west + north_west + +enum TileType: + empty + wall_north + +fun flip_block(block :: maybe(Direction)) :: maybe(Direction): + match block + | 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 + | TileType.empty: #false + | TileType.wall_north: Direction.north + +class Chunk(width :: Int, + height :: Int, + offset_x :: Int, + offset_y :: 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(TileType.empty)), MutableMap()) + + method add_neighbour(chunk :: Chunk, direction :: Direction): + neighbours[direction] := chunk + + method get_tile(x :: Int, y :: Int) :: Tile: + tiles[y * width + x] + + method set_tile(x :: Int, y :: Int, tile :: Tile): + tiles[y * width + x] := tile diff --git a/entity.rhm b/entity.rhm new file mode 100644 index 0000000..07bc81b --- /dev/null +++ b/entity.rhm @@ -0,0 +1,148 @@ +#lang rhombus/static +import: + rhombus/random + "chunk.rhm" open + +export: + Entity + EntityGatherable + EntityPlayer + ActionResponse + +let rand = random.Random() + +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) + // Diagonal case is moving in the same direction (same x & y) and that amount + // is less than or equal to max distance + let diagonal = diff_x == diff_y && diff_x <= max_dist + let x_axis = diff_x <= max_dist && diff_y == 0 + let y_axis = diff_y <= max_dist && diff_x == 0 + 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 + let local_y = y - current_chunk.offset_y * current_chunk.height + let less_x = local_x < 0 + let less_y = local_y < 0 + let more_x = local_x >= current_chunk.width + let more_y = local_y >= current_chunk.height + 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(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: 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) + + method + | move(x :: Int, y :: Int): move(x, y, 1) + | move(x :: Int, y :: Int, max_dist :: Int) :: Boolean: + let target_chunk = validate_chunk(x, y) + + cond + | validate_dist(x, y, max_dist) && target_chunk != #false && validate_move(x, y, max_dist, target_chunk!!): + this.current_chunk := target_chunk!! + this.x := x + this.y := y + #true + | ~else: + #false + +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 + +enum Slot: + right_hand + +enum Item: + bronze_axe + +class Stack(item :: Item, quantity :: Int) + +class EntityPlayer(mutable timer :: Int): + extends Entity + + field max_timer = 4 + field inventory :: Array.now_of(maybe(Stack)) = Array.make(20, #false) + field equip :: MutableMap.now_of(Slot, Item) = MutableMap() + + 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) + 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 + | timer != 0: ActionResponse.cooldown + | right_type && validate_dist(x, y, 1) && target_chunk != #false: + validate_gather_resource(target_entity) + | ~else: + ActionResponse.invalid @@ -1,195 +1,18 @@ #lang rhombus/static -import rhombus/random +import: + "chunk.rhm" open + "entity.rhm" open export: Chunk - Entity - EntityGatherable - EntityPlayer ActionResponse Direction World Tile - -let rand = random.Random() - -enum Direction: - north - north_east - east - south_east - south - south_west - west - north_west - -enum TileType: - empty - wall_north - -fun flip_block(block :: maybe(Direction)) :: maybe(Direction): - match block - | 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 - | TileType.empty: #false - | TileType.wall_north: Direction.north - -class Chunk(width :: Int, - height :: Int, - offset_x :: Int, - offset_y :: 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(TileType.empty)), MutableMap()) - - method add_neighbour(chunk :: Chunk, direction :: Direction): - neighbours[direction] := chunk - - method get_tile(x :: Int, y :: Int) :: Tile: - tiles[y * width + x] - - method set_tile(x :: Int, y :: Int, tile :: Tile): - 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) - // Diagonal case is moving in the same direction (same x & y) and that amount - // is less than or equal to max distance - let diagonal = diff_x == diff_y && diff_x <= max_dist - let x_axis = diff_x <= max_dist && diff_y == 0 - let y_axis = diff_y <= max_dist && diff_x == 0 - 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 - let local_y = y - current_chunk.offset_y * current_chunk.height - let less_x = local_x < 0 - let less_y = local_y < 0 - let more_x = local_x >= current_chunk.width - let more_y = local_y >= current_chunk.height - 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(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: 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) - - method - | move(x :: Int, y :: Int): move(x, y, 1) - | move(x :: Int, y :: Int, max_dist :: Int) :: Boolean: - let target_chunk = validate_chunk(x, y) - - cond - | validate_dist(x, y, max_dist) && target_chunk != #false && validate_move(x, y, max_dist, target_chunk!!): - this.current_chunk := target_chunk!! - this.x := x - this.y := y - #true - | ~else: - #false - - - -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) - 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 - | timer != 0: ActionResponse.cooldown - | right_type && validate_dist(x, y, 1) && target_chunk != #false: - validate_gather_resource(target_entity) - | ~else: - ActionResponse.invalid + Entity + EntityPlayer + EntityGatherable + Direction class World(chunks :: MutableList.now_of(Chunk), entities :: MutableList.now_of(Entity)): |