aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjacopo grandi <jak.sk8@hotmail.it>2021-02-18 14:14:23 +0100
committerjacopo grandi <jak.sk8@hotmail.it>2021-02-18 14:14:23 +0100
commit5f0fce4191309e9526b7109a0d87c092ce6a4193 (patch)
tree105257f876551814aa74a0760ec116bd1bf307a5
parentead78d51e662057467b79d3a65b20c4ba83cbf07 (diff)
main
-rw-r--r--README.md9
-rw-r--r--build/SDL2.dllbin0 -> 1471488 bytes
-rw-r--r--build/SDL2_mixer.dllbin0 -> 123904 bytes
-rw-r--r--build/army/army.txtbin0 -> 21528 bytes
-rw-r--r--build/army/army2.txtbin0 -> 21528 bytes
-rw-r--r--build/content/armor.txt57
-rw-r--r--build/content/augments.txt97
-rw-r--r--build/content/batteries.txt34
-rw-r--r--build/content/brains.txt20
-rw-r--r--build/content/chassis.txt180
-rw-r--r--build/content/gf.bmpbin0 -> 37978 bytes
-rw-r--r--build/content/sounds/mouse_click_0.wavbin0 -> 14566 bytes
-rw-r--r--build/content/sounds/mouse_over.wavbin0 -> 5916 bytes
-rw-r--r--build/content/sounds/mouse_wheel.wavbin0 -> 7778 bytes
-rw-r--r--build/content/sounds/success.wavbin0 -> 40854 bytes
-rw-r--r--build/content/sprites.bmpbin0 -> 1048726 bytes
-rw-r--r--build/content/sprites.pdnbin0 -> 30575 bytes
-rw-r--r--build/content/templates/default - Copy.txt52
-rw-r--r--build/content/templates/default.txt72
-rw-r--r--build/content/weapons.txt192
-rw-r--r--build/libplibsys.dllbin0 -> 482230 bytes
-rw-r--r--build/player.txt1
-rw-r--r--build/test.exebin0 -> 746614 bytes
-rw-r--r--design/components.txt130
-rw-r--r--design/design.txt58
-rw-r--r--design/notes.txt79
-rw-r--r--gst/gst.c82
-rw-r--r--gst/gst.h30
-rw-r--r--gst/info.c754
-rw-r--r--gst/info.h116
-rw-r--r--gst/map.c19
-rw-r--r--gst/map.h16
-rw-r--r--gst/units.c212
-rw-r--r--gst/units.h40
-rw-r--r--hud/hud.c788
-rw-r--r--hud/hud.h74
-rw-r--r--hud/hud_views.c380
-rw-r--r--hud/hud_views.h47
-rw-r--r--json/jsmn.h471
-rw-r--r--json/jsonparse.c167
-rw-r--r--json/jsonparse.h35
-rw-r--r--lcb.py61
-rw-r--r--main.c231
-rw-r--r--mkb/mkb.c53
-rw-r--r--mkb/mkb.h24
-rw-r--r--net/net.c168
-rw-r--r--net/net.h35
-rw-r--r--render/button.c21
-rw-r--r--render/button.h16
-rw-r--r--render/graphicsettings.h8
-rw-r--r--render/render_text.c48
-rw-r--r--render/render_text.h18
-rw-r--r--umath/intersect.c7
-rw-r--r--umath/intersect.h7
-rw-r--r--umath/vec.c42
-rw-r--r--umath/vec.h22
56 files changed, 4972 insertions, 1 deletions
diff --git a/README.md b/README.md
index 692f391..2234928 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,8 @@
-# arena \ No newline at end of file
+# hello
+
+in order to compile
+* have the sdl2 library at C:\MinGW_libs\include
+* have the pylibsys library at C:\MinGW_libs\include
+* have .a files in C:\MinGW_libs\libs
+
+run lcb (link compile build), build will be in build folder
diff --git a/build/SDL2.dll b/build/SDL2.dll
new file mode 100644
index 0000000..3131862
--- /dev/null
+++ b/build/SDL2.dll
Binary files differ
diff --git a/build/SDL2_mixer.dll b/build/SDL2_mixer.dll
new file mode 100644
index 0000000..40bb1c1
--- /dev/null
+++ b/build/SDL2_mixer.dll
Binary files differ
diff --git a/build/army/army.txt b/build/army/army.txt
new file mode 100644
index 0000000..ae1c3b5
--- /dev/null
+++ b/build/army/army.txt
Binary files differ
diff --git a/build/army/army2.txt b/build/army/army2.txt
new file mode 100644
index 0000000..ae1c3b5
--- /dev/null
+++ b/build/army/army2.txt
Binary files differ
diff --git a/build/content/armor.txt b/build/content/armor.txt
new file mode 100644
index 0000000..f418779
--- /dev/null
+++ b/build/content/armor.txt
@@ -0,0 +1,57 @@
+[
+ {
+ "name": "metal plating",
+ "weight": "50",
+ "pierce": "5", "spread": "8"
+ },
+ {
+ "name": "heavy metal plating",
+ "weight": "80",
+ "pierce": "7", "spread": "10", "impact": "5"
+ },
+ {
+ "name": "reflective plating",
+ "weight": "40",
+ "laser": "10"
+ },
+ {
+ "name": "heat resistent plating",
+ "weight": "50",
+ "fusion": "8"
+ },
+ {
+ "name": "padding",
+ "weight": "20",
+ "spread": "5", "impact": "8"
+ },
+ {
+ "name": "reactive armor",
+ "weight": "75",
+ "explosive": "12"
+ },
+ {
+ "name": "energy shields",
+ "weight": "25",
+ "pierce": "3", "spread": "3", "fusion": "3", "explosive": "3", "laser": "3"
+ },
+ {
+ "name": "composite armor",
+ "weight": "30",
+ "pierce": "6", "spread": "4", "impact": "3"
+ },
+ {
+ "name": "plastic armor",
+ "weight": "10",
+ "pierce": "4"
+ },
+ {
+ "name": "sloped steel armor",
+ "weight": "45",
+ "pierce": "10", "spread": "8"
+ },
+ {
+ "name": "charged armor",
+ "weight": "100",
+ "explosive": "25"
+ },
+] \ No newline at end of file
diff --git a/build/content/augments.txt b/build/content/augments.txt
new file mode 100644
index 0000000..c98e1d1
--- /dev/null
+++ b/build/content/augments.txt
@@ -0,0 +1,97 @@
+[
+ {
+ "name": "charged ammo",
+ "weight": "10",
+ "damage_emp": "5"
+ },
+ {
+ "name": "fusion ammo",
+ "weight": "10",
+ "damage_fusion": "4"
+ },
+ {
+ "name": "explosive ammo",
+ "weight": "30",
+ "armor_explosive": "8"
+ },
+ {
+ "name": "radiator",
+ "weight": "10",
+ "armor_fusion": "2"
+ },
+ {
+ "name": "priority module",
+ "weight": "0"
+ },
+ {
+ "name": "communication array",
+ "weight": "50",
+ "armor_pierce": "1",
+ "armor_impact": "1",
+ "armor_fusion": "1",
+ "aoe": "2"
+ },
+ {
+ "name": "long range targeting",
+ "weight": "0",
+ "add_range": "1"
+ },
+ {
+ "name": "long range targeting",
+ "weight": "0",
+ "range": "1"
+ },
+ {
+ "name": "fast target acquisition",
+ "weight": "5",
+ "add_cooldown": "-0.1"
+ },
+ {
+ "name": "overcharger",
+ "weight": "10",
+ "damage_laser": "8",
+ "recharge": "-5"
+ },
+ {
+ "name": "focus lens",
+ "weight": "3",
+ "damage_laser": "3"
+ },
+ {
+ "name": "amplifier",
+ "weight": "30",
+ "damage_laser": "3",
+ "damage_fusion": "5"
+ },
+ {
+ "name": "shrapnel",
+ "weight": "5",
+ "damage_explosive": "5"
+ },
+ {
+ "name": "reloader",
+ "weight": "40",
+ "add_cooldown": "-0.1"
+ },
+ {
+ "name": "anti jamming device",
+ "weight": "2",
+ "armor_emp": "5"
+ },
+ {
+ "name": "weight stripping",
+ "weight": "-10",
+ "add_hp": "-10"
+ },
+ {
+ "name": "barebone weapon setup",
+ "weight": "-30",
+ "damage_pierce": "-25",
+ "damage_laser": "-25",
+ "damage_impact": "-25",
+ "damage_fusion": "-25",
+ "damage_explosive": "-25",
+ "damage_emp": "-25",
+ "damage_spread": "-25"
+ }
+] \ No newline at end of file
diff --git a/build/content/batteries.txt b/build/content/batteries.txt
new file mode 100644
index 0000000..fe5da27
--- /dev/null
+++ b/build/content/batteries.txt
@@ -0,0 +1,34 @@
+[
+ {
+ "name": "small alkaline pack",
+ "weight": "0", "capacity": "50"
+ },
+ {
+ "name": "big alkaline pack",
+ "weight": "2", "capacity": "200"
+ },
+ {
+ "name": "small lithium pack",
+ "weight": "5", "capacity": "150", "recharge": "1"
+ },
+ {
+ "name": "big lithium pack",
+ "weight": "15", "capacity": "500", "recharge": "1"
+ },
+ {
+ "name": "lead battery",
+ "weight": "20", "capacity": "800", "recharge": "1"
+ },
+ {
+ "name": "small molten salt battery",
+ "weight": "40", "capacity": "1500", "recharge": "1"
+ },
+ {
+ "name": "big molten salt battery",
+ "weight": "70", "capacity": "2000", "recharge": "1"
+ },
+ {
+ "name": "atomic battery",
+ "weight": "150", "capacity": "10000"
+ }
+] \ No newline at end of file
diff --git a/build/content/brains.txt b/build/content/brains.txt
new file mode 100644
index 0000000..c9bb4b5
--- /dev/null
+++ b/build/content/brains.txt
@@ -0,0 +1,20 @@
+[
+ {
+ "name": "search and destroy"
+ },
+ {
+ "name": "follower"
+ },
+ {
+ "name": "defensive"
+ },
+ {
+ "name": "kamikaze"
+ },
+ {
+ "name": "run and gun"
+ },
+ {
+ "name": "flank"
+ }
+] \ No newline at end of file
diff --git a/build/content/chassis.txt b/build/content/chassis.txt
new file mode 100644
index 0000000..e4643c2
--- /dev/null
+++ b/build/content/chassis.txt
@@ -0,0 +1,180 @@
+[
+ {
+ "name": "light two legged bot",
+ "slot_weapon": "1",
+ "slot_armor": "0",
+ "slot_aug": "1",
+ "weight_max": "20",
+ "hp": "100",
+ "speed": "1.5"
+ },
+ {
+ "name": "heavy two legged bot",
+ "slot_weapon": "1",
+ "slot_armor": "1",
+ "slot_aug": "3",
+ "weight_max": "45",
+ "hp": "350",
+ "speed": "1"
+ },
+ {
+ "name": "light four legged bot",
+ "slot_weapon": "2",
+ "slot_armor": "1",
+ "slot_aug": "2",
+ "weight_max": "50",
+ "hp": "400",
+ "speed": "1"
+ },
+ {
+ "name": "heavy four legged bot",
+ "slot_weapon": "2",
+ "slot_armor": "2",
+ "slot_aug": "5",
+ "weight_max": "150",
+ "hp": "1200",
+ "speed": "0.67"
+ },
+ {
+ "name": "light six legged bot",
+ "slot_weapon": "2",
+ "slot_armor": "2",
+ "slot_aug": "3",
+ "weight_max": "210",
+ "hp": "640",
+ "speed": "1"
+ },
+ {
+ "name": "heavy six legged bot",
+ "slot_weapon": "2",
+ "slot_armor": "4",
+ "slot_aug": "6",
+ "weight_max": "300",
+ "hp": "1500",
+ "speed": "1"
+ },
+ {
+ "name": "light buggy",
+ "slot_weapon": "1",
+ "slot_armor": "1",
+ "slot_aug": "1",
+ "weight_max": "50",
+ "hp": "200",
+ "speed": "1"
+ },
+ {
+ "name": "buggy",
+ "slot_weapon": "2",
+ "slot_armor": "2",
+ "slot_aug": "2",
+ "weight_max": "150",
+ "hp": "400",
+ "speed": "1"
+ },
+ {
+ "name": "light wheeled vehicle",
+ "slot_weapon": "1",
+ "slot_armor": "0",
+ "slot_aug": "2",
+ "weight_max": "60",
+ "hp": "320",
+ "speed": "1",
+ "recharge": "0.3"
+ },
+ {
+ "name": "medium wheeled vehicle",
+ "slot_weapon": "2",
+ "slot_armor": "2",
+ "slot_aug": "3",
+ "weight_max": "200",
+ "hp": "720",
+ "speed": "1",
+ "recharge": "0.2"
+ },
+ {
+ "name": "heavy wheeled vehicle",
+ "slot_weapon": "2",
+ "slot_armor": "4",
+ "slot_aug": "4",
+ "weight_max": "270",
+ "hp": "950",
+ "speed": "1",
+ "recharge": "0.2"
+ },
+ {
+ "name": "light tank",
+ "slot_weapon": "1",
+ "slot_armor": "3",
+ "slot_aug": "2",
+ "weight_max": "300",
+ "hp": "700",
+ "speed": "1",
+ "recharge": "0.4"
+ },
+ {
+ "name": "medium tank",
+ "slot_weapon": "1",
+ "slot_armor": "4",
+ "slot_aug": "4",
+ "weight_max": "400",
+ "hp": "1250",
+ "speed": "1",
+ "recharge": "0.5"
+ },
+ {
+ "name": "heavy tank",
+ "slot_weapon": "2",
+ "slot_armor": "5",
+ "slot_aug": "5",
+ "weight_max": "450",
+ "hp": "1600",
+ "speed": "1"
+ },
+ {
+ "name": "super heavy tank",
+ "slot_weapon": "3",
+ "slot_armor": "6",
+ "slot_aug": "6",
+ "weight_max": "500",
+ "hp": "2000",
+ "speed": "1"
+ },
+ {
+ "name": "hovercraft",
+ "slot_weapon": "2",
+ "slot_armor": "0",
+ "slot_aug": "3",
+ "weight_max": "40",
+ "hp": "300",
+ "speed": "1",
+ "recharge": "-0.2"
+ },
+ {
+ "name": "jet floater",
+ "slot_weapon": "1",
+ "slot_armor": "0",
+ "slot_aug": "2",
+ "weight_max": "30",
+ "hp": "60",
+ "speed": "1"
+ },
+ {
+ "name": "one wheeler",
+ "slot_weapon": "1",
+ "slot_armor": "0",
+ "slot_aug": "4",
+ "weight_max": "15",
+ "hp": "40",
+ "speed": "1"
+ },
+ {
+ "name": "armored crawler",
+ "slot_weapon": "1",
+ "slot_armor": "4",
+ "slot_aug": "2",
+ "weight_max": "200",
+ "hp": "750",
+ "speed": "1",
+ "recharge": "-0.4"
+ }
+] \ No newline at end of file
diff --git a/build/content/gf.bmp b/build/content/gf.bmp
new file mode 100644
index 0000000..85cd3e2
--- /dev/null
+++ b/build/content/gf.bmp
Binary files differ
diff --git a/build/content/sounds/mouse_click_0.wav b/build/content/sounds/mouse_click_0.wav
new file mode 100644
index 0000000..1dd4ab1
--- /dev/null
+++ b/build/content/sounds/mouse_click_0.wav
Binary files differ
diff --git a/build/content/sounds/mouse_over.wav b/build/content/sounds/mouse_over.wav
new file mode 100644
index 0000000..93114d2
--- /dev/null
+++ b/build/content/sounds/mouse_over.wav
Binary files differ
diff --git a/build/content/sounds/mouse_wheel.wav b/build/content/sounds/mouse_wheel.wav
new file mode 100644
index 0000000..1bca54d
--- /dev/null
+++ b/build/content/sounds/mouse_wheel.wav
Binary files differ
diff --git a/build/content/sounds/success.wav b/build/content/sounds/success.wav
new file mode 100644
index 0000000..409fe49
--- /dev/null
+++ b/build/content/sounds/success.wav
Binary files differ
diff --git a/build/content/sprites.bmp b/build/content/sprites.bmp
new file mode 100644
index 0000000..509189f
--- /dev/null
+++ b/build/content/sprites.bmp
Binary files differ
diff --git a/build/content/sprites.pdn b/build/content/sprites.pdn
new file mode 100644
index 0000000..1775674
--- /dev/null
+++ b/build/content/sprites.pdn
Binary files differ
diff --git a/build/content/templates/default - Copy.txt b/build/content/templates/default - Copy.txt
new file mode 100644
index 0000000..15a5c57
--- /dev/null
+++ b/build/content/templates/default - Copy.txt
@@ -0,0 +1,52 @@
+[
+ {
+ "name": "tank",
+ "chassis": "5",
+ "brain": "1",
+ "battery": "1",
+ "weapons": [ 1, 1, 4, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "tank2",
+ "chassis": "14",
+ "brain": "2",
+ "battery": "2",
+ "weapons": [ 1, 1, 4, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "14",
+ "brain": "5",
+ "battery": "1",
+ "weapons": [ 36, 12, 10, -1, -1, -1, -1, -1 ],
+ "armor": [ 10, 7, 10, 4, 3, 4, -1, -1 ],
+ "augs": [ 3, 4, 3, 2, 1, 3, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "13",
+ "brain": "1",
+ "battery": "4",
+ "weapons": [ 3, 35, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ 3, 2, 1, 4, 4, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "3",
+ "brain": "3",
+ "battery": "3",
+ "weapons": [ 2, 2, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ }
+] \ No newline at end of file
diff --git a/build/content/templates/default.txt b/build/content/templates/default.txt
new file mode 100644
index 0000000..7ec433c
--- /dev/null
+++ b/build/content/templates/default.txt
@@ -0,0 +1,72 @@
+[
+ {
+ "name": "tank",
+ "chassis": "5",
+ "brain": "1",
+ "battery": "1",
+ "weapons": [ 1, 1, 4, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "tank2",
+ "chassis": "14",
+ "brain": "2",
+ "battery": "2",
+ "weapons": [ 1, 1, 4, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "14",
+ "brain": "5",
+ "battery": "1",
+ "weapons": [ 36, 12, 10, -1, -1, -1, -1, -1 ],
+ "armor": [ 10, 7, 10, 4, 3, 4, -1, -1 ],
+ "augs": [ 3, 4, 3, 2, 1, 3, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "13",
+ "brain": "1",
+ "battery": "4",
+ "weapons": [ 3, 35, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ 3, 2, 1, 4, 4, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "3",
+ "brain": "3",
+ "battery": "3",
+ "weapons": [ 2, 2, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ 9, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "11",
+ "brain": "1",
+ "battery": "1",
+ "weapons": [ 0, -1, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ 9, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ },
+ {
+ "name": "nameless",
+ "chassis": "17",
+ "brain": "0",
+ "battery": "0",
+ "weapons": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "armor": [ -1, -1, -1, -1, -1, -1, -1, -1 ],
+ "augs": [ 16, -1, -1, -1, -1, -1, -1, -1 ],
+ "levels": [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+ }
+] \ No newline at end of file
diff --git a/build/content/weapons.txt b/build/content/weapons.txt
new file mode 100644
index 0000000..f4b3b2b
--- /dev/null
+++ b/build/content/weapons.txt
@@ -0,0 +1,192 @@
+[
+ {
+ "name": "smg",
+ "damage_type": "pierce", "weight": "10", "cooldown": "1",
+ "damage": "10", "range": "4"
+ },
+ {
+ "name": "machinegun",
+ "damage_type": "pierce", "weight": "25", "cooldown": "1",
+ "damage": "15", "range": "5"
+ },
+ {
+ "name": "heavy machinegun",
+ "damage_type": "pierce", "weight": "40", "cooldown": "1",
+ "damage": "20", "range": "5"
+ },
+ {
+ "name": "semi autocannon",
+ "damage_type": "pierce", "weight": "70", "cooldown": "2",
+ "damage": "32", "range": "6"
+ },
+ {
+ "name": "autocannon",
+ "damage_type": "pierce", "weight": "100", "cooldown": "1",
+ "damage": "40", "range": "6"
+ },
+ {
+ "name": "high velocity cannon",
+ "damage_type": "pierce", "weight": "120", "cooldown": "4",
+ "damage": "250", "range": "7"
+ },
+ {
+ "name": "scrap gun",
+ "damage_type": "spread", "weight": "5", "cooldown": "2",
+ "damage": "8", "range": "3"
+ },
+ {
+ "name": "burst cannon",
+ "damage_type": "spread", "weight": "15", "cooldown": "2",
+ "damage": "25", "range": "4"
+ },
+ {
+ "name": "heavy burst cannon",
+ "damage_type": "spread", "weight": "30", "cooldown": "2",
+ "damage": "40", "range": "5"
+ },
+ {
+ "name": "maul",
+ "damage_type": "impact", "weight": "200", "cooldown": "3",
+ "damage": "400", "range": "1", "knockback": "2"
+ },
+ {
+ "name": "slam",
+ "damage_type": "impact", "weight": "0", "cooldown": "1",
+ "damage": "6", "range": "1"
+ },
+ {
+ "name": "warhammer",
+ "damage_type": "impact", "weight": "40", "cooldown": "1",
+ "damage": "60", "range": "1", "knockback": "1"
+ },
+ {
+ "name": "rocket",
+ "damage_type": "explosive", "weight": "60", "cooldown": "3",
+ "damage": "100", "range": "8"
+ },
+ {
+ "name": "rocket swarm",
+ "damage_type": "explosive", "weight": "120", "cooldown": "3",
+ "damage": "60", "range": "7", "aoe": "2"
+ },
+ {
+ "name": "tactical rocket",
+ "damage_type": "explosive", "weight": "160", "cooldown": "1",
+ "damage": "100", "range": "8", "aoe": "1"
+ },
+ {
+ "name": "nuclear rocket",
+ "damage_type": "explosive", "weight": "200", "cooldown": "6",
+ "damage": "300", "range": "9", "aoe": "3"
+ },
+ {
+ "name": "light laser",
+ "damage_type": "laser", "weight": "20", "cooldown": "1",
+ "damage": "8", "range": "5"
+ },
+ {
+ "name": "combined light laser",
+ "damage_type": "laser", "weight": "50", "cooldown": "1",
+ "damage": "20", "range": "6"
+ },
+ {
+ "name": "heavy laser",
+ "damage_type": "laser", "weight": "130", "cooldown": "1",
+ "damage": "45", "range": "6"
+ },
+ {
+ "name": "combined heavy laser",
+ "damage_type": "laser", "weight": "300", "cooldown": "1",
+ "damage": "150", "range": "7"
+ },
+ {
+ "name": "plasma cannon",
+ "damage_type": "fusion", "weight": "80", "cooldown": "2",
+ "damage": "125", "range": "5"
+ },
+ {
+ "name": "plasma autocannon",
+ "damage_type": "fusion", "weight": "170", "cooldown": "1",
+ "damage": "110", "range": "5"
+ },
+ {
+ "name": "plasma artillery",
+ "damage_type": "fusion", "weight": "200", "cooldown": "3",
+ "damage": "100", "range": "7", "aoe": "2"
+ },
+ {
+ "name": "fusion blade",
+ "damage_type": "fusion", "weight": "15", "cooldown": "1",
+ "damage": "15", "range": "1"
+ },
+ {
+ "name": "fusion lance",
+ "damage_type": "fusion", "weight": "50", "cooldown": "1",
+ "damage": "45", "range": "2"
+ },
+ {
+ "name": "light railgun",
+ "damage_type": "impact", "weight": "50", "cooldown": "2",
+ "damage": "90", "range": "6"
+ },
+ {
+ "name": "heavy railgun",
+ "damage_type": "impact", "weight": "190", "cooldown": "3",
+ "damage": "450", "range": "7"
+ },
+ {
+ "name": "supercharged railgun",
+ "damage_type": "impact", "weight": "240", "cooldown": "4",
+ "damage": "1000", "range": "8"
+ },
+ {
+ "name": "discharge beam",
+ "damage_type": "emp", "weight": "40", "cooldown": "2",
+ "damage_battery": "3", "range": "4"
+ },
+ {
+ "name": "haywire beam",
+ "damage_type": "emp", "weight": "50", "cooldown": "5",
+ "damage": "80", "damage_battery": "5", "range": "6"
+ },
+ {
+ "name": "stun beam",
+ "damage_type": "emp", "weight": "80", "cooldown": "5",
+ "stun": "1", "range": "4"
+ },
+ {
+ "name": "amplified discharge impulse",
+ "damage_type": "emp", "weight": "150", "cooldown": "3",
+ "damage_battery": "10", "range": "5", "aoe": "1"
+ },
+ {
+ "name": "amplified haywire beam",
+ "damage_type": "emp", "weight": "120", "cooldown": "5",
+ "damage": "200", "damage_battery": "12", "range": "6"
+ },
+ {
+ "name": "amplified stun beam",
+ "damage_type": "emp", "weight": "200", "cooldown": "6",
+ "stun": "1", "range": "4"
+ },
+ {
+ "name": "ion cannon",
+ "damage_type": "emp", "weight": "75", "cooldown": "2",
+ "reduce_fusion": "1", "reduce_laser": "1", "range": "5"
+ },
+ {
+ "name": "heavy ion cannon",
+ "damage_type": "emp", "weight": "150", "cooldown": "1",
+ "reduce_fusion": "1", "reduce_laser": "1", "range": "6"
+ },
+ {
+ "name": "explosive charges",
+ "damage_type": "explosive", "weight": "5", "cooldown": "10",
+ "damage": "100", "range": "0", "aoe": "2"
+ },
+ {
+ "name": "javelin",
+ "damage_type": "explosive", "weight": "60", "cooldown": "2",
+ "damage": "40", "range": "7"
+ }
+] \ No newline at end of file
diff --git a/build/libplibsys.dll b/build/libplibsys.dll
new file mode 100644
index 0000000..2d3f0d9
--- /dev/null
+++ b/build/libplibsys.dll
Binary files differ
diff --git a/build/player.txt b/build/player.txt
new file mode 100644
index 0000000..a0fa615
--- /dev/null
+++ b/build/player.txt
@@ -0,0 +1 @@
+The Nameless One \ No newline at end of file
diff --git a/build/test.exe b/build/test.exe
new file mode 100644
index 0000000..ebb5f5e
--- /dev/null
+++ b/build/test.exe
Binary files differ
diff --git a/design/components.txt b/design/components.txt
new file mode 100644
index 0000000..650da5a
--- /dev/null
+++ b/design/components.txt
@@ -0,0 +1,130 @@
+components have levels (maxelevel field, log stats or exp stats or logistic stats?)
+
+brain: (bonus augments slots only for brain augs)
+state machine
+weak supervised learner
+strong supervised learner
+weak self learner
+strong self learner
+general ai
+
+.chassis: (slots for weapon, battery, armor, augments), max weight, *hp
+light two legged bot (1, 0, 1), 20
+heavy two legged bot (1, 1, 3), 45
+light four legged bot (2, 1, 2), 50
+heavy four legged bot (2, 2, 5), 150
+light six legged bot (2, 2, 3), 210
+heavy six legged bot (2, 4, 6), 300
+light buggy (1, 1, 1), 50
+buggy (2, 2, 2), 150
+light wheeled vehicle (1, 0, 2), 60
+medium wheeled vehicle (2, 2, 3), 200
+heavy wheeled vehicle (2, 4, 4), 270
+light tank (1, 3, 2), 300
+medium tank (1, 4, 4), 400
+heavy tank (2, 5, 5), 450
+super heavy tank (3, 6, 6), 500
+hovercraft (2, 0, 3), 40
+jet floater (1, 0, 2), 30
+one wheeler (1, 0, 4), 15
+armored crawler (1, 4, 2), 200
+motorcycle bot (1, 1, 1), 30
+
+.batteries: weight
+small alkaline pack (not rech), 3
+big alkaline pack (not rech), 10
+small lithium pack, 5
+big lithium pack, 15
+lead battery, 20
+small molten salt battery (military use), 40
+big molten salt battery (military use), 70
+atomic battery (not rech), 150
+
+.weapons: (type), weight, damage, range, cooldown, knockback, aoe
+smg (pierce), 10
+machinegun (pierce), 25
+heavy machinegun (pierce), 40
+semi autocannon (pierce), 70
+autocannon (pierce), 100
+high velocity cannon (pierce), 120
+scrap gun (spread), 5
+burst cannon (spread), 15
+heavy burst cannon (spread), 30
+maul (impact), 200
+slam (impact), 0
+warhammer (impact), 40
+rocket (explosive), 60
+rocket swarm (explosive), 120
+tactical rocket (explosive), 160
+nuclear rocket (explosive), 200
+light laser (laser), 20
+combined light laser (laser), 50
+heavy laser (laser), 130
+combined heavy laser (laser), 300
+plasma cannon (fusion), 80
+plasma autocannon (fusion), 170
+plasma artillery (fusion), 200
+fusion blade (fusion), 15
+fusion lance (fusion), 50
+light railgun (impact), 50
+heavy railgun (impact), 190
+supercharged railgun (impact), 240
+discharge beam (battery dmg), 40
+haywire beam (battery dmg and damage), 50
+stun beam (disables target), 80
+amplified haywire beam, 120
+amplified discharge impulse (aoe on target), 150
+amplified stun beam, 200
+ion cannon (reduces fusion and laser armor), 75
+heavy ion cannon (reduces fusion and laser armor), 150
+body explosives (explosive), 5
+
+.armor:
+metal plating (pierce and spread armor), 50
+heavy metal plating (pierce, spread and impact armor), 80
+reflective plating (laser armor), 40
+heat resistent plating (fusion armor), 50
+padding (spread and impact armor), 20
+reactive armor (explosive armor), 75
+energy shields (overall armor but kinetic), 25
+composite armor (pierce, spread and impact armor), 30
+plastic armor (pierce armor), 10
+sloped armor (pierce, spread armor), 45
+charged armor (explosive armor), 100
+
+augments:
+charged ammo (% emp damage)
+extra radiator (better fusion armor), 10
+priority module (attacks the most costly), 2
+communication array (improves armor of adjacent units), 5
+long range targeting (better range), 1
+fast target acquisition (better cooldown), 3
+overcharger (better laser damage, more battery use), 10
+focus lens (better laser damage), 3
+amplifier (better fusion and laser damage), 30
+shrapnel (better explosive damage), 5
+reloader (better cooldown), 40
+antijammer (stun resistance %), 5
+fusion ammo (% damage is fusion), 10
+stability module (if bot, faster), 20
+torque boost (if wheeled vehicle or tank, +speed), 50
+weight stripping (additional weight +base%10, less hp), 0
+barebone gadgets (additional weight +base%15, less damage), 0
+
+--engines (actuators):
+servos, 5
+brushless, 10
+hydraulics, 30
+diesel engine (vehicles), 60
+hydrogen engine (vehicles), 100
+
+--powergens:
+small diesel engine, 20
+medium diesel engine, 50
+big diesel engine, 120
+small hydrogen engine, 2
+medium hydrogen engine, 25
+big hydrogen engine, 60
+solar panels, 10
+nuclear power core, 100
+critical nuclear power core, 200 \ No newline at end of file
diff --git a/design/design.txt b/design/design.txt
new file mode 100644
index 0000000..b4ee2fc
--- /dev/null
+++ b/design/design.txt
@@ -0,0 +1,58 @@
+descript: arena clone + autochess
+
+turn: move+attack
+
+
+unit design space:
+dps ranged
+dps melee
+tanks
+knockback
+snipers
+aoe
+healers
+slowers
+stunners
+kamikazes
+attrition (battery damage)
+commanders
+
+
+units composition:
+component robots, they are made of components
+basic bot: brain, chassis, weapon, batteries.
+.brain
+.chassis
+ .locomotion
+ --motors (what are they needed for? actuators, meeeeh) meeeeeeeh
+ weapons slots
+ battery slots
+ augments slots
+ armor slots
+.batteries
+.powergens
+.armor (set of floats for every damage type)
+.weapons
+.augments (sensors, ai enhancers (priority targeting, tactics))
+
+
+units stats:
+damage (float)
+damage type
+ pierce bullet
+ impact
+ spread
+ explosive
+ laser
+ fusion
+ emp
+armor (set of floats derived from chassis and armor slots and augments)
+reload (turns in between shots)
+speed (turn in between movement)
+
+
+further expansion:
+roguelike (1-3 hrs runs, build an army along the way and fight 50 times to win)
+rpg (5-30 hrs, long game with map and npcs a story and whatnot)
+long rogue (1-10 hrs, open ended roguelike, infinite battles, map)
+^ those but multiplayer (yikes for devtime but nice for lols) up to 8 ppl tcp
diff --git a/design/notes.txt b/design/notes.txt
new file mode 100644
index 0000000..bace25c
--- /dev/null
+++ b/design/notes.txt
@@ -0,0 +1,79 @@
+tasks: (commit number)
+
+[x] implement rm unit (issued on 6, done on 6)
+[x] implement armor calculation (issued on 6, done on 6)
+[x] implement augment calculations (issued on 6, done on 6)
+[x] implement augment hud view (issued on 6, done on 6)
+[ ] implement sound (issued on 6)
+[ ] implement stats hud view (issued on 6)
+[ ] implement battery calculation (issued on 6)
+[ ] implement brain behaviour (issued on 6)
+[ ] implement component levels (issued on 6)
+[ ] implement persistent settings (issued on 6)
+[ ] implement net hud and minilobby (issued on 6)
+[ ] implement army hud view (issued on 6)
+[ ] implement cost function (issued on 6)
+[ ] implement lobby cost constraints (issued on 6)
+[ ] implement edit unit directly (issued on 6)
+[ ] implement naming template and army (issued on 6)
+[ ] implement move animation (issued on 6)
+[ ] implement fire animation (issued on 6)
+[ ] implement explosions (issued on 6)
+[ ] design 3d units (issued on 6)
+[ ] design 3d map tiles (issued on 6)
+[ ] implement 3d units (issued on 6)
+[ ] design component sprites (issued on 6)
+
+
+bugs:
+
+[ ] symmetric integration (found on 6)
+ (on army movement and fire, equal armies should fair equally)
+
+
+testing:
+
+[ ] armor calculations (issued on 6)
+
+
+balance:
+
+[ ] balance components (issued on 6)
+
+
+view from 6 to the end:
+ game is make templates, assemble for army, fight other army
+ multiplayer up to 2 ppl
+ armies, templates and settings are persistent
+
+
+
+details:
+
+implement rm unit: -> done, paper note solution
+
+implement armor calculation:
+ consider bonuses for damage reduction
+ aggregate them and spit out a percentage
+ editor remove units funct to make it possible to have a test case
+ army has to rebuild grid ref on load
+-> done, barely tested
+
+implement augment calculation:
+ there are a lot of bonuses to keep track. do one at a time.
+ ok add_armor as a malus %
+ ok add_damage (only if same damage type weapon) as a bonus %
+ ok add_range as a fixed sum
+ ok add_cooldown
+ ok add_hp
+ ok add_speed
+-> done, not tested
+
+implement stats hud view:
+? stats have to include individual weapon cooldowns and damage, what to do
+ either put all as lines in stats (clean, but ugly)
+ or modify the components directly (messy)
+! put them in stats later
+
+implement sound:
+ partially done, need sound design \ No newline at end of file
diff --git a/gst/gst.c b/gst/gst.c
new file mode 100644
index 0000000..56db22f
--- /dev/null
+++ b/gst/gst.c
@@ -0,0 +1,82 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+
+#include <gst.h>
+
+void gst_init (gamestate *gst) {
+ map_init(&gst->map_editor, MAXMAP, MAXMAP, 32);
+ army_init(gst->army_bp, &gst->map_editor);
+ gst->playernum = 1;
+ gst->state = 0;
+ gst->starttime = FLT_MAX;
+ gst->turn = 0;
+ gst->coveredtime = 0;
+ gst->turnspeed = 0.35f;
+}
+
+void gst_destroy (gamestate *gst) {
+ army_destory(gst->army_bp+0);
+ map_destroy(&gst->map_editor);
+}
+
+void gst_get_maparmy(gamestate *gst, map **m, army **ar) {
+ if (gst->state == 0) {
+ *m = &gst->map_editor;
+ *ar = gst->army_bp+0;
+ }
+ if (gst->state == 1) {
+ *m = &gst->map_battle;
+ *ar = &gst->ar;
+ }
+}
+
+void gst_tobattle (gamestate *gst) {
+ if (gst->playernum == 1) {
+ //info_load_army(gst->army_bp+1, "army");
+ gst->army_bp[1] = gst->army_bp[0];
+ gst->playernum = 2;
+ }
+ gst->state = 1;
+ int maxx = MAXMAP, maxy = MAXMAP;
+ int dx = 5, dy = 10;
+ int sx = dx*2+maxx, sy = dy+maxy*2;
+ map_init(&gst->map_battle, sx, sy, 32);
+ army_init(&gst->ar, &gst->map_battle);
+ unit u;
+ for (int i=0; i<gst->playernum; i++) {
+ for (int j=0; j<gst->army_bp[i].uslen; j++) {
+ u = gst->army_bp[i].us[j];
+ u.owner = i;
+ if (i==0) {
+ u.gridpos[0] += dx;
+ u.gridpos[1] += dy+maxy;
+ }
+ if (i==1) {
+ u.gridpos[0] = maxx-u.gridpos[0]+dx;
+ u.gridpos[1] = maxy-u.gridpos[1];
+ }
+ u.pos[0] = u.gridpos[0]*gst->map_battle.ts;
+ u.pos[1] = u.gridpos[1]*gst->map_battle.ts;
+ army_spawn(&gst->ar, &gst->map_battle, u);
+ gst->ar.us[gst->ar.uslen].owner = i;
+ }
+ }
+ gst->starttime = FLT_MAX;
+ gst->turn = 0;
+ gst->coveredtime = 0;
+}
+
+void gst_process (gamestate *gst, infos *info, float t) {
+ if (gst->starttime > t) gst->starttime = t;
+ float t_elapsed = t-gst->starttime;
+ if (t_elapsed > gst->coveredtime) {
+ gst->coveredtime += gst->turnspeed;
+ gst->turn ++;
+ map *m; army *ar;
+ gst_get_maparmy(gst, &m, &ar);
+ army_move(info, ar, m);
+ army_fire(info, ar, m);
+ }
+} \ No newline at end of file
diff --git a/gst/gst.h b/gst/gst.h
new file mode 100644
index 0000000..8acb699
--- /dev/null
+++ b/gst/gst.h
@@ -0,0 +1,30 @@
+#ifndef GST_H
+#define GST_H
+
+#include <info.h>
+#include <units.h>
+#include <map.h>
+
+#define MAXMAP 10
+
+typedef struct {
+ map map_editor;
+ army army_bp[8];
+ int playernum;
+ map map_battle;
+ army ar;
+ int state;
+ float cam[2];
+ float starttime;
+ float coveredtime;
+ int turn;
+ float turnspeed;
+} gamestate;
+
+void gst_init (gamestate *gst);
+void gst_destroy (gamestate *gst);
+void gst_get_maparmy(gamestate *gst, map **m, army **ar);
+void gst_tobattle (gamestate *gst);
+void gst_process (gamestate *gst, infos *info, float t);
+
+#endif \ No newline at end of file
diff --git a/gst/info.c b/gst/info.c
new file mode 100644
index 0000000..82f1550
--- /dev/null
+++ b/gst/info.c
@@ -0,0 +1,754 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <units.h>
+#include <info.h>
+
+#include <vec.h>
+#include <jsmn.h>
+#include <jsonparse.h>
+
+int type_damage_map (char strdmg[][32]) {
+ strcpy(strdmg[0], "pierce");
+ strcpy(strdmg[1], "laser");
+ strcpy(strdmg[2], "impact");
+ strcpy(strdmg[3], "fusion");
+ strcpy(strdmg[4], "explosive");
+ strcpy(strdmg[5], "emp");
+ strcpy(strdmg[6], "spread");
+}
+
+int damage_type_map (char *strdmg) {
+ if (strcmp(strdmg, "pierce") == 0) return 0;
+ if (strcmp(strdmg, "laser") == 0) return 1;
+ if (strcmp(strdmg, "impact") == 0) return 2;
+ if (strcmp(strdmg, "fusion") == 0) return 3;
+ if (strcmp(strdmg, "explosive") == 0) return 4;
+ if (strcmp(strdmg, "emp") == 0) return 5;
+ if (strcmp(strdmg, "spread") == 0) return 6;
+ printf("info: damage type unknown\n"); return -1;
+}
+
+
+void info_unit_init (info_unit *u) {
+ strcpy(u->name, "nameless");
+ u->chassis = -1;
+ u->battery = -1;
+ u->brain = -1;
+ for(int i=0; i<8; u->weapons[i] = -1, u->armor[i] = -1, i++);
+ for(int i=0; i<16; u->augs[i] = -1, i++);
+ for(int i=0; i<34; u->levels[i] = 0, i++);
+}
+
+float info_unit_get_weight (infos *info, info_unit *u) {
+ float sum = 0;
+ if (u->battery != -1) {
+ sum += info->batteries[u->battery].weight;
+ }
+ for(int i=0; i<8; i++) {
+ if (u->weapons[i] != -1 && i<info->chassis[u->chassis].slot_weapon) {
+ sum += info->weapons[u->weapons[i]].weight;
+ }
+ if (u->armor[i] != -1 && i<info->chassis[u->chassis].slot_armor) {
+ sum += info->armors[u->armor[i]].weight;
+ }
+ }
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].weight;
+ }
+ }
+ return sum;
+}
+
+float info_unit_get_dps (infos *info, info_unit *u) {
+ float sum = 0;
+ for(int i=0; i<8; i++) {
+ if (u->weapons[i] != -1 && i<info->chassis[u->chassis].slot_weapon) {
+ info_weapon *w = info->weapons+u->weapons[i];
+ float damage = info_unit_get_damage(info, u, i);
+ sum += damage/w->cooldown;
+ }
+ }
+ return sum;
+}
+
+float info_unit_get_health(infos *info, info_unit *u) {
+ float sum = 0;
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_hp;
+ }
+ }
+ sum += info->chassis[u->chassis].hp;
+ return sum;
+}
+
+float info_unit_get_speed(infos *info, info_unit *u) {
+ float sum = 0;
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_speed;
+ }
+ }
+ sum += info->chassis[u->chassis].speed;
+ return sum;
+}
+
+float info_unit_get_damage (infos *info, info_unit *u, int w) {
+ int damage_type = info->weapons[u->weapons[w]].damage_type;
+ float sum = 0;
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_damage[damage_type];
+ }
+ }
+ float mult = (1 + sum/100.0f);
+ if (mult < 0) mult = 0;
+ float dam = info->weapons[u->weapons[w]].damage * mult;
+ return dam;
+}
+
+float info_unit_get_damage_target (infos *info, info_unit *u, int w,
+ info_unit *t)
+{
+ // u shoots at t with w, which is lol
+ int damage_type = info->weapons[u->weapons[w]].damage_type;
+ float reduction_perc = info_unit_get_armor(info, t, damage_type);
+ float damage = info_unit_get_damage(info, u, w);
+ float mult = (1 - reduction_perc / 100.0f);
+ return damage * mult;
+}
+
+float info_unit_get_cooldown(infos *info, info_unit *u, int w) {
+ float sum = 0;
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_cooldown;
+ }
+ }
+ sum += info->weapons[u->weapons[w]].cooldown;
+ return sum;
+}
+
+float info_unit_get_range(infos *info, info_unit *u, int w) {
+ float sum = 0;
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_range;
+ }
+ }
+ sum += info->weapons[u->weapons[w]].range;
+ return sum;
+}
+
+float info_unit_get_armor(infos *info, info_unit *u, int d) {
+ float sum = 0;
+ for(int i=0; i<8; i++) {
+ if (u->armor[i] != -1 && i<info->chassis[u->chassis].slot_armor) {
+ sum += info->armors[u->armor[i]].armor[d];
+ }
+ }
+ for(int i=0; i<16; i++) {
+ if (u->augs[i] != -1 && info->chassis[u->chassis].slot_aug) {
+ sum += info->augs[u->augs[i]].add_armor[d];
+ }
+ }
+ return sum;
+}
+
+
+void weapon_init (info_weapon *w) {
+ strcpy(w->name, "nameless");
+ w->damage_type = 0;
+ w->weight = 0; w->cooldown = 1;
+ w->damage = 0; w->range = 0; w->aoe = 0;
+ w->knockback = 0; w->stun = 0;
+ for (int i=0; i<7; i++) { w->reduce_armor[i]=0; }
+}
+
+void chassis_init (info_chassis *c) {
+ strcpy(c->name, "nameless");
+ c->slot_weapon = 0; c->slot_armor = 0; c->slot_aug = 0;
+ c->weight_max = 0; c->hp = 0;
+}
+
+void battery_init (info_battery *b) {
+ strcpy(b->name, "nameless");
+ b->weight = 0; b->capacity = 0; b->recharge = 0;
+}
+
+void armor_init (info_armor *a) {
+ strcpy(a->name, "nameless");
+ a->weight = 0;
+ for (int i=0; i<7; i++) { a->armor[i]=0; }
+}
+
+void aug_init (info_aug *a) {
+ strcpy(a->name, "nameless");
+ a->weight = 0;
+ for (int i=0; i<7; i++) { a->add_damage[i]=0; }
+ for (int i=0; i<7; i++) { a->add_armor[i]=0; }
+ a->add_range = 0;
+ a->add_cooldown = 0;
+ a->add_speed = 0;
+ a->add_hp = 0;
+}
+
+void brain_init (info_brain *a) {
+ strcpy(a->name, "nameless");
+}
+
+
+void info_unit_parse (char *json, info_unit *u, jsmntok_t *t, int r) {
+ info_unit_init(u);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, u->name, t+i+1);
+ }
+ if (strcmp(key, "chassis") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ u->chassis = atoi(val);
+ }
+ if (strcmp(key, "brain") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ u->brain = atoi(val);
+ }
+ if (strcmp(key, "battery") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ u->battery = atoi(val);
+ }
+ if (strcmp(key, "weapons") == 0) {
+ int rt = json_parse_subtokens(json, t, r, i+1);
+ json_parse_array(json, u->weapons, t+i+2, rt-1, 'c');
+ }
+ if (strcmp(key, "armor") == 0) {
+ int rt = json_parse_subtokens(json, t, r, i+1);
+ json_parse_array(json, u->armor, t+i+2, rt-1, 'c');
+ }
+ if (strcmp(key, "augs") == 0) {
+ int rt = json_parse_subtokens(json, t, r, i+1);
+ json_parse_array(json, u->augs, t+i+2, rt-1, 'c');
+ }
+ if (strcmp(key, "levels") == 0) {
+ int rt = json_parse_subtokens(json, t, r, i+1);
+ json_parse_array(json, u->levels, t+i+2, rt-1, 'c');
+ }
+ }
+ }
+}
+
+void info_weapon_parse (char *json, info_weapon *w, jsmntok_t *t, int r) {
+ weapon_init(w);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, w->name, t+i+1);
+ }
+ if (strcmp(key, "damage_type") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->damage_type = damage_type_map(val);
+ }
+ if (strcmp(key, "weight") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->weight = atof(val);
+ }
+ if (strcmp(key, "cooldown") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->cooldown = atof(val);
+ }
+ if (strcmp(key, "damage") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->damage = atof(val);
+ }
+ if (strcmp(key, "range") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->range = atof(val);
+ }
+ if (strcmp(key, "aoe") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->aoe = atof(val);
+ }
+ if (strcmp(key, "knockback") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->knockback = atoi(val);
+ }
+ if (strcmp(key, "damage_battery") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->damage_battery = atof(val);
+ }
+ if (strcmp(key, "stun") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->stun = atoi(val);
+ }
+ if (strcmp(key, "reduce_pierce") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[0] = atof(val);
+ }
+ if (strcmp(key, "reduce_laser") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[1] = atof(val);
+ }
+ if (strcmp(key, "reduce_impact") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[2] = atof(val);
+ }
+ if (strcmp(key, "reduce_fusion") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[3] = atof(val);
+ }
+ if (strcmp(key, "reduce_explosive") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[4] = atof(val);
+ }
+ if (strcmp(key, "reduce_emp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[5] = atof(val);
+ }
+ if (strcmp(key, "reduce_spread") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ w->reduce_armor[6] = atof(val);
+ }
+ }
+ }
+}
+
+void info_chassis_parse (char *json, info_chassis *c, jsmntok_t *t, int r) {
+ chassis_init(c);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, c->name, t+i+1);
+ }
+ if (strcmp(key, "slot_weapon") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->slot_weapon = atoi(val);
+ }
+ if (strcmp(key, "slot_armor") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->slot_armor = atoi(val);
+ }
+ if (strcmp(key, "slot_aug") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->slot_aug = atoi(val);
+ }
+ if (strcmp(key, "weight_max") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->weight_max = atof(val);
+ }
+ if (strcmp(key, "hp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->hp = atof(val);
+ }
+ if (strcmp(key, "speed") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ c->speed = atof(val);
+ }
+ }
+ }
+}
+
+void info_battery_parse (char *json, info_battery *b, jsmntok_t *t, int r) {
+ battery_init(b);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, b->name, t+i+1);
+ }
+ if (strcmp(key, "weight") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ b->weight = atof(val);
+ }
+ if (strcmp(key, "capacity") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ b->capacity = atof(val);
+ }
+ if (strcmp(key, "recharge") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ b->recharge = atoi(val);
+ }
+ }
+ }
+}
+
+void info_armor_parse (char *json, info_armor *a, jsmntok_t *t, int r) {
+ armor_init(a);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, a->name, t+i+1);
+ }
+ if (strcmp(key, "weight") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->weight = atof(val);
+ }
+ if (strcmp(key, "pierce") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[0] = atof(val);
+ }
+ if (strcmp(key, "laser") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[1] = atof(val);
+ }
+ if (strcmp(key, "impact") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[2] = atof(val);
+ }
+ if (strcmp(key, "fusion") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[3] = atof(val);
+ }
+ if (strcmp(key, "explosive") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[4] = atof(val);
+ }
+ if (strcmp(key, "emp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[5] = atof(val);
+ }
+ if (strcmp(key, "spread") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->armor[6] = atof(val);
+ }
+ }
+ }
+}
+
+void info_aug_parse (char *json, info_aug *a, jsmntok_t *t, int r) {
+ aug_init(a);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, a->name, t+i+1);
+ }
+ if (strcmp(key, "weight") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->weight = atof(val);
+ }
+ if (strcmp(key, "damage_pierce") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[0] = atof(val);
+ }
+ if (strcmp(key, "damage_laser") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[1] = atof(val);
+ }
+ if (strcmp(key, "damage_impact") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[2] = atof(val);
+ }
+ if (strcmp(key, "damage_fusion") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[3] = atof(val);
+ }
+ if (strcmp(key, "damage_explosive") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[4] = atof(val);
+ }
+ if (strcmp(key, "damage_emp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[5] = atof(val);
+ }
+ if (strcmp(key, "add_spread") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_damage[6] = atof(val);
+ }
+ if (strcmp(key, "armor_pierce") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[0] = atof(val);
+ }
+ if (strcmp(key, "armor_laser") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[1] = atof(val);
+ }
+ if (strcmp(key, "armor_impact") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[2] = atof(val);
+ }
+ if (strcmp(key, "armor_fusion") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[3] = atof(val);
+ }
+ if (strcmp(key, "armor_explosive") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[4] = atof(val);
+ }
+ if (strcmp(key, "armor_emp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[5] = atof(val);
+ }
+ if (strcmp(key, "armor_spread") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_armor[6] = atof(val);
+ }
+ if (strcmp(key, "add_range") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_range = atof(val);
+ }
+ if (strcmp(key, "add_cooldown") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_cooldown = atof(val);
+ }
+ if (strcmp(key, "add_hp") == 0) {
+ char val[32]; substr_token(json, val, t+i+1);
+ a->add_hp = atof(val);
+ }
+ }
+ }
+}
+
+void info_brain_parse (char *json, info_brain *a, jsmntok_t *t, int r) {
+ brain_init(a);
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i+=2) {
+ if (t[i].type == JSMN_STRING) {
+ char key[32]; substr_token(json, key, t+i);
+ if (strcmp(key, "name") == 0) {
+ substr_token(json, a->name, t+i+1);
+ }
+ }
+ }
+}
+
+void info_parse_json (infos *info, char *json, char *obj) {
+ jsmn_parser p; jsmn_init(&p);
+ jsmntok_t t[MAXTOKENS];
+ int r = jsmn_parse(&p, json, strlen(json), t, MAXTOKENS);
+ int index = 0;
+ for (int i=1; i<r; i++) { // i=1: ignore outer []
+ if (t[i].type == JSMN_OBJECT) {
+ int rt = json_parse_subtokens(json, t, r, i);
+ if (strcmp(obj, "template") == 0) {
+ info_unit_parse(json, info->templates+index, t+i+1, rt);
+ info->templateslen = index+1;
+ }
+ if (strcmp(obj, "weapon") == 0) {
+ info_weapon_parse(json, info->weapons+index, t+i+1, rt);
+ info->weaponslen = index+1;
+ }
+ if (strcmp(obj, "chassis") == 0) {
+ info_chassis_parse(json, info->chassis+index, t+i+1, rt);
+ info->chassislen = index+1;
+ }
+ if (strcmp(obj, "battery") == 0) {
+ info_battery_parse(json, info->batteries+index, t+i+1, rt);
+ info->batterieslen = index+1;
+ }
+ if (strcmp(obj, "armor") == 0) {
+ info_armor_parse(json, info->armors+index, t+i+1, rt);
+ info->armorslen = index+1;
+ }
+ if (strcmp(obj, "aug") == 0) {
+ info_aug_parse(json, info->augs+index, t+i+1, rt);
+ info->augslen = index+1;
+ }
+ if (strcmp(obj, "brain") == 0) {
+ info_brain_parse(json, info->brains+index, t+i+1, rt);
+ info->brainslen = index+1;
+ }
+ index ++;
+ i += rt-1;
+ }
+ }
+}
+
+int info_read_file (char *dst, char *name, int size) {
+ memset(dst, 0, size*sizeof(char));
+ FILE *f = fopen(name, "rb");
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(dst, 1, fsize, f);
+ fclose(f);
+ dst[fsize] = '\0';
+ return fsize;
+}
+
+void info_load (infos *info) {
+ int size = 1024*64;
+ char json[size];
+ type_damage_map(info->damage_types);
+ info->augslen = 0;
+ info_read_file(json, "content/weapons.txt", size);
+ info_parse_json(info, json, "weapon");
+ info_read_file(json, "content/chassis.txt", size);
+ info_parse_json(info, json, "chassis");
+ info_read_file(json, "content/batteries.txt", size);
+ info_parse_json(info, json, "battery");
+ info_read_file(json, "content/armor.txt", size);
+ info_parse_json(info, json, "armor");
+ info_read_file(json, "content/augments.txt", size);
+ info_parse_json(info, json, "aug");
+ info_read_file(json, "content/brains.txt", size);
+ info_parse_json(info, json, "brain");
+
+ info_read_file(json, "content/templates/default.txt", size);
+ info_parse_json(info, json, "template");
+ /*
+ for (int i=0; i<info->unitslen; i++) {
+ printf("name: %s\n", info->units[i].name);
+ printf(" hp: %f\n", info->units[i].hp);
+ printf(" damage: %f\n", info->units[i].damage);
+ printf(" range: %f\n", info->units[i].range);
+ }*/
+ /*
+ for (int i=0; i<info->weaponslen; i++) {
+ printf("name: %s\n", info->weapons[i].name);
+ printf(" damage_type: %d\n", info->weapons[i].damage_type);
+ printf(" weight: %f\n", info->weapons[i].weight);
+ printf(" cooldown: %f\n", info->weapons[i].cooldown);
+ printf(" damage: %f\n", info->weapons[i].damage);
+ printf(" range: %f\n", info->weapons[i].range);
+ printf(" aoe: %f\n", info->weapons[i].aoe);
+ printf(" knockback: %d\n", info->weapons[i].knockback);
+ printf(" damage_battery: %f\n", info->weapons[i].damage_battery);
+ printf(" stun: %d\n", info->weapons[i].stun);
+ float sum = 0; for (int j=0; j<7; j++) {
+ sum += info->weapons[i].reduce_armor[j];
+ }
+ if (sum > 0) {
+ printf(" red pierce: %f\n", info->weapons[i].reduce_armor[0]);
+ printf(" red laser: %f\n", info->weapons[i].reduce_armor[1]);
+ printf(" red impact: %f\n", info->weapons[i].reduce_armor[2]);
+ printf(" red fusion: %f\n", info->weapons[i].reduce_armor[3]);
+ printf(" red explosive: %f\n", info->weapons[i].reduce_armor[4]);
+ printf(" red emp: %f\n", info->weapons[i].reduce_armor[5]);
+ printf(" red spread: %f\n", info->weapons[i].reduce_armor[6]);
+ }
+ }*/
+ /*
+ for (int i=0; i<info->chassislen; i++) {
+ printf("name: %s\n", info->chassis[i].name);
+ printf(" slot_weapon: %d\n", info->chassis[i].slot_weapon);
+ printf(" slot_armor: %d\n", info->chassis[i].slot_armor);
+ printf(" slot_aug: %d\n", info->chassis[i].slot_aug);
+ printf(" weight_max: %f\n", info->chassis[i].weight_max);
+ printf(" hp: %f\n", info->chassis[i].hp);
+ }*/
+ /*
+ for (int i=0; i<info->batterieslen; i++) {
+ printf("name: %s\n", info->batteries[i].name);
+ printf(" weight: %f\n", info->batteries[i].weight);
+ printf(" capacity: %f\n", info->batteries[i].capacity);
+ printf(" recharge: %d\n", info->batteries[i].recharge);
+ }*/
+ /*
+ for (int i=0; i<info->armorslen; i++) {
+ printf("name: %s\n", info->armors[i].name);
+ printf(" weight: %f\n", info->armors[i].weight);
+ printf(" pierce: %f\n", info->armors[i].armor[0]);
+ printf(" laser: %f\n", info->armors[i].armor[1]);
+ printf(" impact: %f\n", info->armors[i].armor[2]);
+ printf(" fusion: %f\n", info->armors[i].armor[3]);
+ printf(" explosive: %f\n", info->armors[i].armor[4]);
+ printf(" emp: %f\n", info->armors[i].armor[5]);
+ printf(" spread: %f\n", info->armors[i].armor[6]);
+ }*/
+}
+
+void info_dump_json_templates (infos *info, char *str) {
+ int len = 0;
+ sprintf(str+len, "[ \n"); len = strlen(str);
+ for (int i=0; i<info->templateslen; i++) {
+ info_unit *u = info->templates+i;
+ sprintf(str+len, " { \n \"name\": \"%s\",\n", u->name);
+ len = strlen(str);
+ sprintf(str+len, " \"chassis\": \"%d\",\n", u->chassis);
+ len = strlen(str);
+ sprintf(str+len, " \"brain\": \"%d\",\n", u->brain);
+ len = strlen(str);
+ sprintf(str+len, " \"battery\": \"%d\",\n", u->battery);
+ len = strlen(str);
+ char w0[64]; json_dump_array(w0, u->weapons, 8, 'c');
+ sprintf(str+len, " \"weapons\": %s,\n", w0);
+ len = strlen(str);
+ char w1[64]; json_dump_array(w1, u->armor, 8, 'c');
+ sprintf(str+len, " \"armor\": %s,\n", w1);
+ len = strlen(str);
+ char w2[64]; json_dump_array(w2, u->augs, 8, 'c');
+ sprintf(str+len, " \"augs\": %s,\n", w2);
+ len = strlen(str);
+ char w3[128]; json_dump_array(w3, u->levels, 34, 'c');
+ sprintf(str+len, " \"levels\": %s\n", w3);
+ len = strlen(str);
+ char comma = ','; if(i==info->templateslen-1) comma = ' ';
+ sprintf(str+len, " }%c\n", comma);
+ len = strlen(str);
+ }
+ sprintf(str+len, "]"); len = strlen(str);
+}
+
+void info_save_templates (infos *info, char *filename) {
+ char src[1024*64];
+ info_dump_json_templates(info, src);
+ char pathname[64]; sprintf(pathname, "content/templates/%s.txt", filename);
+ FILE *f = fopen(pathname, "wb");
+ fwrite(src, 1, strlen(src)*sizeof(char), f);
+ fclose(f);
+}
+
+void info_template_add (infos *info, info_unit *temp) {
+ if (info->templateslen < MAXTEMPLATES) {
+ info->templates[info->templateslen] = *temp;
+ info->templateslen++;
+ }
+}
+
+void info_load_army(struct army_ *ar, char *filename) {
+ char buf[1024*64];
+ char pathname[64]; sprintf(pathname, "army/%s.txt", filename);
+ int len = info_read_file(buf, pathname, 1024*64);
+ memcpy(ar, buf, len-1);
+ ar->grid = NULL;
+ army_grid_init(ar);
+}
+
+void info_save_army(struct army_ *ar, char *filename) {
+ char pathname[64]; sprintf(pathname, "army/%s.txt", filename);
+ FILE *f = fopen(pathname, "wb");
+ fwrite(ar, 1, sizeof(army), f);
+ fclose(f);
+}
+
+
+void info_load_playername(char n[]) {
+ char buf[1024];
+ int len = info_read_file(buf, "player.txt", 1024);
+ memcpy(n, buf, sizeof(char)*len);
+}
+
+void info_save_playername(char n[]) {
+ FILE *f = fopen("player.txt", "wb");
+ fwrite(n, 1, strlen(n)*sizeof(char), f); fclose(f);
+}
+
+
+#include <plibsys.h>
+int info_army_get_list (char l[][32]) {
+ int len = 0;
+ PDirEntry *entry;
+ PDir *dir = p_dir_new ("army/", NULL);
+ while ((entry = p_dir_get_next_entry (dir, NULL)) != NULL) {
+ if (entry->type == P_DIR_ENTRY_TYPE_FILE) {
+ strcpy(l[len], entry->name);
+ l[len][strlen(l[len])-4] = '\0'; // del .txt
+ len++;
+ }
+ }
+ return len;
+}
diff --git a/gst/info.h b/gst/info.h
new file mode 100644
index 0000000..3ec17f9
--- /dev/null
+++ b/gst/info.h
@@ -0,0 +1,116 @@
+#ifndef INFO_H
+#define INFO_H
+
+#define MAXTEMPLATES 128
+
+#include <stdint.h>
+
+typedef struct {
+ char name[32];
+ // indexes of info.*
+ int8_t chassis;
+ int8_t brain;
+ int8_t weapons[8];
+ int8_t armor[8];
+ int8_t augs[16];
+ int8_t battery;
+ int8_t levels[34];
+} info_unit;
+
+typedef struct {
+ char name[32];
+ int damage_type;
+ float weight;
+ float cooldown;
+ float damage;
+ float range;
+ float aoe;
+ int knockback;
+ float damage_battery;
+ int stun;
+ float reduce_armor[7];
+} info_weapon;
+
+typedef struct {
+ char name[32];
+ int slot_weapon;
+ int slot_armor;
+ int slot_aug;
+ float weight_max;
+ float hp;
+ float speed;
+} info_chassis;
+
+typedef struct {
+ char name[32];
+ float weight;
+ float capacity;
+ int recharge;
+} info_battery;
+
+typedef struct {
+ char name[32];
+ float weight;
+ float armor[7];
+} info_armor;
+
+typedef struct {
+ char name[32];
+ float weight;
+ float add_damage[7];
+ float add_armor[7];
+ float add_range;
+ float add_cooldown;
+ float add_speed;
+ float add_hp;
+} info_aug;
+
+typedef struct {
+ char name[32];
+} info_brain;
+
+typedef struct {
+ char damage_types[7][32];
+ info_unit templates[MAXTEMPLATES];
+ int templateslen;
+ info_weapon weapons[64];
+ int weaponslen;
+ info_chassis chassis[32];
+ int chassislen;
+ info_battery batteries[32];
+ int batterieslen;
+ info_armor armors[32];
+ int armorslen;
+ info_aug augs[32];
+ int augslen;
+ info_brain brains[32];
+ int brainslen;
+} infos;
+
+void info_unit_init (info_unit *u);
+float info_unit_get_weight (infos *info, info_unit *u);
+float info_unit_get_dps (infos *info, info_unit *u);
+float info_unit_get_health(infos *info, info_unit *u);
+float info_unit_get_speed(infos *info, info_unit *u);
+float info_unit_get_damage(infos *info, info_unit *u, int w);
+float info_unit_get_damage_target(infos *info, info_unit *u, int w,
+ info_unit *t);
+float info_unit_get_cooldown(infos *info, info_unit *u, int w);
+float info_unit_get_range(infos *info, info_unit *u, int w);
+float info_unit_get_armor(infos *info, info_unit *u, int d);
+
+void info_load (infos *info);
+
+void info_save_templates (infos *info, char *filename);
+void info_template_add (infos *info, info_unit *temp);
+
+
+void info_load_army(struct army_ *ar, char *filename);
+void info_save_army(struct army_ *ar, char *filename);
+
+int info_army_get_list(char l[][32]);
+
+void info_load_playername(char n[]);
+void info_save_playername(char n[]);
+
+#endif \ No newline at end of file
diff --git a/gst/map.c b/gst/map.c
new file mode 100644
index 0000000..59d1ad1
--- /dev/null
+++ b/gst/map.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <units.h>
+#include <string.h>
+
+#include <map.h>
+
+int ptoi (map *m, int *p) { return p[0]+p[1]*m->sx; }
+int xytoi (map *m, int x, int y) { return x+y*m->sx; }
+
+void map_init (map *m, int sx, int sy, int ts) {
+ m->t = (int*)malloc(sizeof(int)*sx*sy);
+ m->sx = sx; m->sy = sy; m->ts = ts;
+ memset(m->t, 0, sizeof(int)*sx*sy);
+}
+
+void map_destroy (map *m) {
+ free(m->t);
+} \ No newline at end of file
diff --git a/gst/map.h b/gst/map.h
new file mode 100644
index 0000000..415281a
--- /dev/null
+++ b/gst/map.h
@@ -0,0 +1,16 @@
+#ifndef MAP_H
+#define MAP_H
+
+typedef struct {
+ int *t;
+ int sx;
+ int sy;
+ int ts;
+} map;
+
+int ptoi (map *m, int *p);
+int xytoi (map *m, int x, int y);
+void map_init (map *m, int sx, int sy, int ts);
+void map_destroy (map *m);
+
+#endif \ No newline at end of file
diff --git a/gst/units.c b/gst/units.c
new file mode 100644
index 0000000..72089f2
--- /dev/null
+++ b/gst/units.c
@@ -0,0 +1,212 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <units.h>
+#include <string.h>
+
+#include <vec.h>
+#include <jsonparse.h>
+
+void army_grid_init(army *ar) {
+ if (ar->grid != NULL) free(ar->grid);
+ ar->grid = (unit**)malloc(sizeof(unit*)*ar->sx*ar->sy);
+ memset(ar->grid, NULL, sizeof(unit*)*ar->sx*ar->sy);
+ for (int i=0; i<ar->uslen; i++) {
+ unit *u = ar->us+i;
+ // not using ptoi, don't have map, why have map anyway?
+ ar->grid[ar->sx*u->gridpos[1]+u->gridpos[0]] = u;
+ }
+}
+
+void army_init (army *ar, map *m) {
+ ar->uslen = 0;
+ ar->sx = m->sx; ar->sy = m->sy;
+ army_grid_init(ar);
+}
+
+void army_destory(army *ar) {
+ free(ar->grid);
+}
+
+void unit_init (infos *info, army *ar, map *m,
+ int x, int y, info_unit *iu, int owner, unit *u)
+{
+ u->pos[0] = x*m->ts; u->pos[1] = y*m->ts;
+ u->gridpos[0] = x; u->gridpos[1] = y;
+ u->info = *iu;
+ u->owner = owner;
+ u->hp = info_unit_get_health(info, iu);
+ u->move_points = 0;
+ for (int i=0; i<8; u->cooldown[i] = 1, i++);
+}
+
+void army_spawn (army *ar, map *m, unit u) {
+ ar->us[ar->uslen] = u;
+ ar->grid[ptoi(m, u.gridpos)] = ar->us+ar->uslen;
+ ar->uslen++;
+}
+
+void unit_move (army *ar, map *m, unit *u, int *dest) {
+ ar->grid[ptoi(m, u->gridpos)] = NULL;
+ u->gridpos[0] = dest[0];
+ u->gridpos[1] = dest[1];
+ ar->grid[ptoi(m, u->gridpos)] = u;
+ u->pos[0] = dest[0]*m->ts;
+ u->pos[1] = dest[1]*m->ts;
+}
+
+void unit_remove (army *ar, map *m, unit *u) {
+ unit *t = ar->us+ar->uslen-1;
+ int ux = u->gridpos[0], uy = u->gridpos[1];
+ int tx = t->gridpos[0], ty = t->gridpos[1];
+ *u = *t;
+ ar->uslen--;
+ ar->grid[xytoi(m, tx, ty)] = u;
+ ar->grid[xytoi(m, ux, uy)] = NULL;
+ printf("ar->uslen: %d\n", ar->uslen);
+}
+
+void unit_dead (army *ar, map *m, unit *u) {
+ ar->grid[ptoi(m, u->gridpos)] = NULL;
+}
+
+void unit_search (infos *info, army *ar, map *m, unit *u,
+ unit **t, float range)
+{
+ for (int f=0; f<32; t[f] = NULL, f++);
+ int mult[4][2] = { {1, 1},{1,-1},{-1,-1},{-1,1} }, x, y, dx, dy, tmp;
+ *t = NULL;
+ for (int r=1; r<range*1.42 && *t==NULL; r++) {
+ for (int k=0; k<4 && *t==NULL; k++) {
+ for (int j=0; j<r && *t==NULL; j++) {
+ if (k%2==1) { // invert them if k=1 || k=3
+ dx = (j)*mult[k][0]; dy = (r-j)*mult[k][1];
+ } else {
+ dx = (r-j)*mult[k][0]; dy = (j)*mult[k][1];
+ }
+ x = u->gridpos[0]+dx; y = u->gridpos[1]+dy;
+ //printf(" (%d, %d) -> (%d, %d), %d, %d, %d\n", u->gridpos[0], u->gridpos[1], x, y, r, k, j);
+ if (!(x>=0 && y>=0 && x<m->sx && y<m->sy)) continue; // oob
+ *t = ar->grid[xytoi(m, x, y)];
+ if (*t!=NULL && (*t)->owner == u->owner) *t = NULL; // owner check
+ if (*t!=NULL && (*t)->hp <= 0) *t = NULL; // owner check
+ if (*t!=NULL) {
+ // range check
+ float diff[2] = {
+ u->gridpos[0] - (*t)->gridpos[0],
+ u->gridpos[1] - (*t)->gridpos[1]
+ }; float mag = vec2_mag(diff);
+ if (mag > range) *t = NULL;
+ }
+ }}}
+}
+
+
+typedef struct { unit *u; int *dir; int done; } mcom;
+int army_move_step (infos *info, army *ar, map *m) {
+ int dirs[4][2] = { {1, 0},{0, 1},{-1,0},{0,-1} };
+ mcom mcs[ar->uslen];
+ int mclen = 0;
+ float diff[2];
+ int orders = 0;
+ // planning
+ for (int i=0; i<ar->uslen; i++) {
+ unit *u = ar->us+i;
+ if (u->move_points <= 0) continue;
+ if (u->hp <= 0) continue;
+ // search target
+ unit *t[32];
+ unit_search(info, ar, m, u, t, 100);
+ if (t[0] != NULL) {
+ // in range to shoot
+ diff[0] = u->gridpos[0] - t[0]->gridpos[0];
+ diff[1] = u->gridpos[1] - t[0]->gridpos[1];
+ if (vec2_mag(diff) > /*info->units[u->who].range*/1) {
+ // movement command issued
+ float dist[4] = { 9999, 9999, 9999, 9999 };
+ for (int j=0; j<4; j++) {
+ diff[0] = u->gridpos[0]+dirs[j][0]
+ - t[0]->gridpos[0];
+ diff[1] = u->gridpos[1]+dirs[j][1]
+ - t[0]->gridpos[1];
+ dist[j] = vec2_mag(diff);
+ }
+ float min = dist[0]; int minj = 0;
+ for (int j=1; j<4; j++) {
+ if (dist[j] < min) { min = dist[j]; minj = j; }
+ }
+ mcs[mclen].u = u;
+ mcs[mclen].dir = dirs[minj];
+ mcs[mclen].done = 0;
+ mclen++;
+ }
+ }
+ }
+ // execution
+ int sum = 0, lastsum = -1, step = 0;
+ for (; step<MAXSOLVESTEPS; step++) {
+ if (sum == lastsum) { break; }
+ lastsum = sum;
+ sum = 0;
+ for (int i=0; i<mclen; i++) {
+ int dest[2] = {
+ mcs[i].u->gridpos[0]+mcs[i].dir[0],
+ mcs[i].u->gridpos[1]+mcs[i].dir[1]
+ };
+ if (!mcs[i].done && ar->grid[ptoi(m, dest)] == NULL) {
+ unit_move(ar, m, mcs[i].u, dest);
+ mcs[i].done = 1;
+ mcs[i].u->move_points -= 1;
+ orders++;
+ }
+ sum += mcs[i].done;
+ }
+ }
+ if (step == MAXSOLVESTEPS) { printf("army: max steps reached\n"); }
+ if (orders > 0) return 0;
+ else return 1;
+}
+
+void army_move (infos *info, army *ar, map *m) {
+ for (int i=0; i<ar->uslen; i++) {
+ ar->us[i].move_points += info_unit_get_speed(info, &ar->us[i].info);
+ }
+ int iter = 0, finished = 0;
+ for (; iter<5 && !finished; iter++) {
+ finished = army_move_step(info, ar, m);
+ }
+ //printf("stepped %d %d\n", iter, finished);
+}
+
+void army_fire (infos *info, army *ar, map *m) {
+ for (int i=0; i<ar->uslen; i++) {
+ unit *u = ar->us+i;
+ for (int j=0; j<info->chassis[u->info.chassis].slot_weapon; j++) {
+ u->cooldown[j] += 1;
+ }
+ }
+ struct dmg { unit *u; float dam; } dmgs[1024*8]; int dmgslen = 0;
+ unit *t[32];
+ for (int i=0; i<ar->uslen; i++) {
+ unit *u = ar->us+i;
+ if (u->hp <= 0) continue;
+ for (int j=0; j<info->chassis[u->info.chassis].slot_weapon; j++) {
+ if (u->info.weapons[j] == -1) continue;
+ if (u->cooldown[j] <= 0) continue;
+ float range = info_unit_get_range(info, &u->info, j);
+ unit_search(info, ar, m, u, t, range);
+ if (t[0]!=NULL) {
+ dmgs[dmgslen].u = t[0];
+ dmgs[dmgslen].dam = info_unit_get_damage_target(
+ info, &u->info, j, &t[0]->info);
+ dmgslen++;
+ u->cooldown[j] -= info_unit_get_cooldown(info, &u->info, j);
+ }
+ }
+ }
+ for (int i=0; i<dmgslen; i++) {
+ dmgs[i].u->hp -= dmgs[i].dam;
+ if (dmgs[i].u->hp <= 0) {
+ unit_dead(ar, m, dmgs[i].u);
+ }
+ }
+} \ No newline at end of file
diff --git a/gst/units.h b/gst/units.h
new file mode 100644
index 0000000..86f7fd7
--- /dev/null
+++ b/gst/units.h
@@ -0,0 +1,40 @@
+#ifndef UNITS_H
+#define UNITS_H
+
+#define MAXUNITS 128
+#define MAXSOLVESTEPS 128
+
+#include <info.h>
+
+typedef struct unit_ {
+ float pos[2];
+ int gridpos[2];
+ info_unit info;
+ int owner;
+ float hp;
+ float move_points;
+ float cooldown[8];
+ float charge;
+} unit;
+
+typedef struct army_ {
+ unit us[MAXUNITS];
+ unit **grid;
+ int uslen;
+ int sx, sy;
+} army;
+
+
+#include <map.h>
+
+void unit_init (infos *info, army *ar, map *m,
+ int x, int y, info_unit *iu, int owner, unit *u);
+void unit_remove (army *ar, map *m, unit *u);
+void army_grid_init(army *ar);
+void army_init (army *ar, map *m);
+void army_destory(army *ar);
+void army_spawn (army *ar, map *m, unit u);
+void army_move (infos *info, army *ar, map *m);
+void army_fire (infos *info, army *ar, map *m);
+
+#endif \ No newline at end of file
diff --git a/hud/hud.c b/hud/hud.c
new file mode 100644
index 0000000..383cb01
--- /dev/null
+++ b/hud/hud.c
@@ -0,0 +1,788 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <hud.h>
+#include <hud_views.h>
+
+#include <intersect.h>
+
+// TODO: make sound module mabye?
+#define SOUND_MOUSE_OVER 0
+#define SOUND_MOUSE_CLICK_0 1
+#define SOUND_MOUSE_WHEEL 2
+#define SOUND_SUCCESS 3
+
+
+// INIT
+void init_sel_chassis (graphic_settings *gs, hud_sel *sc, txtd *t,
+ SDL_Rect back, float start)
+{
+ sc->start = start;
+ sc->nav = 0;
+ sc->rect_back = back;
+}
+
+void init_form_new_unit (graphic_settings *gs, form_new_unit *fnu, txtd *t) {
+ int w = 290+200+300+20*2+10*4 + 30*3 + 200, h = 145+300+20*2+10*1 + 30*2;
+ int x = gs->resx/2-w/2, y = gs->resy/2-h/2;
+ fnu->rect_back = { x, y, w, h };
+
+ fnu->rect_chassis = { x+20, y+20+145+10+30, 300, 300 };
+ fnu->rect_brain = { x+20, y+20+30, 145, 145 };
+ fnu->rect_battery = { x+150+25, y+20+30, 145, 145 };
+ for (int i=0; i<8; i++) {
+ fnu->rect_weapons[i] = { x+20+300+10+30, y+20+120*i +30, 200, 110 };
+ }
+ for (int i=0; i<8; i++) {
+ fnu->rect_armor[i] = { x+20+500+20+30*2, y+20+60*i +30, 150, 50 };
+ }
+ for (int i=0; i<8; i++) {
+ fnu->rect_augs[i] = { x+20+500+20+160+30*2, y+20+60*i +30, 150, 50 };
+ }
+
+ fnu->rect_stats = { x+w-20-200, y+20, 200, h-70 };
+
+ int width = get_text_width("save", t);
+ button bdone = { "save", 4, { x+w-4*2-width-20, y+h-4*2-11-20 } };
+ fnu->done = bdone;
+}
+
+void init_overlay_game (graphic_settings *gs, overlay_game *og, txtd *t) {
+ int w = 250, h = gs->resy-20;
+ og->rect_templates = { 10, gs->resy-10-h, w, h };
+
+ float wnu = get_text_width("new template", t);
+ button b = { "new template", 4, { w-wnu-4*2, 20 } };
+ og->new_template = b;
+
+ float wst = get_text_width("save templates", t);
+ button b2 = { "save templates", 4, { w-wst-4*2, gs->resy-20-4*2-10 } };
+ og->save_templates = b2;
+
+ int warmy = 250, harmy = gs->resy-20;
+ og->rect_army = { gs->resx-warmy-10, gs->resy-harmy-10, warmy, harmy };
+ button b3 = { "save army", 4, { gs->resx-warmy, gs->resy-20-4*2-10 } };
+ og->save_army = b3;
+
+ int wbattle = 400, hbattle = 100;
+ og->rect_battle = { gs->resx/2-wbattle/2, 10, wbattle, hbattle };
+
+ float wsb = get_text_width("start battle", t);
+ button b1 = { "start battle", 4,
+ { og->rect_battle.x+wbattle-wsb-4*2-5, hbattle-4*2-5 } };
+ og->start_battle = b1;
+
+ button b4 = { "host game", 4,
+ { og->rect_battle.x+5, hbattle-4*2-5 } };
+ og->host_game = b4;
+
+ button b5 = { "join game", 4,
+ { og->rect_battle.x+5, hbattle-4*2-5-25 } };
+ og->join_game = b5;
+}
+
+void hud_reset (graphic_settings *gs, hud *h, txtd *t) {
+ init_form_new_unit(gs, &h->fnu, t);
+ init_overlay_game(gs, &h->og, t);
+ SDL_Rect clip = { h->fnu.rect_back.x, h->sc.ref->y,
+ h->fnu.rect_back.w, 300 };
+ float start = h->sc.ref->x - h->fnu.rect_back.x;
+ init_sel_chassis(gs, &h->sc, t, clip, start);
+}
+
+void hud_init (graphic_settings *gs, hud *h, txtd *t) {
+ h->fnu.sel = 0; h->fnu.ind = 0;
+ h->sc.ref = &h->fnu.rect_chassis;
+ h->og.temp_place = -1;
+ info_unit_init(&h->fnu.uinfo);
+ strcpy(h->og.army_listcur, "army");
+ strcpy(h->og.playername, "");
+ h->nameedit = NULL;
+ h->og.battle_state = 0;
+ h->og.edit_playername = 0;
+ hud_reset(gs, h, t);
+}
+
+void hud_resize (graphic_settings *gs, hud *h, txtd *t) {
+ hud_reset(gs, h, t);
+}
+
+
+// PROCESS
+int hud_fnu_check (info_unit *u, infos *info) {
+ if (u->chassis == -1) return 1;
+ if (u->battery == -1) return 2;
+ if (u->brain == -1) return 3;
+ float curweight = info_unit_get_weight(info, u);
+ float maxweight = info->chassis[u->chassis].weight_max;
+ if (curweight > maxweight) { return 4; }
+ return 0;
+}
+
+void hud_map_sel (info_unit *u, infos *info, int sel, int ind,
+ int8_t **n, int *bound, int size[])
+{
+ if (sel == 0) {
+ *n = &u->chassis;
+ *bound = info->chassislen;
+ size[0] = 300; size[1] = 300;
+ }
+ if (sel == 1) {
+ *n = &u->battery;
+ *bound = info->batterieslen;
+ size[0] = 145; size[1] = 145;
+ }
+ if (sel == 2) {
+ *n = &u->armor[ind];
+ *bound = info->armorslen;
+ size[0] = 150; size[1] = 250;
+ }
+ if (sel == 3) {
+ *n = &u->weapons[ind];
+ *bound = info->weaponslen;
+ size[0] = 200; size[1] = 110;
+ }
+ if (sel == 4) {
+ *n = &u->augs[ind];
+ *bound = info->augslen;
+ size[0] = 150; size[1] = 200;
+ }
+ if (sel == 5) {
+ *n = &u->brain;
+ *bound = info->brainslen;
+ size[0] = 145; size[1] = 145;
+ }
+}
+
+void hud_process_sel (graphic_settings *gs, hud *h, MKb *mkb,
+ infos *info, army *ar, map *m, txtd *t, Mix_Chunk *sounds[])
+{
+ if (mkb->mwheeldelta != 0) {
+ Mix_PlayChannel( -1, sounds[SOUND_MOUSE_WHEEL], 0 );
+ }
+ int8_t *n = NULL; int bound = 0; int size[2];
+ hud_map_sel(&h->fnu.uinfo, info, h->fnu.sel, h->fnu.ind, &n, &bound, size);
+ h->sc.nav += mkb->mwheeldelta*size[0];
+ if (h->sc.nav > (*n+1)*size[0]) {
+ h->sc.nav = (*n+1)*size[0];
+ }
+ if (h->sc.nav < (*n-bound+1)*size[0]) {
+ h->sc.nav = (*n-bound+1)*size[0];
+ }
+ float mousepos[2] = { mkb->mx, mkb->my };
+ if (mkb->mheld[0] == 1) {
+ float possc[2] = { h->sc.rect_back.x, h->sc.rect_back.y };
+ float sizesc[2] = { h->sc.rect_back.w, h->sc.rect_back.h };
+ if (!pt_rect(mousepos, possc, sizesc)) {
+ h->state = 1;
+ } else {
+ int i, inav = (int)h->sc.nav/size[0];
+ for (int j=-7;j<h->sc.rect_back.w/size[0]+1; j++) {
+ i = *n+j-inav;
+ if (i<-1) continue;
+ if (i>=bound) break;
+ float x = h->sc.rect_back.x+size[0]*j
+ +(int)h->sc.nav%size[0]+h->sc.start;
+ float y = h->sc.rect_back.y;
+ float pos[2] = {x, y}, s[2] = { size[0], size[1] };
+ if (pt_rect(mousepos, pos, s)) {
+ *n = i;
+ h->state = 1;
+ Mix_PlayChannel( -1, sounds[SOUND_MOUSE_CLICK_0], 0 );
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+void hud_edit_close(hud *h) {
+ h->nameedit = NULL;
+ h->og.edit_playername = 0;
+}
+
+void hud_open_fnu (hud *h, info_unit *u, int i) {
+ h->state = 1;
+ h->fnu.uinfo = *u;
+ h->og.temp_modify = i;
+ hud_edit_close(h);
+}
+
+void hud_close_fnu (hud *h, infos *info) {
+ if (hud_fnu_check(&h->fnu.uinfo, info) > 0) return;
+ if (h->og.temp_modify == -1) {
+ info_template_add(info, &h->fnu.uinfo);
+ } else {
+ info->templates[h->og.temp_modify] = h->fnu.uinfo;
+ }
+ h->state = 0;
+}
+
+
+void hud_og_place(hud *h, int i) {
+ h->og.temp_place = i;
+}
+
+
+void hud_open_sel (graphic_settings *gs, hud *h,
+ txtd *t, infos *info, SDL_Rect *ref)
+{
+ int8_t *n = NULL; int bound = 0; int size[2];
+ hud_map_sel(&h->fnu.uinfo, info, h->fnu.sel,
+ h->fnu.ind, &n, &bound, size);
+ h->sc.nav = 0; if (*n == -1) h->sc.nav -= size[0];
+ h->sc.ref = ref;
+ hud_resize(gs, h, t);
+ h->sc.rect_back.h = size[1];
+}
+
+void hud_process_form_new_unit (graphic_settings *gs, hud *h, MKb *mkb,
+ infos *info, army *ar, map *m, txtd *t, Mix_Chunk *sounds[])
+{
+ float mousepos[2] = { mkb->mx, mkb->my };
+ if (mkb->mheld[0] == 1) {
+ if (mouse_in_button(mousepos, t, &h->fnu.done)) {
+ hud_close_fnu(h, info);
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ /*
+ for (int i=0; i<ar->uslen; i++) {
+ unit *u = ar->us+i;
+ unit_init(info, ar, m, u->gridpos[0], u->gridpos[1],
+ &u->info, 0, u);
+ }*/
+ }
+ float possc[2] = { h->fnu.rect_chassis.x, h->fnu.rect_chassis.y };
+ float sizesc[2] = { h->fnu.rect_chassis.w, h->fnu.rect_chassis.h };
+ if (pt_rect(mousepos, possc, sizesc)) {
+ h->fnu.sel = 0; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_chassis);
+ }
+ float possb[2] = { h->fnu.rect_battery.x, h->fnu.rect_battery.y };
+ float sizesb[2] = { h->fnu.rect_battery.w, h->fnu.rect_battery.h };
+ if (pt_rect(mousepos, possb, sizesb)) {
+ h->fnu.sel = 1; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_battery);
+ }
+ float possbr[2] = { h->fnu.rect_brain.x, h->fnu.rect_brain.y };
+ float sizesbr[2] = { h->fnu.rect_brain.w, h->fnu.rect_brain.h };
+ if (pt_rect(mousepos, possbr, sizesbr)) {
+ h->fnu.sel = 5; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_brain);
+ }
+ if (h->fnu.uinfo.chassis != -1) {
+ for (int i=0;
+ i<info->chassis[h->fnu.uinfo.chassis].slot_armor; i++)
+ {
+ float possa[2] = {
+ h->fnu.rect_armor[i].x, h->fnu.rect_armor[i].y };
+ float sizesa[2] = {
+ h->fnu.rect_armor[i].w, h->fnu.rect_armor[i].h };
+ if (pt_rect(mousepos, possa, sizesa)) {
+ h->fnu.sel = 2; h->fnu.ind = i; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_armor[i]);
+ }
+ }
+ for (int i=0;
+ i<info->chassis[h->fnu.uinfo.chassis].slot_weapon; i++)
+ {
+ float possa[2] = {
+ h->fnu.rect_weapons[i].x, h->fnu.rect_weapons[i].y };
+ float sizesa[2] = {
+ h->fnu.rect_weapons[i].w, h->fnu.rect_weapons[i].h };
+ if (pt_rect(mousepos, possa, sizesa)) {
+ h->fnu.sel = 3; h->fnu.ind = i; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_weapons[i]);
+ }
+ }
+ for (int i=0;
+ i<info->chassis[h->fnu.uinfo.chassis].slot_aug; i++)
+ {
+ float possa[2] = {
+ h->fnu.rect_augs[i].x, h->fnu.rect_augs[i].y };
+ float sizesa[2] = {
+ h->fnu.rect_augs[i].w, h->fnu.rect_augs[i].h };
+ if (pt_rect(mousepos, possa, sizesa)) {
+ h->fnu.sel = 4; h->fnu.ind = i; h->state = 2;
+ hud_open_sel(gs, h, t, info, &h->fnu.rect_augs[i]);
+ }
+ }
+ }
+ }
+}
+
+void hud_process_overlay_game (graphic_settings *gs, hud *h, MKb *mkb,
+ infos *info, army *ar, map *m, txtd *t, gamestate *gst,
+ net_client *netc, net_server *nets, Mix_Chunk *sounds[])
+{
+ if (h->og.battle_state == 1) {
+ if (nets->sock_client == NULL) {
+ net_server_accept(nets);
+ } else {
+ char buffer[1024*64];
+ int len = net_server_recv(nets, buffer);
+ if (len != -1) {
+ h->og.battle_state = 3;
+
+ int armysize = sizeof(unit)*gst->army_bp[0].uslen;
+ char data[armysize];
+ memcpy(data, gst->army_bp[0].us, armysize);
+ net_server_send(nets, data, armysize);
+ printf("send (%d)\n", armysize);
+
+ memcpy(gst->army_bp[1].us, buffer, len);
+ gst->army_bp[1].uslen = len/sizeof(unit);
+ gst->playernum = 2;
+ gst_tobattle(gst);
+ gst->cam[0] = -gs->resx/2+gst->map_battle.sx*gst->map_battle.ts/2;
+ gst->cam[1] = -gs->resy/2+gst->map_battle.sy*gst->map_battle.ts/2;
+ h->state = 4;
+ }
+ }
+ }
+ if (h->og.battle_state == 2) {
+ char buffer[1024*64];
+ int len = net_client_recv(netc, buffer);
+ if (len != -1) {
+ h->og.battle_state = 3;
+
+ memcpy(gst->army_bp[1].us, buffer, len);
+ gst->army_bp[1].uslen = len/sizeof(unit);
+ gst->playernum = 2;
+ gst_tobattle(gst);
+ gst->cam[0] = -gs->resx/2+gst->map_battle.sx*gst->map_battle.ts/2;
+ gst->cam[1] = -gs->resy/2+gst->map_battle.sy*gst->map_battle.ts/2;
+ h->state = 4;
+ }
+ }
+
+ float mousepos[2] = { mkb->mx, mkb->my };
+ if (mkb->mheld[0] == 1) {
+ if (mouse_in_button(mousepos, t, &h->og.new_template)) {
+ info_unit u; info_unit_init(&u);
+ hud_open_fnu(h, &u, -1);
+ h->og.temp_place = -1;
+ }
+
+ if (mouse_in_button(mousepos, t, &h->og.save_templates)) {
+ info_save_templates(info, "default");
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ }
+
+ if (mouse_in_button(mousepos, t, &h->og.start_battle)) {
+ /*
+ army_move(info, ar, m);
+ army_fire(info, ar, m);*/
+ gst_tobattle(gst);
+ gst->cam[0] = -gs->resx/2+gst->map_battle.sx*gst->map_battle.ts/2;
+ gst->cam[1] = -gs->resy/2+gst->map_battle.sy*gst->map_battle.ts/2;
+ h->og.battle_state = 3;
+ h->state = 4;
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ }
+
+ if (mouse_in_button(mousepos, t, &h->og.join_game)) {
+ printf("open client\n");
+ net_client_open(netc);
+ int conn = net_client_connect(netc, "127.0.0.1", SERVER_PORT);
+ if (conn == 0) {
+ int armysize = sizeof(unit)*gst->army_bp[0].uslen;
+ char data[armysize];
+ memcpy(data, gst->army_bp[0].us, armysize);
+ net_client_send(netc, data, armysize);
+ printf("send (%d)\n", armysize);
+ }
+ h->og.battle_state = 2;
+ }
+
+ if (mouse_in_button(mousepos, t, &h->og.host_game)) {
+ printf("open server\n");
+ net_server_open(nets, SERVER_PORT);
+ h->og.battle_state = 1;
+ }
+
+ if (mouse_in_button(mousepos, t, &h->og.save_army)) {
+ info_save_army(gst->army_bp+0, h->og.army_listcur);
+ h->og.army_listlen = info_army_get_list(h->og.army_list);
+ }
+
+ if (h->og.temp_place != -1) {
+ int x = (int)((mkb->mx+gst->cam[0])/32);
+ int y = (int)((mkb->my+gst->cam[1])/32);
+ if (x >= 0 && y >= 0 && x < m->sx && y < m->sy) {
+ if (ar->grid[xytoi(m,x,y)] == NULL) {
+ unit u;
+ unit_init(info, ar, m, x, y,
+ info->templates+h->og.temp_place, 0, &u);
+ army_spawn(ar, m, u);
+ }
+ } else {
+ h->og.temp_place = -1;
+ }
+ }
+
+ for (int i=0; i<info->templateslen; i++) {
+ float x = h->og.rect_templates.x+5;
+ float y = h->og.rect_templates.y+5 + i*20 + 30;
+ float wedit = get_text_width("edit", t);
+ float possa[2] = { x, y };
+ float sizesa[2] = { wedit+4*2, 11+4*2 };
+ if (pt_rect(mousepos, possa, sizesa)) {
+ hud_open_fnu(h, info->templates+i, i);
+ h->og.temp_place = -1;
+ }
+ float wplace = get_text_width("place", t);
+ float posp[2] = { x+wedit+4*2+5, y };
+ float sizep[2] = { wplace+4*2, 11+4*2 };
+ if (pt_rect(mousepos, posp, sizep)) {
+ hud_og_place(h, i);
+ }
+ }
+
+ for (int i=0; i<h->og.army_listlen; i++) {
+ float x = h->og.rect_army.x+5;
+ float y = h->og.rect_army.y+5 + i*20 + 30;
+ float wload = get_text_width("load", t);
+ float posp[2] = { x, y };
+ float sizep[2] = { wload+4*2, 11+4*2 };
+ if (pt_rect(mousepos, posp, sizep)) {
+ strcpy(h->og.army_listcur, h->og.army_list[i]);
+ info_load_army(gst->army_bp+0, h->og.army_listcur);
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ }
+ }
+
+ if (h->nameedit == NULL) {
+ float pn[2] = { h->og.rect_battle.x+5, h->og.rect_battle.y+5 };
+ char sn[64]; sprintf(sn, "PLAYER NAME: %s", h->og.playername);
+ float sizen[2] = { get_text_width(sn, t), 10 };
+ if (pt_rect(mousepos, pn, sizen)) {
+ h->nameedit = h->og.playername;
+ printf("editing this %s\n", h->nameedit);
+ h->og.edit_playername = 1;
+ }
+ } else {
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ hud_edit_close(h);
+ }
+ }
+
+ // rm unit
+ if (mkb->mheld[2] == 1) {
+ Mix_PlayChannel( -1, sounds[SOUND_MOUSE_CLICK_0], 0 );
+ int x = (int)((mkb->mx+gst->cam[0])/32);
+ int y = (int)((mkb->my+gst->cam[1])/32);
+ if (x >= 0 && y >= 0 && x < m->sx && y < m->sy) {
+ if (ar->grid[xytoi(m,x,y)] != NULL) {
+ unit_remove(ar, m, ar->grid[xytoi(m,x,y)]);
+ }
+ }
+ }
+}
+
+void hud_edit_name(hud *h, MKb *mkb, Mix_Chunk *sounds[]) {
+ for (int i=0; i<mkb->kbnum; i++) {
+ if (mkb->kb[i] >= SDL_SCANCODE_A
+ && mkb->kb[i] <= SDL_SCANCODE_Z) {
+ if (strlen(h->nameedit) < 31) {
+ char c = mkb->kb[i]-SDL_SCANCODE_A+'a';
+ if (SDL_GetModState() & KMOD_SHIFT) {
+ c = mkb->kb[i]-SDL_SCANCODE_A+'A';
+ }
+ sprintf(h->nameedit, "%s%c", h->nameedit, c);
+ }
+ }
+ }
+ if (mkb_search(mkb, SDL_SCANCODE_SPACE)) {
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ if (strlen(h->nameedit) < 31) {
+ sprintf(h->nameedit, "%s ", h->nameedit);
+ }
+ }
+ if (mkb_search(mkb, SDL_SCANCODE_BACKSPACE)) {
+ if (strlen(h->nameedit) > 0)
+ h->nameedit[strlen(h->nameedit)-1] = '\0';
+ }
+ if (mkb_search(mkb, SDL_SCANCODE_ESCAPE)) {
+ Mix_PlayChannel( -1, sounds[SOUND_SUCCESS], 0 );
+ hud_edit_close(h); return;
+ }
+}
+
+void hud_process (graphic_settings *gs, hud *h, MKb *mkb,
+ infos *info, army *ar, map *m, txtd *t, gamestate *gst,
+ net_client *netc, net_server *nets, Mix_Chunk *sounds[])
+{
+ if (h->nameedit != NULL) { hud_edit_name(h, mkb, sounds); }
+ switch (h->state) {
+ case 0:
+ hud_process_overlay_game(gs, h, mkb, info, ar, m, t, gst,
+ netc, nets, sounds);
+ break;
+ case 1: hud_process_form_new_unit(gs, h, mkb, info, ar, m, t,
+ sounds); break;
+ case 2: hud_process_sel(gs, h, mkb, info, ar, m, t, sounds); break;
+ }
+}
+
+
+
+// RENDER
+void hud_render_sel (hud_sel *sc, MKb *mkb, info_unit *u,
+ SDL_Renderer* rend, SDL_Texture *sprites, txtd *t, infos *info,
+ int sel, int ind)
+{
+ int8_t *n = NULL; int bound = 0; int size[2];
+ hud_map_sel(u, info, sel, ind, &n, &bound, size);
+ SDL_SetRenderDrawColor(rend, 150, 200, 0, 255);
+ SDL_RenderFillRect(rend, &sc->rect_back);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &sc->rect_back);
+ SDL_RenderSetClipRect(rend, &sc->rect_back);
+ int i;
+ for (int j=-7;j<sc->rect_back.w/size[0]+1; j++) {
+ i = *n+j - (int)sc->nav/size[0];
+ if (i<-1) continue;
+ if (i>=bound) break;
+ float x = sc->rect_back.x+size[0]*j+(int)sc->nav%size[0]+sc->start;
+ float y = sc->rect_back.y;
+ SDL_Rect r = { x, y, size[0]+1, size[1] };
+ SDL_SetRenderDrawColor(rend, 150, 200, 120, 255);
+ SDL_RenderFillRect(rend, &r);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &r);
+ if (sel==0) render_view_chassis(rend, t, x, y, info, i, sprites);
+ if (sel==1) render_view_battery(rend, t, x, y, info, i);
+ if (sel==2) render_view_armor_detail(rend, t, x, y, info, i);
+ if (sel==3) render_view_weapon_detail(rend, t, x, y, info, i);
+ if (sel==4) render_view_aug_detail(rend, t, x, y, info, i);
+ if (sel==5) render_view_brain(rend, t, x, y, info, i);
+ }
+ SDL_RenderSetClipRect(rend, NULL);
+}
+
+void hud_render_form_new_unit (form_new_unit *fnu, MKb *mkb,
+ SDL_Renderer* rend, txtd *t, infos *info, SDL_Texture *sprites)
+{
+ SDL_SetRenderDrawColor(rend, 150, 200, 255, 255);
+ SDL_RenderFillRect(rend, &fnu->rect_back);
+
+ SDL_SetRenderDrawColor(rend, 200, 0, 255, 255);
+ SDL_RenderFillRect(rend, &fnu->rect_chassis);
+ SDL_RenderFillRect(rend, &fnu->rect_brain);
+ SDL_RenderFillRect(rend, &fnu->rect_battery);
+
+ SDL_SetRenderDrawColor(rend, 255, 150, 50, 255);
+ SDL_RenderFillRect(rend, &fnu->rect_stats);
+
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &fnu->rect_back);
+ SDL_RenderDrawRect(rend, &fnu->rect_chassis);
+ SDL_RenderDrawRect(rend, &fnu->rect_brain);
+ SDL_RenderDrawRect(rend, &fnu->rect_battery);
+ SDL_RenderDrawRect(rend, &fnu->rect_stats);
+
+ render_view_stats(rend, t, fnu->rect_stats.x, fnu->rect_stats.y,
+ info, &fnu->uinfo);
+
+ if (fnu->uinfo.chassis != -1) {
+ for (int i=0; i<info->chassis[fnu->uinfo.chassis].slot_weapon; i++) {
+ SDL_SetRenderDrawColor(rend, 200, 100, 255, 255);
+ SDL_RenderFillRect(rend, fnu->rect_weapons+i);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, fnu->rect_weapons+i);
+ render_view_weapon(rend, t,
+ fnu->rect_weapons[i].x,
+ fnu->rect_weapons[i].y, info, fnu->uinfo.weapons[i]);
+ }
+ for (int i=0; i<info->chassis[fnu->uinfo.chassis].slot_armor; i++) {
+ SDL_SetRenderDrawColor(rend, 200, 200, 255, 255);
+ SDL_RenderFillRect(rend, fnu->rect_armor+i);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, fnu->rect_armor+i);
+ render_view_armor(rend, t,
+ fnu->rect_armor[i].x,
+ fnu->rect_armor[i].y, info, fnu->uinfo.armor[i]);
+ }
+ for (int i=0; i<info->chassis[fnu->uinfo.chassis].slot_aug; i++) {
+ SDL_SetRenderDrawColor(rend, 200, 200, 255, 255);
+ SDL_RenderFillRect(rend, fnu->rect_augs+i);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, fnu->rect_augs+i);
+ render_view_aug(rend, t,
+ fnu->rect_augs[i].x,
+ fnu->rect_augs[i].y, info, fnu->uinfo.augs[i]);
+ }
+ }
+
+ char schassis[32] = "CHASSIS";
+ float wchassis = get_text_width(schassis, t)*2;
+ float pchassis[2] = {
+ fnu->rect_chassis.x+fnu->rect_chassis.w/2 - wchassis / 2,
+ fnu->rect_chassis.y+fnu->rect_chassis.h + 7
+ };
+ render_text_scaled(rend, schassis, pchassis, t, 2);
+
+ char sbrain[32] = "CONTROLLER";
+ float wbrain = get_text_width(sbrain, t)*2;
+ float pbrain[2] = {
+ fnu->rect_brain.x+fnu->rect_brain.w/2 - wbrain / 2,
+ fnu->rect_brain.y - 16-7
+ };
+ render_text_scaled(rend, sbrain, pbrain, t, 2);
+
+ char sbattery[32] = "BATTERY";
+ float wbattery = get_text_width(sbattery, t)*2;
+ float pbattery[2] = {
+ fnu->rect_battery.x+fnu->rect_battery.w/2 - wbattery / 2,
+ fnu->rect_battery.y - 16-7
+ };
+ render_text_scaled(rend, sbattery, pbattery, t, 2);
+
+ char sweapons[32] = "WEAPONS";
+ float wweapons = get_text_width(sweapons, t)*2;
+ float pweapons[2] = {
+ fnu->rect_weapons[0].x+fnu->rect_weapons[0].w/2 - wweapons / 2,
+ fnu->rect_weapons[0].y - 16-7
+ };
+ render_text_scaled(rend, sweapons, pweapons, t, 2);
+
+ char sarmor[32] = "ARMOR";
+ float warmor = get_text_width(sarmor, t)*2;
+ float parmor[2] = {
+ fnu->rect_armor[0].x+fnu->rect_armor[0].w/2 - warmor / 2,
+ fnu->rect_armor[0].y - 16-7
+ };
+ render_text_scaled(rend, sarmor, parmor, t, 2);
+
+ char saugs[32] = "AUGMENTS";
+ float waugs = get_text_width(saugs, t)*2;
+ float pagus[2] = {
+ fnu->rect_augs[0].x+fnu->rect_augs[0].w/2 - waugs / 2,
+ fnu->rect_augs[0].y - 16-7
+ };
+ render_text_scaled(rend, saugs, pagus, t, 2);
+
+ render_button(rend, t, &fnu->done);
+
+ int err = hud_fnu_check(&fnu->uinfo, info);
+ char serr[32] = "ok";
+ if (err==1) strcpy(serr, "select a chassis");
+ if (err==2) strcpy(serr, "select a battery");
+ if (err==3) strcpy(serr, "select a controller");
+ if (err==4) strcpy(serr, "overburdened, remove weight");
+ float werr = get_text_width(serr, t);
+ float perr[2] = {
+ fnu->done.pos[0]-werr-10,
+ fnu->done.pos[1]+fnu->done.pad
+ };
+ render_text_scaled(rend, serr, perr, t, 1);
+
+ render_view_chassis(rend, t,
+ fnu->rect_chassis.x, fnu->rect_chassis.y,
+ info, fnu->uinfo.chassis, sprites);
+ render_view_battery(rend, t,
+ fnu->rect_battery.x, fnu->rect_battery.y, info, fnu->uinfo.battery);
+ render_view_brain(rend, t,
+ fnu->rect_brain.x, fnu->rect_brain.y, info, fnu->uinfo.brain);
+}
+
+void hud_render_overlay_game (overlay_game *og, MKb *mkb,
+ SDL_Renderer* rend, txtd *t, infos *info, SDL_Texture *sprites)
+{
+ SDL_SetRenderDrawColor(rend, 40, 150, 200, 255);
+ SDL_RenderFillRect(rend, &og->rect_templates);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &og->rect_templates);
+ char stemp[32] = "TEMPLATES";
+ float ptemp[2] = {
+ og->rect_templates.x+10,
+ og->rect_templates.y+10
+ };
+ render_text_scaled(rend, stemp, ptemp, t, 2);
+
+ render_button(rend, t, &og->new_template);
+ render_button(rend, t, &og->save_templates);
+
+ for (int i=0; i<info->templateslen; i++) {
+ float x = og->rect_templates.x+5;
+ float y = og->rect_templates.y+5 + i*20 + 30;
+ render_view_template(rend, t, x, y, info, i);
+ }
+
+ SDL_SetRenderDrawColor(rend, 0, 200, 120, 255);
+ SDL_RenderFillRect(rend, &og->rect_army);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &og->rect_army);
+ char sarmy[32] = "ARMY";
+ float parmy[2] = {
+ og->rect_army.x+10,
+ og->rect_army.y+10
+ };
+ render_text_scaled(rend, sarmy, parmy, t, 2);
+
+ render_button(rend, t, &og->save_army);
+
+ button b = { "load", 4, { 0, 0 } };
+ for (int i=0; i<og->army_listlen; i++) {
+ float x = og->rect_army.x+5;
+ float y = og->rect_army.y+5 + i*20 + 30;
+ float bw = get_text_width("load", t)+4*2;
+ b.pos[0] = x; b.pos[1] = y;
+ render_button(rend, t, &b);
+ float pa[2] = { x+bw+5, y+4 };
+ render_text_scaled(rend, og->army_list[i], pa, t, 1);
+ if (strcmp(og->army_listcur, og->army_list[i]) == 0) {
+ float w = get_text_width(og->army_list[i], t);
+ float pe[2] = { x+bw+5+w+5, y+4 };
+ render_text_scaled(rend, "<- editing", pe, t, 1);
+ }
+ }
+
+ SDL_SetRenderDrawColor(rend, 250, 60, 60, 255);
+ SDL_RenderFillRect(rend, &og->rect_battle);
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &og->rect_battle);
+
+ float pn[2] = { og->rect_battle.x+5, og->rect_battle.y+5 };
+ char sn[64];
+ if (og->edit_playername == 1) {
+ sprintf(sn, "PLAYER NAME: %s_", og->playername);
+ printf("looool\n");
+ } else {
+ sprintf(sn, "PLAYER NAME: %s", og->playername);
+ }
+ render_text_scaled(rend, sn, pn, t, 1);
+
+ render_button(rend, t, &og->host_game);
+ render_button(rend, t, &og->join_game);
+ render_button(rend, t, &og->start_battle);
+
+ if (og->temp_place != -1) {
+ SDL_Rect srcRect = {
+ info->templates[og->temp_place].chassis*32, 32, 32, 32 };
+ SDL_Rect dstRect = { mkb->mx - 16, mkb->my - 16, 32, 32 };
+ SDL_RenderCopy(rend, sprites, &srcRect, &dstRect);
+ }
+}
+
+void hud_render (hud *h, SDL_Renderer* rend, txtd *t, MKb *mkb, infos *info,
+ SDL_Texture *sprites)
+{
+ switch (h->state) {
+ case 0:
+ hud_render_overlay_game(&h->og, mkb, rend, t, info, sprites);
+ break;
+ case 1:
+ hud_render_overlay_game(&h->og, mkb, rend, t, info, sprites);
+ hud_render_form_new_unit(&h->fnu, mkb, rend, t, info, sprites);
+ break;
+ case 2:
+ hud_render_overlay_game(&h->og, mkb, rend, t, info, sprites);
+ hud_render_form_new_unit(&h->fnu, mkb, rend, t, info, sprites);
+ hud_render_sel(&h->sc, mkb, &h->fnu.uinfo,
+ rend, sprites, t, info, h->fnu.sel, h->fnu.ind);
+ break;
+ }
+} \ No newline at end of file
diff --git a/hud/hud.h b/hud/hud.h
new file mode 100644
index 0000000..2728bb2
--- /dev/null
+++ b/hud/hud.h
@@ -0,0 +1,74 @@
+#ifndef HUD_H
+#define HUD_H
+
+#include <SDL.h>
+#include <SDL_mixer.h>
+
+#include <render_text.h>
+#include <button.h>
+#include <graphicsettings.h>
+#include <mkb.h>
+#include <info.h>
+#include <units.h>
+#include <map.h>
+#include <gst.h>
+#include <net.h>
+
+typedef struct {
+ float start;
+ float nav;
+ SDL_Rect rect_back;
+ SDL_Rect *ref;
+} hud_sel;
+
+typedef struct {
+ button new_template;
+ button save_templates;
+ button save_army;
+ button start_battle;
+ button host_game;
+ button join_game;
+ SDL_Rect rect_battle;
+ SDL_Rect rect_templates;
+ int temp_modify;
+ int temp_place;
+ SDL_Rect rect_army;
+ char army_list[64][32];
+ int army_listlen;
+ char army_listcur[32];
+ char playername[32];
+ int battle_state;
+ int edit_playername;
+} overlay_game;
+
+typedef struct {
+ SDL_Rect rect_back;
+ SDL_Rect rect_chassis;
+ SDL_Rect rect_brain;
+ SDL_Rect rect_battery;
+ SDL_Rect rect_weapons[8];
+ SDL_Rect rect_armor[8];
+ SDL_Rect rect_augs[8];
+ SDL_Rect rect_stats;
+ button done;
+ info_unit uinfo;
+ int sel, ind;
+} form_new_unit;
+
+typedef struct {
+ hud_sel sc;
+ overlay_game og;
+ form_new_unit fnu;
+ int state;
+ char *nameedit;
+} hud;
+
+void hud_init(graphic_settings *gs, hud *h, txtd *t);
+void hud_resize (graphic_settings *gs, hud *h, txtd *t);
+void hud_process (graphic_settings *gs, hud *h, MKb *mkb,
+ infos *info, army *ar, map *m, txtd *t, gamestate *gst,
+ net_client *netc, net_server *nets, Mix_Chunk *sounds[]);
+void hud_render (hud *h, SDL_Renderer* rend, txtd *t, MKb *mkb, infos *info,
+ SDL_Texture *sprites);
+
+#endif \ No newline at end of file
diff --git a/hud/hud_views.c b/hud/hud_views.c
new file mode 100644
index 0000000..557ff1f
--- /dev/null
+++ b/hud/hud_views.c
@@ -0,0 +1,380 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <hud_views.h>
+
+void render_view_stats (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, info_unit *tm)
+{
+ float h = 10;
+ float pname[2] = { px+10, py+h };
+ char sname[64]; sprintf(sname, "STATS");
+ render_text_scaled(rend, sname, pname, t, 2);
+ h += 35;
+
+ float calcweight = info_unit_get_weight(info, tm);
+ float maxweight = info->chassis[tm->chassis].weight_max;
+ float pw[2] = { px+10, py+h };
+ char sw[64]; sprintf(sw, "WEIGHT: %.0f/%.0f",
+ calcweight, maxweight);
+ render_text_scaled(rend, sw, pw, t, 1);
+ h += 15;
+
+ float hp = info_unit_get_health(info, tm);
+ float php[2] = { px+10, py+h };
+ char shp[64]; sprintf(shp, "HP: %.2f", hp);
+ render_text_scaled(rend, shp, php, t, 1);
+ h += 15;
+
+ float speed = info_unit_get_speed(info, tm);
+ float pspeed[2] = { px+10, py+h };
+ char sspeed[64]; sprintf(sspeed, "SPEED: %.2f", speed);
+ render_text_scaled(rend, sspeed, pspeed, t, 1);
+ h += 15;
+
+ float dps = info_unit_get_dps(info, tm);
+ float pdps[2] = { px+10, py+h };
+ char sdps[64]; sprintf(sdps, "DAMAGE PER TURN: %.2f", dps);
+ render_text_scaled(rend, sdps, pdps, t, 1);
+ h += 20;
+
+ float part[2] = { px+10, py+h };
+ render_text_scaled(rend, "ARMOR:", part, t, 1);
+ h += 15;
+
+ for (int i=0; i<7; i++) {
+ float ar = info_unit_get_armor(info, tm, i);
+ float par[2] = { px+10, py+h };
+ char sar[64]; sprintf(sar, "%s: %.1f%", info->damage_types[i], ar);
+ render_text_scaled(rend, sar, par, t, 1);
+ h += 15;
+ }
+ h += 5;
+}
+
+void render_view_chassis (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int chassis, SDL_Texture *sprites)
+{
+ if (chassis != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->chassis[chassis].name);
+ render_text_scaled(rend, sname, pname, t, 2);
+ float pweight[2] = { px+10, py+40 };
+ char sweight[64]; sprintf(sweight, "MAX WEIGHT: %0.0f",
+ info->chassis[chassis].weight_max);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ float php[2] = { px+10, py+55 };
+ char shp[64]; sprintf(shp, "HP: %0.1f",
+ info->chassis[chassis].hp);
+ render_text_scaled(rend, shp, php, t, 1);
+ float pspeed[2] = { px+10, py+70 };
+ char sspeed[64]; sprintf(sspeed, "SPEED: %0.2f tiles/turn",
+ info->chassis[chassis].speed);
+ render_text_scaled(rend, sspeed, pspeed, t, 1);
+
+ SDL_Rect srcRect = { chassis*32, 32, 32, 32 };
+ SDL_Rect dstRect = { px+300-32-10, py+10, 32, 32 };
+ SDL_RenderCopy(rend, sprites, &srcRect, &dstRect);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select a chassis...", pname, t, 1);
+ }
+}
+
+void render_view_battery (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int batt)
+{
+ if (batt != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->batteries[batt].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ float pweight[2] = { px+10, py+40 };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %0.0f",
+ info->batteries[batt].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ float pcapacity[2] = { px+10, py+55 };
+ char scapacity[64]; sprintf(scapacity, "CAPACITY: %0.1f",
+ info->batteries[batt].capacity);
+ render_text_scaled(rend, scapacity, pcapacity, t, 1);
+ float prech[2] = { px+10, py+70 };
+ char srech[64];
+ if (info->batteries[batt].recharge == 0) {
+ strcpy(srech, "NOT RECHARGEABLE");
+ } else {
+ strcpy(srech, "RECHARGEABLE");
+ }
+ render_text_scaled(rend, srech, prech, t, 1);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select a battery...", pname, t, 1);
+ }
+}
+
+
+void render_view_armor (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int armor)
+{
+ if (armor != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s", info->armors[armor].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ char sa[64]; int j=0;
+ char temp[16] = "red: ";
+ strcpy(sa+j, temp);
+ j += strlen(temp);
+ for (int i=0; i<7; i++) {
+ if (i<7-1) {
+ sprintf(temp, "%.0f, ", info->armors[armor].armor[i]);
+ } else {
+ sprintf(temp, "%.0f", info->armors[armor].armor[i]);
+ }
+ strcpy(sa+j, temp);
+ j += strlen(temp);
+ }
+ sa[j] = '\0';
+ float pa[2] = { px+10, py+25 };
+ render_text_scaled(rend, sa, pa, t, 1);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select an armor...", pname, t, 1);
+ }
+}
+
+void render_view_armor_detail (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int armor)
+{
+ if (armor != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s", info->armors[armor].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ float pweight[2] = { px+10, py+40 };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %0.0f",
+ info->armors[armor].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+
+ float pred[2] = { px+10, py+60 };
+ render_text_scaled(rend, "DAMAGE REDUCTION", pred, t, 1);
+
+ int h=0;
+ for (int i=0; i<7; i++) {
+ if (info->armors[armor].armor[i] < 0.001) continue;
+ float pa[2] = { px+10, py+75+h*15 };
+ char sa[64]; sprintf(sa, "%s: %.1f%",
+ info->damage_types[i], info->armors[armor].armor[i]);
+ render_text_scaled(rend, sa, pa, t, 1);
+ h++;
+ }
+ } else {
+ render_view_weapon(rend, t, px, py, info, armor);
+ }
+}
+
+
+void render_view_weapon (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int weapon)
+{
+ if (weapon != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->weapons[weapon].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ float pweight[2] = { px+10, py+30 };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %.0f",
+ info->weapons[weapon].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ float ptype[2] = { px+10, py+45 };
+ char stype[64]; sprintf(stype, "DAMAGE TYPE: %s",
+ info->damage_types[info->weapons[weapon].damage_type]);
+ render_text_scaled(rend, stype, ptype, t, 1);
+ float pdamage[2] = { px+10, py+60 };
+ char sdamage[64]; sprintf(sdamage, "DAMAGE: %.0f",
+ info->weapons[weapon].damage);
+ render_text_scaled(rend, sdamage, pdamage, t, 1);
+ float prange[2] = { px+10, py+75 };
+ char srange[64]; sprintf(srange, "RANGE: %.0f",
+ info->weapons[weapon].range);
+ render_text_scaled(rend, srange, prange, t, 1);
+ float pcool[2] = { px+10, py+90 };
+ char scool[64]; sprintf(scool, "COOLDOWN: %.0f",
+ info->weapons[weapon].cooldown);
+ render_text_scaled(rend, scool, pcool, t, 1);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select a weapon...", pname, t, 1);
+ }
+}
+
+void render_view_weapon_detail (SDL_Renderer* rend, txtd *t,
+ int px, int py, infos *info, int weapon)
+{
+ if (weapon != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->weapons[weapon].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ float pweight[2] = { px+10, py+30 };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %.0f",
+ info->weapons[weapon].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ float ptype[2] = { px+10, py+45 };
+ char stype[64]; sprintf(stype, "DAMAGE TYPE: %s",
+ info->damage_types[info->weapons[weapon].damage_type]);
+ render_text_scaled(rend, stype, ptype, t, 1);
+ float pdamage[2] = { px+10, py+60 };
+ char sdamage[64]; sprintf(sdamage, "DAMAGE: %.0f",
+ info->weapons[weapon].damage);
+ render_text_scaled(rend, sdamage, pdamage, t, 1);
+ float prange[2] = { px+10, py+75 };
+ char srange[64]; sprintf(srange, "RANGE: %.0f",
+ info->weapons[weapon].range);
+ render_text_scaled(rend, srange, prange, t, 1);
+ float pcool[2] = { px+10, py+90 };
+ char scool[64]; sprintf(scool, "COOLDOWN: %.0f",
+ info->weapons[weapon].cooldown);
+ render_text_scaled(rend, scool, pcool, t, 1);
+ } else {
+ render_view_weapon(rend, t, px, py, info, weapon);
+ }
+}
+
+
+void render_view_aug (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int aug)
+{
+ if (aug != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->augs[aug].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ float pweight[2] = { px+10, py+30 };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %.0f",
+ info->augs[aug].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select an augment...", pname, t, 1);
+ }
+}
+
+void render_view_aug_detail (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int aug)
+{
+ if (aug != -1) {
+ float h = 10;
+ float pname[2] = { px+10, py+h };
+ char sname[64]; sprintf(sname, "%s",
+ info->augs[aug].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ h += 20;
+
+ float pweight[2] = { px+10, py+h };
+ char sweight[64]; sprintf(sweight, "WEIGHT: %.0f",
+ info->augs[aug].weight);
+ render_text_scaled(rend, sweight, pweight, t, 1);
+ h += 15;
+
+ float range = info->augs[aug].add_range;
+ if (range != 0) {
+ float p[2] = { px+10, py+h };
+ char s[64]; sprintf(s, "RANGE: %.1f", range);
+ render_text_scaled(rend, s, p, t, 1);
+ h += 15;
+ }
+
+ float cooldown = info->augs[aug].add_cooldown;
+ if (cooldown != 0) {
+ float p[2] = { px+10, py+h };
+ char s[64]; sprintf(s, "COOLDOWN: %.2f", cooldown);
+ render_text_scaled(rend, s, p, t, 1);
+ h += 15;
+ }
+
+ float speed = info->augs[aug].add_speed;
+ if (speed != 0) {
+ float p[2] = { px+10, py+h };
+ char s[64]; sprintf(s, "SPEED: %.2f", speed);
+ render_text_scaled(rend, s, p, t, 1);
+ h += 15;
+ }
+
+ float hp = info->augs[aug].add_hp;
+ if (hp != 0) {
+ float p[2] = { px+10, py+h };
+ char s[64]; sprintf(s, "HP: %.1f", hp);
+ render_text_scaled(rend, s, p, t, 1);
+ h += 15;
+ }
+
+ h += 5;
+
+ float sum = 0;
+ for (int i=0; i<7; i++) sum += fabs(info->augs[aug].add_armor[i]);
+ if (sum != 0) {
+ float p[2] = { px+10, py+h };
+ render_text_scaled(rend, "ARMOR: ", p, t, 1);
+ h += 15;
+ for (int i=0; i<7; i++) {
+ if (info->augs[aug].add_armor[i] == 0) continue;
+ float pa[2] = { px+10, py+h };
+ char sa[64]; sprintf(sa, "%s: %.1f%",
+ info->damage_types[i], info->augs[aug].add_armor[i]);
+ render_text_scaled(rend, sa, pa, t, 1);
+ h += 15;
+ }
+ }
+
+ sum = 0;
+ for (int i=0; i<7; i++) sum += fabs(info->augs[aug].add_damage[i]);
+ if (sum != 0) {
+ float p[2] = { px+10, py+h };
+ render_text_scaled(rend, "DAMAGE: ", p, t, 1);
+ h += 15;
+ for (int i=0; i<7; i++) {
+ if (info->augs[aug].add_damage[i] == 0) continue;
+ float pa[2] = { px+10, py+h };
+ char sa[64]; sprintf(sa, "%s: %.1f%",
+ info->damage_types[i], info->augs[aug].add_damage[i]);
+ render_text_scaled(rend, sa, pa, t, 1);
+ h += 15;
+ }
+ }
+ } else {
+ render_view_aug(rend, t, px, py, info, aug);
+ }
+}
+
+
+void render_view_brain (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int brain)
+{
+ if (brain != -1) {
+ float pname[2] = { px+10, py+10 };
+ char sname[64]; sprintf(sname, "%s",
+ info->brains[brain].name);
+ render_text_scaled(rend, sname, pname, t, 1);
+ } else {
+ float pname[2] = { px+10, py+10 };
+ render_text_scaled(rend, "select a controller...", pname, t, 1);
+ }
+}
+
+
+void render_view_template (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int temp)
+{
+ button b = { "edit", 4, { px, py } };
+ render_button(rend, t, &b);
+ float wedit = get_text_width("edit", t);
+
+ button b1 = { "place", 4, { px+wedit+2*4+5, py } };
+ render_button(rend, t, &b1);
+ float wplace = get_text_width("place", t);
+
+ float pname[2] = { wplace+wedit+4*4+10+px, py+4 };
+ char *sname = info->chassis[info->templates[temp].chassis].name;
+ render_text_scaled(rend, sname, pname, t, 1);
+} \ No newline at end of file
diff --git a/hud/hud_views.h b/hud/hud_views.h
new file mode 100644
index 0000000..ceced23
--- /dev/null
+++ b/hud/hud_views.h
@@ -0,0 +1,47 @@
+#ifndef HUD_VIEWS_H
+#define HUD_VIEWS_H
+
+#include <SDL.h>
+
+#include <render_text.h>
+#include <button.h>
+#include <graphicsettings.h>
+#include <mkb.h>
+#include <info.h>
+#include <units.h>
+#include <hud.h>
+
+void render_view_stats (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, info_unit *tm);
+
+
+void render_view_chassis (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int chassis, SDL_Texture *sprites);
+
+void render_view_battery (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int batt);
+
+void render_view_armor (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int armor);
+void render_view_armor_detail (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int armor);
+
+void render_view_weapon (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int weapon);
+void render_view_weapon_detail (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int weapon);
+
+void render_view_aug (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int aug);
+void render_view_aug_detail (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int aug);
+
+void render_view_brain (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int brain);
+
+
+void render_view_template (SDL_Renderer* rend, txtd *t, int px, int py,
+ infos *info, int temp);
+
+
+#endif \ No newline at end of file
diff --git a/json/jsmn.h b/json/jsmn.h
new file mode 100644
index 0000000..3178dcc
--- /dev/null
+++ b/json/jsmn.h
@@ -0,0 +1,471 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef JSMN_H
+#define JSMN_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef JSMN_STATIC
+#define JSMN_API static
+#else
+#define JSMN_API extern
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ * o Object
+ * o Array
+ * o String
+ * o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+ JSMN_UNDEFINED = 0,
+ JSMN_OBJECT = 1,
+ JSMN_ARRAY = 2,
+ JSMN_STRING = 3,
+ JSMN_PRIMITIVE = 4
+} jsmntype_t;
+
+enum jsmnerr {
+ /* Not enough tokens were provided */
+ JSMN_ERROR_NOMEM = -1,
+ /* Invalid character inside JSON string */
+ JSMN_ERROR_INVAL = -2,
+ /* The string is not a full JSON packet, more bytes expected */
+ JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * type type (object, array, string etc.)
+ * start start position in JSON data string
+ * end end position in JSON data string
+ */
+typedef struct jsmntok {
+ jsmntype_t type;
+ int start;
+ int end;
+ int size;
+#ifdef JSMN_PARENT_LINKS
+ int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string.
+ */
+typedef struct jsmn_parser {
+ unsigned int pos; /* offset in the JSON string */
+ unsigned int toknext; /* next token to allocate */
+ int toksuper; /* superior token node, e.g. parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each
+ * describing
+ * a single JSON object.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+ jsmntok_t *tokens, const unsigned int num_tokens);
+
+#ifndef JSMN_HEADER
+/**
+ * Allocates a fresh unused token from the token pool.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+ const size_t num_tokens) {
+ jsmntok_t *tok;
+ if (parser->toknext >= num_tokens) {
+ return NULL;
+ }
+ tok = &tokens[parser->toknext++];
+ tok->start = tok->end = -1;
+ tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+ tok->parent = -1;
+#endif
+ return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+ const int start, const int end) {
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+ const size_t len, jsmntok_t *tokens,
+ const size_t num_tokens) {
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+ /* In strict mode primitive must be followed by "," or "}" or "]" */
+ case ':':
+#endif
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ case ',':
+ case ']':
+ case '}':
+ goto found;
+ default:
+ /* to quiet a warning from gcc*/
+ break;
+ }
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#ifdef JSMN_STRICT
+ /* In strict mode primitive must be followed by a comma/object/array */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+#endif
+
+found:
+ if (tokens == NULL) {
+ parser->pos--;
+ return 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ parser->pos--;
+ return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+ const size_t len, jsmntok_t *tokens,
+ const size_t num_tokens) {
+ jsmntok_t *token;
+
+ int start = parser->pos;
+
+ parser->pos++;
+
+ /* Skip starting quote */
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c = js[parser->pos];
+
+ /* Quote: end of string */
+ if (c == '\"') {
+ if (tokens == NULL) {
+ return 0;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ return 0;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if (c == '\\' && parser->pos + 1 < len) {
+ int i;
+ parser->pos++;
+ switch (js[parser->pos]) {
+ /* Allowed escaped symbols */
+ case '\"':
+ case '/':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'r':
+ case 'n':
+ case 't':
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ parser->pos++;
+ for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
+ i++) {
+ /* If it isn't a hex character we have an error */
+ if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ parser->pos++;
+ }
+ parser->pos--;
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+ jsmntok_t *tokens, const unsigned int num_tokens) {
+ int r;
+ int i;
+ jsmntok_t *token;
+ int count = parser->toknext;
+
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ char c;
+ jsmntype_t type;
+
+ c = js[parser->pos];
+ switch (c) {
+ case '{':
+ case '[':
+ count++;
+ if (tokens == NULL) {
+ break;
+ }
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
+ if (token == NULL) {
+ return JSMN_ERROR_NOMEM;
+ }
+ if (parser->toksuper != -1) {
+ jsmntok_t *t = &tokens[parser->toksuper];
+#ifdef JSMN_STRICT
+ /* In strict mode an object or array can't become a key */
+ if (t->type == JSMN_OBJECT) {
+ return JSMN_ERROR_INVAL;
+ }
+#endif
+ t->size++;
+#ifdef JSMN_PARENT_LINKS
+ token->parent = parser->toksuper;
+#endif
+ }
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case '}':
+ case ']':
+ if (tokens == NULL) {
+ break;
+ }
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+ if (parser->toknext < 1) {
+ return JSMN_ERROR_INVAL;
+ }
+ token = &tokens[parser->toknext - 1];
+ for (;;) {
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ token->end = parser->pos + 1;
+ parser->toksuper = token->parent;
+ break;
+ }
+ if (token->parent == -1) {
+ if (token->type != type || parser->toksuper == -1) {
+ return JSMN_ERROR_INVAL;
+ }
+ break;
+ }
+ token = &tokens[token->parent];
+ }
+#else
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ if (token->type != type) {
+ return JSMN_ERROR_INVAL;
+ }
+ parser->toksuper = -1;
+ token->end = parser->pos + 1;
+ break;
+ }
+ }
+ /* Error if unmatched closing bracket */
+ if (i == -1) {
+ return JSMN_ERROR_INVAL;
+ }
+ for (; i >= 0; i--) {
+ token = &tokens[i];
+ if (token->start != -1 && token->end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+#endif
+ break;
+ case '\"':
+ r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+ if (r < 0) {
+ return r;
+ }
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL) {
+ tokens[parser->toksuper].size++;
+ }
+ break;
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ break;
+ case ':':
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case ',':
+ if (tokens != NULL && parser->toksuper != -1 &&
+ tokens[parser->toksuper].type != JSMN_ARRAY &&
+ tokens[parser->toksuper].type != JSMN_OBJECT) {
+#ifdef JSMN_PARENT_LINKS
+ parser->toksuper = tokens[parser->toksuper].parent;
+#else
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ parser->toksuper = i;
+ break;
+ }
+ }
+ }
+#endif
+ }
+ break;
+#ifdef JSMN_STRICT
+ /* In strict mode primitives are: numbers and booleans */
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 't':
+ case 'f':
+ case 'n':
+ /* And they must not be keys of the object */
+ if (tokens != NULL && parser->toksuper != -1) {
+ const jsmntok_t *t = &tokens[parser->toksuper];
+ if (t->type == JSMN_OBJECT ||
+ (t->type == JSMN_STRING && t->size != 0)) {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+#else
+ /* In non-strict mode every unquoted value is a primitive */
+ default:
+#endif
+ r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+ if (r < 0) {
+ return r;
+ }
+ count++;
+ if (parser->toksuper != -1 && tokens != NULL) {
+ tokens[parser->toksuper].size++;
+ }
+ break;
+
+#ifdef JSMN_STRICT
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+#endif
+ }
+ }
+
+ if (tokens != NULL) {
+ for (i = parser->toknext - 1; i >= 0; i--) {
+ /* Unmatched opened object or array */
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
+ return JSMN_ERROR_PART;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+JSMN_API void jsmn_init(jsmn_parser *parser) {
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
+
+#endif /* JSMN_HEADER */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* JSMN_H */
diff --git a/json/jsonparse.c b/json/jsonparse.c
new file mode 100644
index 0000000..6cfae2e
--- /dev/null
+++ b/json/jsonparse.c
@@ -0,0 +1,167 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <jsonparse.h>
+
+void substr_token (char *json, char *temp, jsmntok_t *t) {
+ memcpy(temp, json+t->start, t->end - t->start);
+ temp[t->end-t->start] = '\0';
+}
+
+void json_parse_array(char *json, void *temp, jsmntok_t *t, int r, char type) {
+ for (int i=0; i<r; i++) {
+ if (t[i].type == JSMN_PRIMITIVE) {
+ char val[32]; substr_token(json, val, t+i);
+ if (type == 'i') {
+ int *p = (int*)(intptr_t)temp+sizeof(int)*i;
+ *p = atoi(val);
+ }
+ if (type == 'c') {
+ int8_t *p = (int8_t*)(intptr_t)temp+sizeof(int8_t)*i;
+ *p = atoi(val);
+ }
+ }
+ }
+}
+
+void json_dump_array (char *str, void *arr, int len, char type) {
+ int cur = 0;
+ sprintf(str+cur, "[ "); cur = strlen(str);
+ for (int i=0; i<len; i++) {
+ if (type == 'i') {
+ sprintf(str+cur, "%d", (int)(intptr_t)(arr+i*sizeof(int)));
+ cur = strlen(str);
+ }
+ if (type == 'c') {
+ printf("%d\n", ((int8_t*)(intptr_t)(arr))[i]);
+ sprintf(str+cur, "%d", ((int8_t*)(intptr_t)(arr))[i]);
+ cur = strlen(str);
+ }
+ if (i < len-1) {
+ sprintf(str+cur, ", "); cur = strlen(str);
+ }
+ }
+ sprintf(str+cur, " ]");
+}
+
+int json_parse_subtokens (char *json, jsmntok_t *t, int r, int i) {
+ int rt = 0;
+ for (int j=i; j<r; j++) {
+ if (t[j].start < t[i].end) { rt ++; }
+ else { break; }
+ }
+ return rt;
+}
+
+/* DEPRECATED TRIALS, delete after backup
+// parses a <str, int> pair set with a set of already parsed tokens
+int json_parse_dict_ci_init (char *json,
+ pair_ci *dict, jsmntok_t *t, int r) {
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i++) {
+ if (t[i].type == JSMN_OBJECT) {
+ dict_i ++;
+ obj_i = 0;
+ }
+ if (t[i].type == JSMN_STRING) {
+ if (obj_i == 0) {
+ substr_token(json, dict[dict_i].key, t+i);
+ } else if (obj_i == 1) {
+ char ts[13]; substr_token(json, ts, t+i);
+ dict[dict_i].i = atoi(ts);
+ }
+ obj_i++;
+ }
+ }
+ return dict_i+1;
+}
+
+// parses a <str, int> pair set with a set of already parsed tokens
+int json_parse_dict_cf_init (char *json,
+ pair_cf *dict, jsmntok_t *t, int r) {
+ int obj_i = 0, dict_i = -1;
+ for (int i=0; i<r; i++) {
+ if (t[i].type == JSMN_OBJECT) {
+ dict_i ++;
+ obj_i = 0;
+ }
+ if (t[i].type == JSMN_STRING) {
+ if (obj_i == 0) {
+ substr_token(json, dict[dict_i].key, t+i);
+ } else if (obj_i == 1) {
+ char ts[13]; substr_token(json, ts, t+i);
+ dict[dict_i].i = atof(ts);
+ }
+ obj_i++;
+ }
+ }
+ return dict_i+1;
+}
+
+
+// parses a <str, int> pair set
+int json_parse_dict_ci (char *json, pair_ci *dict) {
+ jsmn_parser p; jsmn_init(&p);
+ jsmntok_t t[MAXTOKENS];
+ int r = jsmn_parse(&p, json, strlen(json), t, MAXTOKENS);
+ json_parse_dict_ci_init(json, dict, t, r);
+}
+
+// parses a <str, float> pair set
+int json_parse_dict_cf (char *json, pair_cf *dict) {
+ jsmn_parser p; jsmn_init(&p);
+ jsmntok_t t[MAXTOKENS];
+ int r = jsmn_parse(&p, json, strlen(json), t, MAXTOKENS);
+ json_parse_dict_cf_init(json, dict, t, r);
+}
+
+
+
+// parses a list of objects which are lists of pairs <str, int>
+int json_parse_list_ci (char *json, list_ci *list) {
+ jsmn_parser p; jsmn_init(&p);
+ jsmntok_t t[MAXTOKENS];
+ int r = jsmn_parse(&p, json, strlen(json), t, MAXTOKENS);
+ int list_i = 0;
+ for (int i=1; i<r; i++) { // i=1: ignore outer []
+ if (t[i].type == JSMN_ARRAY) {
+ int rt = 0;
+ for (int j=i; j<r; j++) {
+ if (t[j].start < t[i].end) { rt ++; }
+ else { break; }
+ }
+ int len = json_parse_dict_ci_init(
+ json, list[list_i].pairs, t+i, rt);
+ list[list_i].len = len;
+ list_i ++;
+ i += rt-1;
+ }
+ }
+ return list_i;
+}
+
+// parses a list of objects which are lists of pairs <str, float>
+int json_parse_list_cf (char *json, list_cf *list) {
+ jsmn_parser p; jsmn_init(&p);
+ jsmntok_t t[MAXTOKENS];
+ int r = jsmn_parse(&p, json, strlen(json), t, MAXTOKENS);
+ int list_i = 0;
+ for (int i=1; i<r; i++) { // i=1: ignore outer []
+ if (t[i].type == JSMN_ARRAY) {
+ int rt = 0;
+ for (int j=i; j<r; j++) {
+ if (t[j].start < t[i].end) { rt ++; }
+ else { break; }
+ }
+ int len = json_parse_dict_cf_init(
+ json, list[list_i].pairs, t+i, rt);
+ list[list_i].len = len;
+ list_i ++;
+ i += rt-1;
+ }
+ }
+ return list_i;
+}
+*/ \ No newline at end of file
diff --git a/json/jsonparse.h b/json/jsonparse.h
new file mode 100644
index 0000000..2186154
--- /dev/null
+++ b/json/jsonparse.h
@@ -0,0 +1,35 @@
+#ifndef JSONPARSE_H
+#define JSONPARSE_H
+
+#define JSMN_STATIC
+#include <jsmn.h>
+
+#define MAXTOKENS 2048
+
+void substr_token(char *json, char *temp, jsmntok_t *t);
+
+void json_parse_array(char *json, void *temp, jsmntok_t *t, int r, char type);
+void json_dump_array (char *str, void *arr, int len, char type);
+
+int json_parse_subtokens (char *json, jsmntok_t *t, int r, int i);
+/*
+
+typedef struct { char key[32]; int i; } pair_ci;
+typedef struct { char key[32]; float i; } pair_cf;
+
+
+int json_parse_dict_ci_init (char *json, pair_ci *dict, jsmntok_t *t, int r);
+int json_parse_dict_cf_init (char *json, pair_cf *dict, jsmntok_t *t, int r);
+int json_parse_dict_ci (char *json, pair_ci *dict);
+int json_parse_dict_cf (char *json, pair_cf *dict);
+
+#define MAXLISTLEN 64
+#define MAXOBJLEN 32
+
+typedef struct { pair_ci pairs[MAXOBJLEN]; int len; } list_ci;
+typedef struct { pair_cf pairs[MAXOBJLEN]; int len; } list_cf;
+
+int json_parse_list_ci (char *json, list_ci *list);
+int json_parse_list_cf (char *json, list_cf *list);
+*/
+#endif \ No newline at end of file
diff --git a/lcb.py b/lcb.py
new file mode 100644
index 0000000..54a6b65
--- /dev/null
+++ b/lcb.py
@@ -0,0 +1,61 @@
+# Jacopo Grandi, 15/08/2020
+# Link - Compile - Build
+# mingw command creation and execution
+
+try:
+ import os
+ import sys
+
+ if len(sys.argv) > 1:
+ os.chdir(sys.argv[1])
+
+ if not("main.c" in os.listdir(".")):
+ # try searching father folder
+ os.chdir("../")
+ if not("main.c" in os.listdir(".")):
+ print("no main.c found, press any key to abort...")
+ import msvcrt as m
+ m.getch()
+ quit()
+
+ dirs = "-I. "
+ fs = ""
+ for d in os.listdir("."):
+ if d.find(".") == -1:
+ flag = False
+ for f in os.listdir("./"+d+"/"):
+ if f.endswith(".c"):
+ fs += d+"/"+f+" "
+ flag = True
+ if flag: dirs += "-I" + d + " "
+
+ cons = ""
+ f = open("main.c", "r");
+ mainraw = f.read(); f.close();
+ if "#define LCB_NO_CONSOLE" in mainraw.splitlines():
+ cons = "-Wl,-subsystem,windows"
+
+ os.system("mkdir build")
+ cmd = "g++ "+\
+ "main.c "+\
+ fs+\
+ dirs+\
+ "-IC:\MinGW_libs\include\SDL2 "+\
+ "-IC:\MinGW_libs\include\plibsys "+\
+ "-LC:\MinGW_libs\lib "+\
+ "-w "+\
+ "-lmingw32 -lSDL2main -lSDL2 -lSDL2_mixer -lplibsys "+\
+ "-o build/test "+\
+ cons
+ print(cmd)
+ r = os.system(cmd)
+
+ if r == 0:
+ print("build successfull")
+ os.chdir("build")
+ os.system("test.exe")
+ else:
+ os.system("pause")
+except e:
+ import traceback;
+ open("error.txt", "w").write(''.join(tb.format_exception(None, e, e.__traceback__))) \ No newline at end of file
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2e92bc1
--- /dev/null
+++ b/main.c
@@ -0,0 +1,231 @@
+//#define LCB_NO_CONSOLE
+
+#include <SDL.h>
+#include <SDL_mixer.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <jsonparse.h>
+#include <render_text.h>
+#include <graphicsettings.h>
+#include <button.h>
+#include <mkb.h>
+#include <vec.h>
+#include <net.h>
+
+#include <units.h>
+#include <map.h>
+#include <info.h>
+#include <hud.h>
+#include <gst.h>
+
+//The music that will be played
+Mix_Music *gMusic = NULL;
+
+//The sound effects that will be used
+Mix_Chunk *sounds[16];
+
+
+int main( int argc, char* args[] ) {
+ net_init();
+
+ graphic_settings gs = { 1250, 700 };
+
+ SDL_Window* window = NULL;
+ SDL_Surface* screenSurface = NULL;
+ SDL_Renderer* rend = NULL;
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+
+ window = SDL_CreateWindow("DESCRIPT", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, gs.resx, gs.resy, SDL_WINDOW_SHOWN
+ | SDL_WINDOW_RESIZABLE);
+ screenSurface = SDL_GetWindowSurface(window);
+
+ rend = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+
+ // render text init
+ txtd textd; char_width_init(textd.cw);
+ SDL_Surface* image = SDL_LoadBMP("content/gf.bmp");
+ textd.tex = SDL_CreateTextureFromSurface(rend, image);
+
+ SDL_Surface* sprites = SDL_LoadBMP("content/sprites.bmp");
+ SDL_Texture* txsprites = SDL_CreateTextureFromSurface(rend, sprites);
+
+ Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 2048 );
+ #define SOUND_MOUSE_OVER 0
+ sounds[SOUND_MOUSE_OVER] = Mix_LoadWAV(
+ "content/sounds/mouse_over.wav" );
+ #define SOUND_MOUSE_CLICK_0 1
+ sounds[SOUND_MOUSE_CLICK_0] = Mix_LoadWAV(
+ "content/sounds/mouse_click_0.wav" );
+ #define SOUND_MOUSE_WHEEL 2
+ sounds[SOUND_MOUSE_WHEEL] = Mix_LoadWAV(
+ "content/sounds/mouse_wheel.wav" );
+ #define SOUND_SUCCESS 3
+ sounds[SOUND_SUCCESS] = Mix_LoadWAV(
+ "content/sounds/success.wav" );
+ Mix_Volume(-1,MIX_MAX_VOLUME/16);
+ // Mix_PlayChannel( -1, mouse_over, 0 );
+
+ // frame timing
+ const double FRAME_TIME = (double)1/60; // delta time for 60 FPS
+ double last_time = SDL_GetTicks();
+ double frame_counter = 0;
+ double tot_time = 0;
+ double unprocessed_time = 0;
+ int frames = 0;
+
+ // mouse and keyboard
+ MKb mkb;
+ mkb_init(&mkb);
+
+
+ // info
+ infos info;
+ info_load(&info);
+
+ gamestate gst;
+ gst_init(&gst);
+ gst.cam[0] = -gs.resx/2+gst.map_editor.sx*gst.map_editor.ts/2;
+ gst.cam[1] = -gs.resy/2+gst.map_editor.sy*gst.map_editor.ts/2;
+
+ // hud
+ hud _hud;
+ hud_init(&gs, &_hud, &textd);
+ _hud.og.army_listlen = info_army_get_list(_hud.og.army_list);
+ info_load_playername(_hud.og.playername);
+
+ float mlast[2] = {0, 0};
+
+ // sockets
+ net_client netc;
+ net_server nets;
+ int server = 0;
+
+ bool quit = false;
+ SDL_Event e;
+ while(!quit) {
+ while(SDL_PollEvent(&e) != 0) {
+ if(e.type == SDL_QUIT) {
+ quit = true;
+ }
+ if(e.type == SDL_WINDOWEVENT
+ && e.window.event == SDL_WINDOWEVENT_RESIZED ) {
+ gs.resx = e.window.data1; gs.resy = e.window.data2;
+ SDL_SetWindowSize(window, gs.resx, gs.resy);
+ hud_resize(&gs, &_hud, &textd);
+ }
+ mkb_event(&mkb, &e);
+ }
+
+ bool render = false;
+
+ double startTime = SDL_GetTicks();
+ double passedTime = (startTime - last_time)/1000;
+ last_time = startTime;
+
+ unprocessed_time += passedTime;
+ frame_counter += passedTime;
+ tot_time += passedTime;
+
+ if (frame_counter >= 1.0) {
+ //printf("FPS: %i | %f ms\n", frames, 1000.0 / ((double)frames));
+ frames = 0;
+ frame_counter = 0;
+ }
+
+ while (unprocessed_time > FRAME_TIME) {
+ float mp[2] = { mkb.mx, mkb.my };
+ if (mkb.mclick[1] == 1) {
+ float delta[2] = { mkb.mx-mlast[0], mkb.my-mlast[1] };
+ vec2_sub(gst.cam, gst.cam, delta);
+ }
+ /*
+ if (mkb_search(&mkb, SDL_SCANCODE_E)) {
+ map *m; army *ar;
+ gst_get_maparmy(&gst, &m, &ar);
+ army_move(&info, ar, m);
+ army_fire(&info, ar, m);
+ }*/
+
+ hud_process(&gs, &_hud, &mkb, &info,
+ gst.army_bp+0, &gst.map_editor, &textd, &gst,
+ &netc, &nets, sounds);
+
+ if (gst.state == 1) {
+ gst_process(&gst, &info, tot_time);
+ }
+
+ render = true;
+ unprocessed_time -= FRAME_TIME;
+ mlast[0] = mkb.mx; mlast[1] = mkb.my;
+ mkb_process(&mkb);
+ }
+
+ if (render) {
+ SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
+ SDL_RenderClear(rend);
+
+ float ts = 32;
+ int posx = gst.cam[0];
+ int posy = gst.cam[1];
+
+ map *m; army *ar;
+ gst_get_maparmy(&gst, &m, &ar);
+
+ // render map
+ for (int y=0; y<m->sy; y++) {
+ for (int x=0; x<m->sx; x++) {
+ float px = x*ts;
+ float py = y*ts;
+ SDL_Rect srcRect = { 1*ts, 0*ts, ts, ts };
+ SDL_Rect dstRect = { (int)px-posx, (int)py-posy, ts, ts };
+ SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect);
+ }
+ }
+
+ // render enemies
+ for (int i=0; i<ar->uslen; i++) {
+ if (ar->us[i].hp <= 0) continue;
+ float x = ar->us[i].pos[0];
+ float y = ar->us[i].pos[1];
+ SDL_Rect srcRect = { ar->us[i].info.chassis*ts, ts, ts, ts };
+ SDL_Rect dstRect = { (int)x-posx, (int)y-posy, ts, ts };
+ SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect);
+
+ float amt = ar->us[i].hp
+ / info_unit_get_health(&info, &ar->us[i].info);
+ SDL_Rect hprect = {
+ (int)x-posx, (int)y-posy+ts-5,
+ ts*amt, 5 };
+ int sw = 1 ? ar->us[i].owner : 0;
+ SDL_SetRenderDrawColor(rend, 255*sw, 255*(1-sw), 0, 255);
+ SDL_RenderFillRect(rend, &hprect);
+
+ char shp[32]; sprintf(shp, "%.0f", ar->us[i].hp);
+ float php[2] = { (int)x-posx, (int)y-posy+ts-5 };
+ render_text_scaled(rend, shp, php, &textd, 1);
+ }
+
+ hud_render(&_hud, rend, &textd, &mkb, &info, txsprites);
+
+ SDL_RenderPresent(rend);
+ frames++;
+ }
+ else {
+ SDL_Delay(1);
+ }
+ }
+
+ Mix_FreeMusic(gMusic);
+ SDL_DestroyWindow(window);
+ Mix_Quit();
+ SDL_Quit();
+ net_client_close(&netc);
+ gst_destroy(&gst);
+
+ return 0;
+} \ No newline at end of file
diff --git a/mkb/mkb.c b/mkb/mkb.c
new file mode 100644
index 0000000..169aa8c
--- /dev/null
+++ b/mkb/mkb.c
@@ -0,0 +1,53 @@
+#include <mkb.h>
+
+bool mkb_search(MKb *mkb, SDL_Scancode scancode) {
+ for (int i=0; i<mkb->kbnum; i++) {
+ if (mkb->kb[i] == scancode)
+ return true;
+ }
+ return false;
+}
+
+bool mkb_statesearch (MKb *mkb, SDL_Scancode scancode) {
+ const Uint8 *state = SDL_GetKeyboardState(NULL);
+ if (state[scancode]) return true;
+ return false;
+}
+
+void mkb_init(MKb *mkb) {
+ mkb->kbnum = 0;
+ for (int i=0;i<3;mkb->mheld[i]=0,mkb->mclick[i]=0,i++);
+ mkb->mwheeldelta = 0;
+}
+
+void mkb_process(MKb *mkb) {
+ mkb->kbnum = 0;
+ SDL_GetMouseState(&(mkb->mx), &(mkb->my));
+ for (int i=0;i<3;i++) {
+ if (mkb->mclick[i] > 0) mkb->mheld[i] += 1;
+ else if (mkb->mheld[i] > 0) mkb->mheld[i] = -1;
+ else mkb->mheld[i] = 0;
+ }
+ mkb->mwheeldelta = 0;
+}
+
+void mkb_event(MKb *mkb, SDL_Event *e) {
+ if(e->type == SDL_KEYDOWN && e->key.repeat == 0) {
+ mkb->kb[mkb->kbnum++] = e->key.keysym.scancode;
+ }
+ if(e->type == SDL_KEYUP) {
+ }
+ if(e->type == SDL_MOUSEBUTTONDOWN) {
+ if (e->button.button == SDL_BUTTON_LEFT) { mkb->mclick[0] = 1; }
+ if (e->button.button == SDL_BUTTON_MIDDLE) { mkb->mclick[1] = 1; }
+ if (e->button.button == SDL_BUTTON_RIGHT) { mkb->mclick[2] = 1; }
+ }
+ if(e->type == SDL_MOUSEBUTTONUP) {
+ if (e->button.button == SDL_BUTTON_LEFT) { mkb->mclick[0] = 0; }
+ if (e->button.button == SDL_BUTTON_MIDDLE) { mkb->mclick[1] = 0; }
+ if (e->button.button == SDL_BUTTON_RIGHT) { mkb->mclick[2] = 0; }
+ }
+ if(e->type == SDL_MOUSEWHEEL) {
+ mkb->mwheeldelta = e->wheel.y;
+ }
+} \ No newline at end of file
diff --git a/mkb/mkb.h b/mkb/mkb.h
new file mode 100644
index 0000000..74b1a47
--- /dev/null
+++ b/mkb/mkb.h
@@ -0,0 +1,24 @@
+#ifndef MKB_H
+#define MKB_H
+
+#include <SDL.h>
+
+// SDL2 mouse and keyboard
+
+typedef struct {
+ SDL_Scancode kb[128]; /* keyboard state, reset every frame */
+ int kbnum;
+ int mx; /* mouse x pos */
+ int my; /* mouse y pos */
+ int mclick[3];
+ int mheld[3];
+ int mwheeldelta;
+} MKb;
+
+void mkb_init(MKb *mkb);
+bool mkb_search(MKb *mkb, SDL_Scancode scancode);
+bool mkb_statesearch(MKb *mkb, SDL_Scancode scancode);
+void mkb_event(MKb *mkb, SDL_Event *e);
+void mkb_process(MKb *mkb);
+
+#endif \ No newline at end of file
diff --git a/net/net.c b/net/net.c
new file mode 100644
index 0000000..7e1dbf4
--- /dev/null
+++ b/net/net.c
@@ -0,0 +1,168 @@
+#include <net.h>
+
+void itob (char *buf, int n) {
+ buf[0] = (n >> 24) & 0xFF;
+ buf[1] = (n >> 16) & 0xFF;
+ buf[2] = (n >> 8) & 0xFF;
+ buf[3] = n & 0xFF;
+}
+
+int btoi (char *buf) {
+ int n = 0;
+ n += buf[0]*256*256*256;
+ n += buf[1]*256*256;
+ n += buf[2]*256;
+ n += buf[3];
+ return n;
+}
+
+
+void net_init () {
+ p_libsys_init ();
+}
+
+int net_open_socket(PSocket **socket, int port) {
+ *socket = p_socket_new (P_SOCKET_FAMILY_INET,
+ P_SOCKET_TYPE_STREAM,
+ P_SOCKET_PROTOCOL_TCP,
+ NULL);
+ p_socket_set_blocking (*socket, FALSE);
+ p_socket_set_timeout (*socket, 10);
+ PSocketAddress *sock_addr = p_socket_address_new("127.0.0.1", port);
+ int sender_port = 0;
+ if (p_socket_bind (*socket, sock_addr, FALSE, NULL) == FALSE) {
+ p_socket_free (*socket);
+ p_socket_address_free (sock_addr);
+ return 1;
+ } else {
+ p_socket_address_free (sock_addr);
+ PSocketAddress *local_addr = p_socket_get_local_address(*socket, NULL);
+ if (local_addr == NULL) {
+ p_socket_free (*socket);
+ p_uthread_exit (-1);
+ return 2;
+ }
+ sender_port = p_socket_address_get_port (local_addr);
+ p_socket_address_free (local_addr);
+ }
+ return 0;
+}
+
+int net_recv (PSocket *socket, char buffer[]) {
+ int len = 0;
+ for (int i=0; ; i++) {
+ psize recv_now = p_socket_receive (socket,
+ buffer+i*1024, 1024, NULL);
+ if (recv_now == -1) {
+ if (len > 0) {
+ printf("received (%d)\n", len);
+ return len;
+ }
+ printf("error server recv\n");
+ return -1;
+ } else {
+ len += recv_now;
+ if (recv_now < 1024) {
+ printf("received (%d)\n", len);
+ return len;
+ }
+ }
+ }
+ printf("received (%d)\n", len);
+ return len;
+}
+
+
+void net_client_open(net_client *c) {
+ int err = net_open_socket(&c->socket, 0);
+ if (err > 0) printf("error opening client socket: %d\n", err);
+}
+
+int net_client_connect (net_client *c, char ip[], int port) {
+ c->addr_server = p_socket_address_new(ip, port);
+ if (c->addr_server == NULL) printf("error client making server addr\n");
+ int is_connected = p_socket_connect(c->socket, c->addr_server, NULL);
+ if (is_connected == FALSE) {
+ if (p_socket_io_condition_wait
+ (c->socket, P_SOCKET_IO_CONDITION_POLLOUT, NULL) == TRUE &&
+ p_socket_check_connect_result (c->socket, NULL) == FALSE)
+ {
+ p_socket_address_free (c->addr_server);
+ p_socket_free (c->socket);
+ p_uthread_exit (-1);
+ printf("error client socket freed\n");
+ }
+ }
+
+ is_connected = p_socket_is_connected (c->socket);
+ if (is_connected == FALSE) {
+ printf("error client can't connect to %s:%d\n", ip, port);
+ return 1;
+ }
+ return 0;
+}
+
+void net_client_send (net_client *c, char data[], int sizeofdata) {
+ if(p_socket_is_connected (c->socket) == FALSE) {
+ printf("error client send lost connection\n");
+ }
+ PError *err;
+ int send_now = p_socket_send (c->socket, data, sizeofdata, &err);
+ if (send_now == -1) printf("error: %d\n", p_error_get_code(err));
+}
+
+int net_client_recv (net_client *c, char buffer[]) {
+ net_recv(c->socket, buffer);
+}
+
+void net_client_close (net_client *c) {
+ p_socket_close (c->socket, NULL);
+ p_socket_address_free (c->addr_server);
+ p_socket_free (c->socket);
+}
+
+
+
+void net_server_open(net_server *s, int port) {
+ int err = net_open_socket(&s->socket, port);
+ if (err > 0) printf("error opening server socket: %d\n", err);
+ if (p_socket_listen (s->socket, NULL) == FALSE) {
+ printf("error server socket listen, nobody in.\n");
+ return;
+ }
+}
+
+void net_server_accept (net_server *s) {
+ pboolean poll = p_socket_io_condition_wait (s->socket,
+ P_SOCKET_IO_CONDITION_POLLIN, NULL);
+ if (poll == FALSE) {
+ printf("server socket, no one in queue\n");
+ return;
+ }
+ s->sock_client = p_socket_accept (s->socket, NULL);
+ if (s->sock_client == NULL) {
+ printf("server socket, no accept\n");
+ }
+ p_socket_set_blocking (s->sock_client, FALSE);
+ printf("connected\n");
+}
+
+int net_server_recv (net_server *s, char buffer[]) {
+ net_recv(s->sock_client, buffer);
+}
+
+void net_server_send (net_server *s, char data[], int sizeofdata) {
+ if(p_socket_is_connected (s->sock_client) == FALSE) {
+ printf("error client send lost connection\n");
+ return;
+ }
+ PError *err;
+ int send_now = p_socket_send (s->sock_client, data, sizeofdata, &err);
+ if (send_now == -1) printf("error: %d\n", p_error_get_code(err));
+}
+
+void net_server_close (net_server *s) {
+ p_socket_close (s->socket, NULL);
+ p_socket_free (s->sock_client);
+ p_socket_free(s->socket);
+}
diff --git a/net/net.h b/net/net.h
new file mode 100644
index 0000000..056114b
--- /dev/null
+++ b/net/net.h
@@ -0,0 +1,35 @@
+#ifndef NET_H
+#define NET_H
+
+#include <plibsys.h>
+
+#define SERVER_PORT 9999
+
+void itob (char *buf, int n);
+int btoi (char *buf);
+
+void net_init ();
+
+typedef struct {
+ PSocket *socket;
+ PSocketAddress * addr_server;
+} net_client;
+
+void net_client_open(net_client *c);
+int net_client_connect (net_client *c, char ip[], int port);
+int net_client_recv(net_client *c, char buffer[]);
+void net_client_send (net_client *c, char data[], int sizeofdata);
+void net_client_close (net_client *c);
+
+typedef struct {
+ PSocket *socket;
+ PSocket *sock_client;
+} net_server;
+
+void net_server_open(net_server *s, int port);
+void net_server_accept(net_server *s);
+int net_server_recv(net_server *s, char buffer[]);
+void net_server_send (net_server *s, char data[], int sizeofdata);
+void net_server_close (net_server *s);
+
+#endif \ No newline at end of file
diff --git a/render/button.c b/render/button.c
new file mode 100644
index 0000000..eb96f59
--- /dev/null
+++ b/render/button.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <button.h>
+
+#include <intersect.h>
+
+bool mouse_in_button (float pt[], txtd *t, button *b) {
+ int width = get_text_width(b->txt, t);
+ float size[2] = { width+b->pad*2, 10+b->pad*2 };
+ if (pt_rect(pt, b->pos, size)) return true;
+ return false;
+}
+
+void render_button (SDL_Renderer* rend, txtd *t, button *b) {
+ int width = get_text_width(b->txt, t);
+ SDL_Rect rect = { b->pos[0], b->pos[1], width+b->pad*2, 10+b->pad*2 };
+ SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
+ SDL_RenderDrawRect(rend, &rect);
+ float offpad[2] = { b->pos[0]+b->pad, b->pos[1]+b->pad };
+ render_text(rend, b->txt, offpad, t);
+} \ No newline at end of file
diff --git a/render/button.h b/render/button.h
new file mode 100644
index 0000000..b8d10b6
--- /dev/null
+++ b/render/button.h
@@ -0,0 +1,16 @@
+#ifndef BUTTON_H
+#define BUTTON_H
+
+#include <SDL.h>
+#include <render_text.h>
+
+typedef struct {
+ char txt[32];
+ int pad;
+ float pos[2];
+} button;
+
+bool mouse_in_button (float pt[], txtd *t, button *b);
+void render_button (SDL_Renderer* rend, txtd *t, button *b);
+
+#endif \ No newline at end of file
diff --git a/render/graphicsettings.h b/render/graphicsettings.h
new file mode 100644
index 0000000..53a83c2
--- /dev/null
+++ b/render/graphicsettings.h
@@ -0,0 +1,8 @@
+#ifndef GRAPHICSETTINGS_H
+#define GRAPHICSETTINGS_H
+
+typedef struct {
+ int resx, resy;
+} graphic_settings;
+
+#endif \ No newline at end of file
diff --git a/render/render_text.c b/render/render_text.c
new file mode 100644
index 0000000..67a13e2
--- /dev/null
+++ b/render/render_text.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <render_text.h>
+
+void char_width_init (int *char_width) {
+ for (int i=0; i<128; char_width[i++]=5);
+ char_width[','] = 1; char_width['-'] = 3; char_width['.'] = 1;
+ char_width['/'] = 4; char_width['!'] = 1;
+ char_width[':'] = 1; char_width[';'] = 1;
+ char_width['<'] = 3; char_width['>'] = 3; char_width['='] = 4;
+ char_width['I'] = 1;
+ char_width['f'] = 4; char_width['i'] = 1; char_width['j'] = 3;
+ char_width['l'] = 1; char_width['k'] = 4; char_width['t'] = 4;
+}
+
+int get_text_width (char str[], txtd *t) {
+ int width = 0;
+ for (int i=0; str[i]!='\0'; i++) {
+ width += t->cw[str[i]];
+ if (str[i+1]!='\0') width++;
+ }
+ return width;
+}
+
+void render_text (SDL_Renderer* gRenderer, char str[], float off[], txtd *t)
+{
+ int width = 0;
+ for (int i=0; str[i]!='\0'; i++) {
+ int char_i = str[i];
+ SDL_Rect srcRect = { (char_i%32)*6+1, (char_i/32)*12+1, 5, 11 };
+ SDL_Rect dstRect = { off[0]+width, off[1], 5, 11 };
+ SDL_RenderCopy(gRenderer, t->tex, &srcRect, &dstRect);
+ width += t->cw[char_i]+1;
+ }
+}
+
+void render_text_scaled (SDL_Renderer* gRenderer, char str[],
+ float off[], txtd *t, float scale)
+{
+ int width = 0;
+ for (int i=0; str[i]!='\0'; i++) {
+ int char_i = str[i];
+ SDL_Rect srcRect = { (char_i%32)*6+1, (char_i/32)*12+1, 5, 11 };
+ SDL_Rect dstRect = { off[0]+width, off[1], 5*scale, 11*scale };
+ SDL_RenderCopy(gRenderer, t->tex, &srcRect, &dstRect);
+ width += t->cw[char_i]*scale+1*scale;
+ }
+} \ No newline at end of file
diff --git a/render/render_text.h b/render/render_text.h
new file mode 100644
index 0000000..e7474ff
--- /dev/null
+++ b/render/render_text.h
@@ -0,0 +1,18 @@
+#ifndef RENDER_TEXT_H
+#define RENDER_TEXT_H
+
+#include <SDL.h>
+
+typedef struct {
+ SDL_Texture *tex;
+ int cw[128];
+} txtd;
+
+void char_width_init (int *char_width);
+int get_text_width (char str[], txtd *t);
+
+void render_text (SDL_Renderer* gRenderer, char str[], float off[], txtd *t);
+void render_text_scaled (SDL_Renderer* gRenderer, char str[],
+ float off[], txtd *t, float scale);
+
+#endif \ No newline at end of file
diff --git a/umath/intersect.c b/umath/intersect.c
new file mode 100644
index 0000000..2d21389
--- /dev/null
+++ b/umath/intersect.c
@@ -0,0 +1,7 @@
+#include <intersect.h>
+
+int pt_rect (float p[], float a[], float b[]) {
+ if (p[0]>a[0] && p[0]<a[0]+b[0] && p[1]>a[1] && p[1]<a[1]+b[1])
+ return 1;
+ return 0;
+} \ No newline at end of file
diff --git a/umath/intersect.h b/umath/intersect.h
new file mode 100644
index 0000000..d3e24ec
--- /dev/null
+++ b/umath/intersect.h
@@ -0,0 +1,7 @@
+#ifndef INTERSECT_H
+#define INTERSECT_H
+
+// rect is [a, b] = [pos, size]
+int pt_rect (float p[], float a[], float b[]);
+
+#endif \ No newline at end of file
diff --git a/umath/vec.c b/umath/vec.c
new file mode 100644
index 0000000..fe82f58
--- /dev/null
+++ b/umath/vec.c
@@ -0,0 +1,42 @@
+#include <vec.h>
+
+float vec2_add (float c[], float a[], float b[]) {
+ c[0]=a[0]+b[0]; c[1]=a[1]+b[1];
+}
+float vec2_sub (float c[], float a[], float b[]) {
+ c[0]=a[0]-b[0]; c[1]=a[1]-b[1];
+}
+float vec2_mul (float c[], float a[], float b) {
+ c[0]=a[0]*b; c[1]=a[1]*b;
+}
+float vec2_div (float c[], float a[], float b) {
+ c[0]=a[0]/b; c[1]=a[1]/b;
+}
+
+float vec2_mag (float v[]) { return sqrt(v[0]*v[0]+v[1]*v[1]); }
+float vec2_mag2 (float v[]) { return v[0]*v[0]+v[1]*v[1]; }
+
+void vec2_norm (float v[]) {
+ float m=vec2_mag(v); v[0]/=m; v[1]/=m;
+}
+
+
+float vec3_add (float c[], float a[], float b[]) {
+ c[0]=a[0]+b[0]; c[1]=a[1]+b[1]; c[2]=a[2]+b[2];
+}
+float vec3_sub (float c[], float a[], float b[]) {
+ c[0]=a[0]-b[0]; c[1]=a[1]-b[1]; c[2]=a[2]-b[2];
+}
+float vec3_mul (float c[], float a[], float b) {
+ c[0]=a[0]*b; c[1]=a[1]*b; c[2]=a[2]*b;
+}
+float vec3_div (float c[], float a[], float b) {
+ c[0]=a[0]/b; c[1]=a[1]/b; c[2]=a[2]/b;
+}
+
+float vec3_mag (float v[]) { return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
+float vec3_mag2 (float v[]) { return v[0]*v[0]+v[1]*v[1]+v[2]*v[2]; }
+
+void vec3_norm (float v[]) {
+ float m=vec3_mag(v); v[0]/=m; v[1]/=m; v[2]/=m;
+} \ No newline at end of file
diff --git a/umath/vec.h b/umath/vec.h
new file mode 100644
index 0000000..b87cae1
--- /dev/null
+++ b/umath/vec.h
@@ -0,0 +1,22 @@
+#ifndef VEC_H
+#define VEC_H
+
+#include <math.h>
+
+float vec2_add (float c[], float a[], float b[]);
+float vec2_sub (float c[], float a[], float b[]);
+float vec2_mul (float c[], float a[], float b);
+float vec2_div (float c[], float a[], float b);
+float vec2_mag (float v[]);
+float vec2_mag2 (float v[]);
+void vec2_norm (float v[]);
+
+float vec3_add (float c[], float a[], float b[]);
+float vec3_sub (float c[], float a[], float b[]);
+float vec3_mul (float c[], float a[], float b);
+float vec3_div (float c[], float a[], float b);
+float vec3_mag (float v[]);
+float vec3_mag2 (float v[]);
+void vec3_norm (float v[]);
+
+#endif \ No newline at end of file