dos33fsprogs/games/mist/cabin_boiler_puzzle.s

775 lines
12 KiB
ArmAsm

; this is a painful one
; mostly because the tree puzzle is sort of obscure in the original
; in original you get a match, then light it
; the match will flicker and burn out if you go outside
; light the pilot, it will turn red
; boiler PSI starts at zero
; turn once clockwise, fire starts, nothing else?
; turn once counter-clockwise fire turns off
; turn twice CW -> ?
; turn 3 CW -> ?
; turn 4, 5, 6, 7, 8, 9, 10, 11, 12, CW -> ?
; can turn up to 25
; at 12 starts gradually going up
; (needle swings hits end, waits like 5s, goes up)
; PSI counts 0 to 24?
; 0 - basement
; 1 - down 1/2
; 2 - down 1
; 3 - half out
; 4 - all out (can get on) *
; 5 -
; 6 - *
; 7 -
; 8 - *
; 9 -
; 10 - *
; 11 -
; 12 - * (top) (can look down at all spots)
; button takes you down a level, but only to ground floor
; will actually bump you back to Level 3 if you press on ground
; button does nothing in basement
; dial in basement does same as one upstairs
; 0123456789012345678901234
; \ \ \ \ \ : / / / / /
; P S I
; \
; BOILER_VALVE
; BOILER_LEVEL: high bit is if pilot lit, low bits are PSI
; BOILER_TOTAL:
; 0...128 warming up
; then if valve>12 inc level, when hit 15 inc tree
; if valve<12 dec level, when hit 0 dec tree
; rate of adding is (valve-12) 0..12 / 4 = 0..3
; 0 = FRAMEL&7f==0
; 1 = FRAMEL&3f==0
; 2 = FRAMEL&1f==0
; 3 = FRAMEL&7==0
; Make noise when change tree level
update_boiler_state:
; if pilot not lit, nothing to do
lda BOILER_LEVEL
bpl done_boiler_state
lda BOILER_VALVE
; beq done_boiler_state
sec
sbc #12
bpl skip_abs
eor #$ff
clc
adc #$1
skip_abs:
; adjust speed based on valve position
; div by 4
lsr
lsr
tay
lda FRAMEL
cpy #0
beq speed_slowest
cpy #1
beq speed_slow
cpy #2
beq speed_fast
speed_fastest:
and #$f
speed_fast:
and #$1f
speed_slow:
and #$3f
speed_slowest:
and #$7f
beq actually_adjust_boiler
rts
actually_adjust_boiler:
lda BOILER_VALVE
cmp #12
bcs valve_positive
bcc valve_negative
valve_positive:
jsr inc_boiler
jmp done_boiler_state
valve_negative:
jsr dec_boiler
done_boiler_state:
rts
inc_boiler:
lda BOILER_LEVEL
and #$7f
cmp #25
beq inc_boiler_overflow
inc BOILER_LEVEL
rts
inc_boiler_overflow:
lda TREE_LEVEL
cmp #6
beq tree_at_top
lda BOILER_LEVEL
and #$80
sta BOILER_LEVEL
inc TREE_LEVEL
jsr change_tree_level
tree_at_top:
rts
dec_boiler:
lda BOILER_LEVEL
and #$1f
cmp #0
beq dec_boiler_overflow
dec BOILER_LEVEL
rts
dec_boiler_overflow:
lda TREE_LEVEL
beq tree_at_bottom
lda #$80|24
sta BOILER_LEVEL
dec TREE_LEVEL
jsr change_tree_level
tree_at_bottom:
rts
change_tree_level:
jsr cabin_update_state
jsr change_direction
jsr long_beep
rts
tree_base_backgrounds:
.word tree_base_n_lzsa ; 0 basement
.word tree_base_n_lzsa ; 1 underground
.word tree_base_l4_n_lzsa ; 2 ground
.word tree_base_l6_n_lzsa ; 3 L6
.word tree_base_n_lzsa ; 4 L8
.word tree_base_n_lzsa ; 5 L10
.word tree_base_n_lzsa ; 6 TOP
tree_base_up_backgrounds:
.word tree_base_up_lzsa ; 0 basement
.word tree_base_up_l2_lzsa ; 1 underground
.word tree_base_up_l4_lzsa ; 2 ground
.word tree_base_up_l6_lzsa ; 3 L6
.word tree_base_up_l8_lzsa ; 4 L8
.word tree_base_up_l10_lzsa ; 5 L10
.word tree_base_up_l12_lzsa ; 6 TOP
tree_elevator_backgrounds:
.word tree_elevator_basement_s_lzsa ; 0 basement
.word tree_elevator_l2_lzsa ; 1 underground
.word tree_elevator_l4_lzsa ; 2 ground
.word tree_elevator_l6_lzsa ; 3 L6
.word tree_elevator_l8_lzsa ; 4 L8
.word tree_elevator_l10_lzsa ; 5 L10
.word tree_elevator_l12_lzsa ; 6 TOP
tree_basement_backgrounds:
.word tree_basement_n_lzsa ; 0 basement
.word tree_basement_noelev_n_lzsa ; 1 underground
.word tree_basement_noelev_n_lzsa ; 2 ground
.word tree_basement_noelev_n_lzsa ; 3 L6
.word tree_basement_noelev_n_lzsa ; 4 L8
.word tree_basement_noelev_n_lzsa ; 5 L10
.word tree_basement_noelev_n_lzsa ; 6 TOP
tree_elevator_exits:
.byte CABIN_TREE_BASEMENT ; 0 basement
.byte $ff ; 1 underground
.byte CABIN_BIG_TREE ; 2 ground
.byte $ff ; 3 L6
.byte $ff ; 4 L8
.byte $ff ; 5 L10
.byte CABIN_TREE_LOOK_DOWN ; 6 TOP
tree_entrance:
.byte CABIN_TREE_LOOK_UP ; 0 basement
.byte CABIN_TREE_LOOK_UP ; 1 underground
.byte CABIN_TREE_ELEVATOR ; 2 ground
.byte CABIN_TREE_LOOK_UP ; 3 L6
.byte CABIN_TREE_LOOK_UP ; 4 L8
.byte CABIN_TREE_LOOK_UP ; 5 L10
.byte CABIN_TREE_LOOK_UP ; 6 TOP
; south if getting on elevator
; north if looking up
tree_entrance_dir:
.byte DIRECTION_N ; 0 basement
.byte DIRECTION_N ; 1 underground
.byte DIRECTION_S ; 2 ground
.byte DIRECTION_N ; 3 L6
.byte DIRECTION_N ; 4 L8
.byte DIRECTION_N ; 5 L10
.byte DIRECTION_N ; 6 TOP
tree_basement_exit:
.byte CABIN_TREE_ELEVATOR ; 0 basement
.byte $ff ; 1 underground
.byte $ff ; 2 ground
.byte $ff ; 3 L6
.byte $ff ; 4 L8
.byte $ff ; 5 L10
.byte $ff ; 6 TOP
;===================================
; update backgrounds based on state
;===================================
cabin_update_state:
; update tree base background
ldy #LOCATION_NORTH_BG
lda TREE_LEVEL
asl
tax
lda tree_base_backgrounds,X
sta location7,Y ; CABIN_BIG_TREE
lda tree_base_backgrounds+1,X
sta location7+1,Y ; CABIN_BIG_TREE
; update tree up background
lda tree_base_up_backgrounds,X
sta location14,Y ; CABIN_TREE_LOOK_UP
lda tree_base_up_backgrounds+1,X
sta location14+1,Y ; CABIN_TREE_LOOK_UP
; update basement background
lda tree_basement_backgrounds,X
sta location9,Y ; CABIN_TREE_BASEMENT
lda tree_basement_backgrounds+1,X
sta location9+1,Y ; CABIN_TREE_BASEMENT
; update tree elevator background
ldy #LOCATION_SOUTH_BG
lda tree_elevator_backgrounds,X
sta location8,Y ; CABIN_TREE_ELEVATOR
lda tree_elevator_backgrounds+1,X
sta location8+1,Y ; CABIN_TREE_ELEVATOR
; update if you can get into tree
lda TREE_LEVEL
tax
ldy #LOCATION_NORTH_EXIT
lda tree_entrance,X
sta location7,Y ; CABIN_BIG_TREE
ldy #LOCATION_NORTH_EXIT_DIR
lda tree_entrance_dir,X
sta location7,Y ; CABIN_BIG_TREE
; update elevator exit
ldy #LOCATION_SOUTH_EXIT
lda tree_elevator_exits,X
sta location8,Y ; CABIN_TREE_ELEVATOR
; update basement exit
ldy #LOCATION_NORTH_EXIT
lda tree_basement_exit,X
sta location9,Y ; CABIN_TREE_BASEMENT
rts
;==========================
; valve clicked in basement
valve_clicked_basement:
lda CURSOR_X
cmp #8
bcc valve_dec
bcs valve_inc
;==================================
; goto safe or valve (cabin boiler)
goto_safe_or_valve:
lda DIRECTION
and #$f
cmp #DIRECTION_W
beq goto_safe
valve_clicked_cabin:
lda CURSOR_X
cmp #33
bcc valve_dec
bcs valve_inc
valve_dec:
lda BOILER_VALVE
beq done_valve
dec BOILER_VALVE
jmp done_valve
valve_inc:
lda BOILER_VALVE
cmp #25
bcs done_valve
inc BOILER_VALVE
done_valve:
rts
;====================
; safe was clicked
;====================
goto_safe:
lda #CABIN_SAFE
sta LOCATION
jmp change_location
;====================
; open safe was touched
;====================
; close safe or take/light match
; how does this interact with holding a page?
touch_open_safe:
lda CURSOR_X
cmp #21
bcc handle_matches
; touching door
touching_safe_door:
lda #CABIN_SAFE
sta LOCATION
jmp change_location
handle_matches:
lda CURSOR_Y
cmp #32
bcc not_matches
cmp #41
bcs not_matches
lda HOLDING_ITEM
cmp #HOLDING_LIT_MATCH
beq not_matches
cmp #HOLDING_MATCH
beq light_match
; not a match yet
take_match:
lda #HOLDING_MATCH
sta HOLDING_ITEM
bne not_matches ; bra
light_match:
lda #HOLDING_LIT_MATCH
sta HOLDING_ITEM
not_matches:
rts
;====================
; safe was touched
;====================
touch_safe:
lda CURSOR_Y
; check if buttons
cmp #26 ; blt
bcc safe_buttons
; check if handle
cmp #34
bcs pull_handle ; bge
; else do nothing
rts
pull_handle:
lda SAFE_HUNDREDS
cmp #7
bne wrong_combination
lda SAFE_TENS
cmp #2
bne wrong_combination
lda SAFE_ONES
cmp #4
bne wrong_combination
lda #CABIN_OPEN_SAFE
sta LOCATION
lda #DIRECTION_W|DIRECTION_ONLY_POINT
sta DIRECTION
jmp change_location
wrong_combination:
rts
safe_buttons:
jsr click_speaker
lda CURSOR_X
cmp #13 ; not a button
bcc no_button
cmp #19
bcc hundreds_inc
cmp #25
bcc tens_inc
bcs ones_inc
no_button:
rts
hundreds_inc:
sed
lda SAFE_HUNDREDS
clc
adc #$1
cld
and #$f
sta SAFE_HUNDREDS
rts
tens_inc:
sed
lda SAFE_TENS
clc
adc #$1
cld
and #$f
sta SAFE_TENS
rts
ones_inc:
sed
lda SAFE_ONES
clc
adc #$1
cld
and #$f
sta SAFE_ONES
rts
;==============================
; draw the numbers on the safe
;==============================
draw_safe_combination:
; hundreds digit
lda SAFE_HUNDREDS
and #$f
asl
tay
lda number_sprites,Y
sta INL
lda number_sprites+1,Y
sta INH
lda #15
sta XPOS
lda #8
sta YPOS
jsr put_sprite_crop
; tens digit
lda SAFE_TENS
and #$f
asl
tay
lda number_sprites,Y
sta INL
lda number_sprites+1,Y
sta INH
lda #21
sta XPOS
lda #8
sta YPOS
jsr put_sprite_crop
; ones digit
lda SAFE_ONES
and #$f
asl
tay
lda number_sprites,Y
sta INL
lda number_sprites+1,Y
sta INH
lda #27
sta XPOS
lda #8
sta YPOS
jsr put_sprite_crop
rts
; valve sprites
valve_sprites:
.word valve0_sprite
.word valve1_sprite
.word valve2_sprite
.word valve3_sprite
valve0_sprite:
.byte 6,6
.byte $AA,$1A,$11,$11,$1A,$AA
.byte $1A,$A1,$11,$AA,$A1,$11
.byte $11,$AA,$d1,$1A,$1A,$11
.byte $11,$A1,$A1,$1A,$AA,$11
.byte $A1,$11,$AA,$11,$1A,$A1
.byte $AA,$A1,$A1,$A1,$A1,$AA
valve1_sprite:
.byte 6,6
.byte $AA,$1A,$A1,$11,$1A,$AA
.byte $11,$A1,$AA,$11,$AA,$11
.byte $11,$A1,$dA,$a1,$AA,$11
.byte $11,$AA,$11,$A1,$A1,$11
.byte $A1,$11,$11,$AA,$1A,$A1
.byte $AA,$AA,$A1,$A1,$A1,$AA
valve2_sprite:
.byte 6,6
.byte $AA,$1A,$A1,$A1,$1A,$AA
.byte $11,$11,$AA,$AA,$11,$11
.byte $11,$AA,$d1,$A1,$AA,$11
.byte $11,$AA,$11,$A1,$1A,$11
.byte $A1,$11,$AA,$AA,$11,$A1
.byte $AA,$AA,$A1,$A1,$A1,$AA
valve3_sprite:
.byte 6,6
.byte $AA,$1A,$A1,$A1,$1A,$AA
.byte $11,$A1,$1A,$AA,$AA,$11
.byte $11,$AA,$d1,$1A,$A1,$11
.byte $11,$1A,$A1,$11,$AA,$11
.byte $AA,$11,$AA,$A1,$11,$A1
.byte $AA,$AA,$A1,$A1,$A1,$AA
;==============
; flame sprites
flame_sprites:
.word flame1_sprite
.word flame2_sprite
flame1_sprite:
.byte 6,3
.byte $f5,$d5,$d5,$95,$95,$95
.byte $ff,$ff,$df,$dd,$9d,$9d
.byte $59,$59,$59,$59,$58,$58
flame2_sprite:
.byte 6,3
.byte $f5,$d5,$d5,$95,$95,$95
.byte $ff,$ff,$df,$dd,$9d,$ff
.byte $5d,$5d,$59,$59,$59,$59
;=============================
; draw valve and other things
; involving the boiler
;=============================
draw_valve_cabin:
; make sure facing right direction
lda DIRECTION
and #$f
cmp #DIRECTION_E
bne done_draw_valve
; see if we need to draw pilot
lda BOILER_LEVEL
bpl skip_pilot
; put $91 at 15,36, $55f
lda #$5
clc
adc DRAW_PAGE
sta pilot_smc+2
lda #$91
pilot_smc:
sta $55f
; see if need to draw flame
lda BOILER_VALVE
beq skip_pilot
; draw flame
lda FRAMEL
and #$8
lsr
lsr
tay
lda flame_sprites,Y
sta INL
lda flame_sprites+1,Y
sta INH
lda #18
sta XPOS
lda #32
sta YPOS
jsr put_sprite_crop
skip_pilot:
draw_psi:
bit TEXTGR ; bit of a hack
; adjust to correct page
lda DRAW_PAGE
clc
adc #$7
sta psi_smc+2
lda BOILER_LEVEL
and #$1f
tay
cpy #13
beq want_colon
bcc want_backslash
want_slash:
lda #'/'|$80
bne put_psi ; bra
want_backslash:
lda #'\'|$80
bne put_psi ; bra
want_colon:
lda #':'|$80
put_psi:
; 7,44 = $757
psi_smc:
sta $757,Y
lda #31
sta XPOS
lda #14
bne really_draw_valve ; bra
draw_valve_basement:
lda DIRECTION
and #$f
cmp #DIRECTION_N
bne done_draw_valve
lda #5
sta XPOS
lda #24
really_draw_valve:
sta YPOS
lda BOILER_VALVE
and #$3
asl
tay
lda valve_sprites,Y
sta INL
lda valve_sprites+1,Y
sta INH
jmp put_sprite_crop
done_draw_valve:
rts
;==============================
; press elevator button
;==============================
press_elevator_button:
lda TREE_LEVEL
cmp #2
beq bump_up
bcc button_ineffective
dec TREE_LEVEL ; drops you a floor
lda #$80
sta BOILER_LEVEL ; give some time before hitting again
jsr change_tree_level
button_ineffective:
rts
bump_up:
inc TREE_LEVEL ; if on ground floor it bumps you up
jsr change_tree_level
jmp button_ineffective