-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathobjectEnemy.asm
More file actions
2533 lines (2425 loc) · 108 KB
/
objectEnemy.asm
File metadata and controls
2533 lines (2425 loc) · 108 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; Bakn 3
; COL DETECT macros use about 3,5kB
SCOOP_RADIUS_Y = 60
SCOOP_RADIUS_X = 30
PLAYER_RADIUS_X = 15
PLAYER_RADIUS_Y = 22
; using a conditional + include
; I can reuse the colision detection for both bugs and "normal" enemies!
; actually it is not the reuse I am keen on - but rather to have
; the collision detection in a singular place
include "enemyShotColDetect.asm"
;
; collision detection player shot -> enemy
; only one shot is tested per game round
; two shots
; main must ensure the two to be tested shots are "halfway"
COL_DETECT_2A macro
COL_DETECT_ENEMY_SHOTS_ENEMY testShot, Y_POS, X_POS, 1
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COL_DETECT_2B macro
COL_DETECT_ENEMY_SHOTS_ENEMY test2Shot, Y_POS, X_POS, 0
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COL_DETECT_PLAYER_BASE macro YBASE, XBASE
lda YBASE +u_offset1,s
ldb playerBonusActive
bitb #BITFIELD_SCOOP
lbne doScoopCheck\?
isBugEnemy\?
cmpa #$80+PLAYER_RADIUS_Y
lbgt notHit\?
ldb XBASE +u_offset1,s
subb playerXpos
bpl noNeg\?
negb
noNeg\?
cmpb #PLAYER_RADIUS_X
bhi notHit_x\?
lda playerBonusActive
bita #BITFIELD_SHIELD ; shield saved player (from all shots)
bne notHit_Shot_removeEnemy\?
bita #BITFIELD_ARMOR
lbeq playerCaughtShot\? ; armor saved player for one shot
anda #255-BITFIELD_ARMOR
sta playerBonusActive
SWITCH_TO_SHORT_SHIELD
if SHORT_INVULNERABILITY
bra notHit_Shot_removeEnemy\?
endif
notHit_Shot_removeEnemy\?
lda #2
sta explosionSound
; set HP = 0
; if enemy collides with player -> it is dead!
; or explode directly :-)
jmp yesExplodeEnemy ; shotHandleDoneRemoved
notHit_x\?
if SCOOPIE_DONT_DIE = 1
jmp notHit\?
else
lda lockPurchased
anda #%00100000
bne notHit\?
endif
; check scoop collision
lda difficulty
anda #$f ;
beq notHit\? ; easy difficulty -> scoops are not hit by enemies/debris
; in b "radius" from player center (ABS)
cmpb #SCOOP_RADIUS_X
bhi notHit\?
; possible scoop hit, check if scoop exists
; check for left or right
ldb XBASE +u_offset1,s
subb playerXpos
bvs notHit\? ; added to ensure leftmost debris does not collide with right most scoopies
bpl checkRightScoop\?
checkLeftScoop\?
ldx scoopEnemy2
beq notHit\? ; there is no scoopy!
; left scoopy hit -> explode !
ldd #0
std scoopEnemy2
scoopyHit\?
lda #2
sta explosionSound
inc enemyCount ; because after explosion, the remove enemy - does again a "dec enemy count" this would screw the counting
; since scoopies were removed before!
lda #-1
sta ALL_PURPOSE ,x ; negative means this enemy is an explosion
ldd #enemyExplosionBehaviour
std BEHAVIOUR ,x ; negative means this enemy is an explosion
clr ANIM_POSITION ,x
ldy ENEMY_STRUCT ,x
ldy WAIT_ANIM_TABLE, y
ldy ,y
sty SMARTLIST_ORG ,x
ldd #$7f09 ; scale
stb EXPLOSION_SCALE ,x
;lda #$7f ; intensity
sta EXPLOSION_INTENSITY ,x
bra notHit\?
checkRightScoop\?
ldx scoopEnemy1
beq notHit\? ; there is no scoopy!
; right scoopy hit -> explode !
ldd #0
std scoopEnemy1
bra scoopyHit\?
doScoopCheck\?
cmpa #$80+SCOOP_RADIUS_Y
bgt notHit\?
ldb X_POS +u_offset1,s
subb playerXpos
bpl noNeg2\?
negb
noNeg2\?
cmpb #SCOOP_RADIUS_X
bhi notHit\?
ldx ENEMY_STRUCT+u_offset1,s
ldx ANGLE8_TABLE,x
lbeq isBugEnemy\?
; or scoop it
jmp repellEnemy
playerCaughtShot\?
lda #1 ; TODO strength of enemy bullet
sta playerWasHitFor
notHit\?
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COL_DETECT_PLAYER macro
COL_DETECT_PLAYER_BASE Y_POS, X_POS
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_COL_DETECT macro
COL_DETECT_2A
ldb X_POS +u_offset1,s
COL_DETECT_2B
COL_DETECT_PLAYER
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
TEST_TO_SHOOT macro
ldd bulletSpawnAt ; only one shot possible per round
bne noBulletSpawn\?
if ENEMY_NO_SHOOTING = 1
bra noBulletSpawn\?
endif
lda shotCount
ldx currentLevelPointer
cmpa levelMaxEnemyShots
bhs noBulletSpawn\?
lda BIT_MASK+u_offset1,s ; do not shoot again in xx rounds
anda #$07 ; only lower nibble BIT_MASK+u_offset1,s
beq try_shot\?
dec BIT_MASK+u_offset1,s
bra noBulletSpawn\?
try_shot\?
ldd BEHAVIOUR+u_offset1,s ; in waiting shots might not be allowed
cmpd #enemyWaitingBehaviour
bne shotseeminglyOk\?
ldx currentLevelPointer
lda LEVEL_TYPE,x
bita #LEVEL_TYPE_DONT_SHOOT_WHILE_WAITING
bne noBulletSpawn\?
RANDOM_A
asla ; waiting has double chance to not initate bullet
cmpa levelBulletBorder
bls doBullet\?
bra noBulletSpawn\?
shotseeminglyOk\?
RANDOM_A
cmpa levelBulletBorder
bhi noBulletSpawn\?
doBullet\?
ldx ENEMY_STRUCT+u_offset1,s
lda ADDITIONAL_TYPE_INFO,x ;
anda #TYPE_DONT_SHOOT
bne noBulletSpawn\?
lda #$07 ; bullet delay for enemy = 15 rounds
ora BIT_MASK+u_offset1,s
sta BIT_MASK+u_offset1,s
ldd Y_POS +u_offset1,s
std bulletSpawnAt
ldb ENEMY_BULLET_SPEED,x
stb shotSpeed
noBulletSpawn\?
endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
END_ENEMY_DISPLAY macro
lda ALL_PURPOSE +u_offset1,s
beq normalEndMacro\?
cmpa #HIT_FLASH_LENGTH
bgt normalEndMacro2\?
inc lightningOn
dec ALL_PURPOSE +u_offset1,s
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
lda #$7f
MY_MOVE_TO_B_END
_INTENSITY_A
bra out\?
normalEndMacro\?
tst lightningOn
beq normalEndMacro2\?
clr lightningOn
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
lda #DEFAULT_ENEMY_INTENSITY
MY_MOVE_TO_B_END
_INTENSITY_A
bra out\?
normalEndMacro2\?
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
MY_MOVE_TO_A_END
out\?
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TEST_FOR_CLONE macro
lda ADDITIONAL_TYPE_INFO,u ;
anda #TYPE_CAN_CLONE
lbeq macroEnd\?
ldu currentLevelPointer
lda LEVEL_TYPE,u
cmpa #LEVEL_TYPE_BIGGY
beq macroEnd\?
lda enemyCount
cmpa #CLONE_MAX_ENEMY_DISPLAYED
bhi macroEnd\?
; start cloning
; basically spawn
; can't jsr here - cause we occupied the Stack register
ldu ENEMY_STRUCT+u_offset1,s
lda CLONE_INFO, u
anda #%00111111
sta tmp4_tmp ; delay between clones
sta tmp2_tmp
lda CLONE_INFO, u
lsra
lsra
lsra
lsra
lsra
lsra
inca
sta tmp1_tmp ; number of clones
anotherClone\?
ldu enemylist_empty_head
cmpu #OBJECT_LIST_COMPARE_ADDRESS
bls macroEnd\? ; set the new empty head
ldd NEXT_ENEMY_OBJECT,u ; the next in out empty list will be the new
std enemylist_empty_head ; head of our empty list
ldd enemylist_objects_head
std NEXT_ENEMY_OBJECT,u
stu enemylist_objects_head
inc enemyCount ; and remember that we created a new object
inc realEnemyCount
; copy this enemy
ldd Y_POS+u_offset1,s
std Y_POS,u
ldd Y_POS16+u_offset1,s
std Y_POS16,u
ldd X_POS16+u_offset1,s
std X_POS16,u
ldd SUB_PATTERN+u_offset1,s
std SUB_PATTERN,u
lda ANGLE_HOMEFLIGHT+u_offset1,s
sta ANGLE_HOMEFLIGHT,u
ldd MY_PATTERN+u_offset1,s
std MY_PATTERN,u
ldd PATTERN_POSITION+u_offset1,s
std PATTERN_POSITION,u
ldd ALL_PURPOSE+u_offset1,s
std ALL_PURPOSE,u
ldd ENEMY_STRUCT+u_offset1,s
std ENEMY_STRUCT,u
; clone delay
inc attackPatternCount ; correct attack pattern count -> clone is also attacking!
lda tmp2_tmp
sta ALL_PURPOSE,u ; delay between clones
adda tmp4_tmp ; is increased between each clone
sta tmp2_tmp
ldd BEHAVIOUR+u_offset1,s ; get the next behavoiur and store it "somewhere"
std PATTERN_POSITION,u ; pattern positions will allways be 0, position will be set to ff
; set clone behaviour
ldd #clonedBehaviour ; just waits - than starts exactly as clone
std BEHAVIOUR,u
dec tmp1_tmp
bne anotherClone\?
macroEnd\?
endm
;***************************************************************************
;
; in x correct pattern position in pattern list
; macro is always exited with a jump to some place else (outside macro)
; the pattern line x is pointing to is check for pattern
; a) relative pattern (+ subpatterns)
; b) absolut pattern
; c) relative pattern
; d) jump to other pattern
; e end of pattern list
LOAD_NEXT_PATTERN macro IS_CLONING
macroStart\?
lda SINGLE_ATTACK_PATTERN_TYPE,x
;SINGLE_ATTACK_RELATIVE_PATTERN = 0 ; relative means - it uses the current address of the enemy as start
;SINGLE_ATTACK_TARGET_ENEMY_PATTERN = 1 ; TARGET - uses somehow the players coordinate as coordinate info
;SINGLE_ATTACK_ABSOLUT_PATTERN = 2 ; moves from current position to an absolut screen position
;SINGLE_ATTACK_JUMP = 3
lbeq doRelativePattern\?
cmpa #SINGLE_ATTACK_TARGET_ENEMY_PATTERN
lbeq doTargetPattern\?
cmpa #SINGLE_ATTACK_ABSOLUT_PATTERN
beq doAbsolutPattern\?
; else jump
lda SINGLE_ATTACK_PATTERN_NEXT_NO,x
ldx SINGLE_ATTACK_PATTERN_POINTER,x
stx MY_PATTERN+u_offset1,s
sta PATTERN_POSITION+u_offset1,s ;
clr SUB_PATTERN_POSITION+u_offset1,s
bra macroStart\?
doAbsolutPattern\?
ldd #enemySingleAttackAbsolutBehaviour
std BEHAVIOUR+u_offset1,s
lda SINGLE_ATTACK_SPEED,x ; speed
sta ANGLE_HOMEFLIGHT+u_offset1,s
ldd 2,x ; second word in attack pattern are target coordinate
targetPatternCont\?
std TARGET_ABSOLUT_Y+u_offset1,s
; get delta of now and target
; divide coordinates by half for angle test
; otherwise we overflow 2 complements
asra
asrb
std _tmpY
ldd Y_POS+u_offset1,s
asra
asrb
nega
negb
adda _tmpY
addb _tmpX
; std _tmpY
; in tmp half of the delta value between target and current pos
; NEW: (angles now between 0-7, not 0 to 20)
; in d is delta
; if y < 0 than angle from 5 to 15
; if y > 0-5 and 15-20
; if x > 0 than angle between 0-10
; if x < 0 than angle between 10 -20
; if x == 0 angle = 5 or 15
; if y == 0 angle = 0 or 10
; if y abs == y abs than angle in the middle of ranges (2.5, 7.5, 12.5, 17.5)
tsta
bmi yIsNeg\?
tstb
bmi yIsPosxIsNeg\?
beq yIsPosxIsNull\?
yIsPosxIsPos\?
tsta
bne yNotNull1\?
lda #2
bra angleDone\?
yNotNull1\?
lda #1
bra angleDone\?
yIsPosxIsNull\?
lda #0
bra angleDone\?
yIsPosxIsNeg\?
tsta
bne yNotNull2\?
lda #6
bra angleDone\?
yNotNull2\?
lda #7
bra angleDone\?
yIsNeg\?
tstb
beq yIsNegxIsNull\?
bmi yIsNegxIsNeg\?
yIsNegxIsPos\?
lda #3
bra angleDone\?
yIsNegxIsNeg\?
lda #5
bra angleDone\?
yIsNegxIsNull\?
lda #4
bra angleDone\?
angleDone\?
; keep speed
lsla ; lower 3 bits are speed
lsla ; angle is 0 - 7 (must be doubled)
lsla
ldb ANGLE_HOMEFLIGHT+u_offset1,s
andb #%00000111
stb ANGLE_HOMEFLIGHT+u_offset1,s
ora ANGLE_HOMEFLIGHT+u_offset1,s
sta ANGLE_HOMEFLIGHT+u_offset1,s
if IS_CLONING = 1
TEST_FOR_CLONE
endif
jmp notThereYetPosition_ab ; jump out of macro
doTargetPattern\?
; same as absolut - but target is current fighter position
ldd #enemySingleAttackAbsolutBehaviour
std BEHAVIOUR+u_offset1,s
lda SINGLE_ATTACK_SPEED,x ; speed
sta ANGLE_HOMEFLIGHT+u_offset1,s
ldb playerXpos
lda #$80
jmp targetPatternCont\?
doRelativePattern\?
; that this is a relative pattern "SINGLE_ATTACK_RELATIVE_PATTERN"
; but checks must consider it may be otherwise!
ldd #enemySingleAttackRelativeBehaviour
std BEHAVIOUR+u_offset1,s
ldx 2,x ; second word in attack pattern is the first sub pattern
lbeq outOfPattern ; dw 0,0 = end of pattern, leave macro and enter delay!
stx SUB_PATTERN+u_offset1,s
; in x pointer to sub pattern
; Y_POS
; X_POS will be out target coordinates in this behaviour
; costs cylces - > but I don't have more RAM
; set 16 bit pos to same as 8 bit pos
; due to wobble this is not kept the same when in
; waiting position
clr RELATIVE_LO_Y+u_offset1,s
clr RELATIVE_LO_X+u_offset1,s
ldd P_YPOS,x
adda Y_POS+u_offset1,s
sta TARGET_RELATIVE_Y+u_offset1,s
addb X_POS+u_offset1,s
stb TARGET_RELATIVE_X+u_offset1,s
if IS_CLONING = 1
TEST_FOR_CLONE
endif
jmp thisPatternNotDone_srp ; jump into relative behaviour
endm
;***************************************************************************
;
; exactly the same as above except TEST_FOR_CLONE macro
; cloning is only initiated when waiting -> attack is done
LOAD_NEXT_PATTERN_START macro
LOAD_NEXT_PATTERN 1
endm
;***************************************************************************
; this is actually a JSR RTS
; without using stack
; PC-return address is kept in U
shotBehaviourStandardStart
COL_DETECT_PLAYER
shotBehaviourStandardStartNoBase
shotBehaviourStandardnoAdditional
; if no of enemies < threshold -> test all shots
if TEST_ALL_SHOTS = 1
ldb realEnemyCount ;enemyCount d
cmpb #ENEMY_THRESHOLD
lble testAllShots
endif
dontCheckAllAfterAll
ldb X_POS +u_offset1,s
COL_DETECT_2A
ldb X_POS +u_offset1,s
COL_DETECT_2B
shotBehaviourStandardTestShootingOnly
TEST_TO_SHOOT
shotBehaviourStandardStartNoCol
lda #OBJECT_SCALE
sta VIA_t1_cnt_lo
jmp ,u
if TEST_ALL_SHOTS = 1
testAllShots
lda playerNumberOfBulletsPerShot
cmpa #6 ; laser
lbeq dontCheckAllAfterAll
;; biggies col detection don't do well with
; normal eneies "all check"
; since test shot is often reset!
lda diverseFlags
anda #BIT_BIG_ENEMY_IN_PLAY
lbne dontCheckAllAfterAll
check for bugs
save testShots
restore testshots
ldd testShot
std laserEnemyPointerRight ; tmp location
COL_DETECT_ALL
; what happens if this shot was removed? and another enemy appears?
; test if testShot DID collision, than take "head"
; if empry do not init!
; nothing should go awry if ye just "clear them
;LASER?
ldd #0
std testShot
std test2Shot
; ldx laserEnemyPointerRight
; JUST_INIT_SHOT_TEST testShot
jmp shotBehaviourStandardTestShootingOnly
endif
;***************************************************************************
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; new list object to U
; destroys d, u
; ensures scoopiesa are always first
newEnemyObject ;#isfunction
ldu enemylist_empty_head
tryNextEO
cmpu #OBJECT_LIST_COMPARE_ADDRESS
bls cs_done_no
inc realEnemyCount
inc enemyCount ; and remember that we created a new object
; set the new empty head
ldd NEXT_ENEMY_OBJECT,u ; the next in out empty list will be the new
std enemylist_empty_head ; head of our empty list
; the old head is always our next
pshs y
ldy enemylist_objects_head
ldd BEHAVIOUR,y
cmpd #enemyPlayerControlledLeftBehaviour
bne noLefty
pshs x
ldx NEXT_ENEMY_OBJECT,y
ldd BEHAVIOUR,x
cmpd #enemyPlayerControlledRightBehaviour
beq leftyIsRight
stu NEXT_ENEMY_OBJECT,y
stx NEXT_ENEMY_OBJECT,u
puls x,y,pc
leftyIsRight
ldy NEXT_ENEMY_OBJECT,x
stu NEXT_ENEMY_OBJECT,x ; diffi
sty NEXT_ENEMY_OBJECT,u
puls x,y,pc
noLefty
cmpd #enemyPlayerControlledRightBehaviour
bne noRighty
pshs x
ldx NEXT_ENEMY_OBJECT,y
ldd BEHAVIOUR,x
cmpd #enemyPlayerControlledLeftBehaviour
beq leftyIsRight
stu NEXT_ENEMY_OBJECT,y
stx NEXT_ENEMY_OBJECT,u
puls x,y,pc
noRighty
sty NEXT_ENEMY_OBJECT,u
; newobject is always head
stu enemylist_objects_head
puls y,pc
cs_done_no
rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; leaves with Z flag
; BEQ no spawn
; BNE spawn Ok
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
spawnEnemy ; #isfunction
bsr newEnemyObject ; "create" (or rather get) new object
cmpu #OBJECT_LIST_COMPARE_ADDRESS
bls spawnEnemy_end
ldd #enemySimpleBehaviour
std BEHAVIOUR,u
rts
spawnEnemy_end
ldu #0
rts
;
;
; this macro is placed at the end of each possible "remove" exit
; it stores the just removed object at the head of the "empty" list and
; sets up its "next" pointer
UPDATE_EMPTY_ENEMYLIST macro
dec enemyCount
dec realEnemyCount
ldy enemylist_empty_head ; set u free, as new free head
sty NEXT_ENEMY_OBJECT,x ; load to u the next linked list element
stx enemylist_empty_head
endm
;
destroyEnemyObject ;#isfunction
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; in ds+u_offset1 pointer to the object that must be removed
; destroys x, y
; puls from ds the next object behaviour
;
; this version is called at the end of an explosion called by "behaviours"
;
leax u_offset1,s ; x -> pointer object struture (correction of offset)
cmpx enemylist_objects_head ; is it the first?
bne was_not_first_enem ; no -> jump
was_first_enem
lds NEXT_ENEMY_OBJECT,x ; s pointer to next objext
sts enemylist_objects_head ; the next object will be the first
bra enemyRemoveDone
was_not_first_enem ; find previous, go thru all objects from first and look where "I" am the next...
ldy enemylist_objects_head ; start at list head
try_next_enem
cmpx NEXT_ENEMY_OBJECT,y ; am I the next object of the current investigated list element
beq found_next_switch_enem ; jup -> jump
ldy NEXT_ENEMY_OBJECT,y ; otherwise load the next as new current
bra try_next_enem ; and search further
found_next_switch_enem
lds NEXT_ENEMY_OBJECT,x ; we load "our" next object to s
sts NEXT_ENEMY_OBJECT,y ; and store our next in the place of our previous next and thus eleminate ourselfs
enemyRemoveDone
UPDATE_EMPTY_ENEMYLIST ; and clean up the empties
; do a clean ending - which is usually done at the end of "SmartDraw"
ldb gameScale
LDa #$CC
STA VIA_cntl ;/BLANK low and /ZERO low
stB VIA_t1_cnt_lo
clra
sta <VIA_port_a
sta <VIA_port_b
MY_MOVE_TO_A_END
puls d,pc ; (D = y,x, X = vectorlist)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
enemyExplosionBehaviour ;#isfunction
MY_MOVE_TO_D_START
explosionBevaiourEntryFromShotTest
ldu SMARTLIST_ORG +u_offset1,s
lda EXPLOSION_SCALE+u_offset1,s
adda #2
cmpa #EXPLOSION_MAX_SCALE
bhs destroyEnemyObject
sta EXPLOSION_SCALE +u_offset1,s
sta VIA_t1_cnt_lo
lda EXPLOSION_INTENSITY +u_offset1,s
suba #10
sta EXPLOSION_INTENSITY +u_offset1,s
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
inc lightningOn
MY_MOVE_TO_B_END
_INTENSITY_A
clra
pulu b,x,pc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; not used
; just statically displays an enemy on it position
enemySimpleBehaviour
enemySingleAttackAbsolutBehaviour ;#isfunction
MY_MOVE_TO_D_START
ldu #back1Shot
jmp shotBehaviourStandardStart
back1Shot
ldd TARGET_ABSOLUT_Y+u_offset1,s ; target y, x position in d
; target y position is always smaller since we start at the top of the screen
cmpa Y_POS+u_offset1,s
beq yIsCorrectPosition_ab
bgt increaseYPos
; load speed
ldb ANGLE_HOMEFLIGHT+u_offset1,s
andb #%00000111
decAgain1
cmpa Y_POS+u_offset1,s ; double check postions because of speed > 1
beq yIsCorrectPosition_ab ; otherwise a BEQmight miss the target
dec Y_POS+u_offset1,s
decb
bne decAgain1
bra yDoneB_ab
increaseYPos
ldb ANGLE_HOMEFLIGHT+u_offset1,s
andb #%00000111
; load speed
incAgain1_a
cmpa Y_POS+u_offset1,s ; double check postions because of speed > 1
beq yIsCorrectPosition_ab
inc Y_POS+u_offset1,s
decb
bne incAgain1_a
bra yDoneB_ab
yIsCorrectPosition_ab
; change angle
; if x finish is positive
; angle = 4 look right
; if x finish is negative
; angle = 12 look left
; XPOS is current position
; XPOS16 is from position
; ldd loaded above is target position
ldb 1+TARGET_ABSOLUT_Y+u_offset1,s ; target y, x position in d
cmpb X_POS+u_offset1,s
blt targetXisNegativeAngle_ab
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
ora #2*2*2*2 ; heading at 3 o'clock
sta ANGLE_HOMEFLIGHT+u_offset1,s
bra yDoneB_ab
targetXisNegativeAngle_ab
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
ora #6*2*2*2
sta ANGLE_HOMEFLIGHT+u_offset1,s
yDoneB_ab
ldd TARGET_ABSOLUT_Y+u_offset1,s ; target y, x position in d
cmpb X_POS+u_offset1,s
bne xNotIsCorrectPosition_ab
; x is correct so
; change angle to point either 12 o'clor or 6 o'clock
cmpa Y_POS+u_offset1,s ; y pos
blt yposIsLowerDoAngle10
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
sta ANGLE_HOMEFLIGHT+u_offset1,s
bra xIsCorrectPosition_ab
yposIsLowerDoAngle10
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
ora #4*2*2*2
sta ANGLE_HOMEFLIGHT+u_offset1,s
bra xIsCorrectPosition_ab
xNotIsCorrectPosition_ab
blt targetXisNegative_ab
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
incAgain2_a
cmpb X_POS+u_offset1,s ; double check postions because of speed > 1
beq xIsCorrectPosition_ab
inc X_POS+u_offset1,s
deca
bne incAgain2_a
bra xIsCorrectPosition_ab
targetXisNegative_ab
lda ANGLE_HOMEFLIGHT+u_offset1,s
anda #%00000111
decAgain2
cmpb X_POS+u_offset1,s ; double check postions because of speed > 1
beq xIsCorrectPosition_ab
dec X_POS+u_offset1,s
deca
bne decAgain2
xIsCorrectPosition_ab
ldd TARGET_ABSOLUT_Y+u_offset1,s ; reload
cmpd Y_POS+u_offset1,s
lbne notThereYetPosition_ab
; we have reached target position
; switch to waiting behaviour
sta Y_POS16+u_offset1,s
stb X_POS16+u_offset1,s
clr Y_POS16+1+u_offset1,s
clr X_POS16+1+u_offset1,s
; load next pattern if available
ldx MY_PATTERN+u_offset1,s
lda PATTERN_POSITION+u_offset1,s ; uper nibble of same byte as
adda #$10 ; add 1 to upper nibble
anda #$f0 ; this clears the sub pattern position in lower nibble
sta PATTERN_POSITION+u_offset1,s ; uper nibble of same byte as
lsra
lsra
anda #0xfc
; in a 4 times the pattern pos of upper nibble
leax a,x
; in x correct pattern position in pattern list
; absolut patterns do not have sub pattern, so look directly if there is
; a next pattern
LOAD_NEXT_PATTERN 0
ldd #enemyWaitingBehaviour
std BEHAVIOUR+u_offset1,s
clr ANIM_POSITION+u_offset1,s
notThereYetPosition_ab
ldu ENEMY_STRUCT+u_offset1,s
ldu ANGLE8_TABLE,u
lda ANGLE_HOMEFLIGHT+u_offset1,s
lsra
lsra
anda #%00111110 ; only upper 5 bits and doubled!
ldu a,u
END_ENEMY_DISPLAY
clra
pulu b,x,pc
; exit current (single) pattern handling and init a standard delay behaviour
outOfPattern
; restore defaults
clr ANIM_POSITION+u_offset1,s
lda #DELAY_TO_REAPEAR
sta ALL_PURPOSE+u_offset1,s
ldd #enemyDelayBehaviour ; delay some time after pattern before they reermage at thetop of the screen
std BEHAVIOUR+u_offset1,s
dec attackPatternCount
jmp endAttackBehaviourDirectly
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
; MUST not be resused
; only to be called from WAITING BEHAVIOUR!
CHECK_START_ATTACK_PATTERN macro
if NO_ATTACK_PATTERN = 1
jmp notAgain\?
endif
tst attackPatternInitiated ; allow only one init of attack pattern per round
lbne notAgain\?
lda attackPatternCount
ldx currentLevelPointer
cmpa levelMaxAttackPatterns
lbhs notAgain\?
ldu ENEMY_STRUCT+u_offset1,s
lda ADDITIONAL_TYPE_INFO,u ; blocker do not attack
anda #TYPE_DONT_ATTACK
lbne notAgain\?
RANDOM_A
cmpa #ATTACK_PATTERN_PROBABILITY
lbhi notAgain\?
inc attackPatternInitiated
inc attackPatternCount
ldx LEVEL_ATTACK_PATTERN,x ; in x a pointer to 4 possible attack patterns
RANDOM_A2
anda #%00000011
ldb difficulty
andb #$f ;
beq easy2\?
decb
beq difCont2\?
decb
beq hard2\?
impossible2\?
adda #2
cmpa #4
blo difCont2\?
lda #3
bra difCont2\?
easy2\?
lsra
bra difCont2\?
hard2\?
adda #1
cmpa #4
blo difCont2\?
lda #3
difCont2\?
asla
ldx a,x ; random attack pattern in x now (1 of four for this level!
; ok - now start an attack
; for now only "single" attacks
; for now only one attack pattern
stx MY_PATTERN+u_offset1,s
clr PATTERN_POSITION+u_offset1,s
clr SUB_PATTERN_POSITION+u_offset1,s
;
; pattern with correct pattern pos in X
LOAD_NEXT_PATTERN_START
notAgain\?
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
clonedBehaviour ;#isfunction
dec ALL_PURPOSE+u_offset1,s
bne cloneDelayDone
; init clone "living"
ldd PATTERN_POSITION+u_offset1,s
std BEHAVIOUR+u_offset1,s
clr PATTERN_POSITION+u_offset1,s
lda #$ff ; a "non" position (will not goto waiting)
sta POSITION+u_offset1,s
cloneDelayDone
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
puls d,pc ; (D = y,x, pc = next object)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; relative means - the enemie has a behaviour where it moves relative to its start position
; 10 to the left- or so
enemySingleAttackRelativeBehaviour ;#isfunction
MY_MOVE_TO_D_START
ldu #back2Shot
jmp shotBehaviourStandardStart
back2Shot
; move in pattern
ldx SUB_PATTERN+u_offset1,s
lda SUB_PATTERN_POSITION+u_offset1,s
anda #$0f ; only lower nibble
asla ; stupid - if it were in the upper nibble one asra would suffice!
asla
asla ; times 8
leax a,x ; position of y add in pattern
lda RELATIVE_HI_Y+u_offset1,s
ldb RELATIVE_LO_Y+u_offset1,s
addd P_YADD,x
sta RELATIVE_HI_Y+u_offset1,s
stb RELATIVE_LO_Y+u_offset1,s
lda RELATIVE_HI_X+u_offset1,s
ldb RELATIVE_LO_X+u_offset1,s
addd P_XADD,x
sta RELATIVE_HI_X+u_offset1,s
stb RELATIVE_LO_X+u_offset1,s
; check if next pattern position reached (near point to PATTERN_TARGET_REACHED_RADIUS)
suba TARGET_RELATIVE_X+u_offset1,s
bpl noNeg1_srp
nega
noNeg1_srp
cmpa P_PATTERN_TARGET_RADIUS,X
lbgt thisPatternNotDone_srp
lda RELATIVE_HI_Y+u_offset1,s
suba TARGET_RELATIVE_Y+u_offset1,s
bpl noNeg2_srp
nega
noNeg2_srp
cmpa P_PATTERN_TARGET_RADIUS,X
lbgt thisPatternNotDone_srp
; initiate next relative subpattern (if avialble)
; in D current on screen position, which is base of next pattern
; unify positions, on multi pattern errors otherwise add up
clrb
lda RELATIVE_HI_Y+u_offset1,s
std Y_POS16+u_offset1,s
lda RELATIVE_HI_X+u_offset1,s
std X_POS16+u_offset1,s
; check if this was last pattern of this sub pattern
lda P_YADD+1+PatternLine,x
lbne thereIsANextPattern_srp
lda P_XADD+1+PatternLine,x
lbne thereIsANextPattern_srp
; here finish the subpattern and do next pattern (if available)
; load next pattern if available
ldx MY_PATTERN+u_offset1,s
lda PATTERN_POSITION+u_offset1,s ; uper nibble of same byte as
adda #$10 ; add 1 to upper nibble
anda #$f0 ; this clears the sub pattern position in lower nibble
sta PATTERN_POSITION+u_offset1,s ; uper nibble of same byte as
lsra
lsra
anda #0xfc
; in a 4 times the pattern pos of upper nibble
leax a,x
; in x correct pattern position in pattern list
LOAD_NEXT_PATTERN 0
thereIsANextPattern_srp
; ASSERT: upper nibble must never be reached by an INC!
inc SUB_PATTERN_POSITION+u_offset1,s ; here init next pattern in list
; get next sub pattern to calculate the next relative address
ldx SUB_PATTERN+u_offset1,s
lda SUB_PATTERN_POSITION+u_offset1,s
anda #$0f ; only lower nibble
asla
asla
asla ; times 8
leax a,x
; add realtive target
nextRelativeTargerAdd
ldd P_YPOS,x ;
adda Y_POS+u_offset1,s
sta TARGET_RELATIVE_Y+u_offset1,s
addb X_POS+u_offset1,s
stb TARGET_RELATIVE_X+u_offset1,s
clr RELATIVE_LO_Y+u_offset1,s
clr RELATIVE_LO_X+u_offset1,s
goOnEnemyPatternBehaviour_srp
thisPatternNotDone_srp
ldu ENEMY_STRUCT+u_offset1,s
ldu ANGLE8_TABLE,u
lda P_ANGLE,x
ldu a,u
END_ENEMY_DISPLAY
clra
pulu b,x,pc
endAttackBehaviourDirectly
lds NEXT_ENEMY_OBJECT+u_offset1,s ; preload next user stack
ldb gameScale