About Social Code
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2025-03-22 13:11:09 +0000
committerLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2025-03-22 13:11:09 +0000
commita2b843b05622f540557fc29ab8962a7f64395fb0 (patch)
tree25f16387585abe0e004b7e98e184cbe9c88ba31c
parentf4e83d48a0e355707dbe6912b4c585436757bb6e (diff)
Work out more of gathering logic
-rw-r--r--main.rhm29
-rw-r--r--world.rhm125
2 files changed, 108 insertions, 46 deletions
diff --git a/main.rhm b/main.rhm
index 91d62f6..2d306bb 100644
--- a/main.rhm
+++ b/main.rhm
@@ -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")
diff --git a/world.rhm b/world.rhm
index a528f89..f473e6e 100644
--- a/world.rhm
+++ b/world.rhm
@@ -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)):