Basic combat
This commit is contained in:
parent
31a0bd9a34
commit
0b164302c4
7 changed files with 636 additions and 55 deletions
361
src/arena.scm
Normal file
361
src/arena.scm
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
(module (arena) ()
|
||||
(import scheme
|
||||
(chicken base)
|
||||
(chicken module)
|
||||
(chicken string)
|
||||
(imugi core)
|
||||
(imugi input)
|
||||
(imugi scene)
|
||||
(imugi math)
|
||||
(bd ui)
|
||||
(bd random)
|
||||
(bd attack)
|
||||
(bd grid)
|
||||
(srfi 1)
|
||||
(srfi 99))
|
||||
|
||||
(define battle-state 'active)
|
||||
|
||||
(define player 'player)
|
||||
(define enemy 'foe)
|
||||
(define empty 'none)
|
||||
|
||||
(define grid-size 5)
|
||||
|
||||
(define field (grid grid-size grid-size empty))
|
||||
|
||||
(define-record-type <unit>
|
||||
(unit type health pos hand-pos stance)
|
||||
unit?
|
||||
(type unit-type)
|
||||
(health unit-health set-unit-health!)
|
||||
(pos unit-pos set-unit-pos!)
|
||||
(hand-pos unit-hand-pos set-unit-hand-pos!)
|
||||
(stance unit-stance set-unit-stance!))
|
||||
|
||||
(define player-unit
|
||||
(unit
|
||||
player
|
||||
3
|
||||
;; Place player
|
||||
(vec (rand-int grid-size)
|
||||
(rand-int grid-size))
|
||||
(hand-direction 'mid 'right)
|
||||
'mid))
|
||||
|
||||
(define enemy-unit
|
||||
(unit
|
||||
enemy
|
||||
3
|
||||
;; Place enemy
|
||||
(let loop ()
|
||||
(let ((p-x (rand-int grid-size))
|
||||
(p-y (rand-int grid-size)))
|
||||
(if (not (v= (vec p-x p-y)
|
||||
(unit-pos player-unit)))
|
||||
(vec p-x p-y)
|
||||
(loop))))
|
||||
(hand-direction 'mid 'left)
|
||||
'mid))
|
||||
|
||||
(define-record-type <order>
|
||||
(order movement attack stance)
|
||||
order?
|
||||
(movement order-mov set-order-mov!)
|
||||
(attack order-atk set-order-atk!)
|
||||
(stance order-stance set-order-stance!))
|
||||
|
||||
(define (empty-order)
|
||||
(order #f
|
||||
#f
|
||||
#f))
|
||||
|
||||
(define player-order
|
||||
(empty-order))
|
||||
|
||||
(define (possible-enemy-moves)
|
||||
(filter
|
||||
(lambda (p)
|
||||
(let ((res (v+ p (unit-pos enemy-unit))))
|
||||
(and (> 5 (v-x res) -1)
|
||||
(> 5 (v-y res) -1))))
|
||||
(list (vec 0 1)
|
||||
(vec 0 -1)
|
||||
(vec 1 0)
|
||||
(vec -1 0))))
|
||||
|
||||
(define (distance-between-units)
|
||||
(let* ((p-pos (unit-pos player-unit))
|
||||
(e-pos (unit-pos enemy-unit))
|
||||
(d-x (abs (- (v-x p-pos) (v-x e-pos))))
|
||||
(d-y (abs (- (v-y p-pos) (v-y e-pos)))))
|
||||
(+ d-x d-y)))
|
||||
|
||||
(define (enemy-order)
|
||||
(let ((o (empty-order)))
|
||||
;; Movement AI
|
||||
(set-order-mov! o
|
||||
(if (= 1 (unit-health enemy-unit))
|
||||
(pick-random (possible-enemy-moves))
|
||||
(if (and (< 0.4 (random))
|
||||
(< 1 (distance-between-units)))
|
||||
(pick-random (possible-enemy-moves))
|
||||
#f)))
|
||||
(when (< 0.5 (random))
|
||||
(set-order-stance! o (pick-random '(high mid low))))
|
||||
(set-order-atk!
|
||||
o
|
||||
(let ((roll (random)))
|
||||
(cond
|
||||
((> 0.6 roll) (unit-hand-pos enemy-unit))
|
||||
((> 0.8 roll) (rotate-pos-cc (unit-hand-pos enemy-unit)))
|
||||
(else (rotate-pos (unit-hand-pos enemy-unit))))))
|
||||
o))
|
||||
|
||||
(define (attempt-attack attack-dir unit)
|
||||
(display (unit-type unit))
|
||||
(newline)
|
||||
(let* ((target (if (eqv? (unit-type unit) player) enemy-unit player-unit))
|
||||
(outcome (resolve-combat (attack-from-stance attack-dir (unit-stance unit))
|
||||
(defense-from-stance attack-dir
|
||||
(unit-hand-pos target)
|
||||
(unit-stance unit)))))
|
||||
(if (eqv? outcome 'hit)
|
||||
(begin
|
||||
(display (conc (unit-type unit) " hits!"))
|
||||
(set-unit-health! target (- (unit-health target) 1))
|
||||
(when (= 0 (unit-health target))
|
||||
(set! battle-state 'ended)))
|
||||
(display (conc (unit-type unit) " misses!")))
|
||||
(newline)
|
||||
(set-unit-hand-pos! unit (opposite-pos attack-dir))))
|
||||
|
||||
(define (move-unit unit pos)
|
||||
(let ((target (if (eqv? (unit-type unit) player) enemy-unit player-unit)))
|
||||
(unless (v= (unit-pos target) pos)
|
||||
(set-unit-pos! unit pos))))
|
||||
|
||||
(define (apply-order order unit)
|
||||
(when (order-mov order)
|
||||
(move-unit unit (v+ (unit-pos unit) (order-mov order))))
|
||||
(when (order-stance order)
|
||||
(set-unit-stance! unit (order-stance order)))
|
||||
(when (and (order-atk order)
|
||||
(= 1 (distance-between-units)))
|
||||
(attempt-attack (order-atk order) unit)))
|
||||
|
||||
(define update-grid-entities
|
||||
(make-system
|
||||
'update-grid-entities
|
||||
0
|
||||
'entity
|
||||
'(<grid-view>)
|
||||
(lambda (_ g)
|
||||
(let ((gd (grid-view-grid g)))
|
||||
(do ((i 0 (+ 1 i)))
|
||||
((= i (length gd)) gd)
|
||||
(let ((row (list-ref gd i)))
|
||||
(do ((j 0 (+ 1 j)))
|
||||
((= j (length row)) row)
|
||||
(gv! gd j i (cond
|
||||
((v= (unit-pos player-unit) (vec j i)) player)
|
||||
((v= (unit-pos enemy-unit) (vec j i)) enemy)
|
||||
(else empty))))))))))
|
||||
|
||||
(export arena)
|
||||
(define (arena)
|
||||
(scene
|
||||
push-actions
|
||||
process-dynamic-labels
|
||||
update-grid-entities
|
||||
draw-labels
|
||||
draw-grid
|
||||
handle-buttons
|
||||
|
||||
;; Level heading
|
||||
(entity
|
||||
(subtitle
|
||||
(vec
|
||||
0
|
||||
10)
|
||||
"Fight!"
|
||||
centered: (cons #t #f)))
|
||||
|
||||
;; Grid view
|
||||
(entity
|
||||
(grid-view
|
||||
(vec 190 100)
|
||||
field
|
||||
75))
|
||||
|
||||
;; Stance inputs
|
||||
(entity
|
||||
(button
|
||||
(vec 50
|
||||
460)
|
||||
(footer (vec 0 0)
|
||||
"High Stance!")
|
||||
(lambda ()
|
||||
(set-order-stance! player-order 'high))
|
||||
size: (vec 100 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 50
|
||||
500)
|
||||
(footer (vec 0 0)
|
||||
"Mid Stance!")
|
||||
(lambda ()
|
||||
(set-order-stance! player-order 'mid))
|
||||
size: (vec 100 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 50
|
||||
540)
|
||||
(footer (vec 0 0)
|
||||
"Low Stance!")
|
||||
(lambda ()
|
||||
(set-order-stance! player-order 'low))
|
||||
size: (vec 100 30)))
|
||||
|
||||
;; Attack inputs
|
||||
(entity
|
||||
(button
|
||||
(vec 12
|
||||
320)
|
||||
(footer (vec 0 0)
|
||||
"Atk: Counter-clockwise")
|
||||
(lambda ()
|
||||
(set-order-atk! player-order (rotate-pos-cc (unit-hand-pos player-unit))))
|
||||
size: (vec 175 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 12
|
||||
360)
|
||||
(footer (vec 0 0)
|
||||
"Atk: From position!")
|
||||
(lambda ()
|
||||
(set-order-atk! player-order (unit-hand-pos player-unit)))
|
||||
size: (vec 175 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 12
|
||||
400)
|
||||
(footer (vec 0 0)
|
||||
"Atk: Clockwise!")
|
||||
(lambda ()
|
||||
(set-order-atk! player-order (rotate-pos (unit-hand-pos player-unit))))
|
||||
size: (vec 175 30)))
|
||||
|
||||
;; Move inputs
|
||||
(entity
|
||||
(button
|
||||
(vec 185
|
||||
517)
|
||||
(footer (vec 0 0)
|
||||
"<")
|
||||
(lambda ()
|
||||
(when (< 0 (v-y (unit-pos player-unit)))
|
||||
(set-order-mov! player-order (vec 0 -1))))
|
||||
size: (vec 30 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 255
|
||||
517)
|
||||
(footer (vec 0 0)
|
||||
">")
|
||||
(lambda ()
|
||||
(when (> 4 (v-y (unit-pos player-unit)))
|
||||
(set-order-mov! player-order (vec 0 1))))
|
||||
size: (vec 30 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 220
|
||||
500)
|
||||
(footer (vec 0 0)
|
||||
"^")
|
||||
(lambda ()
|
||||
(when (< 0 (v-x (unit-pos player-unit)))
|
||||
(set-order-mov! player-order (vec -1 0))))
|
||||
size: (vec 30 30)))
|
||||
(entity
|
||||
(button
|
||||
(vec 220
|
||||
535)
|
||||
(footer (vec 0 0)
|
||||
"v")
|
||||
(lambda ()
|
||||
(when (> 4 (v-x (unit-pos player-unit)))
|
||||
(set-order-mov! player-order (vec 1 0))))
|
||||
size: (vec 30 30)))
|
||||
|
||||
;; End turn button
|
||||
(entity
|
||||
(button
|
||||
(vec (- (/ (car (*window-size*))
|
||||
2)
|
||||
50)
|
||||
500)
|
||||
(footer (vec 0 0)
|
||||
"Submit Order")
|
||||
(lambda ()
|
||||
(when (eqv? battle-state 'active)
|
||||
(let ((o (enemy-order)))
|
||||
(apply-order player-order player-unit)
|
||||
(apply-order o enemy-unit)
|
||||
(set! player-order (empty-order)))))))
|
||||
|
||||
;; Player data display
|
||||
(entity
|
||||
(footer
|
||||
(vec 0 0)
|
||||
""
|
||||
centered: (cons #f #t))
|
||||
(dynamic-label
|
||||
(lambda ()
|
||||
(conc (unit-health player-unit) "/3\n"
|
||||
"Your hand is "
|
||||
(direction-to-string (unit-hand-pos player-unit))
|
||||
"\nStance: " (symbol->string (unit-stance player-unit))))))
|
||||
|
||||
;; Player order display
|
||||
(entity
|
||||
(footer
|
||||
(vec 0 0)
|
||||
"")
|
||||
(dynamic-label
|
||||
(lambda ()
|
||||
(conc "Order:\n Move: "
|
||||
(if (order-mov player-order)
|
||||
(let ((m (order-mov player-order)))
|
||||
(cond
|
||||
((v= (vec 1 0) m) "Down")
|
||||
((v= (vec -1 0) m) "Up")
|
||||
((v= (vec 0 1) m) "Right")
|
||||
((v= (vec 0 -1) m) "Left")))
|
||||
"No change")
|
||||
"\nAttack: " (if (order-atk player-order)
|
||||
(direction-to-string (order-atk player-order))
|
||||
"No change")
|
||||
"\nStance: " (if (order-stance player-order)
|
||||
(order-stance player-order)
|
||||
"No change")))))
|
||||
|
||||
;; Enemy data display
|
||||
(entity
|
||||
(footer
|
||||
(vec 600 0)
|
||||
""
|
||||
centered: (cons #f #t))
|
||||
(dynamic-label
|
||||
(lambda ()
|
||||
(conc (unit-health enemy-unit) "/3\n"
|
||||
"Their hand is "
|
||||
(direction-to-string (unit-hand-pos enemy-unit))
|
||||
"\nStance: " (symbol->string (unit-stance enemy-unit))))))
|
||||
|
||||
(entity
|
||||
player-unit)
|
||||
(entity
|
||||
enemy-unit)
|
||||
))
|
||||
)
|
||||
|
|
@ -4,12 +4,14 @@
|
|||
raylib
|
||||
(imugi core)
|
||||
(imugi input)
|
||||
(main-menu))
|
||||
(main-menu)
|
||||
(arena))
|
||||
|
||||
(register-action 'click 'mouse-press MOUSE_BUTTON_LEFT)
|
||||
|
||||
((main-menu (lambda ()
|
||||
(display "Loading game scene...")
|
||||
(newline))))
|
||||
(newline)
|
||||
((arena)))))
|
||||
|
||||
(create-window))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue