;;-*-Lisp-*- (in-package goal) #| This file runs the game-specific version of the pckernel. See pckernel-common.gc for the bulk of the pckernel. |# (define-extern get-active-mission-description (function discord-info string)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; pc cheats list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype pc-cheat-info (basic) ((name text-id) (unlock text-id) (unlock-func symbol) ;; function symbol (skill int) ;; skill points required. leave as 0 if you only want a custom unlock func (flag pc-cheats) (can-toggle symbol) ;; how it can be toggled ;; only show after this point in the story (avail-after game-task-node) (avail-after-hero game-task-node) ) ) ;;;;; pc cheat unlock functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun pc-cheat-health-bars-unlock () "#t = cheat unlock requirements met. #f = locked" (>= (get-count-for-enemy (-> *pc-settings* stats kill-stats) 'civilian) (-> *pc-cheat-state* kill-civvie-target))) (defun pc-cheat-vehicle-health-bars-unlock () "#t = cheat unlock requirements met. #f = locked" #f) (defun pc-cheat-board-fast-unlock () "#t = cheat unlock requirements met. #f = locked" (cond ;; haven't reached sewer valve task yet or not in sewers or at the start of sewers ((or (not (task-node-closed? (game-task-node sewer-board-introduction))) (not (aif (level-get-target-inside *level*) (= (-> it name) 'sewer))) (aif (get-continue-by-name *game-info* "sewer-start") (< (vector-vector-distance (target-pos 0) (-> it trans)) (meters 20)))) (set! (-> *pc-cheat-state* sewer-valve-on) #b000) (set! (-> *pc-cheat-state* sewer-valve-start-time) 0) (set! (-> *pc-cheat-state* sewer-valve-end-time) 0) #f) ;; during sewer valve task ((not (task-node-closed? (game-task-node sewer-board-resolution))) (set! (-> *pc-cheat-state* sewer-valve-end-time) (get-current-time)) (when (= (get-base-height *ocean-map*) -216498.17) (set! (-> *pc-cheat-state* sewer-valve-start-time) (get-current-time)) ) ;; no cheating! (cond ((task-node-open? (game-task-node sewer-board-drain)) (aif (process-by-ename "sew-valve-6") (if (and (= 'turn (-> it next-state name)) (= (-> *pc-cheat-state* sewer-valve-on) #b000)) (logior! (-> *pc-cheat-state* sewer-valve-on) #b001))) (aif (process-by-ename "sew-valve-7") (if (and (= 'turn (-> it next-state name)) (= (-> *pc-cheat-state* sewer-valve-on) #b001)) (logior! (-> *pc-cheat-state* sewer-valve-on) #b010))) ) ((and (task-node-closed? (game-task-node sewer-board-drain)) (= (-> *pc-cheat-state* sewer-valve-on) #b011)) (logior! (-> *pc-cheat-state* sewer-valve-on) #b100)) ) (when (and (= *cheat-mode* 'debug) (!= (-> *pc-cheat-state* sewer-valve-end-time) (-> *pc-cheat-state* sewer-valve-start-time))) (format *stdcon* "sewer-valve time: ~0e/~D v: ~3B~%" (- (-> *pc-cheat-state* sewer-valve-end-time) (-> *pc-cheat-state* sewer-valve-start-time)) (-> *pc-cheat-state* sewer-valve-target-seconds) (-> *pc-cheat-state* sewer-valve-on)) ) #f) ;; sewer valve task done! (else (let ( (time-taken (- (-> *pc-cheat-state* sewer-valve-end-time) (-> *pc-cheat-state* sewer-valve-start-time)))) (and (< 0 time-taken) (< time-taken (seconds (-> *pc-cheat-state* sewer-valve-target-seconds))) (= #b111 (-> *pc-cheat-state* sewer-valve-on))) ) ) )) (defun pc-cheat-statistics-unlock () "#t = cheat unlock requirements met. #f = locked" (killed-each-metalhead?)) (defun pc-cheat-suck-in-all-unlock () "#t = cheat unlock requirements met. #f = locked" #f) (defun pc-cheat-fast-travel-unlock () "#t = cheat unlock requirements met. #f = locked" #f) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; pc cheat unlock functions end (defmacro static-pc-cheat-info (name flag can-toggle avail-after &key (skill 0) &key (unlock (null true-func))) "helper for making a new static pc-cheat-info unlock is a pair in format (unlock-text-id unlock-func) where unlock-func returns #t if the unlock requirement is met and #f otherwise skill is the skill requirement. until the requirement is met (and avail-after is closed), it will show 'X required' in the menu avail-after can be a single task-node or a pair of two, car is for normal game and cadr for hero mode" `(new 'static 'pc-cheat-info :name (text-id ,name) :unlock (text-id ,(car unlock)) :unlock-func (quote ,(cadr unlock)) :skill ,skill :flag (pc-cheats ,flag) :avail-after (game-task-node ,(if (pair? avail-after) (car avail-after) avail-after)) :avail-after-hero (game-task-node ,(if (pair? avail-after) (cadr avail-after) avail-after)) :can-toggle (quote ,can-toggle)) ) (defmacro def-pc-cheat-list (name &rest items) "helper for making a list of pc cheats. see static-pc-cheat-info for parameters" `(define ,name (new 'static 'boxed-array :type pc-cheat-info ,@(apply (lambda (x) `(static-pc-cheat-info ,@x)) items))) ) ;; the list of cheats (def-pc-cheat-list *pc-cheats-list* ;; name cheat flag can-toggle avail-after (progress-cheats-music-player music-player #f fortress-escape-introduction) (progress-cheats-real-time-of-day real-time-of-day #t fortress-escape-resolution) (progress-cheats-board-tricks board-tricks #t stadium-board1-gold) (progress-cheats-health-bars health-bars #t palace-boss-resolution :unlock (progress-cheats-health-bars-unlock pc-cheat-health-bars-unlock)) ;(progress-cheats-vehicle-health-bars vehicle-health-bars #t palace-boss-resolution :unlock (progress-cheats-vehicle-health-bars-unlock pc-cheat-vehicle-health-bars-unlock)) (progress-cheats-weather-bad weather-bad #t fortress-escape-resolution :skill 85) (progress-cheats-weather-good weather-good #t fortress-escape-resolution :skill 85) ;(progress-cheats-suck-in-all suck-in-all #t forest-scouts-get-board :unlock (progress-cheats-suck-in-all-unlock pc-cheat-suck-in-all-unlock)) (progress-cheats-turbo-board turbo-board #t sewer-board-introduction :unlock (progress-cheats-turbo-board-unlock pc-cheat-board-fast-unlock)) ;(progress-cheats-fast-travel fast-travel auto city-defend-stadium-introduction :unlock (progress-cheats-fast-travel-unlock pc-cheat-fast-travel-unlock)) ;(progress-cheats-orb-tracker orb-tracker auto nest-boss-resolution) (progress-cheats-no-textures no-textures #t nest-boss-resolution :skill 115) (progress-cheats-vehicle-invuln vehicle-invuln #t nest-boss-resolution :skill 185) ;(progress-cheats-fast-movies fast-movies #t nest-boss-resolution :skill 200) ;(progress-cheats-slow-movies slow-movies #t nest-boss-resolution :skill 200) ;(progress-cheats-fast-speed fast-speed #t nest-boss-resolution :skill 250) ;(progress-cheats-slow-speed slow-speed #t nest-boss-resolution :skill 250) ;(progress-cheats-statistics statistics auto atoll-water-introduction :unlock (progress-cheats-statistics-unlock pc-cheat-statistics-unlock)) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; music player list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defenum music-player-flava :bitfield #t :type uint8 (default) (gun) (board) (mech) (darkjak) (pilot) ) (deftype music-player-track-info (basic) ((text text-id) (name symbol) (mode int8) (icon int16) (flava music-player-flava) (avail-after game-task-node) ) ) (defmacro static-music-track-info (name &key text &key avail-after &key (mode 0) &key icon &key (flava ())) `(new 'static 'music-player-track-info :text (text-id ,text) :name ,name :icon ,icon :avail-after (game-task-node ,avail-after) :mode ,mode :flava (music-player-flava ,@flava)) ) (define *music-player-tracks* (new 'static 'boxed-array :type music-player-track-info (static-music-track-info 'city1 :mode 0 :icon 1 :text progress-music-player-city :avail-after fortress-escape-resolution :flava (gun board pilot)) (static-music-track-info 'city1 :mode 1 :icon 1 :text progress-music-player-city-battle :avail-after city-help-kid-resolution) (static-music-track-info 'ruins :mode 0 :icon 4 :text progress-music-player-ruins :avail-after ruins-tower-resolution :flava (gun board mech darkjak)) (static-music-track-info 'atoll :mode 0 :icon 6 :text progress-music-player-atoll :avail-after atoll-water-resolution :flava (gun darkjak board)) (static-music-track-info 'sewer :mode 0 :icon 3 :text progress-music-player-sewer :avail-after fortress-dump-resolution :flava (gun board mech darkjak)) (static-music-track-info 'sewer :mode 1 :icon 3 :text progress-music-player-sewer-battle :avail-after fortress-dump-resolution) (static-music-track-info 'danger11 :mode 0 :icon 3 :text progress-music-player-danger11 :avail-after fortress-dump-resolution) (static-music-track-info 'atoll :mode 1 :icon 6 :text progress-music-player-atoll-battle :avail-after atoll-sig-resolution) (static-music-track-info 'strip :mode 0 :icon 5 :text progress-music-player-strip :avail-after strip-rescue-resolution :flava (gun board mech darkjak)) (static-music-track-info 'mountain :mode 0 :icon 8 :text progress-music-player-mountain :avail-after mountain-collection-resolution :flava (gun board mech darkjak)) (static-music-track-info 'mountain :mode 1 :icon 8 :text progress-music-player-mountain-battle :avail-after mountain-collection-resolution) (static-music-track-info 'palcab :mode 0 :icon 11 :text progress-music-player-palcab :avail-after palace-cable-resolution :flava (gun board darkjak)) (static-music-track-info 'forest :mode 0 :icon 9 :text progress-music-player-forest :avail-after forest-scouts-resolution :flava (gun board mech darkjak)) (static-music-track-info 'forest :mode 1 :icon 9 :text progress-music-player-forest-battle :avail-after forest-scouts-resolution) (static-music-track-info 'danger9 :mode 0 :icon 1 :text progress-music-player-danger9 :avail-after city-intercept-tanker-resolution) (static-music-track-info 'race :mode 0 :icon 2 :text progress-music-player-race :avail-after stadium-race-class3-resolution) (static-music-track-info 'danger3 :mode 0 :icon 1 :text progress-music-player-danger3 :avail-after city-play-onin-game-resolution) (static-music-track-info 'danger1 :mode 0 :icon 8 :text progress-music-player-battle :avail-after canyon-insert-items-resolution) (static-music-track-info 'danger2 :mode 0 :icon 12 :text progress-music-player-danger2 :avail-after tomb-boss-door) (static-music-track-info 'danger7 :mode 0 :icon 15 :text progress-music-player-danger7 :avail-after tomb-boss-resolution) (static-music-track-info 'danger10 :mode 0 :icon 10 :text progress-music-player-danger10 :avail-after drill-mech-resolution) (static-music-track-info 'palcab :mode 1 :icon 14 :text progress-music-player-palcab-battle :avail-after castle-boss-resolution) (static-music-track-info 'danger6 :mode 0 :icon 14 :text progress-music-player-danger6 :avail-after castle-boss-resolution) (static-music-track-info 'danger4 :mode 0 :icon 17 :text progress-music-player-danger4 :avail-after nest-boss-resolution) )) ;; automatically add the default flava to all tracks that had flavas marked (dotimes (i (-> *music-player-tracks* length)) (if (nonzero? (-> *music-player-tracks* i flava)) (logior! (-> *music-player-tracks* i flava) (music-player-flava default))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; fancy controller LED fader mechanics ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype led-fader-state (structure) ((enable? symbol) (amount float) (cur-color vector :inline) (start-color vector :inline) (end-color vector :inline) ) (:methods (enable (_type_ vector) int) (update (_type_ float float) vector) (disable (_type_) int) ) ) (defmethod enable ((this led-fader-state) (start-from vector)) "begin transition." (when (-> this enable?) (disable this)) (vector-copy! (-> this start-color) start-from) (set! (-> this amount) 0.0) (true! (-> this enable?)) 0) (defmethod disable ((this led-fader-state)) "disable transition." (set! (-> this amount) 0.0) (update this 0.0 0.1) (false! (-> this enable?)) 0) (defun vector3-lerp! ((dest vector) (a vector) (b vector) (alpha float)) "Linearly interpolate between two vectors. Alpha isn't clamped. w will be set to what's in vector a." (rlet ((vf0 :class vf) (vf1 :class vf) (vf2 :class vf) (vf3 :class vf) (vf4 :class vf) ) (init-vf0-vector) (.lvf vf1 (&-> a quad)) (.lvf vf2 (&-> b quad)) (.mov vf4 alpha) (.add.x.vf vf3 vf1 vf0 :mask #b1000) (.sub.vf vf2 vf2 vf1) (.mul.x.vf vf2 vf2 vf4) (.add.vf vf3 vf1 vf2 :mask #b111) (.svf (&-> dest quad) vf3) dest ) ) (defun vector3-copy!! ((dest vector) (src vector)) "copy just the xyz fields of src into dest" (rlet ((vf0 :class vf) (dest-vf :class vf) (src-vf :class vf)) (init-vf0-vector) (.lvf dest-vf (&-> dest quad)) (.lvf src-vf (&-> src quad)) (.add.vf dest-vf vf0 src-vf :mask #b111) (.svf (&-> dest quad) dest-vf) dest ) ) (defmethod update ((this led-fader-state) (to float) (duration float)) "disable transition." (when (-> this enable?) (seek! (-> this amount) to (/ (-> *target* clock seconds-per-frame) duration)) (vector4-lerp! (-> this cur-color) (-> this start-color) (-> this end-color) (-> this amount)) (if (and (= to 0.0) (= 0.0 (-> this amount))) (false! (-> this enable?))) ) (-> this cur-color)) ;; global vars (define *led-fader-state* (new 'static 'led-fader-state :enable? #f)) (define *led-darkjak-color* (static-vector 0.5 0.0 0.5 1.0)) (define *led-tomb-simon-off-color* (static-vector 0.0 0.0 0.0 1.0)) (define *led-tomb-simon-color* (static-vector 0.0 0.0 0.0 1.0)) (define *led-wanted-flash-color* (static-vector 1.0 0.0 0.0 1.0)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; methods ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmethod initialize ((obj pc-settings-jak2)) "initial initialize method to be run after allocating" (set! (-> obj music-unlocked) (new 'global 'bit-array (-> *music-player-tracks* length))) ((method-of-type pc-settings initialize) obj) obj) (defmethod set-game-setting! ((obj pc-settings-jak2) (setting symbol) (value symbol)) (case setting (('video-mode) (set! (-> *setting-control* user-current video-mode) #f) (set! (-> *setting-control* user-default video-mode) value) ) (('aspect-ratio) (set! (-> *setting-control* user-default aspect-ratio) value) ) (else (format #t "unknown setting ~A (~A) to set-game-setting!" setting value)) ) ) (defmethod get-game-setting ((obj pc-settings-jak2) (setting symbol)) (case setting (('video-mode) (-> *setting-control* user-default video-mode) ) (('aspect-ratio) (-> *setting-control* user-default aspect-ratio) ) (else (format #t "unknown setting ~A to get-game-setting" setting) #f) ) ) (defmethod set-game-language! ((obj pc-settings-jak2) (lang language-enum)) (set! (-> *setting-control* user-default language) lang) ) (defmethod get-game-language ((obj pc-settings-jak2)) (get-current-language) ) (defmethod update ((obj pc-settings-jak2)) "Set the default misc settings" ((method-of-type pc-settings update) obj) (set! *hires-sky* (-> obj hires-clouds?)) (when (not (led-enabled? obj)) (disable *led-fader-state*) ) (none)) (defun real-movie? () "are we in an actual cutscene and should letterbox the view?" (and (!= #f *scene-player*) (nonzero? movie?) (movie?))) (defmethod update-discord-rpc ((obj pc-settings-jak2)) "update discord rpc module" (let ((info (new 'stack 'discord-info))) (set! (-> info orb-count) (-> *game-info* skill-total)) (set! (-> info gem-count) (-> *game-info* gem-total)) (set! (-> info death-count) (-> *game-info* total-deaths)) (set! (-> info task) "unknown") (set! (-> info status) (get-active-mission-description info)) ;; grab the name of the level we're in (cond ((or (aif (level-get *level* 'title) (= (-> it status) 'active)) (and *progress-process* (= 'title (-> *progress-process* 0 state-stack 0)))) ;; in title screen. (set! (-> info level) (symbol->string 'title)) (set! (-> info status) "In title screen")) (else (set! (-> info level) (aif (-> *load-state* vis-nick) (symbol->string it) "unknown"))) ) (set! (-> info cutscene?) (real-movie?)) (set! (-> info time-of-day) (-> *time-of-day-context* time)) (set! (-> info percent-complete) (calculate-percentage *game-info*)) (set! (-> info focus-status) (if *target* (-> *target* focus-status) 0)) ;; TODO - update to new with-profiler syntax (pc-discord-rpc-update info) ) (none)) (defmethod update-speedrun ((obj pc-settings-jak2)) "update speedrun module" ;; TODO - update to new with-profiler syntax ;; (with-profiler "speedrun-update" (update! *speedrun-info*) ;;) (none)) (defmethod update-video-hacks ((obj pc-settings-jak2)) "update the graphics hacks used for the progress menu. ugh." (set! (-> (get-video-params) relative-x-scale) (-> obj aspect-ratio-reciprocal)) (set! (-> (get-video-params) relative-x-scale-reciprical) (-> obj aspect-ratio-scale)) ) (defmethod eligible-for-fast-elevator? ((obj pc-settings-jak2) (proc process)) "is this a valid process for a fast elevator?" (and (-> obj fast-elevator?) (not (or (string= (-> proc name) "drill-lift-1") (string= (-> proc name) "drill-lift-2")))) ) (defmethod get-airlock-speed ((obj pc-settings-jak2)) "return the current speed modifier for airlocks" (if (-> obj fast-airlock?) (-> *pc-cheat-state* airlock-speed) 1.0)) (defmethod get-airlock-close-speed ((obj pc-settings-jak2)) "return the current closing speed modifier for airlocks" (if (-> obj fast-airlock?) (-> *pc-cheat-state* airlock-close-speed) 1.0)) (defmethod led-enabled? ((obj pc-settings-jak2)) "should the controller led be set?" (or (-> obj controller-led-hp?) (-> obj controller-led-status?) )) (defmethod update-led ((obj pc-settings-jak2)) "set the controller led color by modifying the controller-led-color vector" ;; default color is just blue. (set-vector-xyz! (-> obj controller-led-color) 0.0 0.0 1.0) (when *target* (let ((disable-fader? #t) (simon-plat (the process #f))) (when (-> obj controller-led-hp?) ;; flicker led according to hp. lower hp = faster and more intense flicker (cond ((= (-> *target* fact health) 0.0) ;; dead. just set to minimum brightness. (set! (-> obj controller-led-color a) (-> obj controller-led-min-brightness)) ) (else (let ((flicker-speed (lerp-scale 2.0 0.0 (-> *target* fact health) 1.0 (-> *FACT-bank* health-max-default))) (flicker-amp (lerp-scale (- 1.0 (-> obj controller-led-min-brightness)) (- 1.0 (-> obj controller-led-max-brightness)) (-> *target* fact health) 1.0 (-> *FACT-bank* health-max-default))) ) (set! (-> obj controller-led-color a) (- 1.0 (* flicker-amp (/ (+ 1.0 (sin (* flicker-speed (degrees (current-time))))) 2.0)))) ) ) ) ) (when (-> obj controller-led-status?) (set-vector-xyz! (-> obj controller-led-color) 1.0 1.0 1.0) (cond ;; simon plat ((set! simon-plat (search-process-tree *active-pool* (lambda ((proc process)) (and (= (-> proc type symbol) 'tomb-plat-simon) (-> proc next-state) (symbol-member? (-> proc next-state name) '(appear show-sequence idle)))))) (set! disable-fader? #f) (case (-> simon-plat next-state name) (('appear) ;; simon plats appearing - fade to black (vector-copy! *led-tomb-simon-color* *led-tomb-simon-off-color*) (vector-copy! (-> *led-fader-state* end-color) *led-tomb-simon-off-color*) (if (not (-> *led-fader-state* enable?)) (enable *led-fader-state* (-> obj controller-led-color))) ) (('show-sequence) ;; showing simon sequence - use only the flashing color (vector-copy! (-> obj controller-led-color) *led-tomb-simon-color*) ;; set fader color to max, if it's not somehow. (when (!= (-> *led-fader-state* amount) 1.0) (set! (-> *led-fader-state* amount) 1.0)) ) (('idle) ;; playing simon sequence - simon blocks set end-color here ) ) (update *led-fader-state* 1.0 2.0) (unless (= (-> simon-plat next-state name) 'show-sequence) (vector3-copy!! (-> obj controller-led-color) (-> *led-fader-state* cur-color))) ) ;; simon plat block ((set! simon-plat (search-process-tree *active-pool* (lambda ((proc process)) (and (= (-> proc type symbol) 'tomb-simon-block) (-> proc next-state) (= (-> proc next-state name) 'dangerous))))) ;; simon plat mistake - fade to black (start color was set by simon block) (set! disable-fader? #f) (vector-copy! (-> *led-fader-state* end-color) *led-tomb-simon-off-color*) (update *led-fader-state* 1.0 1.5) (vector3-copy!! (-> obj controller-led-color) (-> *led-fader-state* cur-color)) ) ;; gun ((and (nonzero? (-> *target* gun)) (focus-test? *target* gun)) (case (-> *target* gun gun-type) (((pickup-type eco-yellow)) (set-vector-xyz! (-> obj controller-led-color) 1.0 0.75 0.125)) (((pickup-type eco-red)) (set-vector-xyz! (-> obj controller-led-color) 0.65 0.0 0.0)) (((pickup-type eco-blue)) (set-vector-xyz! (-> obj controller-led-color) 0.4375 0.8125 1.0)) (((pickup-type eco-dark)) (set-vector-xyz! (-> obj controller-led-color) 0.6875 0.6 0.78125)) ) ) ;; darkjak ((and (nonzero? (-> *target* darkjak)) (focus-test? *target* dark)) (vector-copy! (-> *led-fader-state* end-color) *led-darkjak-color*) (set! disable-fader? #f) (if (not (-> *led-fader-state* enable?)) (enable *led-fader-state* (-> obj controller-led-color))) (if (and (-> *target* next-state) (= (-> *target* next-state name) 'target-darkjak-get-off)) (update *led-fader-state* 0.0 0.75) (update *led-fader-state* 1.0 0.3)) (vector3-copy!! (-> obj controller-led-color) (-> *led-fader-state* cur-color)) ) ;; indax ((focus-test? *target* indax) (set-vector-xyz! (-> obj controller-led-color) 1.0 0.5 0.0) ) ;; mech ((focus-test? *target* mech) (set-vector-xyz! (-> obj controller-led-color) 1.0 1.0 0.0) ) ;; board ((focus-test? *target* board) (set-vector-xyz! (-> obj controller-led-color) 0.0 1.0 1.0) ) ) ;; wanted flash (awhen (the hud-map (process-by-name "hud-map" *active-pool*)) (when (not (hidden? it)) (let ((flash-amount (/ (+ (sin (degrees (-> it values 1 current))) 1.0) 2))) (vector3-lerp! (-> obj controller-led-color) (-> obj controller-led-color) *led-wanted-flash-color* flash-amount) )) ) ) (when disable-fader? (disable *led-fader-state*)) )) #t) (defmacro flava-unlocked? (flava) "return #t if the specified flava is unlocked" `(-> *pc-settings* flava-unlocked ,flava)) (defun inside-city? () "are we inside haven city?" (symbol-member? (-> *game-info* current-continue vis-nick) ;; TODO get actual level we're in? '(ctysluma ctyslumb ctyslumc ctygena ctygenb ctygenc ctymarka ctymarkb ctyfarma ctyfarmb ctyinda ctyindb ctypal ctyport stadium))) (defmethod update-cheats ((obj pc-settings-jak2)) "run cheats." ;; run cheats here. ;;;;;;;;;;;;;;;;;;; (when (pc-cheats? (-> obj cheats) real-time-of-day) (let ((date (new 'stack-no-clear 'scf-time))) (scf-get-time date) (when (zero? (-> date stat)) (let* ((cur-time (-> *display* bg-clock frame-counter)) (day-len (seconds 1440)) ;; a full in-game day (want-hour (bcd->dec (-> date hour))) (want-minute (bcd->dec (-> date minute))) (target-hour-frame (/ (the int (* (fsec 3600) want-hour)) 60)) (target-minute-frame (/ (the int (* (fsec 60) want-minute)) 60)) ) (set! (-> *display* bg-clock frame-counter) (+ (- cur-time (mod cur-time day-len)) day-len (+ target-hour-frame target-minute-frame))) )) )) ;; turbo jet board cheat (cond ((and (pc-cheats? (-> obj cheats) turbo-board) *target* (focus-test? *target* board) (inside-city?)) (set-setting! 'string-spline-max-move 'abs (* (-> *pc-cheat-state* turbo-board-speed) (meters 2)) 0) (set-setting! 'string-spline-accel 'abs (* (-> *pc-cheat-state* turbo-board-speed) (meters 0.045)) 0) (set-setting! 'string-spline-max-move-player 'abs (* (-> *pc-cheat-state* turbo-board-speed) (meters 1.5)) 0) (set-setting! 'string-spline-accel-player 'abs (* (-> *pc-cheat-state* turbo-board-speed) (meters 0.035)) 0) (set-cheat-state-flag! turbo-board) ) (else (remove-setting! 'string-spline-max-move) (remove-setting! 'string-spline-accel) (remove-setting! 'string-spline-max-move-player) (remove-setting! 'string-spline-accel-player) (clear-cheat-state-flag! turbo-board) ) ) (pc-set-gfx-hack (pc-gfx-hack no-tex) (pc-cheats? (-> obj cheats) no-textures)) ;; run cheats end!!! ;;;;;;;;;;;;;;;;;;;; ;; check unlocked cheats ;;;;;;;;;;;;;;;;;;;;;;;; (let ((old (-> *pc-settings* cheats)) (old-unlocked (-> *pc-settings* cheats-unlocked)) (old-purchased (-> *pc-settings* cheats-purchased)) (old-revealed (-> *pc-settings* cheats-revealed))) (dotimes (i (-> *pc-cheats-list* length)) ;; reveals cheats if they have been purchased, purchases cheats if they have been unlocked, unlocks cheats if they have been enabled. ;; the cheat process requires the steps to be filled in this order, see sequential checking below (logior! (-> *pc-settings* cheats-revealed) (logior! (-> *pc-settings* cheats-purchased) (logior! (-> *pc-settings* cheats-unlocked) (-> *pc-settings* cheats)))) (let* ((cheat (-> *pc-cheats-list* i)) (cost (-> cheat skill)) (unlock-func (the (function symbol) (-> cheat unlock-func value)))) (when (if (logtest? (-> *game-info* secrets) (game-secrets hero-mode)) (task-node-closed? (-> cheat avail-after-hero)) (task-node-closed? (-> cheat avail-after))) (logior! (-> obj cheats-revealed) (-> cheat flag)) (when (>= (-> *game-info* skill-total) cost) (logior! (-> obj cheats-purchased) (-> cheat flag)) (when (or (zero? unlock-func) (not unlock-func) (unlock-func)) (logior! (-> obj cheats-unlocked) (-> cheat flag))))) (case (-> cheat can-toggle) ((#f) (when (logtest? (-> obj cheats-unlocked) (-> cheat flag)) (logior! (-> obj cheats) (-> cheat flag))) ) ))) (when (or (!= old (-> *pc-settings* cheats)) (!= old-unlocked (-> *pc-settings* cheats-unlocked)) (!= old-purchased (-> *pc-settings* cheats-purchased)) (!= old-revealed (-> *pc-settings* cheats-revealed))) ;; save pc-settings if we made new progress (pc-settings-save))) 0) (defmethod update-music-log ((obj pc-settings-jak2)) "update the music log" (dotimes (i (-> *music-player-tracks* length)) (when (or (logtest? (-> *game-info* secrets) (game-secrets hero-mode)) (task-node-closed? (-> *music-player-tracks* i avail-after))) (set-bit (-> obj music-unlocked) i) ) ) (true! (-> obj flava-unlocked 0)) ;; default always unlocked (if (task-node-closed? (game-task-node city-red-gun-training-resolution)) (true! (-> obj flava-unlocked 1))) ;; gun (if (task-node-closed? (game-task-node forest-scouts-resolution)) (true! (-> obj flava-unlocked 2))) ;; board (if (task-node-closed? (game-task-node ruins-mech-resolution)) (true! (-> obj flava-unlocked 3))) ;; mech (if (task-node-closed? (game-task-node city-oracle-introduction)) (true! (-> obj flava-unlocked 4))) ;; darkjak (if (task-node-closed? (game-task-node city-vehicle-training-resolution)) (true! (-> obj flava-unlocked 5))) ;; pilot 0) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; file I/O ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun bit-array<-int64 ((arr bit-array) (start-offset int) (val int)) "starting from start-offset at arr, fill the next 64 bits of the array from an int64" (let ((i start-offset) (end-offset (min (+ start-offset 64) (-> arr length)))) (while (< i end-offset) (if (nonzero? (logand val (ash 1 (- i start-offset)))) (set-bit arr i)) (1+! i) ) val) ) (defun int64<-bit-array ((arr bit-array) (start-offset int)) "starting from start-offset at arr, pack the next 64 bits into a single value and return it" (let ((val 0) (i start-offset) (end-offset (min (+ start-offset 64) (-> arr length)))) (while (< i end-offset) (if (get-bit arr i) (logior! val (ash 1 (- i start-offset)))) (1+! i) ) val) ) (defmethod handle-input-settings ((obj pc-settings-jak2) (file file-stream)) "handle the text parsing input for the 'settings' group" ((method-of-type pc-settings handle-input-settings) obj file) (case-str *pc-temp-string* (("fast-airlock?") (set! (-> obj fast-airlock?) (file-stream-read-symbol file))) (("fast-elevator?") (set! (-> obj fast-elevator?) (file-stream-read-symbol file))) (("fast-progress?") (set! (-> obj fast-progress?) (file-stream-read-symbol file))) (("smooth-minimap?") (set! (-> obj smooth-minimap?) (file-stream-read-symbol file))) (("hires-clouds?") (set! (-> obj hires-clouds?) (file-stream-read-symbol file))) (("text-language") (set! (-> obj text-language) (the-as pc-language (file-stream-read-int file)))) (("controller-led-status?") (set! (-> obj controller-led-status?) (file-stream-read-symbol file))) (("speedrunner-mode-custom-bind") (set! (-> obj speedrunner-mode-custom-bind) (file-stream-read-int file))) (("cheats") (set! (-> obj cheats) (the-as pc-cheats (file-stream-read-int file)))) (("cheats-revealed") (set! (-> obj cheats-revealed) (the-as pc-cheats (file-stream-read-int file)))) (("cheats-purchased") (set! (-> obj cheats-purchased) (the-as pc-cheats (file-stream-read-int file)))) (("cheats-unlocked") (set! (-> obj cheats-unlocked) (the-as pc-cheats (file-stream-read-int file)))) (("cheats-backup") (file-stream-read-int file)) ;; TODO - Don't remove this, parsing code can't handle unexpected keys (("music-unlocked") (dotimes (i (/ (align64 (-> obj music-unlocked length)) 64)) (bit-array<-int64 (-> obj music-unlocked) (* i 64) (file-stream-read-int file)) ) ) (("flava-unlocked") (dotimes (i 6) (set! (-> obj flava-unlocked i) (file-stream-read-symbol file)) ) ) (("stats") (dosettings (file) (case-str *pc-temp-string* (("kill-stats") (initialize (-> obj stats kill-stats)) (dosettings (file) (let ((enemy-stats (alloc-slot (-> obj stats kill-stats) (string->symbol *pc-temp-string*)))) (dosettings (file) (let ((source (string->kill-source *pc-temp-string*)) (amount (file-stream-read-int file))) (when (!= source (kill-stats-source unknown)) (set! (-> enemy-stats sources source) amount) ) ) ) ) ) ) ) ) ) ) 0) (defmethod handle-output-settings ((obj pc-settings-jak2) (file file-stream)) "handle the text writing output for the 'settings' group" ((method-of-type pc-settings handle-output-settings) obj file) (format file " (fast-airlock? ~A)~%" (-> obj fast-airlock?)) (format file " (fast-elevator? ~A)~%" (-> obj fast-elevator?)) (format file " (fast-progress? ~A)~%" (-> obj fast-progress?)) (format file " (smooth-minimap? ~A)~%" (-> obj smooth-minimap?)) (format file " (hires-clouds? ~A)~%" (-> obj hires-clouds?)) (format file " (text-language ~D)~%" (-> obj text-language)) (format file " (controller-led-status? ~A)~%" (-> obj controller-led-status?)) (format file " (speedrunner-mode-custom-bind ~D)~%" (-> obj speedrunner-mode-custom-bind)) (format file " (cheats #x~x)~%" (-> obj cheats)) (format file " (cheats-revealed #x~x)~%" (-> obj cheats-revealed)) (format file " (cheats-purchased #x~x)~%" (-> obj cheats-purchased)) (format file " (cheats-unlocked #x~x)~%" (-> obj cheats-unlocked)) (format file " (music-unlocked") (dotimes (i (/ (align64 (-> obj music-unlocked length)) 64)) (format file " #x~x" (int64<-bit-array (-> obj music-unlocked) (* i 64))) ) (format file ")~%") (format file " (flava-unlocked") (dotimes (i 6) (format file " ~A" (-> obj flava-unlocked i)) ) (format file ")~%") (format file " (stats~%") (format file " (kill-stats~%") (dotimes (i KILL_STATS_MAX_ENEMY_TYPES) (when (-> obj stats kill-stats enemies i name) (format file " (~A~%" (-> obj stats kill-stats enemies i name)) (dotimes (ii KILL_STATS_MAX_SOURCE) (when (nonzero? (-> obj stats kill-stats enemies i sources ii)) (format file " (~A ~D)~%" (string->symbol (kill-source->string (the kill-stats-source ii))) (-> obj stats kill-stats enemies i sources ii)) )) (format file " )~%") )) (format file " )~%") (format file " )~%") 0) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; PC settings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-once *pc-settings* (new 'global 'pc-settings-jak2)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; other ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun draw-build-revision () (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2)) ;; reset bucket settings prior to drawing - font won't do this for us, and ;; draw-raw-image can sometimes mess them up. (dma-buffer-add-gs-set-flusha buf (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)) (tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1))) (clear *pc-encoded-temp-string*) (clear *temp-string*) (format *temp-string* "~S" *pc-settings-built-sha*) (pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*) (let ((font-ctx (new 'stack 'font-context *font-default-matrix* 2 406 0.0 (font-color default) (font-flags shadow kerning large)))) (set! (-> font-ctx scale) 0.25) (draw-string-adv *pc-encoded-temp-string* buf font-ctx)))) (defun print-level-types ((lev level)) "print the level-type linked list for a level" (format #t "print-level-types for ~A~%" (-> lev nickname)) (let ((cur-type (-> lev level-type))) (while (and cur-type (nonzero? cur-type) (= type (-> cur-type type))) (format #t "~A~%" cur-type) (set! cur-type (the type (-> cur-type method-table 8)))) (format #t "~%")) ) (defun-debug pc-cheat->string ((cheat pc-cheats)) (doenum (name val pc-cheats) (if (= cheat val) (return name)) ) "*unknown*") (defun-debug print-cheat-status (out) (dotimes (i (-> *pc-cheats-list* length)) (let ((flag (-> *pc-cheats-list* i flag))) (cond ((logtest? (-> *pc-settings* cheats) flag) (format out " ~20S(#x~6x): enabled~%" (pc-cheat->string flag) flag)) ((logtest? (-> *pc-settings* cheats-unlocked) flag) (format out " ~20S(#x~6x): unlocked~%" (pc-cheat->string flag) flag)) ((logtest? (-> *pc-settings* cheats-purchased) flag) (format out " ~20S(#x~6x): purchased~%" (pc-cheat->string flag) flag)) ((logtest? (-> *pc-settings* cheats-revealed) flag) (format out " ~20S(#x~6x): revealed~%" (pc-cheat->string flag) flag)) (else (format out " ~20S(#x~6x): locked~%" (pc-cheat->string flag) flag)) ) )) out) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; process pools ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; the actor pool for PC processes! it has space for 4 processes, with 16K of space. (define *pc-dead-pool* (new 'global 'dead-pool 4 (* 16 1024) "*pc-dead-pool*")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; progress adjustments ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defconstant CENTER_X (/ 512 2)) (defun adjust-game-x-centered ((origin int) (x float)) "given an x position ranging from [0, 512) adjust for aspect ratio towards the origin point specified such that it does not get stretched away with the framebuffer" (+ origin (* (- x origin) (-> *pc-settings* aspect-ratio-reciprocal)))) (defmacro adjust-game-x (x) `(adjust-game-x-centered CENTER_X ,x)) (defmacro adjust-game-x-int (x-float) `(the int (adjust-game-x-centered CENTER_X (the float ,x-float))))