Jump to content

Game Duenix for Amiga computers

From Wikiversity

What follows is the source code for the Duenix game by Dan Polansky for Amiga line of computer originally developed in 1994-1998 in the AMOS BASIC language. One of the purposes is to act as an example of use of that language for those who want to learn the language or get an idea of its syntactic face and its facilities; no other such example currently exists in Wikiversity. The syntax is reminiscent of Visual Basic.

The source code package below should be complete now: it consists of the main AMOS file and three Motorola 68000 assembly source code files for the portions for which AMOS was too slow. However, the full game can be compiled and run only with the use of all supporting files, including image, sound and music module files.

Among the assembly files, the most interesting one is the one for Duenix strategy for computer-driven players/worms. One can use it to train understanding of the assembly. Since it merely complements the main AMOS program, it is reasonably short and therefore suitable for learning. One can start learning by picking only some of the supporting routines and trying to understand them. The assembly source code ends with a quick 68000 assembly guide to serve as a quick reference.

The game was inspired by (but has more features than) Amiga Game Wikipedia: Achtung, die Kurve!, whose full title seems to be "Dune 3 – Achtung! Die Kurve"[1]. Dune 3 was inspired by game Cervii[2] ("Worms"). The name Duenix is based on the name Dune.

Duenix.AMOS

[edit | edit source]
Set Buffer 20
Erase All 
Set Sprite Buffer 256
Trap Screen Close 0

VERSION$="$VER: Duenix 1.2 (17.10.98)"
YEAR$="1994-1998"
RELEASE$="Release 1.2"
MEMORY_REQUIREMENT=800000-170000

If Prg State=-1 : Break Off : PATH$=Dir$ : Else : If Exist("ram:editamos.lock") : Kill "ram:editamos.lock" : Edit : End If 
   PATH$="Work:Programming/Duenix/Dx/"
End If 

Dim _NOT(1)
Dim X#(6),Y#(6),SMER(6),NEW_X#(6),NEW_Y#(6),NEW_SMER(6),NEW_PLAYER(6),SCORE(6),SELECTED(6),SEMIALIVE(6),SPACE_COUNTER(6),LINE_COUNTER(6),SPEED(6),SPEED_PERCENT#(6),TURNING(6),LIVES(6),_TOP_LIVES(6),AUCH_COUNTER(6),AUCH_PROTECTION(6)
Dim _PLAYER_RECORD(5),_FREE_VALUE(6),LIVING_PLAYER(6),COMPUTER_STRATEGY(6),CYBORG(6),PLAN_BANK(2),_NEXT_SOUND_FX_CHANNEL(8),WRITE_KOI82IMAGE($),WRITE_KOI82HOOK($),ZOMBIE(6),LINE_LENGTH_(6),SPACE_LENGTH_(6),ALIVE(6)
Dim BOUND_THIS_ROUND(6),BOUND_COUNTER(6),REDRAW_PLAYER(6),ACCEPT_KEYSTROKE(6),_KEYSTROKE_COUNTER(6),SPEED_SOURCE#($F),WIND_FACTOR#(6),UPP($),SPP($),TEAM_MATE_THRU(6),TEAM_MATE(6),DEMOSTORE_PLAYSTATE(6),PL_RGB(6),_PLAYER_PROPRIETY(2,3)
Dim STAYED_ALIVE_BONUS(6),_PLAYER_TYPE(6),_PLAYER_TYPE_IMAGE(3),STANDARD_PLAN_PAL$(5),GS_GAME_NAME$(20,1),_PUTPIX_QUEUE_X(12-1),_PUTPIX_QUEUE_Y(12-1),_PUTPIX_QUEUE_COLOUR(12-1)

Dim NO_IMAGE(2),YES_IMAGE(2),RED_BOX_IMAGE(2),_BOB_PLAYER_IMAGE(1,1),_SPRITE_NUMBER(6),_SPRITE_IMAGE(6),_PLAYER_GREY_COLOUR(6),PL_DEF_COLOR(6),P_COLOR(6),PL_DEF_COLOR_LIGHT(6),PL_DEF_COLOR_DARK(6),OS_LC_BOX(14),OS_RC_BOX(14)
Dim OS_LEFT_COLUMN_TEXT$(14,1),OS_RIGHT_COLUMN_TEXT$(14,1),MAIN_OPTION_TEXT$(4),SELECTING_UPPER_TEXT$(5),SELECTING_LOWER_TEXT$(5),RR_COLUMN_TEXT$(2),CREATE_USER_GS_EXPLANATION$(13),_NOT_ALL_FILES$(2),GAMEPLAN_EXPLANATION$(2),GAMEPLAN_KEY_TEXT$(2)

MAIN

Procedure SET_CONSTANTS
   _TRUE=1 : _FALSE=0 : _NOT(_TRUE)=_FALSE : _NOT(_FALSE)=_TRUE : _T=1 : _F=0

   _ERROR_BADPATH=250
   
   EN$=Chr$($D)+Chr$($A)
   CZ_SEND$="Ahoj.\  Tato hra je Freeware. PŇesto, pokud se ti lÉbÉ,\pĹknĹ prosÉm, poÓli 10 KĂ na adresu:\"
   EN_SEND$="Hello.\  This game is Freeware, but  if you like the game,\pretty please, send twice the price of post stamp to:"
   EN_VALUE$="Note that even one dollar is a big piece of money \for me."
   
   RECORDNAME$="Duenix_GameRecord"
   CONFIG_LENGTH=$80
   
   DEMO_TIMER_LIMIT=50*18
   DEMO_PRESS_SPACE_LIMIT=50*3
   'Pul minuty
   
   V=26-1
   Inc V : PRECOUNTED_SIN__BANK=V
   Inc V : PRECOUNTED_ATAN__BANK=V
   Inc V : DEF_GAMESET__BANK=V
   Inc V : USER_GAMESET__BANK=V
   
   CONFIG_TEMPORARY__BANK=31
   LIFE_MOTION_MUSIC__BANK=15
   WINNER_MUSIC__BANK=16
   
   For I=0 To 2 : PLAN_BANK(I)=8+I : Next I
   
   V=0-1
   Inc V : BOUND_SOUND=V
   Inc V : TELEPORT_SOUND=V
   Inc V : DEATH_SOUND=V
   Inc V : ARROW_SOUND=V
   Inc V : PRESS_SPACE_SOUND=V
   Inc V : AUCH_SOUND=V
   Inc V : BODY_CHANGE_SOUND=V
   
   V=14-1
   Inc V : DUENIX_TITLE_IMAGE=V
   Inc V : DUENIX_ANIM_IMAGE=V
   Inc V : MOUSE_ON_LINE_IMAGE=V
   Inc V : _JOY_ON_LINE_IMAGE=V
   
   Restore CONSTANTS
   
   '          .----------------.
   '          |   Box System   |
   '          `----------------'
   
   Read BS_LEFT_TOP,BS_MIDDLE_TOP,BS_RIGHT_TOP
   Read BS_LEFT_MIDDLE,BS_MIDDLE_MIDDLE,BS_RIGHT_MIDDLE
   Read BS_LEFT_BOTTOM,BS_MIDDLE_BOTTOM,BS_RIGHT_BOTTOM
   
   For I=0 To 3 : Read _PLAYER_TYPE_IMAGE(I) : Next I
   
   For PROP=0 To 2
      For TYPE=0 To 3
         Read _PLAYER_PROPRIETY(PROP,TYPE)
      Next TYPE
   Next PROP
   
   For I=0 To 5
      Read STANDARD_PLAN_PAL$(I)
   Next I
   
   For I=0 To 2 : Read NO_IMAGE(I),YES_IMAGE(I),RED_BOX_IMAGE(I) : Next 
   Read LATERAL_LEFT,LATERAL_RIGHT
   Read HORIZONTAL_WOOD_IMAGE,CORNER_WOOD_IMAGE
   Read VERTICAL_WOOD_IMAGE,NOSCROLL_CORNER_IMAGE
   Read SCORE_PANEL_BACKGROUND_IMAGE
   Read _BOB_PLAYER_IMAGE(0,0),_BOB_PLAYER_IMAGE(1,0)
   Read _BOB_PLAYER_IMAGE(0,1),_BOB_PLAYER_IMAGE(1,1)
   Read LIFE_BOX_IMAGE,PRESS_SPACE_IMAGE
   Read _FREE_FOR_MANIPULATION_IMAGE
   
   For I=1 To 14 : OS_LC_BOX(I)=Rnd(2) : OS_RC_BOX(I)=Rnd(2) : Next 
   
   For I=1 To 6 : Read _SPRITE_NUMBER(I) : Next 
   For I=1 To 6 : Read _SPRITE_IMAGE(I) : Next 
   For I=1 To 6 : Read _PLAYER_GREY_COLOUR(I) : Next 
   For I=1 To 6 : Read PL_DEF_COLOR(I) : Next 
   For I=1 To 6 : Read PL_DEF_COLOR_LIGHT(I) : Next 
   For I=1 To 6 : Read PL_DEF_COLOR_DARK(I) : Next 
   
   _ADDRESS$=""
   For I=1 To 59
      Read A : A=127-(A and $7F)
      _ADDRESS$=_ADDRESS$+Chr$(A)
   Next 
   
   For I=1 To 8
      Read _NEXT_SOUND_FX_CHANNEL(I)
   Next I
   
   '             ############################################ 
   '             ############################################ 
   '             ############################################ 
   
   CONSTANTS:
   Data 23,24,25,26,27,28,29,30,31
   
   Data 12,13,32,47
   
   Data 0,-1,-1,-1,0,0,-1,0,0,0,0,-1
   
   Data "000100200310410520620730830930A30B30C30D30E30F30"
   Data "000010110120220230330340440450550560660670770880"
   Data "000100200301401511612712812913A23B23C24D24E34F35"
   Data "00000110210320420530640740850950A60B60C70D80E80F"
   Data "000100200410510720820A30B30B41A53A64975876887888"
   Data "000010020130140250360470770870980996AA9BBACCBDDC"
   
   Data 20,21,22,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67
   
   Data 0,1,4,6,2,3
   Data 1,2,3,4,1,2
   
   Data $555,$666,$444,$555,$444,$555
   Data $BB9,$D4,$F6E,$FD0,$98F,$DC
   Data $BB9,$D4,$F6E,$FD0,$98F,$DC
   Data $997,$B2,$D4C,$DB0,$76D,$BA
   
   Data 15547871,851935,717919,14521183,15184699,15895454,4796305,14405910,1778714,1785619
   Data 3568095,16049967,16590608,8523667,9276702,6056593,1776908,14231444,1650054,16523762
   Data 8584949,5226207,1411039,12670559,2261855,5154089,11158032,5056525,6662934,11519244
   Data 666900,1713424,13908489,6241310,9845471,10016972,8328520,1943410,12217717,13195487
   Data 15031647,8158431,7539679,14262205,3611437,1997745,9762352,9414386,338933,16412511
   Data 3954015,4265823,6466015,11781321,7741645,5544140,790367,10503503,12815311
   
   Data 2,8,0,1,0,0,0,4
   
End Proc
Procedure SET_TEXT_CONSTANTS
   On Error Proc HANDLE_ERROR
   
   _NOT_ALL_FILES$(0)="You miss Texts file!"
   _NOT_ALL_FILES$(1)="... not to talk about the other files."
   _NOT_ALL_FILES$(2)="Try to get complete version of Duenix."
   
   Set Input 10,-1
   Open In 1,LOCALE_PATH$+"Texts"
   
   Line Input #1,_LOADING$
   For I=0 To 5 : Line Input #1,SELECTING_UPPER_TEXT$(I) : Next 
   For I=0 To 5 : Line Input #1,SELECTING_LOWER_TEXT$(I) : Next 
   
   Line Input #1,PAGE_ONE$,MAIN_OPTION_LOADING_AND_SAVING$
   Line Input #1,MAIN_OPTION_E_TEXT$,MAIN_OPTION_G_TEXT$,MAIN_OPTION_R_TEXT$,MAIN_OPTION_U_TEXT$
   Line Input #1,CONFIGURATION$
   For I=0 To 3 : Line Input #1,MAIN_OPTION_TEXT$(I) : Next 
   Line Input #1,_PRESS_SPACE_OR_ESCAPE$,ESCAPE_ACCEPT$
   
   Line Input #1,PAGE_TWO$,GAME_SETTINGS$
   For PAGE=0 To 1
      For I=1 To 14 : Line Input #1,OS_LEFT_COLUMN_TEXT$(I,PAGE) : Next 
      For I=1 To 14 : Line Input #1,OS_RIGHT_COLUMN_TEXT$(I,PAGE) : Next 
   Next PAGE
   
   Line Input #1,PAGE_THREE$,GAMEPLAN$,THIS_IS_DEFPLAN$
   Line Input #1,THIS_IS_STANDARD_GAMEPLAN_NUMBER$
   Line Input #1,HERE_MAY_BE_YOUR_PLAN$,HERE_IS_YOUR_PLAN$,GAMEPLAN_L_TEXT$
   Line Input #1,ENTER_NAME_OFF_IFF_TO_LOAD$
   For I=0 To 2 : Line Input #1,GAMEPLAN_KEY_TEXT$(I) : Next 
   For I=0 To 2 : Line Input #1,GAMEPLAN_EXPLANATION$(I) : Next 
   
   Line Input #1,PAGE_FOUR$,RECORD_AND_REPLAY$,RECORD_AND_REPLAY_SPACE$
   For I=0 To 2 : Line Input #1,RR_COLUMN_TEXT$(I) : Next 
   For I=0 To 13 : Line Input #1,CREATE_USER_GS_EXPLANATION$(I) : Next 
   
   Line Input #1,PAGE_FIVE$,CREATING_USER_GAMESET$,CREATE_USER_GAMESET$
   Line Input #1,SORRY$
   Line Input #1,_MINIMUM_OF_DIRECTIONS$,_MAXIMUM_OF_DIRECTIONS$
   
   Line Input #1,INSERT_VOLUME$
   For I=0 To 2 : Line Input #1,_NOT_ALL_FILES$(I) : Next 
   Line Input #1,_NOT_FONT$
   Line Input #1,OPERATION_ABORTED$,DUENIX_CONFIG_ISNT_CONFIG$,DEF_CONFIG_LOADED$
   Line Input #1,CANT_FIND_DEF_CONFIG1$,CANT_FIND_DEF_CONFIG2$
   Line Input #1,CONFIG_SAVED_AS_DEF1$,CONFIG_SAVED_AS_DEF2$,ENTER_CONFIGNAME$
   Line Input #1,THIS_FILE_ISNT_CONFIG$,CONFIG_LOADED$,FILE_DOESNT_EXIST$
   Line Input #1,ENTER_NAME_OF_CONFIG_TO_SAVE$,CONFIG_SAVED$,CONFIG_NOT_SAVED$
   Line Input #1,THIS_FILE_ALREADY_EXISTS$,WANT_TO_OVERWRITE$
   Line Input #1,_ORIGINAL_CONFIG_LOADED$,ENTER_NAME_OF_CONFIG_LIST_FILE$
   
   Line Input #1,NONE_OF_FILES_WAS_CONFIG1$,NONE_OF_FILES_WAS_CONFIG2$,YOUR_NEW_GAMESET_IS_SAVED$
   Line Input #1,MORE_THAN_20_FILES1$,MORE_THAN_20_FILES2$,NAME_OF_EMPTY_GAME_IN_GAMESET$
   Line Input #1,YOU_HAVENT_RECORDED1$,YOU_HAVENT_RECORDED2$,YOU_HAVENT_RECORDED3$
   Line Input #1,YOU_HAVENT_SAVED_GAME1$,YOU_HAVENT_SAVED_GAME2$,YOU_HAVENT_SAVED_GAME3$
   Line Input #1,_MAXIMUM_OF_WATER_ANGLE$
   
   Line Input #1,PRESS_U_TO_SELECT_USER_GAME$,SELECT_GAME$
   Line Input #1,SELECT_GAME_FROM_USERSET$,NO_GAMERECORD_SAVED$
   Line Input #1,THE_WINNER$,THE_LOSER1$,THE_LOSER2$,THE_LOSERS$
   Close 1
End Proc
Procedure SET_SCANCODE_CONSTANTS
   Restore _SCANCODE_DATA
   
   Read A_SCANCODE,B_SCANCODE,C_SCANCODE,D_SCANCODE,E_SCANCODE,F_SCANCODE
   Read G_SCANCODE,H_SCANCODE,I_SCANCODE,J_SCANCODE,K_SCANCODE,L_SCANCODE
   Read M_SCANCODE,N_SCANCODE,O_SCANCODE,P_SCANCODE,Q_SCANCODE,R_SCANCODE
   Read S_SCANCODE,T_SCANCODE,U_SCANCODE,V_SCANCODE,W_SCANCODE,X_SCANCODE
   Read Y_SCANCODE,Z_SCANCODE
   Read ESC_SCANCODE,ENTER_SCANCODE,SPACE_SCANCODE
   
   _SCANCODE_DATA:
   Data 32,53,51,34,18,35,36,37,23,38,39,40,55,54,24,25,16,19,33,20,22,52,17,50,21,49,69,68,64
   
End Proc
Procedure COMMENTS__NOT_REALLY_PROC
   'UPP = UserPlanPalette ;; SPP = StandardPlanPalette  
   
   '========== Banky ===========
   
   ' 1  .. Sprite   Classic   
   ' 2  .. Icon     Font  
   ' 3  .. Music    Duning
   ' 4  .. Icon     Digits    
   ' 5  .. Samples  Classic 
   ' 7  .. Work     Config
   ' 8  .. Pic      Default Plan
   ' 9  .. Pic      Standard Plan 
   ' 10 .. Pic      Own Plan
   ' 12 .. Pic      Beau Frame
   ' 15 .. Track    Life Motion 
   ' 16 .. Track    Winner music
   ' 20 .. Ass      PutPix    
   ' 21 .. Pic      SQLogo             ONLY WHEN LOADING
   ' 22 .. Track    SQSound            ONLY WHEN LOADING
   ' 23 .. Sprite   FlagAnimation 
   ' 24 .. Ass      RecordAndReplay 
   ' 25 .. Ass      Strategy           & sin+cos picking
   ' 26 .. Work     Precounted sin, sixe 250*4=1000 
   ' 27 .. Work     Precounted arctan, angle in smeru units 
   ' 28 .. Work     DEF_GAMESET   
   ' 29 .. Work     USER_GAMESET  
   ' 30 .. Work     GameRecordBank
   ' 31 .. Work     Help Config Bank
   
   
   '========= Game Record ======
   
   ' 0   ..  (24) SMERU 
   ' 24  ..  (24) XPositions
   ' 48  ..  (24) YPositions  
   ' 72  ..  (6)  Player on/off 
   ' 78  ..  Playing Config - Dark GamePlan & Turbo 
   ' $AE  ..      This might be record, but it isnt nice size   
   ' $B0  ..  Game configuration
   ' $130 ..  Own Record
   
   
   '========= Options ==========  
   
   ' Smeru=pocet moznych smeru
   ' angle_constant#..z toho pocitana konstanta 
   ' line_length..delka cary nez prijde mezera (vcetne predchozi mezery)
   ' space_length..delka mezery 
   ' speedjump#..procentualni skok rychlosti na kopcich 
   ' rate..rychlost..50-150 
   ' ratemode..0-nezrychlovat rate, 1-zrychlit z 1 na 0 (rate musi byt 2) 
   ' user_rate_length..pocet kol, kdy nezrychlime 
   ' space_kill..1-v mezere se zabiji,0-nezabiji  
   ' bouncing..0-neodrazi,1-odrazi (od okraje)
   ' central_box..0-neni,1-je central_boxalni box 
   ' central_box_size..radius 
   ' teleporting..vyjizdeni na druhe strane 
   ' _music_on-hudba
   ' boldline 1-tlusta,0-tenka
   '
   ' plan..0-default,1-standard,2-own 
   '
   '=========== Config =================
   ' Bank 7 
   ' Offsets: 
   ' 0-flags
   '     1-ratemode   
   '     2-_music_on  
   '     4-space_kill     
   '     8-bouncing   
   '    10-center   
   '    20-teleporting    
   '    40-boldline 
   '    80-turbo (turbolimit) 
   '
   ' 1-Directions 
   ' 2-Speedjump
   ' 3-Spacelen 
   ' 5-line_length
   ' 7-Speeding lenght  
   ' 9-Cbox radius
   ' A-Speed  
   ' B-flags2 
   '     1-watering 
   '     2-always_turning 
   '     3-grey gameplan
   ' C-Water_limit  
   '
   ' D-1F free for future   
   '
   
End Proc

Procedure DUENIX_REQUEST
   If Not Exist(PATH$)
      Screen Open 3,320,8,2,Lowres
      Flash Off : Curs Off : Hide On 
      Screen Display 3,,170,320,8
      Paper 0 : Pen 1
      Palette 0,0
      Cls 0
      Locate 0,0
      Centre INSERT_VOLUME$+PATH$
      Fade 2,0,$FF0
      Wait 30
      Repeat 
      Until Exist(PATH$)
      Fade 2,0,0
      Wait 30
      Screen Close 3
   End If 
End Proc
Procedure HANDLE_ERROR
   E=Errn
   Screen Open 3,640,256,2,Hires : Curs Off 
   Cls 0 : Paper 0 : Pen 1 : Locate 0,10
   If E=_ERROR_BADPATH
      Centre "Bad path." : Print : Print 
      Centre "I guess you have run me from CLI." : Print 
      Centre "In that case you must run me from directory" : Print 
      Centre "where I am located." : Print : Print 
      Centre "You may of course run me from WorkBench." : Print 
   Else If E=81
      Centre _NOT_ALL_FILES$(0) : Print : Print 
      Centre _NOT_ALL_FILES$(1) : Print : Print 
      Centre _NOT_ALL_FILES$(2)
   Else 
      Centre "An error has occured:" : Print : Print 
      Centre Err$(E) : Print : Print 
      Centre "Sorry."
   End If 
   Fade 1,0,$F5A : Wait Key : Fade 1,0,0 : Wait 10
   Erase All : End 
End Proc

Procedure WRITE_INITDATA
   Restore WRITEDATA
   For I=0 To $40-1
      Read WRITE_KOI82IMAGE(I)
   Next I
   For I=0 To $40-1
      Read WRITE_KOI82HOOK(I)
   Next I
   
   WRITEDATA:
   Data 0,97,0,99,100,101,114,0,0,105,117,108,108,0,110,111
   Data 111,97,114,115,116,117,0,101,0,121,122,0,0,0,0,0
   Data 0,65,0,67,68,69,82,0,0,73,85,76,76,0,78,79
   Data 79,65,82,83,84,85,0,69,0,89,90,0,0,0,0,0
   
   Data 0,$61,0,$62,$82,$62,$62,0,0,$61,$63,$81,$83,0,$62,$61
   Data $62,$62,$62,$62,$82,$61,0,$61,0,$61,$62,0,0,0,0,0
   Data 0,$81,0,$82,$82,$82,$82,0,0,$81,$83,$81,$83,0,$82,$81
   Data $82,$82,$82,$82,$82,$81,0,$81,0,$81,$82,0,0,0,0,0
End Proc
Procedure WRITEXY[PRINX,PRINY,PRIN$]
   If PRINX>-1 : SFX=PRINX
   Else If PRINX=-2 : SFX=160-3*Len(PRIN$) : Rem             center 
Else If PRINX=-3 : SFX=320-6*Len(PRIN$) : End If : Rem    right align 
   If PRINY>-1 : SFY=PRINY : End If 
   
   SFDEL=Len(PRIN$)
   If SFDEL=0 : Pop Proc : End If 
   For SFI=1 To SFDEL
      SFCH=Asc(Mid$(PRIN$,SFI,1))
      
      If(SFCH=10) or(SFCH=92) : Rem 92="\" 
         SFY=SFY+9 : SFX=0
      Else 
         If(SFCH>$C0)
            Paste Icon SFX,SFY,WRITE_KOI82IMAGE(SFCH-$C0)-32+1
            HOOKNPOSITION=WRITE_KOI82HOOK(SFCH-$C0)
            Paste Icon SFX,SFY-(HOOKNPOSITION/$10),(HOOKNPOSITION and $F)+$5B
         Else 
            Paste Icon SFX,SFY,Max(0,SFCH-32)+1
         End If 
         If(SFCH=Asc("l")) : Add SFX,4
      Else : Add SFX,6 : End If 
         If SFX>312 : SFX=0 : SFY=SFY+9 : End If 
      End If 
   Next SFI
End Proc

