├── .github └── FUNDING.yml ├── showcase ├── 1.png ├── 2.png ├── 3.png ├── 4.png └── 5.png ├── assets ├── sprites │ ├── upscale.txt │ ├── bomb │ │ ├── 1.png │ │ ├── 2.png │ │ └── 3.png │ ├── levels │ │ ├── 1.png │ │ └── 2.png │ ├── breakabletile.png │ ├── explosion │ │ ├── 1 │ │ │ ├── up.png │ │ │ ├── core.png │ │ │ ├── down.png │ │ │ ├── left.png │ │ │ ├── right.png │ │ │ └── downsc │ │ │ │ ├── core.png │ │ │ │ ├── down.png │ │ │ │ ├── left.png │ │ │ │ ├── up.png │ │ │ │ └── right.png │ │ ├── 2 │ │ │ ├── up.png │ │ │ ├── core.png │ │ │ ├── down.png │ │ │ ├── left.png │ │ │ ├── right.png │ │ │ └── downc │ │ │ │ ├── up.png │ │ │ │ ├── core.png │ │ │ │ ├── down.png │ │ │ │ ├── left.png │ │ │ │ └── right.png │ │ ├── 3 │ │ │ ├── up.png │ │ │ ├── core.png │ │ │ ├── down.png │ │ │ ├── left.png │ │ │ ├── right.png │ │ │ └── downc │ │ │ │ ├── up.png │ │ │ │ ├── core.png │ │ │ │ ├── down.png │ │ │ │ ├── left.png │ │ │ │ └── right.png │ │ ├── 4 │ │ │ ├── up.png │ │ │ ├── core.png │ │ │ ├── down.png │ │ │ ├── left.png │ │ │ ├── right.png │ │ │ └── downc │ │ │ │ ├── up.png │ │ │ │ ├── core.png │ │ │ │ ├── down.png │ │ │ │ ├── left.png │ │ │ │ └── right.png │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ └── nomirror │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ └── 4.png │ ├── player1 │ │ ├── up │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ └── 4.png │ │ ├── down │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ └── 4.png │ │ ├── dying │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ │ ├── left │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ └── 4.png │ │ └── right │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ └── 4.png │ ├── player2 │ │ ├── up │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── down │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── dying │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ │ ├── left │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ └── right │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ ├── player3 │ │ ├── up │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── down │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── dying │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ │ ├── left │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ └── right │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ ├── player4 │ │ ├── up │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── down │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ ├── dying │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ │ ├── left │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ │ └── right │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ └── 3.png │ ├── titlescreen_1.png │ ├── titlescreen_2.png │ └── breakingtile │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ └── 6.png ├── sound │ ├── sfx │ │ ├── die.wav │ │ ├── spawn.wav │ │ ├── walk.wav │ │ ├── laybomb.wav │ │ ├── explosion.wav │ │ ├── menuconfirm.wav │ │ └── respawninvalid.wav │ └── music │ │ ├── ingame.wav │ │ ├── gameover.wav │ │ ├── titlescreen.wav │ │ ├── ingame_lowtime.wav │ │ └── loadingscreen.wav └── credits.txt ├── bomberman_local.rkt ├── game ├── sv_disconnect.rkt ├── sv_network_ingame_latejoin.rkt ├── sh_tick_breakingtile.rkt ├── sh_config_snds.rkt ├── sv_network_ingame_respawn.rkt ├── sv_network_ingame.rkt ├── cl_render_titlescreen.rkt ├── cl_collisions.rkt ├── sv_network_ingame_move.rkt ├── sv_connect.rkt ├── cl_sound.rkt ├── sh_tick.rkt ├── sv_network_ingame_bomb.rkt ├── cl_render.rkt ├── sh_tick_bomb.rkt ├── sh_helper.rkt ├── sv_network_waiting.rkt ├── cl_helper.rkt ├── cl_tick.rkt ├── sv_gamefieldgen.rkt ├── sv_tick.rkt ├── sh_collisions.rkt ├── sh_structs.rkt ├── sv_helper.rkt ├── cl_network.rkt ├── sh_tick_explosion.rkt ├── cl_render_game.rkt ├── sh_config_textures.rkt ├── cl_input.rkt └── sh_config.rkt ├── LICENSE ├── bomberman_server.rkt ├── bomberman_client.rkt ├── bomberman_online.rkt ├── README.md └── bomberman_tests.rkt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [Leystryku] 2 | -------------------------------------------------------------------------------- /showcase/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/showcase/1.png -------------------------------------------------------------------------------- /showcase/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/showcase/2.png -------------------------------------------------------------------------------- /showcase/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/showcase/3.png -------------------------------------------------------------------------------- /showcase/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/showcase/4.png -------------------------------------------------------------------------------- /showcase/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/showcase/5.png -------------------------------------------------------------------------------- /assets/sprites/upscale.txt: -------------------------------------------------------------------------------- 1 | copy individual block 2 | upscale to 250% with best quality ya got 3 | -------------------------------------------------------------------------------- /assets/sound/sfx/die.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/die.wav -------------------------------------------------------------------------------- /assets/sound/sfx/spawn.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/spawn.wav -------------------------------------------------------------------------------- /assets/sound/sfx/walk.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/walk.wav -------------------------------------------------------------------------------- /assets/sprites/bomb/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/bomb/1.png -------------------------------------------------------------------------------- /assets/sprites/bomb/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/bomb/2.png -------------------------------------------------------------------------------- /assets/sprites/bomb/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/bomb/3.png -------------------------------------------------------------------------------- /assets/sprites/levels/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/levels/1.png -------------------------------------------------------------------------------- /assets/sprites/levels/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/levels/2.png -------------------------------------------------------------------------------- /assets/sound/music/ingame.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/music/ingame.wav -------------------------------------------------------------------------------- /assets/sound/sfx/laybomb.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/laybomb.wav -------------------------------------------------------------------------------- /assets/sound/music/gameover.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/music/gameover.wav -------------------------------------------------------------------------------- /assets/sound/sfx/explosion.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/explosion.wav -------------------------------------------------------------------------------- /assets/sound/sfx/menuconfirm.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/menuconfirm.wav -------------------------------------------------------------------------------- /assets/sprites/breakabletile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakabletile.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4.png -------------------------------------------------------------------------------- /assets/sprites/player1/up/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/up/1.png -------------------------------------------------------------------------------- /assets/sprites/player1/up/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/up/2.png -------------------------------------------------------------------------------- /assets/sprites/player1/up/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/up/3.png -------------------------------------------------------------------------------- /assets/sprites/player1/up/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/up/4.png -------------------------------------------------------------------------------- /assets/sprites/player2/up/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/up/1.png -------------------------------------------------------------------------------- /assets/sprites/player2/up/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/up/2.png -------------------------------------------------------------------------------- /assets/sprites/player2/up/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/up/3.png -------------------------------------------------------------------------------- /assets/sprites/player3/up/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/up/1.png -------------------------------------------------------------------------------- /assets/sprites/player3/up/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/up/2.png -------------------------------------------------------------------------------- /assets/sprites/player3/up/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/up/3.png -------------------------------------------------------------------------------- /assets/sprites/player4/up/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/up/1.png -------------------------------------------------------------------------------- /assets/sprites/player4/up/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/up/2.png -------------------------------------------------------------------------------- /assets/sprites/player4/up/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/up/3.png -------------------------------------------------------------------------------- /assets/sprites/titlescreen_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/titlescreen_1.png -------------------------------------------------------------------------------- /assets/sprites/titlescreen_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/titlescreen_2.png -------------------------------------------------------------------------------- /assets/sound/music/titlescreen.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/music/titlescreen.wav -------------------------------------------------------------------------------- /assets/sprites/breakingtile/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/1.png -------------------------------------------------------------------------------- /assets/sprites/breakingtile/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/2.png -------------------------------------------------------------------------------- /assets/sprites/breakingtile/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/3.png -------------------------------------------------------------------------------- /assets/sprites/breakingtile/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/4.png -------------------------------------------------------------------------------- /assets/sprites/breakingtile/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/5.png -------------------------------------------------------------------------------- /assets/sprites/breakingtile/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/breakingtile/6.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/up.png -------------------------------------------------------------------------------- /assets/sprites/player1/down/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/down/1.png -------------------------------------------------------------------------------- /assets/sprites/player1/down/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/down/2.png -------------------------------------------------------------------------------- /assets/sprites/player1/down/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/down/3.png -------------------------------------------------------------------------------- /assets/sprites/player1/down/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/down/4.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/1.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/2.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/3.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/4.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/5.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/6.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/7.png -------------------------------------------------------------------------------- /assets/sprites/player1/dying/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/dying/8.png -------------------------------------------------------------------------------- /assets/sprites/player1/left/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/left/1.png -------------------------------------------------------------------------------- /assets/sprites/player1/left/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/left/2.png -------------------------------------------------------------------------------- /assets/sprites/player1/left/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/left/3.png -------------------------------------------------------------------------------- /assets/sprites/player1/left/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/left/4.png -------------------------------------------------------------------------------- /assets/sprites/player1/right/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/right/1.png -------------------------------------------------------------------------------- /assets/sprites/player1/right/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/right/2.png -------------------------------------------------------------------------------- /assets/sprites/player1/right/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/right/3.png -------------------------------------------------------------------------------- /assets/sprites/player1/right/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player1/right/4.png -------------------------------------------------------------------------------- /assets/sprites/player2/down/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/down/1.png -------------------------------------------------------------------------------- /assets/sprites/player2/down/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/down/2.png -------------------------------------------------------------------------------- /assets/sprites/player2/down/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/down/3.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/1.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/2.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/3.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/4.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/5.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/6.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/7.png -------------------------------------------------------------------------------- /assets/sprites/player2/dying/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/dying/8.png -------------------------------------------------------------------------------- /assets/sprites/player2/left/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/left/1.png -------------------------------------------------------------------------------- /assets/sprites/player2/left/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/left/2.png -------------------------------------------------------------------------------- /assets/sprites/player2/left/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/left/3.png -------------------------------------------------------------------------------- /assets/sprites/player2/right/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/right/1.png -------------------------------------------------------------------------------- /assets/sprites/player2/right/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/right/2.png -------------------------------------------------------------------------------- /assets/sprites/player2/right/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player2/right/3.png -------------------------------------------------------------------------------- /assets/sprites/player3/down/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/down/1.png -------------------------------------------------------------------------------- /assets/sprites/player3/down/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/down/2.png -------------------------------------------------------------------------------- /assets/sprites/player3/down/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/down/3.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/1.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/2.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/3.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/4.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/5.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/6.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/7.png -------------------------------------------------------------------------------- /assets/sprites/player3/dying/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/dying/8.png -------------------------------------------------------------------------------- /assets/sprites/player3/left/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/left/1.png -------------------------------------------------------------------------------- /assets/sprites/player3/left/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/left/2.png -------------------------------------------------------------------------------- /assets/sprites/player3/left/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/left/3.png -------------------------------------------------------------------------------- /assets/sprites/player3/right/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/right/1.png -------------------------------------------------------------------------------- /assets/sprites/player3/right/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/right/2.png -------------------------------------------------------------------------------- /assets/sprites/player3/right/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player3/right/3.png -------------------------------------------------------------------------------- /assets/sprites/player4/down/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/down/1.png -------------------------------------------------------------------------------- /assets/sprites/player4/down/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/down/2.png -------------------------------------------------------------------------------- /assets/sprites/player4/down/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/down/3.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/1.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/2.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/3.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/4.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/5.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/6.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/7.png -------------------------------------------------------------------------------- /assets/sprites/player4/dying/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/dying/8.png -------------------------------------------------------------------------------- /assets/sprites/player4/left/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/left/1.png -------------------------------------------------------------------------------- /assets/sprites/player4/left/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/left/2.png -------------------------------------------------------------------------------- /assets/sprites/player4/left/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/left/3.png -------------------------------------------------------------------------------- /assets/sprites/player4/right/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/right/1.png -------------------------------------------------------------------------------- /assets/sprites/player4/right/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/right/2.png -------------------------------------------------------------------------------- /assets/sprites/player4/right/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/player4/right/3.png -------------------------------------------------------------------------------- /assets/sound/music/ingame_lowtime.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/music/ingame_lowtime.wav -------------------------------------------------------------------------------- /assets/sound/music/loadingscreen.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/music/loadingscreen.wav -------------------------------------------------------------------------------- /assets/sound/sfx/respawninvalid.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sound/sfx/respawninvalid.wav -------------------------------------------------------------------------------- /assets/sprites/explosion/1/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/downc/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/downc/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/downc/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/downc/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/downc/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/downc/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/nomirror/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/nomirror/1.png -------------------------------------------------------------------------------- /assets/sprites/explosion/nomirror/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/nomirror/2.png -------------------------------------------------------------------------------- /assets/sprites/explosion/nomirror/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/nomirror/3.png -------------------------------------------------------------------------------- /assets/sprites/explosion/nomirror/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/nomirror/4.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/downsc/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/downsc/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/downsc/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/downsc/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/downsc/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/downsc/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/downsc/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/downsc/up.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/downc/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/downc/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/downc/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/downc/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/downc/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/downc/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/2/downc/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/2/downc/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/downc/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/downc/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/downc/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/downc/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/downc/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/downc/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/3/downc/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/3/downc/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/downc/core.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/downc/core.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/downc/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/downc/down.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/downc/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/downc/left.png -------------------------------------------------------------------------------- /assets/sprites/explosion/4/downc/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/4/downc/right.png -------------------------------------------------------------------------------- /assets/sprites/explosion/1/downsc/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Leystryku/mpbomberman_racket/HEAD/assets/sprites/explosion/1/downsc/right.png -------------------------------------------------------------------------------- /assets/credits.txt: -------------------------------------------------------------------------------- 1 | Die sounds und Tiles sind alle legal von https://opengameart.org/ 2 | Die Explosionen sind selbstgemalt 3 | Die Charaktere sind von NES bomberman abgepauscht/übergemalt etc -------------------------------------------------------------------------------- /bomberman_local.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "bomberman_server.rkt") 6 | (require "bomberman_client.rkt") 7 | (require "game/cl_sound.rkt") 8 | 9 | 10 | ;; [run] calls launch-many-worlds to start the game and stops sound execution when closing 11 | (define (run) 12 | (launch-many-worlds 13 | (and (create-world "1") 14 | (stop-our-sound)) 15 | (and (create-world "2") 16 | (stop-our-sound)) 17 | (and (launch-server) 18 | (stop-our-sound)) 19 | ) 20 | ) 21 | 22 | ;;call run 23 | (run) 24 | -------------------------------------------------------------------------------- /game/sv_disconnect.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | 8 | ;; export 9 | (provide (all-defined-out)) 10 | 11 | 12 | ;; [disconnect-client] is responsible for removing the client when he disconnects from our world 13 | (define (disconnect-client currentWorld client) 14 | (define newWorld (removeClient currentWorld (iworld-name client))) 15 | 16 | (sendToAllClients 17 | newWorld 18 | (append 19 | (list "game_players") 20 | (map playerToList (getClientDatas newWorld)) 21 | ) 22 | ) 23 | ) -------------------------------------------------------------------------------- /game/sv_network_ingame_latejoin.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | (require "sh_config.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [messageIngamePlayerLateJoin] is called whenever someone joins while the game is not in waiting stage and sends the late joiner the gamefield 14 | (define (messageIngamePlayerLateJoin currentWorld connection message) 15 | (sendToClient currentWorld connection 16 | (append 17 | (list "game_start") 18 | (map fieldElementToList (serversideWorld-gameField currentWorld)) 19 | ) 20 | ) 21 | ) -------------------------------------------------------------------------------- /game/sh_tick_breakingtile.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_sound.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_structs.rkt") 8 | (require "sh_collisions.rkt") 9 | (require "sh_helper.rkt") 10 | ;(require "sh_config_snds.rkt") 11 | 12 | ;; export 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [breakingTileTick] checks whether a breakable tile should be removed from the field 17 | (define (breakingTileTick setGameFieldFn currentWorld elements breakingTile breakingTileData) 18 | (if 19 | (> 20 | (current-inexact-milliseconds) 21 | (extraData-breakingTile-vanishWhen breakingTileData) 22 | ) 23 | (removeFieldElement setGameFieldFn currentWorld elements breakingTile) 24 | currentWorld 25 | ) 26 | ) -------------------------------------------------------------------------------- /game/sh_config_snds.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; export 4 | (provide (all-defined-out)) 5 | 6 | 7 | ;; === sound references === 8 | ;; music 9 | (define sndTitlescreen "./assets/sound/music/titlescreen.wav") 10 | (define sndLoadingscreen "./assets/sound/music/loadingscreen.wav") 11 | (define sndIngame "./assets/sound/music/ingame.wav") 12 | (define sndGameOver "./assets/sound/music/gameover.wav") 13 | 14 | ;; sfx 15 | (define sndDie "./assets/sound/sfx/die.wav") 16 | (define sndExplosion "./assets/sound/sfx/explosion.wav") 17 | (define sndLayBomb "./assets/sound/sfx/laybomb.wav") 18 | (define sndMenuConfirm "./assets/sound/sfx/menuconfirm.wav") 19 | (define sndRespawnInvalid "./assets/sound/sfx/respawninvalid.wav") 20 | (define sndSpawn "./assets/sound/sfx/spawn.wav") 21 | (define sndWalk "./assets/sound/sfx/walk.wav") -------------------------------------------------------------------------------- /game/sv_network_ingame_respawn.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | (require "sh_config.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [messageIngamePlayerSpawn] calls the functions to for respawning a player has respawned, if he has not enough lives just saves the world 14 | (define (messageIngamePlayerRespawn currentWorld connection message) 15 | (define canRespawnWhen (+ (current-inexact-milliseconds) (random bombMinimumExplodeDelay bombMaximumExplodeDelay))) 16 | (define player (getClientData (getClientByConnection currentWorld connection))) 17 | 18 | (if (> (player-lives player) 0) 19 | (doPlayerSpawn currentWorld player (iworld-name connection)) 20 | (saveWorldState currentWorld) 21 | ) 22 | ) -------------------------------------------------------------------------------- /game/sv_network_ingame.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sv_network_ingame_bomb.rkt") 7 | (require "sv_network_ingame_move.rkt") 8 | (require "sv_network_ingame_respawn.rkt") 9 | (require "sv_network_ingame_latejoin.rkt") 10 | 11 | (require "sh_structs.rkt") 12 | (require "sh_config.rkt") 13 | 14 | ;; export 15 | (provide (all-defined-out)) 16 | 17 | 18 | ;; [messageIngame] calls the right ingame networking function for the current messagetype 19 | (define (messageIngame currentWorld client msg) 20 | (define msgHeader (car msg)) 21 | 22 | (case msgHeader 23 | [("movedto") (messageIngamePlayerMovedTo currentWorld client (cdr msg))] 24 | [("bomb") (messageIngamePlayerLayedBomb currentWorld client (cdr msg))] 25 | [("respawn") (messageIngamePlayerRespawn currentWorld client (cdr msg))] 26 | [("imready") (messageIngamePlayerLateJoin currentWorld client (cdr msg))] 27 | 28 | [else (saveWorldState currentWorld)] 29 | ) 30 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Leystryku 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /game/cl_render_titlescreen.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/image) 5 | (require lang/posn) 6 | (require "cl_helper.rkt") 7 | (require "sh_config.rkt") 8 | (require "sh_helper.rkt") 9 | (require "sh_structs.rkt") 10 | (require "sh_config_textures.rkt") 11 | 12 | ;; exports 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [getCurTitlescreenTxt] Returns the current texture for the titlescreen 17 | (define (getCurTitlescreenTxt tickcount div mod) 18 | (if (> div (modulo tickcount mod)) 19 | txtTitlescreen1 20 | txtTitlescreen2 21 | ) 22 | ) 23 | 24 | 25 | ;; [renderTitlescreen] Renders the titlescreen 26 | (define (renderTitlescreen currentWorld curtxt textx) 27 | (place-images/align 28 | (list 29 | (text curtxt 24 "white") 30 | ) 31 | (list 32 | (make-posn 33 | textx 34 | (interpTwo 35 | (* gameHeight 0.65) 36 | (* gameHeight 0.79) 37 | (/ (modulo (clientsideWorld-tickCount currentWorld) 100 ) 50) 38 | ) 39 | ) 40 | ) 41 | "left" "top" 42 | (getCurTitlescreenTxt (clientsideWorld-tickCount currentWorld) 20 40) 43 | ) 44 | ) -------------------------------------------------------------------------------- /game/cl_collisions.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_helper.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_helper.rkt") 8 | (require "sh_collisions.rkt") 9 | (require "sh_structs.rkt") 10 | 11 | ;; exports 12 | (provide (all-defined-out)) 13 | 14 | 15 | ;; [isValidDesiredPosEnts] checks whether a rectangle drawn at (x, y, x+objw, y+obh) intersects with any other collision rectangle on the field 16 | (define (isValidDesiredPosEnts currentWorld x y objw objh) 17 | (define elements (clientsideWorld-gameField currentWorld)) 18 | 19 | (isValidDesiredPosEntsR elements x y objw objh (clientsideWorld-user currentWorld) #f) 20 | ) 21 | 22 | ;; [isValidDesiredPosMove] checks whether a rectangle drawn at (x, y, x+objw, y+obh) intersects with any other collision rectangle on the field or belonging to a player 23 | (define (isValidDesiredPosMove currentWorld x y playerw playerh user) 24 | (and 25 | (isValidDesiredPosEnts currentWorld x y playerw playerh) 26 | (isValidDesiredPosPlyR (getOtherPlayers currentWorld user) x y playerw playerh) 27 | ) 28 | ) 29 | 30 | (define (isValidDesiredPosMoveLst currentWorld lst playerw playerh user) 31 | (isValidDesiredPosMove currentWorld (first lst) (second lst) playerw playerh user) 32 | ) 33 | -------------------------------------------------------------------------------- /game/sv_network_ingame_move.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | (require "sh_config.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [processPlayerMoved] updates the players x,y,facingDir and facingSince on the server 14 | (define (processPlayerMoved currentWorld connection newDirPos) 15 | (let ([clientData (getClientData (getClientByConnection currentWorld connection))]) 16 | (and 17 | (set-player-x! clientData (first (first newDirPos))) 18 | (set-player-y! clientData (second (first newDirPos))) 19 | (set-player-facingDir! clientData (third newDirPos)) 20 | (set-player-facingSince! clientData (current-inexact-milliseconds)) 21 | 22 | currentWorld 23 | ) 24 | ) 25 | ) 26 | 27 | ;; [messageIngamePlayerMovedTo] calls the functions to process a client has moved and the funcs to send it to all clients 28 | (define (messageIngamePlayerMovedTo currentWorld connection newDirPos) 29 | (define clientDatas (getClientDatas currentWorld)) 30 | 31 | (sendToAllClients 32 | (processPlayerMoved currentWorld connection newDirPos) 33 | (append 34 | (list "player_move" (iworld-name connection)) 35 | newDirPos 36 | ) 37 | ) 38 | ) -------------------------------------------------------------------------------- /game/sv_connect.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | (require "sh_config.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [connect-client-newuser] is responsible for establishing a conenction with a new user 14 | (define (connect-client-newuser currentWorld client) 15 | (let* ([newPlayer (generatePlayer (iworld-name client) gamePlayerSpeed)] 16 | [newWorld (addClient currentWorld (clientData newPlayer client))] 17 | [clientDatas (getClientDatas newWorld)]) 18 | 19 | (sendToAllClients 20 | newWorld 21 | (append 22 | (list "game_players") 23 | (map playerToList clientDatas) 24 | ) 25 | ) 26 | ) 27 | ) 28 | 29 | ;; [connect-client-newuser] is responsible for establishing a conenction with a reconnecting 30 | (define (connect-client-reuseduser currentWorld client user) 31 | (connect-client-newuser 32 | (removeClientFromClientList currentWorld user) 33 | client 34 | ) 35 | ) 36 | 37 | ;; [connect-client] is responsible for calling the right funcs for old/new users 38 | (define (connect-client currentWorld client) 39 | (define user (iworld-name client)) 40 | 41 | (if (getClientByUser currentWorld user) 42 | (connect-client-reuseduser currentWorld client user) 43 | (connect-client-newuser currentWorld client) 44 | ) 45 | ) -------------------------------------------------------------------------------- /bomberman_server.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "game/sv_network_waiting.rkt") 6 | (require "game/sv_network_ingame.rkt") 7 | (require "game/sv_connect.rkt") 8 | (require "game/sv_disconnect.rkt") 9 | (require "game/sh_structs.rkt") 10 | (require "game/sv_tick.rkt") 11 | (require "game/sh_config.rkt") 12 | 13 | ;; exports 14 | (provide launch-server) 15 | 16 | ;; [message] is called whenever we receive a message f rom a client 17 | (define (message currentWorld connection msg) 18 | (if (worldWaitingForPlayers currentWorld) 19 | (messageWaiting currentWorld connection msg) 20 | (messageIngame currentWorld connection msg) 21 | ) 22 | ) 23 | 24 | 25 | 26 | ;;[launch-server] calls universe to create the server 27 | (define (launch-server) 28 | (universe (serversideWorld '() #t (+ (current-seconds) (* 60 5)) "" '() '() 0) 29 | (on-new connect-client) 30 | (on-disconnect disconnect-client) 31 | (on-msg message) 32 | (on-tick gameTick (/ 1 gameServerFPS)) 33 | ) 34 | ) 35 | 36 | ;;[launch-server] calls universe to create the server with port 37 | (define (launch-server-withport ourport) 38 | (universe (serversideWorld '() #t (+ (current-seconds) (* 60 5)) "" '() '() 0) 39 | (on-new connect-client) 40 | (on-disconnect disconnect-client) 41 | (on-msg message) 42 | (port ourport) 43 | (on-tick gameTick (/ 1 gameServerFPS)) 44 | ) 45 | ) 46 | 47 | (define (launch-server-cmdline) 48 | (define cmdline (current-command-line-arguments)) 49 | 50 | (if (vector-empty? cmdline) 51 | (and 52 | (println "Launching server for local playing") 53 | (launch-server) 54 | ) 55 | (and 56 | (println "Launching server with port") 57 | (println (vector-ref cmdline 0)) 58 | (launch-server-withport (string->number (vector-ref cmdline 0))) 59 | ) 60 | ) 61 | ) 62 | 63 | ;(launch-server-cmdline) 64 | 65 | ;(launch-server-withport 27015) -------------------------------------------------------------------------------- /game/cl_sound.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require (only-in racket/gui/base play-sound)) 5 | (require ffi/unsafe) 6 | (require "sh_config.rkt") 7 | (require "sh_config_snds.rkt") 8 | 9 | ;; exports 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [sound-fn] calls the proper sound functions for the OS using rackets foreign function interface 14 | (define (sound-fn str) 15 | (cond 16 | [(equal? soundEnabled 1) 17 | (lambda (x) (define mci-send-string 18 | (get-ffi-obj "mciSendStringA" "Winmm" 19 | (_fun _string [_pointer = #f] [_int = 0] [_pointer = #f] 20 | -> [ret : _int])) 21 | ) 22 | (mci-send-string str))(str) 23 | ] 24 | [(equal? soundEnabled 2) 25 | (lambda (x) (define mci-send-string 26 | (get-ffi-obj "mciSendStringA" "Winmm" 27 | (_fun _string [_pointer = #f] [_int = 0] [_pointer = #f] 28 | -> [ret : _int])) 29 | ) 30 | (mci-send-string str))(str) 31 | ] 32 | [else str] 33 | ) 34 | ) 35 | 36 | ;; [windows-play-sound] is a wrapper around sound-fn for playing sounds using the windows sound cmd 37 | (define (windows-play-sound snd) 38 | (if soundEnabled 39 | (sound-fn (string-append (string-append "play " snd))) 40 | (windows-stop-sound snd) 41 | ) 42 | ) 43 | 44 | ;; [windows-stop-sound] is a wrapper around sound-fn for stopping sounds using the windows sound cmd 45 | (define (windows-stop-sound snd) 46 | (sound-fn (string-append (string-append "stop " snd))) 47 | ) 48 | 49 | ;; [play-our-sound] is a wrapper around the play sound functions for the os's 50 | (define (play-our-sound snd) 51 | (cond 52 | [(equal? soundEnabled 1) (windows-play-sound snd)] 53 | [(equal? soundEnabled -1) (play-sound snd #t)] 54 | [else snd] 55 | ) 56 | ) 57 | 58 | ;; [stop-our-sound] is a wrapper around the sound stop functions for the os's 59 | (define (stop-our-sound) 60 | (cond 61 | [(equal? soundEnabled 1) (windows-stop-sound)] 62 | [else #t] 63 | ) 64 | ) -------------------------------------------------------------------------------- /game/sh_tick.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "sh_tick_explosion.rkt") 6 | (require "sh_tick_bomb.rkt") 7 | (require "sh_tick_breakingtile.rkt") 8 | (require "sh_config.rkt" ) 9 | (require "sh_structs.rkt") 10 | (require "sh_collisions.rkt") 11 | (require "sh_helper.rkt") 12 | 13 | ;; export 14 | (provide (all-defined-out)) 15 | 16 | 17 | ;; [elementTick] calls the fitting tick function for a given element 18 | (define (elementTick setGameFieldFn currentWorld elements players element tickCount isServer) 19 | (define elementName (fieldElement-elementName element)) 20 | 21 | (cond 22 | [(equal? elementName 'bomb) (bombTick setGameFieldFn currentWorld elements players element tickCount (fieldElement-extraData element))] 23 | [(equal? elementName 'explosion) (explosionTick setGameFieldFn currentWorld elements players element tickCount (fieldElement-extraData element) isServer)] 24 | [(equal? elementName 'breakingTile) (breakingTileTick setGameFieldFn currentWorld elements element (fieldElement-extraData element))] 25 | [else currentWorld] 26 | ) 27 | ) 28 | 29 | ;; [doElementTicks] calls the tick function on the given elements 30 | (define (doElementTicks setGameFieldFn currentWorld elements elementsdec players tickCount isServer) 31 | (if (empty? elementsdec) 32 | currentWorld 33 | (doElementTicks 34 | setGameFieldFn 35 | (elementTick 36 | setGameFieldFn 37 | currentWorld 38 | elements 39 | players 40 | (car elementsdec) 41 | tickCount 42 | isServer 43 | ) 44 | elements 45 | (cdr elementsdec) 46 | players 47 | tickCount 48 | isServer 49 | ) 50 | ) 51 | ) 52 | 53 | ;; [doSharedTick] is currently only a wrapper around doElementTicks but more might be added when there's more shared logic 54 | (define (doSharedTick setGameFieldFn currentWorld elements players tickCount isServer) 55 | (doElementTicks setGameFieldFn currentWorld elements elements players tickCount isServer) 56 | ) 57 | -------------------------------------------------------------------------------- /game/sv_network_ingame_bomb.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_structs.rkt") 7 | (require "sh_config.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [processLayerLayedBombParseExtraData] processes the extradata for a bomb 14 | (define (processLayerLayedBombParseExtraData currentWorld connection explodeWhen) 15 | (extraData-bomb 16 | explodeWhen 17 | #t 18 | 0 19 | 1 20 | (iworld-name connection) 21 | ) 22 | ) 23 | 24 | ;; [processLayerLayedBombParseElement] Creates a new bomb fieldElement 25 | (define (processLayerLayedBombParseElement currentWorld connection bombPos explodeWhen) 26 | (fieldElement 27 | 'bomb 28 | (first bombPos) 29 | (second bombPos) 30 | 1 31 | 1 32 | (animatedTextureBomb) 33 | (processLayerLayedBombParseExtraData currentWorld connection explodeWhen) 34 | ) 35 | ) 36 | 37 | ;; [processPlayerLayedBomb] Processes the laying of a bomb and appends it to our current serverside gameField 38 | (define (processPlayerLayedBomb currentWorld connection bombPos explodeWhen) 39 | (define curField (serversideWorld-gameField currentWorld)) 40 | (define newFieldElement (processLayerLayedBombParseElement currentWorld connection bombPos explodeWhen)) 41 | 42 | (and 43 | (set-serversideWorld-gameField! currentWorld 44 | (append curField (list newFieldElement)) 45 | ) 46 | currentWorld 47 | ) 48 | ) 49 | 50 | ;; [messageIngamePlayerLayedBombSend] Sends the laying of a bomb to all clients and calls the functions to process it on the server 51 | (define (messageIngamePlayerLayedBomb currentWorld connection bombPos) 52 | (define clientDatas (getClientDatas currentWorld)) 53 | (define explodeWhen (+ (current-inexact-milliseconds) (random bombMinimumExplodeDelay bombMaximumExplodeDelay))) 54 | 55 | (sendToAllClients 56 | (processPlayerLayedBomb currentWorld connection bombPos explodeWhen) 57 | (append 58 | (list "player_bomb" explodeWhen (iworld-name connection)) 59 | bombPos 60 | ) 61 | ) 62 | ) -------------------------------------------------------------------------------- /bomberman_client.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | 5 | (require 2htdp/universe) 6 | (require 2htdp/image) 7 | (require lang/posn) 8 | (require "game/sh_collisions.rkt") 9 | (require "game/cl_collisions.rkt") 10 | (require "game/sh_config.rkt") 11 | (require "game/cl_render.rkt") 12 | (require "game/cl_input.rkt") 13 | (require "game/cl_network.rkt") 14 | (require "game/cl_tick.rkt") 15 | (require "game/cl_sound.rkt") 16 | (require "game/sh_structs.rkt") 17 | 18 | 19 | ;; export 20 | (provide create-world) 21 | (provide create-world-withipandport) 22 | 23 | ;; short hack, stops all sounds etc. from previous run if game opened in editor 24 | (define (onExit) 25 | (stop-our-sound) 26 | ) 27 | 28 | 29 | ;; big-bang call, creates the client, we use curryr to give the client a copy of his local user 30 | ;; (/ 1 gameFPS) is given to on-tick to set the tickCount to gameFPS 31 | (define (create-world user) 32 | (big-bang (clientsideWorld "titlescreen" 0 0 '() '() '() #f #f #f user 0 "") 33 | (on-receive (curryr onReceive user)) 34 | (to-draw renderHandler gameWidth gameHeight) 35 | (on-key (curryr keyPressed user)) 36 | (on-release (curryr keyReleased user)) 37 | (on-tick gameTick (/ 1 gameFPSTick)) 38 | (name user) 39 | (register LOCALHOST) 40 | ) 41 | ) 42 | 43 | ;;big-bang call but with IP and port 44 | (define (create-world-withipandport user connectip connectport) 45 | (big-bang (clientsideWorld "titlescreen" 0 0 '() '() '() #f #f #f user 0 "") 46 | (on-receive (curryr onReceive user)) 47 | (to-draw renderHandler gameWidth gameHeight) 48 | (on-key (curryr keyPressed user)) 49 | (on-release (curryr keyReleased user)) 50 | (on-tick gameTick (/ 1 gameFPSTick)) 51 | (name user) 52 | (register connectip) 53 | (port connectport) 54 | ) 55 | ) 56 | 57 | 58 | ;; another trick to call onExit once world is killed because user pressed X on the window 59 | (onExit) 60 | 61 | ;(create-world-withipandport "1" "77.1.88.147" 27015) 62 | ;(create-world-withipandport "2" "77.1.88.147" 27015) 63 | ;(create-world-withipandport "3" "77.1.88.147" 27015) 64 | ;(create-world-withipandport "4" "77.1.88.147" 27015) 65 | -------------------------------------------------------------------------------- /bomberman_online.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ; import 4 | (require racket/gui) 5 | (require 2htdp/universe) 6 | (require "bomberman_client.rkt") 7 | (require "game/cl_sound.rkt") 8 | 9 | 10 | 11 | (define ip-adress (void)) 12 | (define port-number (void)) 13 | (define user-name (void)) 14 | 15 | 16 | ;; [run-online] starts the game, connect to the server and stops sound execution when closing 17 | (define (run-online player-number ip-adress port-number) 18 | (and 19 | (create-world-withipandport player-number ip-adress port-number) 20 | (stop-our-sound) 21 | ) 22 | ) 23 | 24 | 25 | 26 | ;; defines the window-container which popups when the client wants to connect with a server 27 | (define toplevel 28 | (new frame% 29 | [label "Verbindung mit Server"] 30 | [width 250] 31 | [height 200] 32 | [style '(no-resize-border)] 33 | [spacing 10] 34 | [border 30] 35 | ) 36 | ) 37 | 38 | ;; Textfields for ip-adress and port placed in the container 39 | (define user-name-text 40 | (new text-field% 41 | [label "Spielernummer [1-4] "] 42 | [horiz-margin 40] 43 | [parent toplevel] 44 | ) 45 | ) 46 | 47 | (define ip-text 48 | (new text-field% 49 | [label "IP-Adresse "] 50 | [horiz-margin 40] 51 | [parent toplevel] 52 | ) 53 | ) 54 | 55 | (define port-text 56 | (new text-field% 57 | [label "Port-Nummer "] 58 | [horiz-margin 40] 59 | [parent toplevel] 60 | ) 61 | ) 62 | 63 | 64 | ;; event-handler-function when submitting by clicking the button 65 | (define (button-callback button event) 66 | (define user (send user-name-text get-value)) 67 | (define ip (send ip-text get-value)) 68 | (define port (string->number (send port-text get-value))) 69 | 70 | (send user-name-text set-value "") 71 | (send ip-text set-value "") 72 | (send port-text set-value "") 73 | (send toplevel show #f) ; hide the window when game starts 74 | (run-online user ip port) ; starts 75 | ) 76 | 77 | ;; The button for submitting the input in the textfields 78 | (new button% 79 | [label "Verbinden"] 80 | [parent toplevel] 81 | [callback button-callback] 82 | ) 83 | 84 | ;; The function that's called for opening the server connect window 85 | (define (server-connect-window) 86 | (send toplevel show #t) 87 | ) 88 | 89 | 90 | (server-connect-window) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multiplayer Bomberman in Racket (LISP dialect) 2 | [![License](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT) 3 | [![Racket Version](https://img.shields.io/badge/racket-v7.8%2Bstable-blue)](https://racket-lang.org) 4 | [![App Version](https://img.shields.io/badge/version-v1.0.0-brightgreen)](https://github.com/Leystryku/mpbomberman_racket) 5 | 6 | ## Showcase 7 | ![ingame](https://github.com/Leystryku/mpbomberman_racket/blob/main/showcase/1.png?raw=true "Ingame") 8 | ![ingame_bomblayed](https://github.com/Leystryku/mpbomberman_racket/blob/main/showcase/2.png?raw=true "Layed a bomb") 9 | ![ingame_bombexplode](https://github.com/Leystryku/mpbomberman_racket/blob/main/showcase/3.png?raw=true "Exploding a bomb") 10 | ![ingame_bombburn](https://github.com/Leystryku/mpbomberman_racket/blob/main/showcase/4.png?raw=true "Bomb burning down some trees") 11 | ![titlescreen](https://github.com/Leystryku/mpbomberman_racket/blob/main/showcase/5.png?raw=true "Titlescreen") 12 | 13 | This is a multiplayer Bomberman created in Racket (LISP dialect, functional programming). 14 | File convention is based on the one used in Garry's Mod (https://github.com/Facepunch/garrysmod) 15 | 16 | The project was created for a University Course. Timespan for entire project: 1 week :) 17 | 18 | ## Getting Started 19 | 20 | ###### Running local shared development instance (Client and Server) 21 | - Just run bomberman_local.rkt 22 | 23 | ###### Running the Server 24 | - Run bomberman_server.rkt 25 | - Then proceed to run (launch-server-withport ThePortYouWant) 26 | 27 | ###### Running the Client 28 | - Run bomberman_client.rkt 29 | - Run (create-world-withipandport "ANumberGoingFrom1To4" "TheServerIp" TheServerPort) 30 | 31 | ###### Testing 32 | - Run bomberman_tests.rkt 33 | 34 | # Credits 35 | - Leystryku (me) 36 | * Collision System 37 | * Movement 38 | * Entity System 39 | * Ents 40 | * The game Engine 41 | * Game Logic 42 | * Bomberman Logic 43 | * Rendering engine 44 | * Animation System 45 | * Networking 46 | * Field Logic 47 | * Game Events 48 | * Cleanups 49 | * Comments (Documentation) 50 | * etc 51 | - Marc: 52 | * Manuals PDF 53 | * Gameover Serverside Logic 54 | * Tests 55 | * Cleanups 56 | * Comments (Documentation) 57 | - Serhat: 58 | * Manuals PDF 59 | * Sound Assets 60 | * Sound System 61 | * Cleanups 62 | * Comments (Documentation) 63 | - Assets: 64 | * Opengameart 65 | - Source Engine 66 | * Inspiration for the events system 67 | - Garry's Mod 68 | * The file convention with the cl_, sh_ sv_ 69 | -------------------------------------------------------------------------------- /game/cl_render.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/image) 5 | (require lang/posn) 6 | (require "cl_helper.rkt") 7 | (require "cl_render_game.rkt") 8 | (require "cl_render_titlescreen.rkt") 9 | (require "sh_config.rkt") 10 | (require "sh_helper.rkt") 11 | (require "sh_structs.rkt") 12 | (require "sh_config_textures.rkt") 13 | 14 | ;; exports 15 | (provide (all-defined-out)) 16 | 17 | ;; [renderHandlerCond] Calls the fitting render function for our current state to render the game 18 | (define (renderHandlerCond currentWorld) 19 | (define curState (clientsideWorld-curState currentWorld)) 20 | (case curState 21 | [("titlescreen") (renderTitlescreen currentWorld "HIT ENTER TO JOIN THE GAME" (* gameWidth 0.30)) ] 22 | [("loadingscreen") (renderTitlescreen currentWorld "LOADING..." (* gameWidth 0.45))] 23 | [("ingame") (renderGame currentWorld) ] 24 | [("gameover") (renderTitlescreen currentWorld (generateWinnersText currentWorld) (* gameWidth 0.30)) ] 25 | [("resetscreen") (renderTitlescreen currentWorld "PLAYERS LEFT, REBOOT GAME" (* gameWidth 0.30)) ] 26 | [else (text (string-append (clientsideWorld-curState currentWorld) "IS NOT A INVALID STATE!") 12 "red")] 27 | ) 28 | ) 29 | 30 | 31 | 32 | ;; [renderHandlerRedraw] Calls the rendlerHanderCond since the frame needs to be redrawn 33 | (define (rendlerHandlerRedraw currentWorld) 34 | (place-images/align 35 | (list 36 | (renderHandlerCond currentWorld) 37 | ) 38 | (list 39 | (make-posn 0 0) 40 | ) 41 | "left" 42 | "top" 43 | (empty-scene gameWidth gameHeight "black") 44 | ) 45 | ) 46 | 47 | ;; [renderHandlerRedrawWithCache] Calls [rendlerHandlerRedraw] and caches the new frame 48 | (define (renderHandlerRedrawWithCache currentWorld) 49 | (define newFrame (rendlerHandlerRedraw currentWorld)) 50 | 51 | (and 52 | (set-clientsideWorld-renderCache! 53 | currentWorld 54 | (list 55 | newFrame 56 | (current-inexact-milliseconds) 57 | ) 58 | ) 59 | newFrame 60 | ) 61 | ) 62 | 63 | ;; [rendlerHandlerShouldRedraw] Checks whether the frame should be redrawn to fit to 60FPS 64 | (define (rendlerHandlerShouldRedraw lastRenderTime) 65 | (if lastRenderTime 66 | (>= (- (current-inexact-milliseconds) lastRenderTime) (/ 1 gameFPSRender)) 67 | #t 68 | ) 69 | ) 70 | 71 | ;; [renderHandler] Calls [renderHandlerRedrawWithCache] with a black canvas as background 72 | (define (renderHandler currentWorld) 73 | (define curCache (clientsideWorld-renderCache currentWorld)) 74 | 75 | (if (rendlerHandlerShouldRedraw (clientsideWorld-renderLastTime currentWorld)) 76 | (renderHandlerRedrawWithCache currentWorld) 77 | curCache 78 | ) 79 | 80 | ) 81 | 82 | -------------------------------------------------------------------------------- /game/sh_tick_bomb.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_sound.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_structs.rkt") 8 | (require "sh_collisions.rkt") 9 | (require "sh_helper.rkt") 10 | ;(require "sh_config_snds.rkt") 11 | 12 | ;; export 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [bombTickJustPlacedDisableIfNeeded] Disables a bombs collision/just placed status if the player has moved out of the bomb 17 | (define (bombTickJustPlacedDisableIfNeeded currentWorld elements players bomb bombData) 18 | (define bombOwner (extraData-bomb-user bombData)) 19 | (define p (getPlayerByUserFromPlayers players bombOwner)) 20 | 21 | (if 22 | (isValidDesiredPosEnt 23 | bomb (player-x p) 24 | (player-y p) 25 | gameTileSize 26 | gameTileSize 27 | (player-user p) 28 | #t 29 | ) 30 | (and 31 | (set-extraData-bomb-justPlaced! bombData #f) 32 | currentWorld 33 | ) 34 | currentWorld 35 | ) 36 | ) 37 | 38 | ;; [bombTickJustPlacedTick] Is called for bombs which have been just placed every tick 39 | (define (bombTickJustPlacedTick currentWorld elements players bomb bombData) 40 | (if (extraData-bomb-justPlaced bombData) 41 | (bombTickJustPlacedDisableIfNeeded currentWorld elements players bomb bombData) 42 | currentWorld 43 | ) 44 | ) 45 | 46 | ;; [bombTickExplode] Turns a bomb into a explosion 47 | (define (bombTickExplode currentWorld elements tickCount bomb bombData) 48 | (and 49 | ;(play-our-sound sndExplosion) 50 | (set-fieldElement-elementName! bomb 'explosion) 51 | (set-fieldElement-animatedTexture! bomb (animatedTextureExplosionCore)) 52 | (set-fieldElement-extraData! bomb 53 | (extraData-explosion 54 | (+ explosionVanishInMs (current-inexact-milliseconds)) 55 | 'core 56 | explosionCoreRange 57 | #f 58 | (+ tickCount explosionTickCountTillNextAnim) 59 | 1 60 | (extraData-bomb-user bombData 61 | ) 62 | ) 63 | ) 64 | currentWorld 65 | ) 66 | ) 67 | 68 | 69 | ;; [bombTickExplodeWhenShould] Checks whether a bomb should explode 70 | (define (bombTickExplodeWhenShould currentWorld elements tickCount bomb bombData) 71 | (if 72 | (> 73 | (current-inexact-milliseconds) 74 | (extraData-bomb-explodeWhen bombData) 75 | ) 76 | (bombTickExplode currentWorld elements tickCount bomb bombData) 77 | currentWorld 78 | ) 79 | ) 80 | 81 | ;; [bombTick] is the tick function for the bomb element and calls the [bombTickExplodeWhenShould] & [bombTickJustPlacedTick] function 82 | (define (bombTick setGameFieldFn currentWorld elements players bomb tickCount bombData) 83 | (bombTickExplodeWhenShould 84 | (bombTickJustPlacedTick 85 | currentWorld 86 | elements 87 | players 88 | bomb 89 | bombData 90 | ) 91 | elements 92 | tickCount 93 | bomb 94 | bombData 95 | ) 96 | ) -------------------------------------------------------------------------------- /bomberman_tests.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | 5 | (require rackunit) 6 | (require 2htdp/image) 7 | (require lang/posn) 8 | (require "bomberman_client.rkt") 9 | (require "game/sh_collisions.rkt") 10 | (require "game/sh_structs.rkt") 11 | (require "game/sh_helper.rkt") 12 | (require "game/cl_helper.rkt") 13 | (require "game/sv_gamefieldgen.rkt") 14 | (require "game/cl_collisions.rkt") 15 | (require "game/sh_config.rkt") 16 | (require "game/sv_connect.rkt") 17 | (require "game/sv_disconnect.rkt") 18 | (require "game/cl_input.rkt") 19 | 20 | 21 | (define ACTIVATE_TESTS #t) 22 | 23 | 24 | ;; ACTIVATE_TESTS active? 25 | (when ACTIVATE_TESTS 26 | 27 | #| ------------------------------------------------------ 28 | ------------- Tests for Logic functions ----------------- 29 | ---------------------------------------------------------|# 30 | 31 | #| --- testable, nontrivial functions in sh_collisions --- |# 32 | 33 | (check-true (isRectangleIntersect 10 10 20 20 29 29 20 20)) 34 | (check-false (isRectangleIntersect 10 10 20 20 31 31 20 20)) 35 | 36 | (check-true (isValidDesiredPosEntsR (list (fieldElement 'unbreakableTile 10 10 20 20 '() '())) 29 29 20 20 "1" #t)) 37 | (check-false (isValidDesiredPosEntsR (list (fieldElement 'unbreakableTile 0 0 1 1 '() '())) 31 31 20 20 "1" #t)) 38 | 39 | 40 | 41 | #| --- testable, nontrivial functions in cl_collisions --- |# 42 | 43 | (define players 44 | (list (player (bitmap/file (string-append "." "/assets/sprites/player1/up/1.png")) 20 20 'down 5 #t #t "1") 45 | (player (bitmap/file (string-append "." "/assets/sprites/player1/left/1.png")) 40 40 'left 5 #t #t "2"))) 46 | 47 | (define currendWorld (clientsideWorld 'ingame 1 10 1 1 fieldLevel1 players (list 'w) #f "1")) 48 | 49 | (check-true (isValidDesiredPosPly currendWorld 100 100 20 20 "1")) 50 | (check-false (isValidDesiredPosPly currendWorld 40 40 20 20 "1")) 51 | 52 | 53 | 54 | #| --- testable, nontrivial functions in sh_helper --- |# 55 | 56 | (check-eqv? (coordToTile 40) 1) 57 | 58 | #| --- testable, nontrivial functions in cl_helper --- |# 59 | 60 | 61 | (check-eqv? (interp 5 8 1) 8) 62 | (check-eqv? (interp 5 8 0) 5) 63 | (check-eqv? (interp 5 8 0.5) 6.5) 64 | 65 | 66 | #| --- testbare, nichttriviale Funktionen in sv_gamefieldgen --- |# 67 | 68 | (check-within (lessAnnoyingRandom 1 3) 2 1) 69 | 70 | 71 | 72 | #| --- testbare, nichttriviale Funktionen in cl_input --- |# 73 | 74 | (define players2 75 | (list (player (bitmap/file (string-append "." "/assets/sprites/player1/up/1.png")) 41 41 'down 5 #t #t "1") 76 | (player (bitmap/file (string-append "." "/assets/sprites/player1/right/2.png")) 100 100 'left 5 #t #t "2"))) 77 | (define currworld2 (clientsideWorld 'ingame 1 10 1 1 fieldLevel1 players2 (list 'w) #f "1")) 78 | 79 | (check-equal? (calculateNewPlayerPosMoveDir currworld2 (car players2) 'right 5 "1") '(46 41)) 80 | 81 | 82 | 83 | #| --- testbare, nichttriviale Funktionen in sv_connect --- |# 84 | 85 | (define curMilli current-inexact-milliseconds) 86 | (check-equal? 87 | (set-player-facingInfo! (generatePlayer "1" 5) (list 'left curMilli)) 88 | (set-player-facingInfo! (player (bitmap/file (string-append "." "/assets/sprites/player1/right/2.png")) 41 41 'left 5 #t #f "1") 89 | (list 'left curMilli) 90 | ) 91 | ) 92 | 93 | 94 | (define currWorld (serversideWorld empty #f 10 "" fieldLevel1 12)) 95 | (addClient currWorld (create-world "1")) 96 | (check-true (= (length (serversideWorld-clients currWorld)) 1)) 97 | ) -------------------------------------------------------------------------------- /game/sh_helper.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require "sh_config.rkt") 5 | (require "sh_structs.rkt") 6 | 7 | ;; export 8 | (provide (all-defined-out)) 9 | 10 | 11 | ;; [coordToTile] converts a coordinate from the rackets coord system to the tile system 12 | (define (coordToTile coord) 13 | (/ coord gameTileSize) 14 | ) 15 | 16 | ;; [divisible?] checks whether a number is divisible by another one 17 | (define (divisible? num by) 18 | (zero? 19 | (remainder num by) 20 | ) 21 | ) 22 | 23 | ;; [isBomb] checks whether a given element is a bomb 24 | (define (isBomb e) 25 | (equal? 26 | (fieldElement-elementName e) 27 | 'bomb 28 | ) 29 | ) 30 | 31 | ;; [getPlayersBombs] gets all bombs belonging to that players 32 | (define (getPlayersBombs currentWorld gameField user) 33 | (define bombs (filter isBomb gameField)) 34 | 35 | (filter 36 | (lambda (x) 37 | (define edata (fieldElement-extraData x)) 38 | 39 | (equal? 40 | (extraData-bomb-user edata) 41 | user 42 | ) 43 | ) 44 | bombs 45 | ) 46 | ) 47 | 48 | ;; [getPlayersBombsAmount] count of how many bombs the player has spawned 49 | (define (getPlayersBombsAmount currentWorld gameField user) 50 | (length 51 | (getPlayersBombs currentWorld gameField user) 52 | ) 53 | ) 54 | 55 | ;; [canPlayerPlaceBombs] checks whether the player can place bombs 56 | (define (canPlayerPlaceBombs currentWorld gameField user) 57 | (> 58 | bombMaximumtAmountPerPlayer 59 | (getPlayersBombsAmount currentWorld gameField user) 60 | ) 61 | ) 62 | 63 | 64 | ;; [getPlayerByUserFromPlayers] gets a player with a given username from the given players 65 | (define (getPlayerByUserFromPlayers players user) 66 | (findf 67 | (lambda (e) 68 | (equal? (player-user e) user) 69 | ) 70 | players 71 | ) 72 | ) 73 | 74 | ;; [getFittingExplosionAnim] takes a spreadType and returns the fitting animation texture belonging to it 75 | (define (getFittingExplosionAnim spreadType) 76 | (cond 77 | [(equal? spreadType 'core) (animatedTextureExplosionCore)] 78 | [(equal? spreadType 'up) (animatedTextureExplosionUp)] 79 | [(equal? spreadType 'down) (animatedTextureExplosionDown)] 80 | [(equal? spreadType 'left) (animatedTextureExplosionLeft)] 81 | [(equal? spreadType 'right) (animatedTextureExplosionRight)] 82 | [else (animatedTextureExplosionCore)] 83 | ) 84 | ) 85 | 86 | ;; [addExplosionField] Creates a explosion on the given field position 87 | (define (addExplosionField setGameFieldFn currentWorld elements tx ty vanishWhen spreadType spreadsLeft ticksWhenNextAnim user) 88 | 89 | (define newField 90 | (append 91 | ((second setGameFieldFn) currentWorld) ;; do NOT replace this with elements. This hack IS required 92 | (list 93 | (fieldElement 94 | 'explosion 95 | tx 96 | ty 97 | 1 98 | 1 99 | (getFittingExplosionAnim spreadType) 100 | (extraData-explosion vanishWhen spreadType spreadsLeft #f ticksWhenNextAnim 1 user) 101 | ) 102 | ) 103 | ) 104 | ) 105 | 106 | (and 107 | ((first setGameFieldFn) currentWorld newField) 108 | currentWorld 109 | ) 110 | ) 111 | 112 | ;; [removeFieldElement] Removes a given fieldElement from the field 113 | (define (removeFieldElement setGameFieldFn currentWorld elements object) 114 | (and 115 | ((first setGameFieldFn) 116 | currentWorld 117 | (remove 118 | object 119 | elements 120 | ) 121 | ) 122 | currentWorld 123 | ) 124 | ) -------------------------------------------------------------------------------- /game/sv_network_waiting.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sv_helper.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_helper.rkt") 8 | (require "sh_collisions.rkt") 9 | (require "sv_gamefieldgen.rkt") 10 | (require "sh_structs.rkt") 11 | 12 | ;; export 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [makeClientReady] stores that a client is ready 17 | (define (makeClientReady client) 18 | (and 19 | (set-clientData-player! 20 | client 21 | (and 22 | (set-player-ready! 23 | (clientData-player client) 24 | #t 25 | ) 26 | (clientData-player client) 27 | ) 28 | ) 29 | client 30 | ) 31 | ) 32 | 33 | ;; [isClientReady] Checks whether a client is ready 34 | (define (isClientReady client) 35 | (player-ready (getClientData client)) 36 | ) 37 | 38 | ;; [countPlayersReady] Gets the amount of players who are ready 39 | (define (countPlayersReady clients) 40 | (count isClientReady clients) 41 | ) 42 | 43 | ;; [enoughPlayersReady] Checks whether enough players are ready based on gameMinimumPlayers 44 | (define (enoughPlayersReady currentWorld) 45 | (define amountPlayersReady (countPlayersReady (serversideWorld-clients currentWorld))) 46 | 47 | (> amountPlayersReady gameMinimumPlayers) 48 | ) 49 | 50 | ;; [storeGameField] Stores the current gameField in our world 51 | (define (storeGameField currentWorld gameField) 52 | (and 53 | (set-serversideWorld-gameField! currentWorld gameField) 54 | currentWorld 55 | ) 56 | ) 57 | 58 | ;; [messageWaitingStartGame] Calls the functions for generating the gamefield, setting the start time, and sends it to all the clients 59 | (define (messageWaitingStartGame currentWorld) 60 | (let* ([clientDatas (getClientDatas currentWorld)] 61 | [gameField (generateGameField currentWorld)] 62 | [storedGameField (storeGameField currentWorld gameField)] 63 | [fieldElementList (map fieldElementToList gameField)] 64 | [gameEndTime ( + (current-seconds) gameTime)] 65 | [gameSetEndTime (set-serversideWorld-endTime! currentWorld gameEndTime)]) 66 | 67 | (sendToAllClients 68 | storedGameField 69 | (append 70 | (list "game_start") 71 | fieldElementList 72 | (list gameEndTime) 73 | ) 74 | ) 75 | ) 76 | ) 77 | 78 | 79 | ;; [messageWaitingPlayerReady] Calls the functions to make a client ready, if enough players are ready calls the functions to make the game start 80 | (define (messageWaitingPlayerReady currentWorld connection) 81 | (and (makeClientReady (getClientByConnection currentWorld connection)) 82 | (let ([newWorldStarted (and (set-serversideWorld-isInWaitingStage! currentWorld #f) currentWorld)]) 83 | 84 | (if (enoughPlayersReady currentWorld) 85 | (messageWaitingStartGame newWorldStarted) 86 | (and 87 | (set-serversideWorld-isInWaitingStage! currentWorld #t) 88 | currentWorld 89 | ) 90 | ) 91 | ) 92 | ) 93 | ) 94 | 95 | ;; [messageWaiting] Is called whenever a client sends a message while we're in the waiting state, calls [messageWaitingPlayerReady] when the msg is imready 96 | (define (messageWaiting currentWorld connection msg) 97 | (if (equal? (car msg) "imready") 98 | (messageWaitingPlayerReady currentWorld connection) 99 | (saveWorldState currentWorld) 100 | ) 101 | ) 102 | 103 | ;; [messageWaiting] Checks whether the world is in the waiting stage 104 | (define (worldWaitingForPlayers currentWorld) 105 | (serversideWorld-isInWaitingStage currentWorld) 106 | ) -------------------------------------------------------------------------------- /game/cl_helper.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/image) 5 | (require "sh_config.rkt") 6 | (require "sh_structs.rkt") 7 | 8 | ;; exports 9 | (provide (all-defined-out)) 10 | 11 | 12 | ;; [interp] makes a number go from the number from to the number to depending on frac (fraction between 0.0, 0% and 1.0, 100%) 13 | (define (interp from to frac) 14 | (cond 15 | [(> frac 1) (to)] 16 | [(< frac 0) (from)] 17 | [else (+ (* (- 1 frac) from ) (* to frac))] 18 | ) 19 | ) 20 | 21 | ;; [interpInverse] makes a number go from the number from to the number to depending on frac (fraction between 0.0, 100% and 1.0, 0%) 22 | (define (interpInverse from to frac) 23 | (interp from to (- 1 frac)) 24 | ) 25 | 26 | ;; [interpTwo] interpolate between two numbers but frac -> 1 means from -> to, frac -> 2 means to -> from 27 | (define (interpTwo numa numb frac) 28 | (if (< frac 1) 29 | (interp numa numb frac) 30 | (interpInverse numb numa (- 2 frac)) 31 | ) 32 | ) 33 | 34 | 35 | ;; [getOtherPlayers] gets a list of {player} structs not belonging to that user 36 | (define (getOtherPlayers currentWorld user) 37 | (define players (clientsideWorld-players currentWorld)) 38 | 39 | (filter 40 | (lambda (e) 41 | (not 42 | (equal? 43 | (player-user e) 44 | user 45 | ) 46 | ) 47 | ) 48 | players 49 | ) 50 | ) 51 | 52 | ;; [getPlayerByUser] gets a {player} struct belonging to that user 53 | (define (getPlayerByUser currentWorld user) 54 | (define players (clientsideWorld-players currentWorld)) 55 | 56 | (findf 57 | (lambda (e) 58 | (equal? 59 | (player-user e) 60 | user 61 | ) 62 | ) 63 | players 64 | ) 65 | ) 66 | 67 | ;; [getLocalPlayer] gets a {player} struct belonging to that user 68 | (define (getLocalPlayer currentWorld) 69 | (getPlayerByUser currentWorld (clientsideWorld-user currentWorld)) 70 | ) 71 | 72 | ;; [getPlayerIndexByUser] gets the index of the {player} struct belonging to that user 73 | (define (getPlayerIndexByUser currentWorld user) 74 | (index-of 75 | (clientsideWorld-players currentWorld) 76 | (getPlayerByUser currentWorld user) 77 | ) 78 | ) 79 | 80 | 81 | ;; [setPlayerPosPlayer] sets a players position in his {player} struct 82 | (define (setPlayerPosPlayer player x y dir) 83 | (and 84 | (set-player-x! player x) 85 | (set-player-y! player y) 86 | (set-player-facingDir! player dir) 87 | (set-player-facingSince! player (current-inexact-milliseconds)) 88 | player 89 | ) 90 | ) 91 | 92 | 93 | ;; [getPlayerPos] gets a players position from his {player} struct 94 | (define (getPlayerPos currentWorld user) 95 | (list 96 | (player-x 97 | (getPlayerByUser currentWorld user) 98 | ) 99 | (player-y 100 | (getPlayerByUser currentWorld user) 101 | ) 102 | ) 103 | ) 104 | 105 | ;; [resetAnimationFrame] resets a animation frame 106 | (define (resetAnimationFrame frame tickCount) 107 | (and 108 | (set-animatedTexture-currentTextureNum! frame 1) 109 | (set-animatedTexture-ticksWhenNextAnim! 110 | frame 111 | (+ 112 | tickCount 113 | (animatedTexture-frameAdvanceTicks frame) 114 | ) 115 | ) 116 | frame 117 | ) 118 | ) 119 | 120 | ;; [resetPlayerAnimationFramesR] resets the players animations all to frame 1 by calling [resetAnimationFrame] for all of them 121 | (define (resetPlayerAnimationFramesR player anims tickCount) 122 | (if (empty? anims) 123 | player 124 | (and 125 | (resetAnimationFrame (car anims) tickCount) 126 | (resetPlayerAnimationFramesR player (cdr anims) tickCount) 127 | ) 128 | ) 129 | ) 130 | 131 | ;; [resetPlayerAnimationFrames] calls [resetPlayerAnimationFramesR] to start the reset anim recursion 132 | (define (resetPlayerAnimationFrames player tickCount) 133 | (define anims (player-animatedTextures player)) 134 | (resetPlayerAnimationFramesR player anims tickCount) 135 | ) 136 | 137 | ;; [generateWinnersText] Generates the text for the current winner 138 | (define (generateWinnersText currentWorld) 139 | (define winningPlayer (clientsideWorld-winner currentWorld)) 140 | (string-append "Winner Player: " (second winningPlayer) " Score: " (number->string (first winningPlayer))) 141 | ) -------------------------------------------------------------------------------- /game/cl_tick.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_sound.rkt") 6 | (require "cl_helper.rkt") 7 | (require "cl_input.rkt") 8 | (require "cl_network.rkt") 9 | (require "sh_config.rkt") 10 | (require "sh_structs.rkt") 11 | (require "sh_collisions.rkt") 12 | (require "sh_tick.rkt") 13 | (require "sh_helper.rkt") 14 | (require "sh_config_snds.rkt") 15 | 16 | ;; exports 17 | (provide (all-defined-out)) 18 | 19 | 20 | ;; [onGameStage] Does the initial setup for when tickCount is 0 (currently just playing the background music) 21 | (define (onGameStage currentStage currentWorld) 22 | (cond 23 | [(equal? currentStage "titlescreen") (and (stop-our-sound) (play-our-sound sndTitlescreen) currentWorld)] 24 | [(equal? currentStage "loadingscreen") (and (stop-our-sound) (play-our-sound sndLoadingscreen) currentWorld)] 25 | [(equal? currentStage "ingame") (and (stop-our-sound) (play-our-sound sndIngame) currentWorld)] 26 | [#t] 27 | ) 28 | ) 29 | 30 | ;; [onGameTickTitlescreen] Logic for titlescreen which should run every tick (just return world rn) 31 | (define (onGameTickTitlescreen currentWorld) 32 | currentWorld 33 | ) 34 | 35 | ;; [onGameTickLoadingscreenGameReady] Logic for loadingscreen which should run when the user wants to start the game and certain amounts of ticks have passed 36 | ;; we do this intentionally so that you don't instantly enter the game and instead watch our epic loadingscreen for some seconds 37 | (define (onGameTickLoadingscreenGameReady currentWorld) 38 | (sendToServer currentWorld "gameready" '("imready")) 39 | ) 40 | 41 | ;; [onGameTickLoadingscreen] Logic for loadingscreen 42 | (define (onGameTickLoadingscreen currentWorld) 43 | (if (equal? (clientsideWorld-tickCount currentWorld) 150) ;we want to ensure the loadingscreen always displays so we send that we want the game to start only after these many ticks 44 | (onGameTickLoadingscreenGameReady currentWorld) 45 | currentWorld 46 | ) 47 | ) 48 | 49 | ;; [onGameTickIngame] Logic for when we're ingame 50 | (define (onGameTickIngame currentWorld tickCount) 51 | (define timeLeft (- (clientsideWorld-endTime currentWorld) (current-seconds))) 52 | (set-clientsideWorld-timeLeft! currentWorld timeLeft) 53 | (if (divisible? tickCount gameSharedTicksEvery) 54 | (doSharedTick (list set-clientsideWorld-gameField! clientsideWorld-gameField) currentWorld (clientsideWorld-gameField currentWorld) (clientsideWorld-players currentWorld) tickCount #f) 55 | currentWorld 56 | ) 57 | ) 58 | 59 | ;; [onGameTick] Logic for when we're ingame 60 | (define (onGameTick currentStage currentWorld tickCount) 61 | (case currentStage 62 | [("titlescreen") (onGameTickTitlescreen currentWorld)] 63 | [("loadingscreen") (onGameTickLoadingscreen currentWorld)] 64 | [("ingame") (onGameTickIngame currentWorld tickCount)] 65 | [("gameover") (onGameTickIngame currentWorld tickCount)] 66 | [else (error 'INVALID_STAGE)] 67 | ) 68 | ) 69 | 70 | ;; [gameTickZero] Logic for when we the tickCount is 0 (happens whenever there's a new stage) 71 | (define (gameTickZero currentStage currentWorld) 72 | (onGameStage currentStage currentWorld) 73 | ) 74 | 75 | ;; [gameTick] Logic for calling all the other functions responsible for handling logic when game running 76 | (define (gameTickRunning currentWorld) 77 | 78 | (define setter (set-clientsideWorld-tickCount! currentWorld (+ (clientsideWorld-tickCount currentWorld) 1))) 79 | (define currentStage (clientsideWorld-curState currentWorld)) 80 | (define tickCount (- (clientsideWorld-tickCount currentWorld) 1)) 81 | (define currentWorldKeyTick (keyTick currentWorld (clientsideWorld-user currentWorld))) 82 | (define forceKeySend (clientsideWorld-forceKeySend currentWorld)) 83 | 84 | (if (or forceKeySend (and currentWorldKeyTick (divisible? tickCount gameMoveTicksEvery))) 85 | (if forceKeySend ; fixes some weird bug where world gets overwritten even though the if should make sure it cant be 86 | (or (and (set-clientsideWorld-forceKeySend! currentWorld #f) currentWorldKeyTick) currentWorld) 87 | (or currentWorldKeyTick currentWorld) 88 | ) 89 | (if (equal? tickCount 0) 90 | (onGameStage currentStage currentWorld) 91 | (onGameTick currentStage currentWorld tickCount) 92 | ) 93 | ) 94 | 95 | ) 96 | 97 | ;; [gameTick] Logic for calling all the other functions responsible for handling logic 98 | (define (gameTick currentWorld) 99 | (if (equal? (clientsideWorld-curState currentWorld) "resetscreen") 100 | currentWorld 101 | (gameTickRunning currentWorld) 102 | ) 103 | ) 104 | -------------------------------------------------------------------------------- /game/sv_gamefieldgen.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require "sh_config.rkt") 5 | (require "sh_collisions.rkt") 6 | (require "sh_helper.rkt") 7 | (require "sh_structs.rkt") 8 | 9 | ;; export 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [getSetTilesInTx] Gets the currently set tiles in a given field X 14 | (define (getSetTilesInTx field tx) 15 | (filter 16 | (lambda (num) 17 | (isTileSetEnts field tx num #t) 18 | ) 19 | (build-list gameFieldHeightTiles values) 20 | ) 21 | ) 22 | 23 | ;; [getNonSetTilesInTx] Gets the currently non-set tiles in a field X 24 | (define (getNonSetTilesInTx field tx) 25 | (filter 26 | (lambda (num) 27 | (not (isTileSetEnts field tx num #t)) 28 | ) 29 | (build-list gameFieldHeightTiles values) 30 | ) 31 | ) 32 | 33 | ;; [countSetTilesInTx] Counts the set tiles in a given field X 34 | (define (countSetTilesInTx field tx) 35 | (count 36 | number? 37 | (getSetTilesInTx field tx) 38 | ) 39 | ) 40 | 41 | ;; [countNonSetTilesInTx] Counts the set tiles in a given field X 42 | (define (countNonSetTilesInTx world tx) 43 | (count 44 | number? 45 | (getNonSetTilesInTx world tx) 46 | ) 47 | ) 48 | 49 | ;; [pickAndRemoveRandomElement] Removes a random element from a given lst 50 | (define (pickAndRemoveRandomElement lst) 51 | (let* ([selectedIndex (random 0 (length lst))] 52 | [selectedElement (list-ref lst selectedIndex)]) 53 | 54 | (list 55 | selectedElement 56 | selectedIndex 57 | (remove selectedElement lst equal?) 58 | ) 59 | ) 60 | ) 61 | 62 | ;; [generateBreakableWallAtPos] Generates a breakable wall at a certain field x/y 63 | (define (generateBreakableWallAtPos xtiles ytiles) 64 | (list 65 | (fieldElement 'breakableTile xtiles ytiles 1 1 #f #f) 66 | ) 67 | ) 68 | 69 | 70 | ;; [generateRandomizedBreakableWallsForTxGen] generates breakable wall at random positions for a given nonSetTiles tx 71 | (define (generateRandomizedBreakableWallsForTxGen field xtiles ytiles cntToSet nonSetTilesInTx) 72 | (if (= cntToSet 0) 73 | '() 74 | (let ([pickRemove (pickAndRemoveRandomElement nonSetTilesInTx)]) 75 | (append 76 | (generateBreakableWallAtPos 77 | xtiles 78 | (car pickRemove) 79 | ) 80 | (generateRandomizedBreakableWallsForTxGen 81 | field 82 | xtiles 83 | ytiles 84 | (- cntToSet 1) 85 | (caddr pickRemove) 86 | ) 87 | ) 88 | ) 89 | ) 90 | ) 91 | 92 | ;; [lessAnnoyingRandom] Is a wrapper around [random] to ensure it'll always return a number 93 | (define (lessAnnoyingRandom rndMin rndMax) 94 | (if (< rndMax rndMin) 95 | rndMax 96 | (random rndMin rndMax) 97 | ) 98 | ) 99 | 100 | ;; [generateRandomizedBreakableWallsForTx] Generates breakable walls for a field X 101 | (define (generateRandomizedBreakableWallsForTx field xtiles ytiles) 102 | (let* ([cntSettableTilesInW (countNonSetTilesInTx field xtiles)] 103 | [rndMin (inexact->exact (ceiling (* cntSettableTilesInW gameMinimumPercentageRandomTiles)))] 104 | [rndMax (inexact->exact (ceiling (* cntSettableTilesInW gameMaximumPercentageRandomTiles)))]) 105 | 106 | (if (> cntSettableTilesInW 0) 107 | (generateRandomizedBreakableWallsForTxGen 108 | field 109 | xtiles 110 | ytiles 111 | (lessAnnoyingRandom 112 | rndMin 113 | rndMax 114 | ) 115 | (getNonSetTilesInTx field xtiles) 116 | ) 117 | '() 118 | ) 119 | ) 120 | ) 121 | 122 | 123 | ;; [generateRandomizedBreakableWalls] Calls the functions to generate breakable walls for a entire field 124 | (define (generateRandomizedBreakableWalls field xtiles ytiles) 125 | (if (equal? xtiles 0) 126 | '() 127 | (append (generateRandomizedBreakableWallsForTx field xtiles ytiles) (generateRandomizedBreakableWalls field (- xtiles 1) ytiles)) 128 | ) 129 | ) 130 | 131 | ;; [generateGameFieldWithRandomWalls] Calls [generateRandomizedBreakableWalls] and appends its result to the current Worlds field 132 | (define (generateGameFieldWithRandomWalls world) 133 | (let* ([randomWalls (generateRandomizedBreakableWalls gameField gameFieldWidthTiles gameFieldHeightTiles)] 134 | [result (append gameField randomWalls)]) 135 | 136 | result 137 | ) 138 | ) 139 | 140 | 141 | ;; [generateGameField] Calls the functions to generate random walls if noRandomWalls is false, else reutrns current field 142 | (define (generateGameField world) 143 | (if noRandomWalls 144 | gameField 145 | (generateGameFieldWithRandomWalls world) 146 | ) 147 | ) -------------------------------------------------------------------------------- /game/sv_tick.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_network.rkt") 6 | (require "sh_config.rkt") 7 | (require "cl_helper.rkt") 8 | (require "cl_sound.rkt") 9 | (require "sh_structs.rkt") 10 | (require "sh_collisions.rkt") 11 | (require "cl_input.rkt") 12 | (require "sh_tick.rkt") 13 | (require "sh_helper.rkt") 14 | (require "sv_helper.rkt") 15 | 16 | ;; exports 17 | (provide (all-defined-out)) 18 | 19 | 20 | ;; [queuePlayerKill] Called whenever a bomb explosion should kill a player. We can not call make package here because bomb spawns in all 4 directions simultaniously so all 4 could kill, thus we use a queue 21 | (define (queuePlayerKill currentWorld playerKilled byUser) 22 | (define currentKillQueue (serversideWorld-killQueue currentWorld)) 23 | (set-serversideWorld-killQueue! 24 | currentWorld 25 | (append 26 | currentKillQueue 27 | (list 28 | (list 29 | playerKilled 30 | byUser 31 | (current-inexact-milliseconds) 32 | ) 33 | ) 34 | ) 35 | ) 36 | ) 37 | 38 | ;; [unqueuePlayerKill] Removes a player from the kill queue 39 | (define (unqueuePlayerKill currentWorld currentKillQueue killQueueElement) 40 | (set-serversideWorld-killQueue! currentWorld 41 | (remove 42 | killQueueElement 43 | currentKillQueue 44 | ) 45 | ) 46 | ) 47 | 48 | 49 | ;; [onGameTickSharedTick] Calls the shared tick function 50 | (define (onGameTickSharedTick currentWorld tickCount) 51 | (doSharedTick 52 | (list 53 | set-serversideWorld-gameField! 54 | serversideWorld-gameField 55 | queuePlayerKill 56 | ) 57 | currentWorld 58 | (serversideWorld-gameField currentWorld) 59 | (getClientDatas currentWorld) 60 | tickCount 61 | #t 62 | ) 63 | ) 64 | 65 | ;; [onGameTickProcessKills] Calls the functions to process queued kills 66 | (define (onGameTickProcessKills currentWorld tickCount) 67 | (define currentKillQueue (serversideWorld-killQueue currentWorld)) 68 | 69 | (if (empty? currentKillQueue) 70 | #f 71 | (onGameTickProcessKill currentWorld currentKillQueue tickCount (car currentKillQueue)) 72 | ) 73 | ) 74 | 75 | 76 | ;; [onGameTickProcessKill] Processes a queued kill 77 | (define (onGameTickProcessKill currentWorld currentKillQueue tickCount killQueueElement) 78 | (and 79 | (unqueuePlayerKill 80 | currentWorld 81 | currentKillQueue 82 | killQueueElement 83 | ) 84 | (doPlayerKill 85 | currentWorld 86 | (first killQueueElement) 87 | (second killQueueElement) 88 | ) 89 | ) 90 | ) 91 | 92 | ;; [resetToWaitingStep1] is the first step in resetting the world 93 | (define (resetToWaitingStep1 currentWorld) 94 | (and 95 | (println 96 | "Not enough players, resetting world" 97 | ) 98 | (set-serversideWorld-tickCount! 99 | currentWorld 100 | -1000 101 | ) 102 | (sendToAllClients 103 | currentWorld 104 | (list "game_reset") 105 | ) 106 | ) 107 | ) 108 | 109 | ;; [resetToWaitingStep2] is seocnd step in resetting the world 110 | (define (resetToWaitingStep2 currentWorld) 111 | (serversideWorld '() #t 0 "" '() '() -50) ;wait a few ticks for network lib to stabilize 112 | ) 113 | 114 | (define (resetToWaiting currentWorld tickCount) 115 | (cond 116 | [(> tickCount 0) 117 | (resetToWaitingStep1 currentWorld) 118 | ] 119 | [(> -100 tickCount) 120 | (and 121 | (resetToWaitingStep2 currentWorld) 122 | ) 123 | ] 124 | [else 125 | currentWorld 126 | ] 127 | ) 128 | ) 129 | 130 | ;; fix for racket bug where universe reset doesnt properly reset universe 131 | (define (resetToWaitingIfShould currentWorld tickCount) 132 | (define clients (serversideWorld-clients currentWorld)) 133 | 134 | (if 135 | (or 136 | (> 0 tickCount) 137 | (and 138 | (= 1 (length clients)) 139 | (not (serversideWorld-isInWaitingStage currentWorld)) 140 | ) 141 | ) 142 | (resetToWaiting currentWorld tickCount) 143 | #f 144 | ) 145 | ) 146 | 147 | ;; [onGameTickEnd] is called to check whether the games time is over or only one guy is left alive 148 | (define (onGameTickGameEnd currentWorld) 149 | (define timeLeft (- (serversideWorld-endTime currentWorld) (current-seconds))) 150 | 151 | (if (>= 0 timeLeft) 152 | (doGameOver currentWorld) 153 | (saveWorldState currentWorld) 154 | ) 155 | ) 156 | 157 | ;; [onGameTick] Logic for the server 158 | (define (onGameTick currentWorld tickCount) 159 | (or 160 | (resetToWaitingIfShould currentWorld tickCount) 161 | (processTickOrder currentWorld tickCount) 162 | ) 163 | ) 164 | 165 | ;; [processTickOrder] Calls the tick functions in the correct order. We have to do this to make sure that only one bundle gets returned 166 | (define (processTickOrder currentWorld tickCount) 167 | (define killsBundle (onGameTickProcessKills (onGameTickSharedTick currentWorld tickCount) tickCount)) 168 | 169 | (if killsBundle 170 | killsBundle 171 | (onGameTickGameEnd currentWorld) 172 | ) 173 | ) 174 | 175 | ;; [gameTick] Logic for when we the tickCount is 0 (happens whenever there's a new stage) 176 | (define (gameTick currentWorld) 177 | (define tickCount (serversideWorld-tickCount currentWorld)) 178 | 179 | (and 180 | (set-serversideWorld-tickCount! 181 | currentWorld 182 | (+ tickCount 1) 183 | ) 184 | (onGameTick currentWorld tickCount) 185 | ) 186 | ) -------------------------------------------------------------------------------- /game/sh_collisions.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "sh_helper.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_structs.rkt") 8 | 9 | ;; exports 10 | (provide (all-defined-out)) 11 | 12 | 13 | ;; [isPointWithin] checks whether a certain point is within the rectangle created by the points ( (x,y), (x+w, y), (x,y+h), (x+w,y+h) ) 14 | (define (isPointWithin x y w h x2 y2) 15 | (and 16 | (>= x2 x) 17 | (>= (+ x w) x2) 18 | (>= y2 y) 19 | (>= (+ y h) y2) 20 | ) 21 | ) 22 | 23 | ;; [isRectangleIntersect] checks whether 2 rectangles intersect by comparing their upper left and bottom right points 24 | (define (isRectangleIntersect x1 y1 w1 h1 x2 y2 w2 h2) 25 | (or 26 | (isPointWithin x1 y1 w1 h1 x2 y2) 27 | (isPointWithin x1 y1 w1 h1 (+ x2 w2) (+ y2 h2)) 28 | (isPointWithin x1 y1 w1 h1 (+ x2 w2) y2) 29 | (isPointWithin x1 y1 w1 h1 x2 (+ y2 h2)) 30 | ) 31 | ) 32 | 33 | ;; [shouldIgnoreElementsCollisionsBomb] checks whether a bomb element should collide with a certain user 34 | (define (shouldIgnoreElementsCollisionsBomb e extra user) 35 | (and 36 | (extraData-bomb-justPlaced extra) 37 | (equal? (extraData-bomb-user extra) user) 38 | ) 39 | ) 40 | 41 | ;; [shouldIgnoreElementsCollisions] checks whether a element should collide with a user 42 | (define (shouldIgnoreElementsCollisions e elemName user forceshouldcollide) 43 | (if forceshouldcollide 44 | #f 45 | (cond 46 | [(equal? elemName 'bomb) (shouldIgnoreElementsCollisionsBomb e (fieldElement-extraData e) user) ] 47 | [(equal? elemName 'explosion) #t ] 48 | [else #f] 49 | ) 50 | ) 51 | ) 52 | 53 | ;; [isValidDesiredPosEnt] checks whether a {fieldElement} collides with the rectangle drawn using objx, objy, objw, objh 54 | (define (isValidDesiredPosEnt curelem objx objy objw objh user forceshouldcollide) 55 | (define elemname (fieldElement-elementName curelem)) 56 | (define elemx (tileToCoord (fieldElement-xtiles curelem))) 57 | (define elemy (tileToCoord (fieldElement-ytiles curelem))) 58 | (define elemw (tileToCoord (fieldElement-wtiles curelem))) 59 | (define elemh (tileToCoord (fieldElement-htiles curelem))) 60 | 61 | 62 | (if (and user gameEntitiesNoCollide) 63 | #t 64 | (if (shouldIgnoreElementsCollisions curelem elemname user forceshouldcollide) 65 | #t 66 | (not 67 | (isRectangleIntersect elemx elemy elemw elemh objx objy (- objw 2) (- objh 2)) 68 | ) 69 | ) 70 | ) 71 | ) 72 | 73 | ;; [isValidDesiredPosEntsR] checks whether any {fieldElement} in given lst collides with the rectangle drawn using objx, objy, objw, objh 74 | (define (isValidDesiredPosEntsR elements objx objy objw objh user forceshouldcollide) 75 | (if (empty? elements) 76 | #t 77 | (if 78 | (not 79 | (isValidDesiredPosEnt 80 | (car elements) 81 | objx 82 | objy 83 | objw 84 | objh 85 | user 86 | forceshouldcollide 87 | ) 88 | ) 89 | #f 90 | (isValidDesiredPosEntsR 91 | (cdr elements) 92 | objx 93 | objy 94 | objw 95 | objh 96 | user 97 | forceshouldcollide 98 | ) 99 | ) 100 | ) 101 | ) 102 | 103 | 104 | 105 | ;; [isValidDesiredPosEntsTileSet] checks whetheer a position on the field is set for the world generation 106 | (define (isValidDesiredPosEntsTileSet field x y objw objh) 107 | (isValidDesiredPosEntsR field (+ x 1) (+ y 1) objw objh #f #f) 108 | ) 109 | 110 | ;; [isTileSetEnts] checks whether a tile on the field is set for the world generation, pos close to spawns are always set 111 | (define (isTileSetEnts field tx ty ignoreSpawn) 112 | (if 113 | (and 114 | ignoreSpawn 115 | (or 116 | (< tx 3) (< ty 1) 117 | (> tx (- gameFieldWidthTiles 4)) 118 | (> ty (- gameFieldHeightTiles 2)) 119 | ) 120 | ) 121 | #t 122 | (not 123 | (isValidDesiredPosEntsTileSet 124 | field 125 | (tileToCoord tx) 126 | (tileToCoord ty) 127 | (- gameTileSize 2) 128 | (- gameTileSize 2) 129 | ) 130 | ) 131 | ) 132 | ) 133 | 134 | 135 | ;; [isValidDesiredPosPly] checks whether a given player intersects with the rectangle created by objx, objy, objw, objh 136 | (define (isValidDesiredPosPly curplayer objx objy objw objh) 137 | (define alive (player-alive curplayer)) 138 | 139 | (if gamePlayersNoCollide 140 | #t 141 | (not 142 | (and 143 | alive 144 | (isRectangleIntersect 145 | (player-x curplayer) 146 | (player-y curplayer) 147 | gameTileSize 148 | gameTileSize 149 | objx 150 | objy 151 | (- objw 1) 152 | (- objh 1) 153 | ) 154 | ) 155 | ) 156 | ) 157 | ) 158 | 159 | ;; [isValidDesiredPosPlyR] checks whether any {player} in given list intersects with the rectangle created by objx, objy, objw, objh 160 | (define (isValidDesiredPosPlyR players objx objy objw objh) 161 | (if (or gamePlayersNoCollide (empty? players)) 162 | #t 163 | (if (not (isValidDesiredPosPly (car players) objx objy objw objh)) 164 | #f 165 | (isValidDesiredPosPlyR (cdr players) objx objy objw objh) 166 | ) 167 | ) 168 | ) 169 | 170 | ;; [canBombSpreadToField] checks whether a bomb can spread to a certain fieldposition 171 | (define (canBombSpreadToField field players tx ty) 172 | (not 173 | (isTileSetEnts field tx ty #f) 174 | ) 175 | ) 176 | 177 | ;; [getEntByFieldPos] gets a {fieldElement} by its tile position 178 | (define (getEntByFieldPos field tx ty) 179 | (if (empty? field) 180 | #f 181 | (let* ([curelem (car field)] 182 | [elemtx (fieldElement-xtiles curelem)] 183 | [elemty (fieldElement-ytiles curelem)]) 184 | 185 | (if 186 | (and 187 | (= elemtx tx) 188 | (= elemty ty) 189 | ) 190 | curelem 191 | (getEntByFieldPos (cdr field) tx ty) 192 | ) 193 | ) 194 | ) 195 | ) 196 | 197 | ;; [getPlayerByFieldPos] gets a {player} by his tile position 198 | (define (getPlayerByFieldPos players tx ty) 199 | (if (empty? players) 200 | #f 201 | (let* ([curplayer (car players)] 202 | [playertx (round (coordToTile (player-x curplayer)))] 203 | [playerty (round (coordToTile (player-y curplayer)))] 204 | [alive (player-alive curplayer)]) 205 | 206 | (if 207 | (and 208 | alive 209 | (= playertx tx) 210 | (= playerty ty) 211 | ) 212 | curplayer 213 | (getPlayerByFieldPos (cdr players) tx ty) 214 | ) 215 | ) 216 | ) 217 | ) -------------------------------------------------------------------------------- /game/sh_structs.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require (for-syntax racket/struct-info)) 5 | 6 | ;; export 7 | (provide (all-defined-out)) 8 | 9 | 10 | ; fieldElements have the following form: '(elementName xtiles ytiles wtiles htiles extraData) 11 | 12 | ;elementName -> 'name des Elementes 13 | ;xtiles -> x in Tile-Coords 14 | ;ytiles -> y in Tile-Coords 15 | ;wtiles -> w in Tile-Cords 16 | ;htiles -> h in Tile-Coords 17 | ;animatedTexture -> If set, then this represents the animated texture of this tile 18 | ;extraData -> Extra data about this fieldElement (for e.g. Bombs) 19 | 20 | (struct fieldElement (elementName xtiles ytiles wtiles htiles animatedTexture extraData) #:mutable #:transparent) 21 | 22 | (define (fieldElementToList e) 23 | (list (fieldElement-elementName e) (fieldElement-xtiles e) (fieldElement-ytiles e) (fieldElement-wtiles e) (fieldElement-htiles e) (fieldElement-animatedTexture e) (fieldElement-extraData e)) 24 | ) 25 | 26 | (define (listTofieldElement lst) 27 | (apply fieldElement lst) 28 | ) 29 | 30 | 31 | 32 | ; animatedTexture has the following form: (ticksWhenNextAnim shouldLoop textures) 33 | 34 | ;ticksWhenNextAnim -> >= this tick Count and next texture will be displayed 35 | ;frameAdvanceTicks -> These many ticks will be added to tickCount to calculate ticksWhenNextAnim 36 | ;currentTextureNum -> The current texture number 37 | ;shouldLoop -> Should the animation loop ? if not, then it will stop playing on the last frame 38 | ;isPaused -> If this is set then will not advance texture 39 | ;name -> When set, the name of the animationTexture 40 | ;textures -> The textures (On Server string, On Client bitmap/file) 41 | 42 | (struct animatedTexture (ticksWhenNextAnim frameAdvanceTicks currentTextureNum shouldLoop isPaused name textures) #:mutable #:transparent) 43 | 44 | 45 | (define (animatedTextureToList e) 46 | (list (animatedTexture-ticksWhenNextAnim e) (animatedTexture-frameAdvanceTicks e) (animatedTexture-currentTextureNum e) (animatedTexture-shouldLoop e) (animatedTexture-isPaused e) (animatedTexture-name e) (animatedTexture-textures e)) 47 | ) 48 | 49 | (define (listToAnimatedTexture lst) 50 | (apply animatedTexture lst) 51 | ) 52 | 53 | 54 | 55 | 56 | 57 | ; players have the following form: (texture x y speed alive ready user) 58 | 59 | ;animatedTextures -> Textures of the player (On Server string, On Client bitmap/file) 60 | ;facingDir -> Info about what dir the player is looking in 61 | ;facingSince -> Since when has he been facing that way 62 | ;x -> X in Pixel-Coords 63 | ;y -> Y in Pixel-Coords 64 | ;speed -> Speed as whole number, player moves these many Pixel-Coords every MovementTick 65 | ;alive -> Is the player alive? 66 | ;ready -> Is the player ready? (Used for the lobby/TitleScreen state, ready means the player wants to join the game) 67 | ;lives -> How many lives does he have left? 68 | ;score -> Whats his current score? 69 | ;user -> The name of the current world/Universe controlling the player 70 | 71 | (struct player (animatedTextures x y facingDir facingSince speed alive ready lives score user) #:mutable #:transparent) 72 | 73 | 74 | (define (playerToList e) 75 | (list (player-animatedTextures e) (player-x e) (player-y e) (player-facingDir e) (player-facingSince e) (player-speed e) (player-alive e) (player-ready e) (player-lives e) (player-score e) (player-user e)) 76 | ) 77 | 78 | (define (listToPlayer lst) 79 | (apply player lst) 80 | ) 81 | 82 | 83 | 84 | 85 | 86 | ; extraData-bomb has the following form: (explodeWhen justPlaced ticksWhenNextAnim numCurrentTexture user) 87 | 88 | 89 | ;explodeWhen -> Time when Bomb will explode in ms, uses (current-inexact-milliseconds) 90 | ;justPlaced -> Whether the bomb was just placed and thus the player is still inside of it 91 | ;ticksWhenNextAnim -> >= this tick Count and next texture will be displayed 92 | ;numCurrentTexture -> which texture should be displayed right now? 93 | ;user -> The name of the owner of the bomb 94 | 95 | (struct extraData-bomb (explodeWhen justPlaced ticksWhenNextAnim numCurrentTexture user) #:mutable #:transparent) 96 | 97 | 98 | (define (extraData-bombToList e) 99 | (list (extraData-bomb-explodeWhen e) (extraData-bomb-justPlaced e) (extraData-bomb-ticksWhenNextAnim e) (extraData-bomb-numCurrentTexture e) (extraData-bomb-user e)) 100 | ) 101 | 102 | (define (listToextraData-bomb lst) 103 | (apply extraData-bomb lst) 104 | ) 105 | 106 | 107 | 108 | 109 | 110 | ; extraData-breakingTile has the following form: (vanishWhen ticksWhenNextAnim numCurrentTexture) 111 | 112 | 113 | ;vanishWhen -> Time when BreakingTile will explode in ms, uses (current-inexact-milliseconds) 114 | ;ticksWhenNextAnim -> >= this tick Count and next texture will be displayed 115 | ;numCurrentTexture -> which texture should be displayed right now? 116 | 117 | (struct extraData-breakingTile (vanishWhen ticksWhenNextAnim numCurrentTexture) #:mutable #:transparent) 118 | 119 | 120 | (define (extraData-breakingTileToList e) 121 | (list (extraData-breakingTile-vanishWhen e) (extraData-breakingTile-ticksWhenNextAnim e) (extraData-breakingTile-numCurrentTexture e)) 122 | ) 123 | 124 | (define (listToextraData-breakingTile lst) 125 | (apply extraData-breakingTile lst) 126 | ) 127 | 128 | 129 | 130 | 131 | 132 | ; extraData-explosion has the following form: (texture x y speed alive ready user) 133 | 134 | 135 | ;vanishWhen -> Time when explosionCore will vanish in ms, uses (current-inexact-milliseconds) 136 | ;spreadType -> Whether this is a core or a spread in a direction 137 | ;spreadsLeft -> Amount of times left to spread 138 | ;didSpread -> Did this part of the explosion spread yet? 139 | ;ticksWhenNextAnim -> >= this tick Count and next texture will be displayed 140 | ;numCurrentTexture -> which texture should be displayed right now? 141 | ;user -> The name of the owner of the explosionCore 142 | 143 | (struct extraData-explosion (vanishWhen spreadType spreadsLeft didSpread ticksWhenNextAnim numCurrentTexture user) #:mutable #:transparent) 144 | 145 | 146 | (define (extraData-explosionToList e) 147 | (list (extraData-explosion-vanishWhen e) (extraData-explosion-spreadType e) (extraData-explosion-spreadsLeft e) (extraData-explosion-didSpread e) (extraData-explosion-ticksWhenNextAnim e) (extraData-explosion-numCurrentTexture e) (extraData-explosion-user e)) 148 | ) 149 | 150 | (define (listToextraData-explosion lst) 151 | (apply extraData-explosion lst) 152 | ) 153 | 154 | 155 | 156 | 157 | 158 | ; clientsideState has the following form: ; struct: '(curState tickCount timeLeft livesLeft currentScore gameField players) 159 | ;curState -> 'current State of the game on the client. Can either be 'titlescreen 'ingame or 'loadingscreen 160 | ;tickCount -> Amount of ticks elapsed since start of the current State. Used for timing animations and logic on the client. 161 | ;timeLeft -> Amount of time left till the current round of the game ends 162 | ;gameField -> The field received from the server for the current game. The unbreakable tiles are also in the field but they are not drawn visually except on showCollisions toggle. 163 | ;players -> List of all the players currently connected to the game/their playerData 164 | ;pressedKeys -> List of all currently non released keys 165 | ;renderCache -> Cache for frame renders 166 | ;renderLastTime -> Last time game was rendered 167 | ;forceKeySend -> Force key tick data to be sent 168 | ;user -> Our username 169 | 170 | (struct clientsideWorld (curState tickCount timeLeft gameField players pressedKeys forceKeySend renderCache renderLastTime user endTime winner) #:mutable #:transparent) 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | ; serversideWorld has the following form: ; struct: '(clients isInWaitingStage timeLeft gameWinner) 179 | 180 | ;clients -> List of all currently connected clients 181 | ;isInWaitingStage -> whether we are currently in the waiting stage (waiting for players to connect and press enter on their titlescreen) 182 | ;timeLeft -> Time left until the current round of the game ends 183 | ;gameWinner -> If set to string len > 0, the name of the world of the user who has won the game. Can also be "timeout" in case everybody lost because of the time out. 184 | ;gameField -> The current game Field 185 | ;killQueue -> The queue of players to be killed 186 | ;tickCount -> The current tick count 187 | 188 | (struct serversideWorld (clients isInWaitingStage endTime gameWinner gameField killQueue tickCount) #:mutable #:transparent) 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | ; clientData has the following form: ; struct: '(player connection isReady) 197 | 198 | ;player -> The player related data of this user 199 | ;connection -> The connection of this user ("iWorld" as racket calls it) 200 | 201 | (struct clientData (player connection) #:mutable #:transparent) -------------------------------------------------------------------------------- /game/sv_helper.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/universe) 5 | (require "sh_config.rkt") 6 | (require "sh_structs.rkt") 7 | 8 | ;; export 9 | (provide (all-defined-out)) 10 | 11 | 12 | ;; [saveWorldState] Saves the current world state 13 | (define (saveWorldState currentWorld) 14 | (make-bundle 15 | currentWorld 16 | '() 17 | '() 18 | ) 19 | ) 20 | 21 | ;; [makeClientsMail] Sends a message to all connections given 22 | (define (makeClientsMail connections msg) 23 | (for/list ([connection connections]) 24 | (make-mail connection msg) 25 | ) 26 | ) 27 | 28 | ;; [getClientConnection] Gets the connection of a client 29 | (define (getClientConnection fullClient) 30 | (clientData-connection fullClient) 31 | ) 32 | 33 | ;; [getClientConnection] Gets the connection of all clients 34 | (define (getClientConnections currentWorld) 35 | (define clients (serversideWorld-clients currentWorld)) 36 | 37 | (for/list ([client clients]) 38 | (getClientConnection client) 39 | ) 40 | ) 41 | 42 | 43 | ;; [getClientData] Gets the client data/player data of a client 44 | (define (getClientData fullClient) 45 | (clientData-player fullClient) 46 | ) 47 | 48 | ;; [getClientDatas] Gets the client data/player data of all clients 49 | (define (getClientDatas currentWorld) 50 | (define clients (serversideWorld-clients currentWorld)) 51 | 52 | (for/list ([client clients]) 53 | (getClientData client) 54 | ) 55 | ) 56 | 57 | ;; [getClientByConnection] Gets a client by his connection 58 | (define (getClientByConnection currentWorld connection) 59 | (define clients (serversideWorld-clients currentWorld)) 60 | 61 | (findf 62 | (lambda (client) 63 | (equal? 64 | (getClientConnection client) 65 | connection 66 | ) 67 | ) 68 | clients 69 | ) 70 | ) 71 | 72 | ;; [getClientIndex] Gets the index of a client 73 | (define (getClientIndex currentWorld client) 74 | (index-of 75 | (serversideWorld-clients currentWorld) 76 | client 77 | ) 78 | ) 79 | 80 | ;; [getClientIndexByConnection] Gets the index of a client based on his connection 81 | (define (getClientIndexByConnection currentWorld connection) 82 | (getClientIndex 83 | currentWorld 84 | (getClientByConnection 85 | currentWorld 86 | connection 87 | ) 88 | ) 89 | ) 90 | 91 | ;; [getConnectionByData] Gets a connection by a clientData 92 | (define (getConnectionByData currentWorld clientData) 93 | (define clients (serversideWorld-clients currentWorld)) 94 | 95 | (findf 96 | (lambda (client) 97 | (and 98 | (equal? 99 | (getClientData client) 100 | clientData 101 | ) 102 | (getClientConnection client) 103 | ) 104 | ) 105 | clients 106 | ) 107 | ) 108 | 109 | ;; [getClientByUser] Gets a client by given username 110 | (define (getClientByUser currentWorld user) 111 | (define clients (serversideWorld-clients currentWorld)) 112 | 113 | (findf 114 | (lambda (client) 115 | (and 116 | (equal? 117 | (player-user (getClientData client)) 118 | (getClientData client) 119 | ) 120 | ) 121 | ) 122 | clients 123 | ) 124 | ) 125 | 126 | ;; [sendToAllClients] Sends a message to all clients using makeClientsMail 127 | (define (sendToAllClients currentWorld msg) 128 | (define clientMails (makeClientsMail (getClientConnections currentWorld) msg)) 129 | 130 | (make-bundle 131 | currentWorld 132 | clientMails 133 | '() 134 | ) 135 | ) 136 | 137 | ;; [sendToClient] Sends a message to one client 138 | (define (sendToClient currentWorld connection msg) 139 | (make-bundle 140 | currentWorld 141 | (list 142 | (make-mail connection msg) 143 | ) 144 | '() 145 | ) 146 | ) 147 | 148 | ;; [addClientToClientList] Adds a client to the client list 149 | (define (addClientToClientList clients client) 150 | (append clients (list client)) 151 | ) 152 | 153 | ;; [addClientToClientList] Adds a client to the current world 154 | (define (addClient currentWorld client) 155 | (define clients (serversideWorld-clients currentWorld)) 156 | 157 | (and 158 | (set-serversideWorld-clients! 159 | currentWorld 160 | (addClientToClientList clients client) 161 | ) 162 | currentWorld 163 | ) 164 | ) 165 | 166 | ;; [addClientToClientList] Removes a client from the client list based on his username 167 | (define (removeClientFromClientList clients stringPlayerNumber) 168 | (filter 169 | (lambda (client) 170 | (not 171 | (equal? 172 | (player-user (clientData-player client)) 173 | stringPlayerNumber 174 | ) 175 | ) 176 | ) 177 | clients 178 | ) 179 | ) 180 | 181 | ;; [removeClient] Removes a client from the world based on his user 182 | (define (removeClient currentWorld stringPlayerNumber) 183 | (define clients (serversideWorld-clients currentWorld)) 184 | 185 | (and 186 | (set-serversideWorld-clients! 187 | currentWorld 188 | (removeClientFromClientList 189 | clients 190 | stringPlayerNumber 191 | ) 192 | ) 193 | currentWorld 194 | ) 195 | ) 196 | 197 | ;; [getSpawnPos] Gets the spawn pos for a client based on his username 198 | (define (getSpawnPos user) 199 | (list-ref 200 | gamePlayerSpawns 201 | (- (string->number user) 1) 202 | ) 203 | ) 204 | 205 | ;; [processPlayerDeath] Processses the death of a player 206 | (define (processPlayerDeath currentWorld playerKilled byUser) 207 | (define newLives (- (player-lives playerKilled) 1)) 208 | 209 | 210 | (and 211 | (set-player-alive! playerKilled #f) 212 | (set-player-lives! playerKilled newLives) 213 | (if 214 | (not 215 | (equal? 216 | (player-user playerKilled) 217 | byUser 218 | ) 219 | ) 220 | (givePlayerScore currentWorld byUser) 221 | currentWorld 222 | ) 223 | ) 224 | ) 225 | 226 | ;; [givePlayerScore] Gives a player one more score point 227 | (define (givePlayerScore currentWorld killer) 228 | (define killingPlayer 229 | (first 230 | (filter 231 | (lambda (x) 232 | (equal? (player-user x) killer) 233 | ) 234 | (getClientDatas currentWorld) 235 | ) 236 | ) 237 | ) 238 | 239 | (and 240 | (set-player-score! 241 | killingPlayer 242 | (add1 (player-score killingPlayer)) 243 | ) 244 | currentWorld 245 | ) 246 | ) 247 | 248 | 249 | ;; [doPlayerKill] Calls the functions for processing a players death and transmits it to all clients 250 | (define (doPlayerKill currentWorld playerKilled byUser) 251 | (sendToAllClients 252 | (processPlayerDeath 253 | currentWorld 254 | playerKilled 255 | byUser 256 | ) 257 | (list 258 | "player_death" 259 | (player-user playerKilled) 260 | byUser 261 | ) 262 | ) 263 | ) 264 | 265 | ;; [processPlayerSpawn] Processes the spawn of a player 266 | (define (processPlayerSpawn currentWorld player spawnPos) 267 | (and 268 | (set-player-x! player (first spawnPos)) 269 | (set-player-y! player (second spawnPos)) 270 | (set-player-alive! player #t) 271 | currentWorld 272 | ) 273 | ) 274 | 275 | ;; [doPlayerSpawn] Calls the functions for processing the spawn of a player and sends it to all clients 276 | (define (doPlayerSpawn currentWorld player user) 277 | (sendToAllClients 278 | (processPlayerSpawn 279 | currentWorld 280 | player 281 | (getSpawnPos user) 282 | ) 283 | (list 284 | "player_spawn" 285 | user 286 | (getSpawnPos user) 287 | 'right 288 | ) 289 | ) 290 | ) 291 | 292 | ;; [generatePlayerStruct] creates a {player} fullfilling the given args 293 | (define (generatePlayerStruct stringTexture pos speed user) 294 | (player 295 | #f 296 | (first pos) 297 | (second pos) 298 | 'right 299 | (current-inexact-milliseconds) 300 | speed 301 | #t 302 | #f 303 | gamePlayerLifes 304 | 0 305 | user 306 | ) 307 | ) 308 | 309 | ;; [generatePlayer] creates a {player} based on his username and speed 310 | (define (generatePlayer user speed) 311 | (case user 312 | [("1") (generatePlayerStruct"/assets/sprites/player1.png" (getSpawnPos user) speed user)] 313 | [("2") (generatePlayerStruct"/assets/sprites/player2.png" (getSpawnPos user) speed user)] 314 | [("3") (generatePlayerStruct"/assets/sprites/player3.png" (getSpawnPos user) speed user)] 315 | [("4") (generatePlayerStruct"/assets/sprites/player4.png" (getSpawnPos user) speed user)] 316 | [else (error 'GAME_MAXPLAYERS_IS_4) ] 317 | ) 318 | ) 319 | 320 | ;; [doGameOver] Sends a gameover to all the clients for timing out 321 | (define (doGameOver currentWorld) 322 | (sendToAllClients 323 | currentWorld 324 | (list 325 | "game_over" 326 | (getWinner currentWorld) 327 | ) 328 | ) 329 | ) 330 | 331 | 332 | ;; [getWinner] Gets the winner of the current game 333 | (define (getWinner currentWorld) 334 | (define sortedGameScores 335 | (reverse 336 | (sort 337 | (map 338 | (lambda (x) 339 | (list 340 | (player-score x) (player-user x) 341 | ) 342 | ) 343 | (getClientDatas currentWorld) 344 | ) 345 | #:key car < 346 | ) 347 | ) 348 | ) 349 | 350 | (if (empty? sortedGameScores) 351 | currentWorld 352 | (if (< 1 (length sortedGameScores)) 353 | (checkForDraw sortedGameScores) 354 | (first sortedGameScores) 355 | ) 356 | ) 357 | ) 358 | 359 | ;; [checkForDraw] Checks whether we're dealing with a draw right now 360 | (define (checkForDraw sortedGameScores) 361 | (let* ([highestScorePair (first sortedGameScores)] 362 | [draw (= (first highestScorePair) (caadr sortedGameScores))]) 363 | 364 | (if draw 365 | (list 366 | (first highestScorePair) 367 | "Draw" 368 | ) 369 | highestScorePair 370 | ) 371 | ) 372 | ) -------------------------------------------------------------------------------- /game/cl_network.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/universe) 5 | (require 2htdp/image) 6 | (require "cl_sound.rkt") 7 | (require "cl_helper.rkt") 8 | (require "sh_structs.rkt") 9 | (require "sh_config.rkt") 10 | (require "sh_config_snds.rkt") 11 | 12 | ;; exports 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [sendToServer] Sends the packet contained in msg to the server, with optional logging of msgtype 17 | (define (sendToServer currentWorld msgtype msg) 18 | (if debugNetwork 19 | (and 20 | (println (string-append "SENDING TO SERVER: " msgtype)) 21 | (make-package currentWorld msg) 22 | ) 23 | (make-package currentWorld msg) 24 | ) 25 | ) 26 | 27 | ;; [onReceiveGameStartParseFieldsParseBreakableTile] Parses a breakable Tile 28 | (define (onReceiveGameStartParseFieldsParseBreakableTile e) 29 | (and 30 | (set-fieldElement-animatedTexture! e (animatedBreakableTile)) 31 | e 32 | ) 33 | ) 34 | 35 | ;; [onReceiveGameStartParseFieldsParseElement] Calls the right parsing function depending on the elementName 36 | (define (onReceiveGameStartParseFieldsParseElement e) 37 | (define elementName (fieldElement-elementName e)) 38 | 39 | (cond 40 | [(equal? elementName 'breakableTile) (onReceiveGameStartParseFieldsParseBreakableTile e)] 41 | [else e] 42 | ) 43 | ) 44 | 45 | ;; [onReceiveGameStartParseField] Calls the right parsing function depending on the elementName 46 | (define (onReceiveGameStartParseField field) 47 | (if (empty? field) 48 | '() 49 | (append 50 | (list 51 | (onReceiveGameStartParseFieldsParseElement (car field)) 52 | ) 53 | (onReceiveGameStartParseField (cdr field)) 54 | ) 55 | ) 56 | ) 57 | 58 | ;; [onReceiveGameReset] Is called when the server tells us to reset our game 59 | (define (onReceiveGameReset currentWorld message user) 60 | 61 | (and 62 | (println "game needs reset") 63 | (clientsideWorld "resetscreen" 0 0 '() '() '() #f #f #f user 0 "") 64 | ) 65 | ) 66 | 67 | ;; [onReceiveGameStart] Sets our current state to ingame and calls the sets our gamefield to the parsed game field from the server 68 | (define (onReceiveGameStart currentWorld message user) 69 | (define fieldElements (filter list? message)) 70 | (define endTime (last message)) 71 | (and 72 | (set-clientsideWorld-curState! currentWorld "ingame") 73 | (set-clientsideWorld-tickCount! currentWorld 0) 74 | (set-clientsideWorld-timeLeft! currentWorld (- endTime (current-seconds))) 75 | (set-clientsideWorld-endTime! currentWorld endTime) 76 | (set-clientsideWorld-gameField! 77 | currentWorld 78 | (onReceiveGameStartParseField 79 | (map listTofieldElement fieldElements) 80 | ) 81 | ) 82 | currentWorld 83 | ) 84 | ) 85 | 86 | (define (onReceiveGameTime currentWorld message user) 87 | (set-clientsideWorld-timeLeft! currentWorld (cadr message)) 88 | currentWorld 89 | ) 90 | 91 | (define (onReceiveGameOver currentWorld message user) 92 | (set-clientsideWorld-curState! currentWorld "gameover") 93 | (set-clientsideWorld-winner! currentWorld (second message)) 94 | currentWorld 95 | ) 96 | 97 | 98 | 99 | ;; [onReceiveGamePlayersParseGetTexture] Gets the right animated player texture depending on the user 100 | (define (onReceiveGamePlayersParseGetTexture user) 101 | (case user 102 | [("1") animatedTexturesPlayer1] 103 | [("2") animatedTexturesPlayer2] 104 | [("3") animatedTexturesPlayer3] 105 | [("4") animatedTexturesPlayer4] 106 | [else (animatedTexturesPlayer1)] 107 | ) 108 | ) 109 | 110 | ;; [onReceiveGamePlayersParse] Parses the player 111 | (define (onReceiveGamePlayersParse players) 112 | (for/list ([player players]) 113 | (define user (player-user player)) 114 | (and 115 | (set-player-animatedTextures! player (onReceiveGamePlayersParseGetTexture user)) 116 | player 117 | ) 118 | ) 119 | ) 120 | 121 | ;; [onReceiveGamePlayers] Sets the current players in our world to the ones received from the server 122 | (define (onReceiveGamePlayers currentWorld message user) 123 | (and 124 | (set-clientsideWorld-players! 125 | currentWorld 126 | (onReceiveGamePlayersParse 127 | (map listToPlayer message) 128 | ) 129 | ) 130 | currentWorld 131 | ) 132 | ) 133 | 134 | ;; [onReceivePlayerSpawnLocalPlayer] handles the stuff we display for when we die 135 | (define (onReceivePlayerSpawnLocalPlayer currentWorld message user player) 136 | (and 137 | (play-our-sound sndSpawn) 138 | currentWorld 139 | ) 140 | ) 141 | 142 | ;; [onReceivePlayerSpawnPlayer] Sets the players state to alive 143 | (define (onReceivePlayerSpawnPlayer currentWorld message user player) 144 | (and 145 | (set-player-alive! player #t) 146 | (set-player-x! player (first (second message))) 147 | (set-player-y! player (second (second message))) 148 | (set-player-facingDir! player (third message)) 149 | (set-player-facingSince! player (current-inexact-milliseconds)) 150 | (if (equal? user (clientsideWorld-user currentWorld)) 151 | (onReceivePlayerSpawnLocalPlayer currentWorld message user player) 152 | currentWorld 153 | ) 154 | ) 155 | ) 156 | 157 | ;; [onReceivePlayerSpawn] Sets the players state to alive and his position to the one sent by the server 158 | (define (onReceivePlayerSpawn currentWorld message user) 159 | (define players (clientsideWorld-players currentWorld)) 160 | 161 | (and 162 | (onReceivePlayerSpawnPlayer currentWorld message user (getPlayerByUser currentWorld (first message))) 163 | currentWorld 164 | ) 165 | ) 166 | 167 | ;; [onReceiveDeathPlayerLocalPlayer] handles the stuff we display for when we die 168 | (define (onReceiveDeathPlayerLocalPlayer currentWorld message user player) 169 | (and 170 | (play-our-sound sndDie) 171 | currentWorld 172 | ) 173 | ) 174 | 175 | ;; [onReceivePlayerDeathPlayerFrag] 176 | (define (onReceivePlayerDeathPlayerFrag currentWorld playerKilled killer) 177 | (if (equal? playerKilled killer) 178 | playerKilled 179 | (and 180 | (set-player-score! killer (+ (player-score killer) 1)) 181 | killer 182 | ) 183 | ) 184 | ) 185 | 186 | ;; [onReceivePlayerDeathPlayer] Sets the players state to death 187 | (define (onReceivePlayerDeathPlayer currentWorld message user player) 188 | (define newPlayerLives (- (player-lives player) 1)) 189 | (define killer (getPlayerByUser currentWorld (second message))) 190 | 191 | (and 192 | (onReceivePlayerDeathPlayerFrag currentWorld player killer) 193 | (set-player-alive! player #f) 194 | (set-player-facingDir! player 'dying) 195 | (set-player-facingSince! player (+ 5000 (current-inexact-milliseconds))) 196 | 197 | (set-player-lives! player newPlayerLives) 198 | ;(resetPlayerAnimationFrames player (clientsideWorld-tickCount currentWorld)) 199 | (if (equal? user (clientsideWorld-user currentWorld)) 200 | (onReceiveDeathPlayerLocalPlayer currentWorld message user player) 201 | currentWorld 202 | ) 203 | ) 204 | ) 205 | 206 | ;; [onReceivePlayerDeath] Calls [onReceivePlayerDeathPlayer] for the player who has died 207 | (define (onReceivePlayerDeath currentWorld message user) 208 | (define players (clientsideWorld-players currentWorld)) 209 | 210 | (and 211 | (onReceivePlayerDeathPlayer currentWorld message user (getPlayerByUser currentWorld (first message))) 212 | currentWorld 213 | ) 214 | ) 215 | 216 | ;; [onReceivePlayerMove] Sets the players position and directory to the one received from the server 217 | (define (onReceivePlayerMove currentWorld message user) 218 | (define player (getPlayerByUser currentWorld (first message))) 219 | 220 | (if (or (not player) (equal? (car message) user)) 221 | currentWorld 222 | (and 223 | (setPlayerPosPlayer 224 | player 225 | (first (second message)) 226 | (second (second message)) 227 | (third message) 228 | ) 229 | currentWorld 230 | ) 231 | ) 232 | ) 233 | 234 | ;; [onReceivePlayerBombParse] Parses the new bomb received from the server 235 | (define (onReceivePlayerBombParseExtraData currentWorld bombMsg user) 236 | (extraData-bomb 237 | (car bombMsg) 238 | #t 239 | (+ 240 | (clientsideWorld-tickCount currentWorld) 241 | bombTickCountTillNextAnim 242 | ) 243 | 1 244 | (cadr bombMsg) 245 | ) 246 | ) 247 | 248 | (define (onReceivePlayerBombParse currentWorld bombMsg user) 249 | (fieldElement 250 | 'bomb 251 | (caddr bombMsg) 252 | (cadddr bombMsg) 253 | 1 254 | 1 255 | (animatedTextureBomb) 256 | (onReceivePlayerBombParseExtraData currentWorld bombMsg user) 257 | ) 258 | ) 259 | 260 | ;; [onReceivePlayerBomb] Adds the new bomb received from the server to our field 261 | (define (onReceivePlayerBomb currentWorld message user) 262 | (define curField (clientsideWorld-gameField currentWorld)) 263 | (define newFieldElement (onReceivePlayerBombParse currentWorld message user)) 264 | 265 | (and 266 | (set-clientsideWorld-gameField! currentWorld 267 | (append curField (list newFieldElement)) 268 | ) 269 | currentWorld 270 | ) 271 | ) 272 | 273 | ;; [onReceiveHandler] Receives a event from the server and calls the fitting handler 274 | (define (onReceiveHandler currentWorld message user) 275 | (define event (car message)) 276 | 277 | (case event 278 | [("game_over") (onReceiveGameOver currentWorld message user)] 279 | [("game_reset") (onReceiveGameReset currentWorld (cdr message) user)] 280 | [("game_start") (onReceiveGameStart currentWorld (cdr message) user)] 281 | [("game_players") (onReceiveGamePlayers currentWorld (cdr message) user)] 282 | [("player_spawn") (onReceivePlayerSpawn currentWorld (cdr message) user)] 283 | [("player_death") (onReceivePlayerDeath currentWorld (cdr message) user)] 284 | [("player_move") (onReceivePlayerMove currentWorld (cdr message) user)] 285 | [("player_bomb") (onReceivePlayerBomb currentWorld (cdr message) user)] 286 | [else currentWorld] 287 | ) 288 | ) 289 | 290 | ;; [onReceiveHandler] Receives a event from the server, with optional logging and calls [onReceiveHandler] 291 | (define (onReceive currentWorld message user) 292 | (if debugNetwork 293 | (and 294 | (println (string-append "RECEIVED FROM SERVER: " (car message))) 295 | (onReceiveHandler currentWorld message user) 296 | ) 297 | (onReceiveHandler currentWorld message user) 298 | ) 299 | ) 300 | -------------------------------------------------------------------------------- /game/sh_tick_explosion.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "cl_sound.rkt") 6 | (require "sh_config.rkt") 7 | (require "sh_structs.rkt") 8 | (require "sh_collisions.rkt") 9 | (require "sh_helper.rkt") 10 | (require "sh_tick_bomb.rkt") 11 | 12 | ;; export 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [explosionTickSpreadExplode] Is responsible for turning breakable tiles into breakingTiles 17 | (define (explosionTickSpreadExplodeBreakableTile currentWorld elements tickCount elemToBreak) 18 | (and 19 | (set-fieldElement-elementName! elemToBreak 'breakingTile) 20 | (set-fieldElement-animatedTexture! elemToBreak (animatedTextureBreakingTile)) 21 | (set-fieldElement-extraData! 22 | elemToBreak 23 | (extraData-breakingTile 24 | (+ breakingTileVanishInMs (current-inexact-milliseconds)) 25 | (+ tickCount breakingTileTickCountTillNextAnim) 26 | 1 27 | ) 28 | ) 29 | currentWorld 30 | ) 31 | ) 32 | 33 | ;; [explosionTickSpreadExplodeBomb] Is responsible for exploding other bombs 34 | (define (explosionTickSpreadExplodeBomb currentWorld elements tickCount elemToBreak) 35 | (if gameBombsCanExplodeEachOther 36 | (and 37 | (bombTickExplode 38 | currentWorld 39 | elements 40 | tickCount 41 | elemToBreak 42 | (fieldElement-extraData elemToBreak) 43 | ) 44 | currentWorld 45 | ) 46 | currentWorld 47 | ) 48 | ) 49 | 50 | ;; [explosionTickSpreadExplode] Calls the right function to explode a given tile 51 | (define (explosionTickSpreadExplode setGameFieldFn currentWorld elements tickCount elemToBreak) 52 | (if elemToBreak 53 | (cond 54 | [(equal? (fieldElement-elementName elemToBreak) 'breakableTile) 55 | (explosionTickSpreadExplodeBreakableTile 56 | currentWorld 57 | elements 58 | tickCount 59 | elemToBreak 60 | ) 61 | ] 62 | [(equal? (fieldElement-elementName elemToBreak) 'bomb) 63 | (explosionTickSpreadExplodeBomb 64 | currentWorld 65 | elements 66 | tickCount 67 | elemToBreak 68 | ) 69 | ] 70 | [else currentWorld] 71 | ) 72 | currentWorld 73 | ) 74 | ) 75 | 76 | ;; [explosionTickSpreadExplodeIfCan] Calls the right function to explode a given tile 77 | (define (explosionTickSpreadExplodeIfcan setGameFieldFn currentWorld elements tickCount spreadX spreadY) 78 | (define elemToBreak (getEntByFieldPos elements spreadX spreadY)) 79 | 80 | (and 81 | (explosionTickSpreadExplode 82 | setGameFieldFn 83 | currentWorld 84 | elements 85 | tickCount 86 | elemToBreak 87 | ) 88 | currentWorld 89 | ) 90 | ) 91 | 92 | ;; [explosionTickSpreadPos] Spreads the explosion further in its direction 93 | (define (explosionTickSpreadPos setGameFieldFn currentWorld elements tickCount explosionData spreadX spreadY spreadType) 94 | (define vanishWhen (extraData-explosion-vanishWhen explosionData)) 95 | (define spreadsLeft (extraData-explosion-spreadsLeft explosionData)) 96 | (define ticksWhenNextAnim (+ explosionTickCountTillNextAnim tickCount)) 97 | (define user (extraData-explosion-user explosionData)) 98 | 99 | (addExplosionField 100 | setGameFieldFn 101 | currentWorld 102 | elements 103 | spreadX 104 | spreadY 105 | vanishWhen 106 | spreadType 107 | (- spreadsLeft 1) 108 | ticksWhenNextAnim 109 | user 110 | ) 111 | ) 112 | 113 | ;; [explosionTickSpreadKillPlayer] Calls the functions to kill a player who entered the explosion 114 | (define (explosionTickSpreadKillPlayer setGameFieldFn currentWorld elements tickCount explosionData player isServer) 115 | (define user (extraData-explosion-user explosionData)) 116 | 117 | (if isServer 118 | (and 119 | ((third setGameFieldFn) 120 | currentWorld 121 | player 122 | user 123 | ) 124 | currentWorld 125 | ) 126 | currentWorld 127 | ) 128 | ) 129 | 130 | ;; [explosionTickSpreadPosIfCan] Spreads bomb if possible, otherwise calls functions responsible for handling what we touched (other fields, players) 131 | (define (explosionTickSpreadPosIfCan setGameFieldFn currentWorld elements players tickCount explosionData spreadX spreadY spreadType isServer) 132 | (cond 133 | [(getPlayerByFieldPos players spreadX spreadY) 134 | (explosionTickSpreadKillPlayer 135 | setGameFieldFn 136 | currentWorld 137 | elements 138 | tickCount 139 | explosionData 140 | (getPlayerByFieldPos players spreadX spreadY) 141 | isServer 142 | ) 143 | ] 144 | [(canBombSpreadToField elements players spreadX spreadY) 145 | (explosionTickSpreadPos 146 | setGameFieldFn 147 | currentWorld 148 | elements 149 | tickCount 150 | explosionData 151 | spreadX 152 | spreadY 153 | spreadType 154 | ) 155 | ] 156 | [else 157 | (explosionTickSpreadExplodeIfcan 158 | setGameFieldFn 159 | currentWorld 160 | elements 161 | tickCount 162 | spreadX 163 | spreadY 164 | ) 165 | ] 166 | ) 167 | ) 168 | 169 | ;; [explosionTickSpreadDir] Makes the explosion store that this part spread and calls functions for spreading with position instead of dir 170 | (define (explosionTickSpreadDir setGameFieldFn currentWorld elements players explosion tickCount explosionData dir isServer) 171 | (define currentX (fieldElement-xtiles explosion)) 172 | (define currentY (fieldElement-ytiles explosion)) 173 | 174 | (set-extraData-explosion-didSpread! explosionData #t) 175 | (cond 176 | [(equal? dir 'up) 177 | (explosionTickSpreadPosIfCan 178 | setGameFieldFn 179 | currentWorld 180 | elements 181 | players 182 | tickCount 183 | explosionData 184 | currentX 185 | (- currentY 1) 186 | dir 187 | isServer 188 | ) 189 | ] 190 | [(equal? dir 'down) 191 | (explosionTickSpreadPosIfCan 192 | setGameFieldFn 193 | currentWorld 194 | elements 195 | players 196 | tickCount 197 | explosionData 198 | currentX 199 | (+ currentY 1) 200 | dir 201 | isServer 202 | ) 203 | ] 204 | [(equal? dir 'left) 205 | (explosionTickSpreadPosIfCan 206 | setGameFieldFn 207 | currentWorld 208 | elements 209 | players 210 | tickCount 211 | explosionData 212 | (- currentX 1) 213 | currentY 214 | dir 215 | isServer 216 | ) 217 | ] 218 | [(equal? dir 'right) 219 | (explosionTickSpreadPosIfCan 220 | setGameFieldFn 221 | currentWorld 222 | elements 223 | players 224 | tickCount 225 | explosionData 226 | (+ currentX 1) 227 | currentY 228 | dir 229 | isServer 230 | ) 231 | ] 232 | [else 233 | (error 'INVALID_EXPLOSION_SPREAD_DIR) 234 | ] 235 | ) 236 | ) 237 | 238 | ;; [explosionTickSpreadCore] Responsible for making the core spread in all 4 dirs by calling [explosionTickSpreadDir] 4 t imes 239 | (define (explosionTickSpreadCore setGameFieldFn currentWorld elements players explosion tickCount explosionData isServer) 240 | (let* ( 241 | [worldFieldA (explosionTickSpreadDir setGameFieldFn currentWorld elements players explosion tickCount explosionData 'up isServer)] 242 | [worldFieldB (explosionTickSpreadDir setGameFieldFn currentWorld elements players explosion tickCount explosionData 'down isServer)] 243 | [worldFieldC (explosionTickSpreadDir setGameFieldFn currentWorld elements players explosion tickCount explosionData 'left isServer)] 244 | [worldFieldD (explosionTickSpreadDir setGameFieldFn currentWorld elements players explosion tickCount explosionData 'right isServer)] 245 | ) 246 | 247 | worldFieldD 248 | ) 249 | ) 250 | 251 | ;; [explosionTickSpread] Calls the right function for spreading this type of explosion 252 | (define (explosionTickSpread setGameFieldFn currentWorld elements players explosion tickCount explosionData isServer) 253 | (define spreadType (extraData-explosion-spreadType explosionData)) 254 | 255 | (if (equal? spreadType 'core) 256 | (explosionTickSpreadCore 257 | setGameFieldFn 258 | currentWorld 259 | elements 260 | players 261 | explosion 262 | tickCount 263 | explosionData 264 | isServer 265 | ) 266 | (explosionTickSpreadDir 267 | setGameFieldFn 268 | currentWorld 269 | elements 270 | players 271 | explosion 272 | tickCount 273 | explosionData 274 | spreadType 275 | isServer 276 | ) 277 | ) 278 | 279 | ) 280 | 281 | ;; [explosionTickSpreadIfShould] Checks whether the explosion should spread and if yes calls the fn to make it do so 282 | (define (explosionTickSpreadIfShould setGameFieldFn currentWorld elements players explosion tickCount explosionData isServer) 283 | (if (or (extraData-explosion-didSpread explosionData) (= (extraData-explosion-spreadsLeft explosionData) 0)) 284 | currentWorld 285 | (explosionTickSpread 286 | setGameFieldFn 287 | currentWorld 288 | elements 289 | players 290 | explosion 291 | tickCount 292 | explosionData 293 | isServer 294 | ) 295 | ) 296 | ) 297 | 298 | ;; [explosionTickVanishIfShould] Checks whether the explosion should vanish and if yes calls the fn to make it vanish 299 | (define (explosionTickVanishIfShould setGameFieldFn currentWorld elements explosion explosionData) 300 | (if 301 | (> 302 | (current-inexact-milliseconds) 303 | (extraData-explosion-vanishWhen explosionData) 304 | ) 305 | (removeFieldElement 306 | setGameFieldFn 307 | currentWorld 308 | elements 309 | explosion 310 | ) 311 | currentWorld 312 | ) 313 | ) 314 | 315 | ;; [explosionTick] Calls the functions to make the bomb spread if it should and vanish if it should 316 | (define (explosionTick setGameFieldFn currentWorld elements players explosion tickCount explosionData isServer) 317 | (explosionTickSpreadIfShould 318 | setGameFieldFn 319 | (explosionTickVanishIfShould 320 | setGameFieldFn 321 | currentWorld 322 | elements 323 | explosion 324 | explosionData 325 | ) 326 | elements 327 | players 328 | explosion 329 | tickCount 330 | explosionData 331 | isServer 332 | ) 333 | ) 334 | -------------------------------------------------------------------------------- /game/cl_render_game.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/image) 5 | (require lang/posn) 6 | (require "cl_helper.rkt") 7 | (require "sh_config.rkt") 8 | (require "sh_helper.rkt") 9 | (require "sh_structs.rkt") 10 | (require "sh_config_textures.rkt") 11 | 12 | ;; exports 13 | (provide (all-defined-out)) 14 | 15 | 16 | ;; [renderHandleAnimFrameAdvanceLoop] Advances a animation frame. If at frame end, reset to first frame (loop) 17 | (define (renderHandleAnimFrameAdvanceLoop tickCount anim newTextureNum) 18 | (and 19 | (set-animatedTexture-ticksWhenNextAnim! anim (+ tickCount (animatedTexture-frameAdvanceTicks anim)) ) 20 | (if (> newTextureNum (length (animatedTexture-textures anim))) 21 | (set-animatedTexture-currentTextureNum! anim 1) 22 | (set-animatedTexture-currentTextureNum! anim newTextureNum) 23 | ) 24 | 25 | anim 26 | ) 27 | ) 28 | 29 | ;; [renderHandleAnimFrameAdvanceNoLoop] Advances a animation frame. If at frame end, do not change anything (no loop) 30 | (define (renderHandleAnimFrameAdvanceNoLoop tickCount anim newTextureNum) 31 | (and 32 | (set-animatedTexture-ticksWhenNextAnim! anim (+ tickCount (animatedTexture-frameAdvanceTicks anim)) ) 33 | (if (> newTextureNum (length (animatedTexture-textures anim))) 34 | anim 35 | (set-animatedTexture-currentTextureNum! anim newTextureNum) 36 | ) 37 | ) 38 | ) 39 | 40 | ;; [renderHandleAnimFrameAdvance] Calls the fitting function to advance the animation frame depending on the loop settings and incrments the current textureNumber 41 | (define (renderHandleAnimFrameAdvance tickCount anim) 42 | (let ([newTextureNum (+ 1 (animatedTexture-currentTextureNum anim))]) 43 | (if (animatedTexture-shouldLoop anim) 44 | (renderHandleAnimFrameAdvanceLoop tickCount anim newTextureNum) 45 | (renderHandleAnimFrameAdvanceNoLoop tickCount anim newTextureNum) 46 | ) 47 | ) 48 | ) 49 | 50 | ;; [renderHandleAnimFrameAdvance] Checks if frame should be advanced. If yes, call [renderHandleAnimFrameAdvance] to advance it 51 | (define (renderHandleAnimFrameAdvanceIfShould tickCount anim) 52 | (if (or (animatedTexture-isPaused anim) (> (animatedTexture-ticksWhenNextAnim anim) tickCount)) 53 | anim 54 | (renderHandleAnimFrameAdvance tickCount anim) 55 | ) 56 | ) 57 | 58 | ;; [renderHandleAnimFrame] Renders a frame of a animatedTexture 59 | (define (renderHandleAnimFrame tickCount anim) 60 | (define textures (animatedTexture-textures anim)) 61 | (define currentTextureNum (animatedTexture-currentTextureNum anim)) 62 | 63 | (list-ref textures (- currentTextureNum 1)) 64 | ) 65 | 66 | ;; [renderGameElementG] Renders a game element using [renderHandleAnimFrame] and does the advancement handling by calling [renderHandleAnimFrameAdvanceIfShould] 67 | (define (renderGameElementG tickCount elem anim extraData) 68 | (and 69 | (renderHandleAnimFrameAdvanceIfShould tickCount anim) 70 | (renderHandleAnimFrame tickCount anim) 71 | ) 72 | ) 73 | 74 | ;; [renderGameElement] Calls [renderGameElementG] for valid elements. If a elementName is unknown, draws a error 75 | (define (renderGameElement tickCount elem anim extraData) 76 | (define elementName (fieldElement-elementName elem)) 77 | 78 | (case elementName 79 | ['unbreakableTile (renderGameElementG tickCount elem anim extraData) ] 80 | ['breakableTile (renderGameElementG tickCount elem anim extraData) ] 81 | ['breakingTile (renderGameElementG tickCount elem anim extraData) ] 82 | ['bomb (renderGameElementG tickCount elem anim extraData) ] 83 | ['explosion (renderGameElementG tickCount elem anim extraData) ] 84 | [else (text (string-append (symbol->string elementName) "IS NOT A VALID ELEMENT") 18 "red")] 85 | ) 86 | ) 87 | 88 | ;; [renderGameElementCollisions] Draws collision bounds for 'breakableTile and 'unbreakableTile, for other elements calls [renderGameElement] 89 | (define (renderGameElementCollisions tickCount elem anim extraData) 90 | (cond 91 | [(equal? (fieldElement-elementName elem) 'unbreakableTile) (rectangle (tileToCoord (fieldElement-wtiles elem)) (tileToCoord (fieldElement-ytiles elem)) "solid" "blue") ] 92 | [(equal? (fieldElement-elementName elem) 'breakableTile) (rectangle (tileToCoord (fieldElement-wtiles elem)) (tileToCoord (fieldElement-ytiles elem)) "solid" "white") ] 93 | [else (renderGameElement tickCount elem anim extraData)] 94 | ) 95 | ) 96 | 97 | ;; [renderGameElementsEWithCollisions] Renders game elements with drawing collision bounds 98 | (define (renderGameElementsEWithCollisions tickCount elements) 99 | (for/list ([element elements]) 100 | (renderGameElementCollisions tickCount element (fieldElement-animatedTexture element) (fieldElement-extraData element)) 101 | ) 102 | ) 103 | 104 | ;; [renderGameElementsEWithoutCollisions] Renders game elements without drawing collision bounds 105 | (define (renderGameElementsEWithoutCollisions tickCount elements) 106 | (for/list ([element elements]) 107 | (renderGameElement tickCount element (fieldElement-animatedTexture element) (fieldElement-extraData element)) 108 | ) 109 | ) 110 | 111 | ;; [renderGameElementsE] Calls the right render function depending on whether game should render collisionBounds 112 | (define (renderGameElementsE world tickCount elements) 113 | (if gameRenderCollisionBounds 114 | (renderGameElementsEWithCollisions tickCount elements) 115 | (renderGameElementsEWithoutCollisions tickCount (filter (lambda (elem) (not (equal? (fieldElement-elementName elem) 'unbreakableTile))) elements) ) 116 | ) 117 | ) 118 | 119 | ;; [renderGameElementsP] Calculates the posn for every game Element 120 | (define (renderGameElementsP elements) 121 | (for/list ([element elements]) 122 | (make-posn (tileToCoord (fieldElement-xtiles element)) (tileToCoordY (fieldElement-ytiles element))) 123 | ) 124 | ) 125 | 126 | ;; [renderPlayer] Gets the current active texture of the player, calls funcs to render it and advance if needed 127 | (define (renderPlayer tickCount player) 128 | (let* ( 129 | [facingDir (player-facingDir player)] 130 | [facingSince (player-facingSince player)] 131 | [animtextures (player-animatedTextures player)] 132 | [anim (assoc facingDir animtextures)]) 133 | 134 | (if anim 135 | (if (> (+ 100 facingSince) (current-inexact-milliseconds) ) 136 | (and (renderHandleAnimFrameAdvanceIfShould tickCount (second anim)) (renderHandleAnimFrame tickCount (second anim))) 137 | (renderHandleAnimFrame tickCount (second anim)) 138 | ) 139 | (rectangle 140 | gameTileSize 141 | gameTileSize 142 | "solid" 143 | "grey" 144 | ) 145 | ) 146 | ) 147 | ) 148 | 149 | ;; [renderPlayersE] Renders all the players 150 | (define (renderPlayersE tickCount currentWorld) 151 | (define players (clientsideWorld-players currentWorld)) 152 | 153 | (for/list ([player players]) 154 | (renderPlayer tickCount player) 155 | ) 156 | ) 157 | 158 | ;; [renderPlayersP] Calcuates the posn for every player 159 | (define (renderPlayersP currentWorld) 160 | (define players (clientsideWorld-players currentWorld)) 161 | 162 | (for/list ([player players]) 163 | (make-posn (player-x player) (+ (player-y player) gameScoreHeight)) 164 | ) 165 | ) 166 | 167 | ;; [renderGameScore] Renders our current score 168 | (define (renderGameScore currentWorld localPlayer) 169 | (place-images/align 170 | (list 171 | (text 172 | (string-append " TIME " (string-append (number->string (clientsideWorld-timeLeft currentWorld)) " ") "CURSCORE " (number->string (player-score localPlayer)) " LIVES " (number->string (player-lives localPlayer))) 173 | 24 174 | "white" 175 | ) 176 | ) 177 | (list 178 | (make-posn 0 (* gameScoreHeight 0.4)) 179 | ) 180 | "left" 181 | "top" 182 | (rectangle 183 | gameWidth 184 | gameScoreHeight 185 | "solid" 186 | "grey" 187 | ) 188 | ) 189 | ) 190 | 191 | ;; [renderRespawnText] Renders the respawn text 192 | (define (renderRespawnText currentWorld localPlayer) 193 | (if (player-alive localPlayer) 194 | (text "" 1 "white") 195 | (text "HIT SPACE TO RESPAWN" 18 "red") 196 | ) 197 | ) 198 | 199 | ;; [renderGameOver] Renders gameover 200 | (define (renderGameOver currentWorld localPlayer) 201 | (place-images/align 202 | (list 203 | (text 204 | (string-append " TIME 0 CURSCORE 0 GAME OVER ") 205 | 24 206 | "red" 207 | ) 208 | ) 209 | (list 210 | (make-posn 0 (* gameScoreHeight 0.4)) 211 | ) 212 | "left" 213 | "top" 214 | (rectangle 215 | gameWidth 216 | gameScoreHeight 217 | "solid" 218 | "black" 219 | ) 220 | ) 221 | ) 222 | 223 | 224 | ;; [renderGameR] Renders the HUD 225 | (define (renderHUD currentWorld localPlayer) 226 | 227 | (if (and (not (player-alive localPlayer)) (= 0 (player-lives localPlayer))) 228 | (list 229 | (renderGameOver currentWorld localPlayer) 230 | (text "" 1 "white") 231 | ) 232 | (list 233 | (renderRespawnText currentWorld localPlayer) 234 | (renderGameScore currentWorld localPlayer) 235 | ) 236 | ) 237 | 238 | ) 239 | ;; [renderGameR] Renders the current game 240 | (define (renderGameR currentWorld elements) 241 | (define localPlayer (getLocalPlayer currentWorld)) 242 | 243 | (place-images/align 244 | (append 245 | (renderHUD currentWorld localPlayer) 246 | (renderGameElementsE currentWorld (clientsideWorld-tickCount currentWorld) elements) 247 | (renderPlayersE (clientsideWorld-tickCount currentWorld) currentWorld) 248 | ) 249 | (append 250 | (list (make-posn 0 0) (make-posn 0 0) ) 251 | (renderGameElementsP elements) 252 | (renderPlayersP currentWorld) 253 | ) 254 | "left" 255 | "top" 256 | gameBackgroundTexture 257 | ) 258 | ) 259 | 260 | ;; [renderGame] Calls functions to render the game and if collision bounds should not be drawn, removes 'unbreakableTile from element list (since we don't need to draw them extra) 261 | (define (renderGame currentWorld) 262 | (if gameRenderCollisionBounds 263 | (renderGameR currentWorld (clientsideWorld-gameField currentWorld)) 264 | (renderGameR currentWorld (filter (lambda (elem) (not (equal? (fieldElement-elementName elem) 'unbreakableTile)) ) (clientsideWorld-gameField currentWorld))) 265 | ) 266 | ) -------------------------------------------------------------------------------- /game/sh_config_textures.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | 6 | ;; export 7 | (provide (all-defined-out)) 8 | 9 | 10 | ;;; === configuration for texture paths === 11 | 12 | 13 | ;;titlescreen state 14 | (define txtTitlescreen1 (bitmap/file (string-append "." "/assets/sprites/titlescreen_1.png"))) 15 | (define txtTitlescreen2 (bitmap/file (string-append "." "/assets/sprites/titlescreen_2.png"))) 16 | 17 | ;;titlescreen state 18 | (define txtEndScreen1 (bitmap/file (string-append "." "/assets/sprites/titlescreen_1.png"))) 19 | (define txtEndScreen2 (bitmap/file (string-append "." "/assets/sprites/titlescreen_2.png"))) 20 | 21 | ;;ingame 22 | ;; level bgs 23 | (define txtLevel1 (bitmap/file (string-append "." "/assets/sprites/levels/1.png"))) 24 | (define txtLevel2 (bitmap/file (string-append "." "/assets/sprites/levels/2.png"))) 25 | 26 | ;; breakable tiles 27 | (define txtBreakableTile (bitmap/file (string-append "." "/assets/sprites/breakabletile.png"))) 28 | 29 | ;; bomb 30 | (define txtBomb1 (bitmap/file (string-append "." "/assets/sprites/bomb/1.png"))) 31 | (define txtBomb2 (bitmap/file (string-append "." "/assets/sprites/bomb/2.png"))) 32 | (define txtBomb3 (bitmap/file (string-append "." "/assets/sprites/bomb/3.png"))) 33 | 34 | ;; explosions 35 | ;;; core 36 | (define txtExplosionCore1 (bitmap/file (string-append "." "/assets/sprites/explosion/1/core.png"))) 37 | (define txtExplosionCore2 (bitmap/file (string-append "." "/assets/sprites/explosion/2/core.png"))) 38 | (define txtExplosionCore3 (bitmap/file (string-append "." "/assets/sprites/explosion/3/core.png"))) 39 | (define txtExplosionCore4 (bitmap/file (string-append "." "/assets/sprites/explosion/4/core.png"))) 40 | 41 | ;;; up 42 | (define txtExplosionUp1 (bitmap/file (string-append "." "/assets/sprites/explosion/1/up.png"))) 43 | (define txtExplosionUp2 (bitmap/file (string-append "." "/assets/sprites/explosion/2/up.png"))) 44 | (define txtExplosionUp3 (bitmap/file (string-append "." "/assets/sprites/explosion/3/up.png"))) 45 | (define txtExplosionUp4 (bitmap/file (string-append "." "/assets/sprites/explosion/4/up.png"))) 46 | 47 | ;;; down 48 | (define txtExplosionDown1 (bitmap/file (string-append "." "/assets/sprites/explosion/1/down.png"))) 49 | (define txtExplosionDown2 (bitmap/file (string-append "." "/assets/sprites/explosion/2/down.png"))) 50 | (define txtExplosionDown3 (bitmap/file (string-append "." "/assets/sprites/explosion/3/down.png"))) 51 | (define txtExplosionDown4 (bitmap/file (string-append "." "/assets/sprites/explosion/4/down.png"))) 52 | 53 | ;;; left 54 | (define txtExplosionLeft1 (bitmap/file (string-append "." "/assets/sprites/explosion/1/left.png"))) 55 | (define txtExplosionLeft2 (bitmap/file (string-append "." "/assets/sprites/explosion/2/left.png"))) 56 | (define txtExplosionLeft3 (bitmap/file (string-append "." "/assets/sprites/explosion/3/left.png"))) 57 | (define txtExplosionLeft4 (bitmap/file (string-append "." "/assets/sprites/explosion/4/left.png"))) 58 | 59 | ;;; right 60 | (define txtExplosionRight1 (bitmap/file (string-append "." "/assets/sprites/explosion/1/right.png"))) 61 | (define txtExplosionRight2 (bitmap/file (string-append "." "/assets/sprites/explosion/2/right.png"))) 62 | (define txtExplosionRight3 (bitmap/file (string-append "." "/assets/sprites/explosion/3/right.png"))) 63 | (define txtExplosionRight4 (bitmap/file (string-append "." "/assets/sprites/explosion/4/right.png"))) 64 | 65 | 66 | ;; breaking tiles 67 | (define txtBreakingTile1 (bitmap/file (string-append "." "/assets/sprites/breakingtile/1.png"))) 68 | (define txtBreakingTile2 (bitmap/file (string-append "." "/assets/sprites/breakingtile/2.png"))) 69 | (define txtBreakingTile3 (bitmap/file (string-append "." "/assets/sprites/breakingtile/3.png"))) 70 | (define txtBreakingTile4 (bitmap/file (string-append "." "/assets/sprites/breakingtile/4.png"))) 71 | (define txtBreakingTile5 (bitmap/file (string-append "." "/assets/sprites/breakingtile/5.png"))) 72 | (define txtBreakingTile6 (bitmap/file (string-append "." "/assets/sprites/breakingtile/6.png"))) 73 | 74 | 75 | ;;players 76 | ;;player1 77 | 78 | ;;up 79 | (define txtPlayer1Up1 (bitmap/file (string-append "." "/assets/sprites/player1/up/1.png"))) 80 | (define txtPlayer1Up2 (bitmap/file (string-append "." "/assets/sprites/player1/up/2.png"))) 81 | (define txtPlayer1Up3 (bitmap/file (string-append "." "/assets/sprites/player1/up/3.png"))) 82 | (define txtPlayer1Up4 (bitmap/file (string-append "." "/assets/sprites/player1/up/4.png"))) 83 | 84 | ;;down 85 | (define txtPlayer1Down1 (bitmap/file (string-append "." "/assets/sprites/player1/down/1.png"))) 86 | (define txtPlayer1Down2 (bitmap/file (string-append "." "/assets/sprites/player1/down/2.png"))) 87 | (define txtPlayer1Down3 (bitmap/file (string-append "." "/assets/sprites/player1/down/3.png"))) 88 | (define txtPlayer1Down4 (bitmap/file (string-append "." "/assets/sprites/player1/down/4.png"))) 89 | 90 | ;;left 91 | (define txtPlayer1Left1 (bitmap/file (string-append "." "/assets/sprites/player1/left/1.png"))) 92 | (define txtPlayer1Left2 (bitmap/file (string-append "." "/assets/sprites/player1/left/2.png"))) 93 | (define txtPlayer1Left3 (bitmap/file (string-append "." "/assets/sprites/player1/left/3.png"))) 94 | (define txtPlayer1Left4 (bitmap/file (string-append "." "/assets/sprites/player1/left/4.png"))) 95 | 96 | ;;right 97 | (define txtPlayer1Right1 (bitmap/file (string-append "." "/assets/sprites/player1/right/1.png"))) 98 | (define txtPlayer1Right2 (bitmap/file (string-append "." "/assets/sprites/player1/right/2.png"))) 99 | (define txtPlayer1Right3 (bitmap/file (string-append "." "/assets/sprites/player1/right/3.png"))) 100 | (define txtPlayer1Right4 (bitmap/file (string-append "." "/assets/sprites/player1/right/4.png"))) 101 | 102 | ;;dying 103 | (define txtPlayer1Die1 (bitmap/file (string-append "." "/assets/sprites/player1/dying/1.png"))) 104 | (define txtPlayer1Die2 (bitmap/file (string-append "." "/assets/sprites/player1/dying/2.png"))) 105 | (define txtPlayer1Die3 (bitmap/file (string-append "." "/assets/sprites/player1/dying/3.png"))) 106 | (define txtPlayer1Die4 (bitmap/file (string-append "." "/assets/sprites/player1/dying/4.png"))) 107 | (define txtPlayer1Die5 (bitmap/file (string-append "." "/assets/sprites/player1/dying/5.png"))) 108 | (define txtPlayer1Die6 (bitmap/file (string-append "." "/assets/sprites/player1/dying/6.png"))) 109 | (define txtPlayer1Die7 (bitmap/file (string-append "." "/assets/sprites/player1/dying/7.png"))) 110 | (define txtPlayer1Die8 (bitmap/file (string-append "." "/assets/sprites/player1/dying/8.png"))) 111 | 112 | ;;player2 113 | 114 | ;;up 115 | (define txtPlayer2Up1 (bitmap/file (string-append "." "/assets/sprites/player2/up/1.png"))) 116 | (define txtPlayer2Up2 (bitmap/file (string-append "." "/assets/sprites/player2/up/2.png"))) 117 | (define txtPlayer2Up3 (bitmap/file (string-append "." "/assets/sprites/player2/up/3.png"))) 118 | 119 | ;;down 120 | (define txtPlayer2Down1 (bitmap/file (string-append "." "/assets/sprites/player2/down/1.png"))) 121 | (define txtPlayer2Down2 (bitmap/file (string-append "." "/assets/sprites/player2/down/2.png"))) 122 | (define txtPlayer2Down3 (bitmap/file (string-append "." "/assets/sprites/player2/down/3.png"))) 123 | 124 | ;;left 125 | (define txtPlayer2Left1 (bitmap/file (string-append "." "/assets/sprites/player2/left/1.png"))) 126 | (define txtPlayer2Left2 (bitmap/file (string-append "." "/assets/sprites/player2/left/2.png"))) 127 | (define txtPlayer2Left3 (bitmap/file (string-append "." "/assets/sprites/player2/left/3.png"))) 128 | 129 | ;;right 130 | (define txtPlayer2Right1 (bitmap/file (string-append "." "/assets/sprites/player2/right/1.png"))) 131 | (define txtPlayer2Right2 (bitmap/file (string-append "." "/assets/sprites/player2/right/2.png"))) 132 | (define txtPlayer2Right3 (bitmap/file (string-append "." "/assets/sprites/player2/right/3.png"))) 133 | 134 | ;;dying 135 | (define txtPlayer2Die1 (bitmap/file (string-append "." "/assets/sprites/player2/dying/1.png"))) 136 | (define txtPlayer2Die2 (bitmap/file (string-append "." "/assets/sprites/player2/dying/2.png"))) 137 | (define txtPlayer2Die3 (bitmap/file (string-append "." "/assets/sprites/player2/dying/3.png"))) 138 | (define txtPlayer2Die4 (bitmap/file (string-append "." "/assets/sprites/player2/dying/4.png"))) 139 | (define txtPlayer2Die5 (bitmap/file (string-append "." "/assets/sprites/player2/dying/5.png"))) 140 | (define txtPlayer2Die6 (bitmap/file (string-append "." "/assets/sprites/player2/dying/6.png"))) 141 | (define txtPlayer2Die7 (bitmap/file (string-append "." "/assets/sprites/player2/dying/7.png"))) 142 | (define txtPlayer2Die8 (bitmap/file (string-append "." "/assets/sprites/player2/dying/8.png"))) 143 | 144 | ;;player3 145 | 146 | ;;up 147 | (define txtPlayer3Up1 (bitmap/file (string-append "." "/assets/sprites/player3/up/1.png"))) 148 | (define txtPlayer3Up2 (bitmap/file (string-append "." "/assets/sprites/player3/up/2.png"))) 149 | (define txtPlayer3Up3 (bitmap/file (string-append "." "/assets/sprites/player3/up/3.png"))) 150 | 151 | ;;down 152 | (define txtPlayer3Down1 (bitmap/file (string-append "." "/assets/sprites/player3/down/1.png"))) 153 | (define txtPlayer3Down2 (bitmap/file (string-append "." "/assets/sprites/player3/down/2.png"))) 154 | (define txtPlayer3Down3 (bitmap/file (string-append "." "/assets/sprites/player3/down/3.png"))) 155 | 156 | ;;left 157 | (define txtPlayer3Left1 (bitmap/file (string-append "." "/assets/sprites/player3/left/1.png"))) 158 | (define txtPlayer3Left2 (bitmap/file (string-append "." "/assets/sprites/player3/left/2.png"))) 159 | (define txtPlayer3Left3 (bitmap/file (string-append "." "/assets/sprites/player3/left/3.png"))) 160 | 161 | ;;right 162 | (define txtPlayer3Right1 (bitmap/file (string-append "." "/assets/sprites/player3/right/1.png"))) 163 | (define txtPlayer3Right2 (bitmap/file (string-append "." "/assets/sprites/player3/right/2.png"))) 164 | (define txtPlayer3Right3 (bitmap/file (string-append "." "/assets/sprites/player3/right/3.png"))) 165 | 166 | ;;dying 167 | (define txtPlayer3Die1 (bitmap/file (string-append "." "/assets/sprites/player3/dying/1.png"))) 168 | (define txtPlayer3Die2 (bitmap/file (string-append "." "/assets/sprites/player3/dying/2.png"))) 169 | (define txtPlayer3Die3 (bitmap/file (string-append "." "/assets/sprites/player3/dying/3.png"))) 170 | (define txtPlayer3Die4 (bitmap/file (string-append "." "/assets/sprites/player3/dying/4.png"))) 171 | (define txtPlayer3Die5 (bitmap/file (string-append "." "/assets/sprites/player3/dying/5.png"))) 172 | (define txtPlayer3Die6 (bitmap/file (string-append "." "/assets/sprites/player3/dying/6.png"))) 173 | (define txtPlayer3Die7 (bitmap/file (string-append "." "/assets/sprites/player3/dying/7.png"))) 174 | (define txtPlayer3Die8 (bitmap/file (string-append "." "/assets/sprites/player3/dying/8.png"))) 175 | 176 | ;;player4 177 | 178 | ;;up 179 | (define txtPlayer4Up1 (bitmap/file (string-append "." "/assets/sprites/player4/up/1.png"))) 180 | (define txtPlayer4Up2 (bitmap/file (string-append "." "/assets/sprites/player4/up/2.png"))) 181 | (define txtPlayer4Up3 (bitmap/file (string-append "." "/assets/sprites/player4/up/3.png"))) 182 | 183 | ;;down 184 | (define txtPlayer4Down1 (bitmap/file (string-append "." "/assets/sprites/player4/down/1.png"))) 185 | (define txtPlayer4Down2 (bitmap/file (string-append "." "/assets/sprites/player4/down/2.png"))) 186 | (define txtPlayer4Down3 (bitmap/file (string-append "." "/assets/sprites/player4/down/3.png"))) 187 | 188 | ;;left 189 | (define txtPlayer4Left1 (bitmap/file (string-append "." "/assets/sprites/player4/left/1.png"))) 190 | (define txtPlayer4Left2 (bitmap/file (string-append "." "/assets/sprites/player4/left/2.png"))) 191 | (define txtPlayer4Left3 (bitmap/file (string-append "." "/assets/sprites/player4/left/3.png"))) 192 | 193 | ;;right 194 | (define txtPlayer4Right1 (bitmap/file (string-append "." "/assets/sprites/player4/right/1.png"))) 195 | (define txtPlayer4Right2 (bitmap/file (string-append "." "/assets/sprites/player4/right/2.png"))) 196 | (define txtPlayer4Right3 (bitmap/file (string-append "." "/assets/sprites/player4/right/3.png"))) 197 | 198 | ;;dying 199 | (define txtPlayer4Die1 (bitmap/file (string-append "." "/assets/sprites/player4/dying/1.png"))) 200 | (define txtPlayer4Die2 (bitmap/file (string-append "." "/assets/sprites/player4/dying/2.png"))) 201 | (define txtPlayer4Die3 (bitmap/file (string-append "." "/assets/sprites/player4/dying/3.png"))) 202 | (define txtPlayer4Die4 (bitmap/file (string-append "." "/assets/sprites/player4/dying/4.png"))) 203 | (define txtPlayer4Die5 (bitmap/file (string-append "." "/assets/sprites/player4/dying/5.png"))) 204 | (define txtPlayer4Die6 (bitmap/file (string-append "." "/assets/sprites/player4/dying/6.png"))) 205 | (define txtPlayer4Die7 (bitmap/file (string-append "." "/assets/sprites/player4/dying/7.png"))) 206 | (define txtPlayer4Die8 (bitmap/file (string-append "." "/assets/sprites/player4/dying/8.png"))) -------------------------------------------------------------------------------- /game/cl_input.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; imports 4 | (require 2htdp/universe) 5 | (require 2htdp/image) 6 | (require "cl_sound.rkt") 7 | (require "cl_helper.rkt") 8 | (require "cl_network.rkt") 9 | (require "cl_collisions.rkt") 10 | (require "cl_sound.rkt") 11 | (require "sh_structs.rkt") 12 | (require "sh_config.rkt") 13 | (require "sh_helper.rkt") 14 | (require "sh_collisions.rkt") 15 | (require "sh_config_snds.rkt") 16 | 17 | ;; exports 18 | (provide (all-defined-out)) 19 | 20 | 21 | ;; [calculateNewPlayerPosUDGoClose] checks if position (x y) is valid and returns it if it is, else returns old Positon 22 | (define (calculateNewPlayerPosGoClose currentWorld player x y oldPos user) 23 | (if (isValidDesiredPosMove currentWorld x y gameTileSize gameTileSize user) 24 | (list x y) 25 | oldPos 26 | ) 27 | ) 28 | 29 | ;; [decIfHasTo] Decrements a number if true, else increments it 30 | (define (decIfHasTo shoulddec val) 31 | (if shoulddec 32 | (- val 1) 33 | (+ val 1) 34 | ) 35 | ) 36 | 37 | ;; [alignMoveNumX] Aligns a x move value to the current field 38 | (define (alignMoveNumX shoulddec val) 39 | (if (= (modulo val gameTileSize) 0) 40 | (+ val 1) 41 | (if shoulddec 42 | (+ (- val (modulo val gameTileSize) ) 1) 43 | (+ (- val (modulo val gameTileSize) ) 1) 44 | ) 45 | ) 46 | ) 47 | 48 | ;; [alignMoveNumY] Aligns a y move value to the current field 49 | (define (alignMoveNumY shoulddec val) 50 | (if (= (modulo (- val gameScoreHeight) gameTileSize) 0) 51 | (+ val 1) 52 | (if shoulddec 53 | (+ (- val (modulo (- val gameScoreHeight) gameTileSize) ) 1) 54 | (+ (- val (modulo (- val gameScoreHeight) gameTileSize) ) 1) 55 | ) 56 | ) 57 | ) 58 | 59 | ;; [calculateNewPlayerPosUDGoCloseIfWants] returns a slightly moved up/down player depending on his X on the game field. This is used to smooth out vertical movement. 60 | (define (calculateNewPlayerPosUDGoCloseIfWants currentWorld player newPos oldPos user) 61 | (let* ( 62 | [cury (second newPos)] 63 | [sy (exact->inexact (/ (modulo cury gameTileSize) gameTileSize))] 64 | [ty (round (coordToTile cury))] 65 | [by (exact->inexact (coordToTile (modulo ty gameTileSize)))] 66 | [ty2b (tileToCoord (+ ty 1))] 67 | [ty3b (tileToCoord (- ty 1))] 68 | [goUp (> (abs (- ty3b cury)) (abs (- ty2b cury)))] 69 | ) 70 | 71 | (if (= by 0.05) 72 | oldPos 73 | (cond 74 | [(<= 0 sy 0.09) (calculateNewPlayerPosGoClose currentWorld player (first oldPos) (alignMoveNumX goUp cury) oldPos user)] 75 | [(<= 0 sy 0.32) (calculateNewPlayerPosGoClose currentWorld player (first oldPos) (decIfHasTo goUp cury) oldPos user)] 76 | [(<= 0.68 sy 1.0) (calculateNewPlayerPosGoClose currentWorld player (first oldPos) (decIfHasTo goUp cury) oldPos user)] 77 | [else oldPos] 78 | ) 79 | ) 80 | ) 81 | ) 82 | 83 | ;; [calculateNewPlayerPosLRGoClose] returns a slightly moved left/right player depending on his X on the game field. This is used to smooth out vertical movement. 84 | (define (calculateNewPlayerPosLRGoCloseIfWants currentWorld player newPos oldPos user) 85 | (let* ( 86 | [curx (first newPos)] 87 | [sx (exact->inexact (/ (modulo curx gameTileSize) gameTileSize))] 88 | [tx (round (coordToTile curx))] 89 | [bx (exact->inexact (coordToTile (modulo tx gameTileSize)))] 90 | [tx2b (tileToCoord (+ tx 1))] 91 | [tx3b (tileToCoord (- tx 1))] 92 | [goUp (> (abs (- tx3b curx)) (abs (- tx2b curx)))] 93 | ) 94 | 95 | (if (= bx 0.05) 96 | oldPos 97 | (cond 98 | [(<= 0 sx 0.09) (calculateNewPlayerPosGoClose currentWorld player (alignMoveNumY goUp curx) (second oldPos) oldPos user)] 99 | [(<= 0 sx 0.32) (calculateNewPlayerPosGoClose currentWorld player (decIfHasTo goUp curx) (second oldPos) oldPos user)] 100 | [(<= 0.68 sx 1.0) (calculateNewPlayerPosGoClose currentWorld player (decIfHasTo goUp curx) (second oldPos) oldPos user)] 101 | [else oldPos] 102 | ) 103 | ) 104 | ) 105 | ) 106 | 107 | ;; [calculateNewPlayerPosVertical] returns a {list} with x and y if the position is valid. Otherwise, it calls another function to correct it 108 | (define (calculateNewPlayerPosVertical currentWorld player newPos oldPos user) 109 | (if (isValidDesiredPosMoveLst currentWorld newPos gameTileSize gameTileSize user) 110 | newPos 111 | (calculateNewPlayerPosLRGoCloseIfWants currentWorld player newPos oldPos user) 112 | ) 113 | ) 114 | 115 | ;; [calculateNewPlayerPosHorizontal] returns a {list} with x and y if the position is valid. Otherwise, it calls another function to correct it 116 | (define (calculateNewPlayerPosHorizontal currentWorld player newPos oldPos user) 117 | (if (isValidDesiredPosMoveLst currentWorld newPos gameTileSize gameTileSize user) 118 | newPos 119 | (calculateNewPlayerPosUDGoCloseIfWants currentWorld player newPos oldPos user) 120 | ) 121 | ) 122 | 123 | ;; [calculateNewPlayerPos] returns a new player position depenedent on his current position from his {player} struct and the moveDir. 124 | (define (calculateNewPlayerPosMoveDir currentWorld player moveDir speed user) 125 | (define x (player-x player)) 126 | (define y (player-y player)) 127 | (if (<= speed 0) 128 | (list x y) 129 | (case moveDir 130 | ['up (calculateNewPlayerPosVertical currentWorld player (list x (- y speed)) (list x y) user)] 131 | ['down (calculateNewPlayerPosVertical currentWorld player (list x (+ y speed)) (list x y) user)] 132 | ['left (calculateNewPlayerPosHorizontal currentWorld player (list (- x speed) y) (list x y) user)] 133 | ['right (calculateNewPlayerPosHorizontal currentWorld player (list (+ x speed) y) (list x y) user)] 134 | [else (list x y)] 135 | ) 136 | ) 137 | ) 138 | 139 | 140 | ;; [keyPressedLayBomb] sends a bomb if can be to be placed on the field if one can be placed at the current playerpos 141 | (define (keyPressedLayBomb currentWorld user) 142 | (let* ([localPos (getPlayerPos currentWorld user)] 143 | [field (clientsideWorld-gameField currentWorld)] 144 | [canPlaceBombs (canPlayerPlaceBombs currentWorld field user)] 145 | [xTiles (round (coordToTile (car localPos)))] 146 | [yTiles (round (coordToTile (cadr localPos)))] 147 | [newBomb (list "bomb" xTiles yTiles)] 148 | [playersBombs (getPlayersBombs currentWorld field user)] 149 | ) 150 | 151 | (if (and canPlaceBombs (isValidDesiredPosEntsR playersBombs (tileToCoord xTiles) (tileToCoord yTiles) gameTileSize gameTileSize user #t)) 152 | (and 153 | (set-clientsideWorld-forceKeySend! currentWorld #t) 154 | (play-our-sound sndLayBomb) 155 | (sendToServer currentWorld "bomb" newBomb) 156 | ) 157 | currentWorld 158 | ) 159 | ) 160 | ) 161 | 162 | ;; [keyPressedTryRespawn] requests a respawn from the server 163 | (define (keyPressedTryRespawn currentWorld user) 164 | (and 165 | (set-clientsideWorld-forceKeySend! currentWorld #t) 166 | (if (> (player-lives (getPlayerByUser currentWorld user)) 0) 167 | (sendToServer currentWorld "respawn" (list "respawn")) 168 | (and 169 | (play-our-sound sndRespawnInvalid) 170 | currentWorld 171 | ) 172 | ) 173 | ) 174 | ) 175 | 176 | ;; [keyPressedEnterIngame] Is called whenever confirmation key is pressed while ingame 177 | (define (keyPressedEnterIngame currentWorld user) 178 | (define curPlayer (getPlayerByUser currentWorld user)) 179 | 180 | (if (player-alive curPlayer) 181 | (keyPressedLayBomb currentWorld user) 182 | (keyPressedTryRespawn currentWorld user) 183 | ) 184 | ) 185 | 186 | ;; [keyPressedIngameMove] sends a move packet to the server 187 | (define (keyPressedIngameMove currentWorld move user) 188 | (let* ([curPlayer (getPlayerByUser currentWorld user)] 189 | [newPos (calculateNewPlayerPosMoveDir currentWorld curPlayer move (player-speed curPlayer) user)] 190 | [oldPos (getPlayerPos currentWorld user)] 191 | [alive (player-alive curPlayer)]) 192 | 193 | (if alive 194 | (and 195 | (setPlayerPosPlayer curPlayer (car newPos) (cadr newPos) move) 196 | ;(play-our-sound sndWalk) 197 | (sendToServer 198 | currentWorld 199 | "move" 200 | (append 201 | '("movedto") 202 | (list 203 | newPos 204 | move 205 | (+ 1000 (current-inexact-milliseconds)) 206 | ) 207 | ) 208 | ) 209 | ) 210 | currentWorld 211 | ) 212 | ) 213 | ) 214 | 215 | 216 | ;; [keyPressedEnterGame] sets our stage to the loadingscreen stage 217 | (define (keyPressedEnterGame currentWorld user) 218 | (and 219 | (stop-our-sound) 220 | (set-clientsideWorld-curState! currentWorld "loadingscreen") 221 | (set-clientsideWorld-tickCount! currentWorld 0) 222 | currentWorld 223 | ) 224 | ) 225 | 226 | ;; [keyPressedSpace] checks the current state and depending on it calls the function to either skip the titlescreen, lay a bomb or does nothing 227 | ;; this is handled seperately because you hit the key only once, while the movekeys (W|A|S|D) will be held 228 | (define (keyPressedSpace currentWorld pressedKey user) 229 | (cond 230 | [(equal? (clientsideWorld-curState currentWorld) "titlescreen") (keyPressedEnterGame currentWorld user)] 231 | [(equal? (clientsideWorld-curState currentWorld) "ingame") (keyPressedEnterIngame currentWorld user)] 232 | [else currentWorld] 233 | ) 234 | ) 235 | 236 | ;; [keyPressedTickIngame] Is called every tick to process current waiting key presses for the ingame state 237 | (define (keyPressedTickIngame currentWorld pressedKey user) 238 | (cond 239 | [(key=? pressedKey "w") (keyPressedIngameMove currentWorld 'up user)] 240 | [(key=? pressedKey "s") (keyPressedIngameMove currentWorld 'down user)] 241 | [(key=? pressedKey "a") (keyPressedIngameMove currentWorld 'left user)] 242 | [(key=? pressedKey "d") (keyPressedIngameMove currentWorld 'right user)] 243 | [else #f] 244 | ) 245 | ) 246 | 247 | 248 | ;; [keyPressedTick] Is called every tick to process current waiting key presses 249 | (define (keyPressedTick currentWorld pressedKey user) 250 | (if (equal? (clientsideWorld-curState currentWorld) "ingame") 251 | (or (keyPressedTickIngame currentWorld pressedKey user) currentWorld) 252 | #f 253 | ) 254 | ) 255 | 256 | ;; [keyTickWithKeys] Checks if there are any keys being pressed, and if yes calls [keyPressedTick] to process them 257 | (define (keyTickWithKeys currentWorld currentKeys user) 258 | (if (empty? currentKeys) 259 | #f 260 | (or 261 | (keyPressedTick currentWorld (car currentKeys) user) 262 | (keyTickWithKeys currentWorld (cdr currentKeys) user) 263 | ) 264 | ) 265 | ) 266 | 267 | ;; [keyTick] Is called every tick and gets the current pressed keys and calls [keyTickWithKeys] with them 268 | (define (keyTick currentWorld user) 269 | (define currentKeys (clientsideWorld-pressedKeys currentWorld)) 270 | (keyTickWithKeys currentWorld currentKeys user) 271 | ) 272 | 273 | ;; [keyIsMovementKey] Checks whether the current key is a movement Key 274 | (define (keyIsMovementKey pressedKey) 275 | (cond 276 | [(key=? pressedKey "w") #t] 277 | [(key=? pressedKey "s") #t] 278 | [(key=? pressedKey "a") #t] 279 | [(key=? pressedKey "d") #t] 280 | [else #f] 281 | ) 282 | ) 283 | 284 | ;; [keyIsSubmitKey] Checks whether the current key is a submit key 285 | (define (keyIsSubmitKey pressedKey) 286 | (cond 287 | [(key=? pressedKey "\r") #t] 288 | [(key=? pressedKey " ") #t] 289 | [else #f] 290 | ) 291 | ) 292 | 293 | ;; [keyPressedMovementKey] Appends the current movementKey to the list of pressedKeys 294 | (define (keyPressedMovementKey currentKeys currentWorld pressedKey user) 295 | (if (member pressedKey currentKeys) 296 | currentWorld 297 | (and 298 | (set-clientsideWorld-pressedKeys! 299 | currentWorld 300 | (append currentKeys (list pressedKey)) 301 | ) 302 | currentWorld 303 | ) 304 | ) 305 | ) 306 | 307 | ;; [keyPressedMovementKey] Appends the current movementKey to the list of pressedKeys 308 | (define (keyPressed currentWorld pressedKey user) 309 | (define currentKeys (clientsideWorld-pressedKeys currentWorld)) 310 | 311 | (cond 312 | [(keyIsSubmitKey pressedKey) (keyPressedSpace currentWorld pressedKey user)] 313 | [(keyIsMovementKey pressedKey) (keyPressedMovementKey currentKeys currentWorld pressedKey user)] 314 | [else currentWorld] 315 | ) 316 | ) 317 | 318 | ;; [keyPressedMovementKey] Appends the current movementKey to the list of pressedKeys 319 | (define (keyReleasedMovementKey currentKeys currentWorld pressedKey user) 320 | (if (not (member pressedKey currentKeys)) 321 | currentWorld 322 | (and 323 | (set-clientsideWorld-pressedKeys! currentWorld (remove pressedKey currentKeys)) 324 | currentWorld 325 | ) 326 | ) 327 | ) 328 | 329 | ;; [keyPressedMovementKey] Appends the current movementKey to the list of pressedKeys 330 | (define (keyReleased currentWorld pressedKey user) 331 | (define currentKeys (clientsideWorld-pressedKeys currentWorld)) 332 | 333 | (cond 334 | [(keyIsMovementKey pressedKey) (keyReleasedMovementKey currentKeys currentWorld pressedKey user)] 335 | [else currentWorld] 336 | ) 337 | ) -------------------------------------------------------------------------------- /game/sh_config.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | ;; import 4 | (require 2htdp/image) 5 | (require "sh_structs.rkt") 6 | 7 | ;; export 8 | (provide (all-defined-out)) 9 | 10 | 11 | ;;; === configurations for network === 12 | 13 | ;; enable sound? 14 | ;; 0 = no sound, 1 = windows only, -1 = all os 15 | (define soundEnabled -1) 16 | 17 | ;; at what FPS should the game client render? 18 | (define gameFPSRender 24) 19 | 20 | ;; at what FPS should the game client tick? 21 | (define gameFPSTick 60) 22 | 23 | ;; how many players must be ready till game starts? (> gameMinumPlayers) 24 | (define gameMinimumPlayers 1) 25 | 26 | ;; every gameMoveTicksEvery tick will be spent on checking key input and sending data if required from key handlers. the lower this is the faster you move 27 | (define gameMoveTicksEvery (ceiling (/ gameFPSTick 6))) 28 | 29 | ;;every gameSharedTicksEvery tick will be spent on shared tick (element logic) 30 | (define gameSharedTicksEvery (ceiling (/ gameFPSTick 10))) 31 | 32 | ;; at what FPS should the server tick? 33 | (define gameServerFPS gameSharedTicksEvery) 34 | 35 | ;;every gameHandleDeathsEvery tick will be spent on making the server transfer kills to the client 36 | (define gameHandleDeathsEvery (+ gameMoveTicksEvery 1)) 37 | 38 | ;; amount of lifes a player gets when connecting 39 | (define gamePlayerLifes 5) 40 | 41 | ;;duration a game lasts in seconds 42 | (define gameTime (* 60 3)) 43 | 44 | ;debug network? (cl->sv msgs) 45 | (define debugNetwork #f) 46 | 47 | ; how many breakable walls should at least be placed in % (0 -> 0%, 1 -> 100%) 48 | (define gameMinimumPercentageRandomTiles 0.2) 49 | 50 | ; how many breakable walls should at max be placed in % (0 -> 0%, 1 -> 100%) 51 | (define gameMaximumPercentageRandomTiles 1.0) 52 | 53 | 54 | 55 | 56 | 57 | 58 | ;;; === configurations for players === 59 | 60 | ;when should the next walking anim be played 61 | (define playerTickCountTillNextAnim (ceiling (/ gameFPSTick 15))) 62 | 63 | ;when should the next dying anim be played 64 | (define playerDeathTickCountTillNextAnim (* playerTickCountTillNextAnim 4)) 65 | 66 | ;;; === configurations for breaking tiles === 67 | (define breakingTileTickCountTillNextAnim (* playerTickCountTillNextAnim 2)) 68 | (define breakingTileVanishInMs 600) 69 | 70 | 71 | 72 | 73 | 74 | 75 | ;;; === configurations for bombs === 76 | 77 | ; when do bombs explode by default in ms 78 | (define bombMinimumExplodeDelay 1500) 79 | 80 | (define bombMaximumExplodeDelay 3000) 81 | 82 | ; how many bombs can 2 player have max on the field by default 83 | (define bombMaximumtAmountPerPlayer 2) 84 | 85 | (define bombTickCountTillNextAnim (* playerTickCountTillNextAnim 2)) 86 | 87 | 88 | (define gameBombsCanExplodeEachOther #t) 89 | 90 | 91 | 92 | 93 | 94 | 95 | ;;; === configurations for explosion ==== 96 | 97 | (define explosionVanishInMs 630) 98 | 99 | ;; explosion core 100 | ;How far should explosions spread 101 | (define explosionCoreRange 2) 102 | ;How many ticks till next frame 103 | (define explosionTickCountTillNextAnim (ceiling (* playerTickCountTillNextAnim 2.5))) 104 | 105 | 106 | 107 | 108 | 109 | 110 | ;;; === configurations for collision === 111 | 112 | ;; render collision bounds for unbreakable walls? 113 | (define gameRenderCollisionBounds #f) 114 | 115 | ;; no collisions for players? 116 | (define gamePlayersNoCollide #f) 117 | 118 | 119 | ;; no collisions with objects on the field? 120 | (define gameEntitiesNoCollide #f) 121 | 122 | ; disable generation of random walls 123 | (define noRandomWalls #f) 124 | 125 | 126 | 127 | 128 | 129 | 130 | ;;; === configurations for GUI === 131 | 132 | ;; how large should the game be 133 | (define gameWidth 680) 134 | (define gameHeight 600) 135 | 136 | ;;how large should each tile be (their size = their width = their height) 137 | (define gameTileSize 40) 138 | 139 | ;;how many tiles wide should the is the gamefiled in tiles 140 | (define gameFieldWidthTiles 17) 141 | 142 | ;;how many tiles high should the is the gamefiled in tiles 143 | (define gameFieldHeightTiles 13) 144 | 145 | ;;how tall should the score display be 146 | (define gameScoreHeight (inexact->exact (* gameTileSize 2))) 147 | 148 | ;;how large should the gameField be 149 | (define gameFieldWidth gameWidth) 150 | (define gameFieldHeight (- gameHeight gameScoreHeight)) 151 | 152 | ;; where does the game field start 153 | (define gameFieldY gameScoreHeight) 154 | 155 | ;; right tile border 156 | (define rightBorderXt (- gameFieldWidthTiles 1)) 157 | ;; bottom tile border 158 | (define bottomBorderYt (- gameFieldHeightTiles 1)) 159 | 160 | 161 | 162 | ;; this is here because we need it for the spawns and the spawn ss ould be in config, otherwise this would belong in sh_helper but since the spawns need to be here, this is here. 163 | 164 | (define (tileToCoord tv) 165 | (* tv gameTileSize) 166 | ) 167 | 168 | (define (tileToCoordY tv) 169 | (+ 170 | (* tv gameTileSize) 171 | gameScoreHeight 172 | ) 173 | ) 174 | 175 | 176 | 177 | 178 | 179 | 180 | ;;; === configuration for default player properties === 181 | 182 | 183 | (define gamePlayerSpeed 4) 184 | 185 | (define gamePlayerSpawns 186 | (list 187 | (list (+ gameTileSize 1) (+ gameTileSize 1)) ; player 1 188 | (list (+ (- (tileToCoord rightBorderXt) gameTileSize ) 1) (- (tileToCoord bottomBorderYt) gameTileSize 1) ) ; player 2 189 | (list (+ (- (tileToCoord rightBorderXt) gameTileSize ) 1) (- gameTileSize 1)) ; player 3 190 | (list (+ gameTileSize 1) (- (tileToCoord bottomBorderYt) gameTileSize 1)) ; player 4 191 | ) 192 | ) 193 | 194 | 195 | 196 | 197 | 198 | 199 | ;;; === load configuration for texture paths === 200 | (require "sh_config_textures.rkt") 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | ;;; === configuration for animated Textures === 209 | ;; (yes, these are procedures on purpose. We need a different struct for every animated thing) 210 | 211 | ; breakableTile 212 | (define (animatedBreakableTile) 213 | (animatedTexture 0 bombTickCountTillNextAnim 1 #f #t 'breakableTile (list txtBreakableTile)) 214 | ) 215 | 216 | ; bomb 217 | (define (animatedTextureBomb) 218 | (animatedTexture 0 bombTickCountTillNextAnim 1 #t #f 'bombAnim (list txtBomb3 txtBomb2 txtBomb1 txtBomb2 txtBomb1 txtBomb2)) 219 | ) 220 | 221 | ; breakingTile 222 | (define (animatedTextureBreakingTile) 223 | (animatedTexture 0 breakingTileTickCountTillNextAnim 1 #f #f 'breakingTileAnim (list txtBreakingTile1 txtBreakingTile2 txtBreakingTile3 txtBreakingTile4 txtBreakingTile5 txtBreakingTile6)) 224 | ) 225 | 226 | ;; players 227 | (define animatedTexturesPlayer1 228 | (list 229 | (list 'up (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'up (list txtPlayer1Up1 txtPlayer1Up2 txtPlayer1Up3 txtPlayer1Up4))) 230 | (list 'down (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'down (list txtPlayer1Down1 txtPlayer1Down2 txtPlayer1Down3 txtPlayer1Down4))) 231 | (list 'left (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'left (list txtPlayer1Left1 txtPlayer1Left2 txtPlayer1Left3 txtPlayer1Left4))) 232 | (list 'right (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'right (list txtPlayer1Right1 txtPlayer1Right2 txtPlayer1Right3 txtPlayer1Right4))) 233 | (list 'dying (animatedTexture 0 playerDeathTickCountTillNextAnim 1 #f #f 'dying (list txtPlayer1Die1 txtPlayer1Die2 txtPlayer1Die3 txtPlayer1Die4 txtPlayer1Die5 txtPlayer1Die6 txtPlayer1Die7 txtPlayer1Die8))) 234 | ) 235 | ) 236 | 237 | (define animatedTexturesPlayer2 238 | (list 239 | (list 'up (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'up (list txtPlayer2Up1 txtPlayer2Up2 txtPlayer2Up3))) 240 | (list 'down (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'down (list txtPlayer2Down1 txtPlayer2Down2 txtPlayer2Down3))) 241 | (list 'left (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'left (list txtPlayer2Left1 txtPlayer2Left2 txtPlayer2Left3))) 242 | (list 'right (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'right (list txtPlayer2Right1 txtPlayer2Right2 txtPlayer2Right3))) 243 | (list 'dying (animatedTexture 0 playerDeathTickCountTillNextAnim 1 #f #f 'dying (list txtPlayer2Die1 txtPlayer2Die2 txtPlayer2Die3 txtPlayer2Die4 txtPlayer2Die5 txtPlayer2Die6 txtPlayer2Die7 txtPlayer2Die8))) 244 | ) 245 | ) 246 | 247 | (define animatedTexturesPlayer3 248 | (list 249 | (list 'up (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'up (list txtPlayer3Up1 txtPlayer3Up2 txtPlayer3Up3))) 250 | (list 'down (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'down (list txtPlayer3Down1 txtPlayer3Down2 txtPlayer3Down3))) 251 | (list 'left (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'left (list txtPlayer3Left1 txtPlayer3Left2 txtPlayer3Left3))) 252 | (list 'right (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'right (list txtPlayer3Right1 txtPlayer3Right2 txtPlayer3Right3))) 253 | (list 'dying (animatedTexture 0 playerDeathTickCountTillNextAnim 1 #f #f 'dying (list txtPlayer3Die1 txtPlayer3Die2 txtPlayer3Die3 txtPlayer3Die4 txtPlayer3Die5 txtPlayer3Die6 txtPlayer3Die7 txtPlayer3Die8))) 254 | ) 255 | ) 256 | 257 | (define animatedTexturesPlayer4 258 | (list 259 | (list 'up (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'up (list txtPlayer4Up1 txtPlayer4Up2 txtPlayer4Up3))) 260 | (list 'down (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'down (list txtPlayer4Down1 txtPlayer4Down2 txtPlayer4Down3))) 261 | (list 'left (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'left (list txtPlayer4Left1 txtPlayer4Left2 txtPlayer4Left3))) 262 | (list 'right (animatedTexture 0 playerTickCountTillNextAnim 1 #t #f 'right (list txtPlayer4Right1 txtPlayer4Right2 txtPlayer4Right3))) 263 | (list 'dying (animatedTexture 0 playerDeathTickCountTillNextAnim 1 #f #f 'dying (list txtPlayer4Die1 txtPlayer4Die2 txtPlayer4Die3 txtPlayer4Die4 txtPlayer4Die5 txtPlayer4Die6 txtPlayer4Die7 txtPlayer4Die8))) 264 | ) 265 | ) 266 | 267 | ;; explosions 268 | ;; core 269 | (define (animatedTextureExplosionCore) 270 | (animatedTexture 0 explosionTickCountTillNextAnim 1 #f #f 'explosionCore (list txtExplosionCore1 txtExplosionCore2 txtExplosionCore3 txtExplosionCore4 txtExplosionCore3 txtExplosionCore2 txtExplosionCore1)) 271 | ) 272 | 273 | ;; up 274 | (define (animatedTextureExplosionUp) 275 | (animatedTexture 0 explosionTickCountTillNextAnim 1 #f #f 'explosionUp (list txtExplosionUp1 txtExplosionUp2 txtExplosionUp3 txtExplosionUp4 txtExplosionUp3 txtExplosionUp2 txtExplosionUp1)) 276 | ) 277 | 278 | ;; down 279 | (define (animatedTextureExplosionDown) 280 | (animatedTexture 0 explosionTickCountTillNextAnim 1 #f #f 'explosionDown (list txtExplosionDown1 txtExplosionDown2 txtExplosionDown3 txtExplosionDown4 txtExplosionDown3 txtExplosionDown2 txtExplosionDown1)) 281 | ) 282 | 283 | ;; left 284 | (define (animatedTextureExplosionLeft) 285 | (animatedTexture 0 explosionTickCountTillNextAnim 1 #f #f 'explosionLeft (list txtExplosionLeft1 txtExplosionLeft2 txtExplosionLeft3 txtExplosionLeft4 txtExplosionLeft3 txtExplosionLeft2 txtExplosionLeft1)) 286 | ) 287 | 288 | ;; right 289 | (define (animatedTextureExplosionRight) 290 | (animatedTexture 0 explosionTickCountTillNextAnim 1 #f #f 'explosionRight (list txtExplosionRight1 txtExplosionRight2 txtExplosionRight3 txtExplosionRight4 txtExplosionRight3 txtExplosionRight2 txtExplosionRight1)) 291 | ) 292 | 293 | 294 | #| --- configuration for default field/these tiles are always there --- |# 295 | 296 | ;fieldElements haben die Form: '(elementName xtiles ytiles wtiles htiles) 297 | 298 | (define fieldLevel1 299 | (list 300 | (fieldElement 'unbreakableTile 0 0 gameFieldWidthTiles 1 #f #f) ; top 301 | (fieldElement 'unbreakableTile 0 bottomBorderYt gameFieldWidthTiles 1 #f #f) ; bottom 302 | (fieldElement 'unbreakableTile 0 0 1 gameFieldHeightTiles #f #f) ; left 303 | (fieldElement 'unbreakableTile rightBorderXt 0 1 gameFieldHeightTiles #f #f) ; right 304 | 305 | 306 | (fieldElement 'unbreakableTile 2 2 1 9 #f #f) ; strip 1 307 | (fieldElement 'unbreakableTile 4 2 1 9 #f #f) ; strip 2 308 | (fieldElement 'unbreakableTile 6 2 1 9 #f #f) ; strip 3 309 | (fieldElement 'unbreakableTile 8 2 1 9 #f #f) ; strip 4 310 | (fieldElement 'unbreakableTile 10 2 1 9 #f #f) ; strip 5 311 | (fieldElement 'unbreakableTile 12 2 1 9 #f #f) ; strip 6 312 | (fieldElement 'unbreakableTile 14 2 1 9 #f #f) ; strip 7 313 | 314 | ) 315 | ) 316 | 317 | (define fieldLevel2 318 | (list 319 | (fieldElement 'unbreakableTile 0 0 gameFieldWidthTiles 1 #f #f) ; top 320 | (fieldElement 'unbreakableTile 0 bottomBorderYt gameFieldWidthTiles 1 #f #f) ; bottom 321 | (fieldElement 'unbreakableTile 0 0 1 gameFieldHeightTiles #f #f) ; left 322 | (fieldElement 'unbreakableTile rightBorderXt 0 1 gameFieldHeightTiles #f #f) ; right 323 | 324 | 325 | (fieldElement 'unbreakableTile 2 2 1 1 #f #f) ; alignment 1 326 | (fieldElement 'unbreakableTile 4 2 1 1 #f #f) ; alignment 2 327 | (fieldElement 'unbreakableTile 6 2 1 1 #f #f) ; alignment 3 328 | (fieldElement 'unbreakableTile 8 2 1 1 #f #f) ; alignment 4 329 | (fieldElement 'unbreakableTile 10 2 1 1 #f #f) ; alignment 5 330 | (fieldElement 'unbreakableTile 12 2 1 1 #f #f) ; alignment 6 331 | (fieldElement 'unbreakableTile 14 2 1 1 #f #f) ; alignment 7 332 | 333 | (fieldElement 'unbreakableTile 2 4 1 1 #f #f) ; alignment 1 334 | (fieldElement 'unbreakableTile 4 4 1 1 #f #f) ; alignment 2 335 | (fieldElement 'unbreakableTile 6 4 1 1 #f #f) ; alignment 3 336 | (fieldElement 'unbreakableTile 8 4 1 1 #f #f) ; alignment 4 337 | (fieldElement 'unbreakableTile 10 4 1 1 #f #f) ; alignment 5 338 | (fieldElement 'unbreakableTile 12 4 1 1 #f #f) ; alignment 6 339 | (fieldElement 'unbreakableTile 14 4 1 1 #f #f) ; alignment 7 340 | 341 | (fieldElement 'unbreakableTile 2 6 1 1 #f #f) ; alignment 1 342 | (fieldElement 'unbreakableTile 4 6 1 1 #f #f) ; alignment 2 343 | (fieldElement 'unbreakableTile 6 6 1 1 #f #f) ; alignment 3 344 | (fieldElement 'unbreakableTile 8 6 1 1 #f #f) ; alignment 4 345 | (fieldElement 'unbreakableTile 10 6 1 1 #f #f) ; alignment 5 346 | (fieldElement 'unbreakableTile 12 6 1 1 #f #f) ; alignment 6 347 | (fieldElement 'unbreakableTile 14 6 1 1 #f #f) ; alignment 7 348 | 349 | (fieldElement 'unbreakableTile 2 8 1 1 #f #f) ; alignment 1 350 | (fieldElement 'unbreakableTile 4 8 1 1 #f #f) ; alignment 2 351 | (fieldElement 'unbreakableTile 6 8 1 1 #f #f) ; alignment 3 352 | (fieldElement 'unbreakableTile 8 8 1 1 #f #f) ; alignment 4 353 | (fieldElement 'unbreakableTile 10 8 1 1 #f #f) ; alignment 5 354 | (fieldElement 'unbreakableTile 12 8 1 1 #f #f) ; alignment 6 355 | (fieldElement 'unbreakableTile 14 8 1 1 #f #f) ; alignment 7 356 | 357 | (fieldElement 'unbreakableTile 2 10 1 1 #f #f) ; alignment 1 358 | (fieldElement 'unbreakableTile 4 10 1 1 #f #f) ; alignment 2 359 | (fieldElement 'unbreakableTile 6 10 1 1 #f #f) ; alignment 3 360 | (fieldElement 'unbreakableTile 8 10 1 1 #f #f) ; alignment 4 361 | (fieldElement 'unbreakableTile 10 10 1 1 #f #f) ; alignment 5 362 | (fieldElement 'unbreakableTile 12 10 1 1 #f #f) ; alignment 6 363 | (fieldElement 'unbreakableTile 14 10 1 1 #f #f) ; alignment 7 364 | 365 | ) 366 | ) 367 | 368 | 369 | 370 | ;; config to set level 371 | (define gameBackgroundTexture txtLevel2) 372 | (define gameField fieldLevel2) 373 | 374 | 375 | --------------------------------------------------------------------------------