About Social Code
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2025-03-22 15:38:40 +0000
committerLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2025-03-22 15:38:40 +0000
commitcb01f1f6f930cee6529e51dc3d29945edaa9d95a (patch)
treea1151eacb471430ccae1a35aba18da2a742d0cf2
parenta2b843b05622f540557fc29ab8962a7f64395fb0 (diff)
Split up files
-rw-r--r--chunk.rhm58
-rw-r--r--entity.rhm148
-rw-r--r--world.rhm191
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
diff --git a/world.rhm b/world.rhm
index f473e6e..838b9df 100644
--- a/world.rhm
+++ b/world.rhm
@@ -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)):