'--------constants----------------------------------------------------------------------------------------------------------------------------------
CONST DEBUGMODE
= 0 'Initial state of debug mode CONST FPS
= 100 'Set target frames per seconds to 100 for proper physicss speed CONST RES_X
= -1 'Screen horizontal resolution, set to -1 to match the dsektop CONST RES_Y
= -1 'Screen vertical resolution, set to -1 to match the dsektop CONST FULLSCREENMODE
= 1 'set 1 for fullscreen on startup, other value to window mode CONST RES_X_TARG
= 1920 'target vertical resolution CONST MAX_COL
= 247 'max. color number to use of 255 CONST PLAYER_COUNT_INI
= 4 'Initial players count CONST POCET_GUL_INI
= 20 'Initial non player balls count CONST PLAYER_COUNT_MAX
= 32 'Maximum players count CONST POCET_GUL_MAX
= 512 'Maximal balls count CONST STRAT_COUNT_MAX
= 20 'Maximum players strategies CONST PLAY_BALL_R
= 20 'Players ball size CONST V_MAX
= 300 / FPS
'Max player ball velocity CONST ACC_X
= 10 / FPS
'Balls acceleration X CONST ACC_Y
= 10 / FPS
'Balls accelereation Y CONST FRICTION
= 0.998 'Space fricition coeffifcient CONST ENERGY_ALL_MIN
= 600 'min.starting energy of all players together CONST ENERGY_PLAYER_MIN
= 50 'min. player's starting energy CONST ENERGY_PLAYER_MAX
= 200 'max. player's starting energy CONST ENERGY_DEC
= 5 / FPS
'ball energy decrement CONST REACTIME_AVG_NORMAL
= 0 * FPS
'Average AI reaction time in sec*FPS CONST CHYBASMERU_NORMAL
= 0.0 'Improper reaction rate CONST PRIESTOR_MIN
= PLAY_BALL_R
+ 100 CONST ROUNDSTART_DELAY
= 3 'delay in seconds after round end to accept resume CONST FREEZE_TIME
= 1.0 * FPS
'player freeze time after getting tag in seconds CONST SCORE_POS_X
= 50 'Score horizontal draw position CONST SCORE_DELTA_Y
= 13 'Score draw - vertictal offset from screen top CONST SCORE_DELTA_X
= 350 'Score draw - players score horizontal offset CONST SCORE_NAME_LEN
= 120 'Score draw - horizontal space for player name CONST BOOST_V_KOEF
= 1.0 'boost factor of extra maximum speed CONST BOOST_TRVANIE
= 1 * FPS
'boost duration CONST BOOST_TIME
= 1 * FPS
'min time between boosts in sec*fps CONST MENUCURSOR_COLOR
= 15 'Menu cursor color CONST MENU_PLAYERS_COUNT
= 8 'Number of players in menu CONST FONT_W
= 8 'Font width in pixels CONST FONT_H
= 16 'Font height in pixels CONST GAMESTICK_DEADZONE
= 0.05 'gamepad stick axis maximum value considered as zero
'--------type definitions----------------------------------------------------------------------------------------------------------------------------
TYPE vektor
'general 2D vector type
TYPE tstav
'game world state type (cca 100B) vmax
AS SINGLE 'maximum unboosted ball velocity pocetgulzvoleny
AS INTEGER 'number of balls desired pocetgulx
AS INTEGER 'number of balls in bottom row pocetguly
AS INTEGER 'number of balls in left column pocetgamepadov
AS INTEGER 'number of gamepads detected pocetkontrolerov
AS INTEGER 'number of game controllers energy_allmin
AS SINGLE 'all players starting energy sum energy_playermin
AS SINGLE 'minimum starting energy of player energy_playermax
AS SINGLE 'maximum starting energy of player energy_player_start
AS SINGLE 'player's starting energy energydec
AS SINGLE 'energy decrease unit balbudeto
AS INTEGER 'successor tagged ball idx koniec_hry
AS INTEGER 'end of game flag (0 or 1) massallowed
AS INTEGER 'calculate balls with different masses pauza
AS LONG 'game pause flag (0 or 1) zacinabal
AS INTEGER 'initially tagged ball idx printdebug
AS INTEGER 'debug mode flag (0 or 1) boostallowed
AS INTEGER 'player boost mode allowed (0 or 1)
TYPE gula
'ball type (cca 90B) vi
AS vektor
'desired velocity a
AS vektor
'acceleration riadena
AS INTEGER 'is actually player controllable (0 or 1) complayer
AS INTEGER 'is computer player's ball (0 or 1) protivnik
AS INTEGER 'actual ball's enemy ball id strat
AS INTEGER 'balls behaviour strategy id freezedtime
AS INTEGER 'actual time to unfreeze players control smer_odchyl
AS SINGLE 'actual deviance from intended direction in radians klucka_time
AS INTEGER 'actual time to start doging klucka_uhol
AS SINGLE 'actual dodge angle klucka_trvanie
AS INTEGER 'actual dodge duration boost_time
AS INTEGER 'actual time to boost allowed again boost_trvanie
AS INTEGER 'actual time to end boost reactdrop_time
AS INTEGER 'actual time to start reaction drop in frames reactdrop_dur
AS INTEGER 'actual time to stop reaction drop in frames boostintended
AS INTEGER 'intention to boost or not (1, 0)
TYPE tstrat
'balls behaviour strategy type okraj
AS INTEGER 'distance from screen border to turn okraj_rot
AS SINGLE 'distance from screen border to turn chybasmeru
AS SINGLE 'percentage of deviance from desired direction -- not used currently react_lag
AS INTEGER 'average reaction time in frames klucka_avgtm
AS SINGLE 'average time between dodging in fps +-50% klucka_uhol
AS SINGLE 'average dodge angle klucka_trvanie
AS INTEGER 'average dodge time +-50% klucka_uholodch
AS SINGLE 'dodge angle deviation percentage detekcia_sin
AS SINGLE 'sinus of frontal enemy detection angle detekcia_vzdfull
AS SINGLE 'distance of frontal enemy full detection detekcia_vzdmin
AS SINGLE 'distance of frontal enemy minimum detection detekcia_rot
AS SINGLE 'amount of rotation on enemy detection in radians reactdrop_per
AS INTEGER 'average reaction drop period in frames reactdrop_dur
AS INTEGER 'average reaction drop duration in frames boost_rate
AS SINGLE 'inclination to use boost in percent boost_dist
AS SINGLE 'enemy distance activating boost deciding boost_chasesin
AS SINGLE 'max. sinus of enemy to player velocity angle to apply chasing boost mate_cosenmax
AS SINGLE 'max. cosinus of (player-enemy vector to player velocity) to rotate to mate mate_rot
AS SINGLE 'amount of unit rotation towards nearest mate in rad per frame mate_en_distmin
AS SINGLE 'min. distance from enemy to apply rotation towards mate mate_distmin
AS SINGLE 'min. distance from mate to apply rotation towards mate adrenalin_rate
AS SINGLE 'percentage of reaction improved in adrenalin mode adrenalin_energy
AS SINGLE 'energy level precentage starting adrenalin mode
klavesy
AS INTEGER 'players control keys set index
TYPE klavesy
'players controller type devid
AS INTEGER 'controllers device id (0=unused) typ
AS INTEGER 'type of controller (0=unused, 1=keyboard, 2=mouse reserved, 3=gamepad, 4=AI) nazov
AS STRING * 25 'game controllers name down
AS LONG 'keyp code for down right
AS LONG 'key code for right left
AS LONG 'key code for left shoota
AS LONG 'keyborad key code or gamepad button id shootb
AS LONG 'keyborad key code or gamepad button id isup
AS INTEGER 'controllers actual state for up isdown
AS INTEGER 'controllers actual state for down isright
AS INTEGER 'controllers actual state for right isleft
AS INTEGER 'controllers actual state for left isshoota
AS INTEGER 'controllers actual state for fire 1 isshootb
AS INTEGER 'controllers actual state for fire 2 gvektor
AS vektor
'controllers actual x and y axis state buttonstate
AS LONG 'all gamepads buttons cumulative state value buttonstatechanged
AS INTEGER '0 if no button state change, 1 if any button state changed
title
AS STRING * 10 'menu title use for nothing item_height
AS INTEGER 'menu item height in pixels cursor_xpos
AS INTEGER 'x position of cursors left side cursor_width
AS INTEGER 'cursor width in pixels menucode
AS INTEGER 'stores code of selected action upon active menuitem playercode
AS INTEGER 'stores player id of active menuitem
TYPE tgame
'game session properties --not applied yet
'-----global variables-------------------------------------------------------------------------------------------------------------------------------
DIM SHARED klav
(1 TO PLAYER_COUNT_MAX
) AS klavesy
'keyboard control sets DIM SHARED strat
(1 TO STRAT_COUNT_MAX
) AS tstrat
'computer players strategies
'----main program------------------------------------------------------------------------------------------------------------------------------------
SitoGame 'run the game
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB SetGlobalParameters
'set pre-game world parameters
'-------------------------------set main world parameters----------------------------------------------------------------------------------------
stav.pauza = 0
stav.fps = FPS
stav.fpsactual = FPS
stav.pocethracov = PLAYER_COUNT_INI
stav.pocetgulzvoleny = POCET_GUL_INI
stav.pocetgul = POCET_GUL_INI
stav.energy_allmin = ENERGY_ALL_MIN
stav.energy_playermin = ENERGY_PLAYER_MIN
stav.energy_playermax = ENERGY_PLAYER_MAX
stav.energydec = ENERGY_DEC
stav.printdebug = DEBUGMODE
stav.odpor = FRICTION
stav.minx = 0
stav.miny = 0
stav.vmax = V_MAX * stav.maxx / RES_X_TARG
stav.maxcol = MAX_COL
stav.boostallowed = 1
stav.massallowed = 0 'sticky balls problem if mass allowed unsolved yet
stav.energy_player_start = (stav.energy_allmin / stav.pocethracov) 'calculate players energy
IF stav.energy_player_start
< stav.energy_playermin
THEN stav.energy_player_start
= stav.energy_playermin
IF stav.energy_player_start
> stav.energy_playermax
THEN stav.energy_player_start
= stav.energy_playermax
'-------------------------------set game controllers---------------------------------------------------------------------------------------------
FOR i
= 1 TO UBOUND(klav
) 'set all the other game controllers as unused klav(i).typ = 0
klav(i).devid = 0
'set default controllers
kid = 1 'CPU void controller
klav(kid).id = kid: klav(kid).devid = 1: klav(kid).nazov = "<CPU>": klav(kid).typ = 4
kid = 2 'keyboard set 1 controller
klav(kid).id = kid: klav(kid).devid = 1: klav(kid).nazov = "<Arrow keys + LShift>": klav(kid).typ = 1
klav(kid).up = 18432: klav(kid).down = 20480: klav(kid).left = 19200: klav(kid).right = 19712
klav(kid).shoota = 100304: klav(kid).shootb = 100306
kid = 3 'keyboard set 2 controller
klav(kid).id = kid: klav(kid).devid = 1: klav(kid).nazov = "<W,A,S,D + RShift>": klav(kid).typ = 1
klav(kid).up = 119: klav(kid).down = 115: klav(kid).left = 97: klav(kid).right = 100
klav(kid).shoota = 100303: klav(kid).shootb = 100305
kid = 4 'keyboard set 3 controller
klav(kid).id = kid: klav(kid).devid = 1: klav(kid).nazov = "<I,J,K,L + Enter>": klav(kid).typ = 1
klav(kid).up = 105: klav(kid).down = 107: klav(kid).left = 106: klav(kid).right = 108
klav(kid).shoota = 13: klav(kid).shootb = 21248
'-------------------------------set players------------------------------------------------------------------------------------------------------
FOR i
= 1 TO UBOUND(hrac
) 'initial setting for all players hrac(i).bal = i
hrac(i).skore = 0
hrac(i).klavesy = 1
hrac(i).col = 32 + i * 3
bal(hrac(i).bal).complayer = 1
'personalize some players initially
bal(hrac(1).bal).complayer = 0
hrac(1).klavesy = 2
hrac(1).meno = "Chuck"
hrac(2).meno = "Arnold"
hrac(3).meno = "Jean"
hrac(4).meno = "Bruce"
hrac(5).meno = "Dolph"
hrac(6).meno = "Sylvester"
hrac(7).meno = "Jet"
hrac(8).meno = "Dwayne"
'-------------------------------set behaviour strategies------------------------------------------------------------------------------------------
'some void strategy
strat(1).okraj = PRIESTOR_MIN:
strat(1).okraj_rot = 0.1
strat(1).chybasmeru = 0.00:
strat(1).klucka_avgtm = 1 * FPS: strat(1).klucka_pocet = 5
strat(1).klucka_trvanie = 0.25 * FPS: strat(1).klucka_uhol = pi / 2: strat(1).klucka_uholodch = 0.2
strat
(1).detekcia_sin
= SIN(pi
/ 4): strat
(1).detekcia_vzdfull
= 500: strat
(1).detekcia_vzdmin
= 1000: strat
(1).detekcia_rot
= 0.5 strat(1).boost_dist = 200
strat
(1).boost_chasesin
= SIN(pi
/ 8) strat(1).mate_cosenmax = -0.8 'cos(140/180*pi)
strat(1).mate_rot = 0.1 ' 3*pi /FPS
strat(1).mate_en_distmin = 5 * PLAY_BALL_R
strat(1).mate_distmin = 4 * PLAY_BALL_R
'non dodging strategy
strat(2).okraj = PRIESTOR_MIN + 10
strat(2).okraj_rot = 0.1
strat(2).chybasmeru = 0.00
strat(2).reactdrop_per = 0 * FPS
strat(2).reactdrop_dur = 0 * FPS
strat(2).klucka_avgtm = 10 * FPS
strat(2).klucka_pocet = 0
strat(2).klucka_trvanie = 0 * FPS
strat(2).klucka_uhol = 0 * pi / 3
strat(2).klucka_uholodch = 0.2
strat
(2).detekcia_sin
= SIN(pi
/ 6) strat(2).detekcia_vzdfull = 500
strat(2).detekcia_vzdmin = 1000
strat(2).detekcia_rot = 0.5
strat(2).boost_dist = 200
strat
(2).boost_chasesin
= SIN(pi
/ 8) strat(2).mate_cosenmax = -0.8 'cos(140/180*pi)
strat(2).mate_rot = 0.1 ' 3*pi /FPS
strat(2).mate_en_distmin = 5 * PLAY_BALL_R
strat(2).mate_distmin = 4 * PLAY_BALL_R
'dodging strategy - currently used for all AI players
strat(3).okraj = PRIESTOR_MIN + 10
strat(3).okraj_rot = 0.1
strat(3).chybasmeru = 0.30
strat(3).reactdrop_per = 0.8 * FPS
strat(3).reactdrop_dur = 0.4 * FPS
strat(3).klucka_avgtm = 5 * FPS
strat(3).klucka_pocet = 3
strat(3).klucka_trvanie = 2 * FPS
strat(3).klucka_uhol = pi * 2 / 3
strat(3).klucka_uholodch = 0.2
strat
(3).detekcia_sin
= SIN(pi
/ 6) strat(3).detekcia_vzdfull = 300
strat(3).detekcia_vzdmin = 1500
strat(3).detekcia_rot = 0.5 '10 * pi / FPS
strat(3).boost_dist = 200
strat
(3).boost_chasesin
= SIN(pi
/ 8) strat(3).mate_cosenmax = -0.8 'cos(140/180*pi)
strat(3).mate_rot = 0.1 ' 3*pi /FPS
strat(3).mate_en_distmin = 8 * PLAY_BALL_R
strat(3).mate_distmin = 4 * PLAY_BALL_R
strat(3).adrenalin_rate = 0.90
strat(3).adrenalin_energy = 0.70
'-------------------------------set main menu-----------------------------------------------------------------------------------------------------
menu.item_active = 1
menu.items_count = 22
menu.cursor_col = 15
menu.cursor_width = 400
menu.item_height = FONT_H + 8
menu.cursor_xpos
= INT((stav.maxx
- menu.cursor_width
) / 2) menu.ypos
= INT((stav.maxy
- 500) / 2)
'-----------------------------------------------------------------------------------------------------------------------------------------------------
SUB SitoGame
'main game sub SetGlobalParameters
SetUpControllers
IF stav.pocetgamepadov
> 0 THEN hrac
(1).klavesy
= stav.pocetkontrolerov
'set gamepad as default controller for player1
WINDOW (0, 0)-(stav.maxx
, stav.maxy
)
'----------------------------------new game start-------------------------------------------------------------------------------------------------
MainMenuScreen 'go to main menu
IF stav.exituj
<> 1 THEN 'new game starts here '----------------------------------set the world on the new game start-------------------------------
stav.koniec_hry = 0
stav.pocetgul = stav.pocetgulzvoleny + stav.pocethracov
stav.pocetgulx
= MATHROUND
(SQR(4 / 3 * stav.pocetgul
)) IF stav.pocetgulx
< stav.pocethracov
THEN stav.pocetgulx
= stav.pocethracov
stav.pocetguly
= _CEIL(stav.pocetgul
/ stav.pocetgulx
)
IF stav.pocethracov
< 2 THEN stav.pocethracov
= 2 FOR i
= 1 TO stav.pocethracov
hrac(i).skore = 0
stav.zacinabal
= hrac
(INT(RND * stav.pocethracov
+ 1)).bal
DO 'new round starts here '-------------------------------set the world on the new round start---------------------------
stav.koniec_kola = 0
stav.vitaz = 0
stav.exituj = 0
stav.baljeto = 0
coloffset
= 104 + INT(RND * 10) colcoef
= (1 + INT(RND * (246 - coloffset
))) / stav.pocetgulx
FOR i
= 1 TO stav.pocetguly
+ 1 'set all balls FOR j
= 1 TO stav.pocetgulx
n = (i - 1) * stav.pocetgulx + j:
ry
= 20 + RND * INT(((stav.maxy
- 100) / (stav.pocetguly
+ 1) - 25) / 2) rx
= 10 + RND * INT(((stav.maxx
- 100) / (stav.pocetgulx
+ 1) - 25) / 2) bcol = coloffset + j * colcoef
bal(n).i = n
bal(n).col = bcol
bal
(n
).x
= 100 + j
* INT((stav.maxx
- 100) / (stav.pocetgulx
+ 1)) bal
(n
).y
= 100 + i
* INT((stav.maxy
- 100) / (stav.pocetguly
+ 1)) bal(n).r = rx * -(rx < ry) + ry * -(ry < rx)
bal(n).m = 4 / 4 * pi * bal(n).r ^ 2
bal(n).v.x = -10 / FPS: bal(n).v.y = -30 / FPS
bal(n).a.x = ACC_X * stav.maxx / RES_X_TARG
bal(n).a.y = ACC_Y * stav.maxx / RES_X_TARG
bal
(n
).vi.x
= -(bal
(n
).complayer
= 1) * RND * stav.vmax
- stav.vmax
/ 2 bal
(n
).vi.y
= -(bal
(n
).complayer
= 1) * RND * stav.vmax
- stav.vmax
/ 2 bal(n).riadena = 0
bal(n).energia = stav.energy_player_start
bal(n).freezedtime = 0: bal(n).klucka_time = 0: bal(n).klucka_pocet = 0
bal(n).klucka_trvanie = 0: bal(n).klucka_uhol = 0
bal(n).boost_time = 0: bal(n).boost_trvanie = 0
'---set players balls default atributtes--------------------------------------------------------
FOR i
= 1 TO stav.pocethracov
hrac(i).bal = i
bal(hrac(i).bal).riadena = 1
bal(hrac(i).bal).r = PLAY_BALL_R * stav.maxx / RES_X_TARG
bal(hrac(i).bal).m = 4 / 4 * pi * PLAY_BALL_R ^ 2 / 2 'Players have only half density
bal(hrac(i).bal).col = hrac(i).col
bal(hrac(i).bal).strat = 3
'---decide initially tagged player-------------------------------------------------------------
zacinalNaposledyBal = stav.zacinabal
stav.balbudeto = stav.zacinabal
stav.zacinabal = stav.zacinabal + 1
IF stav.zacinabal
> stav.pocetgulx
THEN stav.zacinabal
= 1 stav.baljeto = stav.zacinabal
FOR b
= 1 TO stav.pocethracov
bal(hrac(b).bal).protivnik = stav.baljeto * -(hrac(b).bal <> stav.baljeto)
bal(stav.zacinabal).protivnik = zacinalNaposledyBal
'----------------------------------game action loop--------------------------------------------
IF stav.pauza
= 1 THEN PauseGame
'game pause stav.tstart
= TIMER(.001) IF k
= 32 OR k
= 102 THEN stav.pauza
= 1
'---debug code begin---------------------------------------------
IF k
= 98 THEN stav.printdebug
= -(stav.printdebug
= 0) IF stav.printdebug
= 1 THEN DebugScreen k
'print debug info on screen '---debug code end-----------------------------------------------
DrawScore 'Draw players score on screen
FOR i
= 1 TO stav.pocethracov
ResolvePlayerControl bal(hrac(i).bal), klav(hrac(i).klavesy) 'resolve players control
IF bal
(hrac
(i
).bal
).riadena
= 1 THEN CalculatePlayerState bal(hrac(i).bal) 'calculate player status
FOR n
= 1 TO stav.pocetgul
PerformMovement bal(n) 'do ball movement
FOR i
= 1 TO stav.pocetgul
FOR j
= i
+ 1 TO stav.pocetgul
BounceTest bal(i), bal(j) 'Test balls bounce
FOR n
= 1 TO stav.pocetgul
DrawBall bal(n) 'draw ball
CalculateFps
'---------------------------end of game action loop---------------------------------------------
stav.koniec_hry = 1
winstr1$
= "....and the winner of this round is... " + RTRIM$(hrac
(stav.vitaz
).meno
) + " !" winstr2$ = "Press <fire> for the next round"
COLOR bal
(hrac
(stav.vitaz
).bal
).col
_PRINTSTRING ((stav.maxx
- LEN(winstr1$
) * 10) / 2, (stav.maxy
- 50) / 2), winstr1$
_PRINTSTRING ((stav.maxx
- LEN(winstr2$
) * 10) / 2, (stav.maxy
- 50) / 2 + 50), winstr2$
anyHumanPlayer = 0
FOR i
= 1 TO stav.pocethracov
IF bal
(hrac
(i
).bal
).complayer
= 0 THEN anyHumanPlayer
= 1 resumegame = 0
FOR i
= 1 TO stav.pocethracov
IF klav
(hrac
(i
).klavesy
).typ
= 3 THEN ReadGamepad klav
(hrac
(i
).klavesy
) IF klav
(hrac
(i
).klavesy
).isshoota
THEN resumegame
= 1 IF klav
(hrac
(i
).klavesy
).isshootb
THEN stav.koniec_hry
= 1 LOOP UNTIL (k
= 27) OR (resumegame
= 1) OR (anyHumanPlayer
= 0) OR (stav.koniec_hry
= 1) '---------------------------end of round-----------------------------------------------------------
'---------------------------end of game------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB SetUpControllers
'detect gamepads and set them as game controllers
FOR i
= 1 TO UBOUND(klav
) 'dispose all gamepad constrollers klav(i).typ = 0
klav(i).devid = 0
klav_volne = 1
stav.pocetgamepadov = 0
klav_volne = klav_volne + 1
klav_used = klav_volne - 1
devices
= _DEVICES 'must be read prior to other device functions usage klav(klav_volne).id = klav_volne
klav(klav_volne).devid = i
klav(klav_volne).typ = 3
klav
(klav_volne
).nazov
= "<Gamepad" + LTRIM$(STR$(klav_volne
- klav_used
)) + ">" klav(klav_volne).xaxis = 1
klav(klav_volne).yaxis = 2
klav(klav_volne).dxaxis = 6
klav(klav_volne).dyaxis = 7
klav(klav_volne).shoota = 1
klav(klav_volne).shootb = 8
klav_volne = klav_volne + 1
stav.pocetgamepadov = stav.pocetgamepadov + 1
stav.pocetkontrolerov = klav_volne - 1
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB MainMenuScreen
'perform choises in main menu vys = FONT_H
sir = FONT_W
menu.items_count = 22
PrintMenuItem 0, menu, 0, 0, 0, "Tag! v.2", 0, 0, -3, 13
PrintMenuItem 0, menu, 0, 0, 0, "Daniel Janec (2019)", 0, 0, -2, 20
PrintMenuItem 1, menu, 6, 0, 0, "Play <Space>", 0, 0, 0, 7
PrintMenuItem
2, menu
, 1, 0, 0, "Refresh gamepads detected: " + STR$(stav.pocetgamepadov
), 0, 0, 0, 7 PrintMenuItem 3, menu, 2, 1, 1, hrac(1).meno + " controls: " + klav(hrac(1).klavesy).nazov, 150, -10 * sir, 1, hrac(1).col
PrintMenuItem
4, menu
, 3, 1, 1, " color:" + STR$(hrac
(1).col
), 150, -10 * sir
, 1, hrac
(1).col
PrintMenuItem 5, menu, 2, 2, 1, hrac(2).meno + " controls: " + klav(hrac(2).klavesy).nazov, 150, -10 * sir, 1, hrac(2).col
PrintMenuItem
6, menu
, 3, 2, 1, " color:" + STR$(hrac
(2).col
), 150, -10 * sir
, 1, hrac
(2).col
PrintMenuItem 7, menu, 2, 3, 1, hrac(3).meno + " controls: " + klav(hrac(3).klavesy).nazov, 150, -10 * sir, 1, hrac(3).col
PrintMenuItem
8, menu
, 3, 3, 1, " color:" + STR$(hrac
(3).col
), 150, -10 * sir
, 1, hrac
(3).col
PrintMenuItem 9, menu, 2, 4, 1, hrac(4).meno + " controls: " + klav(hrac(4).klavesy).nazov, 150, -10 * sir, 1, hrac(4).col
PrintMenuItem
10, menu
, 3, 4, 1, " color:" + STR$(hrac
(4).col
), 150, -10 * sir
, 1, hrac
(4).col
PrintMenuItem 11, menu, 2, 5, 1, hrac(5).meno + " controls: " + klav(hrac(5).klavesy).nazov, 150, -10 * sir, 1, hrac(5).col
PrintMenuItem
12, menu
, 3, 5, 1, " color:" + STR$(hrac
(5).col
), 150, -10 * sir
, 1, hrac
(5).col
PrintMenuItem 13, menu, 2, 6, 1, hrac(6).meno + " controls: " + klav(hrac(6).klavesy).nazov, 150, -10 * sir, 1, hrac(6).col
PrintMenuItem
14, menu
, 3, 6, 1, " color:" + STR$(hrac
(6).col
), 150, -10 * sir
, 1, hrac
(6).col
PrintMenuItem 15, menu, 2, 7, 1, hrac(7).meno + " controls: " + klav(hrac(7).klavesy).nazov, 150, -10 * sir, 1, hrac(7).col
PrintMenuItem
16, menu
, 3, 7, 1, " color:" + STR$(hrac
(7).col
), 150, -10 * sir
, 1, hrac
(7).col
PrintMenuItem 17, menu, 2, 8, 1, hrac(8).meno + " controls: " + klav(hrac(8).klavesy).nazov, 150, -10 * sir, 1, hrac(8).col
PrintMenuItem
18, menu
, 3, 8, 1, " color:" + STR$(hrac
(8).col
), 150, -10 * sir
, 1, hrac
(8).col
PrintMenuItem
19, menu
, 8, 0, 1, "Player starting energy: " + STR$(stav.energy_player_start
), 100, -10 * sir
, 2, 7 PrintMenuItem
20, menu
, 4, 0, 1, " Number of players: " + STR$(stav.pocethracov
), 100, -10 * sir
, 2, 7 PrintMenuItem
21, menu
, 5, 0, 1, " Balls count: " + STR$(stav.pocetgulzvoleny
), 100, -10 * sir
, 2, 7 PrintMenuItem 22, menu, 7, 0, 0, "Exit <Esc>", 0, 0, 2, 7
FOR i
= 1 TO stav.pocetkontrolerov
ReadGamepad klav(i)
IF klav
(i
).buttonstatechanged
THEN IF klav
(i
).isshoota
THEN k
= 13: klav
(i
).isshoota
= 0 IF klav
(i
).isup
THEN k
= 18432: klav
(i
).isup
= 0 IF klav
(i
).isdown
THEN k
= 20480: klav
(i
).isdown
= 0 IF klav
(i
).isright
THEN k
= 19712: klav
(i
).isright
= 0 IF klav
(i
).isleft
THEN k
= 19200: klav
(i
).isleft
= 0
IF menu.item_active
> 1 THEN menu.item_active
= menu.item_active
- 1 IF menu.item_active
< menu.items_count
THEN menu.item_active
= menu.item_active
+ 1 CASE 2 'players controller i = menu.playercode
hrac(i).klavesy = hrac(i).klavesy - 1
IF hrac
(i
).klavesy
< 1 THEN hrac
(i
).klavesy
= stav.pocetkontrolerov
i = menu.playercode
hrac(i).col = hrac(i).col - 1
IF hrac
(i
).col
< 1 THEN hrac
(i
).col
= stav.maxcol
stav.pocethracov = stav.pocethracov - 1
IF stav.pocetgulzvoleny
> 0 THEN stav.pocetgulzvoleny = stav.pocetgulzvoleny - 1
IF stav.energy_player_start
> 10 THEN stav.energy_player_start = stav.energy_player_start - 1
CASE 2 'players controller i = menu.playercode
hrac(i).klavesy = hrac(i).klavesy + 1
IF hrac
(i
).klavesy
> stav.pocetkontrolerov
THEN hrac
(i
).klavesy
= 1 i = menu.playercode
hrac(i).col = hrac(i).col + 1
IF hrac
(i
).col
> stav.maxcol
THEN hrac
(i
).col
= 1 IF stav.pocethracov
< PLAYER_COUNT_MAX
THEN stav.pocethracov = stav.pocethracov + 1
IF stav.pocetgulzvoleny
< POCET_GUL_MAX
THEN stav.pocetgulzvoleny = stav.pocetgulzvoleny + 1
IF stav.energy_player_start
< ENERGY_PLAYER_MAX
THEN stav.energy_player_start = stav.energy_player_start + 1
SetUpControllers
hrac(menu.playercode).meno = InputName$(hrac(menu.playercode).meno, menu.cursor_xpos + 2 * sir, menu.ypos + menu.item_active * menu.item_height, hrac(menu.playercode).col)
k = 32
k = 27
FOR i
= 1 TO PLAYER_COUNT_MAX
'set AI controller type for computer players IF klav
(hrac
(i
).klavesy
).typ
= 4 THEN bal
(hrac
(i
).bal
).complayer
= 1 ELSE bal
(hrac
(i
).bal
).complayer
= 0
IF menu.menucode
= 4 AND (k
= 19712 OR k
= 19200) THEN 'after changing players count stav.energy_player_start
= INT(stav.energy_allmin
/ stav.pocethracov
) 'calculate players energy IF stav.energy_player_start
< stav.energy_playermin
THEN stav.energy_player_start
= stav.energy_playermin
IF stav.energy_player_start
> stav.energy_playermax
THEN stav.energy_player_start
= stav.energy_playermax
stav.exituj = 1
'----------------------------------------------------------------------------------------------------------------------------------------------------
res$ = ""
IF res$
= "" THEN tmpstr
= "<Type name>" ELSE tmpstr
= res$
'----------------------------------------------------------------------------------------------------------------------------------------------------
IF fixedwidth
> 0 THEN slen
= fixedwidth
px
= INT((stav.maxx
- slen
) / 2) + deltax
py = amenu.ypos + (id - 1 + lineoff) * amenu.item_height
IF id
= amenu.item_active
THEN LINE (amenu.cursor_xpos
- 5, stav.maxy
- (py
- 5))-(amenu.cursor_xpos
+ 5 + amenu.cursor_width
, stav.maxy
- (py
+ FONT_H
) - 5), amenu.cursor_col
, B
_PRINTSTRING (amenu.cursor_xpos
+ amenu.cursor_width
+ 10, py
), ">" amenu.menucode = menucode
amenu.playercode = playercode
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB PauseGame
'pause gameplay IF k
= 102 THEN stav.pauza
= 1 stav.pauza = 0
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB DrawBall
(baln
AS gula
) 'draw ball koef = (10 + 90 * stav.printdebug) * FPS / 100
CIRCLE (baln.x
, baln.y
), baln.r
* 2 / 3, 15 CIRCLE (baln.x
, baln.y
), baln.r
* 4 / 5, baln.col
CIRCLE (baln.x
, baln.y
), baln.r
* 1 / 3, baln.col
'PAINT STEP(0, 0), baln.col 'filling players heads with solid color tragically reduces perforamance
LINE (baln.x
, baln.y
)-(baln.x
+ baln.v.x
* koef
, baln.y
+ baln.v.y
* koef
), baln.col
'draw actual velocity IF stav.printdebug
= 1 THEN LINE (baln.x
, baln.y
)-(baln.x
+ baln.vi.x
* koef
, baln.y
+ baln.vi.y
* koef
), bal
(baln.protivnik
).col
'draw intended velocity CIRCLE (baln.x
, baln.y
), baln.r
, baln.col
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB DrawScore
'Draw player score FOR i
= 1 TO stav.pocethracov
scxl = SCORE_DELTA_X * -(stav.maxx >= 4 * SCORE_DELTA_X) + stav.maxx / 4 * -(stav.maxx < 4 * SCORE_DELTA_X)
dx = (stav.maxx - 4 * scxl) / 2
scx
= dx
+ scxl
* ((i
- 4 * INT((i
- 1) / 4)) - 1) scty
= SCORE_DELTA_Y
+ 15 * INT((i
- 1) / 4) scly
= stav.maxy
- SCORE_DELTA_Y
- 15 * INT((i
- 1) / 4) COLOR bal
(hrac
(i
).bal
).col
LINE (scx
+ SCORE_NAME_LEN
, scly
)-(scx
+ SCORE_NAME_LEN
+ bal
(hrac
(i
).bal
).energia
, scly
+ 7), bal
(hrac
(i
).bal
).col
, BF
IF bal
(hrac
(i
).bal
).energia
<= 0 THEN
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB CalculatePlayerState
(baln
AS gula
) 'calculate players states stav.fpscoef = stav.fps / stav.fpsactual
'-----------------------energy decreasing-------------------------------------
baln.freezedtime = baln.freezedtime - 1
baln.energia = baln.energia - (stav.energydec * -(stav.baljeto = baln.i)) * stav.fpscoef
baln.riadena = 0
stav.baljeto = stav.balbudeto
stav.balbudeto = nearestPlayer(bal(stav.baljeto), 0)
pocetriadenych = 0
FOR i
= 1 TO stav.pocethracov
IF bal
(hrac
(i
).bal
).riadena
= 1 THEN pocetriadenych = pocetriadenych + 1
priebeznyvitaz = i
stav.koniec_kola = 1
stav.vitaz = priebeznyvitaz
hrac(stav.vitaz).skore = hrac(stav.vitaz).skore + 1
DrawScore
'-----------------------dodging time-----------------------------------------
IF baln.klucka_time
= 0 AND baln.klucka_trvanie
= 0 AND baln.klucka_pocet
= 0 THEN baln.klucka_time
= INT(RND * strat
(baln.strat
).klucka_avgtm
+ strat
(baln.strat
).klucka_avgtm
/ 2) / stav.fpscoef
baln.klucka_pocet = strat(baln.strat).klucka_pocet
baln.klucka_time = baln.klucka_time - 1
IF baln.klucka_time
= 0 AND baln.klucka_trvanie
> 0 THEN baln.klucka_trvanie = baln.klucka_trvanie - 1
IF baln.klucka_time
= 0 AND baln.klucka_trvanie
= 0 AND baln.klucka_pocet
> 0 THEN baln.klucka_pocet = baln.klucka_pocet - 1
baln.klucka_trvanie
= INT(RND * strat
(baln.strat
).klucka_trvanie
+ strat
(baln.strat
).klucka_trvanie
/ 2) / stav.fpscoef
baln.klucka_uhol
= RND * strat
(baln.strat
).klucka_uhol
* (2 * strat
(baln.strat
).klucka_uholodch
) + strat
(baln.strat
).klucka_uhol
* (1 - strat
(baln.strat
).klucka_uholodch
) * (3 - INT(RND * 2 + 1) * 2) '-----------------------choose nearest enemy if tagged-----------------------
novyprotivnik = nearestPlayer(baln, 0)
IF novyprotivnik
<> 0 THEN baln.protivnik
= novyprotivnik
stav.balbudeto = baln.protivnik
'-----------------------boosting time----------------------------------------
IF baln.boost_time
> 0 AND baln.boost_trvanie
= 0 THEN baln.boost_time
= baln.boost_time
- 1 IF baln.boost_trvanie
> 0 THEN baln.boost_trvanie
= baln.boost_trvanie
- 1
'-----------------------reaction drop time-----------------------------------
IF baln.reactdrop_time
> 0 THEN baln.reactdrop_time
= baln.reactdrop_time
- 1 IF baln.reactdrop_time
<= 0 AND baln.reactdrop_dur
> 0 THEN baln.reactdrop_dur
= baln.reactdrop_dur
- 1 IF baln.reactdrop_time
<= 0 AND baln.reactdrop_dur
<= 0 THEN IF baln.energia
< (stav.energy_player_start
* strat
(baln.strat
).adrenalin_energy
) THEN reactkoef
= (1 - strat
(baln.strat
).adrenalin_rate
) ELSE reactkoef
= 1 baln.reactdrop_time
= INT((RND * strat
(baln.strat
).reactdrop_per
* reactkoef
+ strat
(baln.strat
).reactdrop_per
* reactkoef
/ 2) / stav.fpscoef
) baln.reactdrop_dur
= INT((RND * strat
(baln.strat
).reactdrop_dur
* reactkoef
+ strat
(baln.strat
).reactdrop_dur
* reactkoef
/ 2) / stav.fpscoef
) baln.smer_odchyl
= (RND * strat
(baln.strat
).chybasmeru
- strat
(baln.strat
).chybasmeru
/ 2) * pi
'apply random radian deviance from intended direction
'----------------------------------------------------------------------------------------------------------------------------------------------------
FUNCTION nearestPlayer
(baln
AS gula
, mateonly
AS _BYTE) 'returns nearest opponent idx vzdakt = 0
nearestPlayer = 0
FOR i
= 1 TO stav.pocetgulx
IF bal
(i
).i
<> baln.i
AND bal
(i
).riadena
= 1 AND (mateonly
= 1 IMP i
<> stav.baljeto
) THEN vzd
= SQR((baln.x
- bal
(i
).x
) ^ 2 + (baln.y
- bal
(i
).y
) ^ 2) IF nearestPlayer
= 0 OR vzd
< vzdakt
THEN nearestPlayer = i
vzdakt = vzd
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB GenerateAIControl
(baln
AS gula
) 'Decide computer player's control keys hits DIM d
AS vektor
, vi
AS vektor
, ei
AS vektor
, ve
AS vektor
, di
AS vektor
, dm
AS vektor
vi = baln.vi 'player's intended speed vector copy
vid
= SQR(vi.x
^ 2 + vi.y
^ 2) vi.x = vi.x / vid * stav.vmax
vi.y = vi.y / vid * stav.vmax
vd
= SQR(baln.v.x
^ 2 + baln.v.y
^ 2) ve = bal(baln.protivnik).v 'enemy speed vector copy
ved
= SQR(ve.x
^ 2 + ve.y
^ 2)
d.x = bal(baln.protivnik).x - baln.x 'player to enemy postition vector
d.y = bal(baln.protivnik).y - baln.y
dd
= SQR(d.x
^ 2 + d.y
^ 2) coser = (d.x * baln.v.x + d.y * baln.v.y) / (dd * vd)
siner = (d.x * baln.v.y - d.y * baln.v.x) / (dd * vd)
cosevr = (ve.x * baln.v.x + ve.y * baln.v.y) / (ved * vd)
sinevr = (ve.x * baln.v.y - ve.y * baln.v.x) / (ved * vd)
'!EXPERIMENTAL CODE! - try more exact enemy future position vector, but does not work so well as used approximation
'di.x = d.x + ve.x * d.x / ((((d.x / dd) + (ve.x / ved)) * stav.vmax) - ve.x) 'new intended direction to enemy
'di.y = d.y + ve.y * d.y / ((((d.y / dd) + (ve.y / ved)) * stav.vmax) - ve.y) 'new intended direction to enemy
'!EXPERIMENTAL CODE! end
di.x
= d.x
+ ve.x
* dd
/ vd
* ABS(siner
) 'player to enemy approximate future position vector, future enemy position more relevant when enemy closer di.y
= d.y
+ ve.y
* dd
/ vd
* ABS(siner
) did
= SQR(di.x
^ 2 + di.y
^ 2) coseri = (di.x * baln.v.x + di.y * baln.v.y) / (did * vd)
sineri = (di.x * baln.v.y - di.y * baln.v.x) / (did * vd)
rot_enemy = 0 'rotation away from enemy in rad
rot_border = 0 'rotation away from border in rad
rot_mate = 0 'rotation towards nearest mate in rad
rot_odchyl = 0 'baln.smer_odchyl * -(baln.reactdrop_dur = 1) 'apply direction error if react time
smerdookraju = 0 'is players direction to border
IF NOT (stav.baljeto
= baln.i
) THEN 'decide flee action enemy_dist_factor = 1 * -(dd <= strat(baln.strat).detekcia_vzdfull) + (1 - (dd - strat(baln.strat).detekcia_vzdfull) / _
(strat
(baln.strat
).detekcia_vzdmin
- strat
(baln.strat
).detekcia_vzdfull
)) * -(dd
> strat
(baln.strat
).detekcia_vzdfull
AND dd
<= strat
(baln.strat
).detekcia_vzdmin
)' factor=1 if enemy distance within treshold, then decreasing
IF enemy_dist_factor
> 0 THEN 'if enemy in detection distance, rotate away rot_enemy
= -(coseri
> 0) * -(ABS(sineri
) <= strat
(baln.strat
).detekcia_sin
) * (-(sineri
> 0) + (sineri
< 0)) * strat
(baln.strat
).detekcia_rot
* enemy_dist_factor
* stav.fpscoef
'!EXPERIMENTAL CODE! - try better rotation from enemy
'strat(baln.strat).detekcia_rot = 10 * pi / FPS 'TEMPORARY MODIFICATION
'cosevi = (di.x * vi.x + di.y * vi.y) / (did * vid)
'sinevi = (di.x * vi.y - di.y * vi.x) / (did * vid)
'cosvvi = (v.x * vi.x + v.y * vi.y) / (vd * vid)
'sinvvi = (v.x * vi.y - v.y * vi.x) / (vd * vid)
'IF (coseri > 0) AND (ABS(sineri) <= strat(baln.strat).detekcia_sin) THEN
' rot_dir = -(sineri > 0) + (sineri < 0)
' IF NOT ((cosevi > 0 AND (ABS(sinevi) <= strat(baln.strat).detekcia_sin)) AND NOT (rot_dir = (-(sinevi > 0) + (sinevi < 0)))) THEN
' rot_enemy = rot_dir * strat(baln.strat).detekcia_rot * enemy_dist_factor * stav.fpscoef
' END IF
'END IF
'!EXPERIMENTAL CODE! end
okrajrot = strat(baln.strat).okraj_rot 'border unit rotation in rad
IF baln.x
< strat
(baln.strat
).okraj
AND vi.x
< 0 THEN rot_border = (okrajrot * (vi.y >= 0) + okrajrot * -(vi.y < 0)) '* (1 - enemy_dist_factor)
smerdookraju = 1
IF baln.x
> stav.maxx
- strat
(baln.strat
).okraj
AND vi.x
> 0 THEN rot_border = (okrajrot * -(vi.y >= 0) + okrajrot * (vi.y < 0)) '* (1 - enemy_dist_factor)
smerdookraju = 1
IF baln.y
< strat
(baln.strat
).okraj
AND vi.y
< 0 THEN rot_border = (okrajrot * (vi.x >= 0) + okrajrot * (vi.x < 0)) '* (1 - enemy_dist_factor)
smerdookraju = 1
IF baln.y
> stav.maxy
- strat
(baln.strat
).okraj
AND vi.y
> 0 THEN rot_border = (okrajrot * (vi.x >= 0) + okrajrot * -(vi.x < 0)) '* (1 - enemy_dist_factor)
smerdookraju = 1
rot_klucka = baln.klucka_uhol * -(baln.klucka_time = 0) * -(baln.klucka_trvanie = 1) * -(stav.baljeto <> baln.i) * _
(dd
> strat
(baln.strat
).mate_distmin
OR (coseri
< 0 AND sineri
>= 0 AND baln.klucka_uhol
> 0 AND baln.klucka_uhol
< pi
) OR (coseri
< 0 AND sineri
<= 0 AND baln.klucka_uhol
< 0 AND baln.klucka_uhol
> -pi
)) 'apply dodge if dodging time - TEMPORARY DISABLED!!!
IF baln.i
= bal
(stav.baljeto
).protivnik
THEN 'if ball being chased nearmate = nearestPlayer(baln, 1)
dm.x = bal(nearmate).x - baln.x
dm.y = bal(nearmate).y - baln.y
dmd
= SQR(dm.x
^ 2 + dm.y
^ 2) cosnm = (dm.x * baln.v.x + dm.y * baln.v.y) / (dmd * vd)
sinnm = (dm.x * baln.v.y - dm.y * baln.v.x) / (dmd * vd)
IF (rot_border
= 0) AND (dmd
> strat
(baln.strat
).mate_distmin
) AND (((coseri
< strat
(baln.strat
).mate_cosenmax
) AND (dd
< strat
(baln.strat
).mate_en_distmin
)) OR ((coseri
< 0) AND (dd
> strat
(baln.strat
).mate_en_distmin
))) THEN rot_mate = ((sinnm > 0) * strat(baln.strat).mate_rot * stav.fpscoef - (sinnm <= 0) * strat(baln.strat).mate_rot * stav.fpscoef) 'rotate towards mate
'---debug code begin---
'IF stav.printdebug THEN
' COLOR baln.col
' PRINT "baln.i "; baln.i
' PRINT "vi "; vi.x; vi.y; vid
' PRINT "d "; d.x; d.y; dd
' PRINT "di "; di.x; di.y; did
' PRINT "rot_border "; rot_border
' PRINT "rot_enemy "; rot_enemy
' PRINT "rot_mate "; rot_mate
' PRINT "okrajrot "; okrajrot
' PRINT "nearmate "; nearmate
' PRINT "dm "; dm.x; dm.y; dmd
' PRINT "cosnm;sinnm "; cosnm; sinnm
'END IF
'---debug code end---
RotateVector vi, rot_border + rot_klucka + rot_odchyl + rot_enemy + rot_mate 'aplly all calculated rotations to intended velocity
IF stav.baljeto
= baln.i
THEN 'chasing direction intended IF baln.reactdrop_time
> 0 THEN 'if time is up for reaction baln.boostintended
= -(-(coser
> 0) AND -(cosevr
> 0) AND -(ABS(sinevr
) < strat
(baln.strat
).boost_chasesin
) AND baln.boost_time
= 0 AND smerdookraju
= 0) baln.vi.x = stav.vmax * di.x / did
baln.vi.y = stav.vmax * di.y / did
ELSE 'flee direction intended baln.boostintended
= -(-(coser
< 0) AND baln.boost_time
= 0 AND dd
< (RND * strat
(baln.strat
).boost_dist
+ 2 * PLAY_BALL_R
) AND smerdookraju
= 0) baln.vi.x = vi.x
baln.vi.y = vi.y
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB ReadGamepad
(klavn
AS klavesy
) 'read state of gamepad klavn.gvektor.x
= _AXIS(klavn.xaxis
) klavn.gvektor.y
= -_AXIS(klavn.yaxis
) klavn.isshoota
= _BUTTON(klavn.shoota
) klavn.isshootb
= _BUTTON(klavn.shootb
) klavn.isup
= (_AXIS(klavn.dyaxis
) = -1) klavn.isdown
= (_AXIS(klavn.dyaxis
) = 1) klavn.isleft
= (_AXIS(klavn.dxaxis
) = -1) klavn.isright
= (_AXIS(klavn.dxaxis
) = 1) IF klavn.gvektor.x
> 0.5 THEN klavn.isright
= -1 IF klavn.gvektor.x
< -0.5 THEN klavn.isleft
= -1 IF klavn.gvektor.y
> 0.5 THEN klavn.isup
= -1 IF klavn.gvektor.y
< -0.5 THEN klavn.isdown
= -1
IF klavn.buttonstate
<> (klavn.isshoota
+ klavn.isshootb
* 2 + klavn.isup
* 4 + klavn.isdown
* 8 + klavn.isright
* 16 + klavn.isleft
* 32) THEN klavn.buttonstatechanged = -1
klavn.buttonstatetimer = 50
klavn.buttonstatechanged = 0
klavn.buttonstate = (klavn.isshoota + klavn.isshootb * 2 + klavn.isup * 4 + klavn.isdown * 8 + klavn.isright * 16 + klavn.isleft * 32)
IF klavn.buttonstatetimer
> 0 THEN klavn.buttonstatetimer
= klavn.buttonstatetimer
- 1 IF klavn.buttonstatetimer
= 0 THEN klavn.buttonstatechanged
= -1
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB ResolvePlayerControl
(baln
AS gula
, klavn
AS klavesy
) 'perform players control keys actions DIM vn
AS vektor
, gvector
AS vektor
IF baln.complayer
= 0 THEN 'read human player controls IF klavn.typ
= 1 THEN 'read keyboard control baln.vi.x = baln.v.x
baln.vi.y = baln.v.y
IF klavn.typ
= 3 THEN 'read gamepad control ReadGamepad klavn
baln.vi.x = klavn.gvektor.x * stav.vmax
baln.vi.y = klavn.gvektor.y * stav.vmax
IF ABS(klavn.gvektor.x
) > GAMESTICK_DEADZONE
OR ABS(klavn.gvektor.y
) > GAMESTICK_DEADZONE
THEN klavn.isright = (baln.v.x < baln.vi.x) 'set control keys status for desired direction
klavn.isleft = (baln.v.x > baln.vi.x)
klavn.isup = (baln.v.y < baln.vi.y)
klavn.isdown = (baln.v.y > baln.vi.y)
IF klavn.isshootb
THEN stav.koniec_kola
= 1: stav.koniec_hry
= 1 ELSE 'get controls of computer player IF baln.riadena
= 1 THEN GenerateAIControl baln
klavn.isright = (baln.v.x < baln.vi.x) 'set control keys status for desired direction
klavn.isleft = (baln.v.x > baln.vi.x)
klavn.isup = (baln.v.y < baln.vi.y)
klavn.isdown = (baln.v.y > baln.vi.y)
klavn.isshoota = -baln.boostintended
IF baln.freezedtime
<= 0 AND baln.riadena
= 1 THEN 'apply acquired controls to player movement vn.x = baln.v.x
vn.y = baln.v.y
stav.fpscoef = stav.fps / stav.fpsactual
IF klavn.isright
THEN vn.x
= vn.x
+ baln.a.x
* stav.fpscoef
'accelerate player according to control keys states IF klavn.isleft
THEN vn.x
= vn.x
- baln.a.x
* stav.fpscoef
IF klavn.isdown
THEN vn.y
= vn.y
- baln.a.y
* stav.fpscoef
IF klavn.isup
THEN vn.y
= vn.y
+ baln.a.x
* stav.fpscoef
IF klavn.isshoota
AND baln.boost_time
= 0 AND stav.boostallowed
= 1 THEN 'set boost state baln.boost_trvanie = BOOST_TRVANIE / stav.fpscoef
baln.boost_time = BOOST_TIME / stav.fpscoef
vnd
= SQR(vn.x
^ 2 + vn.y
^ 2) 'limit actual velocity to max. velocity vn.x = vn.x * stav.vmax / vnd
vn.y = vn.y * stav.vmax / vnd
IF baln.boost_trvanie
> 0 THEN 'add some extra speed if boosted vn.x = vn.x + stav.vmax * BOOST_V_KOEF * (baln.boost_trvanie / BOOST_TRVANIE) * stav.fpscoef * vn.x / vnd
vn.y = vn.y + stav.vmax * BOOST_V_KOEF * (baln.boost_trvanie / BOOST_TRVANIE) * stav.fpscoef * vn.y / vnd
baln.v.x = vn.x 'apply controler modified velocity
baln.v.y = vn.y
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB PerformMovement
(baln
AS gula
) 'Calculate ball movement baln.x = baln.x + baln.v.x * stav.fpscoef
baln.y = baln.y + baln.v.y * stav.fpscoef
baln.v.x = baln.v.x * stav.odpor ^ stav.fpscoef
baln.v.y = baln.v.y * stav.odpor ^ stav.fpscoef
IF (baln.x
+ baln.r
> stav.maxx
) THEN baln.v.x = -baln.v.x
baln.x = stav.maxx - baln.r
IF (baln.x
- baln.r
< stav.minx
) THEN baln.v.x = -baln.v.x
baln.x = stav.minx + baln.r
IF (baln.y
+ baln.r
> stav.maxy
) THEN baln.v.y = -baln.v.y
baln.y = stav.maxy - baln.r
IF (baln.y
- baln.r
< stav.miny
) THEN baln.v.y = -baln.v.y
baln.y = stav.miny + baln.r
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB BounceTest
(bala
AS gula
, balb
AS gula
) 'Balls bounce test IF (bala.x
- balb.x
) * (bala.x
- balb.x
) + (bala.y
- balb.y
) * (bala.y
- balb.y
) <= (bala.r
+ balb.r
+ 0) * (bala.r
+ balb.r
+ 0) THEN PerformBounce bala, balb
IF bala.riadena
AND balb.riadena
AND bala.freezedtime
<= 0 AND balb.freezedtime
<= 0 AND (stav.baljeto
= bala.i
OR stav.baljeto
= balb.i
) THEN 'balb.col = bal(bala.protivnik).col stav.baljeto = bala.i * -(stav.baljeto <> bala.i) + balb.i * -(stav.baljeto <> balb.i)
bala.freezedtime = -(stav.baljeto = bala.i) * FREEZE_TIME / stav.fpscoef
balb.freezedtime = -(stav.baljeto = balb.i) * FREEZE_TIME / stav.fpscoef
bala.protivnik = balb.i
balb.protivnik = bala.i
FOR i
= 1 TO stav.pocetgulx
IF bal
(i
).i
<> stav.baljeto
AND bal
(i
).riadena
= 1 THEN bal
(i
).protivnik
= bal
(stav.baljeto
).i
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB PerformBounce
(bala
AS gula
, balb
AS gula
) 'Calculate balls bounce
ma = bala.m
mb = balb.m
ma = 1
mb = 1
dx = balb.x - bala.x
dy = balb.y - bala.y
p = bala.r + balb.r - d 'Move overlapping balls away from each other
bala.x = bala.x - dx * p / d / 2 * 2
bala.y = bala.y - dy * p / d / 2 * 2
balb.x = balb.x + dx * p / d / 2 * 2
balb.y = balb.y + dy * p / d / 2 * 2
dx = balb.x - bala.x
dy = balb.y - bala.y
cosa = dy / d
cosb = -cosa
l = (dx * bala.v.x * ma + dy * bala.v.y * ma) / d
l2 = l * cosa
k = (dy * bala.v.x * ma - dx * bala.v.y * ma) / d
k1 = k * cosa
l1 = bala.v.x * ma - k1
k2 = bala.v.y * ma - l2
n = (-dx * balb.v.x * mb - dy * balb.v.y * mb) / d
n2 = n * cosb
m = (-dy * balb.v.x * mb + dx * balb.v.y * mb) / d
m1 = m * cosb
n1 = balb.v.x * mb - m1
m2 = balb.v.y * mb - n2
bala.v.x = (k1 + n1) / ma
bala.v.y = (k2 + n2) / ma
balb.v.x = (m1 + l1) / mb
balb.v.y = (m2 + l2) / mb
'----------------------------------------------------------------------------------------------------------------------------------------------------
MATHROUND
= FIX(n
+ 0.5 * SGN(n
))
'----------------------------------------------------------------------------------------------------------------------------------------------------
vt.x = vn.x * cosb - vn.y * sinb
vt.y = vn.y * cosb + vn.x * sinb
vn = vt
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB CalculateFps
'calculate actual fps coeficient for correct timig IF stav.tend
= stav.tstart
THEN stav.fpsactual = stav.fps
stav.fpsactual = ((1 / (stav.tend - stav.tstart)) * 1 + stav.fpsactual * 99) / 100
stav.tstart = stav.tend
stav.fpscoef = stav.fps / stav.fpsactual
'----------------------------------------------------------------------------------------------------------------------------------------------------
SUB DebugScreen
(K
AS INTEGER) 'print debyg information on screen in runtime PRINT "FPS: "; stav.fpsactual
IF K
= 101 THEN stav.energydec
= -(stav.energydec
= 0) * ENERGY_DEC
bal(hrac(2).bal).strat = bal(hrac(2).bal).strat + 1
bal(hrac(2).bal).strat = 1
PRINT "hrac(1)..isleft "; klav
(hrac
(1).klavesy
).isleft
PRINT "hrac(1)..isright "; klav
(hrac
(1).klavesy
).isright
PRINT "hrac(1)..isdown "; klav
(hrac
(1).klavesy
).isdown
PRINT "hrac(1)..isup "; klav
(hrac
(1).klavesy
).isup
PRINT "bal(2).vi "; bal
(hrac
(2).bal
).vi.x; bal
(hrac
(2).bal
).vi.y
PRINT "bal(2).strat "; bal
(2).strat
PRINT "bal(2).klucka_time "; bal
(hrac
(2).bal
).klucka_time
PRINT "bal(2).klucka_pocet "; bal
(hrac
(2).bal
).klucka_pocet
PRINT "bal(2).klucka_trvanie "; bal
(hrac
(2).bal
).klucka_trvanie
PRINT "bal(2).klucka_uhol "; bal
(hrac
(2).bal
).klucka_uhol
PRINT "bal(n).protivnik "; bal
(1).protivnik; bal
(2).protivnik; bal
(3).protivnik; bal
(stav.pocetgulx
).protivnik
PRINT "stav.baljeto "; stav.baljeto
PRINT "stav.balbudeto "; stav.balbudeto
PRINT "nearestPlayer(1) "; nearestPlayer
(bal
(1), 0) PRINT "bal(n).reactdrop_time _dur "; bal
(2).reactdrop_time; bal
(2).reactdrop_dur
PRINT "bal(1).v "; bal
(1).v.x; bal
(1).v.y
PRINT "bal(1).a "; bal
(1).a.x; bal
(1).a.y
PRINT "bal(2).boostintended "; bal
(2).boostintended
PRINT "bal(2).boost_time "; bal
(1).boost_time
PRINT "bal(2).boost_trvanie "; bal
(1).boost_trvanie
'----------------------------------------------------------------------------------------------------------------------------------------------------