jak-project/goal_src/engine/game/game-info.gc
ManDude 80a002f8c0
[decomp] entity birth (#964)
* make birthing work

* fix float representation on defskelgroup

* test

* update

* debugger improvements & dont upload aux sprites

* ?

* fix progress

* fixes

* fixes

* Create bea.gd

* fix test

* fix xmm reg clobbering in kernel (water)

* cleanup cam-start

* clear gamepad state every frame

* allow controller connects and disconnects while running
2021-11-15 19:05:28 -05:00

1134 lines
41 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: game-info.gc
;; name in dgo: game-info
;; dgos: GAME, ENGINE
;; The game-info is the logic for pickups/lives/eco/tasks/collectables/check points/saved data
;; The *game-info* object constains the "game state", like how many lives you have etc.
;; The "perm" data is saved to the memory card.
;;;;;;;;;;;;;;;;;;
;; border plane
;;;;;;;;;;;;;;;;;;
;; This border-plane seems to be unused. This is separate from load boundaries.
(defmethod debug-draw! border-plane ((obj border-plane))
"Debug draw a border plane with a vector and text."
(let* ((v1-0 (-> obj action))
;; pick color based on action
(s5-0 (if (= v1-0 'load)
(new 'static 'rgba :g #xff :a #x80)
(new 'static 'rgba :r #xff :a #x80)
)
)
)
;; add text and vector
(add-debug-text-sphere #t (bucket-id debug-draw1) (-> obj trans) 819.2 (symbol->string (-> obj name)) s5-0)
(add-debug-vector #t (bucket-id debug-draw1) (-> obj trans) (-> obj normal) 8192.0 s5-0)
)
0
(none)
)
(defmethod point-past-plane? border-plane ((obj border-plane) (arg0 vector))
"Which side of the plane is the given point on?
#t = on the plane, or on the side the normal points toward."
(>= (vector-dot
(vector-! (new 'stack-no-clear 'vector) arg0 (-> obj trans))
(-> obj normal))
0.0)
)
(defmethod task-complete? game-info ((obj game-info) (arg0 game-task))
"Likely closed, or in the process of closing"
(logtest? (-> obj task-perm-list data arg0 status) (entity-perm-status real-complete))
)
;; set up a static continue point that can be used as a temporary continue point.
(define *default-continue*
(new 'static 'continue-point
:name "default"
:level #f
:trans (new 'static 'vector :w 1.0)
:quat (new 'static 'quaternion :w 1.0)
:camera-trans (new 'static 'vector :w 1.0)
:load-commands '()
:vis-nick #f
:lev0 #f
:disp0 #f
:lev1 #f
:disp1 #f
)
)
(defmethod get-or-create-continue! game-info ((obj game-info))
"Attempt to get a continue point, if it doesn't exist set the
default-continue to a location in front of the camera."
(cond
((and (= (-> obj mode) 'play) (-> obj current-continue))
;; we have a continue.
(-> obj current-continue)
)
(else
;; need to make one
(let ((gp-0 *default-continue*))
(position-in-front-of-camera! (-> gp-0 trans) 40960.0 4096.0)
(quaternion-identity! (-> gp-0 quat))
(set! (-> gp-0 vis-nick) (-> *load-state* vis-nick))
(set! (-> gp-0 lev0) (-> *load-state* want 0 name))
(set! (-> gp-0 disp0) (-> *load-state* want 0 display?))
(set! (-> gp-0 lev1) (-> *load-state* want 1 name))
(set! (-> gp-0 disp1) (-> *load-state* want 1 display?))
gp-0
)
)
)
)
(defmethod get-continue-by-name game-info ((obj game-info) (arg0 string))
"Look up a continue point by string name"
(let ((s5-0 *level-load-list*))
;; loop over levels
(while (not (null? s5-0))
(let ((s4-0 (-> (the-as level-load-info (-> (the-as symbol (car s5-0)) value)) continues)))
;; loop over continues in the level
(while (not (null? s4-0))
(let ((s3-0 (car s4-0)))
(if (string= arg0 (the-as string (-> (the-as continue-point s3-0) name)))
;; match!
(return (the continue-point s3-0))
)
)
(set! s4-0 (cdr s4-0))
)
)
(set! s5-0 (cdr s5-0))
)
)
(the-as continue-point #f)
)
(defmethod set-continue! game-info ((obj game-info) (arg0 basic))
"Set the current continue to to arg0.
arg0 can be:
'() or #f, in which case it does nothing.
a string, in which case it looks up by name
a continue point.
If it fails to get a continue-point, sets up a temporary continue point
in the default-continue
If the continue is changed, resets the death and time counters
"
(let ((s5-0 (-> obj current-continue)))
(if (null? arg0)
(set! arg0 #f)
)
(let ((v1-3 (-> arg0 type)))
(cond
((= v1-3 string)
(let ((v1-5 (get-continue-by-name obj (the-as string arg0))))
(if v1-5
(set! (-> obj current-continue) v1-5)
)
)
)
(else
(cond
((= v1-3 continue-point)
(set! (-> obj current-continue) (the-as continue-point arg0))
)
(else
(let ((s4-3 *default-continue*))
(position-in-front-of-camera! (-> s4-3 trans) 40960.0 4096.0)
(quaternion-identity! (-> s4-3 quat))
(set! (-> s4-3 vis-nick) (-> *load-state* vis-nick))
(set! (-> s4-3 lev0) (-> *load-state* want 0 name))
(set! (-> s4-3 disp0) (-> *load-state* want 0 display?))
(set! (-> s4-3 lev1) (-> *load-state* want 1 name))
(set! (-> s4-3 disp1) (-> *load-state* want 1 display?))
(set! (-> obj current-continue) s4-3)
)
)
)
)
)
)
(when (!= s5-0 (-> obj current-continue))
(set! (-> obj continue-deaths) 0)
(set! (-> obj continue-time) (-> *display* base-frame-counter))
)
)
(-> obj current-continue)
)
(defmethod get-entity-task-perm game-info ((obj game-info) (arg0 game-task))
"Get the permanent storage for a game-task"
(-> obj task-perm-list data arg0)
)
(defmethod initialize! game-info ((obj game-info) (cause symbol) (save-to-load game-save) (continue-point-override string))
"Initialize the game-info.
The cause can be 'dead if you die, or 'game to reset everything.
If save-to-load is not #f will load data from that.
If continue-point-override is not #f, will use that."
(local-vars (v0-0 int) (sv-96 symbol))
(let ((selected-cause cause))
(when (= selected-cause 'dead)
;; reload game-info because we died. Increase death counts
(set! (-> obj total-deaths) (+ (-> obj total-deaths) 1))
(set! (-> obj continue-deaths) (+ (-> obj continue-deaths) 1))
(set! (-> obj fuel-cell-deaths) (+ (-> obj fuel-cell-deaths) 1))
(when *target*
(let ((lev-info (-> *target* current-level info)))
(when (>= (-> *level-task-data-remap* length) (-> lev-info index))
;; update death per level.
(set! v0-0
(seekl
(the-as int (-> obj deaths-per-level (-> *level-task-data-remap* (+ (-> lev-info index) -1))))
255
1
)
)
(set! (-> obj deaths-per-level (-> *level-task-data-remap* (+ (-> lev-info index) -1))) (the-as uint v0-0))
)
)
)
(let ((v1-27 (-> obj mode)))
(cond
((= v1-27 'play)
;; now pick between life/try depending on if we ran out of lives or not.
(if (< 0.0 (-> obj life))
(set! cause 'life)
(set! cause 'try)
)
)
(else
;; not in play mode, we're done.
(begin
(set! obj obj)
(goto cfg-50)
)
)
)
)
)
)
;; ?
(kill-current-level-hint '() '() 'die)
(let ((v1-31 cause))
(when (= v1-31 'game)
;; we are doing a full restart.
;; reset everything!
(reset-all-hint-controls)
(set-continue! obj
(cond
(continue-point-override
continue-point-override
)
((!= *kernel-boot-message* 'play)
"demo-start"
)
(*debug-segment*
"village1-hut"
)
(else
"title-start"
)
)
)
(set! (-> obj auto-save-count) 0)
(set! (-> *setting-control* default auto-save) #f)
(set! (-> obj money) 0.0)
(set! (-> obj fuel) 0.0)
(set! (-> obj money-total) 0.0)
(set! (-> obj buzzer-total) 0.0)
(set! (-> obj perm-list length) 0)
(clear-all! (-> obj text-ids-seen))
(set! (-> obj death-movie-tick) (rand-vu-int-count 10))
(set! (-> obj total-deaths) 0)
(set! (-> obj continue-deaths) 0)
(set! (-> obj fuel-cell-deaths) 0)
(set! (-> obj death-pos length) 0)
(set! (-> obj game-start-time) (-> *display* base-frame-counter))
(set! (-> obj fuel-cell-pickup-time) (-> *display* base-frame-counter))
(set! (-> obj continue-time) (-> *display* base-frame-counter))
(set! (-> obj death-time) (-> *display* base-frame-counter))
(set! (-> obj hit-time) (-> *display* base-frame-counter))
(dotimes (v1-50 116)
(set! (-> obj fuel-cell-time 0) 0)
(nop!)
)
(dotimes (v1-53 32)
(set! (-> obj money-per-level v1-53) 0)
(set! (-> obj deaths-per-level v1-53) 0)
(set! (-> obj enter-level-time v1-53) 0)
(set! (-> obj in-level-time v1-53) 0)
(set! (-> obj level-opened v1-53) 0)
(nop!)
)
)
)
(let ((v1-56 cause))
(when (or (= v1-56 'game) (= v1-56 'try))
;; full restart, or ran out of lives
(let ((v1-59 (-> obj mode)))
(when (= v1-59 'play)
(set! *display-profile* #f)
(set! *display-entity-errors* #f)
)
)
;; reset lives to default.
(set! (-> obj life-max) (-> *GAME-bank* life-max-default))
(set! (-> obj life) (-> *GAME-bank* life-start-default))
)
)
(let ((v1-65 (-> obj mode)))
(cond
((= v1-65 'debug)
;; in debug, we didn't kill things so we don't need to restart them
(reset-actors cause)
(if save-to-load
(load-game! obj save-to-load)
)
)
((= v1-65 'play)
;; don't allow pausing/start menu
(when *target*
(set-setting! *setting-control* *target* 'allow-pause #f 0.0 0)
(set-setting! *setting-control* *target* 'allow-progress #f 0.0 0)
(copy-settings-from-target! *setting-control*)
)
;; send the auto-save process a 'die message
(send-event (handle->process (-> *game-info* auto-save-proc)) 'die)
;; black screen, stop spawning actors
(set! (-> *level* border?) #f)
(set! (-> *setting-control* default border-mode) #f)
(set! *spawn-actors* #f)
(set-blackout-frames 30)
;; send target a 'reset message.
(send-event *target* 'reset)
;; start a temporary process to restart things
(let ((proc (get-process *4k-dead-pool* process #x4000)))
(when proc
(activate proc *default-pool* 'process *scratch-memory-top*)
(run-next-time-in-process
proc
(lambda ((stop-arg symbol) (reset-arg symbol) (c continue-point) (load game-save))
(stop stop-arg)
(reset-actors reset-arg)
(set-continue! *game-info* c)
(when load
(load-game! *game-info* load)
(set! c (get-or-create-continue! *game-info*))
)
(suspend)
(start stop-arg c)
)
(-> obj mode) ;; play, debug
cause
(get-or-create-continue! obj)
save-to-load
)
)
)
(set-master-mode 'game)
)
)
)
(label cfg-50)
obj
)
(defmethod adjust game-info ((obj game-info) (item symbol) (amount float) (source handle))
"Adjust the number of items by amount."
(let ((v1-0 item))
(cond
((= v1-0 'life)
;; get/lose a life, just modify the life field
(if (>= amount 0.0)
(set! (-> obj life) (seek (-> obj life) (-> obj life-max) amount))
(set! (-> obj life) (seek (-> obj life) 0.0 (- amount)))
)
(-> obj life)
)
((= v1-0 'money)
(if (and (< 0.0 amount) (= (+ (-> obj money) amount) (-> *GAME-bank* money-task-inc)))
;; got enough orbs to trade, display a hint
(level-hint-spawn (game-text-id MISSING-orb-hint) "sksp0014" (the entity #f) *entity-pool* (game-task none))
)
;; need to update the various orb counters
(when (< 0.0 amount)
(let ((proc (handle->process source)))
(when (and proc (-> proc entity))
;; we have task data for this level!
(when (>= (-> *level-task-data-remap* length) (-> proc entity extra level info index))
;; get the level index
(let ((level-idx (-> *level-task-data-remap* (+ (-> proc entity extra level info index) -1))))
;; increment the level money count
(set! (-> obj money-per-level level-idx) (+ (-> obj money-per-level level-idx) (the-as uint (the int amount))))
;; increment our total money in the game (out of the 2000 max orbs)
(set! (-> obj money-total) (+ (-> obj money-total) amount))
;; if we have all the money in our level, display the all orbs graphic
(if (= (-> obj money-per-level level-idx) (-> (get-game-count level-idx) money-count))
(activate-orb-all level-idx)
)
)
)
)
)
)
;; increment our current money count
(let ((f0-18 (+ (-> obj money) amount)))
(set! (-> obj money) f0-18)
f0-18
)
)
((= v1-0 'fuel-cell)
;; got a power cell!
;; in this case, the amount is actually the index of the power cell's task
(let ((s5-1 (the int amount)))
(when (not (or (task-complete? obj (the-as game-task s5-1))
(>= (the-as uint 1) (the-as uint s5-1))
)
)
;; the cell corresponds to a valid and previously incomplete task.
;; update our stats
(set! (-> obj fuel-cell-deaths) 0)
(set! (-> obj fuel-cell-pickup-time) (-> *display* base-frame-counter))
(set! (-> obj fuel-cell-time s5-1) (-> *display* base-frame-counter))
;; increment power cells!
(set! (-> obj fuel) (+ 1.0 (-> obj fuel)))
;; mark as completed
(set! (-> obj task-perm-list data s5-1 status)
(logior (-> obj task-perm-list data s5-1 status)
(entity-perm-status real-complete)
)
)
;; unused.
(get-task-control (the game-task s5-1))
;; close the task!
(close-specific-task!
(the-as game-task s5-1)
(task-status need-resolution)
)
)
)
(-> obj fuel)
)
((= v1-0 'buzzer)
;; got a scout fly. In this case, the amount is actually two 16 bit numbers
;; the lower 16 bits are the task, and the upper is why fly
(let ((buzz-task (logand (the int amount) #xffff))
(buzz-index (sar (the int amount) 16))
(buzz-count 0.0)
)
(when (> (the-as uint buzz-task) 0)
;; valid task
(let* ((ctrl (get-task-control (the game-task buzz-task)))
(buzz-bits (get-reminder ctrl 0)) ;; the currently collected flies
)
(when (and (>= buzz-index 0)
(< buzz-index (the int (-> *FACT-bank* buzzer-max-default)))
)
;; valid fly index
;; increment total if we haven't collected it before
(if (zero? (logand buzz-bits (ash 1 buzz-index)))
(set! (-> obj buzzer-total) (+ 1.0 (-> obj buzzer-total)))
)
;; set the updated bits
(let ((t9-10 (method-of-object ctrl save-reminder)))
(set! buzz-bits (logior buzz-bits (ash 1 buzz-index)))
(t9-10 ctrl buzz-bits 0)
)
)
;; recompute the total count
(countdown (v1-58 (the int (-> *FACT-bank* buzzer-max-default)))
(if (nonzero? (logand buzz-bits (ash 1 v1-58)))
(set! buzz-count (+ 1.0 buzz-count))
)
)
)
)
buzz-count
)
)
)
)
)
(defmethod got-buzzer? game-info ((obj game-info) (arg0 game-task) (arg1 int))
"Do we have the arg1-th buzzer for the given buzzer task?"
;; buzzers mis-use their reminder bits as a bitfield of which ones have been collected
(nonzero? (logand (get-reminder (get-task-control arg0) 0) (ash 1 arg1)))
)
(defmethod buzzer-count game-info ((obj game-info) (arg0 game-task))
"How many buzzers do we have for this task?"
(let ((v1-1 (get-reminder (get-task-control arg0) 0)) ;; buzzer bitmask
(v0-2 0) ;; count
)
(countdown (a0-4 (the int (-> *FACT-bank* buzzer-max-default)))
(if (nonzero? (logand v1-1 (ash 1 a0-4)))
(+! v0-2 1)
)
)
v0-2
)
)
(defmethod seen-text? game-info ((obj game-info) (arg0 game-text-id))
"Have we already displayed this text?
This is used to display level names on only the first enter.
It seems like hints could also display text on screen at one point in time."
(get-bit (-> obj text-ids-seen) (the-as int arg0))
)
(defmethod mark-text-as-seen game-info ((obj game-info) (arg0 game-text-id))
"Mark the game text as seen. This only works if the text id < 4096, and ignores otherwise"
(if (and (< (the-as uint arg0) (the-as uint 4095)) (> (the-as uint arg0) 0))
(set-bit (-> obj text-ids-seen) (the-as int arg0))
)
(none)
)
(defmethod clear-text-seen! game-info ((obj game-info) (arg0 game-text-id))
"Mark text as unseen. MUST be a valid text id"
(clear-bit (-> obj text-ids-seen) (the-as int arg0))
(none)
)
(defmethod reset! fact-info-target ((obj fact-info-target) (arg0 symbol))
"Reset the facts for a given thing"
(when (or (not arg0) (= arg0 'eco))
(set! (-> obj eco-timeout) 0)
(set! (-> obj eco-level) 0.0)
(set! (-> obj eco-pickup-time) (-> *display* game-frame-counter))
)
(when (or (not arg0) (= arg0 'health))
(set! (-> obj health-max) (-> *FACT-bank* health-max-default))
(set! (-> obj health) (-> obj health-max))
(set! (-> obj health-pickup-time) (the-as uint -30000))
)
(when (or (not arg0) (= arg0 'buzzer))
(set! (-> obj buzzer-max) (-> *FACT-bank* buzzer-max-default))
(set! (-> obj buzzer) 0.0)
)
(when (or (not arg0) (= arg0 'eco-pill))
(set! (-> obj eco-pill-max) (-> *FACT-bank* eco-pill-max-default))
(set! (-> obj eco-pill) 0.0)
)
(none)
)
(declare-type vent process-drawable)
(defmethod pickup-collectable! fact-info-target ((obj fact-info-target) (kind pickup-type) (amount float) (source-handle handle))
"Pickup a thing!"
(with-pp
(case kind
(((pickup-type eco-green))
;; big green eco. This counts toward the health (up to 3), and if that's full, maxes out the little green ecos to 50.
(cond
((>= amount 0.0)
;; got a positive or 0 amount.
(when (< 0.0 amount)
;; when we get a different source, OR we it's been more than 0.5 seconds since we last got eco
;; from this source.
(if (or (!= (handle->process source-handle) (handle->process (-> obj eco-source)))
(>= (the-as int (- (-> *display* base-frame-counter) (-> obj eco-source-time))) 150)
)
;; play the sound!
(sound-play-by-name (static-sound-name "get-green-eco")
(new-sound-id)
1024
0
0
1
#t
)
)
;; remember the source.
(when (handle->process source-handle)
(set! (-> obj eco-source) source-handle)
(set! (-> obj eco-source-time) (-> *display* base-frame-counter))
)
)
;; if we are at max health (3), and collect additional an additional big green eco,
;; then max out the little green ecos.
(if (= (-> obj health) (-> obj health-max))
(pickup-collectable!
obj
(pickup-type eco-pill)
(-> *FACT-bank* eco-pill-max-default)
(process->handle (-> obj process))
)
)
;; remember when
(set! (-> obj health-pickup-time) (-> *display* base-frame-counter))
;; increase the health!
(set! (-> obj health) (seek (-> obj health) (-> obj health-max) amount))
)
(else
;; negative health. Subtract.
(set! (-> obj health) (seek (-> obj health) 0.0 (- amount)))
;; not sure why we do this. But this will set the eco pill collection time.
(if (>= amount -10.0)
(pickup-collectable! obj (pickup-type eco-pill) 0.0 source-handle)
)
;; subtract lives.
(if (= (-> obj health) 0.0)
(adjust
(-> (the-as target (-> obj process)) game)
'life
(- (-> *GAME-bank* life-single-inc))
source-handle
)
)
)
)
;; some sort of hack for eco vents.
(b! (and (logtest? (-> (the-as collide-shape (-> obj process root)) root-prim prim-core action) 512)
(type-type? (-> (handle->process source-handle) type) vent)
)
cfg-80)
(-> obj health)
)
(((pickup-type eco-pill))
;; collect small green eco
(when (>= amount 0.0)
;; update small eco count
(set! (-> obj eco-pill-pickup-time) (-> *display* base-frame-counter))
(set! (-> obj eco-pill) (seek (-> obj eco-pill) (-> obj eco-pill-max) amount))
;; increment big health if needed
(when (and (>= (-> obj eco-pill) (-> *FACT-bank* eco-pill-max-default)) ;; have enough smalls
(< (-> obj health) (-> obj health-max)) ;; and enough room for another health
)
;; decrease eco pills
(set! (-> obj eco-pill)
(- (-> obj eco-pill) (-> *FACT-bank* eco-pill-max-default))
)
;; get a big health.
(pickup-collectable!
obj
(pickup-type eco-green)
(-> *FACT-bank* health-small-inc)
(process->handle (-> obj process))
)
)
)
(-> obj eco-pill)
)
(((pickup-type money))
;; get money.
(when (< 0.0 amount)
;; play sound.
(if (>= (the-as int (- (-> *display* base-frame-counter) (-> obj money-pickup-time))) 15)
(sound-play-by-name (static-sound-name "money-pickup")
(new-sound-id)
1024
0
0
1
#t
)
)
(set! (-> obj money-pickup-time) (-> *display* base-frame-counter))
)
(adjust (-> (the-as target (-> obj process)) game)
'money
amount
source-handle
)
)
(((pickup-type fuel-cell))
;; the amount is actually the index of the task.
(let ((s4-2 (the int amount)))
(if (not (or (task-complete? (-> (the-as target (-> obj process)) game) (the-as game-task s4-2) )
(>= (the-as uint 1) (the-as uint s4-2))
)
)
(set! (-> obj fuel-cell-pickup-time) (-> *display* base-frame-counter))
)
)
(adjust
(-> (the-as target (-> obj process)) game)
'fuel-cell
amount
source-handle
)
)
(((pickup-type buzzer))
;; scout fly.
(let ((buzz-count (adjust
(-> (the-as target (-> obj process)) game)
'buzzer
amount
source-handle
)
)
)
(if (!= buzz-count (-> obj buzzer))
(set! (-> obj buzzer-pickup-time) (-> *display* base-frame-counter))
)
(set! (-> obj buzzer) buzz-count)
)
(-> obj buzzer)
)
(((pickup-type eco-red) (pickup-type eco-blue) (pickup-type eco-yellow))
;; the green vent jumps here.
(label cfg-80)
;; if the amount is zero, we just want to know how much eco there is.
(if (= amount 0.0)
(return (if (= (-> obj eco-type) kind)
(-> obj eco-level)
0.0 ;; we don't have this kind of eco.
)
)
)
;; new type of eco. Reset and use the new type.
(when (!= (-> obj eco-type) kind)
;; as far as I can tell, the eco-level isn't really used other than just 1 or 0.
(set! (-> obj eco-level) 0.0)
(set! (-> obj eco-timeout) (the-as seconds 0))
0
)
(set! (-> obj eco-type) (the-as int kind))
(let ((eco-lev (-> obj eco-level)))
(set! (-> obj eco-level) 1.0) ;; just set to 1.
;; this check now doesn't make much sense...
(when (and (= eco-lev 0.0) (< 0.0 (-> obj eco-level)))
;; didn't have eco and now we do, remember when
(set! (-> obj eco-pickup-time) (-> *display* game-frame-counter))
;; send a reset-collide message. Not sure why we do this.
(send-event (-> obj process) 'reset-collide)
)
;; this logic prevents eco from respawning before you are out.
;; the time until respawn is min(full_eco_time, old_time + single_timeout)
(set! (-> obj eco-timeout)
(the-as seconds
(min (the-as int (+ (-> obj eco-timeout) (* (the-as int (-> *FACT-bank* eco-single-timeout)) (the int amount))))
(the-as int (+ (-> *FACT-bank* eco-full-timeout) (- (-> *display* game-frame-counter) (-> obj eco-pickup-time))))
)
)
)
;; if you max out the eco, this should trigger
(if (>= (the-as int (- (-> obj eco-timeout) (the-as uint (- (-> *display* game-frame-counter) (-> obj eco-pickup-time)))))
(the-as int (-> *FACT-bank* eco-full-timeout))
)
(set! (-> obj eco-level) 2.0)
)
;; sound and controller vibration.
(when (not (and (= (handle->process source-handle) (handle->process (-> obj eco-source)))
(< (the-as int (- (-> *display* base-frame-counter) (-> obj eco-source-time))) 150)
)
)
(cpad-set-buzz! (-> *cpad-list* cpads 0) 1 127 60)
(cpad-set-buzz! (-> *cpad-list* cpads 0) 0 17 60)
(case kind
(((pickup-type eco-blue))
(sound-play-by-name (static-sound-name "get-blue-eco") (new-sound-id) 1024 0 0 1 #t)
)
(((pickup-type eco-green))
(sound-play-by-name (static-sound-name "get-green-eco") (new-sound-id) 1024 0 0 1 #t)
)
(((pickup-type eco-yellow))
(sound-play-by-name (static-sound-name "get-yellow-eco") (new-sound-id) 1024 0 0 1 #t)
)
(((pickup-type eco-red))
(sound-play-by-name (static-sound-name "get-red-eco") (new-sound-id) 1024 0 0 1 #t)
)
)
)
(set! (-> obj eco-source) source-handle)
(set! (-> obj eco-source-time) (-> *display* base-frame-counter))
;; special case for blue eco magnet effect
(when (= kind (pickup-type eco-blue))
(when (= eco-lev 0.0) ;; old level was 0, we just got our first piece of eco
(let ((s5-1 (-> obj process)))
(let* ((s3-5 (get-process *default-dead-pool* touch-tracker #x4000))
(s4-3 (when s3-5
;; interestingly, this uses the activate method of touch-tracker, not process.
(let ((t9-28 (method-of-type touch-tracker activate)))
(t9-28 (the-as touch-tracker s3-5) s5-1 'touch-tracker (the-as pointer #x70004000))
)
(run-now-in-process s3-5 touch-tracker-init (-> s5-1 root trans) (-> *FACT-bank* suck-bounce-dist) 300)
(-> s3-5 ppointer)
)
)
)
;; send the touch tracker the target
(send-event (ppointer->process s4-3) 'target s5-1)
;; tell it we have blue eco.
(send-event (ppointer->process s4-3) 'event 'eco-blue)
;; give it a function to call to see if it's time to exit
(send-event (ppointer->process s4-3)
'exit
(lambda ()
(send-event *target* 'query 'powerup 3)
)
;; set up some collision thing.
(send-event (ppointer->process s4-3)
'eval
(lambda :behavior process-drawable
()
(set! (-> (the-as collide-shape (-> self root)) root-prim collide-with)
(the-as uint #x800e)
)
(none)
)
)
)
)
;; create a process that just keeps sending 'effect 'eco-blue
(let ((s4-4 (get-process *4k-dead-pool* process #x4000)))
(when s4-4
(let ((t9-35 (method-of-type process activate)))
(t9-35 s4-4 s5-1 'process (the-as pointer #x70004000))
)
(run-next-time-in-process s4-4
(lambda ((arg0 process-drawable))
(with-pp
(let ((start-time (-> *display* base-frame-counter)))
(until (>= (the-as int (- (-> *display* base-frame-counter) start-time)) 180)
(let ((a1-0 (new 'stack-no-clear 'event-message-block)))
(set! (-> a1-0 from) pp)
(set! (-> a1-0 num-params) 1)
(set! (-> a1-0 message) 'effect)
(set! (-> a1-0 param 0) (the-as uint 'eco-blue))
(send-event-function arg0 a1-0)
)
(suspend)
)
)
(none)
)
)
s5-1
)
(-> s4-4 ppointer)
)
)
)
)
)
)
(-> obj eco-level)
)
(else
((method-of-type fact-info pickup-collectable!)
obj
kind
amount
source-handle
)
)
)
)
)
(defmethod lookup-entity-perm-by-aid game-info ((obj game-info) (aid actor-id))
(let ((v1-0 (-> obj perm-list)))
(countdown (a0-1 (-> v1-0 length))
(if (= aid (-> v1-0 data a0-1 aid))
(return (-> v1-0 data a0-1))
)
)
)
(the-as entity-perm #f)
)
(defmethod copy-perms-from-level! game-info ((obj game-info) (lev level))
"Iterate through entities in the level and copy their perms into game-info"
(let ((perms (-> obj perm-list)) ;; our perms
(lev-entities (-> lev bsp level entity)) ;; entities in the level
)
;; loop over every entity in the level
(dotimes (lev-entity-idx (-> lev-entities length))
;; and get the perm
(let ((lev-entity-perm (-> lev-entities data lev-entity-idx entity extra perm)))
;; only look at ones with an associated task
(when (nonzero? (-> lev-entity-perm task))
;; look up the perm in the game info
(let ((info-entity-perm (lookup-entity-perm-by-aid obj (-> lev-entity-perm aid))))
(cond
(info-entity-perm
;; it exists, set it to the value from the level
(set! (-> info-entity-perm quad) (-> lev-entity-perm quad))
)
((< (-> perms length) (-> perms allocated-length))
;; nope, doesn't exist, but we have room for another, so add it to the back
(set! (-> perms data (-> perms length) quad) (-> lev-entity-perm quad))
(set! (-> perms length) (+ (-> perms length) 1))
)
)
)
)
)
)
)
0
(none)
)
(defmethod copy-perms-to-level! game-info ((obj game-info) (lev level))
"Does the opposite of the previous, copies perms from game-info to level entities"
(let ((lev-entities (-> lev bsp level entity)))
(dotimes (lev-entity-idx (-> lev-entities length))
(let* ((lev-entity-perm (-> lev-entities data lev-entity-idx entity extra perm))
(info-entity-perm (lookup-entity-perm-by-aid obj (-> lev-entity-perm aid)))
)
(when info-entity-perm
;; found the level entity in game-info, copy
(set! (-> lev-entity-perm quad) (-> info-entity-perm quad))
;; and also do this thing, not sure exactly what, but updates the status bits
(update-perm! lev-entity-perm 'try
(entity-perm-status
bit-0
bit-1
dead
bit-3
user-set-from-cstage
complete
bit-9
)
)
)
)
)
)
0
(none)
)
(defmethod print continue-point ((obj continue-point))
(format #t "#<~A ~S @ #x~X>" (-> obj type) (-> obj name) obj)
obj
)
(defmethod debug-draw! continue-point ((obj continue-point))
"Draw a continue point."
(add-debug-x #t
(bucket-id debug-draw1)
(-> obj trans)
(new 'static 'rgba :r #xff :a #x80)
)
(add-debug-text-3d #t
(bucket-id debug-draw1)
(-> obj name)
(-> obj trans)
(font-color white)
(new 'static 'vector2h :data (new 'static 'array int16 2 0 8))
)
(let ((a3-2 (vector-z-quaternion! (new-stack-vector0) (-> obj quat))))
(add-debug-vector
#t
(bucket-id debug-draw1)
(-> obj trans)
a3-2
8192.0
(new 'static 'rgba :r #xff :g #x80 :a #x80)
)
)
0
(none)
)
(defun-debug trsq->continue-point ((arg0 trsq))
"Print out a continue point."
(let ((a2-0 (level-get-target-inside *level*)))
(format #t "~%(static-continue-point ~A ()~%"
(symbol->string (-> a2-0 name))
)
)
(format #t " (target ~m ~m ~m "
(-> arg0 trans x)
(-> arg0 trans y)
(-> arg0 trans z)
)
(format #t "~f ~f ~f ~f)~%"
(-> arg0 quat x)
(-> arg0 quat y)
(-> arg0 quat z)
(-> arg0 quat w)
)
(let ((gp-1 *math-camera*))
(format #t " (camera ~m ~m ~m ~f ~f ~f "
(-> gp-1 trans x)
(-> gp-1 trans y)
(-> gp-1 trans z)
(-> gp-1 inv-camera-rot vector 0 x)
(-> gp-1 inv-camera-rot vector 0 y)
(-> gp-1 inv-camera-rot vector 0 z)
)
(format #t "~f ~f ~f ~f ~f ~f)~%"
(-> gp-1 inv-camera-rot vector 1 x)
(-> gp-1 inv-camera-rot vector 1 y)
(-> gp-1 inv-camera-rot vector 1 z)
(-> gp-1 inv-camera-rot vector 2 x)
(-> gp-1 inv-camera-rot vector 2 y)
(-> gp-1 inv-camera-rot vector 2 z)
)
)
(format #t " (load '~A '~A '~A '~A '~A)~%"
(-> *load-state* vis-nick)
(-> *load-state* want 0 name)
(-> *load-state* want 0 display?)
(-> *load-state* want 1 name)
(-> *load-state* want 1 display?)
)
(format #t " )~%")
0
(none)
)
(defun-debug game-task->string ((arg0 game-task))
(enum->string game-task arg0)
)
(defmethod debug-print game-info ((obj game-info) (arg0 symbol))
(inspect obj)
(when (or (not arg0) (= arg0 'game-task))
(format #t "~Tgame-task:~%")
(dotimes (s4-0 116)
(if (task-complete? obj (the-as game-task s4-0))
(format #t "~T~T~S~%" (game-task->string (the-as game-task s4-0)))
)
)
)
(when (or (not arg0) (= arg0 'entity-perm))
(format #t "~Tentity-perm:~%")
(let ((s5-1 (-> obj perm-list)))
(dotimes (s4-1 (-> s5-1 length))
(format #t "~T~T~`entity-perm`P~%" (-> s5-1 data s4-1))
)
)
)
obj
)
;; allocate storage for game info
(let ((gp-0 *game-info*))
;; perms
(when (zero? (-> gp-0 perm-list))
(set! (-> gp-0 perm-list) (new 'global 'entity-perm-array 4096))
(set! (-> gp-0 perm-list length) 0)
0
)
;; task perms
(when (zero? (-> gp-0 task-perm-list))
(let ((v1-15 (new 'global 'entity-perm-array 116)))
(set! (-> gp-0 task-perm-list) v1-15)
(dotimes (a0-24 (-> v1-15 length))
(set! (-> v1-15 data a0-24 task) (the-as game-task a0-24))
)
(set!
(-> v1-15 data 1 status)
(logior (-> v1-15 data 1 status) (entity-perm-status real-complete))
)
)
)
;; text idx
(if (zero? (-> gp-0 text-ids-seen))
(set! (-> gp-0 text-ids-seen) (new 'global 'bit-array 4095))
)
;; death locations
(when (zero? (-> gp-0 death-pos))
(set! (-> gp-0 death-pos) (new 'global 'vector-array 64))
(set! (-> gp-0 death-pos length) 0)
0
)
;; initialize some fields
(if (zero? (-> gp-0 display-text-handle))
(set! (-> gp-0 display-text-handle) (the-as handle #f))
)
(if (not (-> gp-0 current-continue))
(set-continue! gp-0 *default-continue*)
)
(set! (-> gp-0 want-auto-save) #f)
(set! (-> gp-0 auto-save-proc) (the-as handle #f))
(set! (-> gp-0 auto-save-status) (mc-status-code ok))
(set! (-> gp-0 auto-save-card) 0)
(set! (-> gp-0 auto-save-which) -1)
(set! (-> gp-0 pov-camera-handle) (the-as handle #f))
(set! (-> gp-0 other-camera-handle) (the-as handle #f))
)
(defmethod get-death-count game-info ((obj game-info) (arg0 symbol))
(let ((v1-13
(if (and arg0
*target*
(>= (-> *level-task-data-remap* length) (-> *target* current-level info index))
)
(the-as int
(-> obj deaths-per-level
(-> *level-task-data-remap* (+ (-> *target* current-level info index) -1))
)
)
(-> obj fuel-cell-deaths)
)
)
)
0
(min 4 (/ v1-13 5))
)
)
(defmethod get-health-percent-lost game-info ((obj game-info))
(* 0.25 (the float (get-death-count obj #f)))
)