diff options
| author | Juan MarÃn Noguera <juan.marinn@um.es> | 2019-06-27 20:25:01 +0200 |
|---|---|---|
| committer | Juan MarÃn Noguera <juan.marinn@um.es> | 2019-06-27 20:25:01 +0200 |
| commit | 3228fe41df5fc737efe3ddfde26d6983619458e8 (patch) | |
| tree | 7e6f79f9866a59eb4028dc57ca0c8bcebf8ed0d4 | |
Real initial commit
| -rw-r--r-- | .gitignore | 5 | ||||
| -rw-r--r-- | 1w | 163 | ||||
| -rw-r--r-- | 50365.bmp | bin | 0 -> 1228494 bytes | |||
| -rw-r--r-- | 50365.png | bin | 0 -> 47582 bytes | |||
| -rw-r--r-- | 52569.bmp | bin | 0 -> 774282 bytes | |||
| -rw-r--r-- | 52569.png | bin | 0 -> 46932 bytes | |||
| -rw-r--r-- | 52570.bmp | bin | 0 -> 413834 bytes | |||
| -rw-r--r-- | 52570.png | bin | 0 -> 27512 bytes | |||
| -rw-r--r-- | 52571.bmp | bin | 0 -> 946314 bytes | |||
| -rw-r--r-- | 52571.png | bin | 0 -> 36402 bytes | |||
| -rw-r--r-- | 56929.bmp | bin | 0 -> 1009074 bytes | |||
| -rw-r--r-- | 56929.png | bin | 0 -> 7833 bytes | |||
| -rw-r--r-- | Game.cbp | 86 | ||||
| -rw-r--r-- | Game.depend | 312 | ||||
| -rw-r--r-- | Game.layout | 79 | ||||
| -rw-r--r-- | LICENSE | 674 | ||||
| -rw-r--r-- | Makefile | 52 | ||||
| -rw-r--r-- | README.md | 42 | ||||
| -rw-r--r-- | block.c | 176 | ||||
| -rw-r--r-- | block.h | 153 | ||||
| -rw-r--r-- | block_list.c | 165 | ||||
| -rw-r--r-- | block_list.h | 146 | ||||
| -rw-r--r-- | collision.c | 161 | ||||
| -rw-r--r-- | collision.h | 56 | ||||
| -rw-r--r-- | collision_type.h | 44 | ||||
| -rw-r--r-- | error.c | 54 | ||||
| -rw-r--r-- | error.h | 66 | ||||
| -rw-r--r-- | item.c | 296 | ||||
| -rw-r--r-- | item.h | 166 | ||||
| -rw-r--r-- | item_list.c | 155 | ||||
| -rw-r--r-- | item_list.h | 127 | ||||
| -rw-r--r-- | main.c | 160 | ||||
| -rw-r--r-- | player.c | 326 | ||||
| -rw-r--r-- | player.h | 286 | ||||
| -rw-r--r-- | screen.c | 289 | ||||
| -rw-r--r-- | screen.h | 200 | ||||
| -rw-r--r-- | world.c | 345 | ||||
| -rw-r--r-- | world.h | 102 |
38 files changed, 4886 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3343df3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +main +main.exe +*.dll + @@ -0,0 +1,163 @@ +3 2 3 195 +f0 0 69 2 +h0 2 +x8 9 +y9 9 +z10 9 +m11 2 +n12 2 3 +o15 2 +i16 2 +m23 2 +n24 2 +o25 2 +c16 5 +c20 5 +a21 5 +c22 5 +e23 5 +e22 9 +d24 5 +x19 11 +y20 11 +z21 11 +x27 10 +y28 10 3 +z31 10 +t28 3 +u28 2 +x36 11 +y37 11 2 +z39 11 +t38 4 +u38 2 1 2 +m41 2 +n42 2 2 +o44 2 +t46 5 +u46 2 1 3 +h48 2 +t57 5 +u57 2 1 3 +x56 10 +y57 10 +z58 10 +m59 2 +n60 2 3 +o63 2 +i64 2 +x67 11 +y68 11 +z69 11 +f71 0 15 2 +m73 2 +n74 2 +o75 2 +c77 5 +a78 5 +c79 5 +x75 10 +y76 10 3 +z79 10 +c80 9 8 +x84 11 +y85 11 2 +z87 11 +f89 0 64 2 +c91 9 3 +e94 9 +g94 5 +h96 2 +c100 5 2 +m107 2 +n108 2 3 +o111 2 +e106 5 +e109 5 +a109 9 +e112 5 +i112 2 +x115 11 +y116 11 +z117 11 +c118 5 +m119 2 +n120 2 +o121 2 +c121 9 3 +x123 10 +y124 10 3 +z127 10 +c128 9 +e129 9 2 +c131 9 +x132 11 +y133 11 2 +z135 11 +c129 5 2 +s134 2 4 +s135 3 3 +s136 4 2 +s137 5 +n138 2 2 +s140 2 4 +s140 3 3 +s140 4 2 +s140 5 +h144 2 +s148 2 5 +s149 3 4 +s150 4 3 +s151 5 2 +x152 10 +y153 10 +z154 10 +f155 0 64 2 +s155 2 4 +s155 3 3 +s155 4 2 +s155 5 +o159 2 +i160 2 +t163 3 +u163 2 +m167 2 +n168 2 +o169 2 +c168 5 2 +e170 5 +c171 5 +x171 10 +y172 10 3 +z175 10 +t178 3 +u178 2 +x179 11 +y180 11 2 +z182 11 +s180 2 9 +s181 3 8 +s182 4 7 +s183 5 6 +s184 6 5 +s185 7 4 +s186 8 3 +s187 9 2 +h191 2 +x199 10 +y200 10 +z201 10 +b201 2 +o206 2 +i207 2 +% +g21 2 +g44 2 +g52 2 +g54 2 +g77 6 +k104 2 +g112 2 +g114 2 +g128 2 +g130 2 diff --git a/50365.bmp b/50365.bmp Binary files differnew file mode 100644 index 0000000..a69d46e --- /dev/null +++ b/50365.bmp diff --git a/50365.png b/50365.png Binary files differnew file mode 100644 index 0000000..6238e76 --- /dev/null +++ b/50365.png diff --git a/52569.bmp b/52569.bmp Binary files differnew file mode 100644 index 0000000..b99e2ba --- /dev/null +++ b/52569.bmp diff --git a/52569.png b/52569.png Binary files differnew file mode 100644 index 0000000..59ad90c --- /dev/null +++ b/52569.png diff --git a/52570.bmp b/52570.bmp Binary files differnew file mode 100644 index 0000000..38c9616 --- /dev/null +++ b/52570.bmp diff --git a/52570.png b/52570.png Binary files differnew file mode 100644 index 0000000..3ce0824 --- /dev/null +++ b/52570.png diff --git a/52571.bmp b/52571.bmp Binary files differnew file mode 100644 index 0000000..23059be --- /dev/null +++ b/52571.bmp diff --git a/52571.png b/52571.png Binary files differnew file mode 100644 index 0000000..31d7a8f --- /dev/null +++ b/52571.png diff --git a/56929.bmp b/56929.bmp Binary files differnew file mode 100644 index 0000000..842b330 --- /dev/null +++ b/56929.bmp diff --git a/56929.png b/56929.png Binary files differnew file mode 100644 index 0000000..6b52b72 --- /dev/null +++ b/56929.png diff --git a/Game.cbp b/Game.cbp new file mode 100644 index 0000000..6d85b9a --- /dev/null +++ b/Game.cbp @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="Game" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <Build> + <Target title="Debug"> + <Option output="bin/Debug/Game" prefix_auto="1" extension_auto="1" /> + <Option object_output="obj/Debug/" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Compiler> + <Add option="-g" /> + </Compiler> + <Linker> + <Add option="-l mingw32 -l SDL2main -l SDL2" /> + </Linker> + </Target> + <Target title="Release"> + <Option output="bin/Release/Game" prefix_auto="1" extension_auto="1" /> + <Option object_output="obj/Release/" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Compiler> + <Add option="-O2" /> + </Compiler> + <Linker> + <Add option="-s" /> + </Linker> + </Target> + </Build> + <Compiler> + <Add option="-Wall" /> + </Compiler> + <Linker> + <Add option="-l mingw32 -l SDL2main -l SDL2" /> + </Linker> + <Unit filename="block.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="block.h" /> + <Unit filename="block_list.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="block_list.h" /> + <Unit filename="collision.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="collision.h" /> + <Unit filename="collision_type.h" /> + <Unit filename="error.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="error.h" /> + <Unit filename="item.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="item.h" /> + <Unit filename="item_list.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="item_list.h" /> + <Unit filename="main.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="player.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="player.h" /> + <Unit filename="screen.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="screen.h" /> + <Unit filename="world.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="world.h" /> + <Extensions> + <code_completion /> + <debugger /> + <envvars /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/Game.depend b/Game.depend new file mode 100644 index 0000000..42295fe --- /dev/null +++ b/Game.depend @@ -0,0 +1,312 @@ +# depslib dependency file v1.0
+1525599899 source:/home/juan/Desktop/univ2/tp/pr/Game/error.c
+ <errno.h>
+ <SDL2/SDL.h>
+ <SDL2/SDL_image.h>
+ <stdio.h>
+ <stdlib.h>
+ "error.h"
+
+1525607895 /home/juan/Desktop/univ2/tp/pr/Game/error.h
+
+1525606956 source:/home/juan/Desktop/univ2/tp/pr/Game/block.c
+ <malloc.h>
+ "block.h"
+ "constants.h"
+ "error.h"
+ "item.h"
+ "player.h"
+
+1525604991 /home/juan/Desktop/univ2/tp/pr/Game/block.h
+ "collision_type.h"
+ "item.h"
+ "player.h"
+ "screen.h"
+
+1525604938 /home/juan/Desktop/univ2/tp/pr/Game/collision_type.h
+
+1525605071 /home/juan/Desktop/univ2/tp/pr/Game/item.h
+ "collision_type.h"
+ "player.h"
+ "screen.h"
+
+1525605490 /home/juan/Desktop/univ2/tp/pr/Game/player.h
+ "screen.h"
+
+1525599981 /home/juan/Desktop/univ2/tp/pr/Game/screen.h
+ <SDL2/SDL.h>
+
+1525606074 /home/juan/Desktop/univ2/tp/pr/Game/constants.h
+
+1525628815 source:/home/juan/Desktop/univ2/tp/pr/Game/block_list.c
+ <malloc.h>
+ "error.h"
+ "block.h"
+ "block_list.h"
+ "screen.h"
+
+1525614379 /home/juan/Desktop/univ2/tp/pr/Game/block_list.h
+ "block.h"
+ "screen.h"
+
+1525605767 source:/home/juan/Desktop/univ2/tp/pr/Game/collision.c
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "item.h"
+ "item_list.h"
+ "player.h"
+
+1525604940 /home/juan/Desktop/univ2/tp/pr/Game/collision.h
+ "block_list.h"
+ "collision_type.h"
+ "item_list.h"
+ "player.h"
+
+1525629388 /home/juan/Desktop/univ2/tp/pr/Game/item_list.h
+ "item.h"
+ "screen.h"
+
+1525605860 source:/home/juan/Desktop/univ2/tp/pr/Game/item.c
+ <malloc.h>
+ <stdlib.h>
+ "collision_type.h"
+ "constants.h"
+ "error.h"
+ "item.h"
+ "player.h"
+ "screen.h"
+
+1525629432 source:/home/juan/Desktop/univ2/tp/pr/Game/item_list.c
+ <malloc.h>
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+
+1525638419 source:/home/juan/Desktop/univ2/tp/pr/Game/main.c
+ <stdio.h>
+ <string.h>
+ "error.h"
+ "screen.h"
+ "world.h"
+
+1525626674 /home/juan/Desktop/univ2/tp/pr/Game/world.h
+ <stdio.h>
+ "screen.h"
+
+1525625971 source:/home/juan/Desktop/univ2/tp/pr/Game/player.c
+ "collision_type.h"
+ "constants.h"
+ "error.h"
+ "player.h"
+ "screen.h"
+
+1525631696 source:/home/juan/Desktop/univ2/tp/pr/Game/screen.c
+ <malloc.h>
+ <SDL2/SDL.h>
+ <SDL2/SDL_image.h>
+ <string.h>
+ "error.h"
+ "screen.h"
+
+1525629405 source:/home/juan/Desktop/univ2/tp/pr/Game/world.c
+ <malloc.h>
+ <stdio.h>
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+ "world.h"
+
+1525704695 source:c:\users\alumno\downloads\game\game\código\block_list.c
+ <malloc.h>
+ "error.h"
+ "block.h"
+ "block_list.h"
+ "screen.h"
+
+1525800003 c:\users\alumno\downloads\game\game\código\error.h
+
+1525715885 c:\users\alumno\downloads\game\game\código\block.h
+ "collision_type.h"
+ "item.h"
+ "player.h"
+ "screen.h"
+
+1525716019 c:\users\alumno\downloads\game\game\código\collision_type.h
+
+1525788190 c:\users\alumno\downloads\game\game\código\item.h
+ "collision_type.h"
+ "player.h"
+ "screen.h"
+
+1525719674 c:\users\alumno\downloads\game\game\código\player.h
+ "screen.h"
+
+1525799945 c:\users\alumno\downloads\game\game\código\screen.h
+ <SDL2/SDL.h>
+
+1525715902 c:\users\alumno\downloads\game\game\código\block_list.h
+ "block.h"
+ "screen.h"
+
+1525790039 source:c:\users\alumno\downloads\game\game\código\collision.c
+ <math.h>
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "collision_type.h"
+ "item.h"
+ "item_list.h"
+ "player.h"
+
+1525790840 c:\users\alumno\downloads\game\game\código\collision.h
+ "block_list.h"
+ "collision_type.h"
+ "item_list.h"
+ "player.h"
+
+1525781263 c:\users\alumno\downloads\game\game\código\item_list.h
+ "item.h"
+ "screen.h"
+
+1525792851 source:c:\users\alumno\downloads\game\game\código\item_list.c
+ <malloc.h>
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+
+1525794474 source:c:\users\alumno\downloads\game\game\código\main.c
+ <stdio.h>
+ <string.h>
+ "error.h"
+ "player.h"
+ "screen.h"
+ "world.h"
+
+1525719460 c:\users\alumno\downloads\game\game\código\world.h
+ <stdio.h>
+ "screen.h"
+
+1525790808 source:c:\users\alumno\downloads\game\game\código\world.c
+ <malloc.h>
+ <stdio.h>
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+ "world.h"
+
+1525794528 source:c:\users\alumno\downloads\game\game\código\player.c
+ <malloc.h>
+ "collision_type.h"
+ "block.h"
+ "error.h"
+ "player.h"
+ "screen.h"
+
+1525704694 source:c:\users\alumno\desktop\game\game\código\block_list.c
+ <malloc.h>
+ "error.h"
+ "block.h"
+ "block_list.h"
+ "screen.h"
+
+1525800002 c:\users\alumno\desktop\game\game\código\error.h
+
+1525715884 c:\users\alumno\desktop\game\game\código\block.h
+ "collision_type.h"
+ "item.h"
+ "player.h"
+ "screen.h"
+
+1525716018 c:\users\alumno\desktop\game\game\código\collision_type.h
+
+1525788190 c:\users\alumno\desktop\game\game\código\item.h
+ "collision_type.h"
+ "player.h"
+ "screen.h"
+
+1525719674 c:\users\alumno\desktop\game\game\código\player.h
+ "screen.h"
+
+1525799944 c:\users\alumno\desktop\game\game\código\screen.h
+ <SDL2/SDL.h>
+
+1525715902 c:\users\alumno\desktop\game\game\código\block_list.h
+ "block.h"
+ "screen.h"
+
+1525790038 source:c:\users\alumno\desktop\game\game\código\collision.c
+ <math.h>
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "collision_type.h"
+ "item.h"
+ "item_list.h"
+ "player.h"
+
+1525790840 c:\users\alumno\desktop\game\game\código\collision.h
+ "block_list.h"
+ "collision_type.h"
+ "item_list.h"
+ "player.h"
+
+1525781262 c:\users\alumno\desktop\game\game\código\item_list.h
+ "item.h"
+ "screen.h"
+
+1525792850 source:c:\users\alumno\desktop\game\game\código\item_list.c
+ <malloc.h>
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+
+1525794474 source:c:\users\alumno\desktop\game\game\código\main.c
+ <stdio.h>
+ <string.h>
+ "error.h"
+ "player.h"
+ "screen.h"
+ "world.h"
+
+1525719460 c:\users\alumno\desktop\game\game\código\world.h
+ <stdio.h>
+ "screen.h"
+
+1525794528 source:c:\users\alumno\desktop\game\game\código\player.c
+ <malloc.h>
+ "collision_type.h"
+ "block.h"
+ "error.h"
+ "player.h"
+ "screen.h"
+
+1525790808 source:c:\users\alumno\desktop\game\game\código\world.c
+ <malloc.h>
+ <stdio.h>
+ "block.h"
+ "block_list.h"
+ "collision.h"
+ "collision_type.h"
+ "error.h"
+ "item.h"
+ "item_list.h"
+ "screen.h"
+ "world.h"
+
diff --git a/Game.layout b/Game.layout new file mode 100644 index 0000000..3f41854 --- /dev/null +++ b/Game.layout @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_layout_file> + <ActiveTarget name="Debug" /> + <File name="block.c" open="0" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="782" topLine="1" /> + </Cursor> + </File> + <File name="block.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="960" topLine="21" /> + </Cursor> + </File> + <File name="error.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="831" topLine="4" /> + </Cursor> + </File> + <File name="main.c" open="1" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="2100" topLine="56" /> + </Cursor> + </File> + <File name="item_list.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="811" topLine="3" /> + </Cursor> + </File> + <File name="block_list.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="817" topLine="4" /> + </Cursor> + </File> + <File name="player.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="208" topLine="0" /> + </Cursor> + </File> + <File name="block_list.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="16" topLine="0" /> + </Cursor> + </File> + <File name="item.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="857" topLine="3" /> + </Cursor> + </File> + <File name="screen.h" open="0" top="0" tabpos="1" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="2777" topLine="78" /> + </Cursor> + </File> + <File name="collision_type.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="757" topLine="4" /> + </Cursor> + </File> + <File name="world.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="850" topLine="4" /> + </Cursor> + </File> + <File name="item.c" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="841" topLine="18" /> + </Cursor> + </File> + <File name="player.c" open="1" top="1" tabpos="2" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="4692" topLine="241" /> + </Cursor> + </File> + <File name="collision.h" open="0" top="0" tabpos="0" split="0" active="1" splitpos="0" zoom_1="0" zoom_2="0"> + <Cursor> + <Cursor1 position="842" topLine="3" /> + </Cursor> + </File> +</CodeBlocks_layout_file> @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..be58572 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +# Makefile for the project. The commented parts show how the images have been +# obtained via wget and ImageMagick. +CFLAGS=-Os -Wall -pedantic +OFILES=main.o screen.o error.o player.o item.o collision.o item_list.o block.o block_list.o world.o +LINUX_EXEC=main +WINDOWS_EXEC=main.exe +SDLLIB ?= /usr/lib/x86_64-linux-gnu/libSDL2.so +WINLIB=libSDL2.dll +#BMPFILES=50365.bmp 52570.bmp 52569.bmp 52571.bmp 56929.bmp +#PNGFILES=50365.png 52570.png 52569.png 52571.png 56929.png + +.PHONY=all windows base clean + +all: base $(LINUX_EXEC) + +windows: base $(WINDOWS_EXEC) libSDL2.dll + +base: #$(BMPFILES) + +$(LINUX_EXEC): $(OFILES) + gcc -o $(LINUX_EXEC) $(CFLAGS) $(SDLLIB) $(OFILES) + +$(WINDOWS_EXEC): $(OFILES) + gcc -o $(WINDOWS_EXEC) $(CFLAGS) $(WINLIB) $(OFILES) + +%.o : %.c + gcc -c $(CFLAGS) $< + +clean: + rm -f $(OFILES) $(LINUX_EXEC) $(WINDOWS_EXEC) #$(BMPFILES) $(PNGFILES) + +#50365.png: +# wget https://www.spriters-resource.com/resources/sheets/47/50365.png +# +#52570.png: +# wget https://www.spriters-resource.com/resources/sheets/49/52570.png +# +#52569.png: +# wget https://www.spriters-resource.com/resources/sheets/49/52569.png +# +#52571.png: +# wget https://www.spriters-resource.com/resources/sheets/49/52571.png +# +#56929.png: +# wget https://www.spriters-resource.com/resources/sheets/54/56929.png +# +#56929.bmp: 56929.png +# convert 56929.png -transparent "#5c94fc" 56929.bmp +# +#%.bmp: %.png +# convert $< $@ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6bae53 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# A Super Mario-like game + +This is a GPL3-licensed game I've created as a Computer Engineering class +project. Image assets are Copyright (c) 1985 Nintendo Entertainment Inc., and +have been obtained from <https://www.spriters-resource.com>. + +## Installing on Linux + +This games requires LibSDL2 to be installed. Version 2.0.0 does not work, +but 2.0.8 does. You'll also need `gcc` and `make`. You will most likely need to +indicate the path of the SDL library to `make` with the `SDLLIB` environment +variable. + +Once these requierements are met, you simply type `make` and the game is +built to `./main`. + +Note: In Debian-based distributions, you run `apt install libsdl2-dev` and then +use `apt-file libsdl2-2.0-0` (or whatever), having installed `apt-file`, to +get the location of the shared library. + +## Installing on Windows + +You need MinGW. You'll also need to install SDL2 on MinGW (once you compile the +game, you'll only need the DLL file). + +In order to install, you have to options: + +* Type `make windows`. + +* Open the file `Game.cbp` with CodeBlocks and compile from there. You still + need to generate the BMP files, which are not handled by CodeBlocks. + +## Notes + +The documentation for Doxygen (in the header files) is in Spanish as this +was required. The instructions screen is in Spanish as well. + +The default level is `1w`, and the format is the one being parsed at `world.c`. +Bugs likely remain. Pull requests are very welcome and will (likely) be accepted +if they are actual improvements of the game (i.e. more levels, features, level +selection, fine-tuning, bug fixes, etc.) while not breaking other stuff or +changing other things just because. @@ -0,0 +1,176 @@ +/* + * block.c -- Implementa los bloques que aparecen en el juego. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <malloc.h> +#include "block.h" +#include "error.h" +#include "item.h" +#include "player.h" + +#define BLOCK_FILE "52571.bmp" +#define BLOCK_TICKS_PER_MOVE 10 +#define BLOCK_MOVE_FRAMES 3 +#define BLOCK_TICKS_MULTICOIN_THRESHOLD 300 +#define BLOCK_END_X 3 +#define BLOCK_END_Y 0 +#define BLOCK_ANIM_TICKS 3 + +struct Block { + BlockType type; + int x; + int y; + int ix; + int iy; + int cnt; + int nanim; +}; + +Picture block_pict = NULL; + +Block block_create(BlockType type, int x, int y, int ix, int iy, int nanim) +{ + Block b = malloc(sizeof(struct Block)); + if (b == NULL) + error_libc_exit(); + + if (nanim <= 0) + error_exit(ERR_OUT_OF_RANGE); + + b->x = x; + b->y = y; + b->type = type; + b->ix = ix; + b->iy = iy; + b->cnt = 0; + b->nanim = nanim; + + return b; +} + +void block_free(Block b) +{ + free(b); +} + +void block_end() +{ + screen_free_picture(block_pict); +} + +int block_x(Block b) +{ + return b->x; +} + +int block_y(Block b) +{ + return b->y; +} + +int block_render(Screen scr, Block b, int scroll) +{ + int x = b->ix + ((b->cnt++ / BLOCK_ANIM_TICKS) % b->nanim); + + if (BLOCK_SIZE*(b->x+1) <= scroll || + BLOCK_SIZE*b->x >= scroll + screen_width(scr)) + return 0; // Don't need to render + + if (block_pict == NULL) + block_pict = screen_get_picture(BLOCK_FILE); + + screen_place( + scr, + block_pict, + b->x * BLOCK_SIZE - scroll, + screen_height(scr) - (b->y + 1) * BLOCK_SIZE, + BLOCK_SIZE * x, + BLOCK_SIZE * b->iy, + BLOCK_SIZE, + BLOCK_SIZE, + 0); + + return 1; +} + +int block_can_pass_through(Block b) +{ + return b->type == BLOCK_TYPE_PASSTHROUGH; +} + +void block_make_opaque(Block b) +{ + b->type = BLOCK_TYPE_OPAQUE; + b->ix = BLOCK_END_X; + b->iy = BLOCK_END_Y; + b->nanim = 1; +} + + +void block_return_coin(Player p, Block b, Item *item) +{ + if (item != NULL) + *item = item_create( + ITEM_TYPE_TEMPCOIN, + b->x * BLOCK_SIZE, + (b->y + 1) * BLOCK_SIZE); + player_add_coin(p); +} + +int block_hit(Player p, Block b, Item *item) +{ + switch (b->type) { + case BLOCK_TYPE_PASSTHROUGH: + if (item != NULL) + *item = NULL; + return 0; + case BLOCK_TYPE_OPAQUE: + if (item != NULL) + *item = NULL; + return 0; + case BLOCK_TYPE_COIN: + block_return_coin(p, b, item); + block_make_opaque(b); + return 0; + case BLOCK_TYPE_DESTROYCOIN: + block_return_coin(p, b, item); + return 1; + case BLOCK_TYPE_MULTICOIN: + // Put counter in some small number without altering the + // animation. + b->cnt %= BLOCK_TICKS_PER_MOVE * BLOCK_MOVE_FRAMES; + b->type = BLOCK_TYPE_HIT_MULTICOIN; + case BLOCK_TYPE_HIT_MULTICOIN: + block_return_coin(p, b, item); + if (b->cnt >= BLOCK_TICKS_MULTICOIN_THRESHOLD) + block_make_opaque(b); + return 0; + case BLOCK_TYPE_UPGRADE: + if (item != NULL) + *item = item_create( + player_state(p) == PLAYER_ST_BIG || + player_state(p) == PLAYER_ST_FLOWER ? + ITEM_TYPE_FLOWER : ITEM_TYPE_MUSHROOM, + b->x * BLOCK_SIZE, + (b->y + 1) * BLOCK_SIZE); + block_make_opaque(b); + return 0; + default: + error_exit(ERR_OUT_OF_RANGE); + return 0; // Execution will never reach this point. + } +} + @@ -0,0 +1,153 @@ +/* + * block.h -- Implementa los bloques que aparecen en el juego. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file block.h Implementa los bloques que aparecen en el juego. + */ + +#ifndef __BLOCK_H +#define __BLOCK_H +#include "collision_type.h" +#include "item.h" +#include "player.h" +#include "screen.h" + +/** El tamaño de un bloque en píxeles. */ +#define BLOCK_SIZE 16 + +/** Representa un tipo de bloque. */ +typedef enum BlockType { + /** Indica que se trata de decoración de fondo, por tanto + * atravesable sin ningún efecto. + */ + BLOCK_TYPE_PASSTHROUGH, + + /** Indica un bloque opaco, no atravesable pero que no hace nada. */ + BLOCK_TYPE_OPAQUE, + + /** Indica un bloque que al golpearlo devuelve una moneda y se + * convierte en opaco. + */ + BLOCK_TYPE_COIN, + + /** Indica un bloque que al golpearlo devuelve una moneda y al hacerlo + * es destruído. + */ + BLOCK_TYPE_DESTROYCOIN, + + /** Indica un bloque que devuelve una moneda y después sigue + * devolviendo monedas durante un intervalo aproximado de tiempo, tras + * el cual se convierte en bloque opaco normal. + */ + BLOCK_TYPE_MULTICOIN, + + /** Indica un bloque del tipo BLOCK_TYPE_MULTICOIN que ya ha sido + * golpeado. + */ + BLOCK_TYPE_HIT_MULTICOIN, + + /** Indica un bloque que devuelve un champiñón, o una + * flor si el personaje que lo golpea ya está en estado + * "grande" o "flor". + */ + BLOCK_TYPE_UPGRADE +} BlockType; + +/** Representa un bloque (fijo) del mundo. */ +typedef struct Block *Block; + +/** + * \brief Crea un bloque del mapa. + * \param type El tipo de bloque. + * \param x La posición X del bloque, en bloques desde la izquierda del + * mundo. + * \param y La posición Y del bloque, en bloques desde la parte inferior + * del mundo. + * \param ix La coordenada X en la imagen de bloques en la que se encuentra el + * bloque, en bloques. + * \param iy La coordenada Y en la imagen de bloques en la que se encuentra el + * bloque, en bloques. + * \param nanim El número de pasos de la animación del bloque, que + * en la imagen de bloques se almacenan de forma consecutiva en horizontal a + * partir de las coordenadas dadas. Si el bloque no tiene animación, este + * valor debe ser 1. + * \return El bloque creado. + */ +Block block_create(BlockType type, int x, int y, int ix, int iy, int nanim); + +/** + * \brief Libera un bloque. + * \param b El bloque a liberar. + */ +void block_free(Block b); + +/** + * \brief Libera los recursos ocupados por el módulo que no pertenecen a ningún bloque en concreto, como son las imágenes de + * estos. + * \remarks Debe ser llamada antes que a screen_end. + */ +void block_end(); + +/** + * \brief Obtiene la coordenada X del bloque. + * \param b El bloque. + * \return La coordenada X del bloque, en bloques desde la parte izquierda del + * mundo. + */ +int block_x(Block b); + +/** + * \brief Obtiene la coordenada Y del bloque. + * \param b El bloque. + * \return La coordenada Y del bloque, en bloques desde la parte inferior del + * mundo. + */ +int block_y(Block b); + +/** + * \brief Dibuja un bloque en la pantalla. + * \param scr La ventana donde dibujar el bloque. + * \param b El bloque a dibujar. + * \param scroll La distancia en píxeles desde la parte izquierda del + * mundo hasta la parte izquierda de la ventana. + * \return Un valor distinto de 0 si el bloque está dentro del + * área visible del mundo (solo comprueba la coordenada horizontal), + * o 0 si queda fuera de dicha área. + */ +int block_render(Screen scr, Block b, int scroll); + +/** + * \brief Compruba si el bloque es atravesable (por objetos o personajes). + * \param b El bloque. + * \return Un valor distinto de 0 si el bloque es atravesable, o 0 si no lo es. + */ +int block_can_pass_through(Block b); + +/** + * \brief Realiza las acciones necesiarias cuando un personaje golpea un bloque. + * \param p El personaje. + * \param b El bloque golpeado por el personaje. + * \param item Parámetro de salida. Si no es NULL, la función + * deposita aquí el objeto devuelto por el bloque al ser golpeado, o + * NULL si no devuelve ningún objeto. + * \return Un valor distinto de 0 si el bloque debe ser eliminado, o 0 si no + * debe serlo. + */ +int block_hit(Player p, Block b, Item *item); + +#endif // __BLOCK_H diff --git a/block_list.c b/block_list.c new file mode 100644 index 0000000..59308be --- /dev/null +++ b/block_list.c @@ -0,0 +1,165 @@ +/* + * block_list.c -- Implementa las listas de bloques. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <malloc.h> +#include "error.h" +#include "block.h" +#include "block_list.h" +#include "screen.h" + +struct BlockNode { + Block e; + BlockNode nx; +}; + +struct BlockList { + BlockNode first; + BlockNode last; +}; + +BlockList block_list_create() +{ + BlockList bl; + BlockNode bn; + + if ((bl = malloc(sizeof(struct BlockList))) == NULL) + error_libc_exit(); + + if ((bn = malloc(sizeof(struct BlockNode))) == NULL) + error_libc_exit(); + + bn->e = NULL; + bn->nx = NULL; + + bl->first = bn; + bl->last = bn; + + return bl; +} + +void block_list_free(BlockList bl) +{ + BlockNode bn = bl->first->nx, nx; + + while (bn != NULL) { + nx = bn->nx; + block_free(bn->e); + free(bn); + bn = nx; + } + + free(bl); +} + +BlockNode block_list_begin(BlockList bl) +{ + return bl->first; +} + +Block block_list_current(BlockNode bn) +{ + return bn->nx->e; +} + +BlockNode block_list_next(BlockNode bn) +{ + return bn->nx; +} + +void block_list_delete(BlockNode bn) +{ + BlockNode nx = bn->nx->nx; + block_free(bn->nx->e); + free(bn->nx); + bn->nx = nx; +} + +void block_list_delete_preserving(BlockNode bn) +{ + BlockNode nx = bn->nx->nx; + free(bn->nx); + bn->nx = nx; +} + +int block_list_isend(BlockNode bn) +{ + return bn->nx == NULL; +} + +int block_list_isempty(BlockList bl) +{ + return block_list_isend(block_list_begin(bl)); +} + +void block_list_append(BlockList bl, Block e) +{ + BlockNode bn; + + if (bl == NULL || e == NULL) + error_exit(ERR_NULL_PARAM); + + bn = malloc(sizeof(struct BlockNode)); + bn->e = e; + bn->nx = NULL; + bl->last->nx = bn; + bl->last = bn; +} + +BlockList block_list_sort(BlockList bl) +{ + BlockList dst = block_list_create(); + BlockNode src; + Block b; + int i = 0, nx = -1; + + while (!block_list_isempty(bl)) { + src = block_list_begin(bl); + while (!block_list_isend(src)) { + b = block_list_current(src); + if (block_x(b) == i) { + block_list_append(dst, b); + block_list_delete_preserving(src); + } else { + nx = nx == -1 || block_x(b) < nx ? + block_x(b) : nx; + src = block_list_next(src); + } + } + i = nx; + nx = -1; + } + + block_list_free(bl); + return dst; +} + +void block_list_render(Screen scr, BlockList bl, int scroll) +{ + BlockNode bn = block_list_begin(bl); + Block b; + int w = screen_width(scr); + + while (!block_list_isend(bn) && + (block_x(block_list_current(bn)) + 1) * BLOCK_SIZE <= scroll) + block_list_delete(bn); + + while (!block_list_isend(bn) && + block_x(b = block_list_current(bn)) * BLOCK_SIZE < scroll + w) { + block_render(scr, b, scroll); + bn = block_list_next(bn); + } +} diff --git a/block_list.h b/block_list.h new file mode 100644 index 0000000..cd87f1d --- /dev/null +++ b/block_list.h @@ -0,0 +1,146 @@ +/* + * block_list.h -- Implementa las listas de bloques. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file block_list.h Implementa las listas de bloques. + */ + +#ifndef __BLOCK_LIST_H +#define __BLOCK_LIST_H +#include "block.h" +#include "screen.h" + +/** Representa un nodo de la lista de bloques. Usado para iterar sobre esta. */ +typedef struct BlockNode *BlockNode; + +/** Representa una lista de bloques. */ +typedef struct BlockList *BlockList; + +/** + * \brief Crea una lista vacía de bloques. + * \return Una nueva lista vacía de bloques. + */ +BlockList block_list_create(); + +/** + * \brief Libera una lista de bloques, junto con todos sus elementos. + * \param bl La lista de bloques a liberar. + * \remarks Si la lista es liberada, todo iterador sobre ella dejará de + * ser válido (ver block_list_begin). + */ +void block_list_free(BlockList bl); + +/** + * \brief Devuelve un iterador para la lista, que apunta al primer elemento de + * esta (si existe). + * \param bl La lista sobre la que iterar. + * \return Iterador de la lista apuntando al primer elemento. Si la lista + * está vacía, el iterador apunta al final (ver block_list_isend). + */ +BlockNode block_list_begin(BlockList bl); + +/** + * \brief Devuelve el bloque apuntado por un iterador de lista de bloques. + * \param bn El iterador. + * \return El elemento actual al que apunta el iterador. + */ +Block block_list_current(BlockNode bn); + +/** + * \brief Devuelve un iterador que apunta al elemento siguiente al que apunta + * este. + * \param bn El iterador. + * \return Un iterador al siguiente elemento. + * \remarks No se debe liberar el apuntador anterior al reemplazarlo por el + * nuevo (ni en ningún otro caso). Si bn apunta al último + * elemento, el iterador devuelto apuntará al final (ver + * block_list_isend). + */ +BlockNode block_list_next(BlockNode bn); + +/** + * \brief Elimina de la lista el elemento actual al que apunta el iterador (el + * devuelto por block_list_current), liberándolo. + * \param bn El iterador. + * \remarks Tras llamar a esta función, el iterador apuntará al + * elemento siguiente al que apuntaba. + */ +void block_list_delete(BlockNode bn); + +/** + * \brief Elimina de la lista el elemento actual al que apunta el iterador (el + * devuelto por block_list_current), pero sin liberar la memoria ocupada por + * el bloque en sí. + * \param bn El iterador. + * \remarks Tras llamar a esta función, el iterador apuntará al + * elemento siguiente al que apuntaba. + */ +void block_list_delete_preserving(BlockNode bn); + +/** + * \brief Comprueba si el apuntador pasado como parámetro apunta al + * final. + * \param bn El iterador. + * \return Un valor distinto de 0 si el elemento es el final, o 0 si no lo es. + * \remarks Es un error llamar a block_list_current, block_list_next o + * block_list_delete con un iterador que apunta al final, pues es como si + * apuntase al elemento posterior al último. + */ +int block_list_isend(BlockNode bn); + +/** + * \brief Comprueba si la lista de bloques es vacía. + * \param bl La lista a comprobar. + * \return Un valor distinto de 0 si la lista es vacía, o 0 si no lo es. + */ +int block_list_isempty(BlockList bl); + +/** + * \brief Añade un elemento al final de la lista. + * \param bl La lista en la que añadir el elemento. + * \param e El elemento a añadir. + */ +void block_list_append(BlockList bl, Block e); + +/** + * \brief Ordena una lista de bloques según la coordenada horizontal de + * los bloques. + * \param bl La lista de bloques a ordenar. + * \return La lista de bloques ordenada. + * \remarks Esta función libera la memoria ocupada por la lista de + * bloques que se le pasa como parámetro, salvo la correspondiente a los + * bloques en sí, que pasa a ser accesible desde la lista de bloques + * devuelta. La función asume que la coordenada horizontal de todos los + * bloques es mayor o igual a cero; de lo contrario la lista devuelta + * podrí no estar bien ordenada. + */ +BlockList block_list_sort(BlockList bl); + +/** + * \brief Dibuja todos los elementos de la lista de bloques, suponiendo que + * están ordenados por posición en el mundo de izquierda y derecha + * y eliminando los elementos que quedan a la izquierda del área visible + * del mundo. + * \param bl La lista de bloques. + * \param scr La ventana sobre la que dibujar los bloques. + * \param scroll La distnacia en píxeles desde la parte izquierda del + * mundo hasta la parte izquierda de la ventana. + */ +void block_list_render(Screen scr, BlockList bl, int scroll); + +#endif // __BLOCK_LIST_H diff --git a/collision.c b/collision.c new file mode 100644 index 0000000..828dea7 --- /dev/null +++ b/collision.c @@ -0,0 +1,161 @@ +/* + * collision.c -- Comntiene funciones de detección de colisiones. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <math.h> +#include "block.h" +#include "block_list.h" +#include "collision.h" +#include "collision_type.h" +#include "item.h" +#include "item_list.h" +#include "player.h" + +CollisionType collision_data(double x1, double y1, double w1, double h1, + double x2, double y2, double w2, double h2) +{ + double dw = (w1+w2)/2, dh = (h1+h2)/2; + double dx = x1 - x2 + dw - w2, dy = y1 - y2 + dh - h2; + double dxp, dyp; + CollisionType c = 0; + if (dx < dw && -dx < dw && dy < dh && -dy < dh) { + dxp = dx * 0.75 - dy; + dyp = dx * 0.75 + dy; + if (dxp > 0) { + if (dyp > 0) + c |= COLLISION_RIGHT; + else + c |= COLLISION_BOTTOM; + } else { + if (dyp > 0) + c |= COLLISION_TOP; + else + c |= COLLISION_LEFT; + } + } + return c; +} + +void collision_hit_if_top_and_advance(Player p, BlockNode *bn, + CollisionType c, ItemList il) +{ + Item i = NULL; + if (c & COLLISION_TOP) { + if (block_hit(p, block_list_current(*bn), &i)) + block_list_delete(*bn); + else + *bn = block_list_next(*bn); + + if (i != NULL) + item_list_append(il, i); + } else { + *bn = block_list_next(*bn); + } +} + +void collision_player_with_blocks(Player p, BlockList bl, ItemList il) +{ + BlockNode bn = block_list_begin(bl); + Block b; + double px = player_x(p), py = player_y(p), ph = player_height(p); + int pxb = (int)player_x(p) / BLOCK_SIZE; + CollisionType total_collisions = 0, c; + + while (!block_list_isend(bn) && + block_x(block_list_current(bn)) < pxb) + bn = block_list_next(bn); + + while (!block_list_isend(bn) && + block_x(b = block_list_current(bn)) < pxb + 2) + if (!block_can_pass_through(b) && + (c = collision_data( + block_x(b) * BLOCK_SIZE, + block_y(b) * BLOCK_SIZE, + BLOCK_SIZE, + BLOCK_SIZE, + px, + py, + PLAYER_WIDTH, + ph)) + != 0) { + collision_hit_if_top_and_advance(p, &bn, c, il); + total_collisions |= c; + } else { + bn = block_list_next(bn); + } + + player_correct_on_collision(p, total_collisions); +} + +void collision_player_with_items(Player p, ItemList il) +{ + ItemNode in = item_list_begin(il); + Item i; + double px = player_x(p), py = player_y(p), ph = player_height(p); + CollisionType c; + + while (!item_list_isend(in)) { + i = item_list_current(in); + c = collision_data( + item_x(i), item_y(i), item_width(i), item_height(i), + px, py, PLAYER_WIDTH, ph); + + if (c != 0 && item_player_collide(i, p, c)) + item_list_delete(in); + else + item_list_advance(in); + } + + item_list_free_node(in); +} + +void collision_blocks_with_items(BlockList bl, ItemList il) +{ + ItemNode in; + Item i; + BlockNode bn; + Block b; + CollisionType c; + double ix, iy, iw, ih; + + for (in = item_list_begin(il); !item_list_isend(in); + item_list_advance(in)) { + i = item_list_current(in); + ix = item_x(i); + iy = item_y(i); + iw = item_width(i); + ih = item_height(i); + c = 0; + for (bn = block_list_begin(bl); !block_list_isend(bn); + bn = block_list_next(bn)) { + b = block_list_current(bn); + if (!block_can_pass_through(b)) + c |= collision_data( + block_x(b) * BLOCK_SIZE, + block_y(b) * BLOCK_SIZE, + BLOCK_SIZE, + BLOCK_SIZE, + ix, + iy, + iw, + ih); + } + if (c != 0) + item_correct_on_block_collision(i, c); + } + + item_list_free_node(in); +} diff --git a/collision.h b/collision.h new file mode 100644 index 0000000..2c17828 --- /dev/null +++ b/collision.h @@ -0,0 +1,56 @@ +/* + * collision.h -- Contiene funciones de detección de colisiones. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file collision.h -- Contiene funciones de detección de colisiones. + */ + +#ifndef __COLLISION_H +#define __COLLISION_H +#include "block_list.h" +#include "collision_type.h" +#include "item_list.h" +#include "player.h" + +/** + * \brief Comprueba las colisiones del personaje con los bloques y realiza las + * acciones oportunas. + * \param p El personaje. + * \param bl La lista de bloques a comprobar. + * \param il La lista de objetos, por si fuera necesario añadirle + * elementos. + */ +void collision_player_with_blocks(Player p, BlockList bl, ItemList il); + +/** + * \brief Comprueba las colisiones del personaje con los objetos y realiza las + * acciones oportunas. + * \param p El personaje. + * \param il La lista de objetos. + */ +void collision_player_with_items(Player p, ItemList il); + +/** + * \brief Comprueba las colisiones de los bloques con los objetos y realiza las + * acciones oportunas. + * \param bl La lista de bloques. + * \param il La lista de objetos. + */ +void collision_blocks_with_items(BlockList bl, ItemList il); + +#endif // __COLLISION_H diff --git a/collision_type.h b/collision_type.h new file mode 100644 index 0000000..b391570 --- /dev/null +++ b/collision_type.h @@ -0,0 +1,44 @@ +/* + * collision_type.h -- Define los tipos de colisión. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file collision_type.h Define los tipos de colisión. + */ + +#ifndef __COLLISION_TYPE_H +#define __COLLISION_TYPE_H + +/** Representa un tipo de colisión. Este tipo funciona por máscara + * de bits, por lo que el tipo de colisión puede ser la + * combinación de varios tipos. + */ +typedef enum CollisionType { + /** Indica que una colisión es por arriba. */ + COLLISION_TOP = 1, + + /** Indica que una colisión es por abajo. */ + COLLISION_BOTTOM = 2, + + /** Indica que una colisión es por la izquierda. */ + COLLISION_LEFT = 4, + + /** Indica que una colisión es por la derecha. */ + COLLISION_RIGHT = 8 +} CollisionType; + +#endif // __COLLISION_TYPE_H @@ -0,0 +1,54 @@ +/* + * error.c -- Implementa la gestión de errores del programa. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <errno.h> +#include <SDL2/SDL.h> +#include <stdio.h> +#include <stdlib.h> +#include "error.h" + +#define ERR_ON_SDL -1023 +#define ERR_BASE -1024 + +const char *error_table[] = { + "Invalid scancode.", + "Null pointer incorrectly passed as a parameter.", + "Parameter out of range.", + "Invalid input." +}; + +void error_exit(ErrorType type) +{ + if (type < 0 || sizeof(error_table) / sizeof(char*) <= type) + fputs("Unknown error.\n", stderr); + else + fprintf(stderr, "Error: %s\n", error_table[type]); + exit(ERR_BASE-type); +} + +void error_libc_exit() +{ + int err = errno; // perror may change the value of errno + perror("Error"); + exit(err); +} + +void error_sdl_exit() +{ + fputs(SDL_GetError(), stderr); + exit(ERR_ON_SDL); +} @@ -0,0 +1,66 @@ +/* + * error.h -- Implementa la gestión de errores del programa. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file error.h Implementa la gestión de errores del programa. + */ + +#ifndef __ERROR_H +#define __ERROR_H + +/** Representa un tipo de error propio del programa (no de SDL ni de la + * biblioteca estándar de C. + */ +typedef enum ErrorType { + /** El código de escaneo de tecla especificado no es + * válido. + */ + ERR_INVALID_SCANCODE = 0, + + /** Se ha pasado un puntero nulo a una función incorrectamente. + */ + ERR_NULL_PARAM = 1, + + /** Un parámetro de función está fuera de rango. */ + ERR_OUT_OF_RANGE = 2, + + /** El fichero de entrada no es válido o se ha producido un error + * de lectura. + */ + ERR_INVALID_INPUT = 3 +} ErrorType; + +/** + * \brief Informa de un error del propio programa y lo finaliza. + * \param type El tipo de error. + */ +void error_exit(ErrorType type); + +/** + * \brief Informa del último error que ha tenido lugar en la biblioteca + * est´ndar de C y finaliza el programa. + */ +void error_libc_exit(); + +/** + * \brief Informa del &uactute;ltimo error que ha tenido lugar en la + * biblioteca SDL y finaliza el programa. + */ +void error_sdl_exit(); + +#endif // __ERROR_H @@ -0,0 +1,296 @@ +/* + * item.c -- Implementa los objetos (y enemigos) que aparecen en el juego. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <malloc.h> +#include <stdlib.h> +#include "block.h" +#include "collision_type.h" +#include "error.h" +#include "item.h" +#include "player.h" +#include "screen.h" + +#define ITEM_GRAVITY 0.15 +#define ITEM_VELOCITY_X 1.2 +#define ITEM_KOOPA_MAX_STILL 300 +#define ITEM_TEMPCOIN_LIFETIME 5 +#define ITEM_ANIM_TICKS 3 +#define ITEM_ANIM_X_SHIFT 16 +#define ITEM_GOOMBA_ANIM_NO 2 +#define ITEM_KOOPA_ANIM_NO 4 +#define ITEM_FLOWER_ANIM_NO 4 + +#define ITEM_GOOMBA_X 0 +#define ITEM_GOOMBA_Y 16 +#define ITEM_GOOMBA_W 16 +#define ITEM_GOOMBA_H 16 +#define ITEM_KOOPA_GROUND_X 160 +#define ITEM_KOOPA_GROUND_Y 24 +#define ITEM_KOOPA_GROUND_W 16 +#define ITEM_KOOPA_GROUND_H 8 +#define ITEM_KOOPA_X 96 +#define ITEM_KOOPA_Y 10 +#define ITEM_KOOPA_W 15 +#define ITEM_KOOPA_H 22 +#define ITEM_MUSHROOM_X 0 +#define ITEM_MUSHROOM_Y 0 +#define ITEM_FLOWER_X 0 +#define ITEM_FLOWER_Y 32 +#define ITEM_COIN_X 0 +#define ITEM_COIN_Y 96 +#define ITEM_UPGRADE_W 16 +#define ITEM_UPGRADE_H 16 + +#define ITEM_ENEMIES_FILE "52570.bmp" +#define ITEM_UPGRADES_FILE "52569.bmp" + +struct Item { + ItemType type; + int dir; + int cnt; + double x; + double y; + double vy; +}; + +Picture item_enemies_pict = NULL, item_upgrades_pict = NULL; + +Item item_create(ItemType type, double x, double y) +{ + Item i = malloc(sizeof(struct Item)); + + if (i == NULL) + error_libc_exit(); + + i->type = type; + i->x = x; + i->y = y; + i->vy = 0; + if (type == ITEM_TYPE_GOOMBA || type == ITEM_TYPE_KOOPA) + i->dir = -1; + else if (type == ITEM_TYPE_MUSHROOM) + i->dir = 2 * (rand() % 1) - 1; + else + i->dir = 0; + i->cnt = 0; + return i; +} + +void item_free(Item i) +{ + if (i == NULL) + error_exit(ERR_NULL_PARAM); + free(i); +} + +void item_end() +{ + if (item_enemies_pict != NULL) + screen_free_picture(item_enemies_pict); + if (item_upgrades_pict != NULL) + screen_free_picture(item_upgrades_pict); +} + +double item_x(Item i) +{ + return i->x; +} + +double item_y(Item i) +{ + return i->y; +} + +double item_vx(Item i) +{ + return i->dir * ITEM_VELOCITY_X; +} + +double item_vy(Item i) +{ + return i->vy; +} + +int item_height(Item i) +{ + switch (i->type) { + case ITEM_TYPE_GOOMBA: + return ITEM_GOOMBA_H; + case ITEM_TYPE_KOOPA: + return i->dir == 0 ? ITEM_KOOPA_GROUND_H : ITEM_KOOPA_H; + default: + return ITEM_UPGRADE_H; + } +} + +int item_width(Item i) +{ + switch (i->type) { + case ITEM_TYPE_GOOMBA: + return ITEM_GOOMBA_W; + case ITEM_TYPE_KOOPA: + return i->dir == 0 ? ITEM_KOOPA_GROUND_W : ITEM_KOOPA_W; + default: + return ITEM_UPGRADE_W; + } +} + +int item_update(Item i) +{ + i->vy -= ITEM_GRAVITY; + i->y += i->vy; + + i->x += i->dir * ITEM_VELOCITY_X; + i->cnt++; + + if (i->type == ITEM_TYPE_KOOPA && i->dir == 0 && + i->cnt >= ITEM_KOOPA_MAX_STILL) { + i->cnt = 0; + i->dir = 1; + } + + return i->type == ITEM_TYPE_TEMPCOIN && i->cnt > ITEM_TEMPCOIN_LIFETIME; +} + +void item_correct_on_block_collision(Item i, CollisionType dir) +{ + if (dir & COLLISION_TOP) { + i->vy = 0; + i->y = i->y - 2 * (((int)i->y) % BLOCK_SIZE); + } + if (dir & COLLISION_BOTTOM) { + i->vy = 0; + i->y = ((int)(i->y + BLOCK_SIZE) / BLOCK_SIZE) * BLOCK_SIZE; + } + if (dir & COLLISION_LEFT) { + i->x = (((int)(i->x + BLOCK_SIZE)) / BLOCK_SIZE) * BLOCK_SIZE; + if (i->dir != 0) + i->dir = 1; + } + if (dir & COLLISION_RIGHT) { + i->x = (((int)i->x) / BLOCK_SIZE) * BLOCK_SIZE; + if (i->dir != 0) + i->dir = -1; + } +} + +int item_player_collide(Item i, Player p, CollisionType dir) +{ + switch (i->type) { + case ITEM_TYPE_GOOMBA: + if (dir & COLLISION_BOTTOM) { + return 1; + } else { + if (player_vulnerable(p)) + player_downgrade(p); + return 0; + } + case ITEM_TYPE_KOOPA: + if (dir & COLLISION_BOTTOM && i->dir == 0) { + return 1; + } else if (dir & COLLISION_BOTTOM) { + i->dir = 0; + i->cnt = 0; + return 0; + } else { + if (player_vulnerable(p)) + player_downgrade(p); + return 0; + } + case ITEM_TYPE_MUSHROOM: + player_upgrade_to(p, PLAYER_ST_BIG); + return 1; + case ITEM_TYPE_FLOWER: + player_upgrade_to(p, PLAYER_ST_FLOWER); + return 1; + case ITEM_TYPE_COIN: + player_add_coin(p); + return 1; + case ITEM_TYPE_TEMPCOIN: + return 0; + default: + error_exit(ERR_OUT_OF_RANGE); + return 0; // Execution will never reach this point. + } +} + + +void item_render(Screen scr, Item i, int scroll) +{ + Picture pict; + int x, y, w = item_width(i), h = item_height(i); + + if (item_enemies_pict == NULL) + item_enemies_pict = screen_get_picture(ITEM_ENEMIES_FILE); + if (item_upgrades_pict == NULL) + item_upgrades_pict = screen_get_picture(ITEM_UPGRADES_FILE); + + switch (i->type) { + case ITEM_TYPE_GOOMBA: + pict = item_enemies_pict; + x = ITEM_GOOMBA_X + + ((i->cnt / ITEM_ANIM_TICKS) % ITEM_GOOMBA_ANIM_NO) + * ITEM_ANIM_X_SHIFT; + y = ITEM_GOOMBA_Y; + break; + case ITEM_TYPE_KOOPA: + pict = item_enemies_pict; + if (i->dir == 0) { + x = ITEM_KOOPA_GROUND_X; + y = ITEM_KOOPA_GROUND_Y; + } else { + x = ITEM_KOOPA_X + + ((i->cnt / ITEM_ANIM_TICKS) % + ITEM_KOOPA_ANIM_NO) + * ITEM_ANIM_X_SHIFT; + y = ITEM_KOOPA_Y; + } + break; + case ITEM_TYPE_MUSHROOM: + pict = item_upgrades_pict; + x = ITEM_MUSHROOM_X; + y = ITEM_MUSHROOM_Y; + break; + case ITEM_TYPE_FLOWER: + pict = item_upgrades_pict; + x = ITEM_FLOWER_X + + ((i->cnt / ITEM_ANIM_TICKS) % ITEM_FLOWER_ANIM_NO) + * ITEM_ANIM_X_SHIFT; + y = ITEM_FLOWER_Y; + break; + case ITEM_TYPE_COIN: + case ITEM_TYPE_TEMPCOIN: + pict = item_upgrades_pict; + x = ITEM_COIN_X; + y = ITEM_COIN_Y; + break; + default: + error_exit(ERR_OUT_OF_RANGE); + return; // Execution will never reach this point + } + + screen_place( + scr, + pict, + i->x - scroll, + screen_height(scr) - i->y - h, + x, + y, + w, + h, + i->dir == 1); +} @@ -0,0 +1,166 @@ +/* + * item.h -- Implementa los objetos (y enemigos) que aparecen en el juego. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file item.h Implementa los objetos (y enemigos) que aparecen en el juego. + */ + +#ifndef __ITEM_H +#define __ITEM_H +#include "collision_type.h" +#include "player.h" +#include "screen.h" + +/** Representa un tipo de objeto. */ +typedef enum ItemType { + /** Indica que el objeto es un goomba. */ + ITEM_TYPE_GOOMBA, + + /** Indica que el objeto es un koopa. */ + ITEM_TYPE_KOOPA, + + /** Indica que el objeto es un champiñón. */ + ITEM_TYPE_MUSHROOM, + + /** Indica que el objeto es una flor. */ + ITEM_TYPE_FLOWER, + + /** Indica que el objeto es una moneda. */ + ITEM_TYPE_COIN, + + /** Indica que el objeto es una "moneda temporal", es decir, una que + * se muestra al golpear un bloque que devuelve una moneda pero que se + * contabiliza en el momento de golpear el bloque, y no al coger la + * moneda. + */ + ITEM_TYPE_TEMPCOIN +} ItemType; + +/** Tipo de dato objeto. */ +typedef struct Item *Item; + +/** + * \brief Crea un objeto. + * \param type Tipo de objeto, uno de los definidos como ITEM_TYPE_*. + * \param x Coordenada X de la posición inicial del objeto, en + * píxeles respecto del borde izquierdo del mundo. + * \param y Coordenada Y de la posición inicial del objeto, en + * píxeles respecto de la parte inferior del mundo. + */ +Item item_create(ItemType type, double x, double y); + +/** + * \brief Libera un objeto. + * \param i El objeto a liberar. + */ +void item_free(Item i); + +/** + * \brief Libera los recursos utilizados por el TDA de forma global (las + * imágenes. + */ +void item_end(); + +/** + * \brief Obtiene la coordenada X del objeto. + * \param i El objeto. + * \return La coordenada X del objeto, en píxeles desde la parte + * izquierda del mundo. + */ +double item_x(Item i); + +/** + * \brief Obtiene la coordenada Y del objeto. + * \param i El objeto. + * \return La coordenada Y del objeto, en píxeles desde la parte inferior + * del mundo. + */ +double item_y(Item i); + +/** + * \brief Devuelve la velocidad horizontal del objeto. + * \param i El objeto. + * \return La velocidad horizontal del objeto (hacia la derecha) en + * píxeles por frame. + */ +double item_vx(Item i); + +/** + * \brief Devuelve la velocidad vertical del objeto. + * \param i El objeto. + * \return La velocidad vertical del objeto (hacia arriba) en píxeles + * por frame. + */ +double item_vy(Item i); + +/** + * \brief Devuelve el ancho del objeto. + * \param i El objeto. + * \return El ancho del objeto en píxeles. + */ +int item_width(Item i); + +/** + * \brief Devuelve el alto del objeto. + * \param i El objeto. + * \return El alto del objeto en píxeles. + */ +int item_height(Item i); + +/** + * \brief Actualiza la posición y propiedades de un objeto después + * de un frame. + * \param i El objeto en cuestión. + * \return Un valor distinto de 0 si el objeto debe ser eliminado, o 0 si no + * debe serlo. + * \remarks Esta función actúa como si el objeto no chocara con + * nada. Puede ser necesario llamar posteriormente a + * item_correct_on_block_collision o a item_player_collide. + */ +int item_update(Item i); + +/** + * \brief Corrige la posición de un objeto tras colisionar con un bloque. + * \param i El objeto en cuestión. + * \param dir La dirección relativa del bloque con el que choca el objeto + * respecto de la posición del objeto. + */ +void item_correct_on_block_collision(Item i, CollisionType dir); + +/** + * \brief Realiza las acciones necesarias cuando el objeto colisiona con el + * personaje. + * \param i El objeto en cuestión. + * \param p El personaje. + * \param dir La posición relativa del objeto respecto del personaje. + * \return Valor distinto de 0 si debería liberarse y eliminarse el + * objeto, o 0 si no debería. + */ +int item_player_collide(Item i, Player p, CollisionType dir); + +/** + * \brief Dibuja el objeto en la pantalla, siempre que esté en el + * área visible. + * \param scr La ventana donde dibujar el objeto. + * \param i El objeto. + * \param scroll La distancia en píxeles desde la parte izquierda del + * mundo hasta la parte izquierda de la ventana. + */ +void item_render(Screen scr, Item i, int scroll); + +#endif // __ITEM_H diff --git a/item_list.c b/item_list.c new file mode 100644 index 0000000..93da3e9 --- /dev/null +++ b/item_list.c @@ -0,0 +1,155 @@ +/* + * item_list.c -- Implementa las listas de objetos. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <stdlib.h> +#include "collision_type.h" +#include "error.h" +#include "item.h" +#include "item_list.h" +#include "screen.h" + +struct ItemNode { + ItemList l; + int n; +}; + +struct ItemList { + int len; + int capacity; + Item *elems; +}; + +ItemList item_list_create() +{ + ItemList il; + + il = malloc(sizeof(struct ItemList)); + + if (il == NULL) + error_libc_exit(); + + il->len = 0; + il->capacity = 1; + + il->elems = malloc(sizeof(Item)); + + if (il->elems == NULL) + error_libc_exit(); + + return il; +} + +void item_list_free(ItemList il) +{ + int i; + + for (i = il->len - 1; i >= 0; i--) + item_free(il->elems[i]); + + free(il->elems); + free(il); +} + +ItemNode item_list_begin(ItemList il) +{ + ItemNode in = malloc(sizeof(struct ItemNode)); + + if (in == NULL) + error_libc_exit(); + + in->l = il; + in->n = 0; + + return in; +} + +Item item_list_current(ItemNode in) +{ + return in->l->elems[in->n]; +} + +void item_list_advance(ItemNode in) +{ + in->n++; +} + +void item_list_delete(ItemNode in) +{ + item_free(in->l->elems[in->n]); + in->l->elems[in->n] = in->l->elems[--in->l->len]; + + if (in->l->len > 0 && in->l->len * 2 <= in->l->capacity) { + in->l->capacity /= 2; + in->l->elems = realloc (in->l->elems, + in->l->capacity * sizeof(Item)); + + if (in->l->elems == NULL) + error_libc_exit(); + } +} + +int item_list_isend(ItemNode in) +{ + return in->n >= in->l->len; +} + +void item_list_free_node(ItemNode in) +{ + free(in); +} + +void item_list_append(ItemList il, Item e) +{ + if (il->len == il->capacity) { + il->capacity *= 2; + il->elems = realloc(il->elems, il->capacity * sizeof(Item)); + + if (il->elems == NULL) + error_libc_exit(); + } + + il->elems[il->len++] = e; +} + +void item_list_update(ItemList il, int scroll, int w) +{ + ItemNode in = item_list_begin(il); + Item i; + + while (!item_list_isend(in)) { + if (item_x(i = item_list_current(in)) < scroll + w && + (item_update(i) || + item_y(i) + item_height(i) <= 0 || + item_x(i) + item_width(i) <= scroll)) + item_list_delete(in); + else + item_list_advance(in); + } + + item_list_free_node(in); +} + +void item_list_render(Screen scr, ItemList il, int scroll) +{ + ItemNode in; + + for (in = item_list_begin(il); !item_list_isend(in); + item_list_advance(in)) + item_render(scr, item_list_current(in), scroll); + + item_list_free_node(in); +} diff --git a/item_list.h b/item_list.h new file mode 100644 index 0000000..027e2fe --- /dev/null +++ b/item_list.h @@ -0,0 +1,127 @@ +/* + * item_list.h -- Implementa las listas de objetos. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file item_list.h Implementa las listas de objetos. + */ + +#ifndef __ITEM_LIST_H +#define __ITEM_LIST_H +#include "item.h" +#include "screen.h" + +/** Representa un nodo de la lista de objetos. Usado para iterar sobre esta. */ +typedef struct ItemNode *ItemNode; + +/** Representa una lista de objetos. */ +typedef struct ItemList *ItemList; + +/** + * \brief Crea una lista vacía de objetos. + * \return Una nueva lista vacía de objetos. + */ +ItemList item_list_create(); + +/** + * \brief Libera una lista de objetos, junto con todos sus elementos. + * \param il La lista de objetos a liberar. + * \remarks Si la lista es liberada, todo iterador sobre ella dejará de + * ser válido (ver item_list_begin). + */ +void item_list_free(ItemList il); + +/** + * \brief Devuelve un iterador para la lista, que apunta al primer elemento de + * esta (si existe). + * \param il La lista sobre la que iterar. + * \return Iterador de la lista apuntando al primer elemento. Si la lista + * está vacía, el iterador apunta al final (ver item_list_isend). + */ +ItemNode item_list_begin(ItemList il); + +/** + * \brief Devuelve el objeto apuntado por un iterador de lista de objetos. + * \param in El iterador. + * \return El elemento actual al que apunta el iterador. + */ +Item item_list_current(ItemNode in); + +/** + * \brief Avanza el iterador para que apunte al elemento siguiente al actual. + * \param in El iterador. + */ +void item_list_advance(ItemNode in); + +/** + * \brief Elimina de la lista el elemento actual al que apunta el iterador (el + * devuelto por item_list_current), liberándolo. + * \param in El iterador. + * \remarks Tras llamar a esta función, el iterador apuntará a + * un elemento posterior. No se garantiza que se mantenga el orden de los + * elementos de la lista tras llamar a esta función. + */ +void item_list_delete(ItemNode in); + +/** + * \brief Comprueba si el apuntador pasado como parámetro apunta al + * final. + * \param in El iterador. + * \return Un valor distinto de 0 si el elemento es el final, o 0 si no lo es. + * \remarks Es un error llamar a item_list_current, item_list_next o + * item_list_delete con un iterador que apunta al final, pues es como si + * apuntase al elemento posterior al último. + */ +int item_list_isend(ItemNode in); + +/** + * \brief Libera de memoria un iterador. + * \param in El iterador a liberar. + */ +void item_list_free_node(ItemNode in); + +/** + * \brief Añade un elemento al final de la lista. + * \param il La lista en la que añadir el elemento. + * \param e El elemento a añadir. + */ +void item_list_append(ItemList il, Item e); + +/** + * \brief Actualiza los elementos de la lista de objetos, eliminando los que han + * quedado a la izquierda del área visible del mundo y los que han + * dejado de ser visibles por haber caído por debajo de este área, + * y teniendo en cuenta las posibles colisiones. + * \param il La lista de objetos. + * \param scroll La distancia en píxeles desde el borde izquierdo del + * mundo hasta el borde izquierdo del área visible de este. + * \param w El ancho del área visible del mundo, en píxeles. + * \remarks Esta función no tiene en cuenta posibles colisiones, por + * lo que es necesario manejar las colisiones aparte. + */ +void item_list_update(ItemList il, int scroll, int w); + +/** + * \brief Dibuja todos los elementos de la lista de objetos. + * \param il La lista de objetos. + * \param scr La ventana sobre la que dibujar los objetos. + * \param scroll La distnacia en píxeles desde la parte izquierda del + * mundo hasta la parte izquierda de la ventana. + */ +void item_list_render(Screen scr, ItemList il, int scroll); + +#endif // __ITEM_LIST_H @@ -0,0 +1,160 @@ +/* + * main.c -- Rutina principal del programa. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \mainpage Juego de plataformas + * En este juego controlas un personaje que va avanzando por un nivel con + * el objetivo de llegar hasta el final, mientras esquiva enemigos y golpea + * bloques para conseguir monedas u objetos. + * \file main.c Fichero principal del juego. + */ + +#include <stdio.h> +#include <string.h> +#include "error.h" +#include "player.h" +#include "screen.h" +#include "world.h" + +#define FRAME_MILLISECONDS 20 +#define MSG_BG_R 0 +#define MSG_BG_G 0 +#define MSG_BG_B 0 +#define MSG_BG_A 255 +#define WIDTH 256 +#define HEIGHT 240 +#define MSG_MILLISECONDS 3000 + +WorldState play(Screen scr, World w) +{ + WorldState ws; + + while ((ws = world_play_frame(scr, w)) == WORLD_ST_KEEP_ON) + screen_wait(FRAME_MILLISECONDS); + + return ws; +} + +void show_msg(Screen scr, char *s) +{ + screen_fill(scr, MSG_BG_R, MSG_BG_G, MSG_BG_B, MSG_BG_A); + screen_text_centered(scr, WIDTH / 2, HEIGHT / 2 - 4, s); + screen_update(scr); + screen_wait(MSG_MILLISECONDS); +} + +void show_copyright() +{ + printf( + "Copyright (C) 2018 Juan MarÃn Noguera\n" + "This is free software; see the source for copying " + "conditions. There is NO warranty; not even for " + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" + "\n" + "The graphics and designs are Copyright (C) 1985 " + "Nintendo, Inc.\n" + "All rights reserved.\n" + "\n"); +} + +void show_instructions(Screen scr) +{ + SDL_Scancode sc; + int k; + + do { + screen_text_print(scr, 8, 72, 30, + " Use las flechas IZQUIERDA y " + " " + " DERECHA para moverse " + " " + " " + " Salte pulsando la flecha " + " " + " ARRIBA " + " " + " " + " " + " Pulse ESPACIO para continuar "); + screen_update(scr); + + k = screen_get_keyboard_event(&sc); + if (k == 0) + screen_wait(20); + + } while (k != SCREEN_KEYDOWN || sc != SDL_SCANCODE_SPACE); +} + +int main(int argc, char **argv) +{ + Screen scr; + World w; + WorldState ws; + Player p = NULL; + FILE *f; + char c[13]; + + scr = screen_create("Super Mario Bros.", 255, 240); + + show_copyright(); + show_instructions(scr); + + do { + f = fopen("1w", "r"); + if (f == NULL) + error_libc_exit(); + + w = world_create(f); + fclose(f); + + if (p != NULL) + world_substitute_player(w, p); + + ws = play(scr, w); + + p = world_player(w); + player_restart(p); + + if (ws != WORLD_ST_DEAD || player_lives(p) <= 0) + break; + + sprintf(c, "%i lives left", player_lives(p)); + show_msg(scr, c); + } while (1); + + switch (ws) { + case WORLD_ST_DEAD: + show_msg(scr, "GAME OVER"); + break; + case WORLD_ST_WON: + show_msg(scr, "YOU WON"); + break; + case WORLD_ST_MANY_COINS: + show_msg(scr, "YOU GOT TO THE MILLION COINS"); + break; + case WORLD_ST_KEEP_ON: + show_msg(scr, "Sorry - something wrong happened"); + } + + world_free(w); + screen_free(scr); + world_end(); + screen_end(); + return 0; +} + diff --git a/player.c b/player.c new file mode 100644 index 0000000..9a05971 --- /dev/null +++ b/player.c @@ -0,0 +1,326 @@ +/* + * player.c -- Implementa el personaje controlado por el jugador. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */
+#include <malloc.h> +#include "collision_type.h" +#include "block.h" +#include "error.h" +#include "player.h" +#include "screen.h" + +#define PLAYER_GRAVITY 0.15 +#define PLAYER_ACCEL 0.2 +#define PLAYER_ACCEL_FLYING 0.02 +#define PLAYER_VELOCITY_JUMP 4.5 +#define PLAYER_MAX_VELOCITY 1.8 +#define PLAYER_ANIM_TICKS 5 +#define PLAYER_ANIM_NO 3 +#define PLAYER_PICT_FILE "50365.bmp" +#define PLAYER_SMALL_Y 34 +#define PLAYER_SMALL_H 16 +#define PLAYER_BIG_Y 1 +#define PLAYER_BIG_H 32 +#define PLAYER_FLOWER_Y 129 +#define PLAYER_SHIFT_X 17 +#define PLAYER_DEAD_X 182 +#define PLAYER_LOOK_X 80 +#define PLAYER_JUMP_X 165 +#define PLAYER_GROUND_X 182 +#define PLAYER_WALK_X 97 +#define PLAYER_VULNERABLE_TICKS 60 + +struct Player { + double x; + double y; + double vx; + double vy; + PlayerState state; + PlayerPos pos; + int left; + int counter; + int coins; + int lives; + int vuln; +}; + +Picture player_pict = NULL; + +Player player_create(int x, int y, int lives) +{ + Player p = malloc(sizeof(struct Player)); + if (p == NULL) + error_libc_exit(); + + p->x = x; + p->y = y; + p->vx = 0; + p->vy = 0; + p->state = PLAYER_ST_SMALL; + p->pos = PLAYER_POS_UPRIGHT; + p->counter = 0; + p->left = 0; + p->coins = 0; + p->lives = lives; + p->vuln = PLAYER_VULNERABLE_TICKS; + + return p; +} + +void player_free(Player p) +{ + if(p == NULL) + error_exit(ERR_NULL_PARAM); + free(p); +} + +void player_end() +{ + if (player_pict != NULL) { + screen_free_picture(player_pict); + player_pict = NULL; + } +} + +double player_x(Player p) +{ + return p->x; +} + +void player_set_x(Player p, double x) +{ + p->x = x; +} + +double player_y(Player p) +{ + return p->y; +} + +void player_set_y(Player p, double y) +{ + p->y = y; +} + +double player_vx(Player p) +{ + return p->vx; +} + +double player_vy(Player p) +{ + return p->vy; +} + +PlayerState player_state(Player p) +{ + return p->state; +} + +PlayerPos player_pos(Player p) +{ + return p->pos; +} + +void player_set_pos(Player p, PlayerPos pos) +{ + if (pos == PLAYER_POS_JUMP && p->pos != PLAYER_POS_JUMP) + p->vy = PLAYER_VELOCITY_JUMP; + p->pos = pos; +} + +int player_coins(Player p) +{ + return p->coins; +} + +int player_lives(Player p) +{ + return p->lives; +} + +void player_update(Player p) +{ + p->counter++; + p->vuln++; + p->vy -= PLAYER_GRAVITY; + p->x += p->vx; + p->y += p->vy; +} + +int player_vulnerable(Player p) +{ + return p->vuln >= PLAYER_VULNERABLE_TICKS; +} + +void player_correct_on_collision(Player p, int dir) +{ + if (dir & COLLISION_BOTTOM) { + p->vy = 0; + p->y = ((int)(p->y + BLOCK_SIZE) / BLOCK_SIZE) * BLOCK_SIZE; + if (dir & COLLISION_TOP) + p->pos = PLAYER_POS_GROUND; + else + p->pos = PLAYER_POS_UPRIGHT; + } else if (dir & COLLISION_TOP) { + p->vy = 0; + p->y = p->y - 2 * (((int)p->y) % BLOCK_SIZE); + } + if (dir & COLLISION_LEFT) { + p->vx = 0; + p->x = (((int)(p->x + BLOCK_SIZE)) / BLOCK_SIZE) * BLOCK_SIZE; + } + if (dir & COLLISION_RIGHT) { + p->vx = 0; + p->x = (((int)(p->x)) / BLOCK_SIZE) * BLOCK_SIZE; + } +} + +void player_accel(Player p, int left) +{ + double amount = p->pos == PLAYER_POS_JUMP && p->vy < 0 ? + PLAYER_ACCEL_FLYING : PLAYER_ACCEL; + if (left) + p->vx = (p->vx > 0 ? -amount : p->vx - amount); + else + p->vx = (p->vx < 0 ? amount : p->vx + amount); + + if (p->vx > PLAYER_MAX_VELOCITY) + p->vx = PLAYER_MAX_VELOCITY; + else if (p->vx < -PLAYER_MAX_VELOCITY) + p->vx = -PLAYER_MAX_VELOCITY; +} + +void player_jump(Player p) +{ + if (p->pos != PLAYER_POS_JUMP) { + p->vy = PLAYER_VELOCITY_JUMP; + p->pos = PLAYER_POS_JUMP; + } +} + + +void player_stop(Player p) +{ + if (p->pos != PLAYER_POS_JUMP) + p->vx = 0; +} + +int player_pict_y(Player p) +{ + switch (p->state) { + case PLAYER_ST_SMALL: + case PLAYER_ST_DEAD: + return PLAYER_SMALL_Y; + case PLAYER_ST_BIG: + return PLAYER_BIG_Y; + case PLAYER_ST_FLOWER: + return PLAYER_FLOWER_Y; + default: + error_exit(ERR_OUT_OF_RANGE); + return 0; // Execution will never reach this point. + } +} + +int player_height(Player p) { + return p->state == PLAYER_ST_SMALL || p->state == PLAYER_ST_DEAD ? + PLAYER_SMALL_H : PLAYER_BIG_H; +} + +int player_pict_x(Player p) +{ + if (p->state == PLAYER_ST_DEAD) + return PLAYER_DEAD_X; + else if (p->pos == PLAYER_POS_JUMP) + return PLAYER_JUMP_X; + else if (p->pos == PLAYER_POS_GROUND && + p->state != PLAYER_ST_SMALL) + return PLAYER_GROUND_X; + else if (p->vx == 0) + return PLAYER_LOOK_X; + else // Walking + return PLAYER_WALK_X + + ((p->counter / PLAYER_ANIM_TICKS) % PLAYER_ANIM_NO) + * PLAYER_SHIFT_X; +} + +void player_render(Screen scr, Player p, int scroll) +{ + int h = player_height(p); + + if (p->vx < 0) + p->left = 1; + else if (p->vx > 0) + p->left = 0; + + if (player_pict == NULL) + player_pict = screen_get_picture(PLAYER_PICT_FILE); + + screen_place( + scr, + player_pict, + p->x - scroll, + screen_height(scr) - p->y - h, + player_pict_x(p), + player_pict_y(p), + PLAYER_WIDTH, + h, + p->left); +} + +void player_downgrade(Player p) +{ + if (p->state != PLAYER_ST_DEAD) + p->state--; + p->vuln = 0; +} + +void player_upgrade_to(Player p, int state) +{ + if (p->state > PLAYER_ST_FLOWER) + error_exit(ERR_OUT_OF_RANGE); + if (p->state < state) + p->state = state; +} + +void player_die(Player p) +{ + p->state = PLAYER_ST_DEAD; +} + +void player_add_coin(Player p) +{ + if (++p->coins % 100 == 0) + ++p->lives; +} + + +int player_restart(Player p) +{ + p->vx = 0; + p->vy = 0; + p->pos = PLAYER_POS_UPRIGHT; + p->left = 0; + p->counter = 0; + p->vuln = PLAYER_VULNERABLE_TICKS; + + if (p->state == PLAYER_ST_DEAD) { + player_upgrade_to(p, PLAYER_ST_SMALL); + p->coins = 0; + } + + return --p->lives > 0; +} diff --git a/player.h b/player.h new file mode 100644 index 0000000..b10e086 --- /dev/null +++ b/player.h @@ -0,0 +1,286 @@ +/* + * player.h -- Implementa el personaje controlado por el jugador. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file player.h Implementa el personaje controlado por el jugador. + */ + +#ifndef __PLAYER_H +#define __PLAYER_H +#include "screen.h" + +/** Ancho del personaje en píxeles. */ +#define PLAYER_WIDTH 16 + +/** Representa el estado del personaje. */ +typedef enum PlayerState { + /** Indica que el personaje está en estado "pequeño". */ + PLAYER_ST_SMALL = 1, + + /** Indica que el personaje está en estado "grande". */ + PLAYER_ST_BIG = 2, + + /** Indica que el personaje está en estado "flor". */ + PLAYER_ST_FLOWER = 3, + + /** Indica que el personaje está muerto. */ + PLAYER_ST_DEAD = 0 +} PlayerState; + +/** Representa la posición relativa del personaje (de pie, saltando o + * agachado). + */ +typedef enum PlayerPos { + /** Indica que el personaje está de pie. */ + PLAYER_POS_UPRIGHT, + + /** Indica que el personaje está saltando. */ + PLAYER_POS_JUMP, + + /** Indica que el personaje está agachado. */ + PLAYER_POS_GROUND +} PlayerPos; + +/** Representa al personaje. */ +typedef struct Player *Player; + +/** + * \brief Crea una instancia de personaje. + * \param x La coordenada X de la posición de inicio. + * \param y La coordenada Y de la posición de inicio. + * \param lives El número de vidas con el que empieza. + * \return El personaje creado. + * \remarks Al crearse, el personaje está de pie, parado y mirando hacia + * la derecha. + */ +Player player_create(int x, int y, int lives); + +/** + * \brief Libera una instancia de personaje. + * \param p El personaje a liberar. + */ +void player_free(Player p); + +/** + * \brief Libera los recursos (im´genes) alojados por este TDA de forma + * global. Debe ser llamado antes de screen_end. + */ +void player_end(); + +/** + * \brief Obtiene la coordenada X de la posición actual del personaje. + * \param p El personaje. + * \return La coordenada X del personaje. + */ +double player_x(Player p); + +/** + * \brief Establece la coordenada X de la posición del personaje. + * \param p El personaje. + * \param x El nuevo valor de la coordenada X. + */ +void player_set_x(Player p, double x); + +/** + * \brief Obtiene la coordenada Y de la posición actual del personaje. + * \param p El personaje. + * \return La coordenada Y del personaje. + */ +double player_y(Player p); + +/** + * \brief Establece la coordenada Y de la posición del personaje. + * \param p El personaje. + * \param y El nuevo valor de la coordenada Y. + */ +void player_set_y(Player p, double y); + +/** + * \brief Obtiene la velocidad horizontal del personaje. + * \param p El personaje. + * \return La componente horizontal de la velocidad actual del personaje. + */ +double player_vx(Player p); + +/** + * \brief Obtiene la velocidad vertical del personaje. + * \param p El personaje. + * \return La componente vertical de la velocidad actual del personaje. + */ +double player_vy(Player p); + +/** + * \brief Obtiene el estado actual del personaje. + * \param p El personaje. + * \return El estado del personaje. Puede ser PLAYER_ST_SMALL, PLAYER_ST_BIG o + * PLAYER_ST_FLOWER. + */ +PlayerState player_state(Player p); + +/** + * \brief Obtiene el número de monedas recogidas por el personaje. + * \param p El personaje. + * \return El número de monedas que tiene. + */ +int player_coins(Player p); + +/** + * \brief Obtiene el número de vidas que le quedan al personaje, + * incluyendo la que esté siendo usada en el momento actual. + */ +int player_lives(Player p); + +/** + * \brief Obtiene la posición (postura) actual del personaje. + * \param p El personaje. + * \return La posición del personale. Puede ser PLAYER_POS_UPRIGHT, + * PLAYER_POS_JUMP o PLAYER_POS_GROUND. + */ +PlayerPos player_pos(Player p); + +/** + * \brief Obtiene la altura del personaje. + * \param p El personaje. + * \return La altura actual del personaje en píxeles. + */ +int player_height(Player p); + +/** + * \brief Establece la posición actual del personaje. + * \param p El personaje. + * \param pos La nueva posición del personaje. Puede ser + * PLAYER_POS_UPRIGHT, PLAYER_POS_JUMP o PLAYER_POS_GROUND. + */ +void player_set_pos(Player p, PlayerPos pos); + +/** + * \brief Actualiza la posición del personaje por un frame. + * \param p El personaje. + * \remarks La función actúa como si no hubiera nada alrededor del + * personaje (cae). Para evitarlo, se debe llamar posteriormente a + * player_correct_on_collision. + */ +void player_update(Player p); + +/** + * \brief Comprueba si el personaje es vulnerable a daño por parte de + * enemigos (como Goombas y Koopas). El personaje se vuelve invulnerable tras + * chocar con uno y bajar de estado, durante un corto periodo de tiempo, y + * no se debería llamar a player_downgrade si esta función + * devuelve 0. + * \param p El personaje. + * \return Devuelve 0 si el personaje es invulnerable, u otro valor en caso + * contrario. + */ +int player_vulnerable(Player p); + +/** + * \brief Corrige la posición del personaje después de llamar + * a player_update en caso de haber una colisión. + * \param p El personaje. + * \param dir El tipo de colisión por el que corregir la posición. + * Esta par´metro puede valer COLLISION_TOP, COLLISION_BOTTOM, + * COLLISION_LEFT o COLLISION_RIGHT (definidos en collision.h), o el resultado + * de hacer la disyunción lógica bit a bit (operador '|') para + * corregir varios tipos de colisión en la misma llamada a la + * función. + */ +void player_correct_on_collision(Player p, int dir); + +/** + * \brief Acelera al personaje a la izquierda o a la derecha según + * valores fijos para la aceleración y la velocidad máxima. + * \param p El personaje. + * \param left Si es distinto de 0, la aceleración será hacia la + * izquierda. De lo contrario será hacia la derecha. + * \remarks Si el personaje está avanzando en dirección contraria, + * frena en seco antes de acelerar en esta dirección. + */ +void player_accel(Player p, int left); + +/** + * \brief Hace saltar al personaje. + * \param p El personaje. + */ +void player_jump(Player p); + +/** + * \brief Establece a cero la componente horizontal de la velocidad del + * personaje, salvo si este está saltando. + * \param p El personaje. + */ +void player_stop(Player p); + +/** + * \brief Dibuja al personaje en la posición de la pantalla que le + * corresponde. + * \param scr La ventana donde dibujar al personaje. + * \param p El personaje. + * \param scroll El scroll, la coordenada X de la parte izquierda de la ventana + * respecto de la parte izquierda del mundo. + */ +void player_render(Screen scr, Player p, int scroll); + +/** + * \brief Pasa al personaje al estado inferior al actual. + * \param p El personaje. + * \remarks Pasa de estado "flor" a "grande", de "grande" a "pequeño" y + * de "pequeño" a "muerto". + */ +void player_downgrade(Player p); + +/** + * \brief Pasa al personaje a un estado dado si está en un estado + * inferior. + * \param p El personaje. + * \param state El nuevo estado, entre PLAYER_ST_DEAD, PLAYER_ST_SMALL, + * PLAYER_ST_BIG o PLAYER_ST_FLOWER. + */ +void player_upgrade_to(Player p, int state); + +/** + * \brief "Mata" a un personaje (cambia su estado a "muerto"). + * \param p El personaje. + */ +void player_die(Player p); + +/** + * \brief Añade una moneda al contador de monedas recogidas por el + * personaje. + * \param p El personaje. + * \remarks Si se llega a un número de monedas múltiplo de 100, + * el personaje gana una vida extra. + */ +void player_add_coin(Player p); + +/** + * \brief Resetea el personaje para empezar un mundo de nuevo. + * \param p El personaje. + * \return Un número distinto de 0 si quedan vidas como para empezar una + * nueva partida. De lo contrario devuelve 0. + * \remarks Al resetear, el personaje queda parado, mirando hacia la derecha. + * Si el personaje estaba en estado "muerto", se resetean las monedas y el + * personaje pasa a estado "pequeño", y de lo contrario el personaje + * conserva su estado. Esta función también disminuye el + * número de vidas en 1. Sin embargo, el personaje queda en las mismas + * coordenadas del mundo que tenía antes. + */ +int player_restart(Player p); + +#endif // __PLAYER_H + diff --git a/screen.c b/screen.c new file mode 100644 index 0000000..2176cb4 --- /dev/null +++ b/screen.c @@ -0,0 +1,289 @@ +/* + * screen.c -- Abstracción sobre SDL para la entrada y salida gráfica. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <malloc.h> +#include <SDL2/SDL.h> +#include <string.h> +#include "error.h" +#include "screen.h" + +#define TEXT_X 3 +#define TEXT_Y 460 +#define TEXT_FILE "56929.bmp" +#define TEXT_H 8 +#define TEXT_W 8 +#define TEXT_PER_ROW 16 + +struct Picture { + SDL_Surface *s; + SDL_Surface *f; +}; + +struct Screen { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Surface *surface; +}; + +Picture screen_text_bmp = NULL; + +static void screen_init() +{ + if (!SDL_WasInit(SDL_INIT_VIDEO) && SDL_Init(SDL_INIT_VIDEO) < 0) + error_sdl_exit(); +} + +Screen screen_create(const char *caption, int w, int h) +{ + Screen scr; + + if (w <= 0 || h <= 0) + error_exit(ERR_OUT_OF_RANGE); + + scr = malloc(sizeof(struct Screen)); + if (scr == NULL) + error_libc_exit(); + + screen_init(); + + scr->window = SDL_CreateWindow( + caption, + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + w, + h, + 0); + if (scr->window == NULL) + error_sdl_exit(); + + scr->surface = SDL_GetWindowSurface(scr->window); + if (scr->surface == NULL) + error_sdl_exit(); + + scr->renderer = SDL_CreateSoftwareRenderer(scr->surface); + if (scr->renderer == NULL) + error_sdl_exit(); + + if (SDL_SetRenderDrawBlendMode(scr->renderer, SDL_BLENDMODE_BLEND) == + -1) + error_sdl_exit(); + + return scr; +} + +void screen_free(Screen scr) +{ + SDL_DestroyWindow(scr->window); + SDL_DestroyRenderer(scr->renderer); +} + +void screen_end() +{ + if (screen_text_bmp != NULL) + screen_free_picture(screen_text_bmp); + SDL_Quit(); +} + + +int screen_width(Screen scr) +{ + return scr->surface->w; +} + +int screen_height(Screen scr) +{ + return scr->surface->h; +} + +void screen_wait(int ms) +{ + SDL_Delay(ms); +} + +void screen_update(Screen scr) +{ + if (SDL_UpdateWindowSurface(scr->window) == -1) + error_sdl_exit(); +} + +int screen_get_keyboard_event(SDL_Scancode *sc) +{ + SDL_Event event; + while (SDL_PollEvent(&event)) + switch (event.type) { + case SDL_KEYDOWN: + if (event.key.repeat) + break; + if (sc != NULL) + *sc = event.key.keysym.scancode; + return SCREEN_KEYDOWN; + case SDL_KEYUP: + if (event.key.repeat) + break; + if (sc != NULL) + *sc = event.key.keysym.scancode; + return SCREEN_KEYUP; + case SDL_QUIT: + exit(0); + } + + return 0; +} + +int screen_key_pressed(SDL_Scancode scancode) +{ + int len; + const uint8_t *state; + + SDL_PumpEvents(); + state = SDL_GetKeyboardState(&len); + if (len <= scancode || scancode < 0) + error_exit(ERR_INVALID_SCANCODE); + return state[scancode]; +} + +void screen_fill(Screen scr, int r, int g, int b, int a) +{ + if (SDL_SetRenderDrawColor(scr->renderer, r, g, b, a) == -1) + error_sdl_exit(); + if (SDL_RenderClear(scr->renderer) == -1) + error_sdl_exit(); +} + +void screen_place(Screen scr, Picture pict, int x, int y, int sx, int sy, + int w, int h, int flipped) +{ + SDL_Rect src, dst; + int total_width = screen_width(scr), total_height = screen_height(scr); + SDL_Surface *surface; + + if (flipped) { + sx = pict->f->w - sx - w; + surface = pict->f; + } else { + surface = pict->s; + } + + if (x > total_width || y > total_height || x + w <= 0 || y + h <= 0) + return; // Nothing to do here + + src.x = x < 0 ? sx - x : sx; + src.y = y < 0 ? sy - y : sy; + src.w = x < 0 ? w + x : + x + w > total_width ? total_width - x : + w; + src.h = y < 0 ? h + y : + y + h > total_height ? total_height - y: + h; + dst.x = x < 0 ? 0 : x; + dst.y = y < 0 ? 0 : y; + dst.w = src.w; + dst.h = src.h; + + if (SDL_BlitSurface(surface, &src, scr->surface, &dst) == -1) + error_sdl_exit(); +} + +Picture screen_get_picture(const char *file) +{ + SDL_Surface *raw, *converted, *flipped; + SDL_PixelFormat *pxf; + Picture pict = malloc(sizeof(struct Picture)); + + if (pict == NULL) + error_libc_exit(); + + raw = SDL_LoadBMP(file); + if (raw == NULL) + error_sdl_exit(); + + pxf = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); + if (pxf == NULL) + error_sdl_exit(); + + converted = SDL_ConvertSurface(raw, pxf, 0); + if (converted == NULL) + error_sdl_exit(); + + SDL_FreeFormat(pxf); + SDL_FreeSurface(raw); + + flipped = SDL_CreateRGBSurface(0, raw->w, raw->h, 32, + pxf->Rmask, pxf->Gmask, pxf->Bmask, pxf->Amask); + if (flipped == NULL) + error_sdl_exit(); + for (int y = 0; y < raw->h; y++) + for (int x = 0; x < raw->w; x++) + ((int*)flipped->pixels)[(y + 1) * raw->w - x - 1] = + ((int*)converted->pixels)[y * raw->w + x]; + pict->s = converted; + pict->f = flipped; + return pict; +} + +void screen_free_picture(Picture pict) +{ + SDL_FreeSurface(pict->f); + SDL_FreeSurface(pict->s); + free(pict); +} + +void screen_print_char(Screen scr, int x, int y, char c) +{ + int i; + if (c >= '0' && c <= '9') + i = c - '0'; + else if (c >= 'a' && c <= 'z') + i = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + i = c - 'A' + 10; + else if (c == '.') + i = 36; // This is the copyright mark. + else if (c == '-') + i = 40; + else if (c == '*') + i = 41; + else if (c == '!') + i = 43; + else + return; + screen_place(scr, screen_text_bmp, x, y, + TEXT_X + (i % TEXT_PER_ROW) * TEXT_W, + TEXT_Y + (i / TEXT_PER_ROW) * TEXT_H, + TEXT_W, + TEXT_H, + 0); +} + +void screen_text_print(Screen scr, int x, int y, int w, const char *str) +{ + if (screen_text_bmp == NULL) + screen_text_bmp = screen_get_picture(TEXT_FILE); + + for (int i = 0; str[i] != '\0'; i++) + screen_print_char( + scr, + x + (w != 0 ? i % w : i) * TEXT_W, + y + (w != 0 ? i / w : 0) * TEXT_H, + str[i]); +} + +void screen_text_centered(Screen scr, int x, int y, const char *str) +{ + int len = strlen(str); + screen_text_print(scr, x - len * TEXT_W / 2, y, 0, str); +} diff --git a/screen.h b/screen.h new file mode 100644 index 0000000..509e95e --- /dev/null +++ b/screen.h @@ -0,0 +1,200 @@ +/* + * screen.h -- Abstracción sobre SDL para la entrada y salida gráfica. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file screen.h Abstracción sobre SDL para la entrada y salida gráfica. + */ + +#ifndef __SCREEN_H +#define __SCREEN_H + +#include <SDL2/SDL.h> + +/** Representa una imagen. */ +typedef struct Picture *Picture; + +/** + * Representa una ventana de tamaño fijo sobre la que podemos dibujar. + */ +typedef struct Screen *Screen; + +/** Representa el inicio de una pulsación de tecla. Usado en + * screen_get_keyboard_event. + */ +#define SCREEN_KEYDOWN 1 + +/** Representa el final de una pulsación de tecla. Usado en + * screen_get_keyboard_event. + */ +#define SCREEN_KEYUP 2 + +/** Representa una imagen. */ +typedef struct Picture *Picture; + +/** Representa una ventana de tamaño fijo sobre la que podemos dibujar. + */ +typedef struct Screen *Screen; + +/** + * \brief Crea una ventana con la que el usuario puede interactuar. + * \param caption El título de la ventana. + * \param w Ancho de la ventana. + * \param h Alto de la ventana. + * \return La instancia del TDA Screen para manejar la ventana. + */ +Screen screen_create(const char *caption, int w, int h); + +/** + * \brief Libera un objeto Screen y cierra la ventana asociada. + * \param scr El objeto Screen a liberar. + */ +void screen_free(Screen scr); + +/** + * \brief Libera todos los recursos de SDL, que fueron alojados al llamar por + * primera vez a screen_create. + */ +void screen_end(); + +/** + * \brief Devuelve el ancho de la ventana. + * \param scr La ventana en cuestión. + * \return El ancho de la ventana. + */ +int screen_width(Screen scr); + +/** + * \brief Devuelve el alto de la ventana. + * \param src La ventana en cuesti&oactue;n. + * \return El alto de la ventana. + */ +int screen_height(Screen scr); + +/** + * \brief Pausa el programa durante una cantidad de tiempo determinada. + * \param ms La cantidad de tiempo a esperar. + */ +void screen_wait(int ms); + +/** + * \brief Actualiza el contenido de la ventana. Esta funci&oactue;n debe ser + * llamada una vez se ha terminado de dibujar en el objeto Screen para que los + * resultados sean visibles. + * \param scr La ventana en cuestión. + */ +void screen_update(Screen scr); + +/** + * \brief Comprueba si se ha pulsado (o dejado de pulsar) una tecla del + * teclado. + * \param sc Si es no nulo, se guarda qué tecla se ha pulsado. + * \return SCREEN_KEYDOWN si se ha pulsado una tecla, SCREEN_KEYUP si se + * ha dejado de pulsar o 0 si no ha ocurrido ninguna de las dos cosas. + * \remarks Esta función consume (e ignora) el resto de eventos que + * puedan ocurrir hasta dicha pulsación de tecla, salvo la + * notificación de cierre de ventana, que termina la aplicación. + */ +int screen_get_keyboard_event(SDL_Scancode *sc); + +/** + * \brief Comprueba si una tecla del teclado está siendo pulsada. + * \param scancode El código de la tecla en cuestión, véase + * <a href="https://wiki.libsdl.org/SDL_Scancode">SDL_Scancode</a> en la + * documentación de SDL para más información. + */ +int screen_key_pressed(SDL_Scancode scancode); + +/** + * \brief Llena una ventana con un color dado. + * \param scr La ventana en cuestión. + * \param r El componente rojo del color, de 0 a 255. + * \param g El componente verde del color, de 0 a 255. + * \param b El componente azul del color, de 0 a 255. + * \param a El nivel de opacidad, de 0 a 255. + */ +void screen_fill(Screen scr, int r, int g, int b, int a); + +/** + * \brief Copia una imagen (o un trozo de una) en una ventana. + * \param scr La ventana en cuestión. + * \param pict La imagenn en cuestión. + * \param x La coordenada X en la pantalla donde situar la esquina superior + * izquierda del trozo a copiar. + * \param y La coordenada Y en la pantalla donde situar la esquina superior + * izquierda del trozo a copiar. + * \param sx La coordenada X en la imagen de la esquina superior izquierda de + * lo que se ha de copiar. + * \param sy La coordenada Y en la imagen de la esquina superior izquierda de + * lo que se ha de copiar. + * \param w El ancho del trozo de la imagen a copiar. + * \param h El alto del trozo de la imagen a copiar. + * \param flipped Si es distinto de 0, la imagen se copia "en espejo" sobre el + * eje horizontal. De lo contrario se copia "normal". + * \remarks Si el cuadrado donde se ha de copiar la imagen queda fuera del + * área visible, la imagen no se muestra. Parte de la imagen puede salir + * del área visible, y entonces se copia solo la parte visible. + */ +void screen_place(Screen scr, Picture pict, int x, int y, int sx, int sy, + int w, int h, int flipped); + +/** + * \brief Carga una imagen desde un fichero. + * \param file La ruta del fichero. + * \return La imagen leída. + * \remarks El fichero debe ser una imagen BMP no comprimida. + */ +Picture screen_get_picture(const char *file); + +/** + * \brief Libera la memoria ocupada por una imagen. + * \param La imagen en cuestión. + */ +void screen_free_picture(Picture pict); + +/** + * \brief Imprime un texto en pantalla. + * \param scr La ventana en la que imprimir el texto. + * \param x La coordenada X en la pantalla donde irá la esquina superior + * izquierda del texto. + * \param y La coordenada Y en la pantalla donde irá la esquina superior + * izquierda del texto. + * \param w El ancho en número de caracteres del recuadro donde + * irá el texto. Si el texto es más largo que esto, se + * ocuparán más líneas en la pantalla según sea + * necesario. Si este parámetro es 0, se escribirá todo en la + * misma línea. + * \param str El texto a imprimir. + * \remarks El texto puede salir del área visible de la pantalla. El + * caracter . será sustituido por el signo de copyright. Algunos + * caracteres no están soportados. + */ +void screen_text_print(Screen scr, int x, int y, int w, const char *str); + +/** + * \brief Imprime un texto en pantalla, centrado en una cierta área. + * \param scr La ventana en la que imprimir el texto. + * \param x La coordenada horizontal en la que centrar el texto. + * \param y La coordenada vertical de lo que será el borde superior del + * texto en la ventana. + * \param str El texto a imprimir. + * \remarks El texto puede salir del área visible de la pantalla. El + * caracter . será sustituido por el signo de copyright. Algunos + * caracteres no están soportados. + */ +void screen_text_centered(Screen scr, int x, int y, const char *str); +#endif // __SCREEN_H @@ -0,0 +1,345 @@ +/* + * world.c -- Representación del estado del juego y carga del nivel. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include <malloc.h> +#include <stdio.h> +#include "block.h" +#include "block_list.h" +#include "collision.h" +#include "collision_type.h" +#include "error.h" +#include "item.h" +#include "item_list.h" +#include "screen.h" +#include "world.h" + +#define WORLD_BGCOLOR_R 128 +#define WORLD_BGCOLOR_G 128 +#define WORLD_BGCOLOR_B 255 +#define WORLD_BGCOLOR_A 255 + +struct World { + BlockList bl; + ItemList il; + Player p; + int scroll; + int dir; + int max_scroll; +}; + +struct WorldBlockDec { + BlockType type; // Block type + int ix; // X coordinate of the block in the picture (tiles) + int iy; // Y coordinate of the block in the picture (tiles) + int nanim; // Number of animation steps + int dx; // In world_block_dec, (dx,dy) is the size of the + int dy; // structure. In world_block_conts, this is the + // position of the block relative to the position of + // the first block defined in the structure. + int next; // Index of the next block in world_block_conts, + // or -1. +}; + +const struct WorldBlockDec world_block_dec[] = { + {BLOCK_TYPE_UPGRADE, 24, 0, 3, 1, 1, -1}, //a: Upgrade ? block + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 5, 5, 16}, //b: Castle + {BLOCK_TYPE_COIN, 2, 0, 1, 1, 1, -1}, //c: Simple coin block + {BLOCK_TYPE_DESTROYCOIN, 2, 0, 1, 1, 1, -1}, //d: Destroy coin block + {BLOCK_TYPE_COIN, 24, 0, 3, 1, 1, -1}, //e: Coin ? block + {BLOCK_TYPE_OPAQUE, 0, 0, 1, 1, 1, -1}, //f: Floor block + {BLOCK_TYPE_MULTICOIN, 2, 0, 1, 1, 1, -1}, //g: Multiple coin block + {BLOCK_TYPE_PASSTHROUGH, 8, 8, 1, 5, 3, 0}, //h: Hill + {BLOCK_TYPE_PASSTHROUGH, 8, 8, 1, 3, 2, 11}, //i: Small hill + {0, 16, 8, 1, 1, 1, -1}, //j: Nothing + {0, 16, 8, 1, 1, 1, -1}, //k: Nothing + {0, 16, 8, 1, 1, 1, -1}, //l: Nothing + {BLOCK_TYPE_PASSTHROUGH, 11, 9, 1, 1, 1, -1}, //m: Bush (left) + {BLOCK_TYPE_PASSTHROUGH, 12, 9, 1, 1, 1, -1}, //n: Bush (middle) + {BLOCK_TYPE_PASSTHROUGH, 13, 9, 1, 1, 1, -1}, //o: Bush (right) + {0, 16, 8, 1, 1, 1, -1}, //p: Nothing + {0, 16, 8, 1, 1, 1, -1}, //q: Nothing + {0, 16, 8, 1, 1, 1, -1}, //r: Nothing + {BLOCK_TYPE_OPAQUE, 0, 1, 1, 1, 1, -1}, //s: Stairs + {BLOCK_TYPE_OPAQUE, 0, 8, 1, 2, 1, 14}, //t: Tube (upper part) + {BLOCK_TYPE_OPAQUE, 0, 9, 1, 2, 1, 15}, //u: Tube (lower part) + {0, 16, 8, 1, 1, 1, -1}, //v: Nothing + {0, 16, 8, 1, 1, 1, -1}, //w: Nothing + {BLOCK_TYPE_PASSTHROUGH, 0, 21, 1, 1, 2, 8}, //x: Cloud (left) + {BLOCK_TYPE_PASSTHROUGH, 1, 21, 1, 1, 2, 9}, //y: Cloud (middle) + {BLOCK_TYPE_PASSTHROUGH, 2, 21, 1, 1, 1, 10}, //z: Cloud (right) +}, world_block_conts[] = { + {BLOCK_TYPE_PASSTHROUGH, 8, 8, 1, 1, 1, 1}, // Hill + {BLOCK_TYPE_PASSTHROUGH, 8, 9, 1, 1, 0, 2}, + {BLOCK_TYPE_PASSTHROUGH, 10, 9, 1, 3, 0, 3}, + {BLOCK_TYPE_PASSTHROUGH, 8, 9, 1, 2, 1, 4}, + {BLOCK_TYPE_PASSTHROUGH, 9, 9, 1, 2, 0, 5}, + {BLOCK_TYPE_PASSTHROUGH, 9, 8, 1, 2, 2, 6}, + {BLOCK_TYPE_PASSTHROUGH, 10, 8, 1, 3, 1, 7}, + {BLOCK_TYPE_PASSTHROUGH, 10, 8, 1, 4, 0, -1}, + {BLOCK_TYPE_PASSTHROUGH, 0, 20, 1, 0, 1, -1}, // Cloud (left) + {BLOCK_TYPE_PASSTHROUGH, 1, 20, 1, 0, 1, -1}, // Cloud (middle) + {BLOCK_TYPE_PASSTHROUGH, 2, 20, 1, 0, 1, -1}, // Cloud (right) + {BLOCK_TYPE_PASSTHROUGH, 8, 9, 1, 1, 0, 12}, // Small hill + {BLOCK_TYPE_PASSTHROUGH, 10, 8, 1, 2, 0, 13}, + {BLOCK_TYPE_PASSTHROUGH, 9, 8, 1, 1, 1, -1}, + {BLOCK_TYPE_OPAQUE, 1, 8, 1, 1, 0, -1}, // Tube (upper part) + {BLOCK_TYPE_OPAQUE, 1, 9, 1, 1, 0, -1}, // Tube (lower part) + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 1, 0, 17}, // Castle + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 0, 1, 18}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 1, 1, 19}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 3, 0, 20}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 3, 1, 21}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 4, 0, 22}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 4, 1, 23}, + {BLOCK_TYPE_PASSTHROUGH, 13, 1, 1, 2, 0, 24}, + {BLOCK_TYPE_PASSTHROUGH, 12, 1, 1, 2, 1, 25}, + {BLOCK_TYPE_PASSTHROUGH, 11, 0, 1, 0, 2, 26}, + {BLOCK_TYPE_PASSTHROUGH, 11, 1, 1, 1, 2, 27}, + {BLOCK_TYPE_PASSTHROUGH, 11, 1, 1, 2, 2, 28}, + {BLOCK_TYPE_PASSTHROUGH, 11, 1, 1, 3, 2, 29}, + {BLOCK_TYPE_PASSTHROUGH, 11, 0, 1, 4, 2, 30}, + {BLOCK_TYPE_PASSTHROUGH, 14, 0, 1, 1, 3, 31}, + {BLOCK_TYPE_PASSTHROUGH, 2, 0, 1, 2, 3, 32}, + {BLOCK_TYPE_PASSTHROUGH, 14, 0, 1, 3, 3, 33}, + {BLOCK_TYPE_PASSTHROUGH, 11, 0, 1, 1, 4, 34}, + {BLOCK_TYPE_PASSTHROUGH, 11, 0, 1, 2, 4, 35}, + {BLOCK_TYPE_PASSTHROUGH, 11, 0, 1, 3, 4, -1} +}; + +Player world_read_player(FILE *f) +{ + int x, y, lives; + + if (fscanf(f, " %i %i %i", &x, &y, &lives) != 3) + error_exit(ERR_INVALID_INPUT); + + return player_create(x * BLOCK_SIZE, y * BLOCK_SIZE, lives); +} + +Block world_block_from_dec(const struct WorldBlockDec *wbd, int x, int y) +{ + return block_create(wbd->type, x, y, wbd->ix, wbd->iy, wbd->nanim); +} + +void world_parse_one_block(char type, int x, int y, BlockList bl) +{ + const struct WorldBlockDec *wbd; + + wbd = &(world_block_dec[type - 'a']); + block_list_append(bl, world_block_from_dec(wbd, x, y)); + + while (wbd->next != -1) { + wbd = &world_block_conts[wbd->next]; + block_list_append(bl, + world_block_from_dec(wbd, x + wbd->dx, y + wbd->dy)); + } +} + +void world_parse_block(char type, int x, int y, int nx, int ny, + BlockList bl) +{ + int i, j, dx, dy; + const struct WorldBlockDec *wbd; + + if (type < 'a' || type > 'z') + error_exit(ERR_INVALID_INPUT); + + wbd = &(world_block_dec[type - 'a']); + dx = wbd->dx; + dy = wbd->dy; + + for (i = 0; i < nx; i++) + for (j = 0; j < ny; j++) + world_parse_one_block( + type, + x + dx*i, + y + dy*j, + bl); +} + +BlockList world_read_blocks(FILE *f) +{ + BlockList bl = block_list_create(); + char type; + int x, y, nx, ny, read; + while ((read = fscanf(f, " %c %i %i %i %i", &type, &x, &y, &nx, &ny)) + >= 3) { + if (read < 5) { + ny = 1; + if (read == 3) + nx = 1; + } + world_parse_block(type, x, y, nx, ny, bl); + } + return block_list_sort(bl); +} + +ItemType world_item_type(char c) +{ + switch (c) { + case 'g': + return ITEM_TYPE_GOOMBA; + case 'k': + return ITEM_TYPE_KOOPA; + case 'c': + return ITEM_TYPE_COIN; + default: + error_exit(ERR_INVALID_INPUT); + return 0; // Execution will never reach this point + } +} + +ItemList world_read_items(FILE *f) +{ + ItemList il = item_list_create(); + char type; + int x, y, read; + + while ((read = fscanf(f, " %c %i %i", &type, &x, &y)) == 3) + item_list_append(il, + item_create(world_item_type(type), + x * BLOCK_SIZE, + y * BLOCK_SIZE)); + + return il; +} + +World world_create(FILE *f) +{ + World w = malloc(sizeof(struct World)); + + if (w == NULL) + error_libc_exit(); + + w->p = world_read_player(f); + + if (fscanf(f, " %i", &w->max_scroll) != 1) + error_libc_exit(); + + w->max_scroll *= BLOCK_SIZE; + + w->bl = world_read_blocks(f); + w->il = world_read_items(f); + w->scroll = 0; + + return w; +} + +void world_free(World w) +{ + player_free(w->p); + block_list_free(w->bl); + item_list_free(w->il); + free(w); +} + +void world_end() +{ + block_end(); + item_end(); + player_end(); +} + +Player world_player(World w) +{ + return w->p; +} + +void world_substitute_player(World w, Player p) +{ + int x = player_x(w->p), y = player_y(w->p); + player_free(w->p); + w->p = p; + player_set_x(w->p, x); + player_set_y(w->p, y); +} + +WorldState world_play_frame(Screen scr, World w) +{ + SDL_Scancode sc; + int k; + char coins[7]; + + while ((k = screen_get_keyboard_event(&sc)) != 0) + if (k == SCREEN_KEYDOWN) + switch (sc) { + case SDL_SCANCODE_UP: + player_jump(w->p); + break; + case SDL_SCANCODE_LEFT: + w->dir = -1; + break; + case SDL_SCANCODE_RIGHT: + w->dir = 1; + break; + default: + ; + } + else if (k == SCREEN_KEYUP) + switch (sc) { + case SDL_SCANCODE_LEFT: + w->dir = screen_key_pressed(SDL_SCANCODE_RIGHT) + ? 1 : 0; + break; + case SDL_SCANCODE_RIGHT: + w->dir = screen_key_pressed(SDL_SCANCODE_LEFT) + ? -1 : 0; + break; + default: + ; + } + + switch(w->dir) { + case -1: + player_accel(w->p, 1); + break; + case 0: + player_stop(w->p); + break; + case 1: + player_accel(w->p, 0); + } + + player_update(w->p); + if (player_x(w->p) < w->scroll) + player_set_x(w->p, w->scroll); + if ((player_x(w->p) - w->scroll) * 2 > screen_width(scr)) + w->scroll = player_x(w->p) - screen_width(scr) / 2; + if ((player_y(w->p) + player_height(w->p)) < 0) + player_die(w->p); + + item_list_update(w->il, w->scroll, screen_width(scr)); + collision_player_with_blocks(w->p, w->bl, w->il); + collision_player_with_items(w->p, w->il); + collision_blocks_with_items(w->bl, w->il); + + screen_fill(scr, WORLD_BGCOLOR_R, WORLD_BGCOLOR_G, WORLD_BGCOLOR_B, + WORLD_BGCOLOR_A); + block_list_render(scr, w->bl, w->scroll); + item_list_render(scr, w->il, w->scroll); + player_render(scr, w->p, w->scroll); + + if (player_coins(w->p) >= 1000000) + return WORLD_ST_MANY_COINS; + sprintf(coins, "%06d", player_coins(w->p)); + screen_text_print(scr, 0, 0, 0, coins); + + screen_update(scr); + + return player_state(w->p) == PLAYER_ST_DEAD ? WORLD_ST_DEAD : + w->scroll >= w->max_scroll ? WORLD_ST_WON : WORLD_ST_KEEP_ON; +} @@ -0,0 +1,102 @@ +/* + * world.h -- Representación del estado del juego y carga del nivel. + * Copyright (C) 2018 Juan MarÃn Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * \file world.h Representación del estado del juego y carga del nivel. + */ + +#ifndef __WORLD_H +#define __WORLD_H + +#include <stdio.h> +#include "screen.h" + +/** Resultados de la llamada a world_play_frame, que indican el estado del + * mundo. + */ +typedef enum WorldState { + + /** Indica que la partida continúa normalmente. */ + WORLD_ST_KEEP_ON, + + /** Indica que el personaje ha muerto. */ + WORLD_ST_DEAD, + + /** Indica que el nivel ha sido superado. */ + WORLD_ST_WON, + + /** Indica que el juego ha sido superado por llegar al millón de + * monedas. + */ + WORLD_ST_MANY_COINS +} WorldState; + +/** Representa un mundo en el juego, con bloques, items, etc. */ +typedef struct World *World; + +/** + * \brief Crea un mundo del juego. + * \param f Flujo del fichero con la información del mundo. + * \return El mundo creado. + * \remarks El flujo debe haber sido abierto en un modo que permita la lectura. + * Una vez ejecutada esta función no es necesario mantener el flujo de + * fichero abierto. + */ +World world_create(FILE *f); + +/** + * \brief Libera un mundo del juego. + * \param w El mundo en cuestión. + */ +void world_free(World w); + +/** + * \brief Libera los recursos globales ocupados por el módulo, como las + * imágenes. + * \remarks Requiere ser llamada antes que a screen_end. +void world_end(); + */ +void world_end(); + +/** + * \brief Obtiene el personaje que juega en el nivel. + * \param w El nivel. + * \return El personaje. + */ +Player world_player(World w); + +/** + * \brief Sustituye el personaje actual en el mundo por el personaje dado, que + * establece en la posición ocupada por el anterior. + * \param w El mundo. + * \param p El nuevo personaje. + * \remarks Esta función libera la memoria ocupada por el personaje + * anterior del mundo. + */ +void world_substitute_player(World w, Player p); + +/** + * \brief Ejecuta un frame del mundo, en el que lee los eventos de teclado, + * actualiza el estado del mundo y lo dibuja en pantalla. + * \param scr La ventana donde dibujar el mundo. + * \param w El mundo en cuestión. + * \return Devuelve el estado actual de la partida. + */ +WorldState world_play_frame(Screen scr, World w); + +#endif // __WORLD_H |