Procedure HELP
   Open In 1,LOCALE_PATH$+"Help"
   SFY=0
   
   Repeat 
      Unpack PLAN_BANK(0)
      P0=Phybase(0) : P1=Phybase(1) : P2=Phybase(2) : P3=Phybase(3)
      Copy P1,P1+10240-1 To P0
      Copy P2,P2+10240-1 To P1
      Copy P3,P3+10240-1 To P2
      Fill P3 To P3+10240-1,0
      
      Palette $0,$101,$201,$301,$402,$502,$602,$702,,,,,,,,,,,,,,,,,$831,$A52,$B62,$C73,$D83,$E94,$F94,$FA5
      Repeat 
         Line Input #1,A$
         WRITEXY[0,-1,A$+"\"]
      Until Eof(1) or SFY>(256-10)
      Clear Key 
      Repeat 
         A$=Lower$(Inkey$)
         ESC=Key State(ESC_SCANCODE)
      Until(A$<>"") or ESC
      FAST_FADE_OUT
      Cls 0 : SFY=0
   Until Eof(1) or ESC
   
   Close 1
   
End Proc

Procedure INIT_PUTPIX_STRATEGY_SIN_ATAN
   Screen 1
   For I=0 To 4
      Loke BITPLAN_BASE+I*4,Phybase(I)
   Next I
   Loke VA_PQ_X,Varptr(_PUTPIX_QUEUE_X(0))
   Loke VA_PQ_Y,Varptr(_PUTPIX_QUEUE_Y(0))
   Loke VA_PQ_COL,Varptr(_PUTPIX_QUEUE_COLOUR(0))
   Loke VA_PQ_TOP,Varptr(_PUTPIX_QUEUE_TOP)
   
   
   
   Loke VA_BITPLAN4,Phybase(4)
   Loke VA_SIN_TABLE,Start(26)
   Loke VA_DIRECTIONS,SMERU
   Loke VA_DIRSTEP0,SMERU*0.08
   Loke VA_DIRSTEP1,SMERU*0.16
   Loke VA_DIRSTEP2,SMERU*0.26
   Loke VA_DIRSTEP3,SMERU*0.32
   Loke VA_DIRSTEP4,SMERU*0.38
   
   Loke VA_ATAN_TABLE,Start(27)
   
   Loke VA_XHASH,Varptr(X#(1))
   Loke VA_YHASH,Varptr(Y#(1))
   Loke VA_PLAYERSDIR,Varptr(SMER(1))
   Loke VA_PLAYERALIVE,Varptr(SEMIALIVE(1))
   
   Loke VA_PLAYERSCHOICE,0
   Doke VA_PLAYERSCHOICE+4,0
   
   Poke VA_TURN,0
   '   Poke VA_BIGSCREEN,BIG_SCREEN 
   Poke VA_BIGSCREEN,Sgn(_SCREEN_SIZE)


   ANGLE_CONSTANT#=2*Pi#/SMERU : Rem      Userdirs=smeru/4 by the way   
   
   '          ________________________________
   '         |                                |   
   '         | Sin                            |     
   '         |________________________________| 
   
   For I=0 To USER_DIRECTIONS
      LOCAL#=Sin(ANGLE_CONSTANT#*I)
      Loke Start(26)+4*I,Leek(Varptr(LOCAL#))
   Next I

   '          ________________________________
   '         |                                | 
   '         | Atan                           | 
   '         |________________________________| 
   
   For I=0 To 256
      I#=I
      LOC#=I#/256
      AN=Atan(LOC#)/ANGLE_CONSTANT#
      Poke Start(27)+I,AN
   Next I

End Proc

'             ________________________________________ 
'            |                                        \  
'            |  Begin actions, configuration n dialogs \ 
'            |__________________________________________\        


Procedure _GET_IMAGES
   On Error Proc HANDLE_ERROR
   
   '          ________________________________
   '         |                                | 
   '         | GET FLAG ANIMATION             | 
   '         |________________________________| 
   
   
   Screen Open 2,320,256,16,Lowres
   Screen To Front 1
   
   Load Iff PATH$+"Flag"
   For J=0 To 2
      For I=0 To 3
         Get Sprite J*4+I+1,I*32,J*24 To(I+1)*32,(J+1)*24
      Next I
   Next J
   
   Bank Swap 1,23
   
   '          ________________________________
   '         |                                | 
   '         | GET HEAD SPRITES               | 
   '         |________________________________| 
   
   '    Sprites 1,2,5,6 are 4 col,       1,2 are small while 5,6 are big    
   '    Sprites 3,4,7,8 are 16 col,      3,4 are small while 7,8 are big      
   
   
   Ink 3 : Bar 0,0 To 1,1 : Get Sprite 7,0,0 To 2,2 : Get Sprite 3,0,0 To 1,1
   Ink 4 : Bar 0,0 To 1,1 : Get Sprite 8,0,0 To 2,2 : Get Sprite 4,0,0 To 1,1
   
   Screen Close 2
   
   Screen Open 2,320,256,4,Lowres
   Screen To Front 1
   
   Load Iff PATH$+"Lateral"
   
   Get Sprite LATERAL_LEFT,0,0 To 5,218
   Get Sprite LATERAL_RIGHT,5,0 To 5+5,218
   
   
   Ink 1 : Bar 0,0 To 1,1 : Get Sprite 5,0,0 To 2,2 : Get Sprite 1,0,0 To 1,1
   Ink 2 : Bar 0,0 To 1,1 : Get Sprite 6,0,0 To 2,2 : Get Sprite 2,0,0 To 1,1
   
   '          ________________________________
   '         |                                | 
   '         | 32 colour images               | 
   '         |________________________________| 
   
   
   Screen Open 2,320,256,32,Lowres
   Flash Off : Curs Off : Hide On 
   Screen To Front 1
   
   Ink $13 : Bar 0,0 To 1,1 : Get Sprite _BOB_PLAYER_IMAGE(0,1),0,0 To 2,2
   Get Sprite _BOB_PLAYER_IMAGE(0,0),0,0 To 1,1
   Ink $14 : Bar 0,0 To 1,1 : Get Sprite _BOB_PLAYER_IMAGE(1,1),0,0 To 2,2
   Get Sprite _BOB_PLAYER_IMAGE(1,0),0,0 To 1,1
   
   
   '        ========================================= 
   '        = 12    X                               = 
   '        = 13    cervik                          = 
   '        = 20,21 Yellow fajfky                   =   
   '        = 22    box                             = 
   '        = 32    computer                        = 
   '        = 47    cyborg                          = 
   '        ========================================= 
   
   Load Iff PATH$+"Graphics"
   
   Get Sprite 12,160,0 To 160+40,20
   Get Sprite 13,160,20 To 160+40,20+20
   Get Sprite DUENIX_TITLE_IMAGE,0,154 To 205,154+26+3
   Get Sprite DUENIX_ANIM_IMAGE,0,200 To 0+48,200+32
   Get Sprite 16,0,22+36+2 To 153,22+36+18
   Get Sprite 17,0,22+36+18 To 153,22+36+18+18
   
   Get Sprite MOUSE_ON_LINE_IMAGE,0,99 To 50,125
   Get Sprite _JOY_ON_LINE_IMAGE,50,99 To 100,125
   
   For I=0 To 2
      Get Sprite NO_IMAGE(I),35*I,0 To 35*I+35,17
      Get Sprite YES_IMAGE(I),35*I,17 To 35*I+35,2*17
      Get Sprite RED_BOX_IMAGE(I),35*I,2*17 To 35*I+35,3*17
   Next I
   
   Get Sprite 32,160,40 To 160+40,40+20
   Get Sprite 47,160,60 To 160+40,60+20
   
   Get Sprite SCORE_PANEL_BACKGROUND_IMAGE,0,55 To 40,55+40
   
   Get Sprite HORIZONTAL_WOOD_IMAGE,0,256-4 To 160,256
   Get Sprite CORNER_WOOD_IMAGE,160,256-4 To 160+9,256
   Get Sprite VERTICAL_WOOD_IMAGE,320-4,0 To 320,256-30-2*4
   Get Sprite NOSCROLL_CORNER_IMAGE,160+10,256-4 To 160+10+4,256
   
   '         ___________________________  
   '        |                           | 
   '        |          .--------------. |   
   '        | Box      | 23 | 24 | 25 | |   
   '        | Systems  |----+----+----| | 
   '        |          | 26 | 27 | 28 | | 
   '        |          |----+----+----| | 
   '        |          | 29 | 30 | 31 | | 
   '        |          `--------------' | 
   '        |___________________________| 
   
   Get Sprite 23,0,127 To 0+16,127+8
   Get Sprite 24,0+16,127 To 0+16+16,127+8
   Get Sprite 25,0+16+16,127 To 0+16+16+16,127+8
   
   Get Sprite 26,0,127+8 To 0+16,127+8+8
   Get Sprite 27,0+16,127+8 To 0+16+16,127+8+8
   Get Sprite 28,0+16+16,127+8 To 0+16+16+16,127+8+8
   
   Get Sprite 29,0,127+8+8 To 0+16,127+8+8+8
   Get Sprite 30,0+16,127+8+8 To 0+16+16,127+8+8+8
   Get Sprite 31,0+16+16,127+8+8 To 0+16+16+16,127+8+8+8
   
   '          ________________________________
   '         |                                | 
   '         | logo anim 33-46                | 
   '         |________________________________| 
   
   
   BASE=Phybase(4)
   Fill BASE To BASE+10239,0
   
   For I=1 To 14
      Get Sprite 32+I,(I-1)*20,182 To I*20-1,182+18
   Next I
   
   '          ________________________________
   '         |                                | 
   '         | Press space                    | 
   '         |________________________________| 
   
   
   Load Iff LOCALE_PATH$+"PressSpace"
   Get Sprite PRESS_SPACE_IMAGE,0,0 To 53,33
   
   Screen 1
End Proc
Procedure _GET_ICONS_FROM_SCOREIMAGES
   Screen Open 2,320,256,16,Lowres
   Screen To Front 1
   
   Load Iff PATH$+"scorepanel"
   Get Icon 1,0,0 To 320,30
   Get Icon 2,0,30 To 320,30+30
   
   For I=0 To 10+6-1
      Get Icon 3+I,20*I,83 To 20*(I+1),83+24
   Next I
   Get Icon 19,0,108 To 0+55,108+30
   Get Icon 20,55,108 To 55+10,108+4
   Make Icon Mask 
   
   Screen Close 2
End Proc
Procedure _PROC_SHOW_SQ_LOGO
   DUENIX_REQUEST
   Load PATH$+"SQLogo",21
   Track Load PATH$+"SQSound",22
   
   Screen Open 2,320,256,64,EHB
   Flash Off : Curs Off : Hide On 
   
   Unpack 21
   Fade 3,$0,$741,$270,$255,$E80,$424,$550,$565,$4A0,$290,$5C0,$5F5,$C20,$A10,$A60,$954,$E30,$F40,$878,$B90,$AA5,$BC0,$AF5,$EA0,$FC1,$FF1,$FF5,$AA9,$ADA,$C98,$FFA,$FFE
   Track Play 22
   PAUSED=_FALSE
   Timer=0 : Repeat 
      If Key State(P_SCANCODE)
         PAUSED=_TRUE
      End If 
   Until Timer>50*6
   Track Stop 
   If PAUSED
      Clear Key : Wait Key 
   End If 
   
   Fade 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   Wait 50
   Screen Close 2
   Erase 22 : Erase 21
   
End Proc
Procedure SEND_MONEY
   Screen Open 2,320,256,32,Lowres
   Flash Off : Curs Off : Hide On 
   
   Cls 0
   WRITEXY[0,9*2,CZ_SEND$+"\\"+_ADDRESS$+"\"]
   WRITEXY[0,130,EN_SEND$+"\"+_ADDRESS$+"\    Czech Republic\\"+EN_VALUE$]
   
   Ink $12,0 : Set Font FONT_NUMBER
   Text 10*10,128-4-4,RELEASE$
   
   BASE=Phybase(4) : Fill BASE+5120 To BASE+10239,0
   
   Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$A07,$B18,$C29,$D3A,$E49,$F59,$F69,$F78,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$223,$334,$557,$779,$99A,$AAB,$CCC,$DDD
   Clear Key 
   Repeat 
      PRESS$=Inkey$ : PRESS$=Lower$(PRESS$)
   Until PRESS$<>""
   _SHOW_SQ_LOGO= Not(Scancode=ESC_SCANCODE)
   
   Fade 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   Wait 15
   Screen Close 2
   
End Proc
Procedure _ASK_FOR_LANGUAGE
   Screen Open 2,320,256,32,Lowres
   Flash Off : Curs Off : Hide On 
   
   Cls 0
   WRITEXY[0,9*2,"Zvol si prosÉm jazyk:\\                C: ăeÓtina\                E: AngliĂtina\"]
   WRITEXY[-1,130,"Select the language please:\\                C: Czech\                E: English\"]
   
   BASE=Phybase(4)
   Fill BASE+5120 To BASE+10239,0
   
   Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$A07,$B18,$C29,$D3A,$E49,$F59,$F69,$F78,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$223,$334,$557,$779,$99A,$AAB,$CCC,$DDD
   Clear Key 
   Repeat 
      PRESS$=Inkey$ : PRESS$=Lower$(PRESS$)
   Until PRESS$="c" or PRESS$="e"
   
   If PRESS$="c"
      LOCALE_PATH$=PATH$+"czech_files/"
   Else 
      LOCALE_PATH$=PATH$+"english_files/"
   End If 
   
   Fade 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   Wait 15
   Screen Close 2
   
End Proc
Procedure BEGIN_LOADING
   On Error Proc HANDLE_ERROR

   If Not Exist(PATH$+"Duenix.info")
      Error _ERROR_BADPATH
   End If 

   LOCALE_PATH$=""
   If Exist(PATH$+"Language")
      Open In 1,PATH$+"Language"
      Line Input #1,LANGUAGE$
      Close 1
      LOCALE_PATH$=PATH$+LANGUAGE$+"_files/"
      If Not Exist(LOCALE_PATH$)
         LOCALE_PATH$=""
      End If 
   End If 
   
   If _COMPILED or _LOAD_DUENIX_FONT
      
      '          ________________________________
      '         |                                | 
      '         | Load textfont                  | 
      '         |________________________________| 
      
      Exec "Makedir T:tempfonts"
      Exec "Copy Fonts:Duenix.font T:tempfonts"
      Exec "Assign ofonts: fonts:"
      Exec "Assign fonts: T:tempfonts"
      Get Fonts 
      Exec "Assign fonts: ofonts:"
      Exec "Assign ofonts:"
      Exec "Delete T:tempfonts"
      
      FONT_NUMBER=0
      Repeat 
         Inc FONT_NUMBER
         CURRENTFONT$=Lower$(Left$(Font$(FONT_NUMBER),11))
      Until CURRENTFONT$="" or CURRENTFONT$="duenix.font"
      
      If CURRENTFONT$=""
         If LOCALE_PATH$=""
            LOCALE_PATH$=PATH$+"english_files/"
         End If 
         SET_TEXT_CONSTANTS

         Screen Open 3,640,256,2,Hires : Curs Off 
         Cls 0 : Paper 0 : Pen 1 : Locate 0,10
         Centre _NOT_FONT$ : Print : Print : Centre _NOT_ALL_FILES$(1)
         Print : Print : Centre _NOT_ALL_FILES$(2)
         Fade 1,0,$F5A : Wait Key : Fade 1,0,0 : Wait 14
         Screen Close 3 : Erase All : End 
      Else 
         Set Font FONT_NUMBER
      End If 
   End If 
   
   _TRUE=Asc(Mid$(_ADDRESS$,36,1))-50
   _FALSE=Len(_ADDRESS$)-59
   
   DUENIX_REQUEST
   _GET_ICONS_FROM_SCOREIMAGES
   Bank Swap 4,2
   Load PATH$+"Font",2 : Make Icon Mask 
   
   If _COMPILED
      SEND_MONEY
      If _SHOW_SQ_LOGO
         If LOCALE_PATH$=""
            _ASK_FOR_LANGUAGE
         End If 
         _PROC_SHOW_SQ_LOGO
      End If 
      If LOCALE_PATH$=""
         LOCALE_PATH$=PATH$+"czech_files/"
      End If 
   Else 
      LOCALE_PATH$=PATH$+"czech_files/"
   End If 
   
   
   '          ________________________________
   '         |                                | 
   '         | The Rest                       | 
   '         |________________________________| 
   
   
   SET_TEXT_CONSTANTS
   
   
   If _COMPILED
      Cls 0
      WRITEXY[-2,124,_LOADING$]
      SELECTING_FADE_UP
   End If 
   
   DUENIX_REQUEST
   Pload PATH$+"PutPixel",20
   Pload PATH$+"RecordAndReplay",24
   Pload PATH$+"Strategy",25
   
   Reserve As Work PRECOUNTED_SIN__BANK,1004
   Reserve As Work PRECOUNTED_ATAN__BANK,$101
   
   '          __________________________________
   '         |                                  | 
   '         | Setting CatchPoints of Assembler | 
   '         |__________________________________| 
   
   
   A20=Start(20)
   BITPLAN_BASE=A20 : Add A20,$20
   VA_PQ_X=A20 : Add A20,4
   VA_PQ_Y=A20 : Add A20,4
   VA_PQ_COL=A20 : Add A20,4
   VA_PQ_TOP=A20 : Add A20,4
   VA_PUTPIX_TYPE=A20 : Add A20,4
   PA_DRAW_PIXEL_QUEUE=A20 : Add A20,4
   PA_SMALL_PIX=A20 : Add A20,4
   PA_BIG_PIX=A20 : Add A20,4
   PA_SMALL_PIX_BIGSCREEN=A20 : Add A20,4
   PA_BIG_PIX_BIGSCREEN=A20 : Add A20,4
   
   VA_PLAYER_RECORD=Start(24)
   VA_GAME_RECORD=Start(24)+4
   VA_GAME_RECORD_POINTER=Start(24)+8
   PA_SAVE_POSITION=Start(24)+$C
   PA_LOAD_POSITION=Start(24)+$10
   
   A25=Start(25)
   VA_BITPLAN4=A25 : Add A25,4
   VA_SIN_TABLE=A25 : Add A25,4
   VA_ATAN_TABLE=A25 : Add A25,4
   
   VA_DIRECTIONS=A25 : Add A25,4
   VA_DIRSTEP0=A25 : Add A25,4
   VA_DIRSTEP1=A25 : Add A25,4
   VA_DIRSTEP2=A25 : Add A25,4
   VA_DIRSTEP3=A25 : Add A25,4
   VA_DIRSTEP4=A25 : Add A25,4
   
   VA_ROTATION=A25 : Add A25,4
   VA_DIRECTION=A25 : Add A25,4
   VA_XAMOSREAL=A25 : Add A25,4
   VA_YAMOSREAL=A25 : Add A25,4
   VA_PLAYER=A25 : Add A25,4
   VA_XHASH=A25 : Add A25,4
   VA_YHASH=A25 : Add A25,4
   VA_PLAYERSDIR=A25 : Add A25,4
   VA_PLAYERALIVE=A25 : Add A25,4
   VA_PLAYERSCHOICE=A25 : Add A25,6
   VA_TURN=A25 : Add A25,1
   VA_BIGSCREEN=A25 : Add A25,1
   
   PA_STRATEGY=A25 : Add A25,4
   PA_COUNTSINANDCOS=A25 : Add A25,4
   PA_COUNTTESTANDSPEEDPOINTS_1PIX=A25 : Add A25,4
   PA_COUNTTESTANDSPEEDPOINTS_2PIX=A25 : Add A25,4
   
   '          ________________________________
   '         |                                | 
   '         | Continue                       | 
   '         |________________________________| 
   
   
   Track Load PATH$+"LifeMotion",LIFE_MOTION_MUSIC__BANK
   
   _GET_IMAGES
   
   If _COMPILED
      For I=1 To 6
         A$=PATH$+"Plan"+(Str$(I)-" ")
         If Not Exist(A$) : Error 81 : End If : Rem NOT ALL FILES  
      Next I
   End If 

   Load PATH$+"PlanDef",PLAN_BANK(0)
   Load PATH$+"Plan1",PLAN_BANK(1)
   
   DUENIX_REQUEST
   _LOAD_CONFIGURATION[3] : Rem AT STARTUP 
   
   Load PATH$+"Default_Gameset",DEF_GAMESET__BANK
   BASE=Start(DEF_GAMESET__BANK)
   For I=0 To 19
      OFFSET=Deek(BASE+2*I)
      If OFFSET=0
         GS_GAME_NAME$(I,0)="Level"+Str$(I-10+1)
      Else 
         GS_GAME_NAME$(I,0)=Peek$(BASE+OFFSET,16)
      End If 
   Next I
   
   If Exist(PATH$+"User_Gameset")
      Load PATH$+"User_Gameset",USER_GAMESET__BANK
      BASE=Start(USER_GAMESET__BANK)
      For I=0 To 19
         OFFSET=Deek(BASE+2*I)
         If OFFSET=0
            GS_GAME_NAME$(I,1)="Empty"
         Else 
            GS_GAME_NAME$(I,1)=Peek$(BASE+OFFSET,16)
         End If 
      Next I
   End If 
   
   '          _________________________________________ 
   '         |                                         |  
   '         | Not neccessary, only when enough memory |  
   '         |_________________________________________|  
   
   
   If(Chip Free>28000+128000)
      Load PATH$+"Samples",5
      ENABLED_SOUND=True
   Else 
      If Not Exist(PATH$+"Samples") : Error 81 : End If : Rem NOT ALL FILES
      ENABLED_SOUND=False
   End If 
   
   If Chip Free>19000+128000
      GAME_MUSIC_IN_CHIP_RAM=True
      Load PATH$+"Duming",3
   Else 
      GAME_MUSIC_IN_CHIP_RAM=False
   End If 
   
   If Chip Free>30000+128000
      GAME_MUSIC_IN_CHIP_RAM=True
      Track Load PATH$+"WinnerMusic",WINNER_MUSIC__BANK
   Else 
      If Not Exist(PATH$+"WinnerMusic") : Error 81 : End If : Rem _NOT_ALL_FILES 
      GAME_MUSIC_IN_CHIP_RAM=False
   End If 
   
   RECORDING_ALLOWED=False
   If(Chip Free+Fast Free)>10000+128000
      Reserve As Work 30,10000
      RECORDING_ALLOWED=True

      Loke VA_PLAYER_RECORD,Varptr(_PLAYER_RECORD(0))
      Loke VA_GAME_RECORD_POINTER,0
      
      RECORD_BASE=Start(30)
      RECORD_MOVEMENTS_START=RECORD_BASE+$130
      Loke VA_GAME_RECORD,RECORD_MOVEMENTS_START
      GAME_RECORD_EMPTY=True
   End If 
   
   If _COMPILED
      Fade 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Wait 30
      Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   End If 
   
   If _COMPILED or _LOAD_DUENIX_FONT
      Screen 2
      Set Font FONT_NUMBER
      Screen 1
   End If 
   
   '          ________________________________
   '         |                                | 
   '         | Now change the plan            | 
   '         |________________________________| 
   
   
   SET_PLAN_USING_CONFIG[True]
   
   Track Loop Of 
   If _MUSIC_ON
      Track Play LIFE_MOTION_MUSIC__BANK
   End If 
   
End Proc

Procedure SET_PLAN_USING_CONFIG[LONG_TERMED]
   If PLAN=1
      Trap Load PATH$+"Plan"+Str$(GAMEPLAN)-" ",PLAN_BANK(1)
   End If 
   
   If PLAN=1
      SET_SPP
   End If 
   
   If LONG_TERMED or PLAN=2
      If OWN_PLAN_PATH$<>""
         OWN_PLAN_LOAD[OWN_PLAN_PATH$,False]
      Else 
         If(LONG_TERMED=False) and(Length(PLAN_BANK(2))>0)
            Erase PLAN_BANK(2)
         End If 
         For I=0 To $F
            UPP(I)=0
         Next I
      End If 
   End If 
End Proc
Procedure _DECONFIG[BASE,FROM_SET]
   SHORT_CONFIG=-Peek(BASE)
   USER_DIRECTIONS=Peek(BASE+1)
   SMERU=USER_DIRECTIONS*4
   ANGLE_CONSTANT#=2*Pi#/SMERU
   SMERU_QUARTER=USER_DIRECTIONS
   SMERU_HALVE=USER_DIRECTIONS*2
   SPEEDJUMP=Peek(BASE+2)
   SPACE_LENGTH=Deek(BASE+3)
   _DRAWING_LINE_LENGTH=Deek(BASE+5)
   LINE_LENGTH=SPACE_LENGTH+_DRAWING_LINE_LENGTH+20
   USER_RATE_LENGTH=Deek(BASE+7)
   CENTRAL_BOX_SIZE=Peek(BASE+9)
   FINAL_RATE=Peek(BASE+$A)
   FLAGS=Peek(BASE+$B)
   WATERING=FLAGS and $1
   ALWAYS_TURNING=FLAGS and $2 : Ror.b 1,ALWAYS_TURNING
   USER_SOUND_FX=FLAGS and $4 : Ror.b 2,USER_SOUND_FX
   COMPUDEATH=FLAGS and $8 : Ror.b 3,COMPUDEATH
   TEAM_GAME=FLAGS and $10 : Ror.b 4,TEAM_GAME
   TEAM_GAME=-TEAM_GAME
   LONG_GAME=FLAGS and $20 : Ror.b 5,LONG_GAME
   COMPUTURBO=FLAGS and $40 : Ror.b 6,COMPUTURBO
   SURPRISING_START=FLAGS and $80 : Ror.b 7,SURPRISING_START
   WATER_LIMIT=Peek(BASE+$C)
   WATER_LIMIT#=WATER_LIMIT*Pi#/180
   '       LIVES_TOP=Peek(BASE+$D)
   PLAN=Peek(BASE+$E)
   GAMEPLAN=Peek(BASE+$F)
   FLAGS=Peek(BASE+$10)
   RATEMODE=FLAGS and 1
   _MUSIC_ON=FLAGS and 2 : Ror.b 1,_MUSIC_ON
   SPACE_KILL=FLAGS and 4 : Ror.b 2,SPACE_KILL
   BOUNCING=FLAGS and 8 : Ror.b 3,BOUNCING
   CENTRAL_BOX=FLAGS and $10 : Ror.b 4,CENTRAL_BOX
   TELEPORTING=FLAGS and $20 : Ror.b 5,TELEPORTING
   BOLDLINE=FLAGS and $40 : Ror.b 6,BOLDLINE
   TURBO=(FLAGS and $80) : Ror.b 7,TURBO
   FLAGS=Peek(BASE+$11)
   WIND=FLAGS and 1
   BODY_CHANGE=FLAGS and 2 : Ror.b 1,BODY_CHANGE
   ZOMBIES=FLAGS and 4 : Ror.b 2,ZOMBIES
   WIND_STRENGTH=Peek(BASE+$12)
   _SCREEN_SIZE=Peek(BASE+$13)
   BODY_CHANGE_PERCENT=Peek(BASE+$14)
   
   SET_APPROPRIATE_DRAWPIXEL_PROC
   
   If Not FROM_SET
      PATH_S_LEN=Peek(BASE+$20)
      If PATH_S_LEN<$60
         OWN_PLAN_PATH$=Peek$(BASE+$21,PATH_S_LEN)
      Else 
         _LOAD_CONFIGURATION[0] : Rem BUILTIN  
      End If 
   End If 
   
   '          ________________________________
   '         |                                | 
   '         | Is It Configuration ?!         | 
   '         |________________________________| 
   
   
   FCONFIG=0 : Rem False configuration bool 
   
   FCONFIG=FCONFIG or(PLAN>2) or(GAMEPLAN<1) or(GAMEPLAN>6) or(WATERING+TELEPORTING+BOUNCING>1)
   FCONFIG=FCONFIG or(SPEEDJUMP>95) or(USER_RATE_LENGTH>999) or(CENTRAL_BOX_SIZE>80) or(CENTRAL_BOX_SIZE<10)
   FCONFIG=FCONFIG or(FINAL_RATE>100) or(_SCREEN_SIZE>2)
   FCONFIG=FCONFIG or(USER_DIRECTIONS<5) or(USER_DIRECTIONS>250) or(SPACE_LENGTH>999) or(_DRAWING_LINE_LENGTH>999)
   
   If FCONFIG
      _LOAD_CONFIGURATION[0] : Rem BUILTIN  
   End If 
End Proc
Procedure CONFIG[BASE,FROM_SET]
   OWN_PLAN_PATH$=Left$(OWN_PLAN_PATH$,$5F)
   
   Poke BASE,-SHORT_CONFIG
   Poke BASE+1,USER_DIRECTIONS
   Poke BASE+2,SPEEDJUMP
   Doke BASE+3,SPACE_LENGTH
   Doke BASE+5,_DRAWING_LINE_LENGTH
   Doke BASE+7,USER_RATE_LENGTH
   Poke BASE+9,CENTRAL_BOX_SIZE
   Poke BASE+$A,FINAL_RATE
   FLAGS=WATERING
   Add FLAGS,2*ALWAYS_TURNING
   Add FLAGS,4*USER_SOUND_FX
   Add FLAGS,8*COMPUDEATH
   Add FLAGS,-$10*TEAM_GAME
   Add FLAGS,$20*LONG_GAME
   Add FLAGS,$40*COMPUTURBO
   Add FLAGS,$80*SURPRISING_START
   Poke BASE+$B,FLAGS
   Poke BASE+$C,WATER_LIMIT
   Poke BASE+$D,LIVES_TOP
   Poke BASE+$E,PLAN
   Poke BASE+$F,GAMEPLAN
   FLAGS=RATEMODE
   Add FLAGS,2*_MUSIC_ON
   Add FLAGS,4*SPACE_KILL
   Add FLAGS,8*BOUNCING
   Add FLAGS,$10*CENTRAL_BOX
   Add FLAGS,$20*TELEPORTING
   Add FLAGS,$40*BOLDLINE
   Add FLAGS,$80*TURBO
   Poke BASE+$10,FLAGS
   FLAGS=WIND
   Add FLAGS,2*BODY_CHANGE
   Add FLAGS,4*ZOMBIES
   Poke BASE+$11,FLAGS
   Poke BASE+$12,WIND_STRENGTH
   Poke BASE+$13,_SCREEN_SIZE
   Poke BASE+$14,BODY_CHANGE_PERCENT
   
   If Not FROM_SET
      Poke BASE+$20,Len(OWN_PLAN_PATH$)
      Poke$ BASE+$21,OWN_PLAN_PATH$
   End If 
End Proc
Procedure _LOAD_CONFIGURATION[WHAT]
   If(WHAT=0) or(WHAT=3) : Rem 3 means at StartUp 
      '          ________________________________
      '         |                                | 
      '         | Builtin                        | 
      '         |________________________________| 
      
      USER_DIRECTIONS=18
      SMERU=USER_DIRECTIONS*4 : ANGLE_CONSTANT#=2*Pi#/SMERU
      SMERU_QUARTER=USER_DIRECTIONS : SMERU_HALVE=USER_DIRECTIONS*2
      _DRAWING_LINE_LENGTH=100
      SPACE_LENGTH=10 : LINE_LENGTH=SPACE_LENGTH+_DRAWING_LINE_LENGTH+20
      SPEEDJUMP=60
      RATE=100
      RATEMODE=1
      USER_RATE_LENGTH=500
      FINAL_RATE=100
      SPACE_KILL=1
      BOUNCING=0
      TELEPORTING=0
      _MUSIC_ON=1
      BOLDLINE=1 : SET_APPROPRIATE_DRAWPIXEL_PROC
      PLAN=0
      CENTRAL_BOX=0
      CENTRAL_BOX_SIZE=50
      XBOTTOM=145-CENTRAL_BOX_SIZE : XTOP=146+CENTRAL_BOX_SIZE
      YBOTTOM=127-CENTRAL_BOX_SIZE : YTOP=128+CENTRAL_BOX_SIZE
      TURBOLIMIT=0
      WATERING=1
      WATER_LIMIT=75 : WATER_LIMIT#=WATER_LIMIT*Pi#/180
      ALWAYS_TURNING=0
      SURPRISING_START=1
      BODY_CHANGE=1
      BODY_CHANGE_PERCENT=80
      COMPUDEATH=1
      ZOMBIES=0

      PLAN=0
      GAMEPLAN=1
   End If 
   
   
   If WHAT=3
      '          ________________________________
      '         |                                | 
      '         | At startup                     | 
      '         |________________________________| 
      
      Trap If Exist(PATH$+"Config")
         Trap Load PATH$+"Config",7
         If Length(7)>=$80
            _DECONFIG[Start(7),False]
         End If 
      End If 
   Else If WHAT=1
      '          ________________________________
      '         |                                | 
      '         | Default                        | 
      '         |________________________________| 
      
      DUENIX_REQUEST
      
      If Exist(PATH$+"Config")
         Trap Load PATH$+"Config",7
         If Not((Length(7)=$80))
            HALFWAITING_DIALOG[DUENIX_CONFIG_ISNT_CONFIG$,OPERATION_ABORTED$,""]
         Else 
            _DECONFIG[Start(7),False]
            HALFWAITING_DIALOG["",DEF_CONFIG_LOADED$,""]
         End If 
      Else 
         HALFWAITING_DIALOG[CANT_FIND_DEF_CONFIG1$,CANT_FIND_DEF_CONFIG2$,""]
      End If 
   Else If WHAT=2
      '          ________________________________
      '         |                                | 
      '         | Other                          | 
      '         |________________________________| 
      
      Screen 1
      Show On 
      Change Mouse 1
      Trap A$=Fsel$(PATH$+"","",ENTER_CONFIGNAME$)
      Hide On 
      
      If Exist(A$)
         Trap Load A$,7
         If(Length(7)<>$80)
            HALFWAITING_DIALOG[THIS_FILE_ISNT_CONFIG$,OPERATION_ABORTED$,""]
         Else 
            _DECONFIG[Start(7),False]
            HALFWAITING_DIALOG["",CONFIG_LOADED$,""]
         End If 
      Else 
         HALFWAITING_DIALOG["",FILE_DOESNT_EXIST$,""]
      End If 
   End If 
   
   
   Erase 7
End Proc
Procedure _SAVE_CONFIGURATION[WHAT]
   If WHAT=0
      '          ________________________________
      '         |                                | 
      '         | Default                        | 
      '         |________________________________| 
      
      CONFIG_LENGTH=$80
      Reserve As Work 7,CONFIG_LENGTH
      CONFIG[Start(7),False]
      DUENIX_REQUEST
      Trap Save PATH$+"Config",7
      HALFWAITING_DIALOG[CONFIG_SAVED_AS_DEF1$,CONFIG_SAVED_AS_DEF2$,""]
      
   Else 
      '          ________________________________
      '         |                                | 
      '         | Other                          | 
      '         |________________________________| 
      
      CONFIG_LENGTH=$80
      Reserve As Work 7,CONFIG_LENGTH
      CONFIG[Start(7),False]
      
      Screen 1
      Show On 
      Change Mouse 1
      A$=Fsel$(PATH$+"","",ENTER_NAME_OF_CONFIG_TO_SAVE$)
      Hide On 
      If Exist(A$)
         _DIALOGBEG
         B$=THIS_FILE_ALREADY_EXISTS$ : Text 160-4*Len(B$),14*8+6,B$
         B$=WANT_TO_OVERWRITE$ : Text 160-4*Len(B$),15*8+6,B$
         Repeat 
            B$=Lower$(Inkey$)
         Until(B$="y") or(B$="n")
         _DIALOGEND
         
         If B$="y"
            Trap Save A$,7
            HALFWAITING_DIALOG["",CONFIG_SAVED$,""]
         Else 
            HALFWAITING_DIALOG["",CONFIG_NOT_SAVED$,""]
         End If 
      Else 
         Trap Save A$,7
         If A$="" : HALFWAITING_DIALOG["",CONFIG_NOT_SAVED$,""]
      Else : HALFWAITING_DIALOG["",CONFIG_SAVED$,""] : End If 
      End If 
   End If 
   
   Erase 7
End Proc

Procedure _DIALOGBEG
   Screen 1 : Get Block 1,0,104,320,50
   Screen 2 : Put Block 1,0,0 : Rem STORE UNDERDIALOG
   
   Paste Bob 0+32,104,BS_LEFT_TOP
   For I=1 To 14 : Paste Bob I*16+32,104,BS_MIDDLE_TOP : Next I
   Paste Bob 320-16-32,104,BS_RIGHT_TOP
   
   For J=1 To 3
      J_OFFSET=8*J
      Paste Bob 0+32,104+8*J,BS_LEFT_MIDDLE
      For I=1 To 14 : Paste Bob I*16+32,104+J_OFFSET,BS_MIDDLE_MIDDLE : Next I
      Paste Bob 320-16-32,104+8*J,BS_RIGHT_MIDDLE
   Next J
   
   Paste Bob 0+32,104+8*4,BS_LEFT_BOTTOM
   For I=1 To 14 : Paste Bob I*16+32,104+8*4,BS_MIDDLE_BOTTOM : Next I
   Paste Bob 320-16-32,104+8*4,BS_RIGHT_BOTTOM
   
   Get Block 1,0,104,320,50,1 : Screen 1
   Put Block 1,0,104
   Del Block 1
   
   Ink $11,$15
End Proc
Procedure _DIALOGEND
   Screen 2 : Get Block 1,0,0,320,50 : Screen 1
   Wait Vbl : Put Block 1,0,104
   Del Block 1
End Proc
Procedure HALFWAITING_DIALOG[HW_T1$,HW_T2$,HW_T3$]
   _DIALOGBEG
   Text 160-4*Len(HW_T1$),14*8+6,HW_T1$
   Text 160-4*Len(HW_T2$),15*8+6,HW_T2$
   Text 160-4*Len(HW_T3$),16*8+6,HW_T3$
   
   Wait 5 : Clear Key : Timer=0
   Repeat 
      A$=Inkey$
   Until A$<>"" or Timer>50*6
   Clear Key 
   _DIALOGEND
   Wait 10 : Clear Key 
End Proc

'             ______________________________________ 
'            |                                      \  
'            |  Options                              \ 
'            |________________________________________\        


Procedure MAKE_OPTIONS_BACKGROUND[PAGE_NUMBER$,PAGE_NAME$]
   
   Screen 1
   Cls 0
   Unpack PLAN_BANK(0)
   
   Screen 2
   Cls 0
   Paste Bob 35,1,DUENIX_TITLE_IMAGE
   
   WRITEXY[5,12,PAGE_NUMBER$]
   WRITEXY[316-6*Len(PAGE_NAME$),12,PAGE_NAME$]
   
End Proc
Procedure BOOL_OPTION[BO_SIGN,BO_I,BO_COLUMN]
   If BO_SIGN=0 Then IMAGE=NO_IMAGE(OS_LC_BOX(BO_I)) Else IMAGE=YES_IMAGE(OS_LC_BOX(BO_I))
   Paste Bob 152*BO_COLUMN+116+6,8*(2*BO_I+1)-4,IMAGE
End Proc
Procedure NUMBER_OPTION[NO_NUMBER,NO_NUMBER_SIZE,NO_HIGHLITE,NO_I,NO_COLUMN]
   Ink $13,$15
   If NO_HIGHLITE=_FALSE : Ink $16 : End If 
   
   A$=Str$(NO_NUMBER)-" " : A$=String$("0",NO_NUMBER_SIZE-Len(A$))+A$
   Text 152*NO_COLUMN+8*(19-NO_NUMBER_SIZE),8*(NO_I*2+1)+6,A$
End Proc
Procedure DEPENDENT_OPTION[DEO_SIGN,DEO_NUMBER,DEO_NUMBER_SIZE,DEO_YPOS,DEO_COLUMN]
   If DEO_SIGN=0 Then IMAGE=NO_IMAGE(OS_LC_BOX(DEO_YPOS)) Else IMAGE=YES_IMAGE(OS_LC_BOX(DEO_YPOS))
   Paste Bob 152*DEO_COLUMN+116+6,8*(2*DEO_YPOS+1)-4,IMAGE
   
   Ink $13,$15
   If DEO_SIGN=_FALSE : Ink $16 : End If 
   
   A$=Str$(DEO_NUMBER)-" " : A$=String$("0",DEO_NUMBER_SIZE-Len(A$))+A$
   Text 152*DEO_COLUMN+8*(19-DEO_NUMBER_SIZE),8*(DEO_YPOS*2+1+2)+6,A$
End Proc
Procedure _GET_3NUMBER[G3X,G3Y]
   Clear Key : Wait 5
   
   G3NUMBER=0
   G3C=100
   For I=0 To 2
      Ink $0,$13
      Text 8*(G3X+I),8*G3Y+6," "
      Ink $13,$15
      Repeat 
         A$=Inkey$
         A=Asc(A$)
      Until(A>47) and(A<58)
      Text 8*(G3X+I),8*G3Y+6,A$-" "
      Add G3NUMBER,G3C*(A-48)
      G3C=G3C/10
   Next I
End Proc[G3NUMBER]

Procedure OPTIONS_MAIN
   
   If _NOT(E_THRU or G_THRU or R_THRU)
      OPTIONS_MAIN_RESTORE_SCREEN
   End If 
   
   ESC_QUITED=False
   Clear Key 
   Repeat 
      If Key State(L_SCANCODE)
         _LOAD_CONFIGURATION[1] : Rem DEFAULT
      End If 
      If Key State(S_SCANCODE)
         _SAVE_CONFIGURATION[0] : Rem DEFAULT
      End If 
      If Key State(Z_SCANCODE)
         _LOAD_CONFIGURATION[2] : Rem OTHER
      End If 
      If Key State(X_SCANCODE)
         _SAVE_CONFIGURATION[1] : Rem OTHER
      End If 
      If Key State(E_SCANCODE) or E_THRU
         If Not E_THRU
            FAST_FADE_OUT
         End If 
         E_THRU=False
         OPTIONS_GAMESETTINGS
         If Not ESC_QUITED
            OPTIONS_GAMESETTINGS2
            If Not ESC_QUITED
               OPTIONS_MAIN_RESTORE_SCREEN
            End If 
         End If 
      End If 
      If Key State(G_SCANCODE) or G_THRU
         If Not G_THRU
            FAST_FADE_OUT
         End If 
         G_THRU=False
         OPTIONS_GAMEPLAN
         If Not ESC_QUITED
            OPTIONS_MAIN_RESTORE_SCREEN
         End If 
      End If 
      If Key State(R_SCANCODE) or R_THRU
         If Not R_THRU
            FAST_FADE_OUT
         End If 
         R_THRU=False
         OPTIONS_RECORD_AND_REPLAY
         If Not ESC_QUITED
            OPTIONS_MAIN_RESTORE_SCREEN
         End If 
      End If 
      If Key State(U_SCANCODE)
         FAST_FADE_OUT
         OPTIONS_USER_GAMESET
         If Not ESC_QUITED
            OPTIONS_MAIN_RESTORE_SCREEN
         End If 
      End If 
      
   Until Key State(SPACE_SCANCODE) or Key State(ESC_SCANCODE) or ESC_QUITED
   
   If Not ESC_QUITED
      If FAST_INTERFACE
         Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Else 
         Fade 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
         Wait 15
      End If 
   End If 
   
End Proc
Procedure OPTIONS_MAIN_FADEUP
   If FAST_INTERFACE
      Wait Vbl 
      Palette $0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$81D,$A1D,$C2E,$E1E,$F0F,$F2F,$F4F,$F6F
      Wait 1
   Else 
      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$81D,$A1D,$C2E,$E1E,$F0F,$F2F,$F4F,$F6F
      Wait 15
   End If 
End Proc
Procedure OPTIONS_MAIN_RESTORE_SCREEN
   MAKE_OPTIONS_BACKGROUND[PAGE_ONE$,MAIN_OPTION_LOADING_AND_SAVING$]
   
   WRITEXY[-2,8*17-16,CONFIGURATION$]
   
   For I=6 To 9
      WRITEXY[-2,(I+3)*12+7*8-16,MAIN_OPTION_TEXT$(I-6)]
   Next I
   
   WRITEXY[-2,6*8,MAIN_OPTION_E_TEXT$]
   WRITEXY[-2,6*8+12,MAIN_OPTION_G_TEXT$]
   WRITEXY[-2,6*8+24,MAIN_OPTION_R_TEXT$]
   WRITEXY[-2,6*8+36,MAIN_OPTION_U_TEXT$]
   WRITEXY[-2,27*8,_PRESS_SPACE_OR_ESCAPE$]
   WRITEXY[-2,29*8,ESCAPE_ACCEPT$]

   LET_IT_SHOW
   Screen 1
   OPTIONS_MAIN_FADEUP
End Proc

Procedure OPTIONS_USER_GAMESET
   '          ________________________________
   '         |                                | 
   '         | Print                          | 
   '         |________________________________| 
   
   
   MAKE_OPTIONS_BACKGROUND[PAGE_FIVE$,CREATING_USER_GAMESET$]
   
   WRITEXY[-2,32,CREATE_USER_GAMESET$]
   
   SFX=0 : COORDY=50
   For I=0 To 13
      WRITEXY[0,COORDY,CREATE_USER_GS_EXPLANATION$(I)]
      Add COORDY,9
   Next 
   
   WRITEXY[-2,29*8,RECORD_AND_REPLAY_SPACE$]
   LET_IT_SHOW
   Screen 1
   If FAST_INTERFACE
      Wait Vbl 
      Palette $0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$664,$775,$887,$998,$AAA,$BBB,$CCC,$DDD
      Wait 1
   Else 
      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$664,$775,$887,$998,$AAA,$BBB,$CCC,$DDD
      Wait 15
   End If 
   
   
   '          ________________________________
   '         |                                | 
   '         | Key control                    | 
   '         |________________________________| 
   
   
   ESC_QUITED=False
   Clear Key 
   Repeat 
      If Key State(C_SCANCODE)
         Screen 1
         Show On 
         Change Mouse 1
         Trap A$=Fsel$("","",ENTER_NAME_OF_CONFIG_LIST_FILE$)
         Hide On 
         If Not Exist(A$)
            HALFWAITING_DIALOG["",FILE_DOESNT_EXIST$,""]
         Else 
            CREATE_GAMESET[USER_GAMESET__BANK,A$]
            CONFIGS=Param
            If CONFIGS=0
               HALFWAITING_DIALOG[NONE_OF_FILES_WAS_CONFIG1$,"",NONE_OF_FILES_WAS_CONFIG2$]
            Else If CONFIGS>20
               Trap Save PATH$+"User_gameset",USER_GAMESET__BANK
               HALFWAITING_DIALOG[YOUR_NEW_GAMESET_IS_SAVED$,MORE_THAN_20_FILES1$,MORE_THAN_20_FILES2$]
            Else 
               Trap Save PATH$+"User_gameset",USER_GAMESET__BANK
               HALFWAITING_DIALOG["",YOUR_NEW_GAMESET_IS_SAVED$,""]
            End If 
         End If 
         
         If Length(USER_GAMESET__BANK)>0
            BASE=Start(USER_GAMESET__BANK)
            For I=0 To 19
               OFFSET=Deek(BASE+2*I)
               If OFFSET=0
                  GS_GAME_NAME$(I,1)=NAME_OF_EMPTY_GAME_IN_GAMESET$
               Else 
                  GS_GAME_NAME$(I,1)=Peek$(BASE+OFFSET,16)
               End If 
            Next I
         End If 
         
      End If 
      ESC_QUITED=Key State(ESC_SCANCODE)
   Until Key State(SPACE_SCANCODE) or ESC_QUITED
   
   FAST_FADE_OUT
   
End Proc

Procedure OPTIONS_RECORD_AND_REPLAY
   '          ________________________________
   '         |                                | 
   '         | Print                          | 
   '         |________________________________| 
   
   MAKE_OPTIONS_BACKGROUND[PAGE_FOUR$,RECORD_AND_REPLAY$]
   
   For I=0 To 2 : WRITEXY[5,(I+1)*16+8,RR_COLUMN_TEXT$(I)] : Next 
   
   WRITEXY[-2,29*8,RECORD_AND_REPLAY_SPACE$]
   
   For I=1 To 3
      Paste Bob 122,16*I+4,RED_BOX_IMAGE(OS_LC_BOX(I))
   Next I
   
   BOOL_OPTION[USER_RECORDING,1,0]
   BOOL_OPTION[USER_REPLAYING,2,0]
   BOOL_OPTION[REPLAY_ALL_SAVED_ON,3,0]
   
   LET_IT_SHOW
   Screen 1
   
   If FAST_INTERFACE
      Wait Vbl 
      Palette $0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$81D,$A1D,$C2E,$E1E,$F0F,$F2F,$F4F,$F6F
      Wait 1
   Else 
      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$111,$81D,$A1D,$C2E,$E1E,$F0F,$F2F,$F4F,$F6F
      Wait 15
   End If 
   
   '          ________________________________
   '         |                                | 
   '         | Key control                    | 
   '         |________________________________| 
   
   
   ESC_QUITED=_FALSE : Clear Key 
   Repeat 
      If Key State(R_SCANCODE)
         USER_RECORDING= Not USER_RECORDING
         Wait Vbl 
         BOOL_OPTION[USER_RECORDING,1,0]
         If USER_REPLAYING
            USER_REPLAYING=False
            BOOL_OPTION[USER_REPLAYING,2,0]
         Else If REPLAY_ALL_SAVED_ON
            REPLAY_ALL_SAVED_ON=False
            BOOL_OPTION[REPLAY_ALL_SAVED_ON,3,0]
         End If 
         Clear Key : Wait 10
      End If 
      If Key State(P_SCANCODE)
         Wait Vbl 
         If Not USER_REPLAYING
            If GAME_RECORD_EMPTY
               HALFWAITING_DIALOG[YOU_HAVENT_RECORDED1$,YOU_HAVENT_RECORDED2$,YOU_HAVENT_RECORDED3$]
            Else 
               USER_REPLAYING=True
               BOOL_OPTION[USER_REPLAYING,2,0]
               If USER_RECORDING
                  USER_RECORDING=False
                  BOOL_OPTION[USER_RECORDING,1,0]
               Else If REPLAY_ALL_SAVED_ON
                  REPLAY_ALL_SAVED_ON=False
                  BOOL_OPTION[REPLAY_ALL_SAVED_ON,3,0]
               End If 
            End If 
         Else 
            USER_REPLAYING=False
            BOOL_OPTION[USER_REPLAYING,2,0]
         End If 
         Clear Key : Wait 10
      End If 
      If Key State(A_SCANCODE)
         
         If Not REPLAY_ALL_SAVED_ON
            
            _EXISTS_INDEX=True
            If Exist("Duenrecord:")
               GAME_SAVING_PATH$="DuenRecord:"
            Else 
               If Not Exist("ram:DuenRecord/")
                  _EXISTS_INDEX=False
               End If 
               GAME_SAVING_PATH$="ram:DuenRecord/"
            End If 
            
            If _EXISTS_INDEX
               INDEX=0
               _EXISTS_INDEX=False
               Repeat 
                  INDEX$=Str$(INDEX)-" " : INDEX$=String$("0",2-Len(INDEX$))+INDEX$
                  If Exist(GAME_SAVING_PATH$+RECORDNAME$+INDEX$)
                     _EXISTS_INDEX=True
                  End If 
                  Inc INDEX
               Until _EXISTS_INDEX or(INDEX=100)
               Dec INDEX
            End If 
            
            If _EXISTS_INDEX
               REPLAY_ALL_SAVED_ON= Not REPLAY_ALL_SAVED_ON
               Wait Vbl 
               BOOL_OPTION[REPLAY_ALL_SAVED_ON,3,0]
               If USER_RECORDING
                  USER_RECORDING=False
                  BOOL_OPTION[USER_RECORDING,1,0]
               Else If USER_REPLAYING
                  USER_REPLAYING=False
                  BOOL_OPTION[USER_REPLAYING,2,0]
               End If 
            Else 
               HALFWAITING_DIALOG[YOU_HAVENT_SAVED_GAME1$,YOU_HAVENT_SAVED_GAME2$,YOU_HAVENT_SAVED_GAME3$]
            End If 
         Else 
            REPLAY_ALL_SAVED_ON= Not REPLAY_ALL_SAVED_ON
            Wait Vbl 
            BOOL_OPTION[REPLAY_ALL_SAVED_ON,3,0]
         End If 
         Clear Key : Wait 10
      End If 
      
      ESC_QUITED=Key State(ESC_SCANCODE)
   Until Key State(SPACE_SCANCODE) or ESC_QUITED
   
   FAST_FADE_OUT
End Proc

Procedure OPTIONS_GAMESETTINGS
   '          ________________________________
   '         |                                | 
   '         | Print                          | 
   '         |________________________________| 
   
   
   MAKE_OPTIONS_BACKGROUND[PAGE_TWO$,GAME_SETTINGS$]
   
   For I=1 To 14
      WRITEXY[8,I*16+8,OS_LEFT_COLUMN_TEXT$(I,0)]
      Paste Bob 116+6,16*I+4,RED_BOX_IMAGE(OS_LC_BOX(I))
      WRITEXY[8*21,I*16+8,OS_RIGHT_COLUMN_TEXT$(I,0)]
      Paste Bob 152+116+6,16*I+4,RED_BOX_IMAGE(OS_RC_BOX(I))
   Next 
   
   Wait Vbl 
   NUMBER_OPTION[USER_DIRECTIONS,3,_TRUE,1,0]
   NUMBER_OPTION[SPEEDJUMP,2,_TRUE,2,0]
   NUMBER_OPTION[SPACE_LENGTH,3,_TRUE,3,0]
   NUMBER_OPTION[_DRAWING_LINE_LENGTH,3,_TRUE,4,0]
   DEPENDENT_OPTION[RATEMODE,USER_RATE_LENGTH,3,5,0]
   NUMBER_OPTION[FINAL_RATE,3,_TRUE,7,0]
   BOOL_OPTION[SPACE_KILL,8,0]
   BOOL_OPTION[BOUNCING,9,0]
   BOOL_OPTION[TELEPORTING,10,0]
   DEPENDENT_OPTION[WATERING,WATER_LIMIT,3,11,0]
   BOOL_OPTION[_MUSIC_ON,13,0]
   BOOL_OPTION[USER_SOUND_FX,14,0]
   
   BOOL_OPTION[TURBO,1,1]
   BOOL_OPTION[COMPUTURBO,2,1]
   DEPENDENT_OPTION[CENTRAL_BOX,CENTRAL_BOX_SIZE,3,3,1]
   BOOL_OPTION[ALWAYS_TURNING,5,1]
   BOOL_OPTION[1-BOLDLINE,6,1]
   DEPENDENT_OPTION[BODY_CHANGE,BODY_CHANGE_PERCENT,2,7,1]
   BOOL_OPTION[TEAM_GAME,9,1]
   BOOL_OPTION[LONG_GAME,10,1]
   BOOL_OPTION[SURPRISING_START,11,1]
   DEPENDENT_OPTION[WIND,WIND_STRENGTH,2,12,1]
   NUMBER_OPTION[_SCREEN_SIZE+1,1,_TRUE,14,1]
   
   LET_IT_SHOW
   Screen 1
   OPTIONS_GAMESETTINGS_FADE_UP
   
   '          ________________________________
   '         |                                | 
   '         | Key control                    | 
   '         |________________________________| 
   
   
   
   ESC_QUITED=_FALSE : Clear Key 
   Repeat 
      If Key State(1)
         _GET_3NUMBER[16,3] : USER_DIRECTIONS=Param
         If USER_DIRECTIONS<5
            USER_DIRECTIONS=5
            HALFWAITING_DIALOG[_MINIMUM_OF_DIRECTIONS$,SORRY$,""]
         Else If USER_DIRECTIONS>250
            USER_DIRECTIONS=250
            HALFWAITING_DIALOG[_MAXIMUM_OF_DIRECTIONS$,SORRY$,""]
         End If 
         
         SMERU=USER_DIRECTIONS*4
         ANGLE_CONSTANT#=2*Pi#/SMERU
         SMERU_QUARTER=USER_DIRECTIONS
         SMERU_HALVE=USER_DIRECTIONS*2
         
         NUMBER_OPTION[USER_DIRECTIONS,3,_TRUE,1,0]
         Wait 10
      Else If Key State(2)
         Add SPEEDJUMP,5,0 To 95
         NUMBER_OPTION[SPEEDJUMP,2,_TRUE,2,0]
         Wait 10
      Else If Key State(3)
         _GET_3NUMBER[16,7] : SPACE_LENGTH=Param
         LINE_LENGTH=SPACE_LENGTH+_DRAWING_LINE_LENGTH+20
         Wait 10
      Else If Key State(4)
         _GET_3NUMBER[16,9] : _DRAWING_LINE_LENGTH=Param
         LINE_LENGTH=SPACE_LENGTH+_DRAWING_LINE_LENGTH+20
         Wait 10
      Else If Key State(5)
         RATEMODE=1-RATEMODE
         DEPENDENT_OPTION[RATEMODE,USER_RATE_LENGTH,3,5,0]
         Wait 10
      Else If Key State(6) and(RATEMODE=1)
         _GET_3NUMBER[16,13] : USER_RATE_LENGTH=Param
         Wait 10
      Else If Key State(7)
         Add FINAL_RATE,5,50 To 100
         NUMBER_OPTION[FINAL_RATE,3,_TRUE,7,0]
         Wait 10
      Else If Key State(8)
         SPACE_KILL=1-SPACE_KILL
         BOOL_OPTION[SPACE_KILL,8,0]
         Wait 10
      Else If Key State(9)
         BOUNCING=1-BOUNCING
         If BOUNCING
            TELEPORTING=0
            WATERING=0
            BOOL_OPTION[TELEPORTING,10,0]
            DEPENDENT_OPTION[WATERING,WATER_LIMIT,3,11,0]
         End If 
         BOOL_OPTION[BOUNCING,9,0]
         Wait 10
      Else If Key State(O_SCANCODE)
         TELEPORTING=1-TELEPORTING
         If TELEPORTING
            BOUNCING=0
            WATERING=0
            BOOL_OPTION[BOUNCING,9,0]
            DEPENDENT_OPTION[WATERING,WATER_LIMIT,3,11,0]
         End If 
         BOOL_OPTION[TELEPORTING,10,0]
         Wait 10
      Else If Key State(P_SCANCODE)
         '~~~ Change of watering 0/1) ~~~ 
         WATERING=WATERING xor 1
         If WATERING=1
            BOUNCING=0
            TELEPORTING=0
            BOOL_OPTION[BOUNCING,9,0]
            BOOL_OPTION[TELEPORTING,10,0]
         End If 
         
         DEPENDENT_OPTION[WATERING,WATER_LIMIT,3,11,0]
         Wait 10
      Else If Key State(Q_SCANCODE) and(WATERING=1)
         _GET_3NUMBER[16,25]
         WATER_LIMIT=Param
         If WATER_LIMIT>=90
            WATER_LIMIT=89
            
            DEPENDENT_OPTION[WATERING,WATER_LIMIT,3,11,0]
            
            HALFWAITING_DIALOG[_MAXIMUM_OF_WATER_ANGLE$,SORRY$,""]
         End If 
         WATER_LIMIT#=WATER_LIMIT*Pi#/180
         Clear Key 
         Wait 5
      Else If Key State(R_SCANCODE)
         _MUSIC_ON=_NOT(_MUSIC_ON)
         If _MUSIC_ON : Track Play LIFE_MOTION_MUSIC__BANK
      Else : Track Stop : End If 
         
         BOOL_OPTION[_MUSIC_ON,13,0]
         Wait 10
      Else If Key State(S_SCANCODE)
         USER_SOUND_FX=_NOT(USER_SOUND_FX)
         BOOL_OPTION[USER_SOUND_FX,14,0]
         Wait 10
      Else If Key State(A_SCANCODE)
         TURBO=_NOT(TURBO)
         If TURBO : COMPUTURBO=_FALSE : End If 
         BOOL_OPTION[TURBO,1,1]
         BOOL_OPTION[COMPUTURBO,2,1]
         Wait 10
      Else If Key State(B_SCANCODE)
         COMPUTURBO=_NOT(COMPUTURBO)
         If COMPUTURBO : TURBO=_FALSE : End If 
         BOOL_OPTION[TURBO,1,1]
         BOOL_OPTION[COMPUTURBO,2,1]
         Wait 10
      Else If Key State(C_SCANCODE)
         CENTRAL_BOX=_NOT(CENTRAL_BOX)
         DEPENDENT_OPTION[CENTRAL_BOX,CENTRAL_BOX_SIZE,3,3,1]
         Wait 10
      Else If Key State(D_SCANCODE) and CENTRAL_BOX
         Add CENTRAL_BOX_SIZE,5,10 To 80
         DEPENDENT_OPTION[CENTRAL_BOX,CENTRAL_BOX_SIZE,3,3,1]
         Wait 10
      Else If Key State(E_SCANCODE)
         ALWAYS_TURNING=_NOT(ALWAYS_TURNING)
         BOOL_OPTION[ALWAYS_TURNING,5,1]
         Wait 10
      Else If Key State(F_SCANCODE)
         BOLDLINE=_NOT(BOLDLINE)
         SET_APPROPRIATE_DRAWPIXEL_PROC
         BOOL_OPTION[_NOT(BOLDLINE),6,1]
         Wait 10
      Else If Key State(G_SCANCODE)
         BODY_CHANGE=1-BODY_CHANGE
         DEPENDENT_OPTION[BODY_CHANGE,BODY_CHANGE_PERCENT,3,7,1]
         Wait 10
      Else If Key State(H_SCANCODE) and BODY_CHANGE
         Add BODY_CHANGE_PERCENT,20,20 To 120
         DEPENDENT_OPTION[BODY_CHANGE,BODY_CHANGE_PERCENT,3,7,1]
         Wait 5
      Else If Key State(I_SCANCODE)
         TEAM_GAME= Not TEAM_GAME
         BOOL_OPTION[TEAM_GAME,9,1]
         Wait 10
      Else If Key State(J_SCANCODE)
         LONG_GAME=1-LONG_GAME
         BOOL_OPTION[LONG_GAME,10,1]
         Wait 10
      Else If Key State(K_SCANCODE)
         SURPRISING_START=_NOT(SURPRISING_START)
         BOOL_OPTION[SURPRISING_START,11,1]
         Wait 10
      Else If Key State(L_SCANCODE)
         WIND=_NOT(WIND)
         DEPENDENT_OPTION[WIND,WIND_STRENGTH,2,12,1]
         Wait 10
      Else If Key State(M_SCANCODE)
         Add WIND_STRENGTH,1,1 To 10
         DEPENDENT_OPTION[WIND,WIND_STRENGTH,2,12,1]
         Wait 10
      Else If Key State(N_SCANCODE)
         Add _SCREEN_SIZE,1,0 To 2
         SET_APPROPRIATE_DRAWPIXEL_PROC
         NUMBER_OPTION[_SCREEN_SIZE+1,1,_TRUE,14,1]
         Wait 10
      End If 
      
      ESC_QUITED=Key State(ESC_SCANCODE)
   Until Key State(SPACE_SCANCODE) or ESC_QUITED
   
   FAST_FADE_OUT
End Proc
Procedure OPTIONS_GAMESETTINGS2
   '          ________________________________
   '         |                                | 
   '         | Print                          | 
   '         |________________________________| 
   
   MAKE_OPTIONS_BACKGROUND[PAGE_TWO$,GAME_SETTINGS$]
   
   For I=1 To 1
      WRITEXY[8,I*16+8,OS_LEFT_COLUMN_TEXT$(I,1)]
      Paste Bob 116+6,16*I+4,RED_BOX_IMAGE(OS_LC_BOX(I))
      WRITEXY[8*21,I*16+8,OS_RIGHT_COLUMN_TEXT$(I,1)]
      Paste Bob 152+116+6,16*I+4,RED_BOX_IMAGE(OS_RC_BOX(I))
   Next 
   
   BOOL_OPTION[COMPUDEATH,1,0]
   BOOL_OPTION[ZOMBIES,1,1]
   
   LET_IT_SHOW
   Screen 1
   OPTIONS_GAMESETTINGS_FADE_UP
   
   '          ________________________________
   '         |                                | 
   '         | Key control                    | 
   '         |________________________________| 
   
   
   ESC_QUITED=_FALSE : Clear Key 
   Repeat 
      If Key State(1)
         COMPUDEATH=1-COMPUDEATH
         BOOL_OPTION[COMPUDEATH,1,0]
         Wait 10
      End If 
      If Key State(A_SCANCODE)
         ZOMBIES=1-ZOMBIES
         BOOL_OPTION[ZOMBIES,1,1]
         Wait 10
      End If 
      
      ESC_QUITED=Key State(ESC_SCANCODE)
   Until Key State(SPACE_SCANCODE) or ESC_QUITED
   
   FAST_FADE_OUT
End Proc
Procedure OPTIONS_GAMESETTINGS_FADE_UP
   If FAST_INTERFACE
      Palette $0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$122,$177,$196,$2A7,$1B6,$B5,$2C4,$4D3,$6E2
   Else 
      '      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$122,$177,$196,$2A7,$1B6,$B5,$2C4,$4D3,$6E2
      Fade 1,$10,$10,$121,$121,$232,$232,$343,$343,$454,$454,$565,$565,$676,$676,$787,$787,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$122,$177,$196,$2A7,$1B6,$B5,$2C4,$4D3,$6E2
      
      ' PALETTE VER 1.1      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,$F80,$EA0,$DC0,$CE0,$F01,$F20,$F50,$122,$177,$196,$2A7,$1B6,$B5,$2C4,$4D3,$6E2
      Wait 15
   End If 
End Proc

Procedure OPTIONS_GAMEPLAN

   OPTIONS_GAMEPLAN_RESTORE_SCREEN
   
   ESC_QUITED=False
   Clear Key 
   Repeat 
      If Key State(D_SCANCODE) and(PLAN>0)
         PLAN=0
         FAST_FADE_OUT
         OPTIONS_GAMEPLAN_RESTORE_SCREEN
      Else If Key State(Y_SCANCODE) and(PLAN<2)
         PLAN=2
         FAST_FADE_OUT
         OPTIONS_GAMEPLAN_RESTORE_SCREEN
      Else If Key State(L_SCANCODE) and(PLAN=2)
         Screen 1
         Show On 
         Change Mouse 1
         Trap A$=Fsel$("","",ENTER_NAME_OFF_IFF_TO_LOAD$)
         Hide On 
         OWN_PLAN_LOAD[A$,True]
      End If 
      
      For I=1 To 6
         If Key State(I) and((GAMEPLAN<>I) or(PLAN<>1))
            GAMEPLAN=I
            SET_SPP
            PLAN=1
            DUENIX_REQUEST
            Trap Load PATH$+"Plan"+Str$(GAMEPLAN)-" ",PLAN_BANK(1)
            FAST_FADE_OUT
            OPTIONS_GAMEPLAN_RESTORE_SCREEN
         End If 
      Next 
      
      ESC_QUITED=Key State(ESC_SCANCODE)
   Until Key State(SPACE_SCANCODE) or ESC_QUITED
   
   FAST_FADE_OUT
End Proc
Procedure OPTIONS_GAMEPLAN_RESTORE_SCREEN
   Screen 1
   If Length(PLAN_BANK(PLAN))>0
      Unpack PLAN_BANK(PLAN)
   Else 
      Cls 0
   End If 
   
   Screen 2
   Cls 0
   Paste Bob 35,0,DUENIX_TITLE_IMAGE
   WRITEXY[5,12,PAGE_THREE$]
   WRITEXY[316-6*Len(GAMEPLAN$),12,GAMEPLAN$]
   
   Pen $14
   
   If PLAN=1
      WRITEXY[8,4*8,THIS_IS_STANDARD_GAMEPLAN_NUMBER$+Str$(GAMEPLAN)]
   Else If PLAN=2
      If Length(PLAN_BANK(2))=0
         A$=HERE_MAY_BE_YOUR_PLAN$
      Else 
         A$=HERE_IS_YOUR_PLAN$
      End If 
      WRITEXY[8,4*8,A$+"\"]
      
      WRITEXY[1*8,11*8,GAMEPLAN_L_TEXT$+"\"]
      Add SFY,20
      For I=0 To 2 : WRITEXY[-1,-1,GAMEPLAN_EXPLANATION$(I)+"\"] : Next 
   Else 
      WRITEXY[8,4*8,THIS_IS_DEFPLAN$]
   End If 
   
   SFY=180
   For I=0 To 2 : WRITEXY[10,-1,GAMEPLAN_KEY_TEXT$(I)+"\"] : Next 
   
   WRITEXY[-2,29*8,RECORD_AND_REPLAY_SPACE$]

   LET_IT_SHOW
   Screen 1

   Wait Vbl 
   If FAST_INTERFACE
      If PLAN=0
         Palette $0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      Else If PLAN=2
         Palette 0,UPP(1),UPP(2),UPP(3),UPP(4),UPP(5),UPP(6),UPP(7),UPP(8),UPP(9),UPP(10),UPP(11),UPP(12),UPP(13),UPP(14),UPP(15),0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      Else 
         Palette 0,SPP(1),SPP(2),SPP(3),SPP(4),SPP(5),SPP(6),SPP(7),SPP(8),SPP(9),SPP(10),SPP(11),SPP(12),SPP(13),SPP(14),SPP(15),0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      End If 
      Clear Key : Wait 1
   Else 
      If PLAN=0
         Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      Else If PLAN=2
         Fade 1,UPP(0),UPP(1),UPP(2),UPP(3),UPP(4),UPP(5),UPP(6),UPP(7),UPP(8),UPP(9),UPP(10),UPP(11),UPP(12),UPP(13),UPP(14),UPP(15),0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      Else If DARK_GAMEPLAN=0
         Fade 1,0,SPP(1),SPP(2),SPP(3),SPP(4),SPP(5),SPP(6),SPP(7),SPP(8),SPP(9),SPP(10),SPP(11),SPP(12),SPP(13),SPP(14),SPP(15),0,$E7D,$DD,$D42,$88F,$953,$F0F,$0,$D15,$E26,$E37,$F48,$F59,$F6A,$F7B,$F8C
      End If 
      Wait 15
   End If 


End Proc

Procedure OWN_PLAN_LOAD[FILE$,OP_INTERACTIVE]
   Screen 2
   Trap Load Iff FILE$
   If Errtrap=0
      BASE=Phybase(4)
      Fill BASE To BASE+10239,0
      For I=0 To $F
         UPP(I)=Colour(I)
      Next I
      
      Screen 1
      If OP_INTERACTIVE
         FAST_FADE_OUT
      End If 
      Screen Copy 2 To 1
      
      Pack 1 To PLAN_BANK(2)
      If OP_INTERACTIVE
         OPTIONS_GAMEPLAN_RESTORE_SCREEN
      End If 
      OWN_PLAN_PATH$=FILE$
   Else 
      OWN_PLAN_PATH$=""
   End If 
End Proc


'             ______________________________________ 
'            |                                      \  
'            |  Selecting and Gameset work           \ 
'            |________________________________________\        


Procedure SELECTING_FADE_UP
   
   '   Fade 1,$0,$0,$110,$110,$221,$221,$332,$332,$443,$443,$554,$554,$665,$665,$776,$776,0,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$0,$811,$931,$A41,$B51,$C61,$D81,$EA1,$FC2
   '   Fade 1,$0,$0,$110,$110,$221,$221,$332,$332,$443,$443,$554,$554,$665,$665,$776,$776,0,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$0,$822,$942,$A52,$B62,$C72,$D92,$EB2,$FD3
   Fade 1,$0,$110,$221,$332,$443,$554,$665,$776,$822,$942,$A52,$B62,$C72,$D92,$EB2,$FD3,$0,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$0,$832,$942,$A43,$B53,$C54,$D64,$E75,$F76
   
   
   
   'PALETTE Ver 1.1   Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778,0,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$0,$915,$A26,$B37,$C48,$D59,$E6A,$F7B,$F8C  
   '   Fade 1,$0,$1,$2,$3,$112,$114,$116,$118,$333,$335,$337,$339,$555,$558,$55C,$55F,0,$BB9,$D4,$F6E,$FD0,$98F,$DC,$0,$915,$A26,$B37,$C48,$D59,$E6A,$F7B,$F8C
   Wait 15
End Proc
Procedure SELECTING_PRINT[CLEAR_SCREEN_1]
   
   If CLEAR_SCREEN_1
      Screen 2
      Sprite Off 
      Screen 1
      Unpack PLAN_BANK(0)
      
      P0=Phybase(0) : P1=Phybase(1) : P2=Phybase(2) : P3=Phybase(3)
      Copy P1,P1+10240-1 To P0
      Copy P2,P2+10240-1 To P1
      Copy P3,P3+10240-1 To P2
      Fill P3 To P3+10240-1,0
   End If 
   
   Screen 2
   Cls 0 : Paper 0 : Pen $18
   Paste Bob 35,1+3,DUENIX_TITLE_IMAGE
   Paste Bob 255,1,DUENIX_ANIM_IMAGE
   '   Wait Vbl 
   
   '          ________________________________
   '         |                                | 
   '         | Print Fajfky and Lives         | 
   '         |________________________________| 
   
   For _PLAYER=1 To 6
      Ink $10+_PLAYER,0
      Bar 33*8-6,3*8*_PLAYER+10 To 33*8+25,24*_PLAYER+16+10
      Paste Bob 33*8-8,24*_PLAYER+10,_PLAYER_TYPE_IMAGE(_PLAYER_TYPE(_PLAYER))
      
      If _TOP_LIVES(_PLAYER)>0
         Ink $10+_PLAYER,1
         Text 33*8+42,24*_PLAYER+22,Str$(_TOP_LIVES(_PLAYER))-" "
      End If 
   Next _PLAYER
   
   If CLEAR_SCREEN_1=0
      Screen 1 : Put Block 1 : Screen 2
   End If 
   
   '          ________________________________
   '         |                                | 
   '         | Print Player Texts             | 
   '         |________________________________| 
   
   For I=1 To 6
      A$=SELECTING_UPPER_TEXT$(I-1)
      Ink $17 : Text 1,8*(3*I+2)+6,A$
      Get Sprite _FREE_FOR_MANIPULATION_IMAGE,1,8*(3*I+2) To 8*Len(A$),8*(3*I+2)+8
      Screen 1
      Paste Bob 1,8*(3*I+2)+1,_FREE_FOR_MANIPULATION_IMAGE
      Paste Bob 2,8*(3*I+2),_FREE_FOR_MANIPULATION_IMAGE
      Paste Bob 1,8*(3*I+2)-1,_FREE_FOR_MANIPULATION_IMAGE
      Paste Bob 0,8*(3*I+2),_FREE_FOR_MANIPULATION_IMAGE
      Paste Bob 1,8*(3*I+2)+5,_FREE_FOR_MANIPULATION_IMAGE
      Paste Bob 1,8*(3*I+2)+6,_FREE_FOR_MANIPULATION_IMAGE
      Screen 2
      
      Ink $17
      If I=5
         Box 245,24*5+20+3 To 250,24*5+20+3
         Box 198-2*8,24*5+20+3 To 200,24*5+20+3
      Else If I=3
         Box 245,24*3+20+3 To 250,24*3+20+3
         Box Len(A$)*8+6,24*3+20+3 To 220,24*3+20+3
      Else 
         Box Len(A$)*8+6,24*I+20+3 To 250,24*I+20+3
      End If 
      
      Ink $10+I
      If I=5
         Draw 245,24*5+20 To 250,24*5+20
         Draw 198-2*8,24*5+20 To 200,24*5+20
      Else If I=3
         Draw 245,24*3+20 To 250,24*3+20
         Draw Len(A$)*8+6,24*3+20 To 220,24*3+20
      Else 
         Draw Len(A$)*8+6,24*I+20 To 250,24*I+20
      End If 
      
      Text 1,8*(3*I+2)+6,A$
   Next 
   
   '          ________________________________
   '         |                                | 
   '         | Draw Mouse & Joy               | 
   '         |________________________________| 
   
   Paste Bob 200,130,MOUSE_ON_LINE_IMAGE
   Paste Bob 200,82,_JOY_ON_LINE_IMAGE
   
   '          ________________________________
   '         |                                | 
   '         | Other Texts                    | 
   '         |________________________________| 
   
   LET_IT_SHOW
   
   If CLEAR_SCREEN_1
      Screen 1
      WRITEXY[-2,178,SELECTING_LOWER_TEXT$(0)]
      WRITEXY[-2,188,SELECTING_LOWER_TEXT$(1)]
      WRITEXY[-2,198,SELECTING_LOWER_TEXT$(2)]
      WRITEXY[-2,208,SELECTING_LOWER_TEXT$(3)]
      WRITEXY[-2,228,SELECTING_LOWER_TEXT$(4)]
      WRITEXY[-2,247,SELECTING_LOWER_TEXT$(5)+YEAR$]
   End If 
   Screen 2
End Proc
Procedure SELECTING
   SELECTING_RESTORE_SCREEN
   
   For _PLAYER=1 To 6
      ACCEPT_KEYSTROKE(_PLAYER)=_TRUE
      _KEYSTROKE_COUNTER(_PLAYER)=0
   Next _PLAYER
   
   LAST_CHANGED_PLAYER=6
   
   Repeat 
      
      '          ________________________________
      '         |                                | 
      '         | Test player keys               | 
      '         |________________________________| 
      
      
      REDRAW_ANY_PLAYER=_FALSE
      
      For _PLAYER=1 To 6
         REDRAW_PLAYER(_PLAYER)=_FALSE
         If ACCEPT_KEYSTROKE(_PLAYER)
            
            On _PLAYER Goto LTL1,LTL2,LTL3,LTL4,LTL5,LTL6
            LTL1: RIGHT_PUSHED=Key State(66)
            LEFT_PUSHED=Key State(0) : Goto LTL_END
            LTL2: RIGHT_PUSHED=((Key Shift and $40)>0)
            LEFT_PUSHED=((Key Shift and $10)>0) : Goto LTL_END
            LTL3: RIGHT_PUSHED=Key State(54) or Jright(1)
            LEFT_PUSHED=Key State(53) or Jleft(1) : Goto LTL_END
            LTL4: RIGHT_PUSHED=((Key Shift and $20)>0)
            LEFT_PUSHED=((Key Shift and $80)>0) : Goto LTL_END
            LTL5: RIGHT_PUSHED=Key State(95) or((Mouse Key and 2)=2)
            LEFT_PUSHED=Key State(70) or((Mouse Key and 1)=1) : Goto LTL_END
            LTL6: RIGHT_PUSHED=Key State(63)
            LEFT_PUSHED=Key State(47)
            LTL_END:
            
            If LEFT_PUSHED or RIGHT_PUSHED
               _KEYSTROKE_COUNTER(_PLAYER)=10
               ACCEPT_KEYSTROKE(_PLAYER)=_FALSE
               REDRAW_PLAYER(_PLAYER)=_TRUE
               REDRAW_ANY_PLAYER=_TRUE
               
               Add _PLAYER_TYPE(_PLAYER),1,0 To 3
               SELECTED(_PLAYER)=(_PLAYER_TYPE(_PLAYER)>0)
               If SELECTED(_PLAYER)=0
                  _TOP_LIVES(_PLAYER)=0
               End If 
            End If 
         Else 
            Dec _KEYSTROKE_COUNTER(_PLAYER)
            If(_KEYSTROKE_COUNTER(_PLAYER)=0)
               ACCEPT_KEYSTROKE(_PLAYER)=_TRUE
            End If 
         End If 
      Next _PLAYER
      
      _COUNT_SELECTED
      
      '          ________________________________
      '         |                                | 
      '         | Test lives keys                | 
      '         |________________________________| 
      
      If(HRAJOU>0)
         If Key State(10)
            Repeat 
               Add LAST_CHANGED_PLAYER,1,1 To 6
            Until SELECTED(LAST_CHANGED_PLAYER)
            
            Timer=0
            _TOP_LIVES(LAST_CHANGED_PLAYER)=0
            REDRAW_PLAYER(LAST_CHANGED_PLAYER)=_TRUE
            REDRAW_ANY_PLAYER=_TRUE
            
            Wait 7
         End If 
         For KEY=1 To 7
            If Key State(KEY)
               Repeat 
                  Add LAST_CHANGED_PLAYER,1,1 To 6
               Until SELECTED(LAST_CHANGED_PLAYER)
               
               Timer=0
               _TOP_LIVES(LAST_CHANGED_PLAYER)=KEY
               REDRAW_PLAYER(LAST_CHANGED_PLAYER)=_TRUE
               REDRAW_ANY_PLAYER=_TRUE
               
               Wait 7
            End If 
         Next KEY
      End If 
      
      '          ________________________________
      '         |                                | 
      '         | Redraw selected players n lives| 
      '         |________________________________| 
      
      If REDRAW_ANY_PLAYER
         Timer=0
         Screen 2
         For _PLAYER=1 To 6
            If REDRAW_PLAYER(_PLAYER)
               Ink $10+_PLAYER,0
               Bar 33*8-6,3*8*_PLAYER+10 To 33*8+25,24*_PLAYER+16+10
               Paste Bob 33*8-8,24*_PLAYER+10,_PLAYER_TYPE_IMAGE(_PLAYER_TYPE(_PLAYER))
               
               T=_TOP_LIVES(_PLAYER)
               T$=" "
               If T>0 : T$=Str$(T)-" " : End If 
               Ink $10+_PLAYER,1
               Text 33*8+42,24*_PLAYER+22,T$
            End If 
         Next _PLAYER
         
         Get Block 1,16*16,0,320-16*16,256,1
         Screen 1
         Wait Vbl 
         Put Block 1
         Del Block 1
      Else 
         Wait Vbl 
      End If 
      
      Clear Key 
      
      
      
      '          ________________________________
      '         |                                | 
      '         | Test screen keys               | 
      '         |________________________________| 
      
      If Key State(H_SCANCODE)
         FAST_FADE_OUT
         Amal Off : Sprite Off 
         HELP
         SELECTING_RESTORE_SCREEN
      Else If Key State(L_SCANCODE)
         _PLAYER_COLOURS_SET=1-_PLAYER_COLOURS_SET
         If _PLAYER_COLOURS_SET=0
            For I=1 To 6 : PL_DEF_COLOR(I)=PL_DEF_COLOR_LIGHT(I) : Next 
         Else 
            For I=1 To 6 : PL_DEF_COLOR(I)=PL_DEF_COLOR_DARK(I) : Next 
         End If 
         Fade 1,,,,,,,,,,,,,,,,,,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
         Wait 10
      Else If Key State(O_SCANCODE)
         FAST_FADE_OUT
         Amal Off : Sprite Off 
         OPTIONS_MAIN
         SELECTING_RESTORE_SCREEN
      Else If Key State(E_SCANCODE)
         FAST_FADE_OUT : E_THRU=_TRUE
         Amal Off : Sprite Off 
         OPTIONS_MAIN
         SELECTING_RESTORE_SCREEN
      Else If Key State(G_SCANCODE)
         FAST_FADE_OUT : G_THRU=_TRUE
         Amal Off : Sprite Off 
         OPTIONS_MAIN
         SELECTING_RESTORE_SCREEN
      Else If Key State(R_SCANCODE)
         FAST_FADE_OUT : R_THRU=_TRUE
         Amal Off : Sprite Off 
         OPTIONS_MAIN
         SELECTING_RESTORE_SCREEN
      Else If Key State(S_SCANCODE)
         SELECT_GAME : Timer=0
      Else If Key State(U_SCANCODE)
         If Length(USER_GAMESET__BANK)>0
            U_THRU=_TRUE
            SELECT_GAME : Timer=0
         End If 
      Else If Key State(Q_SCANCODE)
         Fade 3 : Wait 50 : Track Stop : Erase All 
         Screen Close 2 : Screen Close 1
         If Prg State=-1
            End 
         Else 
            Edit 
         End If 
      End If 
      
      DEMO_ON=(Timer>DEMO_TIMER_LIMIT)
      
   Until Key State(SPACE_SCANCODE) and(((HRAJOU>1) and(TEAM_GAME=False)) or HRAJOU=4 or HRAJOU=6 or REPLAY_ALL_SAVED_ON) or DEMO_ON or _ONE_PLAYER_GAME
   _ONE_PLAYER_GAME=False
   Fade 1
   Wait 15
   
   If DEMO_ON
      DEMO_ENVIRONMENT[0] : Rem Store envi before demo and set demo envi 
   End If 
   
   If Not(DEMO_ON or REPLAY_ALL_SAVED_ON)
      REALIZE_PLAYER_TYPE
   End If 
   
   SET_TEAMMATES
   
   If Not DEMO_ON
      Track Stop 
   End If 
   
   Amal Off 
   Sprite Off 
   Paper 0
   Cls 0
   
End Proc
Procedure SELECTING_RESTORE_SCREEN
   Sprite Off 
   SELECTING_PRINT[True]
   Screen 1
   Sprite Off : Wait Vbl : Wait 1
   '#### My Last Attempt #### 
   For I=0 To 7
      Sprite I,0,0,0
   Next I
   
   Sprite 0,260+X Hard(0)-24-4+30+2+2,5+4+42,33
   '   _ANIM_FLAG$="Anim 0,(33,6)(34,6)(35,6)(36,6)(37,6)(38,6)(39,6)(40,6)(41,6)(42,6)(43,6)(44,6)(45,6)(46,6)"
   _ANIM_FLAG$="Anim 0,(33,6)(34,6)(35,5)(36,4)(37,3)(38,3)(39,4)(40,5)(41,6)(42,6)(43,6)(44,6)(45,6)(46,6)(33,4)(34,1)(35,1)(36,1)(37,1)(38,1)(39,1)(40,1)(41,1)(42,1)(43,2)(44,3)(45,4)(46,5)"
   Amal 0,_ANIM_FLAG$
   Amal On 
   
   SELECTING_FADE_UP
   Timer=0 : DEMO_ON=False
End Proc
Procedure SET_TEAMMATES
   Dim TM(3)
   
   If Not TEAM_GAME
      For I=1 To 6
         TEAM_MATE(I)=I
      Next I
   Else 
      If HRAJOU=6
         TEAM_MATE_THRU(1)=$12
         TEAM_MATE_THRU(2)=0
         TEAM_MATE_THRU(3)=$14
         TEAM_MATE_THRU(4)=0
         TEAM_MATE_THRU(5)=$16
         TEAM_MATE_THRU(6)=0
         
         TEAM_MATE(1)=2
         TEAM_MATE(2)=1
         TEAM_MATE(3)=4
         TEAM_MATE(4)=3
         TEAM_MATE(5)=6
         TEAM_MATE(6)=5
      Else 
         TM_INDEX=0
         For I=1 To 6
            If SELECTED(I)
               TM(TM_INDEX)=I
               Inc TM_INDEX
            End If 
         Next I
         
         TEAM_MATE_THRU(TM(0))=$10+TM(1)
         TEAM_MATE_THRU(TM(1))=0
         TEAM_MATE_THRU(TM(2))=$10+TM(3)
         TEAM_MATE_THRU(TM(3))=0
         
         TEAM_MATE(TM(0))=TM(1)
         TEAM_MATE(TM(1))=TM(0)
         TEAM_MATE(TM(2))=TM(3)
         TEAM_MATE(TM(3))=TM(2)
      End If 
   End If 
End Proc

Procedure _DO_SELECTION_SCREEN[GS_TYPE]
   U_GOES_TO_USERBANK=(GS_TYPE=0) and(Length(USER_GAMESET__BANK)>0)
   
   For I=0 To 9
      WRITEXY[20-4,20+51-10+I*9,Str$(I)+" "+GS_GAME_NAME$(I,GS_TYPE)]
   Next I
   For I=0 To 9
      WRITEXY[20-2+120,20+51-10+I*9,Chr$(I+65)+" "+GS_GAME_NAME$(I+10,GS_TYPE)]
   Next I
   If U_GOES_TO_USERBANK
      WRITEXY[45,156,PRESS_U_TO_SELECT_USER_GAME$]
   End If 
   
   '          ________________________________
   '         |                                | 
   '         | Draw Box                       | 
   '         |________________________________| 

   _W_=10 : _E_=250 : _N_=36 : _S_=170
   Ink $10
   Box _W_+3,_N_+3 To _E_+3,_S_+3
   Box _W_+2,_N_+2 To _E_+2,_S_+2
   Ink $19 : Box _W_+1,_N_+1 To _E_+1,_S_+1
   Ink $1E : Box _W_,_N_ To _E_,_S_
   Ink $10
   Box _W_-1,_N_-1 To _E_+2,_S_+2
   Box _W_+2,_N_+2 To _E_-1,_S_-1
   
   Get Block 1,0,32,320-32-32,140 : Screen 1
   Put Block 1 : Del Block 1
   
   '             .-----------------------------------------.
   '             |    Now wait for what key is pressed     |  
   '             `-----------------------------------------'
   
   Clear Key : _DO_RECONFIGURING=True : OK=0
   Repeat 
      A$=Upper$(Inkey$)
      If(Scancode=ESC_SCANCODE) or(U_GOES_TO_USERBANK and(A$="U"))
         OK=True
         _DO_RECONFIGURING=False
      Else If A$<>""
         IND=Asc(A$)
         If(IND>48-1) and(IND<48+10)
            Add IND,-48 : OK=True
         Else If(IND>65-1) and(IND<65+10)
            Add IND,-55 : OK=True
         End If 
         
         OK=OK and((GS_TYPE=0) or(Left$(GS_GAME_NAME$(Min(IND,19),GS_TYPE),5)<>NAME_OF_EMPTY_GAME_IN_GAMESET$))
      End If 
   Until OK
   
   '             .-----------------------------------------.
   '             |    Now do the reconfiguring             |  
   '             `-----------------------------------------'
   
   If _DO_RECONFIGURING
      _ONE_PLAYER_GAME=((GS_TYPE=0) and(IND>=10))
      
      If _ONE_PLAYER_GAME
         _LOAD_CONFIGURATION[0] : Rem          BUILTIN CONFIGURATION 

         _PLAYER_TYPE(1)=2
         _PLAYER_TYPE(2)=2
         _PLAYER_TYPE(3)=0
         _PLAYER_TYPE(4)=1
         _PLAYER_TYPE(5)=0
         _PLAYER_TYPE(6)=0

         For _PLAYER=1 To 6
            SELECTED(_PLAYER)=(_PLAYER_TYPE(_PLAYER)>0)
            _TOP_LIVES(_PLAYER)=0
         Next 
         Add IND,-10
         _TOP_LIVES(1)=IND
         If IND>7 : _TOP_LIVES(1)=IND-2
         Else If IND>5 : _TOP_LIVES(1)=IND-1 : End If 
         _TOP_LIVES(2)=IND
         If IND>8 : _TOP_LIVES(2)=IND-2
         Else If IND>6 : _TOP_LIVES(2)=IND-1 : End If 
      Else 
         If GS_TYPE=0
            BASE=Start(DEF_GAMESET__BANK)
         Else 
            BASE=Start(USER_GAMESET__BANK)
         End If 
         C_BASE=BASE+Deek(BASE+2*IND)+$10
         _DECONFIG[C_BASE,True]
         If PLAN=2
            P_LEN=Peek(C_BASE+$20)
            OWN_PLAN_PATH$=Peek$(C_BASE+$21,P_LEN)
         End If 
         If PLAN>0
            SET_PLAN_USING_CONFIG[False]
         End If 
      End If 
   End If 
   
End Proc
Procedure SELECT_GAME
   
   Screen 1 : Get Block 1,0,32,320-32-32,140
   
   If _NOT(U_THRU)
      Screen 2
      Unpack PLAN_BANK(0)
      P0=Phybase(0) : P1=Phybase(1) : P2=Phybase(2) : P3=Phybase(3)
      Copy P1,P1+10240-1 To P0
      Copy P2,P2+10240-1 To P1
      Copy P3,P3+10240-1 To P2
      Fill P3 To P3+10240-1,0
      
      WRITEXY[45+7*5+20,51-10,SELECT_GAME$]
      
      _DO_SELECTION_SCREEN[0]
   End If 
   
   If(A$="U") or U_THRU
      Screen 2
      Unpack PLAN_BANK(0)
      P0=Phybase(0) : P1=Phybase(1) : P2=Phybase(2) : P3=Phybase(3)
      Copy P1,P1+10240-1 To P0
      Copy P2,P2+10240-1 To P1
      Copy P3,P3+10240-1 To P2
      Fill P3 To P3+10240-1,0
      
      WRITEXY[45+7*5+20-7*8,51-10,SELECT_GAME_FROM_USERSET$]
      _DO_SELECTION_SCREEN[1]
      U_THRU=False
   End If 
   
   If(_ONE_PLAYER_GAME=0)
      Screen 2 : Unpack PLAN_BANK(0)
      P0=Phybase(0) : P1=Phybase(1) : P2=Phybase(2) : P3=Phybase(3)
      Copy P1,P1+10240-1 To P0
      Copy P2,P2+10240-1 To P1
      Copy P3,P3+10240-1 To P2
      Fill P3 To P3+10240-1,0
   
      Get Block 1,0,32,320-32-32,140
      SELECTING_PRINT[False]
      Screen 1
   End If 
End Proc
Procedure CREATE_GAMESET[GS__BANK,CONFIG_LIST_NAME$]
   
   '          ________________________________
   '         |                                | 
   '         | Count length to open           | 
   '         |________________________________| 
   
   
   EXTRACT_PATH[CONFIG_LIST_NAME$] : GAMESET_PATH$=Param$
   
   NUMBER_OF_CONFIGS=0
   Open In 1,CONFIG_LIST_NAME$
   
   GAMESET_LENGTH=0
   While Not Eof(1) or(NUMBER_OF_CONFIGS>=20)
      Input #1,F_NAME$ : F_NAME$=GAMESET_PATH$+F_NAME$
      If Exist(F_NAME$)
         Open In 2,F_NAME$
         Add GAMESET_LENGTH,Lof(2)+$10-20
         Inc NUMBER_OF_CONFIGS
         Close 2
      End If 
   Wend 
   Close 1
   Add GAMESET_LENGTH,20*2
   
   '          ________________________________
   '         |                                | 
   '         | Push configs to set            | 
   '         |________________________________| 
   
   If NUMBER_OF_CONFIGS>0
      Reserve As Work GS__BANK,GAMESET_LENGTH
      CONFIG_NUMBER=0
      Open In 1,CONFIG_LIST_NAME$
      GS_BASE=Start(GS__BANK)
      GS_POS=GS_BASE+20*2
      
      For I=GS_BASE To GS_BASE+20*2-1
         Poke I,0
      Next I
      
      While Not Eof(1) or(CONFIG_NUMBER>=20)
         
         Input #1,F_NAME$ : C_NAME$=F_NAME$ : F_NAME$=GAMESET_PATH$+F_NAME$
         
         If Exist(F_NAME$)
            Erase CONFIG_TEMPORARY__BANK
            Load F_NAME$,CONFIG_TEMPORARY__BANK
            
            Doke GS_BASE+2*CONFIG_NUMBER,GS_POS-GS_BASE
            
            C_NAME$=Left$(C_NAME$,$10)
            C_NAME$=C_NAME$+Space$($10-Len(C_NAME$))
            Poke$ GS_POS,C_NAME$ : Add GS_POS,16
            
            BASE=Start(CONFIG_TEMPORARY__BANK)
            TEMP_PLAN=Peek(BASE)+$E
            Copy BASE,BASE+$20-1 To GS_POS : Add GS_POS,$20
            If TEMP_PLAN=2
               P_LEN=Peek(BASE+$20)
               Copy BASE+$20,BASE+$20+P_LEN+1-1 To GS_POS : Add GS_POS,P_LEN+1
            End If 
            
            Inc CONFIG_NUMBER
         End If 
      Wend 
      Close 1
   End If 
End Proc[NUMBER_OF_CONFIGS]

'             ______________________________________   
'            |                                      \    
'            |  @ Rest                               \   
'            |________________________________________\          


Procedure _DO_SOUND[ST]
   ' ST means sound type
   
   If SOUND_FX
      If ST=BOUND_SOUND
         Sam Play SOUND_FX_CHANNEL,2,7500+200*Rnd(5)
      Else If ST=TELEPORT_SOUND
         Sam Play SOUND_FX_CHANNEL,3,16000
      Else If ST=DEATH_SOUND
         Sam Play SOUND_FX_CHANNEL,1,12000
      Else If ST=ARROW_SOUND
         Sam Play SOUND_FX_CHANNEL,3,10000
      Else If ST=PRESS_SPACE_SOUND
      Else If ST=AUCH_SOUND
         Sam Play SOUND_FX_CHANNEL,4,6000+500*Rnd(5)
      Else If ST=BODY_CHANGE_SOUND
         Sam Play SOUND_FX_CHANNEL,5,7000
      End If 
      
      If GAME_MUSIC_PLAYING=0
         SOUND_FX_CHANNEL=_NEXT_SOUND_FX_CHANNEL(SOUND_FX_CHANNEL)
      End If 
   End If 
End Proc

Procedure SET_SPP
   P$=STANDARD_PLAN_PAL$(GAMEPLAN-1)
   For I=0 To $F
      C$="$"+Left$(P$,3) : P$=Mid$(P$,4,Len(P$)-3)
      SPP(I)=Val(C$)
   Next I
End Proc
Procedure FAST_FADE_OUT
   If FAST_INTERFACE
      Wait Vbl 
      Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Clear Key 
      Wait 1
   Else 
      Fade 1
      Wait 13
      Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Wait Vbl : Wait 1
   End If 
End Proc
Procedure LET_IT_SHOW
   Get Block 1,0,0,320,256,1
   Screen 1
   Put Block 1
   Del Block 1
   Screen 2
End Proc

Procedure _COUNT_SELECTED
   HRAJOU=0
   NUMBER_OF_LIVING_HUMANS=0
   For _PLAYER=1 To 6
      If SELECTED(_PLAYER)
         Inc HRAJOU
         If Not COMPUTER_STRATEGY(_PLAYER)
            Inc NUMBER_OF_LIVING_HUMANS
         End If 
      End If 
   Next _PLAYER
   ZIJOU=HRAJOU
End Proc
Procedure SET_APPROPRIATE_DRAWPIXEL_PROC
   _SPRITE_INDEX_BASE=4*BOLDLINE
   
   '   Poke VA_PUTPIX_TYPE,4*(Abs(BIG_SCREEN)*2+Abs(BOLDLINE))
   Poke VA_PUTPIX_TYPE,4*(Sgn(_SCREEN_SIZE)*2+Abs(BOLDLINE))
   
   If BOLDLINE=0
      If _SCREEN_SIZE>0
         PA_CURRENT_PIX=PA_SMALL_PIX_BIGSCREEN
      Else 
         PA_CURRENT_PIX=PA_SMALL_PIX
      End If 
      PA_COUNTTESTANDSPEEDPOINTS=PA_COUNTTESTANDSPEEDPOINTS_1PIX
   Else 
      If _SCREEN_SIZE>0
         PA_CURRENT_PIX=PA_BIG_PIX_BIGSCREEN
      Else 
         PA_CURRENT_PIX=PA_BIG_PIX
      End If 
      PA_COUNTTESTANDSPEEDPOINTS=PA_COUNTTESTANDSPEEDPOINTS_2PIX
   End If 
End Proc
Procedure REALIZE_PLAYER_TYPE
   For _PLAYER=1 To 6
      SELECTED(_PLAYER)=_PLAYER_PROPRIETY(0,_PLAYER_TYPE(_PLAYER))
      COMPUTER_STRATEGY(_PLAYER)=_PLAYER_PROPRIETY(1,_PLAYER_TYPE(_PLAYER))
      CYBORG(_PLAYER)=_PLAYER_PROPRIETY(2,_PLAYER_TYPE(_PLAYER))
   Next _PLAYER
End Proc
Procedure _UPDATE_SCORE
   If TEAM_GAME
      For I=1 To 6
         If ALIVE(I) and(I<>TEAM_MATE(_PLAYER))
            Add SCORE(I),STAYED_ALIVE_BONUS(I)
            Add SCORE(TEAM_MATE(I)),STAYED_ALIVE_BONUS(I)
            If SCORE(I)>GR
               GR=SCORE(I)
               GRP=I
            End If 
         End If 
      Next I
   Else 
      For I=1 To 6
         If ALIVE(I)
            Add SCORE(I),STAYED_ALIVE_BONUS(I)
            If SCORE(I)>GR
               GR=SCORE(I)
               GRP=I
            End If 
         End If 
      Next I
   End If 
End Proc

Procedure MAKE_SCOREPANEL
   Screen 4 : Cls 0
   
   Paste Icon 0,0,1
   Paste Icon 320,0,2
   
   For _PLAYER=1 To 6
      If SELECTED(_PLAYER)
         Paste Icon 60*(_PLAYER-1)+25,0,19
      End If 
   Next _PLAYER
   
   '                      _____________________ 
   '                     |                     |    
   '                     |   Draw Init Lives   |          
   '                     |_____________________|  
   
   If LIVES_ON
      For _PLAYER=1 To 6
         If SELECTED(_PLAYER) and(_TOP_LIVES(_PLAYER)>0)
            For I=1 To _TOP_LIVES(_PLAYER)
               Paste Icon 28+21+25+6+60*(_PLAYER-1)-2,2+(I-1)*4-1,20
               Ink 9+_PLAYER
               Bar 28+21+25+6+60*(_PLAYER-1),2+(I-1)*4 To 4+28+21+25+6+60*(_PLAYER-1),2+(I-1)*4+1
            Next I
         End If 
      Next _PLAYER
   End If 
   
   Screen Copy 4 To 3
End Proc
Procedure _DRAW_SCORE
   If Not(REPLAY_ALL_SAVED_ON) and 0
      Screen 4
      For I=1 To 6
         If SEMIALIVE(I) or SEMIALIVE(TEAM_MATE(I))
            If SCORE(I)>=10
               Paste Icon 25+6+60*(I-1),3,12+I
               Paste Icon 25+6+60*(I-1),3,SCORE(I)/10+3
            End If 
            Paste Icon 25+6+60*(I-1)+21,3,12+I
            Paste Icon 25+6+60*(I-1)+21,3,SCORE(I) mod 10+3
         End If 
      Next I
      Screen 1
   End If 
   Screen Copy 4 To 3
End Proc
Procedure _DRAW_SMALL_WOOD_FRAME
   Paste Bob 0,0,HORIZONTAL_WOOD_IMAGE+$4000
   Paste Bob 160,0,HORIZONTAL_WOOD_IMAGE+$4000
   Paste Bob 0,0,NOSCROLL_CORNER_IMAGE
   Paste Bob 320-16,0,NOSCROLL_CORNER_IMAGE+$8000
   Paste Bob 0,256-30-4-2,HORIZONTAL_WOOD_IMAGE
   Paste Bob 160,256-30-4-2,HORIZONTAL_WOOD_IMAGE
   Paste Bob 0,256-30-4-2,NOSCROLL_CORNER_IMAGE+$4000
   Paste Bob 320-16,256-30-4-2,NOSCROLL_CORNER_IMAGE+$8000+$4000
   
   Paste Bob 0,4,VERTICAL_WOOD_IMAGE
   Paste Bob 320-16,4,VERTICAL_WOOD_IMAGE+$8000
End Proc
Procedure _DRAW_WINNER_WOOD_FRAME[DS_HEIGHT]
   Paste Bob 0,0,HORIZONTAL_WOOD_IMAGE+$4000
   Paste Bob 160,0,HORIZONTAL_WOOD_IMAGE+$4000
   Paste Bob 0,0,NOSCROLL_CORNER_IMAGE
   Paste Bob 320-16,0,NOSCROLL_CORNER_IMAGE+$8000
   Paste Bob 0,DS_HEIGHT-4,HORIZONTAL_WOOD_IMAGE
   Paste Bob 160,DS_HEIGHT-4,HORIZONTAL_WOOD_IMAGE
   Paste Bob 0,4,VERTICAL_WOOD_IMAGE
   Paste Bob 320-16,4,VERTICAL_WOOD_IMAGE+$8000
   Paste Bob 0,DS_HEIGHT-4,NOSCROLL_CORNER_IMAGE+$4000
   Paste Bob 320-16,DS_HEIGHT-4,NOSCROLL_CORNER_IMAGE+$8000+$4000
End Proc

Procedure EDGES_FOR_BOUNCING
   If(X_WORK#<_LEFT_LIMIT) or(X_WORK#>_RIGHT_LIMIT)
      SMER(_PLAYER)=SMERU-SMER(_PLAYER)
      _DO_SOUND[BOUND_SOUND]
      RECALCULATE_ANGLE=True
      BOUND_THIS_ROUND(_PLAYER)=True
      BOUND_COUNTER(_PLAYER)=3
   End If 
   If(Y_WORK#<_UP_LIMIT) or(Y_WORK#>_DOWN_LIMIT)
      SMER(_PLAYER)=SMERU/2-SMER(_PLAYER)
      If SMER(_PLAYER)<0
         Add SMER(_PLAYER),SMERU
      End If 
      _DO_SOUND[BOUND_SOUND]
      RECALCULATE_ANGLE=True
      BOUND_THIS_ROUND(_PLAYER)=True
      BOUND_COUNTER(_PLAYER)=3
   End If 
   
   If CENTRAL_BOX=1
      If(((X_WORK=XBOTTOM) or(X_WORK=XTOP)) and(Y_WORK>=YBOTTOM) and(Y_WORK<=YTOP))
         SMER(_PLAYER)=SMERU-SMER(_PLAYER)
         _DO_SOUND[BOUND_SOUND]
         RECALCULATE_ANGLE=True
         BOUND_THIS_ROUND(_PLAYER)=True
         BOUND_COUNTER(_PLAYER)=3
      End If 
      If(((Y_WORK=YBOTTOM) or(Y_WORK=YTOP)) and(X_WORK>=XBOTTOM) and(X_WORK<=XTOP))
         SMER(_PLAYER)=SMERU/2-SMER(_PLAYER)
         If SMER(_PLAYER)<0
            Add SMER(_PLAYER),SMERU
         End If 
         _DO_SOUND[BOUND_SOUND]
         RECALCULATE_ANGLE=True
         BOUND_THIS_ROUND(_PLAYER)=True
         BOUND_COUNTER(_PLAYER)=3
      End If 
   End If 
   
End Proc
Procedure EDGES_STANDARD
   If(X_WORK#<_LEFT_LIMIT) or(X_WORK#>_RIGHT_LIMIT) or(Y_WORK#<_UP_LIMIT) or(Y_WORK#>_DOWN_LIMIT)
      _PLAYER_KILLED
   End If 
   If CENTRAL_BOX=1
      If((X_WORK=XBOTTOM) and(Y_WORK>YBOTTOM) and(Y_WORK<YTOP)) or((X_WORK=XTOP) and(Y_WORK>YBOTTOM) and(Y_WORK<YTOP))
         _PLAYER_KILLED
      End If 
      If((Y_WORK=YBOTTOM) and(X_WORK>XBOTTOM) and(X_WORK<XTOP)) or((Y_WORK=YTOP) and(X_WORK>XBOTTOM) and(X_WORK<XTOP))
         _PLAYER_KILLED
      End If 
   End If 
End Proc
Procedure EDGES_FOR_TELEPORTING
   If X_WORK#<_LEFT_LIMIT
      X#(_PLAYER)=_RIGHT_LIMIT
      
      If(Point(_RIGHT_LIMIT-0.5,Y#(_PLAYER))>$10) or(Point(_RIGHT_LIMIT-1.5,Y#(_PLAYER))>$10)
         _PLAYER_KILLED__TESTED_ON_LIVES
      End If 
      
      _DO_SOUND[TELEPORT_SOUND]
      RECALCULATE_COORDINATES=True
   Else If X_WORK#>_RIGHT_LIMIT
      X#(_PLAYER)=_LEFT_LIMIT
      
      If(Point(_LEFT_LIMIT,Y#(_PLAYER))>$10) or(Point(_LEFT_LIMIT+1,Y#(_PLAYER))>$10)
         _PLAYER_KILLED__TESTED_ON_LIVES
      End If 
      
      _DO_SOUND[TELEPORT_SOUND]
      RECALCULATE_COORDINATES=True
   End If 
   If Y_WORK#<_UP_LIMIT
      Y#(_PLAYER)=_DOWN_LIMIT
      
      If(Point(X#(_PLAYER),_DOWN_LIMIT-0.5)>$10) or(Point(X#(_PLAYER),_DOWN_LIMIT-1.5)>$10)
         _PLAYER_KILLED__TESTED_ON_LIVES
      End If 
      
      _DO_SOUND[TELEPORT_SOUND]
      RECALCULATE_COORDINATES=True
   Else If Y_WORK#>_DOWN_LIMIT
      Y#(_PLAYER)=_UP_LIMIT
      
      If(Point(X#(_PLAYER),_UP_LIMIT)>$10) or(Point(X#(_PLAYER),_UP_LIMIT+1)>$10)
         _PLAYER_KILLED__TESTED_ON_LIVES
      End If 
      
      _DO_SOUND[TELEPORT_SOUND]
      RECALCULATE_COORDINATES=True
   End If 
   
   If CENTRAL_BOX=1
      If(X_WORK=XBOTTOM) and(Y_WORK>YBOTTOM) and(Y_WORK<YTOP)
         X#(_PLAYER)=XTOP+1
         
         If(Point(XTOP+1,Y#(_PLAYER))>$10) or(Point(XTOP+1+1,Y#(_PLAYER))>$10)
            _PLAYER_KILLED__TESTED_ON_LIVES
         End If 
         
         _DO_SOUND[TELEPORT_SOUND]
         RECALCULATE_COORDINATES=True
      Else If(X_WORK=XTOP) and(Y_WORK>YBOTTOM) and(Y_WORK<YTOP)
         X#(_PLAYER)=XBOTTOM
         
         If(Point(XBOTTOM-0.5,Y#(_PLAYER))>$10) or(Point(XBOTTOM-1.5,Y#(_PLAYER))>$10)
            _PLAYER_KILLED__TESTED_ON_LIVES
         End If 
         
         _DO_SOUND[TELEPORT_SOUND]
         RECALCULATE_COORDINATES=True
      End If 
      If(Y_WORK=YBOTTOM) and(X_WORK>XBOTTOM) and(X_WORK<XTOP)
         Y#(_PLAYER)=YTOP+1
         
         If(Point(X#(_PLAYER),YTOP+1)>$10) or(Point(X#(_PLAYER),YTOP+1+1)>$10)
            _PLAYER_KILLED__TESTED_ON_LIVES
         End If 
         
         _DO_SOUND[TELEPORT_SOUND]
         RECALCULATE_COORDINATES=True
      End If 
      If(Y_WORK=YTOP) and(X_WORK>XBOTTOM) and(X_WORK<XTOP)
         Y#(_PLAYER)=YBOTTOM
         
         If(Point(X#(_PLAYER),YBOTTOM-0.5)>$10) or(Point(X#(_PLAYER),YBOTTOM-1.5)>$10)
            _PLAYER_KILLED__TESTED_ON_LIVES
         End If 
         
         _DO_SOUND[TELEPORT_SOUND]
         RECALCULATE_COORDINATES=True
      End If 
   End If 
End Proc
Procedure EDGES_FOR_WATERING
   CAST_TYPE=0
   If(X_WORK#<_LEFT_LIMIT) or(X_WORK#>_RIGHT_LIMIT)
      CAST_TYPE=1
   End If 
   If(Y_WORK#<_UP_LIMIT) or(Y_WORK#>_DOWN_LIMIT)
      CAST_TYPE=2
      Goto EW_FOUND
   End If 
   
   If CENTRAL_BOX=1
      If(((X_WORK=XBOTTOM) or(X_WORK=XTOP)) and(Y_WORK>=YBOTTOM) and(Y_WORK<=YTOP))
         CAST_TYPE=1
      End If 
      If(((Y_WORK=YBOTTOM) or(Y_WORK=YTOP)) and(X_WORK>=XBOTTOM) and(X_WORK<=XTOP))
         CAST_TYPE=2
      End If 
   End If 
   
   '~~~~~~ Uz vime kde prekroceno ~~~~~~
   EW_FOUND:
   
   If CAST_TYPE>0
      
      ANGLE_MAKER=SMER(_PLAYER) mod SMERU_HALVE
      
      '~~~~~~ Special transformation ~~~~~~  
      
      _REVERSE_CAST=(ANGLE_MAKER<SMERU_QUARTER)
      If CAST_TYPE=1
         _REVERSE_CAST= Not _REVERSE_CAST
      End If 
      
      ANGLE_MAKER=ANGLE_MAKER mod SMERU_QUARTER
      If _REVERSE_CAST
         ANGLE_MAKER=SMERU_QUARTER-ANGLE_MAKER
      End If 
      
      If ANGLE_MAKER*ANGLE_CONSTANT#<WATER_LIMIT#
         EDGES_FOR_BOUNCING
      Else 
         EDGES_FOR_TELEPORTING
      End If 
   End If 
End Proc

Procedure _PLAYER_KILLED
   _PUTPIX_QUEUE_X(_PUTPIX_QUEUE_TOP)=X#(_PLAYER)
   _PUTPIX_QUEUE_Y(_PUTPIX_QUEUE_TOP)=Y#(_PLAYER)
   _PUTPIX_QUEUE_COLOUR(_PUTPIX_QUEUE_TOP)=$10+_PLAYER
   Inc _PUTPIX_QUEUE_TOP
   
   If ZOMBIES
      If ZOMBIE(_PLAYER)
         Inc LINE_LENGTH_(_PLAYER)
         Inc SPACE_LENGTH_(_PLAYER)
         SPACE_COUNTER(_PLAYER)=SPACE_LENGTH_(_PLAYER)
      Else 
         _DO_SOUND[DEATH_SOUND]
         ALIVE(_PLAYER)=_FALSE
         ZOMBIE(_PLAYER)=_TRUE
         Dec ZIJOU
         _UPDATE_SCORE
         _DRAW_SCORE
         LINE_LENGTH_(_PLAYER)=1
         SPACE_LENGTH_(_PLAYER)=15
         LINE_COUNTER(_PLAYER)=LINE_LENGTH_(_PLAYER)+20-SPACE_LENGTH_(_PLAYER)+30
         SPACE_COUNTER(_PLAYER)=SPACE_LENGTH_(_PLAYER)
      End If 
   Else 
      _DO_SOUND[DEATH_SOUND]
      SEMIALIVE(_PLAYER)=_FALSE
      ALIVE(_PLAYER)=_FALSE
      Dec ZIJOU
      Dec NUMBER_OF_SEMIALIVES
      If GO_FOR_COMPUTURBO
         If(COMPUTER_STRATEGY(_PLAYER)=False)
            Dec NUMBER_OF_LIVING_HUMANS
            If NUMBER_OF_LIVING_HUMANS=0
               GO_FOR_COMPUTURBO=_FALSE
               DIE_COMPUTERS=COMPUDEATH
               TURBOLIMIT=-1
            End If 
         End If 
      End If 
      NS=_SPRITE_NUMBER(_PLAYER)
      If(_SCREEN_SIZE=0) or(NS<4)
         Sprite Off _SPRITE_NUMBER(_PLAYER)
      Else 
         Bob Off _PLAYER-2
      End If 
      _UPDATE_SCORE
      _DRAW_SCORE
   End If 
End Proc
Procedure _PLAYER_KILLED__TESTED_ON_LIVES
   If LIVES_ON and(LIVES(_PLAYER)>0)
      _DO_SOUND[AUCH_SOUND]
      
      Screen 3
      Ink 0
      Bar 28+21+25+6+60*(_PLAYER-1),2+(LIVES(_PLAYER)-1)*4 To 4+28+21+25+6+60*(_PLAYER-1),2+(LIVES(_PLAYER)-1)*4+1
      Screen 4
      Ink 0
      Bar 28+21+25+6+60*(_PLAYER-1),2+(LIVES(_PLAYER)-1)*4 To 4+28+21+25+6+60*(_PLAYER-1),2+(LIVES(_PLAYER)-1)*4+1
      Screen 1
      
      '      Dreg(0)=278 : Dreg(1)=LIVES(_PLAYER)*3-1+(_PLAYER-1)*43 : Dreg(2)=0 
      '      Call(PA_BIG_PIX)
      
      Dec LIVES(_PLAYER)
      AUCH_PROTECTION(_PLAYER)=True
      AUCH_COUNTER(_PLAYER)=30
      LINE_COUNTER(_PLAYER)=LINE_LENGTH_(_PLAYER)+20-SPACE_LENGTH_(_PLAYER)+30
      SPACE_COUNTER(_PLAYER)=30
   Else 
      _PLAYER_KILLED
   End If 
End Proc

Procedure GAME
   
   If ESC
      Goto _FADE_OUT
   End If 
   
   If GAME_MUSIC_PLAYING
      Volume 0
      For I=0 To 40 Step 5 : Volume I : Wait Vbl : Next I
   Else 
      Volume 40
   End If 
   Make Mask 
   
   If J_REPLAYING_OR_J_RECORDING
      Loke VA_GAME_RECORD_POINTER,0
   End If 
   
   '<<<<<<<<<<<<<<<< Main Loop >>>>>>>>>>>>>>>> 
   
   CYCLES=0
   
   Repeat 
      Timer=0
      If JUST_REPLAYING
         Call(PA_LOAD_POSITION)
      End If 
      
      _PUTPIX_QUEUE_TOP=0
      
      For _PLAYER=1 To 6
         If SEMIALIVE(_PLAYER)
            
            
            '     ---------------- Care About Spaces --------------- 
            
            
            Dec LINE_COUNTER(_PLAYER)
            If LINE_COUNTER(_PLAYER)=0
               If J_REPLAYING_OR_J_RECORDING or ZOMBIE(_PLAYER)
                  LINE_COUNTER(_PLAYER)=LINE_LENGTH_(_PLAYER)+20
               Else 
                  LINE_COUNTER(_PLAYER)=LINE_LENGTH_(_PLAYER)+Rnd(40)-20
               End If 
               SPACE_COUNTER(_PLAYER)=SPACE_LENGTH_(_PLAYER)
            End If 
            
            If AUCH_PROTECTION(_PLAYER)
               Dec AUCH_COUNTER(_PLAYER)
               If AUCH_COUNTER(_PLAYER)=0
                  AUCH_PROTECTION(_PLAYER)=False
                  GAME_SLOWED=_FALSE
               End If 
            End If 
            
            
            '     ---------------- Compute New position -------------              
            
            
            If WIND
               TIMES_CONSTANT#=SPEED_PERCENT#(_PLAYER)*RATE#*WIND_FACTOR#(_PLAYER)
            Else 
               TIMES_CONSTANT#=SPEED_PERCENT#(_PLAYER)*RATE#
            End If 
            
            '          ________________
            '         |                |   
            '         | count sin+cos  |     
            '         |________________|   
            
            Dreg(0)=SMER(_PLAYER)
            Call(PA_COUNTSINANDCOS)
            Loke Varptr(_SIN_ANGLE#),Dreg(0)
            Loke Varptr(_COS_ANGLE#),Dreg(2)
            
            _SIN_KRAT_TIMES_CONSTANT#=_SIN_ANGLE#*TIMES_CONSTANT#
            _COS_KRAT_TIMES_CONSTANT#=_COS_ANGLE#*TIMES_CONSTANT#
            
            X_WORK#=X#(_PLAYER)+_SIN_KRAT_TIMES_CONSTANT#
            Y_WORK#=Y#(_PLAYER)+_COS_KRAT_TIMES_CONSTANT#
            X_WORK=X_WORK#
            Y_WORK=Y_WORK#
            
            RECALCULATE_ANGLE=False
            RECALCULATE_COORDINATES=False
            
            If BOUNCING
               EDGES_FOR_BOUNCING
            Else If TELEPORTING
               EDGES_FOR_TELEPORTING
            Else If WATERING
               EDGES_FOR_WATERING
            Else 
               EDGES_STANDARD
            End If 
            
            If BOUND_THIS_ROUND(_PLAYER)
               Dec BOUND_COUNTER(_PLAYER)
               If BOUND_COUNTER(_PLAYER)=0
                  BOUND_THIS_ROUND(_PLAYER)=False
               End If 
            End If 
            
            '          ________________________________
            '         |                                | 
            '         | Count test and speed points    | 
            '         |________________________________| 
            
            Dreg(0)=SMER(_PLAYER)
            Areg(1)=Leek(Varptr(X#(_PLAYER)))
            Areg(2)=Leek(Varptr(Y#(_PLAYER)))
            Call(PA_COUNTTESTANDSPEEDPOINTS)
            Loke Varptr(X_TESTPOINT),Dreg(0)
            Loke Varptr(Y_TESTPOINT),Dreg(1)
            Loke Varptr(X_SPEEDPOINT),Areg(1)
            Loke Varptr(Y_SPEEDPOINT),Areg(2)
            
            '          ________________________________
            '         |                                | 
            '         | Ted uloz do x#,y# novou posici | 
            '         |________________________________| 
            
            If RECALCULATE_ANGLE
               Dreg(0)=SMER(_PLAYER)
               Call(PA_COUNTSINANDCOS)
               Loke Varptr(_SIN_ANGLE#),Dreg(0)
               Loke Varptr(_COS_ANGLE#),Dreg(2)
               X#(_PLAYER)=X#(_PLAYER)+_SIN_ANGLE#*TIMES_CONSTANT#
               Y#(_PLAYER)=Y#(_PLAYER)+_COS_ANGLE#*TIMES_CONSTANT#
            Else If RECALCULATE_COORDINATES
               X#(_PLAYER)=X#(_PLAYER)+_SIN_KRAT_TIMES_CONSTANT#
               Y#(_PLAYER)=Y#(_PLAYER)+_COS_KRAT_TIMES_CONSTANT#
            Else 
               X#(_PLAYER)=X_WORK#
               Y#(_PLAYER)=Y_WORK#
            End If 
            
            '     .-------------------------------------------------------.
            '     |                 What's under head?                    |
            '     `-------------------------------------------------------'
            
            TEST_POINT=Point(X_TESTPOINT,Y_TESTPOINT)
            SPEED_POINT=Point(X_SPEEDPOINT,Y_SPEEDPOINT)
            
            If TEST_POINT>$10
               If BOUND_THIS_ROUND(_PLAYER)
                  If(TEST_POINT<>($10+_PLAYER)) and(TEST_POINT<$18) and(SPACE_COUNTER(_PLAYER)<(SPACE_LENGTH+10)*SPACE_KILL) and(AUCH_PROTECTION(_PLAYER)=_FALSE)
                     _PLAYER_KILLED__TESTED_ON_LIVES
                  End If 
               Else If TEAM_GAME
                  If(TEST_POINT<$18) and(SPACE_COUNTER(_PLAYER)<(SPACE_LENGTH+10)*SPACE_KILL) and(AUCH_PROTECTION(_PLAYER)=False) and((TEST_POINT=TEAM_MATE_THRU(_PLAYER))=False)
                     _PLAYER_KILLED__TESTED_ON_LIVES
                  End If 
               Else 
                  If(TEST_POINT<$18) and(SPACE_COUNTER(_PLAYER)<(SPACE_LENGTH+10)*SPACE_KILL) and(AUCH_PROTECTION(_PLAYER)=False)
                     _PLAYER_KILLED__TESTED_ON_LIVES
                  End If 
               End If 
            End If 
            
            If DIE_COMPUTERS and COMPUTER_STRATEGY(_PLAYER)
               _PLAYER_KILLED__TESTED_ON_LIVES
            End If 
            
            If SPEED_POINT<$10
               SPEED_PERCENT#(_PLAYER)=SPEED_SOURCE#(SPEED_POINT)
            End If 
            
            If Not SEMIALIVE(_PLAYER)
               Goto DEAD
            End If 
            
            '     .-------------------------------------------------------.
            '     |                 Umisti sprita                         |
            '     `-------------------------------------------------------'
            
            NS=_SPRITE_NUMBER(_PLAYER)
            
            If _SCREEN_SIZE>0
               If NS<4
                  NI=_SPRITE_IMAGE(_PLAYER)
                  _SPRITE_Y=Y#(_PLAYER)+42-_VIEWED_AREA_Y
                  If _SPRITE_Y>(256-36+42-2)
                     Sprite Off NS
                  Else 
                     Sprite NS,X#(_PLAYER)+X Hard(0)-_VIEWED_AREA_X,_SPRITE_Y,NI+_SPRITE_INDEX_BASE
                  End If 
               Else 
                  Bob _PLAYER-2,X#(_PLAYER),Y#(_PLAYER),
               End If 
            Else 
               Sprite NS,X#(_PLAYER)+X Hard(0),Y#(_PLAYER)+42,
            End If 
            
            
            Dec SPACE_COUNTER(_PLAYER)
            If(SPACE_COUNTER(_PLAYER)<0)
               _PUTPIX_QUEUE_X(_PUTPIX_QUEUE_TOP)=X#(_PLAYER)
               _PUTPIX_QUEUE_Y(_PUTPIX_QUEUE_TOP)=Y#(_PLAYER)
               _PUTPIX_QUEUE_COLOUR(_PUTPIX_QUEUE_TOP)=$10+_PLAYER
               Inc _PUTPIX_QUEUE_TOP
            End If 
            
            '     .-------------------------------------------------------.
            '     |            Player or Computer input                   |
            '     `-------------------------------------------------------'
            
            If JUST_REPLAYING
               LEFT_PUSHED=(_PLAYER_RECORD(_PLAYER-1)=1)
               RIGHT_PUSHED=(_PLAYER_RECORD(_PLAYER-1)=2)
            Else If CYBORG(_PLAYER)
               Clear Key 
               
               On _PLAYER Goto C1,C2,C3,C4,C5,C6
               
               C1: RIGHT_PUSHED=Key State(66)
               LEFT_PUSHED=Key State(0) : Goto C_END
               C2: RIGHT_PUSHED=(Key Shift and $40)
               LEFT_PUSHED=(Key Shift and $10) : Goto C_END
               C3: RIGHT_PUSHED=Key State(54) or Jright(1)
               LEFT_PUSHED=Key State(53) or Jleft(1) : Goto C_END
               C4: RIGHT_PUSHED=(Key Shift and $20)
               LEFT_PUSHED=(Key Shift and $80) : Goto C_END
               C5: RIGHT_PUSHED=Key State(95) or(Mouse Key and 2)
               LEFT_PUSHED=Key State(70) or(Mouse Key and 1) : Goto C_END
               C6: RIGHT_PUSHED=Key State(63)
               LEFT_PUSHED=Key State(47)
               C_END:
               
               If Not(RIGHT_PUSHED or LEFT_PUSHED)
                  PRUMER_CHANGE#=(1+TIMES_CONSTANT#)/2
                  
                  Loke VA_DIRECTION,SMER(_PLAYER)
                  Loke VA_XAMOSREAL,Leek(Varptr(X#(_PLAYER)))
                  Loke VA_YAMOSREAL,Leek(Varptr(Y#(_PLAYER)))
                  Loke VA_ROTATION,(SMERU_QUARTER*PRUMER_CHANGE#+2)
                  Loke VA_PLAYER,(_PLAYER-1)
                  
                  Call(PA_STRATEGY)
                  LEFT_PUSHED=(Dreg(7)=1)
                  RIGHT_PUSHED=(Dreg(7)=2)
               End If 
            Else If COMPUTER_STRATEGY(_PLAYER)
               PRUMER_CHANGE#=(1+TIMES_CONSTANT#)/2
               
               Loke VA_DIRECTION,SMER(_PLAYER)
               Loke VA_XAMOSREAL,Leek(Varptr(X#(_PLAYER)))
               Loke VA_YAMOSREAL,Leek(Varptr(Y#(_PLAYER)))
               Loke VA_ROTATION,(SMERU_QUARTER*PRUMER_CHANGE#+2)
               Loke VA_PLAYER,(_PLAYER-1)
               
               Call(PA_STRATEGY)
               LEFT_PUSHED=(Dreg(7)=1)
               RIGHT_PUSHED=(Dreg(7)=2)
               
            Else 
               Clear Key 
               
               On _PLAYER Goto L1,L2,L3,L4,L5,L6
               
               L1: RIGHT_PUSHED=Key State(66)
               LEFT_PUSHED=Key State(0) : Goto L_END
               L2: RIGHT_PUSHED=(Key Shift and $40)
               LEFT_PUSHED=(Key Shift and $10) : Goto L_END
               L3: RIGHT_PUSHED=Key State(54) or Jright(1)
               LEFT_PUSHED=Key State(53) or Jleft(1) : Goto L_END
               L4: RIGHT_PUSHED=(Key Shift and $20)
               LEFT_PUSHED=(Key Shift and $80) : Goto L_END
               L5: RIGHT_PUSHED=Key State(95) or(Mouse Key and 2)
               LEFT_PUSHED=Key State(70) or(Mouse Key and 1) : Goto L_END
               L6: RIGHT_PUSHED=Key State(63)
               LEFT_PUSHED=Key State(47)
               L_END:
            End If 
            
            '!!!!!!!!!!!! Future FIRE !!!!!!!! 
            If(LEFT_PUSHED and RIGHT_PUSHED)
               LEFT_PUSHED=False
               RIGHT_PUSHED=False
            End If 
            
            _PLAYER_MOVE=0
            If ALWAYS_TURNING=1
               If LEFT_PUSHED
                  TURNING(_PLAYER)=1
               End If 
               If RIGHT_PUSHED
                  TURNING(_PLAYER)=2
               End If 
               
               If TURNING(_PLAYER)=1
                  Add SMER(_PLAYER),1,0 To SMERU-1
               End If 
               If TURNING(_PLAYER)=2
                  Add SMER(_PLAYER),-1,0 To SMERU-1
               End If 
               
               If JUST_RECORDING
                  _PLAYER_MOVE=TURNING(_PLAYER)
               End If 
               
            Else 
               If LEFT_PUSHED
                  Add SMER(_PLAYER),1,0 To SMERU-1
                  _PLAYER_MOVE=1
               End If 
               If RIGHT_PUSHED
                  Add SMER(_PLAYER),-1,0 To SMERU-1
                  _PLAYER_MOVE=2
               End If 
            End If 
            
            '     .-------------------------------------------------------.
            '     |           Change directions according to wind         |
            '     `-------------------------------------------------------'
            
            If WIND
               TEMP_ANGLE=SMER(_PLAYER)-WIND_ANGLE
               If TEMP_ANGLE<0
                  Add TEMP_ANGLE,SMERU
               End If 
               Dreg(0)=TEMP_ANGLE : Call(PA_COUNTSINANDCOS)
               Loke Varptr(_SIN_ANGLE#),Dreg(0)
               Loke Varptr(_COS_ANGLE#),Dreg(2)
               SIGN=Sgn(_SIN_ANGLE#) : _SIN_ANGLE#=Abs(_SIN_ANGLE#)
               A=Rnd(999)
               If A<Int(WIND_STRENGTH#*_SIN_ANGLE#*1000.0)
                  Add SMER(_PLAYER),SIGN,0 To SMERU-1
               End If 
               WIND_FACTOR#(_PLAYER)=Sqr(1.0-WIND_STRENGTH#*_COS_ANGLE#)
            End If 
            
            If JUST_RECORDING
               _PLAYER_RECORD(_PLAYER-1)=_PLAYER_MOVE
            End If 
            
            DEAD:
         End If 
      Next _PLAYER
      
      If _BOBS_USED
         Bob Clear 
         Call(PA_DRAW_PIXEL_QUEUE)
         Bob Draw 
      Else 
         Call(PA_DRAW_PIXEL_QUEUE)
      End If 
      
      If GAME_SLOWED
         Repeat : Until Timer>2
      Else 
         Repeat : Until Timer>TURBOLIMIT
      End If 
      
      If JUST_RECORDING
         Call(PA_SAVE_POSITION)
      End If 
      
      '          ________________________________
      '         |                                | 
      '         | Viewed area possition          | 
      '         |________________________________| 
      
      
      If _SCREEN_SIZE>0
         X_SUM=0 : Y_SUM=0 : SUM_NUM=0
         For I=1 To 6
            If SEMIALIVE(I) and(_PLAYER_TYPE(I)=1)
               X_SUM=X_SUM+Int(X#(I))
               Y_SUM=Y_SUM+Int(Y#(I))
               Inc SUM_NUM
            End If 
         Next I
         If SUM_NUM=0
            For I=1 To 6
               If SEMIALIVE(I)
                  X_SUM=X_SUM+Int(X#(I))
                  Y_SUM=Y_SUM+Int(Y#(I))
                  Inc SUM_NUM
               End If 
            Next I
         End If 
         
         If SUM_NUM>0
            X_SUM=(X_SUM/SUM_NUM)-160
            Y_SUM=(Y_SUM/SUM_NUM)-110
         End If 
         
         D_X0=X_SUM-_VIEWED_AREA_X
         D_Y0=Y_SUM-_VIEWED_AREA_Y
         
         X_SUM=Max(X_SUM,0)
         Y_SUM=Max(Y_SUM,0)
         X_SUM=Min(X_SUM,X_SCROLL_LIMIT)
         Y_SUM=Min(Y_SUM,Y_SCROLL_LIMIT)
         D_X=X_SUM-_VIEWED_AREA_X
         D_Y=Y_SUM-_VIEWED_AREA_Y
         
         If _NOT(_DO_X_SCROLL) and(Abs(D_X0)>20)
            _DO_X_SCROLL=_TRUE
         End If 
         
         If _NOT(_DO_Y_SCROLL) and(Abs(D_Y0)>20)
            _DO_Y_SCROLL=_TRUE
         End If 
         
         If _DO_X_SCROLL
            If(Abs(D_X)>0)
               _VIEWED_AREA_X=_VIEWED_AREA_X+Sgn(D_X)
            Else 
               _DO_X_SCROLL=_FALSE
            End If 
         End If 
         
         If _DO_Y_SCROLL
            If(Abs(D_Y)>0)
               _VIEWED_AREA_Y=_VIEWED_AREA_Y+Sgn(D_Y)
            Else 
               _DO_Y_SCROLL=_FALSE
            End If 
         End If 
         
         Screen Offset 1,_VIEWED_AREA_X,_VIEWED_AREA_Y
         
      End If 
      
      '          ________________________________
      '         |                                | 
      '         | Care about rate                | 
      '         |________________________________| 
      
      
      If STILL_SPEEDING_UP
         RATE#=RATE#+RATEJUMP#
         _MUSIC_TEMPO#=_MUSIC_TEMPO#+_MUSIC_TEMPO_JUMP#
         Tempo _MUSIC_TEMPO#
         
         If RATE#>=FINAL_RATE#
            STILL_SPEEDING_UP=False
         End If 
      End If 
      
      '          ________________________________
      '         |                                | 
      '         | Body Change                    | 
      '         |________________________________| 
      
      If BODY_CHANGE and(ZIJOU>1)
         Dec BODY_CHANGE_COUNTER
         If BODY_CHANGE_COUNTER<0
            BODY_CHANGE_COUNTER=(_EXPECTED_GAME_LENGTH*BODY_CHANGE_PERCENT)/200+Rnd((_EXPECTED_GAME_LENGTH*BODY_CHANGE_PERCENT)/100)
            BODY_CHANGE_COUNTER=Max(BODY_CHANGE_COUNTER,100)
            
            _DO_SOUND[BODY_CHANGE_SOUND]
            
            GAME_SLOWED=_TRUE
            
            '         ------- make list of living players ---------- 
            
            LIVING_PLAYER=1
            _PLAYER=1
            While LIVING_PLAYER<=ZIJOU
               If ALIVE(_PLAYER)
                  LIVING_PLAYER(LIVING_PLAYER)=_PLAYER
                  Inc LIVING_PLAYER
               End If 
               Inc _PLAYER
            Wend 
            
            '         ---------- Permute living players ---------- 
            
            Repeat 
               CORRECT=_TRUE
               For _PLAYER=1 To ZIJOU
                  _FREE_VALUE(_PLAYER)=_TRUE
               Next 
               _PLAYER=1
               While(_PLAYER<=ZIJOU) and CORRECT
                  P=(Rnd(ZIJOU-1) mod(ZIJOU-_PLAYER+1))+1
                  I=0
                  Repeat 
                     Inc I
                     If _FREE_VALUE(I) : Dec P : End If 
                  Until P=0
                  _FREE_VALUE(I)=_FALSE
                  NEW_PLAYER(_PLAYER)=I
                  CORRECT=CORRECT and(I<>_PLAYER)
                  Inc _PLAYER
               Wend 
            Until CORRECT
            
            '         ---------- swap x,y,smer  ----------               
            
            For LIVING_PLAYER=1 To ZIJOU
               _PLAYER=LIVING_PLAYER(LIVING_PLAYER)
               NEW_PLAYER=LIVING_PLAYER(NEW_PLAYER(LIVING_PLAYER))
               
               AUCH_PROTECTION(_PLAYER)=True
               AUCH_COUNTER(_PLAYER)=50
               LINE_COUNTER(_PLAYER)=LINE_LENGTH+20
               
               
               NEW_X#(_PLAYER)=X#(NEW_PLAYER)
               NEW_Y#(_PLAYER)=Y#(NEW_PLAYER)
               NEW_SMER(_PLAYER)=SMER(NEW_PLAYER)
            Next 
            
            For _PLAYER=1 To 6
               If ALIVE(_PLAYER)
                  X#(_PLAYER)=NEW_X#(_PLAYER)
                  Y#(_PLAYER)=NEW_Y#(_PLAYER)
                  SMER(_PLAYER)=NEW_SMER(_PLAYER)
               End If 
            Next _PLAYER
         End If 
      End If 
      
      If WIND_TURNING
         If Rnd(999)<2
            Add WIND_ANGLE,1,0 To SMERU-1
         End If 
      End If 
      
      ESC=ESC or Key State(ESC_SCANCODE)
      
      Inc CYCLES
      Poke VA_TURN,Peek(VA_TURN) xor 1
   Until(ZIJOU<2) or ESC
   
   '          ________________________________
   '         |                                | 
   '         | All players are dead           | 
   '         |________________________________| 
   
   For _PLAYER=1 To 6
      If ZOMBIE(_PLAYER)
         NS=_SPRITE_NUMBER(_PLAYER)
         If(_SCREEN_SIZE=0) or(NS<4)
            Sprite Off _SPRITE_NUMBER(_PLAYER)
         Else 
            Bob Off _PLAYER-2
         End If 
      End If 
   Next _PLAYER
   
   
   
   WIN=_FALSE
   If GR>=_TOPSCORE
      WIN=_TRUE
      For I=1 To 6
         If TEAM_GAME
            WIN=WIN and((I=GRP) or(I=TEAM_MATE(GRP)) or(SCORE(I)<>GR))
         Else 
            WIN=WIN and((I=GRP) or(SCORE(I)<>GR))
         End If 
      Next I
   End If 
   
   If GAME_MUSIC_PLAYING
      For I=40 To 0 Step -1 : Mvolume I : Wait Vbl : Next I
      Mvolume 0
   End If 
   
   If WIN and JUST_RECORDING
      GAME_RECORD_EMPTY=_FALSE
   End If 
   
   _ANIM_FLAG_AND_PRESS_SPACE_PRINT
   
   Inc GAMES_PLAYED
   
   _FADE_OUT:
   
   GAME_FADE_OUT
   Sprite Off 
   Bob Off 
End Proc

Procedure _ANIM_FLAG_AND_PRESS_SPACE_PRINT
   If(ESC or WIN)=0
      '------------------ Is Anyone Alive ? ---------------------
      SURVIVAL_PLAYER=0
      For I=1 To 6
         If ALIVE(I)
            SURVIVAL_PLAYER=I
         End If 
      Next I
      
      If(SURVIVAL_PLAYER>0) and(_SCREEN_SIZE>0)
         For I=1 To 6
            NS=_SPRITE_NUMBER(I)
            If(I<>SURVIVAL_PLAYER) and(NS<4)
               Sprite Off NS
            End If 
         Next I
         
         X_SUM=X#(SURVIVAL_PLAYER)-160
         Y_SUM=Y#(SURVIVAL_PLAYER)-110
         X_SUM=Max(X_SUM,0)
         Y_SUM=Max(Y_SUM,0)
         X_SUM=Min(X_SUM,X_SCROLL_LIMIT)
         Y_SUM=Min(Y_SUM,Y_SCROLL_LIMIT)
         
         X_SUM=X_SUM and $FFFE
         Y_SUM=Y_SUM and $FFFE
         _VIEWED_AREA_X=_VIEWED_AREA_X and $FFFE
         _VIEWED_AREA_Y=_VIEWED_AREA_Y and $FFFE
         
         Repeat 
            _VIEWED_AREA_X=_VIEWED_AREA_X+2*Sgn(X_SUM-_VIEWED_AREA_X)
            _VIEWED_AREA_Y=_VIEWED_AREA_Y+2*Sgn(Y_SUM-_VIEWED_AREA_Y)
            
            NS=_SPRITE_NUMBER(SURVIVAL_PLAYER)
            NI=_SPRITE_IMAGE(SURVIVAL_PLAYER)
            _SPRITE_Y=Y#(SURVIVAL_PLAYER)+42-_VIEWED_AREA_Y
            Sprite NS,X#(SURVIVAL_PLAYER)+X Hard(0)-_VIEWED_AREA_X,_SPRITE_Y,NI+_SPRITE_INDEX_BASE
            
            Screen Offset 1,_VIEWED_AREA_X,_VIEWED_AREA_Y
            Wait Vbl 
         Until(_VIEWED_AREA_X=X_SUM) and(_VIEWED_AREA_Y=Y_SUM)
      End If 
      
      If JUST_RECORDING
         GAME_RECORD_EMPTY=_FALSE
         IS_GAME_SAVING
      Else 
         ALLOW_GAME_SAVING=_FALSE
      End If 
      
      Paste Bob 160-50/2+_VIEWED_AREA_X,160-30/2+_VIEWED_AREA_Y,PRESS_SPACE_IMAGE
      
      If SURVIVAL_PLAYER>0
         If _SCREEN_SIZE=0
           Sprite Off 
         End If 
         
         Bank Swap 1,23
         
         SURVIVAL_COLOUR=Colour($10+SURVIVAL_PLAYER)
         For I=1 To 6 : PL_RGB(I)=_PLAYER_GREY_COLOUR(I) : Next I
         PL_RGB(SURVIVAL_PLAYER)=SURVIVAL_COLOUR
         
         Fade 1,,,,,,,,,,,,,,,,,,PL_RGB(1),PL_RGB(2),PL_RGB(3),PL_RGB(4),PL_RGB(5),PL_RGB(6)
         
         Wait 12
         
         Y_FLAG=Int(Y#(SURVIVAL_PLAYER))
         Colour $17,Colour($10+SURVIVAL_PLAYER)
         Sprite 0,X#(SURVIVAL_PLAYER)+X Hard(0)-15-_VIEWED_AREA_X,Y_FLAG+42-22+BOLDLINE-_VIEWED_AREA_Y,1
         
         If _SCREEN_SIZE>0
            Screen 5
            Get Palette 1
            Screen 1
         End If 
         
         _ANIM_FLAG$="Anim 0,(1,2)(2,2)(3,2)(4,2)(5,2)(6,2)(12,2)(11,2)(10,2)(9,2)(8,2)(7,2)"
         Amal 0,_ANIM_FLAG$
         Amal On 
         
         
         If Y_FLAG<14
            For Y_CURR=Y_FLAG To 30
               Sprite 0,X#(SURVIVAL_PLAYER)+X Hard(0)-15-_VIEWED_AREA_X,Y_CURR+42-22+BOLDLINE_VIEWED_AREA_Y,
               Wait Vbl 
            Next Y_CURR
         End If 
      End If 
      
      Timer=0
      If DEMO_ON
         Repeat 
         Until Timer>DEMO_PRESS_SPACE_LIMIT
      Else 
         If _ONLY_COMPUTERS_IN_GAME
            PRESS_SPACE_LIMIT=50*4
         Else 
            PRESS_SPACE_LIMIT=999999999
         End If 
         Clear Key 
         Repeat 
            ESC_PRESSED=Key State(ESC_SCANCODE)
            SPACE_PRESSED=Key State(SPACE_SCANCODE)
            R_PRESSED=Key State(R_SCANCODE) and JUST_RECORDING
            S_PRESSED=Key State(S_SCANCODE) and ALLOW_GAME_SAVING
         Until ESC_PRESSED or SPACE_PRESSED or R_PRESSED or S_PRESSED or(Timer>PRESS_SPACE_LIMIT)
         ESC=ESC_PRESSED
         If R_PRESSED
            JUST_RECORDING=_FALSE
         End If 
         If S_PRESSED
            Trap Save GAME_SAVING_PATH$+RECORDNAME$+INDEX$,30
         End If 
      End If 
      
      If SURVIVAL_PLAYER>0
         Amal Off 
         Sprite Off 
         Bank Swap 1,23
      End If 
      
      _DO_SOUND[PRESS_SPACE_SOUND]
      Wait Vbl 
   End If 
End Proc

Procedure INITIALIZE_GAME
   
   
   '                      ________________________________
   '                     |                                | 
   '                     | Load gamerecord                | 
   '                     |________________________________| 
   
   
   If REPLAY_ALL_SAVED_ON
      Trap Load GAME_SAVING_PATH$+RECORDNAME$+INDEX$,30
   End If 
   
   If JUST_REPLAYING or JUST_RECORDING
      RECORD_BASE=Start(30)
      RECORD_MOVEMENTS_START=RECORD_BASE+$130
      Loke VA_GAME_RECORD,RECORD_MOVEMENTS_START
      
      If JUST_REPLAYING
         _DECONFIG[RECORD_BASE+$B0,False]
         SET_PLAN_USING_CONFIG[False]
      Else If JUST_RECORDING
         CONFIG[RECORD_BASE+$B0,False]
      End If 
      
   End If 
   
   '                      ________________________________
   '                     |                                | 
   '                     | Some neccessities              | 
   '                     |________________________________| 
   
   
   SOUND_FX=USER_SOUND_FX and ENABLED_SOUND
   SOUND_FX_CHANNEL=1
   
   If JUST_REPLAYING
      For I=1 To 6
         SELECTED(I)=-Peek(RECORD_BASE+72+I-1)
      Next I
      _COUNT_SELECTED
   End If 
   
   If GAMES_PLAYED>0
      _EXPECTED_GAME_LENGTH=(_EXPECTED_GAME_LENGTH*GAMES_PLAYED+CYCLES)/(GAMES_PLAYED+1)
   End If 
   
   BODY_CHANGE_COUNTER=(_EXPECTED_GAME_LENGTH*BODY_CHANGE_PERCENT)/200+Rnd((_EXPECTED_GAME_LENGTH*BODY_CHANGE_PERCENT)/100)
   BODY_CHANGE_COUNTER=Max(BODY_CHANGE_COUNTER,100)
   
   GAME_SLOWED=_FALSE
   DIE_COMPUTERS=_FALSE

   If(Prg State=-1)
      _TOPSCORE=(HRAJOU-1)*5
      If LONG_GAME
         _TOPSCORE=_TOPSCORE*2
      End If 
   Else 
      _TOPSCORE=(HRAJOU-1)*DEBUGGING_LIFELIMIT_COEFICIENT
   End If 
   
   '                     .---------------------.
   '                     |   Draw Background   |
   '                     `---------------------'
   
   If _SCREEN_SIZE>0
      Screen 2
      If Length(PLAN_BANK(PLAN))>0 : Unpack PLAN_BANK(PLAN)
      Else : Cls 0 : End If 
      
      Screen Copy 2,0,0,320,256 To 1,0,0
      Screen Copy 2,0,0,320,256 To 1,320,256
      Screen Copy 2,0,0,320,256 To 1,320,0
      Screen Copy 2,0,0,320,256 To 1,0,256
   Else 
      Screen 1
      If Length(PLAN_BANK(PLAN))>0 : Unpack PLAN_BANK(PLAN)
   Else : Cls 0 : End If 
      Ink 0 : Bar 0,256-30-3 To 320-1,256-1
   End If 
   
   
   '                     .----------------. 
   '                     |   Set bordes   | 
   '                     `----------------' 
   
   If _SCREEN_SIZE=2
      XBOTTOM=640/2-2*CENTRAL_BOX_SIZE
      XTOP=640/2+2*CENTRAL_BOX_SIZE
      YBOTTOM=(512-30)/2-2*CENTRAL_BOX_SIZE
      YTOP=(512-30)/2+2*CENTRAL_BOX_SIZE
      
      _LEFT_LIMIT=4+3+1
      _UP_LIMIT=4+3
      _RIGHT_LIMIT=320*2-5-3-1
      _DOWN_LIMIT=256*2-5-3
      
      X_SCROLL_LIMIT=640-320
      Y_SCROLL_LIMIT=512-256+31
   Else If _SCREEN_SIZE=1
      XBOTTOM=480/2-2*CENTRAL_BOX_SIZE
      XTOP=480/2+2*CENTRAL_BOX_SIZE
      YBOTTOM=(384-30)/2-2*CENTRAL_BOX_SIZE
      YTOP=(384-30)/2+2*CENTRAL_BOX_SIZE
      
      _LEFT_LIMIT=4+3+1
      _UP_LIMIT=4+3
      _RIGHT_LIMIT=320*1.5-5-3-1
      _DOWN_LIMIT=256*1.5-5-3
      
      X_SCROLL_LIMIT=480-320
      Y_SCROLL_LIMIT=384-256+31
   Else 
      XBOTTOM=320/2-CENTRAL_BOX_SIZE
      XTOP=320/2+CENTRAL_BOX_SIZE
      YBOTTOM=(256-30)/2-CENTRAL_BOX_SIZE
      YTOP=(256-30)/2+CENTRAL_BOX_SIZE
      
      _LEFT_LIMIT=4
      _UP_LIMIT=4
      _RIGHT_LIMIT=320-5
      _DOWN_LIMIT=256-30-5-2
   End If 
   
   If BOLDLINE=0
      Inc _RIGHT_LIMIT
      Inc _DOWN_LIMIT
      Inc XBOTTOM
      Inc YBOTTOM
   End If 
   
   _VIEWED_AREA_X=0
   _VIEWED_AREA_Y=0
   _DO_X_SCROLL=_FALSE
   _DO_Y_SCROLL=_FALSE
   Screen Offset 1,_VIEWED_AREA_X,_VIEWED_AREA_Y
   Sprite Off 
   
   
   
   '                     .-----------------------------------.  
   '                     |   Precount SpeedSource#           |  
   '                     `-----------------------------------'  
   
   TEMP#=SPEEDJUMP : SPEEDJUMP#=0.01*TEMP#/15
   
   For UNDER_HEAD=0 To $F
      SPEED=UNDER_HEAD
      SPEED_SOURCE#(UNDER_HEAD)=1-SPEED*SPEEDJUMP#
   Next UNDER_HEAD
   
   
   '                     .-----------------------------------.  
   '                     |   Set begin positions of players  |  
   '                     `-----------------------------------'  
   
   BEGIN_Y_MAX=256-36-10
   LIVES_ON=_FALSE
   
   For _PLAYER=1 To 6
      If SELECTED(_PLAYER)
         NC=_TRUE : Rem New Coordinates  
         While NC
            If JUST_REPLAYING
               SMER(_PLAYER)=Leek(RECORD_BASE+4*(_PLAYER-1))
               If SMER(_PLAYER)>=SMERU
                  SMER(_PLAYER)=SMERU-1
               End If 
               ANGLE#=ANGLE_CONSTANT#*SMER(_PLAYER)
               X#(_PLAYER)=Leek(RECORD_BASE+24+4*(_PLAYER-1))
               Y#(_PLAYER)=Leek(RECORD_BASE+48+4*(_PLAYER-1))
            Else 
               SMER(_PLAYER)=Rnd(SMERU)
               RADIUS=Rnd(160)+40
               ANGLE#=ANGLE_CONSTANT#*SMER(_PLAYER)
               X#(_PLAYER)=145-Sin(ANGLE#)*RADIUS
               Y#(_PLAYER)=127-Cos(ANGLE#)*RADIUS
               X#(_PLAYER)=Int(X#(_PLAYER))
               Y#(_PLAYER)=Int(Y#(_PLAYER))
            End If 
            
            NC=_FALSE
            NC=NC or(X#(_PLAYER)<10) or(X#(_PLAYER)>270) or(Y#(_PLAYER)<10) or(Y#(_PLAYER)>BEGIN_Y_MAX)
            NC=NC or((X#(_PLAYER)>XBOTTOM-10) and(X#(_PLAYER)<XTOP+10)) or((Y#(_PLAYER)>YBOTTOM-10) and(Y#(_PLAYER)<YTOP+10))
            If _PLAYER>1
               For I=1 To _PLAYER-1
                  If SELECTED(I)
                     NC=NC or(Abs(X#(I)-X#(_PLAYER))<15) and(Abs(Y#(I)-Y#(_PLAYER))<15)
                  End If 
               Next I
            End If 
         Wend 
         
         If JUST_RECORDING
            Loke RECORD_BASE+4*(_PLAYER-1),SMER(_PLAYER)
            Loke RECORD_BASE+24+4*(_PLAYER-1),Int(X#(_PLAYER))
            Loke RECORD_BASE+48+4*(_PLAYER-1),Int(Y#(_PLAYER))
         End If 
         
         If JUST_RECORDING or JUST_REPLAYING
            LINE_COUNTER(_PLAYER)=LINE_LENGTH+6
         Else 
            LINE_COUNTER(_PLAYER)=LINE_LENGTH+Rnd(12)-6
         End If 
         
         
         SPACE_COUNTER(_PLAYER)=-1
         SPEED_PERCENT#(_PLAYER)=1
         TURNING(_PLAYER)=0
         AUCH_PROTECTION(_PLAYER)=False
         LIVES(_PLAYER)=_TOP_LIVES(_PLAYER)
         LIVES_ON=LIVES_ON or(_TOP_LIVES(_PLAYER)>0)
         _PLAYER_RECORD((_PLAYER-1))=0
         BOUND_THIS_ROUND(_PLAYER)=False
         WIND_FACTOR#(_PLAYER)=1.0
         STAYED_ALIVE_BONUS(_PLAYER)=1
         ZOMBIE(_PLAYER)=_FALSE
         LINE_LENGTH_(_PLAYER)=LINE_LENGTH
         SPACE_LENGTH_(_PLAYER)=SPACE_LENGTH
      End If 

      SEMIALIVE(_PLAYER)=SELECTED(_PLAYER)
      ALIVE(_PLAYER)=SELECTED(_PLAYER)
   Next _PLAYER
   
   
   '                     .----------------------------------. 
   '                     |   Draw bordes, scores and lives  | 
   '                     `----------------------------------' 
   
   
   INITIALIZE_GAME____DRAW_BORDERS
   MAKE_SCOREPANEL
   _DRAW_SCORE
   
   
   '                      ________________________________
   '                     |                                | 
   '                     | Set Colours                    | 
   '                     |________________________________| 
   
   If SURPRISING_START
      P_COLOR(1)=Rnd(5)+1
      For _PLAYER=2 To 6
         C=Rnd(5)+1
         Repeat 
            CORRECT=_TRUE
            Add C,1,1 To 6
            For I=1 To _PLAYER-1
               If P_COLOR(I)=C : CORRECT=_FALSE : End If 
            Next I
         Until CORRECT
         P_COLOR(_PLAYER)=C
      Next _PLAYER
      For _PLAYER=1 To 6
         P_COLOR(_PLAYER)=PL_DEF_COLOR(P_COLOR(_PLAYER))
      Next _PLAYER
   Else 
      For _PLAYER=1 To 6
         P_COLOR(_PLAYER)=PL_DEF_COLOR(_PLAYER)
      Next _PLAYER
   End If 
   
   If _SCREEN_SIZE>0
      Sprite 4,0+X Hard(0),4+42,LATERAL_LEFT
      Sprite 5,320-5+X Hard(0),4+42,LATERAL_RIGHT
   End If 
   Sprite Off 6
   Sprite Off 7
   
   '                      ______________________________________
   '                     |                                      | 
   '                     | Let all players know their positions | 
   '                     |______________________________________| 
   
   Screen 1
   GAME_FADE_UP
   INIT_PUTPIX_STRATEGY_SIN_ATAN
   
   ESC=False
   
   If SURPRISING_START
   Else 
      _ANIM_FLAG$="Anim 1,(1,3)(2,2)(3,3)(4,2)(5,3)(6,2)(12,3)(11,2)(10,3)(9,2)(8,3)(7,2)(1,3)(2,2)(3,3)"
      Bank Swap 1,23
      For I=1 To 6
         If SELECTED(I) and(ESC=False)
            Volume 1,40
            _DO_SOUND[ARROW_SOUND]
            Colour $17,Colour($10+I)
            If _SCREEN_SIZE>0
               Screen 5
               Get Palette 1
               Screen 1
            End If 
            
            Sprite 0,X#(I)+X Hard(0)-15,Y#(I)+42-22+BOLDLINE,1
            Amal 0,_ANIM_FLAG$
            Amal On 
            Wait 2
            While Chanan(0) and(ESC=False)
               If Key State(ESC_SCANCODE)
                  ESC=True
               End If 
            Wend 
            Dreg(0)=X#(I) : Dreg(1)=Y#(I) : Dreg(2)=$10+I
            Call(PA_CURRENT_PIX)
            Sprite Off 0
            Wait Vbl 
         End If 
         If ESC
            Exit 
         End If 
      Next I
      Amal Off 
      For I=0 To 3
         Sprite Off I
      Next I
      Bank Swap 1,23
   End If 
   
   '                      ______________________________________
   '                     |                                      | 
   '                     | Set begin possitions of sprites      | 
   '                     |______________________________________| 
   
   For I=1 To 6
      If SELECTED(I)
         NS=_SPRITE_NUMBER(I)
         If(_SCREEN_SIZE=0) or(NS<4)
            NI=_SPRITE_IMAGE(I)
            Sprite NS,X#(I)+X Hard(0),Y#(I)+42,NI+_SPRITE_INDEX_BASE
         Else 
            Bob I-2,X#(I),Y#(I),_BOB_PLAYER_IMAGE(I-3,Abs(BOLDLINE))
            _BOBS_USED=_TRUE : Bob Update Off 
         End If 
      End If 
   Next I
   
   INITIALIZE_GAME____SET_RATE_VARIABLES
   
   J_REPLAYING_OR_J_RECORDING=JUST_REPLAYING or JUST_RECORDING
   TURBOLIMIT=0
   GO_FOR_COMPUTURBO=_FALSE
   If TURBO
      TURBOLIMIT=-1
   Else If(_ONLY_COMPUTERS_IN_GAME=_FALSE)
      GO_FOR_COMPUTURBO=COMPUTURBO or COMPUDEATH
   End If 
   
   If WIND
      WIND_ANGLE=Rnd(SMERU-1)
      WIND_STRENGTH#=WIND_STRENGTH
      WIND_STRENGTH#=WIND_STRENGTH#*0.08
   End If 
   
   
   SEMIALIVE(0)=False
   Clear Key 
   
   ' Paper 0 : Pen $12 : Locate 1,1 : Print BODY_CHANGE_COUNTER;" ";_EXPECTED_GAME_LENGTH;" ";BODY_CHANGE_PERCENT 
   
End Proc
Procedure INITIALIZE_GAME____DRAW_BORDERS
   
   Screen 1
   If _SCREEN_SIZE=2
      Ink 0 : Box 5,4 To 640-6,512-5
      Ink $D : Box 6,5 To 640-7,512-6
      Ink $10 : Box 7,6 To 640-8,512-7
      Ink 0 : Box 8,7 To 640-9,512-8
   Else If _SCREEN_SIZE=1
      Ink 0 : Box 5,4 To 480-6,384-5
      Ink $D : Box 6,5 To 480-7,384-6
      Ink $10 : Box 7,6 To 480-8,384-7
      Ink 0 : Box 8,7 To 480-9,384-8
   Else 
      _DRAW_SMALL_WOOD_FRAME
      Ink 0 : Box 4,4 To 320-5,256-32-5
   End If 
   
   If CENTRAL_BOX=1
      Ink 0 : Bar XBOTTOM,YBOTTOM To XTOP+1,YTOP+1
      If _SCREEN_SIZE>0
         Ink $10 : Box XBOTTOM+1,YBOTTOM+1 To XTOP+1-1,YTOP+1-1
         Ink $D : Box XBOTTOM+2,YBOTTOM+2 To XTOP+1-2,YTOP+1-2
      Else 
         Get Bob 100,0,10 To 5,10+YTOP-YBOTTOM
         Paste Bob XTOP-3,YBOTTOM+1,100
         Paste Bob XBOTTOM-(16-5),YBOTTOM+1,100+$8000
         
         Get Bob 100,XBOTTOM+3,0 To XTOP-3,5
         Paste Bob XBOTTOM+4,YTOP-3,100
         Paste Bob XBOTTOM+4,YBOTTOM,100+$4000 : Del Bob 100
      End If 
   End If 
End Proc
Procedure INITIALIZE_GAME____SET_RATE_VARIABLES
   
   If RATEMODE=1
      RATE_LENGTH#=USER_RATE_LENGTH*2
      STILL_SPEEDING_UP=True
      
      RATE#=0.5
      RATEJUMP#=0.01*(FINAL_RATE-50)/RATE_LENGTH#
      FINAL_RATE#=FINAL_RATE/100.0
      
      _MUSIC_TEMPO#=7+50/7.0
      _MUSIC_TEMPO_JUMP#=(FINAL_RATE-50)/RATE_LENGTH#/7.0
   Else 
      STILL_SPEEDING_UP=False
      RATE#=FINAL_RATE*0.01
      _MUSIC_TEMPO#=7+FINAL_RATE/7.0
   End If 
   
   If GAME_MUSIC_PLAYING
      Tempo _MUSIC_TEMPO#
   End If 
   
End Proc
Procedure INITIALIZE_GAMESET
   For I=1 To 6 : SCORE(I)=0 : Next I
   GR=0 : GRP=1 : WIN=False
   GAME_MUSIC_PLAYING=((_MUSIC_ON=1) and(DEMO_ON=False))
   
   JUST_REPLAYING=USER_REPLAYING or REPLAY_ALL_SAVED_ON
   JUST_RECORDING=USER_RECORDING
   
   If USER_RECORDING
      For I=1 To 6
         Poke(RECORD_BASE+72+I-1),-SELECTED(I)
      Next I
   Else If USER_REPLAYING
      If Length(31)=0
         Reserve As Work 31,CONFIG_LENGTH
      End If 
      CONFIG[Start(31),False]
   End If 
   
   If REPLAY_ALL_SAVED_ON
      INDEX=0 : _EXISTS_INDEX=False
      Repeat 
         INDEX$=Str$(INDEX)-" " : INDEX$=String$("0",2-Len(INDEX$))+INDEX$
         _EXISTS_INDEX=_EXISTS_INDEX or Exist(GAME_SAVING_PATH$+RECORDNAME$+INDEX$)
         Inc INDEX
      Until _EXISTS_INDEX or(INDEX=100)
      Dec INDEX
      If _EXISTS_INDEX
         If Length(31)=0
            Reserve As Work 31,CONFIG_LENGTH
         End If 
         CONFIG[Start(31),False]
      End If 
   End If 
   
   _ONLY_COMPUTERS_IN_GAME=_TRUE
   For _PLAYER=1 To 6
      If(_PLAYER_TYPE(_PLAYER)=1) or(_PLAYER_TYPE(_PLAYER)=3)
      _ONLY_COMPUTERS_IN_GAME=_FALSE : End If 
   Next 
   
   If _SCREEN_SIZE>0
      Screen 2 : Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Screen Close 1
      Screen Open 1,640,512,32,Lowres
      Flash Off : Curs Off : Hide On 
      Screen Display 1,128,42,320,256-30
      Screen Offset 1,0,0
      Set Font FONT_NUMBER
   End If 
   
   GAMES_PLAYED=0
   _EXPECTED_GAME_LENGTH=(1000+250*HRAJOU)*(2^_SCREEN_SIZE)
End Proc
Procedure INITIALIZE_GAMESET____MIDDLE_PART
   If GAME_MUSIC_PLAYING
      Volume 0 : Music 1
   End If 
   
   
   Screen Open 4,640,30,16,Hires
   Flash Off : Curs Off : Hide On 
   Screen Hide 4
   
   Screen Open 3,640,30,16,Hires
   Flash Off : Curs Off : Hide On 
   Screen Display 3,128,42+300,640,30
   
   If _SCREEN_SIZE>0
      Screen Open 5,320,8,32,Lowres
      Flash Off : Curs Off : Hide On 
      Screen Display 5,128,42,320,4
      
      Paste Bob 0,0,HORIZONTAL_WOOD_IMAGE
      Paste Bob 160,0,HORIZONTAL_WOOD_IMAGE
      Paste Bob 0,0,CORNER_WOOD_IMAGE
      Paste Bob 320-16,0,CORNER_WOOD_IMAGE+$8000
      Ink 0 : Draw 5,0 To 5,4 : Draw 320-6,0 To 320-6,4
      
      Screen Open 6,320,8,32,Lowres
      Flash Off : Curs Off : Hide On 
      Screen Display 6,128,42+256-30-5,320,4
      
      Paste Bob 0,0,HORIZONTAL_WOOD_IMAGE+$4000
      Paste Bob 160,0,HORIZONTAL_WOOD_IMAGE+$4000
      Paste Bob 0,0,CORNER_WOOD_IMAGE
      Paste Bob 320-16,0,CORNER_WOOD_IMAGE+$8000
      Ink 0 : Draw 5,0 To 5,4 : Draw 320-6,0 To 320-6,4
   End If 
End Proc

Procedure ICON_AND_MUSIC_CARE_BEFORE_GAMESET
   
   '~~~ Care about music ~~~
   
   If GAME_MUSIC_PLAYING
      If Not GAME_MUSIC_IN_CHIP_RAM
         Erase 15
         DUENIX_REQUEST
         If Exist(PATH$+"Duming")
            Load PATH$+"Duming",3
         Else 
            End 
         End If 
      End If 
   End If 
   
   '~~~ Pred gamesou swapni icony~~~
   Bank Swap 2,4
   
End Proc
Procedure ICON_AND_MUSIC_CARE_AFTER_GAMESET
   
   '~~~ Vrat icony, sycaku ~~~
   Bank Swap 2,4
   
   '~~~ Vrat muziku, sycaku ~~~ 
   
   If GAME_MUSIC_PLAYING
      Volume 0 : Music Off 
      If Not GAME_MUSIC_IN_CHIP_RAM
         Erase 3
         DUENIX_REQUEST
         If Exist(PATH$+"LifeMotion")
            Load PATH$+"LifeMotion",15
         Else 
            Erase All : End 
         End If 
      End If 
   End If 
   
   If(DEMO_ON=False) and(_MUSIC_ON=1)
      Track Play 15
   End If 
End Proc
Procedure GAME_FADE_UP
   If PLAN=0
      Fade 1,$0,$1,$2,$3,$4,$15,$115,$116,$227,$228,$339,$33A,$459,$669,$779,$778
   Else If PLAN=2
      Fade 1,0,UPP(1),UPP(2),UPP(3),UPP(4),UPP(5),UPP(6),UPP(7),UPP(8),UPP(9),UPP(10),UPP(11),UPP(12),UPP(13),UPP(14),UPP(15)
   Else 
      Fade 1,0,SPP(1),SPP(2),SPP(3),SPP(4),SPP(5),SPP(6),SPP(7),SPP(8),SPP(9),SPP(10),SPP(11),SPP(12),SPP(13),SPP(14),SPP(15)
   End If 
   
   Wait 14
   Fade 1,,,,,,,,,,,,,,,,,,,,,,,,,$810,$A30,$B40,$C50,$D60,$E70,$F71,$F63
   If _SCREEN_SIZE>0
      Screen 5
      Palette ,,,,,,,,,,,,,,,,Colour($A),P_COLOR(1),P_COLOR(2),P_COLOR(3),P_COLOR(4),P_COLOR(5),P_COLOR(6),$EEE,$810,$A30,$B40,$C50,$D60,$E70,$F71,$F63
      Screen 6
      Palette ,,,,,,,,,,,,,,,,Colour($A),P_COLOR(1),P_COLOR(2),P_COLOR(3),P_COLOR(4),P_COLOR(5),P_COLOR(6),$EEE,$810,$A30,$B40,$C50,$D60,$E70,$F71,$F63
      Screen 1
   End If 
   Wait 14
   Fade 1,,,,,,,,,,,,,,,,,Colour($A),P_COLOR(1),P_COLOR(2),P_COLOR(3),P_COLOR(4),P_COLOR(5),P_COLOR(6),$EEE
   '$EEE,$DDD,$1F1,$F6E,$FF0,$5AF,$EE,$EEE
   
   ROLL_SCORE_IN
End Proc
Procedure GAME_FADE_OUT
   Fade 1,,,,,,,,,,,,,,,,,0,0,0,0,0,0,0,0,0
   Wait 14
   Fade 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,,,,,,,,,0,0,0,0,0,0,0,0
   If _SCREEN_SIZE>0
      Screen 5
      Palette ,,,,,,,,,,,,,,,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Screen 6
      Palette ,,,,,,,,,,,,,,,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Screen 1
   End If 
   '   Wait 14
   
   For I=256-30 To 300 Step 5
      Screen Display 3,128,42+I,640,30
      Wait Vbl 
   Next I
   
End Proc
Procedure ROLL_SCORE_IN
   Screen 3
   PAL=Rnd(4)
   If PAL=1
      Palette $0,$200,$410,$620,$930,$B40,$D50,$F60,$430,$540,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
   Else If PAL=2
      Palette $0,$200,$500,$710,$A20,$C30,$E40,$F50,$430,$540,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
   Else If PAL=3
      Palette $0,$112,$222,$332,$442,$552,$662,$772,$530,$740,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
   Else If PAL=4
      Palette $0,$110,$230,$440,$750,$960,$B70,$D80,$31,$42,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
   Else 
      Palette $0,$11,$32,$143,$453,$663,$873,$A83,$33,$44,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6)
   End If 
   Screen 1
   Wait Vbl 
   
   For I=300 To 256-20 Step -5
      Screen Display 3,128,42+I,640,30
      Wait Vbl 
   Next I
   For I=256-20 To 256-25 Step -5
      Screen Display 3,128,42+I,640,30
      Wait Vbl 
   Next I
End Proc
Procedure WINNERS_AND_LOSERS
   'toto je nutne, aby winnerprint vytiskl vsechny selectedy  
   
   For I=1 To 6 : SEMIALIVE(I)=SELECTED(I) : Next I
   
   MAKE_SCOREPANEL
   _DRAW_SCORE
   
   WINNER=GRP : Rem winner already known 
   LOSER=GRP : Rem zatim! 
   
   '          ________________________________
   '         |                                |   
   '         | Find all losers                |     
   '         |________________________________| 
   
   
   For I=1 To 6
      If SELECTED(I) and(SCORE(I)<SCORE(LOSER))
         LOSER=I
      End If 
   Next I
   
   '      ==  Co kdyby jich bylo vic ! ==   
   
   LOWEST_SCORE=SCORE(LOSER)
   NUMBER_OF_LOSERS=0
   For I=1 To 6
      If(SCORE(I)=LOWEST_SCORE) and SELECTED(I)
         Inc NUMBER_OF_LOSERS
      End If 
   Next I
   
   '          ________________________________
   '         |                                |   
   '         | Music'n Backgorund             |     
   '         |________________________________| 
   
   
   Music Stop 
   If _MUSIC_ON : Track Play WINNER_MUSIC__BANK : End If 
   
   Screen 2
   If Length(PLAN_BANK(PLAN))>0 : Unpack PLAN_BANK(PLAN)
Else : Cls 0 : End If 
   
   
   Screen 2 : Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   Screen Close 1
   
   Screen Open 1,320,60,32,Lowres
   Flash Off : Curs Off : Hide On 
   Screen Copy 2,0,0,320,60 To 1,0,0
   Sprite Off 
   Screen Display 1,128,42,320,60
   
   _DRAW_WINNER_WOOD_FRAME[60]
   
   Screen Open 7,320,160,32,Lowres
   Flash Off : Curs Off : Hide On 
   Screen Display 7,128,42+60+3,320,160
   Screen Copy 2,0,63,320,63+160 To 7,0,0
   
   _DRAW_WINNER_WOOD_FRAME[160]
   
   Screen 2
   
   
   '          ________________________________
   '         |                                |   
   '         | Write all texts                |     
   '         |________________________________| 
   
   
   
   HLASKA$=THE_WINNER$
   Cls 0 : Ink $10+WINNER,0 : Text(40-Len(HLASKA$))*4,40-10,HLASKA$
   
   If NUMBER_OF_LOSERS=1
      Randomize Timer
      If Rnd(1)=0
         HLASKA$=THE_LOSER1$
      Else 
         HLASKA$=THE_LOSER2$
      End If 
      Ink $10+LOSER,0 : Text(40-Len(HLASKA$))*4,90,HLASKA$
   Else 
      HLASKA$=THE_LOSERS$
      CURRENT_LOSER=0
      For I=1 To 6
         If(SCORE(I)=LOWEST_SCORE) and SELECTED(I)
            Ink $10+I,0 : Text(40-Len(HLASKA$))*4,CURRENT_LOSER*20+90,HLASKA$
            Inc CURRENT_LOSER
         End If 
      Next I
   End If 
   
   '          ________________________________
   '         |                                |   
   '         | Fade Up and wait for any key   |     
   '         |________________________________| 
   
   
   Get Block 1,0,0,320,80,1
   Screen 1 : Put Block 1 : Del Block 1
   Screen 2 : Get Block 1,0,63,320,160,1
   Screen 7 : Put Block 1,0,0 : Del Block 1
   
   Screen 1
   Fade 1,$0,$101,$201,$311,$412,$512,$623,$723,$824,$935,$A35,$B36,$C46,$D47,$E47,$F48,$F17,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$EEE,$810,$A30,$B40,$C50,$D60,$E70,$F71,$F63
   ROLL_SCORE_IN
   Screen 7
   Fade 1,$0,$1,$2,$3,$4,$5,$6,$7,$8,$9,$A,$B,$C,$D,$E,$F,$F17,PL_DEF_COLOR(1),PL_DEF_COLOR(2),PL_DEF_COLOR(3),PL_DEF_COLOR(4),PL_DEF_COLOR(5),PL_DEF_COLOR(6),$EEE,$10,$111,$222,$333,$444,$555,$666,$777
   
   _ANIM_FLAG$="Anim 0,(1,3)(2,2)(3,3)(4,2)(5,3)(6,2)(12,3)(11,2)(10,3)(9,2)(8,3)(7,2)"
   Bank Swap 1,23
   Colour $17,Colour($10+GRP)
   Sprite 0,40+X Hard(0),42+23-5,1
   Sprite 4,320-40-20+X Hard(0),42+23-5,1
   Amal 0,_ANIM_FLAG$
   Amal 4,_ANIM_FLAG$
   Amal On 
   
   Wait 10 : Clear Key : Timer=0
   Repeat : A$=Inkey$ : Until(A$<>"") or(Timer>50*(60+4))
   
   Amal Off : Sprite Off 
   Bank Swap 1,23
   
   GAME_FADE_OUT
   Screen 1
   Fade 1
   Wait 14
   Screen Close 7
   
   Track Stop 
   
End Proc
Procedure IS_GAME_SAVING
   If Exist("Duenrecord:")
      Edit 
      GAME_SAVING_PATH$="DuenRecord:"
   Else 
      If Not Exist("ram:DuenRecord/")
         Mkdir "ram:DuenRecord"
      End If 
      GAME_SAVING_PATH$="ram:DuenRecord/"
   End If 
   INDEX=0
   _FREE_INDEX=False
   Repeat 
      INDEX$=Str$(INDEX)-" " : INDEX$=String$("0",2-Len(INDEX$))+INDEX$
      If Not Exist(GAME_SAVING_PATH$+RECORDNAME$+INDEX$)
         _FREE_INDEX=True
      End If 
      Inc INDEX
   Until _FREE_INDEX or(INDEX=100)
   If((PATH$="ram:DuenRecord") and(Chip Free+Fast Free<20000)) or(_FREE_INDEX=False)
      ALLOW_GAME_SAVING=False
   Else 
      ALLOW_GAME_SAVING=True
   End If 
End Proc

Procedure DEMO_ENVIRONMENT[ACTION]
   If ACTION=0
      '          ________________________________
      '         |                                | 
      '         | Store before demo              | 
      '         |________________________________| 
      
      DEMOSTORE_PLAN=PLAN
      DEMOSTORE_USER_RECORDING=USER_RECORDING
      DEMOSTORE_USER_REPLAYING=USER_REPLAYING
      DEMOSTORE_REPLAY_ALL_SAVED_ON=REPLAY_ALL_SAVED_ON
      DEMOSTORE_TEAM_GAME=TEAM_GAME
      DEMOSTORE_ENABLED_SOUND=ENABLED_SOUND
      
      '          ________________________________
      '         |                                | 
      '         | Set environment                | 
      '         |________________________________| 
      
      For I=1 To 6
         SELECTED(I)=0
         COMPUTER_STRATEGY(I)=0
         CYBORG(I)=0
      Next I
      SELECTED(2)=-1
      COMPUTER_STRATEGY(2)=-1
      SELECTED(4)=-1
      COMPUTER_STRATEGY(4)=-1
      
      PLAN=0
      USER_RECORDING=False
      USER_REPLAYING=False
      REPLAY_ALL_SAVED_ON=False
      TEAM_GAME=False
      ENABLED_SOUND=False
      
   Else If ACTION=1
      
      '          ________________________________
      '         |                                | 
      '         | Restore after demo            |  
      '         |________________________________| 
      
      PLAN=DEMOSTORE_PLAN
      USER_RECORDING=DEMOSTORE_USER_RECORDING
      USER_REPLAYING=DEMOSTORE_USER_REPLAYING
      REPLAY_ALL_SAVED_ON=DEMOSTORE_REPLAY_ALL_SAVED_ON
      TEAM_GAME=DEMOSTORE_TEAM_GAME
      ENABLED_SOUND=DEMOSTORE_ENABLED_SOUND
      
   End If 
End Proc
Procedure _GLOBAL_INITIALIZATION
   If(Chip Free+Fast Free)<MEMORY_REQUIREMENT
      Screen Open 3,640,256,2,Hires : Curs Off 
      Cls 0 : Paper 0 : Pen 1 : Locate 0,10
      Centre "Low memory." : Print : Print 
      Centre "Don't be surprised, if Duenix suddenly quits."
      Fade 1,0,$F5A : Wait Key : Fade 1,0,0 : Wait 10
      Screen Close 3
   End If 

   Set Input $A,-1 : Led Off 
   
   _COMPILED=(Prg State=-1)
   
   DEBUGGING_LIFELIMIT_COEFICIENT=2
   _LOAD_DUENIX_FONT=_TRUE
   
   Default Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   
   Screen Open 1,320,256,32,Lowres
   Flash Off : Curs Off : Hide On 
   
   SET_CONSTANTS
   SET_SCANCODE_CONSTANTS
   WRITE_INITDATA
   
   BEGIN_LOADING
   
   For _PLAYER=1 To 6
      SELECTED(_PLAYER)=_FALSE
      COMPUTER_STRATEGY(_PLAYER)=_FALSE
      CYBORG(_PLAYER)=_FALSE
      _PLAYER_TYPE(_PLAYER)=0
      _TOP_LIVES(_PLAYER)=0
   Next _PLAYER
   
   DEMO_ON=_FALSE
   U_THRU=_FALSE
   
   '-----------------------------This is temporary----------------------
   
   FAST_INTERFACE=False
   WIND_TURNING=_FALSE
   _PLAYER_COLOURS_SET=0
End Proc
Procedure MAIN
   _GLOBAL_INITIALIZATION
   
   Do 
      SELECTING
      
      INITIALIZE_GAMESET
      ICON_AND_MUSIC_CARE_BEFORE_GAMESET
      If REPLAY_ALL_SAVED_ON and(_EXISTS_INDEX=False)
         Bank Swap 2,4
         WRITEXY[-2,100,NO_GAMERECORD_SAVED$]
         Bank Swap 2,4
         
         SELECTING_FADE_UP
         Clear Key : Wait Key : FAST_FADE_OUT
         Goto INDEX_FAULT
      End If 
      
      INITIALIZE_GAMESET____MIDDLE_PART
      
      Repeat 
         If REPLAY_ALL_SAVED_ON
            JUST_REPLAYING=_TRUE
         End If 
         
         _COUNT_SELECTED
         INITIALIZE_GAME
         GAME
         If REPLAY_ALL_SAVED_ON
            JUST_REPLAYING=_FALSE
            _EXISTS_INDEX=False
            Repeat 
               Inc INDEX
               If INDEX<100
                  INDEX$=Str$(INDEX)-" " : INDEX$=String$("0",2-Len(INDEX$))+INDEX$
                  _EXISTS_INDEX=Exist(GAME_SAVING_PATH$+RECORDNAME$+INDEX$)
               End If 
            Until _EXISTS_INDEX or(INDEX=100)
            ESC=ESC or _EXISTS_INDEX
         End If 
      Until WIN or ESC or JUST_REPLAYING or DEMO_ON
      
      If(ESC or JUST_REPLAYING or DEMO_ON)=0
         WINNERS_AND_LOSERS
      End If 
      
      If _SCREEN_SIZE>0
         Screen Close 3
      End If 
      
      If REPLAY_ALL_SAVED_ON or USER_REPLAYING
         _DECONFIG[Start(31),False]
      End If 
      
      INDEX_FAULT:
      
      Screen 2 : Palette 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
      Screen Close 1
      Screen Open 1,320,256,32,Lowres
      Flash Off : Curs Off : Hide On 
      Set Font FONT_NUMBER
      
      ICON_AND_MUSIC_CARE_AFTER_GAMESET
      If DEMO_ON
         DEMO_ENVIRONMENT[1]
      End If 
      REALIZE_PLAYER_TYPE
   Loop 
End Proc

Procedure EXTRACT_PATH[EX$]
   '  58 je code of :   47 je code of / 
   
   EX_TOP=Len(EX$)
   If EX_TOP>0
      EX_POS=EX_TOP
      OK=False
      Repeat 
         EX_VAL=Asc(Mid$(EX$,EX_POS,1))
         If(EX_VAL=47) or(EX_VAL=58)
            OK=True
         Else 
            EX$=Left$(EX$,Len(EX$)-1)
         End If 
         Dec EX_POS
      Until(EX_POS=0) or OK
   End If 
End Proc[EX$]


'             ______________________________________   
'            |                                      \    
'            |  @ Globals                            \   
'            |________________________________________\          



Global _TRUE,_FALSE,_NOT(),_T,_F,PATH$,_COMPILED,YEAR$,RELEASE$
Global _LOAD_DUENIX_FONT,CONSUMED_TIME,DEBUGGING_LIFELIMIT_COEFICIENT

Global X#(),Y#(),SMER(),NEW_X#(),NEW_Y#(),NEW_SMER()
Global _SPRITE_NUMBER(),_SPRITE_IMAGE()
Global TURNING(),COMPUTER_STRATEGY(),CYBORG(),ALIVE()
Global SCORE(),SELECTED(),SEMIALIVE(),SPACE_COUNTER(),LINE_COUNTER()
Global BOUND_THIS_ROUND(),BOUND_COUNTER(),REDRAW_PLAYER()
Global ACCEPT_KEYSTROKE(),_KEYSTROKE_COUNTER()
Global SPEED_SOURCE#()
Global UPP(),SPP()
Global TEAM_MATE_THRU(),TEAM_MATE()
Global GS_GAME_NAME$()
Global STAYED_ALIVE_BONUS(),_PLAYER_TYPE(),_PLAYER_PROPRIETY(),NEW_PLAYER()
Global _PLAYER_GREY_COLOUR(),PL_DEF_COLOR(),P_COLOR()
Global WIND_FACTOR#()
Global _BOB_PLAYER_IMAGE()
Global _PUTPIX_QUEUE_X(),_PUTPIX_QUEUE_Y(),_PUTPIX_QUEUE_COLOUR(),_PUTPIX_QUEUE_TOP
Global _PLAYER_RECORD(),PL_RGB(),_FREE_VALUE(),LIVING_PLAYER()
Global _NEXT_SOUND_FX_CHANNEL()
Global PL_DEF_COLOR_LIGHT(),PL_DEF_COLOR_DARK()
Global WRITE_KOI82IMAGE(),WRITE_KOI82HOOK(),ZOMBIE(),LINE_LENGTH_(),SPACE_LENGTH_()

Global RIGHT_PUSHED,LEFT_PUSHED,HELP
Global GR,GRP,_TOPSCORE,LONG_GAME
Global SMERU,ANGLE_CONSTANT#,SMERU_QUARTER,SMERU_HALVE
Global ZIJOU,HRAJOU,SPACE_LENGTH,LINE_LENGTH,_DRAWING_LINE_LENGTH
Global SPEED(),SPEED_PERCENT#(),SPEEDJUMP#,SPEEDJUMP
Global RATE,FINAL_RATE,RATEMODE,SPEEDING_UP_COUNTER,STILL_SPEEDING_UP,USER_RATE_LENGTH,RATEJUMP#
Global BODY_CHANGE,BODY_CHANGE_COUNTER,BODY_CHANGE_PERCENT,_EXPECTED_GAME_LENGTH
Global GAMES_PLAYED

Global ESC,WIN
Global GAMEPLANS,GAMEPLAN,PLAN
Global _PLAYER,ANGLE#
Global XBOTTOM,YBOTTOM,XTOP,YTOP
Global BASE,BASE1,BASE2
Global GAME_MUSIC_PLAYING,GAME_SLOWED,SOUND_FX_CHANNEL
Global _SCREEN_SIZE,_VIEWED_AREA_X,_VIEWED_AREA_Y
Global _DO_X_SCROLL,_DO_Y_SCROLL,X_SCROLL_LIMIT,Y_SCROLL_LIMIT

Global _MUSIC_TEMPO_JUMP#,_MUSIC_TEMPO#
Global RATE#,FINAL_RATE#
Global OWN_PLAN_PATH$
Global _RIGHT_LIMIT,_DOWN_LIMIT,_LEFT_LIMIT,_UP_LIMIT
Global X_WORK#,Y_WORK#,X_WORK,Y_WORK
Global SFX,SFY
Global ENABLED_MUSIC,ENABLED_SOUND
Global DEMO_ON,DEMO_TIMER_LIMIT

Global HLASKA$,PAUSED,LOCALE_PATH$,FONT_NUMBER,EN$
Global RECALCULATE_ANGLE,RECALCULATE_COORDINATES
Global LIVES_ON,LIVES(),_TOP_LIVES(),AUCH_COUNTER(),AUCH_PROTECTION(),LIVES_TOP
Global NUMBER_OF_LIVING_HUMANS
Global SHORT_CONFIG,CONFIG_LENGTH

Global CENTRAL_BOX,CENTRAL_BOX_SIZE
Global WATERING,WATER_LIMIT#,WATER_LIMIT
Global ALWAYS_TURNING,USER_DIRECTIONS
Global TURBOLIMIT,TELEPORTING,BOLDLINE
Global TURBO,COMPUTURBO,GO_FOR_COMPUTURBO
Global TEAM_GAME,SPACE_KILL,BOUNCING,_MUSIC_ON,SURPRISING_START
Global USER_SOUND_FX,SOUND_FX,COMPUDEATH,DIE_COMPUTERS,ZOMBIES
Global FAST_INTERFACE,_ONE_PLAYER_GAME
Global WIND,WIND_ANGLE,WIND_STRENGTH#,WIND_STRENGTH

Global GAME_MUSIC_IN_CHIP_RAM,MEMORY_REQUIREMENT

Global _SPRITE_INDEX_BASE
Global ESC_QUITED,_SHOW_SQ_LOGO

Global ALLOW_GAME_SAVING,GAME_SAVING_PATH$,INDEX$,INDEX
Global JUST_REPLAYING,JUST_RECORDING,J_REPLAYING_OR_J_RECORDING
Global RECORDING_ALLOWED
Global USER_RECORDING,GAME_RECORD_EMPTY
Global USER_REPLAYING,REPLAY_ALL_SAVED_ON
Global _PLAYER_COLOURS_SET,NUMBER_OF_SEMIALIVES

Global R_THRU,G_THRU,E_THRU,U_THRU
Global _SIN_ANGLE#,_COS_ANGLE#
Global _EXISTS_INDEX
Global X_TESTPOINT,Y_TESTPOINT
Global REDRAW_ANY_PLAYER,_ONLY_COMPUTERS_IN_GAME
Global _BOBS_USED,CYCLES

Global DEMOSTORE_PLAYSTATE()
Global DEMOSTORE_PLAN,DEMOSTORE_USER_RECORDING
Global DEMOSTORE_USER_REPLAYING,DEMOSTORE_REPLAY_ALL_SAVED_ON
Global DEMOSTORE_TEAM_GAME,DEMOSTORE_ENABLED_SOUND

'                 ______________________________________   
'                |                                      |    
'                |  Assembler CatchPoints Globals       |    
'                |______________________________________|            


Global BITPLAN_BASE,PA_CURRENT_PIX,PA_SMALL_PIX,PA_BIG_PIX,PA_SMALL_PIX_BIGSCREEN,PA_BIG_PIX_BIGSCREEN,VA_PQ_X,VA_PQ_Y,VA_PQ_COL,VA_PQ_TOP,VA_PUTPIX_TYPE,PA_DRAW_PIXEL_QUEUE
Global VA_PLAYER_RECORD,VA_GAME_RECORD,VA_GAME_RECORD_POINTER,PA_SAVE_POSITION,PA_LOAD_POSITION
Global VA_BITPLAN4,VA_SIN_TABLE,VA_ATAN_TABLE,VA_DIRECTIONS,VA_DIRECTION,VA_XAMOSREAL,VA_YAMOSREAL,PA_STRATEGY,PA_COUNTSINANDCOS,VA_ROTATION,VA_PLAYER,VA_XHASH,VA_YHASH,VA_PLAYERSDIR,VA_PLAYERALIVE
Global VA_DIRSTEP0,VA_DIRSTEP1,VA_DIRSTEP2,VA_DIRSTEP3,VA_DIRSTEP4,VA_PLAYERSCHOICE,VA_TURN,VA_BIGSCREEN,PA_TESTPROCEDURE,PA_COUNTTESTANDSPEEDPOINTS,PA_COUNTTESTANDSPEEDPOINTS_1PIX,PA_COUNTTESTANDSPEEDPOINTS_2PIX
Global PA_COUNTSPEEDPOINT,PA_COUNTSPEEDPOINT_1PIX,PA_COUNTSPEEDPOINT_2PIX,RECORD_BASE
Global PA_COUNTSINANDCOSFIXED

'                 _____________________________  
'                |                             | 
'                | "Constants" Definitions     | 
'                |_____________________________| 

Global _ERROR_BADPATH

Global BS_LEFT_TOP,BS_MIDDLE_TOP,BS_RIGHT_TOP,BS_LEFT_MIDDLE,BS_MIDDLE_MIDDLE,BS_RIGHT_MIDDLE,BS_LEFT_BOTTOM,BS_MIDDLE_BOTTOM,BS_RIGHT_BOTTOM
Global RECORDNAME$,DEMO_PRESS_SPACE_LIMIT,CONFIG_LENGTH
Global _PLAYER_TYPE_IMAGE(),STANDARD_PLAN_PAL$()
Global NO_IMAGE(),YES_IMAGE(),RED_BOX_IMAGE(),_FREE_FOR_MANIPULATION_IMAGE,SCORE_PANEL_BACKGROUND_IMAGE,HORIZONTAL_WOOD_IMAGE,CORNER_WOOD_IMAGE,VERTICAL_WOOD_IMAGE,NOSCROLL_CORNER_IMAGE,LIFE_BOX_IMAGE,PRESS_SPACE_IMAGE
Global DUENIX_TITLE_IMAGE,DUENIX_ANIM_IMAGE,MOUSE_ON_LINE_IMAGE,_JOY_ON_LINE_IMAGE
Global LATERAL_LEFT,LATERAL_RIGHT
Global _PLAYER_GREY_COLOUR()
Global OS_LC_BOX(),OS_RC_BOX()
Global EN$,CZ_SEND$,EN_SEND$,EN_VALUE$,_ADDRESS$
Global BOUND_SOUND,TELEPORT_SOUND,DEATH_SOUND,ARROW_SOUND,PRESS_SPACE_SOUND,AUCH_SOUND,BODY_CHANGE_SOUND

Global OS_LEFT_COLUMN_TEXT$(),OS_RIGHT_COLUMN_TEXT$(),MAIN_OPTION_TEXT$(),MAIN_OPTION_E_TEXT$,MAIN_OPTION_G_TEXT$,MAIN_OPTION_R_TEXT$,MAIN_OPTION_U_TEXT$,PAGE_ONE$,MAIN_OPTION_LOADING_AND_SAVING$
Global CONFIGURATION$,_PRESS_SPACE_OR_ESCAPE$,ESCAPE_ACCEPT$,SELECTING_UPPER_TEXT$(),SELECTING_LOWER_TEXT$(),PAGE_TWO$,GAME_SETTINGS$,GAME_SETTINGS_SPACE1$,GAME_SETTINGS_SPACE2$,PAGE_FOUR$,RECORD_AND_REPLAY$,RECORD_AND_REPLAY_SPACE$
Global RR_COLUMN_TEXT$(),CREATE_USER_GS_EXPLANATION$(),PAGE_FIVE$,CREATING_USER_GAMESET$,CREATE_USER_GAMESET$,SORRY$,_MINIMUM_OF_DIRECTIONS$,_MAXIMUM_OF_DIRECTIONS$,INSERT_VOLUME$,_NOT_ALL_FILES$(),_NOT_FONT$
Global OPERATION_ABORTED$,DUENIX_CONFIG_ISNT_CONFIG$,DEF_CONFIG_LOADED$,CANT_FIND_DEF_CONFIG1$,CANT_FIND_DEF_CONFIG2$,CONFIG_SAVED_AS_DEF1$,CONFIG_SAVED_AS_DEF2$,ENTER_CONFIGNAME$,THIS_FILE_ISNT_CONFIG$,CONFIG_LOADED$,FILE_DOESNT_EXIST$
Global ENTER_NAME_OF_CONFIG_TO_SAVE$,CONFIG_SAVED$,CONFIG_NOT_SAVED$,THIS_FILE_ALREADY_EXISTS$,WANT_TO_OVERWRITE$,_ORIGINAL_CONFIG_LOADED$,ENTER_NAME_OF_CONFIG_LIST_FILE$
Global NONE_OF_FILES_WAS_CONFIG1$,NONE_OF_FILES_WAS_CONFIG2$,YOUR_NEW_GAMESET_IS_SAVED$,MORE_THAN_20_FILES1$,MORE_THAN_20_FILES2$,NAME_OF_EMPTY_GAME_IN_GAMESET$,YOU_HAVENT_RECORDED1$,YOU_HAVENT_RECORDED2$,YOU_HAVENT_RECORDED3$
Global YOU_HAVENT_SAVED_GAME1$,YOU_HAVENT_SAVED_GAME2$,YOU_HAVENT_SAVED_GAME3$,_MAXIMUM_OF_WATER_ANGLE$,PAGE_THREE$,GAMEPLAN$,THIS_IS_STANDARD_GAMEPLAN_NUMBER$,HERE_MAY_BE_YOUR_PLAN$,HERE_IS_YOUR_PLAN$,GAMEPLAN_L_TEXT$
Global GAMEPLAN_EXPLANATION$(),THIS_IS_DEFPLAN$,GAMEPLAN_KEY_TEXT$(),ENTER_NAME_OFF_IFF_TO_LOAD$,PRESS_U_TO_SELECT_USER_GAME$,SELECT_GAME$,SELECT_GAME_FROM_USERSET$,NO_GAMERECORD_SAVED$,THE_WINNER$,THE_LOSER1$,THE_LOSER2$,THE_LOSERS$
Global _LOADING$

Global A_SCANCODE,B_SCANCODE,C_SCANCODE,D_SCANCODE,E_SCANCODE,F_SCANCODE,G_SCANCODE,H_SCANCODE,I_SCANCODE,J_SCANCODE,K_SCANCODE,L_SCANCODE,M_SCANCODE,N_SCANCODE,O_SCANCODE,P_SCANCODE,Q_SCANCODE,R_SCANCODE,S_SCANCODE,T_SCANCODE,U_SCANCODE,V_SCANCODE
Global W_SCANCODE,X_SCANCODE,Y_SCANCODE,Z_SCANCODE,ESC_SCANCODE,ENTER_SCANCODE,SPACE_SCANCODE

Global DEF_PLAN__BANK,STANDARD_PLAN__BANK,OWN_PLAN__BANK,PRECOUNTED_SIN__BANK,PRECOUNTED_ATAN__BANK,DEF_GAMESET__BANK,CONFIG_TEMPORARY__BANK,USER_GAMESET__BANK,LIFE_MOTION_MUSIC__BANK,WINNER_MUSIC__BANK
Global PLAN_BANK()

'             ______________________________________ 
'            |                                      |  
'            |  Silly variables                     |  
'            |______________________________________|          


Global A$,TEMP,TEMP#,I,P

Duenix strategy.s

[edit | edit source]
;__________________________________________________________________________________________________
;  Duenix Computer Strategy
;__________________________________________________________________________________________________
;
; This is Motorola 68000 assembly.
;
; The comments are in part original from years 1994-1998 and in part updated to make them more legible
; and comprehensive. Comments were added to make the code and logic easier to follow.
;
; The strategy is split between two turns/passes (probably for performance reasons); the choice to
; turn left, turn right or move straight on is made only at the end of the 2nd turn/pass. That is to say,
; the choice is made on every 2nd call from the AMOS code to the strategy.
;
; The core of the strategy is this: identify a set of directions to investigate: straight on, left 1, right 1
; left 2, right 2, etc. For each direction, determine how far one can go without hitting an obstacle,
; where an obstacle is the rectangle bounding the playground or a line drawn by another player.
; Then, turn left or right depending on whether the maximum length direction found is at the left
; or the right; or go straight on. The strategy starts at label DoStrategy.
;
; Additional logic covers the case where there are obstacles ahead rather close
; to the player, in which case letting large free space e.g. in left 4 or right 4 direction determine
; the decision would be a mistake.  The case is given by the condition
; Len0 * 2 <= 6 and Len0 * 2 < LenL1 and Len0 * 2 < LenR1.
; To achieve its objective, it sets blocks of LenL* and LenR* to zero in dependence on certain
; conditions, thereby disabling the impact of these LenL* values on the final decision.
; This logic starts at label DS_ArrowCollisionLogic.
;
; Additional logic reckons with where other players are and it is to be reverse
; engineered and documented. It seems to be replacing the direction lengths.
; This logic starts at label OtherPlayersCare. It is called from turn/pass 1.
;
; A small number of comments seems questionable or incorrect. Finding out what the proper correction
; would be was decided (in 2024) to be not worth the effort. One can learn something from
; the code and comments as they are. A search for "issue" should find places marked as potentially
; problematic.
;
; At the end of this file, there is a quick 68000 asm guide.
;__________________________________________________________________________________________________
; Constants
LengthLimit = 100
ASizeLimit  = 200            ;For handling of other players, the limit of the vector length ("a") above which
                             ;the logic is not applied.

BitPlan4    dc.l 0           ;The address of bitplan 4, where bitplans are numbered from 0; obstacles have a bit there
SinTable    dc.l 0           ;The table of precalculated sine values of directions
AtanTable   dc.l 0           ;The table of precalculated atan 

Directions  dc.l 80          ;The direction count (into how many direction angles the 360 degrees are to be divided)
DirStep0    dc.l 10          ;The step size of a small bend, expressed as an int in the units given by the above direction count
DirStep1    dc.l 20
DirStep2    dc.l 30
DirStep3    dc.l 40     
DirStep4    dc.l 50          ;The skips for different directions

Rotation    dc.l 15          ;The rotation radius
Direction   dc.l 60          ;The direction of motion, expressed as an integer in the units given by direction count
XAMOSReal   dc.l $80000045   ;X coordinate in AMOS real
YAMOSReal   dc.l $80000045   ;Y coordinate in AMOS real
Player      dc.l 0
XHash       dc.l $80000048   ;The address of an array of player x coordinate in AMOS real
YHash       dc.l $80000048   ;The address of an array of player y coordinate in AMOS real
PlayersDir  dc.l 46          ;The address of an array of directions of the players
PlayerOn    dc.l 0           ;The address of the indicator whether the player is playing, of an array
PlayersChoice dc.b 0,0,0,0   ;The choice made by the players in the previous turn/pass
            dc.b 0,0
Turn        dc.b 0           ;Which turn/pass is occurring; for a player this is global
IsBigScreen dc.b 0           ;1=We have big screen
        

        Bra DoStrategyDebug
;       Bra DoStrategy
        Bra CalculateSinAndCos
        Bra CalcTestAndSpeedPoints_1Pixel
        Bra CalcTestAndSpeedPoints_2Pixel
        Bra CalculateSinAndCosFixed

;_____________________________
;
;  Program Variables
;_____________________________

XFixed  dc.l 0      ;Fixed X coord
YFixed  dc.l 0      ;Fixed Y coord
XInt    dc.l $80
YInt    dc.l $80

;    ________________________________________________________________________________________________
;   |
;   | Convert AMOSReal to Fixed 
;   | 
;   | in:  d0 - AMOSReal input, assuming it is positive; negative numbers are malprocessed.
;   | out: d0 - Fixed-point output: 16.16 signed, but during the conversion, we do not reckon with
;   |           numbers not fitting into it.
;   | changed regs: d0, d1
;   |
;   | The logic:
;   | sub.l #$40,d1 .. AMOS convention .. we get the position of the decimal point.
;   | Now we want to shift the number by ($10-dec point position) to the right.
;   | Hence  Sub.l #$10,d1
;   |        Neg.l d1
;   |________________________________________________________________________________________________

ConvertAMOSRealToFixed
    Move.l  d0,d1
    And.l   #$FF,d1
    Sub.l   #$50,d1
    Neg.l   d1               ; d1 := $50 - (d0 & $FF)
    And.l   #$FFFFFF00,d0    ; in d0, erase the information about the decimal point
    Cmp.b   #$20,d1
    Ble     CARTF_1          ; if d1 > 32: return 0
    Moveq   #$0,d0
    Rts
CARTF_1
    Lsr.l   d1,d0            ; else: shift to the right to handle the decimal point
    Rts

;    ______________________________________________________________________________________________
;   |
;   | Test Length of Direction
;   |
;   | Determines the length to which the worm can go into the direction before it hits an obstacle,
;   | e.g. a worm line. The obstacle is determined as a filled bit in bitplan 4. (In a bitplan, there
;   | is a bit per pixel, so a byte covers 8 pixels. This means the worm line colors are in the range
;   | of 16-31 of the color palette.) Depends on the sin values calculated from the AMOS program and
;   | stored in SinTable; these values are in the AMOS real format and need to be converted
;   | to fixed-point representation (the int part in the upper word, the after dec.point part
;   | in the lower word).
;   |
;   | in:        d0     = Direction (integer in units given by the number of directions)
;   | out:       d7     = Length
;   | changed registers: d-all a0, a6
;   |______________________________________________________________________________________________

TestLengthOfDirection
    
    ;____________________________
    ; Calculate Sin and Cos
    ;____________________________

    Move.l Directions(pc),d6
    Lsr.w  #2,d6             ;d6 := direction count / 4 (DirCntQuarter)
    Move.l d0,d7             ;d7 := direction
    Divu.w d6,d7             ;d7 := direction / (direction count / 4)
                             ;remainder is saved in the upper word or d7; d7.w has quadrant
    Move.l d7,d1
    Swap   d1
    Ext.l  d1                ;d1 := remainder of direction / (direction count / 4)

    Btst   #0,d7
    Beq TL_FinalDir
    Sub.l  d6,d1
    Neg.l  d1                ;dir = -(dir - direction count / 4)
TL_FinalDir

    ;Now d1 == DifDirection
    Move.l d1,d5             ;Store DifDirection In (d5 is free yet)
    Asl.l  #2,d1             ;d1 := d1 * 4
    Move.l SinTable(pc),a0
    Move.l (a0,d1),d0
    Bsr    ConvertAMOSRealToFixed

    ;If required, multiply by -1
    Btst   #1,d7
    Beq TL_SinCalculated     ;If the quadrant is 2 or 3 => minus
    Neg.l  d0
TL_SinCalculated
    Move.l d0,d3             ;d3 := WorkSin just calculated

    Move.l d6,d2             ;d2 := DirCntQuarter
    Sub.w  d5,d2             ;d2 := DirCntQuarter-DifDirection
    Asl.l  #2,d2
    Move.l SinTable(pc),a0
    Move.l (a0,d2),d0
    Bsr    ConvertAMOSRealToFixed

    Move.b d7,d2             ;d2 := quadrant
    Add.b  #1,d2
    Btst   #1,d2
    Beq TL_CosCalculated
    Neg.l  d0
TL_CosCalculated
    Move.l d0,d4             ;d4 := WorkCos just calculated
    
    ;  Set start position
    Move.l XFixed(pc),d5
    Move.l YFixed(pc),d6

    ;____________________________
    ; Go straight
    ;____________________________

    ;a6: Bitplan4
    ;d3: worksin
    ;d4: workcos
    ;d5: XFixed
    ;d6: YFixed
    ;d7: length
        
    ;____________________________
    ;  First two times forth
    ;____________________________

    Move.l BitPlan4(pc),a6
    Cmp.w  #0,d7             ;Is quadrant 0?
    Beq  TL_QUAD_ZERO
    Moveq  #0,d7
    Bra    TL_TwoTimes
TL_QUAD_ZERO
    Moveq  #1,d7
TL_TwoTimes
    Add.l  d3,d5             ;XFixed := XFixed + worksin
    Add.l  d4,d6             ;YFixed := YFixed + workcos
    DBra   d7,TL_TwoTimes    ;Decrement and branch unless the result is -1

    Moveq  #0,d7             ;Clear length

    Move.b IsBigScreen(pc),d0
    Bne TL_GoStraight_BS

TL_GoStraight
    
    Addq   #1,d7             ;line length := line length + 1

    Add.l  d3,d5             ;XFixed := XFixed + worksin
    Move.l d5,d0             ;d0 := XFixed
    Swap   d0;               ;d0 := X (the int part of XFixed, with the upper 16 bit dirty)
    ; No need to extend since in the following, we work with word.

    Add.l  d4,d6             ;YFixed := YFixed + workcos
    Move.l d6,d1             ;d1 := YFixed
    Swap   d1
    And.l  #$FFFF,d1         ;d1 := Y (the int part of YFixed)

    ;d1 := Y * 40 (40 = screen x size / 8)
    Asl.w   #3,d1
    Move.w  d1,d2
    Asl.w   #2,d2
    Add.w   d2,d1

    ;d1 := d1 + X / 8
    Move.w  d0,d2
    Lsr.w   #3,d2
    Add.w   d2,d1

    ;d1 == the offset of the address from the beginning of BitPlan4

    ;d0 := (X bitand 7) xor 7 == the bit number in the byte
    And.b   #7,d0
    Eor.b   #7,d0

    Btst.b  d0,(a6,d1)       ;test d0 bit from BitPlan4
    Bne  TL_Finished         ;as long as zero, go on
    Cmp.b  #LengthLimit,d7
    Bls  TL_GoStraight 
TL_Finished
    Rts

    ;  Go straight (for big screen)
TL_GoStraight_BS

    Addq   #1,d7             ;line length := line length + 1

    Add.l  d3,d5             ;XFixed := Xfixed + worksin
    Move.l d5,d0             ;d0:=XFixed 
    Swap   d0
    ; No need to extend since in the following, we work with word.

    Add.l  d4,d6             ;YFixed := Yfixed + workcons
    Move.l d6,d1             ;d1:=YFixed
    Swap   d1
    And.l  #$FFFF,d1

    ;d1 := d1 * 80
    Asl.w   #4,d1
    Move.w  d1,d2
    Asl.w   #2,d2
    Add.w   d2,d1

    ;d1 := d1 + X / 8
    Move.w  d0,d2
    Lsr.w   #3,d2
    Add.w   d2,d1

    ;d1 == the offset of the address from the beginning of bitplan 4
    
    ;d0 := (X bitand 7) xor 7 == the bit number in the byte
    And.b   #7,d0            ;V D0 je pocet bitu
    Eor.b   #7,d0

    Btst.b  d0,(a6,d1.l)    ;test d0 bit from bitplan 4
    Bne  TL_Finished_BS     ;as long as zero, go on
    Cmp.b  #LengthLimit,d7   
    Bls  TL_GoStraight_BS 
TL_Finished_BS       
    Rts


; _____________________________________________________________________________
;| DoStrategy
;|
;| d5: Tested Direction.Variable
;|
;| Inputs: XAMOSReal(pc), YAMOSReal(pc), Directions(pc), Direction(pc),
;|         Rotation(pc)
;|
;| output d7: 0: no action, 1: turn left, 2: turn right
;|_____________________________________________________________________________

DS_Len0 dc.l 18      ;length in the straight direction
DS_LenL1 dc.l 17     ;length in the left 1 direction
DS_LenR1 dc.l 23     ;length in the right 1 direction
DS_LenL2 dc.l 101    ;length in the left 2 direction
DS_LenR2 dc.l 200    ;length in the right 2 direction
DS_LenL3 dc.l 14     ;length in the left 3 direction
DS_LenR3 dc.l 13     ;length in the right 3 direction
DS_LenL4 dc.l 101    ;length in the left 4 direction
DS_LenR4 dc.l 200    ;length in the right 4 direction
DS_LenL5 dc.l 3      ;length in the left 5 direction
DS_LenR5 dc.l 8      ;length in the right 5 direction

DS_PrecalculatedLens
    ds.l 6*8         ;For all players, obstacle-free lengths calculated in turn/pass 0, to be used in turn/pass 1.
                     ;There is a room for 8 lengths per player, but only 5 lengths are stored.

DS_ArrowDecisionStore
        dc.l 0,0     ;6 bytes of one of 0, 1, and 2, one per player

; a2: DirStore
; a3: Directions
; a4: Pointer to DS_Len Table 
; a5: Dirs 1/6

DoStrategy

    ;-------------------------------------------------
    ; Convert XAMOSReal to XFixed and XInt
    ;-------------------------------------------------
    Move.l XAMOSReal(pc),d0
    Bsr    ConvertAMOSRealToFixed
    Lea.l  XFixed(pc),a0
    Move.l d0,(a0)
    Swap   d0
    Ext.l  d0
    Lea.l  XInt(pc),a0
    Move.l d0,(a0)

    ;--------------------------------------------------
    ; Convert YAMOSReal to YFixed and YInt
    ;--------------------------------------------------
    Move.l YAMOSReal(pc),d0
    Bsr    ConvertAMOSRealToFixed
    Lea.l  YFixed(pc),a0
    Move.l d0,(a0)
    Swap   d0
    Ext.l  d0
    Lea.l  YInt(pc),a0
    Move.l d0,(a0)

    ;------------------------
    ; Pick turn
    ;------------------------    
    Btst.b #0,Turn(pc)
    Bne    DS_Turn1

    ;--------------------
    ; TURN ZERO
    ;--------------------

DS_Turn0

    ;--------------------
    ; Fill variables
    ;--------------------
    Lea.l  DS_Len0(pc),a4
    Move.l Directions(pc),a3

    ; ----------------------------------------------
    ; Calculate the length of the straight direction
    ; ----------------------------------------------
    Move.l Direction(pc),d0
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of the left 1 direction
    ; ----------------------------------------------
    Move.l DirStep0(pc),a5
    Move.l Direction(pc),d0 
    Add.l  a5,d0
    Cmp    d0,a3
    Bhi    DS_OK0           ;d0 < a3
    Sub.l  a3,d0            
DS_OK0
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+     

    ; ----------------------------------------------
    ; Calculate the length of the right 1 direction
    ; ----------------------------------------------
    Move.l Direction(pc),d0
    Cmp    d0,a5
    Bls    DS_OK1       ;d0 >= a5
    Add.l  a3,d0    
DS_OK1  Sub.l  a5,d0    
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of the left 2 direction
    ; ----------------------------------------------
    Move.l DirStep1(pc),a5
    Move.l Direction(pc),d0 
    Add.l  a5,d0
    Cmp    d0,a3
    Bhi    DS_OK2           ;d0 < a3
    Sub.l  a3,d0            
DS_OK2
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+     

    ; ----------------------------------------------
    ; Calculate the length of the right 2 direction
    ; ----------------------------------------------
    Move.l Direction(pc),d0
    Cmp    d0,a5
    Bls    DS_OK3       ;d0 >= a5
    Add.l  a3,d0    
DS_OK3  Sub.l  a5,d0
    Move.l d0,a2            ;Store
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ---------------------
    ; OtherPlayersCare
    ; ---------------------
    Bsr OtherPlayersCare

    ;-----------------------------------------------
    ; Return the choice made in previous turn via d7
    ;-----------------------------------------------
    Move.l Player(pc),d0
    Lea.l  PlayersChoice(pc),a0
    Moveq  #0,d7
    Move.b (a0,d0),d7        ;d7 := PlayersChoice[Player]

    ;----------------------
    ; Store lengths
    ;----------------------
    ;DS_PrecalculatedLens[0, 1, ...] := DS_Len0, DS_LenL1, ...
    Asl.w  #5,d0             ;d0 := player no * 4 * 8
    Moveq  #5,d1             ;This could also be only 4.
    Lea.l  DS_PrecalculatedLens(pc),a0
    Add.l  d0,a0
    Lea.l  DS_Len0(pc),a1
DS_StoreLensLoop
    Move.l (a1)+,(a0)+  
    Dbra   d1,DS_StoreLensLoop

    ;----------------------
    ; Debugging
    ;----------------------
    Move.l Player(pc),d0
    Lea.l  DS_ArrowDecisionStore(pc),a0
    Move.b (a0,d0),d0       ;d0 := DS_ArrowDecisionStore[Player]
    Moveq  #1,d6
    Tst.b  d0
    Bne    DS_DebugSkip
    Moveq  #0,d6
DS_DebugSkip
    Rts

    ;----------------------
    ; TURN ONE
    ;----------------------

DS_Turn1
    ;----------------------
    ; Load lengths
    ;----------------------

    Move.l Player(pc),d0
    Asl.w  #5,d0        ;d0 := player*4*8

    Moveq  #5,d1        ; This could also be only 4.
    Lea.l  DS_PrecalculatedLens(pc),a0
    Add.l  d0,a0
    Lea.l  DS_Len0(pc),a1
DS_LoadLensLoop
    Move.l (a0)+,(a1)+  
    Dbra   d1,DS_LoadLensLoop

    ;--------------------
    ; Fill variables
    ;--------------------

    Lea.l  DS_LenL3(pc),a4
    Move.l Directions(pc),a3

    ; ----------------------------------------------
    ; Calculate the length of the left 3 direction
    ; ----------------------------------------------
    Move.l DirStep2(pc),a5
    Move.l Direction(pc),d0 
    Add.l  a5,d0
    Cmp    d0,a3
    Bhi    DS_1OK0          ;d0 < a3
    Sub.l  a3,d0            
DS_1OK0
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of right 3 direction
    ; ----------------------------------------------
    Move.l Direction(pc),d0
    Cmp    d0,a5
    Bls    DS_1OK1      ;d0 >= a5
    Add.l  a3,d0    
DS_1OK1 Sub.l  a5,d0
    
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of left 4 direction
    ; ----------------------------------------------
    Move.l DirStep3(pc),a5
    Move.l Direction(pc),d0 
    Add.l  a5,d0
    Cmp    d0,a3
    Bhi    DS_1OK2          ;d0 < a3
    Sub.l  a3,d0            
DS_1OK2
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of right 4 direction
    ; ----------------------------------------------
    Move.l Direction(pc),d0
    Cmp    d0,a5
    Bls    DS_1OK3      ;d0 >= a5
    Add.l  a3,d0    
DS_1OK3 Sub.l  a5,d0
    
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of left 5 direction
    ; ----------------------------------------------
    Move.l DirStep4(pc),a5
    Move.l Direction(pc),d0 
    Add.l  a5,d0
    Cmp    d0,a3
    Bhi    DS_1OK4          ;d0 < a3
    Sub.l  a3,d0            
DS_1OK4
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ; ----------------------------------------------
    ; Calculate the length of right 5 direction
    ; ----------------------------------------------
    
    Move.l Direction(pc),d0
    Cmp    d0,a5
    Bls    DS_1OK5      ;d0 >= a5
    Add.l  a3,d0    
DS_1OK5 Sub.l  a5,d0
    Bsr    TestLengthOfDirection
    Move.l d7,(a4)+

    ;------------------------------------------------------
    ; Rotation radius and arrow collision special logic
    ;------------------------------------------------------
    ; An "arrow" collision is the following condition:
    ; Len0 * 2 <= 6 and Len0 * 2 < LenL1 and Len0 * 2 < LenR1
    ; In words, the straight ahead len is small, and
    ; LenL1 and LenR1 are greater than twice the straight ahead len.
    ; On a new arrow collision, make the decision only
    ; based on LenL1 and LenR1 and not the other
    ; LenL* and LenR*.
    ; There is a certain stickiness to the decision from a previous turn/pass,
    ; as per the above jump to DS_WasArrowCollision.
    ;------------------------------------------------------
    
DS_ArrowCollisionLogic
    Move.l  #0,d6           ;DEBUG

    Move.l Player(pc),d0
    Lea.l  DS_ArrowDecisionStore(pc),a0
    Move.b (a0,d0),d0        ;d0 := DS_ArrowDecisionStore[Player]
    Tst.b  d0
    Bne    DS_WasArrowCollision

DS_WasntArrowCollision

    ;Set fractions of the radius of the rotation into d1, d2, d3, d4 and d5
    Move.l Rotation(pc),d1   ;d1 := the radius of the rotation
    ;   Move.l d1,d2
    ;   Lsr.w  #3,d2            
    ;   Sub.w  d1,d2
    ;   Neg.w  d2            ;d2 := 7/8 * the radius
    Move.l d1,d2
    Lsr.w  #2,d2            
    Move.l d2,d5             ;d5 := 1/4 * the radius
    Sub.w  d1,d2
    Neg.w  d2                ;d2 := 3/4 * the radius
    Addq   #2,d2    
    Move.l d1,d3
    Lsr.w  #1,d3             ;d3 := 1/2 * the radius
    Addq   #4,d3
    Move.l d2,d4
    Lsr.w  #1,d4             ;d4 := 3/8 * the radius

    ; Check for arrow collision
    Move.l DS_Len0(pc),d0
    Lsr.w  #1,d0
    Cmp.l  #6,d0
    Bgt    DS_NotNewArrowCollision       ;if DS_Len0 * 2 > 6: branch to DS_NotNewArrowCollision
    ;   Cmp.l  d0,d4
    ;   Bls    DS_NotNewArrowCollision
    Cmp.l  DS_LenL1(pc),d0
    Bge    DS_NotNewArrowCollision       ;if DS_Len0 * 2 >= DS_LenL1: branch to DS_NotNewArrowCollision
    Cmp.l  DS_LenR1(pc),d0
    Blt    DS_NewArrowCollision          ;if DS_Len0 * 2 < DS_LenR1: branch to DS_NewArrowCollision

DS_NotNewArrowCollision
    ; If LenL* or LenR* are so small that turning left or right becomes too tight given the rotation radius,
    ; zero all directions at the same side with a higher index;
    ; then branch to DS_FindMax.
    ; Rationale: the FindMax logic takes plain maximum from L* and R*, and thus, free space in
    ; e.g. L4 overrides lack of free space in L1. The above zeroing makes sure that the tight
    ; conditions near to the ahead direction prevail in the decision.

DS_Left_Care
    Cmp.l  DS_LenL1(pc),d3
    Bgt  DS_L1_Collision            ;if 1/2 * the radius > DS_LenL1: branch to DS_L1_Collision
    Cmp.l  DS_LenL2(pc),d2
    Bgt  DS_L2_Collision            ;if 3/4 * the radius > DS_LenL2: branch to DS_L2_Collision
    Cmp.l  DS_LenL3(pc),d3           
    Bgt  DS_L3_Collision;           ;if 1/2 * the radius > DS_LenL3 (changed from d1, which is the radius)
DS_Right_Care
    Cmp.l  DS_LenR1(pc),d3
    Bgt  DS_R1_Collision            ;if 1/2 * the radius > DS_LenR1: branch to DS_R1_Collision
    Cmp.l  DS_LenR2(pc),d2
    Bgt  DS_R2_Collision            ;if 3/4 * the radius > DS_LenR2: branch to DS_R2_Collision
    Cmp.l  DS_LenR3(pc),d3
    Bgt  DS_R3_Collision            ;if 1/2 * the radius > DS_LenR3 (changed from d1, which is the radius)

    Bra  DS_FindMax

DS_L1_Collision
    Moveq  #0,d0
    Lea.l  DS_LenL2(pc),a0
    Move.l d0,(a0)+                 ;DS_LenL2 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenL3 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenL4 := 0
    Addq   #4,a0
    Move.l d0,(a0)                  ;DS_LenL5 := 0
    Bra DS_Right_Care

DS_L2_Collision
    Moveq  #0,d0
    Lea.l  DS_LenL3(pc),a0
    Move.l d0,(a0)+                 ;DS_LenL3 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenL4 := 0
    Addq   #4,a0
    Move.l d0,(a0)                  ;DS_LenL5 := 0
    Bra DS_Right_Care

DS_L3_Collision
    Moveq  #0,d0
    Lea.l  DS_LenL4(pc),a0
    Move.l d0,(a0)+                 ;DS_LenL4 := 0
    Addq   #4,a0    
    Move.l d0,(a0)                  ;DS_LenL5 := 0
    Bra DS_Right_Care

DS_R1_Collision
    Moveq  #0,d0
    Lea.l  DS_LenR2(pc),a0
    Move.l d0,(a0)+;                ;DS_LenR2 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenR3 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenR4 := 0
    Addq   #4,a0
    Move.l d0,(a0)                  ;DS_LenR5 := 0
    Bra  DS_FindMax
    
DS_R2_Collision
    Moveq  #0,d0
    Lea.l  DS_LenR3(pc),a0
    Move.l d0,(a0)+                 ;DS_LenR3 := 0
    Addq   #4,a0
    Move.l d0,(a0)+                 ;DS_LenR4 := 0
    Addq   #4,a0
    Move.l d0,(a0)                  ;DS_LenR5 := 0
    Bra  DS_FindMax
    
DS_R3_Collision
    Moveq  #0,d0
    Lea.l  DS_LenR4(pc),a0
    Move.l d0,(a0)+                 ;DS_LenR4 := 0
    Addq   #4,a0
    Move.l d0,(a0)                  ;DS_LenR5 := 0
    Bra  DS_FindMax

DS_WasArrowCollision              ;There was an arrow collision in the previous frame.
    ;Preserve the previously made turn left or turn right decision driven by arrow collision
    ;unless quitting condition obtains
    Move.l DS_Len0(pc),d1
    Cmp.l  DS_LenL1(pc),d1
    Bge  DS_QuitArrowCollision    ;if DS_Len0 >= DS_LenL1: branch to DS_QuitArrowCollision
    Cmp.l  DS_LenR1(pc),d1
    Bge  DS_QuitArrowCollision    ;if DS_Len0 >= DS_LenR1: branch to DS_QuitArrowCollision

    Move.l d0,d7                  ;d7 := DS_ArrowDecisionStore[Player]

    Move.l  #$1,d6                ;DEBUG

    Bra DS_Store_Decision

DS_QuitArrowCollision
    Move.l Player(pc),d0
    Move.b #0,(a0,d0)             ;DS_ArrowDecisionStore[Player] := 0
    Bra DS_WasntArrowCollision

DS_NewArrowCollision
    Moveq  #1,d7                  ;#1: turn left
    Move.l DS_LenL1(pc),d0
    Cmp.l  DS_LenR1(pc),d0
    Bge    DS_NAC_DirInD7         ;if DS_LenL1 >= DS_LenR1: branch to DS_NAC_DirInD7
    Moveq #2,d7                   ;#2: turn right
DS_NAC_DirInD7
    Move.l Player(pc),d0
    Move.b d7,(a0,d0)             ;DS_ArrowDecisionStore[Player] := d7

    Move.l #$1,d6                 ;DEBUG

    Bra DS_Store_Decision
    
    ;------------------------------------------------------
    ; Find max direction length and max index of the length
    ;------------------------------------------------------
DS_FindMax
    Lea.l  DS_Len0(pc),a4
    Moveq  #$A,d0
    Moveq  #0,d1        ;lenMax: max value of length
    Moveq  #0,d2        ;lenMaxIdx: index of max length
DS_DecLoop
    Move.l (a4)+,d3
    Cmp.w  d1,d3
    Bls    DS_NotHigher ;if DS_LenX <= lenMax: goto DS_NotHigher
    Move.w d3,d1        ;lenMax := value
    Move.b d0,d2        ;lenMaxIdx := index of the max value found
DS_NotHigher
    DBra   d0,DS_DecLoop

    ;------------------------------------------------------------------------
    ; Calculate decision number (0, 1, 2) and store it to PlayersChoice array
    ;------------------------------------------------------------------------
    Cmp.b  #$A,d2
    Beq    DS_STRAIGHT_ON_INDEX   
    
    ; d7 := ((lenMaxIdx bitand 1) xor 1) + 1
    And.b  #1,d2
    Eor.b  #1,d2
    Add.b  #1,d2
    Move.l d2,d7        ;Save to decision register, d7

DS_Store_Decision
    Move.l Player(pc),d0
    Lea.l  PlayersChoice(pc),a0
    Move.b d7,(a0,d0)   ;PlayersChoice[Player] := decision (0: no action, 1: turn left, 2: turn right)
    Rts

DS_STRAIGHT_ON_INDEX
    Moveq  #0,d7        ;Save to decision register
    Bra DS_Store_Decision


; ___________________________________________________________________
;| Handle other players
;|___________________________________________________________________
;| Take into account a possible collision with a future trajectory
;| of other players and potentially change/reduce the calculated
;| lengths for how far one can go in different directions, thereby
;| affecting the decision to turn left or right or stay moving straight on.
;| The projected trajectory is a linear extension of the
;| current direction.
;|
;| The detail of the logic seems difficult to understand in retrospect (2024).
;| It involves the calculation of a certain vector, its size and a direction,
;| certain angles, certain other values based on these angles,
;| sin values of these values, a ratio of these sin values,
;| and a certain length times the ratio.
;|
;| Input: PlayerOn, PlayersDir, XHash, YHash, XInt 
;|        YInt, Direction
;| Affected: DS_Len0, DS_LenL1, DS_LenL2, DS_LenR1, DS_LenR2.
;|
;| Loop registers:
;| a1: plrNoTimesFour: other player no * 4 (an outer loop variable)
;| a2: ownPlrExamDirection: the examined own player direction,
;|     initially the own player direction itself and then its modifications
;| a3: directionLoopVar: driving variable of the direction loop
;| Other register with invariant meaning:
;| a4: othPlrDirection: a player direction
;|
;| This procedure does not depend on any registers for input or output.
;|___________________________________________________________________

OP_PlayerX  dc.l 0
OP_PlayerY  dc.l 0
OP_A        dc.l 0

OtherPlayersCare
    Move.l #20,a1           ;for plrNoTimesFour from 5*4 to 0*4, step -4
    
OP_PlayersLoop_Start
    Move.l PlayerOn(pc),a0
    Tst.l  (a0,a1)
    Beq OP_PlayerFinished   ;if PlayerOn[plrNoTimesFour] == 0, skip the player.

    Move.l PlayersDir(pc),a0
    Move.l (a0,a1),a4       ;othPlrDirection := PlayersDir[plrNoTimesFour]

    ;----------------------------------------------------------------
    ; Calculate dx and dy; and the vector quadrant
    ;----------------------------------------------------------------
    ; dx := abs(other player x int - the own player x int)
    ; dy := abs(other player y int - the own player y int)
    ; d2 := quadrant of the dx, dy vector before applying the abs
    ;----------------------------------------------------------------

    Move.l YHash(pc),a0
    Move.l (a0,a1),d0
    Bsr   ConvertAMOSRealToFixed
    Swap   d0
    Move.w d0,d3            ;d3.w := Y#[plrNoTimesFour] converted to int

    Move.l XHash(pc),a0
    Move.l (a0,a1),d0
    Bsr   ConvertAMOSRealToFixed 
    Swap   d0
    Ext.l  d0               ;d0 := int(X#[plrNoTimesFour])
    Move.w d3,d1
    Ext.l  d1               ;d1 := int(Y#[plrNoTimesFour])
    Sub.l  XInt(pc),d0      ;d0 := int(X#[plrNoTimesFour]) - XInt
    Sub.l  YInt(pc),d1      ;d1 := int(Y#[plrNoTimesFour]) - YInt
    Tst.l  d0
    Bmi    OP_XMinus
    Tst.l  d1
    Bmi    OP_XPlus_YMinus
OP_XPlus_YPlus    
    Moveq  #0,d2            ;quadrant is 0
    Bra    OP_Quadrant_Calculated
OP_XPlus_YMinus
    Moveq  #1,d2            ;quadrant is 1
    Neg.l  d1
    Bra    OP_Quadrant_Calculated
OP_XMinus
    Tst.l  d1
    Bmi    OP_XMinus_YMinus
OP_XMinus_YPlus
    Moveq  #3,d2            ;quadrant is 3
    Neg.l  d0
    Bra    OP_Quadrant_Calculated
OP_XMinus_YMinus
    Neg.l  d0
    Neg.l  d1
    Moveq  #2,d2            ;quadrant is 2
OP_Quadrant_Calculated 

    ;--------------------------------------------

    ; If dx == 0 and dy == 0, finish the business.
    Tst.w  d1
    Bne OP_DxDyNotZero
    Tst.w  d0
    Beq OP_PlayerFinished

    ;----------------------------------------------------------------
    ; Calculate the direction of the dx, dy vector given the quadrant
    ;----------------------------------------------------------------
    
OP_DxDyNotZero
    Move.l d1,d7            ;d7 := dy
    Move.l d0,d6            ;d6 := dx

    Cmp.w  d1,d0
    Bls    OP_ReverseOK     ;if dx <= dy: goto OP_ReverseOK
OP_ReverseDo
    Asl.w  #8,d1
    Divu.w d0,d1            ;d1 == tan(alpha)*$100, which is d1 * $100/d0, which is dy * $100/dx
    Ext.l  d1
    Move.l AtanTable(pc),a0
    Moveq  #0,d3
    Move.b (a0,d1),d3       ;d3 := ATan(d1), in the directions units
    Move.l Directions(pc),d4
    Lsr.w  #2,d4            ;d4 := DirectionsQuarter
    Sub.w  d3,d4            ;d4 := DirectionsQuarter - ATan(d1), in the directions units
    Bra OP_Correct_Angle_Using_Quadrant
OP_ReverseOK                ;d0 <=d1         
    Asl.w  #8,d0
    Divu.w d1,d0            ;d0 == tan(alpha)*$100, which is d0 * $100/d1, which is dx * $100/dy
    Ext.l  d0
    Move.l AtanTable(pc),a0
    Moveq  #0,d4
    Move.b (a0,d0),d4       ;d4 := ATan(d0) in the directions units
OP_Correct_Angle_Using_Quadrant
    Move.l Directions(pc),d3
    Lsr.w  #1,d3            ;d3 := DirectionsHalf
    Btst   #0,d2            ;Is it 1 or 3 quadrant?
    Beq OP_TestBit2         ;It isn't.
    Sub.w  d3,d4
    Neg.w  d4               ;d4 := DirectionsHalf - Direction
OP_TestBit2
    Btst   #1,d2            ;Is it 2 or 3 quadrant?
    Beq OP_VectorDirectionCalculated
    Add.w  d3,d4            ;d4 := d4 + DirectionsHalf
                            ;This pertains only to quadrant 3
    Cmp.l  Directions(pc),d4    
    Bne    OP_VectorDirectionCalculated
    Moveq  #0,d4;           ;if d4 == 2 * pi: d4 := 0
OP_VectorDirectionCalculated
    
    ;-----------------------------
    ; d4: direction of vector
    ; d6: dx                    
    ; d7: dy                    
    ;-----------------------------
    ; Calculate the size of vector
    ;-----------------------------
    Bsr CalculateVectorSize
    Move.l d6,d0               ;d0 := vector size of dy and dy

    ;---------------------------
    ; We need to preserve:
    ; d0: a (the vector size of dy and dy)
    ; d4: ownToOthrVectorDir: direction of vector
    ; Issue: it needs to be verified that the above is really a direction from own player
    ; to the other player rather than the other way around.
    ;---------------------------

    Cmp.w  #ASizeLimit,d0
    Bhi OP_PlayerFinished      ;if vector size > ASizeLimit: goto OP_PlayerFinished
    Move.l #100,a6             ;DEBUG

    ;-----------------------------------
    ; A loop for own player directions
    ;-----------------------------------
    ;Direction will be in a2
    ;a3: loop variable 4->0 (init to 5, but the first taking into account is a decrement)

    Move.l Direction(pc),a2    ;a2 := the own player direction (loop initialization)
    Move.l #5,a3               ;directionLoopVar := straight ahead
OP_DirectionLoop_Start

    ;Let's check possibilities
    Cmp.w  a2,d4
    Beq  OP_LengthIsA          ;if the own player direction == direction of vector: goto OP_LengthIsA
    Move.l #$FFFF,d1           ;length := $FFFF
    
    ;------------------------------------------------------------------------------------
    ; Calculate alpha and beta
    ;------------------------------------------------------------------------------------
    ; alpha := direction of the vector - other player direction, normalized to positive value
    ; beta := direction of the vector - own player direction, normalized to positive value
    ; The normalization to positive value is adding 2 * pi if required.
    ; The alpha and beta angles are expressed in direction count units as integers.
    ; d7 := alpha; d6 := beta    
    ;------------------------------------------------------------------------------------

    Move.l a4,d3               ;d3 := othPlrDirection
    Move.l d4,d7               ;d7 := direction of vector
    Sub.l  d3,d7               ;d7 := direction of vector - othPlrDirection
    Bpl    OP_AlphaCalculated
    Add.l  Directions(pc),d7
OP_AlphaCalculated             ;d7 := alpha (direction of vector - othPlrDirection, norm. to positive value)

    Move.l a2,d3               ;d3 := own player direction
    Move.l d4,d6               ;d6 := direction of vector
    Sub.l  d3,d6
    Bpl    OP_BetaCalculated
    Add.l  Directions(pc),d6
OP_BetaCalculated              ;d6 := beta (direction of vector - own player direction, norm. to positive value)

    Move.l Directions(pc),d3
    Lsr.w  #1,d3               ;d3:= pi (=directions half)

    ;----------------------------------------------------------------
    ; Compare alpha and beta
    ; Issue: a description or a specification could be added here.
    ;----------------------------------------------------------------
    ; at time of entry: d7 == alpha; d6 == beta; d3 == pi
    ;----------------------------------------------------------------

    Cmp.w  d3,d7
    Bls OP_AlphaNotGtThanPi ;if alpha <= pi: goto OP_AlphaNoGtThanPi
    Cmp.w  d3,d6
    Bls OP_NoCollision      ;if alpha > pi and beta <= pi: goto OP_NoCollision

    ; Holds true: alpha > pi and beta > pi

    Asl.w  #1,d3            ;d3 := 2 * pi
    Sub.l  d3,d7
    Neg.l  d7               ;d7 := -(alpha - 2 * pi) == 2 * pi - alpha
    Sub.l  d3,d6
    Neg.l  d6               ;d6 := -(beta - 2 * pi) == 2 * pi - beta
    Lsr.w  #1,d3            ;d3 := pi
    Bra OP_MainAlphaBetaCase

OP_AlphaNotGtThanPi
    Cmp.w  d3,d6
    Bhi OP_NoCollision      ;if alpha <= pi and beta > pi: goto OP_NoCollision
OP_MainAlphaBetaCase
    ;----------------------------------------------------------------
    ; Handle main case
    ;----------------------------------------------------------------
    ; d6 and d7 are a) beta and alpha or b) 2 * pi - beta and 2 * pi - alpha.
    ; d7: alpha2; d6: beta2 (let us choose this notation).
    ; Issue: a description or specification could be added.
    ;----------------------------------------------------------------
    Cmp.l  d6,d7
    Bls OP_NoCollision          ;if alpha2 <= beta2: goto OP_NoCollision
    Move.l d3,d5
    Sub.l  d7,d5                ;d5 := pi - alpha2
    Cmp.l  d5,d6
    Bhi OP_NoCollision          ;if pi + beta2 > alpha2: goto OP_NoCollision
    ; Issue: The above comment "if pi + beta2 > alpha2: goto OP_NoCollision" needs to be verified.
    
    ; Calculate to handle potential collision
    ; Issue: The above description needs to be verified.
    Move.l #1000,a6             ;DEBUG

    Sub.l  d7,d6
    Neg.l  d6                   ;d6 := alpha2 - beta2
    Sub.l  d3,d7
    Neg.l  d7                   ;d7 := pi - alpha2
    Move.l d3,d5                ;d5 := pi 
    Lsr.w  #1,d3                ;d3 := pi/2

    Cmp.w  d3,d7
    Bls OP_PiMinusAlphaCorrected
    Sub.l  d5,d7
    Neg.l  d7                   ;if pi - alpha2 > pi/2: d7 := pi - d7
OP_PiMinusAlphaCorrected
    Cmp.w  d3,d6
    Bls OP_AlphaMinusBetaCorrected  
    Sub.l  d5,d6
    Neg.l  d6                   ;if alpha2 - beta2 > pi/2: d6 := pi - d6
OP_AlphaMinusBetaCorrected
    Move.l d0,d5                ;d5 := d0, which is a
    ;
    Move.l SinTable(pc),a0
    Asl.w  #2,d6
    Move.l (a0,d6),d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,d3                ;d3 := sin(d6)

    Asl.w  #2,d7
    Move.l (a0,d7),d0
    Bsr ConvertAMOSRealToFixed  ;d0 := sin(d7)

    ;----------------------------------------------------------------
    ; Calculate d0/d3
    ; d0 and d3 are 16.16 fixed-point numbers
    ;
    ; Issue: The above comment seems incorrect since the code seems to do more than calculate d0/d3.
    ; This idea is supported by the label "OP_DividePlusTimes" containing "PlusTimes".
    ; The purpose of the initial swaps and rors is unclear.
    ;
    ; Issue: The meaning of the comment "This operation shifts d1,d2 as high as possible" is unclear.
    ;
    ; d1: position in out counter
    ; d6: result
    ;
    ; What are the conditions under which there is and is not the ror applied to d0 and d3:
    ; Ror is skipped iff d3.w == 0 and d0.w == 0.
    ;----------------------------------------------------------------
OP_DividePlusTimes
    Swap   d3
    Swap   d0
    Cmp.w  #0,d3
    Beq OP_d1OK              ;if d3.w == 0: goto OP_d1OK
OP_DoRor
    Ror.l  #1,d3
    Ror.l  #1,d0
    Bra OP_RorFin
OP_d1OK
    Cmp.w  #0,d0
    Bne OP_DoRor             ;if d0.w != 0: goto OP_DoRor
OP_RorFin                    ;This operation shifts d1,d2 as high as possible
    
    Swap   d0
    And.l  #$FFFF,d1         ;This seems unnecessary given there is d1 := 31 later anyway.

    Moveq  #0,d6             ;Clear the result
    Moveq  #31,d1            ;Position := 31
OP_Divide_Loop_Start
    ;if d3 <= d0: d0 := d0 - d3; set bit d1 in d6(result)
    Cmp.l  d0,d3
    Bhi OP_Divide_NotSub     ;d3>d0
    Sub.l  d3,d0
    Bset.l d1,d6
OP_Divide_NotSub    
    Lsr.l  #1,d3             ;d3 := d3 / 2
    Subq   #1,d1             ;position counter -= 1
    Tst.l  d3
    Bne OP_Divide_Loop_Start ;if d3 != 0: goto OP_Divide_Loop_Start
    Asl.l  #1,d6             ;d6 := d6 * 2

    ;----------------------------------------------------------------
    ; d6 is a 16.16 fixed-point number.
    ;----------------------------------------------------------------
    ; d1 := d6 * a, where a is in d5
    ; a is the dx, dy vector length, an integer
    ;----------------------------------------------------------------
    Move.w d6,d0
    Mulu.w d5,d0             ;d0 := ratio.w * a
    Swap   d6
    Mulu.w d5,d6             ;d6 := ratio.uw * a
    Moveq  #0,d1
    Move.w d6,d1
    Swap   d1                ;d1.uw := d6.w
    Add.l  d0,d1             ;d1 := d1 + d0; and thus, d1 := (ratio.uw * a) << 16 + ratio.w * a
    Swap   d1
    And.l  #$FFFF,d1         ;d1 := int(d1 as 16.16 fixed-point number)
    ;-------------------------------
    ; d1 == collDist
    ;-------------------------------
    Move.l d5,d0             ;d0 := a
    Bra OP_NoCollision

OP_LengthIsA
    Move.l d0,d1             ;collDist := d0

    ;--------------------------------------------------------------------------
    ; Use the calculated distance to collision (in d1) to limit DS_LenL* or DS_LenR*
    ; as applicable for the currently evaluated direction.
    ; Then, finish the direction loop by changing a2, which is ownPlrExamDirection.
    ; Issue: The part "calculated distance to collision" needs to be verified.
    ;--------------------------------------------------------------------------
    ; d1 == collDist: the distance to a potential collision with the other player,
    ; possibly an approximation or heuristic
    ;--------------------------------------------------------------------------
    ; Issue: The label "OP_NoCollision" below seems misleading;
    ; it seems once can arrive at the label even when there was a collision.
    
OP_NoCollision
    Subq   #1,a3             ;directionLoopVar -= 1
    Cmp.w  #4,a3
    Beq    OP_Straight_Lim   ;if directionLoopVar == 4: goto straight
    Cmp.w  #3,a3
    Beq    OP_L0_Lim         ;if directionLoopVar == 3: goto left 0
    Cmp.w  #2,a3
    Beq    OP_R0_Lim         ;if directionLoopVar == 2: goto right 0
    Cmp.w  #1,a3
    Beq    OP_L1_Lim         ;if directionLoopVar == 1: goto left 1
    Bra    OP_R1_Lim         ;goto right 1

    ;------------------------------------------------------
    ; Limit straight and advance to next direction
    ;------------------------------------------------------

OP_Straight_Lim
                    ;   Cmp.w  #$FFFF,d1
                    ;   Beq    OP_PlayerFinished
    Lea.l  DS_Len0(pc),a0
    Cmp.l  (a0),d1
    Bhi OP_Straight_NoCol
    Move.l d1,(a0)           ;if collDist <= DS_Len0: DS_Len0 := collDist
OP_Straight_NoCol
    Add.l  DirStep0(pc),a2   ;ownPlrExamDirection += DirStep0
    Move.l Directions(pc),d1
    Cmp    d1,a2
    Bls    OP_OK0
    Sub.l  d1,a2             ;if ownPlrExamDirection > Directions: ownPlrExamDirection -= Directions
OP_OK0
    Bra OP_DirectionLoop_Start

    ;--------------------------------------------
    ; Limit left 1 and advance to next direction
    ;--------------------------------------------

OP_L0_Lim
    Lea.l  DS_LenL1(pc),a0
    Cmp.l  (a0),d1
    Bhi OP_L0_NoCol
    Move.l d1,(a0)              ;if collDist <= DS_LenL1: DS_LenL1 := collDist
OP_L0_NoCol
    Move.l Direction(pc),a2 
    Move.l DirStep0(pc),d1      ;ownPlrExamDirection := Direction
    Cmp    a2,d1
    Bls    OP_OK1
    Add.l  Directions(pc),a2    ;if ownPlrExamDirection > DirStep0: ownPlrExamDirection += Directions
OP_OK1
    Sub.l  d1,a2                ;ownPlrExamDirection -= DirStep0
    Bra OP_DirectionLoop_Start

    ;--------------------------------------------
    ; Limit right 1 and advance to next direction
    ;--------------------------------------------
OP_R0_Lim
    Lea.l  DS_LenR1(pc),a0
    Cmp.l  (a0),d1
    Bhi OP_R0_NoCol
    Move.l d1,(a0)              ;if collDist <= DS_LenR1: DS_LenR1 := collDist
OP_R0_NoCol
    Move.l Direction(pc),a2
    Add.l  DirStep1(pc),a2      ;ownPlrExamDirection := Direction + DirStep1
    Move.l Directions(pc),d1
    Cmp    d1,a2
    Bls    OP_OK2
    Sub.l  d1,a2                ;if ownPlrExamDirection > Directions: ownPlrExamDirection -= Directions
OP_OK2
    Bra OP_DirectionLoop_Start

    ;--------------------------------------------
    ; Limit left 2 and advance to next direction
    ;--------------------------------------------

OP_L1_Lim
    Lea.l  DS_LenL2(pc),a0
    Cmp.l  (a0),d1
    Bhi OP_L1_NoCol
    Move.l d1,(a0)              ;if collDist <= DS_LenL2: DS_LenL2 := collDist
OP_L1_NoCol
    Move.l Direction(pc),a2
    Move.l DirStep1(pc),d1
    Cmp    a2,d1
    Bls    OP_OK3
    Add.l  Directions(pc),a2    ;if ownPlrExamDirection < DirStepSmall: ownPlrExamDirection += Directions
OP_OK3
    Sub.l  d1,a2                ;ownPlrExamDirection -= DirStepSmall
    Bra OP_DirectionLoop_Start

    ;--------------------------------------------
    ; Limit right 2 and exit the direction loop
    ;--------------------------------------------
OP_R1_Lim
    Lea.l  DS_LenR2(pc),a0
    Cmp.l  (a0),d1
    Bhi OP_R1_NoCol
    Move.l d1,(a0)              ;if collDist <= DS_LenR2: DS_LenR2 := collDist
OP_R1_NoCol

OP_PlayerFinished
    ;--------------------
    ; End of player loop
    ;--------------------
    Subq   #4,a1                ;plrNoTimesFour -= 4
    Cmp.w  #0,a1
    Bge    OP_PlayersLoop_Start ;loop on plrNoTimesFour >= 0

    Rts

;    _________________________________________________________
;   | Calculate vector size
;   |_________________________________________________________
;   | in d6: dx
;   | in d7: dy
;   | out d6: the result
;   | preserve d4
;   | used up: d2, d3
;   | This is sqrt(dx^2+dy^2) as a four-case approximation,
;   | where each case is a linear combination of dx and dy.
;   |_________________________________________________________

CalculateVectorSize
    Cmp.l  d6,d7
    Bls CV_RegOK        ;d7<=d6
    Exg.l  d6,d7        ;Swap d6 and d7
CV_RegOK                ;Holds true: d7 <= d6
    Move.l d6,d2
    Lsr.w  #2,d2        ;d2 := d6/4
    Move.l d6,d3        ;d3 := d6
    Sub.w  d2,d3        ;d3 := 3/4 * d6
    Cmp.w  d7,d3
    Bls CV_CASE1        ;d7 >= 3/4 * d6
    Sub.w  d2,d3
    Cmp.w  d7,d3
    Bls CV_CASE2        ;d7 >= 1/2 * d6
    Sub.w  d2,d3
    Cmp.w  d7,d3
    Bls CV_CASE3        ;d7 >= 1/4 * d6
CV_CASE4    
    Rts     ; The result is in d6.
CV_CASE1
    Sub.w  d2,d6        ;d6 := 3/4*d6
    Move.l d7,d3
    Lsr.w  #1,d3        ;d3 := d7/2
    Add.w  d3,d6        ;d6 := 3/4*d6+d7/2
    Lsr.w  #3,d7
    Add.w  d7,d6        ;d6 := 3/4*d6+d7/2+d7/8
    Rts
CV_CASE2
    Lsr.w  #1,d2
    Sub.w  d2,d6        ;d6 := d6*7/8
    Move.l d7,d3
    Lsr.w  #4,d3
    Sub.w  d3,d6        ;d6 := d6*7/8-d7/16
    Lsr.w  #1,d7
    Add.w  d7,d6        ;d6 := d6*7/8+d7/2-d7/16
    Rts             
CV_CASE3
    Lsr.w  #3,d7        ;d7 := d7/2
    Add.w  d7,d6        ;d6 := d6+d7/8
    Lsr.w  #1,d7    
    Add.w  d7,d6        ;d6 := d6+d7/8+d7/16
    Rts

;=========================== DEBUGGING =========================

DoStrategyDebug
    Bsr DoStrategy

;   Move.l a6,d0
;   Move.l a5,d1
;   In a1 there is the direction of the vector
;
    Move.l DS_Len0(pc),d0
    Move.l DS_LenL1(pc),d1
    Move.l DS_LenR1(pc),d2
;   Move.l DS_LenL2(pc),d3
;   Move.l DS_LenR2(pc),d4
    Rts

;  _______________________________
; |                           
; | CalcTestAndSpeedPoints 
; |_______________________________
; |                           
; | d0-direction     IN       
; | a12-oxy#                  
; |                           
; | a12-speedxy      OUT      
; | d01-testxy                
; |                           
; | changed regs: d0-d7
; |               a1, a2, a4, a5 
; |_______________________________

; d4 -xint
; d5 -yint
; d6 -xint+2
; d7 -yint+2

CalcTestAndSpeedPoints_2Pixel
    Bsr CalculateSinAndCosFixed
    Move.l d4,a4
    Move.l d5,a5        ;Store fixed dx,dy for later

    Move.l d4,d2
    Move.l d5,d3        ;d23 = dxy

    Move.l a2,d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,a2
    Move.l a1,d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,a1

    Move.l a2,d1        ;so that d0, d1 == xfixed, yfixed

    Move.l d0,d4
    And.l  #$FFFF0000,d4
    Move.l d4,d6
    Move.l d1,d5
    And.l  #$FFFF0000,d5
    Move.l d5,d7        ;d46:=xint, d57:=yint
    Sub.l  #$10000,d4
    Sub.l  #$10000,d5
    Add.l  #$30000,d6
    Add.l  #$30000,d7   ;INTS filled

    Bsr    CTP_StraightLoop

    Exg.l  d0,a1   
    Exg.l  d1,a2        ;a12:=xyspeed, d01:=xyfixed

    Move.l a4,d2
    Move.l a5,d3        ;d23 = dxy

    Move.l d0,d4
    And.l  #$FFFF0000,d4
    Move.l d4,d6
    Move.l d1,d5
    And.l  #$FFFF0000,d5
    Move.l d5,d7        ;d4,d6:=xint d5,d7:=yint

    Add.l  #$20000,d6
    Add.l  #$20000,d7       ;INTS filled

    Bsr    CTP_StraightLoop

    Rts         ;d0,d1..test,a1,a2..speed

;------------------------------------- d01 ----
    
CTP_StraightLoop
    Add.l  d2,d0
    Add.l  d3,d1

    Cmp.l  d0,d4        ;x<xint
    Bgt CTP_Finished
    Cmp.l  d1,d5        ;y<yint
    Bgt CTP_Finished
    Cmp.l  d0,d6        ;x>=xint+2
    Bls CTP_Finished
    Cmp.l  d1,d7        ;not y>=yint+2
    Bgt CTP_StraightLoop

CTP_Finished
    And.l  #$FFFF0000,d0
    And.l  #$FFFF0000,d1
    Swap   d0
    Swap   d1
    Rts

;------------------------------------

CalcTestAndSpeedPoints_1Pixel
    Bsr CalculateSinAndCosFixed
    Move.l d4,a4        
    Move.l d5,a5             ;Store fixed dx,dy

    Move.l d4,d2
    Move.l d5,d3             ;d2 is dx, d3 is dy

    Move.l a2,d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,a2
    Move.l a1,d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,a1

    Move.l a2,d1             ;so that d0,d1=x,y fixed

    Move.l d0,d4
    And.l  #$FFFF0000,d4
    Move.l d4,d6
    Move.l d1,d5
    And.l  #$FFFF0000,d5
    Move.l d5,d7             ;d4,d6:=xint d5,d7:=yint
    Sub.l  #$10000,d4
    Sub.l  #$10000,d5
    Add.l  #$20000,d6
    Add.l  #$20000,d7        ;INTS filled

    Bsr    CTP_StraightLoop

    Exg.l  d0,a1   
    Exg.l  d1,a2             ;a1,a2:=xyspeed,d0,d1:=beginxyfixed

    Move.l a4,d2
    Move.l a5,d3             ;d2 is dx, d3 is dy

    Move.l d0,d4
    And.l  #$FFFF0000,d4
    Move.l d4,d6
    Move.l d1,d5
    And.l  #$FFFF0000,d5
    Move.l d5,d7             ;d4,d6:=xint d5,d7:=yint
    Add.l  #$10000,d6
    Add.l  #$10000,d7        ;INTS filled
    Bsr    CTP_StraightLoop 

    Rts         ;d0,d1..test,a1,a2..speed

;    _____________________________________________
;   |                           
;   | CalculateSinAndCosFixed   
;   |_____________________________________________
;   |
;   | d0: direction in
;   | d4: sin fixed out
;   | d5: cos fixed out
;   |
;   | change regs: d0,d1,d3,d4,d5,d6,d7
;   |        a0
;   |_____________________________________________

CalculateSinAndCosFixed
    Move.l Directions(pc),d6
    Lsr.w  #2,d6            ;d6 := DirectQuarter
    Move.l d0,d7            ;d7 := Direction    
    Divu.w d6,d7            ;d7 := direction / (direction count / 4)
                            ; remainder is saved in the upper word or d7; d7.w has quadrant
    Move.l d7,d1        
    Swap   d1
    Ext.l  d1               ;d1 := remainder

    Btst   #0,d7
    Beq CSF_FinalDir
    Sub.l  d6,d1
    Neg.l  d1               ;Dir=-(Dir-DirsQuarter)
CSF_FinalDir
    ;Now d1 == DifDirection
    Move.l d1,d3            ;StoreDifDirection

    Asl.l  #2,d1            ; d1 := d1 * 4
    Move.l SinTable(pc),a0
    Move.l (a0,d1),d0
    Bsr ConvertAMOSRealToFixed
    Move.l d0,d4

    Btst   #1,d7
    Beq CSF_SinCalculated
    Neg.l  d4
CSF_SinCalculated
    Sub.l  d6,d3
    Neg.l  d3               ;Dir=-(Dir-DirsQuarter)
    Asl.l  #2,d3
    Move.l (a0,d3),d0       ;a0 == SinTable
    Bsr ConvertAMOSRealToFixed
    Move.l d0,d5
    
    Add.b  #1,d7
    Btst   #1,d7
    Beq CSF_CosCalculated
    Neg.l  d5
CSF_CosCalculated
    Rts

;    _____________________________________________
;   |                           
;   | CalculateSinAndCos
;   |_____________________________________________
;   |                           
;   | d0: direction in           
;   | d0: sin       out
;   | d2: cos       out          
;   |                           
;   | changed regs: d0, d1, d2, d3, d6, d7
;   |               a0
;   |_____________________________________________

CalculateSinAndCos
    Move.l Directions(pc),d6
    Lsr.w  #2,d6            ;d6 := direction count / 4 (DirCntQuarter)
    Move.l d0,d7            ;d7 := direction
    Divu.w d6,d7            ;d7 := direction / (direction count / 4)
                            ;remainder is saved in the upper word or d7; d7.w has quadrant
    Move.l d7,d1
    Swap   d1
    Ext.l  d1               ;d1 := remainder of direction / (direction count / 4)

    Btst   #0,d7
    Beq CS_FinalDir
    Sub.l  d6,d1
    Neg.l  d1               ;dir = -(dir - direction count / 4)
CS_FinalDir
    ;Now d1 == DifDirection
    Move.l d1,d3            ;StoreDifDirection

    Asl.l  #2,d3
    Move.l SinTable(pc),a0
    Move.l (a0,d3),d0       ;Picked from the table

    Btst   #1,d7
    Beq CS_SinCalculated    
    Add.b  #$80,d0
CS_SinCalculated            ;The sine is in d0

    Sub.l  d6,d1
    Neg.l  d1               ;Dir=-(Dir-DirsQuarter)
    Asl.l  #2,d1
    Move.l (a0,d1),d2       ;Picked from the table
    
    Add.b  #1,d7
    Btst   #1,d7
    Beq CS_CosCalculated
    Add.b  #$80,d2
CS_CosCalculated
    Rts
    
;--------------------------------------------------------------------
; Quick 68000 asm guide, to support the above as a quick reference
;--------------------------------------------------------------------
; Registers: 32-bit registers d0 through d7, and then a0 through a7;
; then there are other registers such as stack pointer.
; .l, .w and .b selects on which part of the register or location to operate:
; .l: 32 bits; .w: 16 bits; .b: 8 bits
; Negative integers are using two's complement representation.
;
; Move.l: copy the 32 bits from 1st to 2nd operand (left to right)
; Move.l (a0,d1),d2: add d1 to the address a0 to get address to read from, and copy the result to d2
; Moveq: move quick a small immediate value to the 32 bits of the register
; Lea: load effective address
; Swap: swap the upper and lower 16-bit words of the register
; Ext.l: extend the sign bit of the lower 16-bit word to all the bits of the upper 16-bit word
; Exg: exchange/swap the values of the two locations, e.g. registers
; Bsr: branch to subroutine
; Rts: return from subroutine
; Bra: branch
; DBra: decrement and branch unless the result is -1 (good for loop control)
; Asl: arithmetic shift left, a bit operation
; Lsr: logical shift right, a bit operation
; Neg.l: multiply the 32 bits of the register -1
; And.l: bitwise and
; Add.l: integer addition
; Sub.l: integer subtraction
; Mulu.w: multiplies (unsigned) the lower 16-bit words, storing the result into the 32 bits of the 2nd operand
; Mulu.l: not possible
; Divu: divide unsigned; the upper 16-bit word has the remainder, whereas the lower 16-bit word has the quotient
; Cmp: compares two values, affecting subsequent Beq, etc.
; Btst #0,d0: test the least significant bit (bits counted from 0, from least significant); affects subsequent Beq
; Beq: branch on equal
; Bne: branch on not equal  
; Bhi: branch on higher than (the 2nd operand of Cmp > the 1st operand; somewhat counterintuitive)
; Bls: branch on lower than or same
; Bgt: branch on greater than
; Bge: branch on greater than or equal
; Bmi: branch on minus; used e.g. after Tst
; Bpl: branch on plus; used e.g. after Tst
; Bset x, y: set the bit number x (counting from least significant ones, from zero) in y
; Tst: compare to zero and affect subsequent Beq and Bne
; Ror: bitwise rotate right
; Rol: bitwise rotate left
;--------------------------------------------------------------------

RecordAndReplay.s

[edit | edit source]
;------------------------------------------------------------------------------
; Record and replay assembly procedures for Duenix for the Amiga
;------------------------------------------------------------------------------
; Player decisions (one of three options 0, 1, and 2, requiring two bits)
; are being stored/saved, to be loaded later.
; The single round/frame requires 6 * 2 bits of storage,
; two bits per player; they are stored in a single 16-bit word.
; One would think this would have been fast enough in
; in AMOS using peeks, pokes and similar.
; The comments have been expanded in 2024 to be excessively detailed,
; which is fine for educational purposes.
; This is Motorola 68000 assembly.
;------------------------------------------------------------------------------

MaxSize = 8000 

   ;-------------------------
   ; Interface variables
   ;-------------------------

PMove   dc.l 0      ;The beginning of an array of player moves/decisions for the current round.
                    ;Each move is stored in an AMOS integer, so the array takes 4 * 6 bytes.
Record  dc.l 0      ;The address of record space, containing recorded decisions of players for all rounds.
                    ;In this space, the decision for all players for a given round takes 16 bits
                    ;(12 bits, plus 4 bits free).
TopPtr  dc.l 0      ;The pointer in the record space

   ;-------------------------
   ; Procedure entry points
   ;-------------------------

    Bra SavePos
    Bra LoadPos

   ;----------------------
   ; Procedure SavePos
   ;----------------------

SavePos
    Moveq  #0,d1             ;d1 := 0
    Moveq  #5,d0             ;PlayerNumber := 5
    Move.l PMove(pc),a0      ;a0 := PMove address
    Lea    TopPtr(pc),a2     ;a2 := TopPtr address
SavePos_Loop
    Move.l d0,d2
    Asl.l  #2,d2             ;d2 := PlayerNumber * 4
    Move.l (a0,d2),d3        ;d3 := PMove[PlayerNumber], which is one of 0, 1, and 2
    Asl.w  d0,d3
    Asl.w  d0,d3             ;d3 := d3 << (2 * PlayerNumber)
    Or.w   d3,d1             ;d1 := d1 bitor d3
    DBra   d0,SavePos_Loop   ;Go to next PlayerNumber

    Move.l Record(pc),a1
    Move.l (a2),d2
    Move.w d1,(a1,d2)        ;Record[TopPtr] := word containing the decisions of all players

    Cmp.w  #MaxSize,a2
    Beq SavePos_Skip
    Addq.l #2,(a2)           ;TopPtr += 2
SavePos_Skip
    Rts

   ;----------------------
   ; Procedure LoadPos
   ;----------------------

LoadPos
    Move.l PMove(pc),a0      ;a0 := PMove address
    Lea    TopPtr(pc),a2     ;a2 := TopPtr address
    Move.l Record(pc),a1
    Move.l (a2),d2
    Move.w (a1,d2),d1        ;d1 := Record[TopPtr]

    Cmp.w  #MaxSize,d2
    Beq    LoadPos_Skip
           
    Addq.l #2,(a2)           ;TopPtr += 2
LoadPos_Skip
    Moveq  #5,d0             ;PlayerNumber := 5
LoadPos_Loop 
    Move.w d1,d2             ;d2 := Record[TopPtr]
    Asr.w  d0,d2
    Asr.w  d0,d2
    And.w  #3,d2             ;d2 := (Record[TopPtr] >> (2 * PlayerNumber)) bitand 0b11
    Ext.l  d2
    Move.l d0,d3
    Asl.l  #2,d3
    Move.l d2,(a0,d3)        ;PMove[PlayerNumber] := (Record[TopPtr] >> (2 * PlayerNumber)) bitand 0b11
    DBra   d0,LoadPos_Loop   ;Go to next PlayerNumber
    Rts

PutPixel.s

[edit | edit source]
;------------------------------------------------------------------------------
; DrawPixel - for Duenix for the Amiga
;------------------------------------------------------------------------------
; A set of procedures to draw 1 and 2x2 pixels of a given color.
; It also supports drawing a big (2x2) pixel with conditionally present
; dark boundary pixels around it.
; The logic deals with 5 bitplans; placing a pixel means modifying
; the corresponding bit in each of the 5 bitplans.
; The job seems rather trivial; one has to wonder why doing the same
; in AMOS was too slow (2024).
; This is Motorola 68000 assembly for the Amiga.
;------------------------------------------------------------------------------

;----------------------------------------------------------
; Interface variables
;----------------------------------------------------------
Bitplan0    dc.l 0,0,0,0     ;Addresses of bitplans 0-3
Bitplan4    dc.l 0,0,0,0     ;Address of bitplan 4 and three dummy zeros
pq_x_addr   dc.l 0           ;Pixel queue x address
pq_y_addr   dc.l 0           ;Pixel queue y address
pq_colour_addr  dc.l 0       ;Pixel queue color address
pq_top      dc.l 0           ;Top index of the item in the pixel queue
putpix_type dc.b 0
        dc.b 0,0,0

;----------------------------------------------------------
; Entry points for procedures
;----------------------------------------------------------
    bra Draw_queue_of_pixels
    bra Draw_Small_Pixel_Conditioned
    bra Draw_Big_Pixel_Conditioned
    bra DSP_Conditioned_BigScreen
    bra DBP_Conditioned_BigScreen

;----------------------------------------------------------
; Procedure Draw_One_Pixel_BigScreen
; Procedure Draw_One_Pixel
;----------------------------------------------------------
; d0: xcoord (input, does not change)
; d1: ycoord (input, does not change)
; d2: color (input, does not change)
; more input: Bitplan0
;
; used registers: d0-d7 but for d6, a0, a1, a2
;----------------------------------------------------------

Draw_One_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3
    Move.l  d1,d4
    Mulu    #80,d4
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 80 + xcoord / 8, which is the offset of the pixel address
    bra dop_address_known

Draw_One_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3
    Move.l  d1,d4
    Mulu    #40,d4
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 40 + xcoord / 8, which is the offset of the pixel address
dop_address_known
    Move.l  d0,d3
    And.l   #7,d3       
    Sub.l   #7,d3
    Neg.l   d3               ;d3 := 7 - (xcoord band 0b111), which is the bit number

    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0 address
    Moveq   #4,d5            ;d5 := bitplan number, and a loop control register (we have 5 bitplans)
    Move.l  d2,d7            ;d7 := color
dop_Loop_Start
    Move.l  (a1)+,a2         ;a2 := current bitplan address
    Add.l   a0,a2
    Move.b  (a2),d4          ;d4 := the value of the byte of the pixel in the bitplane
    Bclr.l  d3,d4
    Btst    #0,d7
    Beq dop_Zero
    Bset.l  d3,d4            ;clear the pixel bit or set it to 1 as applicable
dop_Zero
    Move.b  d4,(a2)          ;write d4 back to the bitplane
    Lsr.b   #1,d7
    DBra    d5,dop_Loop_Start
    Rts 

;--------------------------------------------------------------
; Procedure Draw_Conditioned_Pixel_BigScreen
; Procedure Draw_Conditioned_Pixel
; DCP: Draw conditioned pixel.
; Draw using the color of 1.
; "conditioned" means draw the pixel only if its bitplan 4
; bit is empty.
;--------------------------------------------------------------
; d0: xcoord
; d1: ycoord
;-------------------------------------------------------------

Draw_Conditioned_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #80,d4           ;d4 := ycoord * 80 
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 80 + xcoord / 8, which is offset of the pixel address
    bra dcp_address_known

Draw_Conditioned_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #40,d4           ;d4 := ycoord * 40 
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := ycoord * 40 + xcoord / 8, which is offset of the pixel address
dcp_address_known
    Move.l  d0,d3
    And.l   #7,d3
    Sub.l   #7,d3
    Neg.l   d3               ;d3 := 7 - (xcoord band 0b111), which is the bit number
    Move.l  Bitplan4(pc),a1
    Btst.b  d3,(a1,a0.l)
    Bne dcp_Finished         ;If bitplan 4 is non-zero, do not draw anything
    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0 address
    ;The first round outside of the loop
    Move.l  (a1)+,a2
    Bset.b  d3,(a2,a0.l)
    Moveq   #2,d2            ;Only 3 bitplans remain
dcp_Loop_Start
    Move.l  (a1)+,a2
    Bclr.b  d3,(a2,a0.l)
    DBra    d2,dcp_Loop_Start
dcp_Finished
    Rts 

;--------------------------------------
; Procedure DSP_Conditioned_BigScreen
; DSP: Draw small pixel
;--------------------------------------

DSP_Conditioned_BigScreen
    ;Draw classical pixel
    Bsr Draw_One_Pixel_BigScreen
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Rts

Draw_Small_Pixel_Conditioned
    ;Draw classical pixel
    Bsr Draw_One_Pixel
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Rts

;--------------------------------------
; Procedure DBP_Conditioned_BigScreen
; DBP: Draw big pixel.
; The boundary pixels are drawn in
; color 1 and are drawn only
; if the pixel being overwritten
; has color less than 16.
;--------------------------------------

DBP_Conditioned_BigScreen
    ;Draw classical pixel
    Bsr Draw_Big_Pixel_BigScreen    
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel_BigScreen
    Rts

Draw_Big_Pixel_Conditioned
    ;Draw classical pixel
    Bsr Draw_Big_Pixel
    ;Draw boundary pixels
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d0
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Addq    #1,d1
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d0
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Subq    #1,d1
    Bsr Draw_Conditioned_Pixel
    Rts

;================================================
; Second, perhaps better take at big pixel
;================================================

;------------------------------------------------
; Procedure Draw_Big_Pixel_BigScreen
;------------------------------------------------
; d0: xcoord
; d1: ycoord
; d2: color
; used: d3, d4, d6, a0
;------------------------------------------------
Draw_Big_Pixel_BigScreen
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4   
    Mulu    #80,d4           ;d4 := ycoord * 80
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := xcoord / 8 + ycoord * 80

    Move.l  d0,d4
    And.w   #$7,d4           ;d4 := xcoord band 0b111 (the bit number)
    Move.w  #$C000,d3
    Lsr.w   d4,d3            ;d3 := 0xC000 >> (xcoord band 0b111), which is the oring word 
    Move.w  d3,d6
    Eor.w   #$FFFF,d6        ;d6 := oring word XOR FFFF, which is the anding word   

    Bsr dbp_Double_Pixel    ;using a0, d2, d3 and d6
    Add #80,a0
    Bsr dbp_Double_Pixel    ;using a0, d2, d3 and d6
    Rts

;------------------------------------------------
; Procedure Draw_Big_Pixel
; Draws a "big pixel" consisting of 2x2 pixels
;------------------------------------------------
; d0: xcoord
; d1: ycoord
; d2: color
; used: d3, d4, d6, a0
;------------------------------------------------
Draw_Big_Pixel
    Move.l  d0,d3
    Lsr.w   #3,d3            ;d3 := xcoord / 8
    Move.l  d1,d4
    Mulu    #40,d4           ;d4 := ycoord * 40
    Add.l   d4,d3
    Move.l  d3,a0            ;a0 := xcoord / 8 + ycoord * 40

    Move.l  d0,d4
    And.w   #$7,d4           ;d4 := xcoord band 0b111 (the bit number)
    Move.w  #$C000,d3
    Lsr.w   d4,d3            ;d3 := 0xC000 >> (xcoord band 0b111), which is the oring word 
    Move.w  d3,d6
    Eor.w   #$FFFF,d6        ;d6 := oring word XOR FFFF, which is the anding word

    Bsr dbp_Double_Pixel     ;using a0, d2, d3 and d6
    Add #40,a0
    Bsr dbp_Double_Pixel     ;using a0, d2, d3 and d6
    Rts

;------------------------------------------------------------------------------
; Procedure dbp_Double_Pixel
; Draws two pixels horizontally next to each other. To be called two times,
; to draw the complete 2x2 big pixel.
;------------------------------------------------------------------------------
; a0: offset of the word to be modified, against the base of the bitplans
; d2: color
; d3: oring word
; d6: anding word    
;------------------------------------------------------------------------------
dbp_Double_Pixel
    Lea     Bitplan0(pc),a1  ;a1 := Bitplan0
    Moveq   #4,d5            ;d5 := bitplan number, and a loop control register (we have 5 bitplans)
    Move.l  d2,d7            ;d7 := color
dbp_Loop_Start
    Move.l  (a1)+,a2         ;a2 := a1; a1 += 1
    Add.l   a0,a2            ;a2 := start of the current bitplan + offset of the byte to be modified
    Move.w  (a2),d4          ;d4 := content of the byte to be modified
    And.w   d6,d4
    Btst    #0,d7
    Beq dbp_Zero
    Or.w    d3,d4
dbp_Zero
    Move.w  d4,(a2)          ;write d4 back to the bitplane
    Lsr.b   #1,d7
    DBra    d5, dbp_Loop_Start
    Rts

;============================================================

;------------------------------------------------
; Procedure Draw_queue_of_pixels
;------------------------------------------------
; input:
;   pq_x_addr
;   pq_y_addr
;   pq_colour_addr
;   pq_top
;   putpix_type
; local:
;   d0, d1, d2, d3, a0
;   a6: index of the current element in the queue
;------------------------------------------------

Draw_queue_of_pixels
    Move.l pq_x_addr(pc),a3
    Move.l pq_y_addr(pc),a4
    Move.l pq_colour_addr(pc),a5

    Move.l #-1,a6            ;for each item in the queue (d6 := queue_item_idx)
dq_Loop 
    Addq   #1,a6
    Move.l pq_top(pc),a0
    Cmp.l  (a0),a6
    Bge    dq_finished       ;if queue_item_idx >= pq_top: go to dq_finished

    Move.l a6,d0
    Asl.w  #2,d0
    Move.l (a5,d0),d2
    Move.l (a4,d0),d1
    Move.l (a3,d0),d0

    Moveq  #0,d3
    Move.b putpix_type(pc),d3
    Lea.l  putpix(pc),a0
    Jsr    (a0,d3)

    Bra    dq_Loop
dq_finished
    Rts

putpix
    Bra Draw_Small_Pixel_Conditioned
    Bra Draw_Big_Pixel_Conditioned
    Bra DSP_Conditioned_BigScreen
    Bra DBP_Conditioned_BigScreen

References

[edit | edit source]
  1. Dune 3 aneb Achtung! Die Kurve... (1993), MobyGames
  2. Cervii (Červi), oldgames.sk
[edit | edit source]