From 20a21f0f28bf6fcdffd21393144d45e0a685ca72 Mon Sep 17 00:00:00 2001 From: Berlin Brown Date: Sat, 19 Apr 2008 21:47:44 -0400 Subject: [PATCH] Initial Import --- glants_mech/linux/CHANGES | 11 + glants_mech/linux/Makefile | 18 + glants_mech/linux/README | 42 + glants_mech/linux/config.ini | 176 + glants_mech/linux/data/title1.ilf | Bin 0 -> 196664 bytes glants_mech/linux/glants | Bin 0 -> 178588 bytes glants_mech/linux/misc/1.raw | 1 + glants_mech/linux/misc/tech.raw | 1 + glants_mech/linux/src/Makefile | 115 + glants_mech/linux/src/ant.c | 316 ++ glants_mech/linux/src/backup.ini | 176 + glants_mech/linux/src/bitmap.c | 979 ++++++ glants_mech/linux/src/bot.c | 829 +++++ glants_mech/linux/src/bot.h | 305 ++ glants_mech/linux/src/camera.c | 819 +++++ glants_mech/linux/src/camera.h | 99 + glants_mech/linux/src/collision.c | 953 ++++++ glants_mech/linux/src/collision.h | 121 + glants_mech/linux/src/commands.c | 74 + glants_mech/linux/src/config.ini | 176 + glants_mech/linux/src/cube.c | 342 ++ glants_mech/linux/src/data/title1.ilf | Bin 0 -> 196664 bytes glants_mech/linux/src/defaults.h | 42 + glants_mech/linux/src/error.log | 2 + glants_mech/linux/src/fireants.c | 3536 ++++++++++++++++++++ glants_mech/linux/src/fireants.h | 79 + glants_mech/linux/src/garden.c | 587 ++++ glants_mech/linux/src/glant.c | 957 ++++++ glants_mech/linux/src/gldrawlib.c | 212 ++ glants_mech/linux/src/gldrawlib.h | 78 + glants_mech/linux/src/globals.c | 2333 +++++++++++++ glants_mech/linux/src/globals.h | 284 ++ glants_mech/linux/src/grid.c | 199 ++ glants_mech/linux/src/keys.c | 532 +++ glants_mech/linux/src/keys.h | 27 + glants_mech/linux/src/lights.c | 204 ++ glants_mech/linux/src/lights.h | 37 + glants_mech/linux/src/list.c | 187 ++ glants_mech/linux/src/list.h | 21 + glants_mech/linux/src/los.c | 246 ++ glants_mech/linux/src/maps.c | 185 + glants_mech/linux/src/maps.h | 38 + glants_mech/linux/src/menu.h | 32 + glants_mech/linux/src/network/CHANGES | 8 + glants_mech/linux/src/network/clients.c | 498 +++ glants_mech/linux/src/network/connect.c | 138 + glants_mech/linux/src/network/include/clients.h | 54 + glants_mech/linux/src/network/include/connect.h | 60 + glants_mech/linux/src/network/include/msg.h | 100 + glants_mech/linux/src/network/include/server.h | 11 + glants_mech/linux/src/network/msg.c | 420 +++ glants_mech/linux/src/network/network.c | 643 ++++ glants_mech/linux/src/network/network.h | 93 + glants_mech/linux/src/network/server.c | 324 ++ glants_mech/linux/src/network/stats.c | 144 + glants_mech/linux/src/norm_cube.c | 382 +++ glants_mech/linux/src/objects.c | 564 ++++ glants_mech/linux/src/objects.h | 73 + glants_mech/linux/src/octree.c | 331 ++ glants_mech/linux/src/octree.h | 41 + glants_mech/linux/src/particles.c | 282 ++ glants_mech/linux/src/particles.h | 58 + glants_mech/linux/src/pheromone.c | 372 ++ glants_mech/linux/src/play.c | 222 ++ glants_mech/linux/src/plist.c | 280 ++ glants_mech/linux/src/plist.h | 37 + glants_mech/linux/src/pyramid.c | 584 ++++ glants_mech/linux/src/resource.h | 16 + glants_mech/linux/src/sound.c | 516 +++ glants_mech/linux/src/sound.h | 52 + glants_mech/linux/src/stars.c | 142 + glants_mech/linux/src/static.c | 253 ++ glants_mech/linux/src/text.c | 1944 +++++++++++ glants_mech/linux/src/text.h | 71 + glants_mech/linux/src/tree.c | 381 +++ glants_mech/linux/src/tree.h | 28 + glants_mech/linux/src/tree_test.x | 506 +++ glants_mech/linux/src/walls.h | 20 + glants_mech/linux/src/wirebox.c | 138 + glants_mech/linux/src/world.c | 284 ++ glants_mech/linux/src/world.h | 38 + glants_mech/remove_cvs.sh | 4 + glants_mech/remove_svn.sh | 4 + glants_mech/win32/glAntsV05/ant.cpp | 313 ++ glants_mech/win32/glAntsV05/backup.ini | 176 + glants_mech/win32/glAntsV05/bitmap.cpp | 800 +++++ glants_mech/win32/glAntsV05/bot.cpp | 829 +++++ glants_mech/win32/glAntsV05/bot.h | 287 ++ glants_mech/win32/glAntsV05/camera.cpp | 843 +++++ glants_mech/win32/glAntsV05/camera.h | 96 + glants_mech/win32/glAntsV05/collision.cpp | 949 ++++++ glants_mech/win32/glAntsV05/collision.h | 119 + glants_mech/win32/glAntsV05/commands.cpp | 75 + glants_mech/win32/glAntsV05/config.ini | 176 + glants_mech/win32/glAntsV05/cube.cpp | 343 ++ glants_mech/win32/glAntsV05/defaults.h | 40 + glants_mech/win32/glAntsV05/error.log | 2 + glants_mech/win32/glAntsV05/fireants.cpp | 2995 +++++++++++++++++ glants_mech/win32/glAntsV05/fireants.h | 58 + glants_mech/win32/glAntsV05/garden.cpp | 587 ++++ glants_mech/win32/glAntsV05/glAnt.aps | Bin 0 -> 33716 bytes glants_mech/win32/glAntsV05/glAnt.dsp | 314 ++ glants_mech/win32/glAntsV05/glAnt.rc | 72 + glants_mech/win32/glAntsV05/glant.cpp | 1042 ++++++ glants_mech/win32/glAntsV05/glant.dsw | 29 + glants_mech/win32/glAntsV05/glant.ncb | Bin 0 -> 828416 bytes glants_mech/win32/glAntsV05/glant.opt | Bin 0 -> 48640 bytes glants_mech/win32/glAntsV05/glant.plg | 62 + glants_mech/win32/glAntsV05/gldrawlib.cpp | 212 ++ glants_mech/win32/glAntsV05/gldrawlib.h | 77 + glants_mech/win32/glAntsV05/globals.cpp | 1941 +++++++++++ glants_mech/win32/glAntsV05/globals.h | 231 ++ glants_mech/win32/glAntsV05/grid.cpp | 200 ++ glants_mech/win32/glAntsV05/lights.cpp | 206 ++ glants_mech/win32/glAntsV05/lights.h | 36 + glants_mech/win32/glAntsV05/list.cpp | 187 ++ glants_mech/win32/glAntsV05/list.h | 20 + glants_mech/win32/glAntsV05/los.cpp | 246 ++ glants_mech/win32/glAntsV05/maps.cpp | 179 + glants_mech/win32/glAntsV05/maps.h | 37 + glants_mech/win32/glAntsV05/menu.h | 21 + glants_mech/win32/glAntsV05/norm_cube.cpp | 382 +++ glants_mech/win32/glAntsV05/objects.cpp | 564 ++++ glants_mech/win32/glAntsV05/objects.h | 73 + glants_mech/win32/glAntsV05/octree.cpp | 329 ++ glants_mech/win32/glAntsV05/octree.h | 41 + glants_mech/win32/glAntsV05/particles.cpp | 282 ++ glants_mech/win32/glAntsV05/particles.h | 57 + glants_mech/win32/glAntsV05/pheromone.cpp | 372 ++ glants_mech/win32/glAntsV05/plist.cpp | 280 ++ glants_mech/win32/glAntsV05/plist.h | 35 + glants_mech/win32/glAntsV05/pyramid.cpp | 584 ++++ glants_mech/win32/glAntsV05/readme.txt | 52 + glants_mech/win32/glAntsV05/resource.h | 16 + glants_mech/win32/glAntsV05/small_img.ico | Bin 0 -> 2238 bytes glants_mech/win32/glAntsV05/stars.cpp | 143 + glants_mech/win32/glAntsV05/static.cpp | 253 ++ glants_mech/win32/glAntsV05/static.pp | 0 glants_mech/win32/glAntsV05/t.txt | 15 + glants_mech/win32/glAntsV05/text.cpp | 1944 +++++++++++ glants_mech/win32/glAntsV05/text.h | 71 + glants_mech/win32/glAntsV05/tree.cpp | 380 +++ glants_mech/win32/glAntsV05/tree.h | 27 + glants_mech/win32/glAntsV05/tree_test.x | 506 +++ glants_mech/win32/glAntsV05/walls.h | 20 + glants_mech/win32/glAntsV05/wirebox.cpp | 138 + glants_mech/win32/glAntsV05/world.cpp | 298 ++ glants_mech/win32/glAntsV05/world.h | 37 + glants_mech/win32/release/backup.ini | 176 + glants_mech/win32/release/config.ini | 176 + glants_mech/win32/release/data/titles1.bmp | Bin 0 -> 196664 bytes glants_mech/win32/release/error.log | 2 + glants_mech/win32/release/glAnt.exe | Bin 0 -> 434234 bytes glants_mech/win32/release/readme.txt | 52 + octanemech/media/images/prev_version_game1.jpg | Bin 0 -> 27842 bytes octanemech/src/BasicMechs.hs | 56 + octanemech/src/ColorDefs.hs | 27 + octanemech/src/HUnit/Example.hs | 37 + octanemech/src/HUnit/Guide.html | 715 ++++ octanemech/src/HUnit/HUnit.lhs | 13 + octanemech/src/HUnit/HUnitBase.lhs | 230 ++ octanemech/src/HUnit/HUnitLang.lhs | 71 + octanemech/src/HUnit/HUnitLang98.lhs | 71 + octanemech/src/HUnit/HUnitLangExc.lhs | 69 + octanemech/src/HUnit/HUnitTest98.lhs | 11 + octanemech/src/HUnit/HUnitTestBase.lhs | 375 +++ octanemech/src/HUnit/HUnitTestExc.lhs | 39 + octanemech/src/HUnit/HUnitText.lhs | 127 + octanemech/src/HUnit/License | 29 + octanemech/src/HUnit/README | 12 + octanemech/src/HUnit/Terminal.lhs | 31 + octanemech/src/HUnit/TerminalTest.lhs | 21 + octanemech/src/Makefile | 50 + octanemech/src/MatrixUtils.hs | 22 + octanemech/src/MechDisplay.hs | 50 + octanemech/src/MechGLScreen.hs | 71 + octanemech/src/MechGenericObjects.hs | 59 + octanemech/src/MechKeys.hs | 53 + octanemech/src/MechTerrain.hs | 53 + octanemech/src/MechTests.hs | 22 + octanemech/src/OctaneMech.hs | 24 + octanemech/src/Tests/GLTests.hs | 76 + octanemech/src/Tests/GLTestsExample.hs | 30 + octanemech/src/example/BasicMechs.hs | 56 + octanemech/src/example/ColorDefs.hs | 27 + octanemech/src/example/Makefile | 41 + octanemech/src/example/MatrixUtils.hs | 22 + octanemech/src/example/MechDisplay.hs | 50 + octanemech/src/example/MechGLScreen.hs | 71 + octanemech/src/example/MechGenericObjects.hs | 59 + octanemech/src/example/MechKeys.hs | 53 + octanemech/src/example/MechTerrain.hs | 53 + octanemech/src/example/OctaneMech.hs | 21 + octanemech/src/example/README.txt | 60 + octanemech/src/misc/Test1.hs | 173 + octanemech/src/misc/Test2.hs | 24 + octanemech/src/misc/camera/DisplayLoop.hs | 205 ++ octanemech/src/misc/camera/Makefile | 32 + octanemech/src/misc/camera/MechCamera.hs | 110 + octanemech/src/misc/camera/MechGenericObjects.hs | 81 + octanemech/src/misc/camera/README.txt | 19 + octanemech/src/misc/camera/csrc/Makefile | 42 + octanemech/src/misc/camera/csrc/MechCamera.c | 167 + octanemech/src/misc/camera/media/camera_demo.png | Bin 0 -> 9589 bytes octanemech/src/misc/camera/package.sh | 15 + octanemech/src/misc/server/ProxyServer.hs | 110 + octanemech/src/misc/server/SimpleClient.hs | 62 + octanemech/src/misc/textmenu/DisplayLoop.hs | 205 ++ octanemech/src/misc/textmenu/Makefile | 33 + octanemech/src/misc/textmenu/MechGenericObjects.hs | 81 + octanemech/src/misc/textmenu/MechTextDemo.hs | 109 + octanemech/src/misc/textmenu/README.txt | 20 + octanemech/src/misc/textmenu/ScreenSettings.hs | 22 + octanemech/src/misc/textmenu/Text/ByteFontData.hs | 1564 +++++++++ octanemech/src/misc/textmenu/Text/TextUtil.hs | 75 + octanemech/src/misc/textmenu/csrc/Makefile | 50 + octanemech/src/misc/textmenu/csrc/MechTextDemo.c | 602 ++++ octanemech/src/misc/textmenu/csrc/TextData.c | 1555 +++++++++ octanemech/src/misc/textmenu/package.sh | 15 + 219 files changed, 54920 insertions(+) create mode 100644 glants_mech/linux/CHANGES create mode 100644 glants_mech/linux/Makefile create mode 100644 glants_mech/linux/README create mode 100644 glants_mech/linux/config.ini create mode 100644 glants_mech/linux/data/title1.ilf create mode 100644 glants_mech/linux/glants create mode 100644 glants_mech/linux/misc/1.raw create mode 100644 glants_mech/linux/misc/tech.raw create mode 100644 glants_mech/linux/src/Makefile create mode 100644 glants_mech/linux/src/ant.c create mode 100644 glants_mech/linux/src/backup.ini create mode 100644 glants_mech/linux/src/bitmap.c create mode 100644 glants_mech/linux/src/bot.c create mode 100644 glants_mech/linux/src/bot.h create mode 100644 glants_mech/linux/src/camera.c create mode 100644 glants_mech/linux/src/camera.h create mode 100644 glants_mech/linux/src/collision.c create mode 100644 glants_mech/linux/src/collision.h create mode 100644 glants_mech/linux/src/commands.c create mode 100644 glants_mech/linux/src/config.ini create mode 100644 glants_mech/linux/src/cube.c create mode 100644 glants_mech/linux/src/data/title1.ilf create mode 100644 glants_mech/linux/src/defaults.h create mode 100644 glants_mech/linux/src/error.log create mode 100644 glants_mech/linux/src/fireants.c create mode 100644 glants_mech/linux/src/fireants.h create mode 100644 glants_mech/linux/src/garden.c create mode 100644 glants_mech/linux/src/glant.c create mode 100644 glants_mech/linux/src/gldrawlib.c create mode 100644 glants_mech/linux/src/gldrawlib.h create mode 100644 glants_mech/linux/src/globals.c create mode 100644 glants_mech/linux/src/globals.h create mode 100644 glants_mech/linux/src/grid.c create mode 100644 glants_mech/linux/src/keys.c create mode 100644 glants_mech/linux/src/keys.h create mode 100644 glants_mech/linux/src/lights.c create mode 100644 glants_mech/linux/src/lights.h create mode 100644 glants_mech/linux/src/list.c create mode 100644 glants_mech/linux/src/list.h create mode 100644 glants_mech/linux/src/los.c create mode 100644 glants_mech/linux/src/maps.c create mode 100644 glants_mech/linux/src/maps.h create mode 100644 glants_mech/linux/src/menu.h create mode 100644 glants_mech/linux/src/network/CHANGES create mode 100644 glants_mech/linux/src/network/clients.c create mode 100644 glants_mech/linux/src/network/connect.c create mode 100644 glants_mech/linux/src/network/include/clients.h create mode 100644 glants_mech/linux/src/network/include/connect.h create mode 100644 glants_mech/linux/src/network/include/msg.h create mode 100644 glants_mech/linux/src/network/include/server.h create mode 100644 glants_mech/linux/src/network/msg.c create mode 100644 glants_mech/linux/src/network/network.c create mode 100644 glants_mech/linux/src/network/network.h create mode 100644 glants_mech/linux/src/network/server.c create mode 100644 glants_mech/linux/src/network/stats.c create mode 100644 glants_mech/linux/src/norm_cube.c create mode 100644 glants_mech/linux/src/objects.c create mode 100644 glants_mech/linux/src/objects.h create mode 100644 glants_mech/linux/src/octree.c create mode 100644 glants_mech/linux/src/octree.h create mode 100644 glants_mech/linux/src/particles.c create mode 100644 glants_mech/linux/src/particles.h create mode 100644 glants_mech/linux/src/pheromone.c create mode 100644 glants_mech/linux/src/play.c create mode 100644 glants_mech/linux/src/plist.c create mode 100644 glants_mech/linux/src/plist.h create mode 100644 glants_mech/linux/src/pyramid.c create mode 100644 glants_mech/linux/src/resource.h create mode 100644 glants_mech/linux/src/sound.c create mode 100644 glants_mech/linux/src/sound.h create mode 100644 glants_mech/linux/src/stars.c create mode 100644 glants_mech/linux/src/static.c create mode 100644 glants_mech/linux/src/text.c create mode 100644 glants_mech/linux/src/text.h create mode 100644 glants_mech/linux/src/tree.c create mode 100644 glants_mech/linux/src/tree.h create mode 100644 glants_mech/linux/src/tree_test.x create mode 100644 glants_mech/linux/src/walls.h create mode 100644 glants_mech/linux/src/wirebox.c create mode 100644 glants_mech/linux/src/world.c create mode 100644 glants_mech/linux/src/world.h create mode 100644 glants_mech/remove_cvs.sh create mode 100644 glants_mech/remove_svn.sh create mode 100644 glants_mech/win32/glAntsV05/ant.cpp create mode 100644 glants_mech/win32/glAntsV05/backup.ini create mode 100644 glants_mech/win32/glAntsV05/bitmap.cpp create mode 100644 glants_mech/win32/glAntsV05/bot.cpp create mode 100644 glants_mech/win32/glAntsV05/bot.h create mode 100644 glants_mech/win32/glAntsV05/camera.cpp create mode 100644 glants_mech/win32/glAntsV05/camera.h create mode 100644 glants_mech/win32/glAntsV05/collision.cpp create mode 100644 glants_mech/win32/glAntsV05/collision.h create mode 100644 glants_mech/win32/glAntsV05/commands.cpp create mode 100644 glants_mech/win32/glAntsV05/config.ini create mode 100644 glants_mech/win32/glAntsV05/cube.cpp create mode 100644 glants_mech/win32/glAntsV05/defaults.h create mode 100644 glants_mech/win32/glAntsV05/error.log create mode 100644 glants_mech/win32/glAntsV05/fireants.cpp create mode 100644 glants_mech/win32/glAntsV05/fireants.h create mode 100644 glants_mech/win32/glAntsV05/garden.cpp create mode 100644 glants_mech/win32/glAntsV05/glAnt.aps create mode 100644 glants_mech/win32/glAntsV05/glAnt.dsp create mode 100644 glants_mech/win32/glAntsV05/glAnt.rc create mode 100644 glants_mech/win32/glAntsV05/glant.cpp create mode 100644 glants_mech/win32/glAntsV05/glant.dsw create mode 100644 glants_mech/win32/glAntsV05/glant.ncb create mode 100644 glants_mech/win32/glAntsV05/glant.opt create mode 100644 glants_mech/win32/glAntsV05/glant.plg create mode 100644 glants_mech/win32/glAntsV05/gldrawlib.cpp create mode 100644 glants_mech/win32/glAntsV05/gldrawlib.h create mode 100644 glants_mech/win32/glAntsV05/globals.cpp create mode 100644 glants_mech/win32/glAntsV05/globals.h create mode 100644 glants_mech/win32/glAntsV05/grid.cpp create mode 100644 glants_mech/win32/glAntsV05/lights.cpp create mode 100644 glants_mech/win32/glAntsV05/lights.h create mode 100644 glants_mech/win32/glAntsV05/list.cpp create mode 100644 glants_mech/win32/glAntsV05/list.h create mode 100644 glants_mech/win32/glAntsV05/los.cpp create mode 100644 glants_mech/win32/glAntsV05/maps.cpp create mode 100644 glants_mech/win32/glAntsV05/maps.h create mode 100644 glants_mech/win32/glAntsV05/menu.h create mode 100644 glants_mech/win32/glAntsV05/norm_cube.cpp create mode 100644 glants_mech/win32/glAntsV05/objects.cpp create mode 100644 glants_mech/win32/glAntsV05/objects.h create mode 100644 glants_mech/win32/glAntsV05/octree.cpp create mode 100644 glants_mech/win32/glAntsV05/octree.h create mode 100644 glants_mech/win32/glAntsV05/particles.cpp create mode 100644 glants_mech/win32/glAntsV05/particles.h create mode 100644 glants_mech/win32/glAntsV05/pheromone.cpp create mode 100644 glants_mech/win32/glAntsV05/plist.cpp create mode 100644 glants_mech/win32/glAntsV05/plist.h create mode 100644 glants_mech/win32/glAntsV05/pyramid.cpp create mode 100644 glants_mech/win32/glAntsV05/readme.txt create mode 100644 glants_mech/win32/glAntsV05/resource.h create mode 100644 glants_mech/win32/glAntsV05/small_img.ico create mode 100644 glants_mech/win32/glAntsV05/stars.cpp create mode 100644 glants_mech/win32/glAntsV05/static.cpp create mode 100644 glants_mech/win32/glAntsV05/static.pp create mode 100644 glants_mech/win32/glAntsV05/t.txt create mode 100644 glants_mech/win32/glAntsV05/text.cpp create mode 100644 glants_mech/win32/glAntsV05/text.h create mode 100644 glants_mech/win32/glAntsV05/tree.cpp create mode 100644 glants_mech/win32/glAntsV05/tree.h create mode 100644 glants_mech/win32/glAntsV05/tree_test.x create mode 100644 glants_mech/win32/glAntsV05/walls.h create mode 100644 glants_mech/win32/glAntsV05/wirebox.cpp create mode 100644 glants_mech/win32/glAntsV05/world.cpp create mode 100644 glants_mech/win32/glAntsV05/world.h create mode 100644 glants_mech/win32/release/backup.ini create mode 100644 glants_mech/win32/release/config.ini create mode 100644 glants_mech/win32/release/data/titles1.bmp create mode 100644 glants_mech/win32/release/error.log create mode 100644 glants_mech/win32/release/glAnt.exe create mode 100644 glants_mech/win32/release/readme.txt create mode 100644 octanemech/media/images/prev_version_game1.jpg create mode 100644 octanemech/src/BasicMechs.hs create mode 100644 octanemech/src/ColorDefs.hs create mode 100644 octanemech/src/HUnit/Example.hs create mode 100644 octanemech/src/HUnit/Guide.html create mode 100644 octanemech/src/HUnit/HUnit.lhs create mode 100644 octanemech/src/HUnit/HUnitBase.lhs create mode 100644 octanemech/src/HUnit/HUnitLang.lhs create mode 100644 octanemech/src/HUnit/HUnitLang98.lhs create mode 100644 octanemech/src/HUnit/HUnitLangExc.lhs create mode 100644 octanemech/src/HUnit/HUnitTest98.lhs create mode 100644 octanemech/src/HUnit/HUnitTestBase.lhs create mode 100644 octanemech/src/HUnit/HUnitTestExc.lhs create mode 100644 octanemech/src/HUnit/HUnitText.lhs create mode 100644 octanemech/src/HUnit/License create mode 100644 octanemech/src/HUnit/README create mode 100644 octanemech/src/HUnit/Terminal.lhs create mode 100644 octanemech/src/HUnit/TerminalTest.lhs create mode 100644 octanemech/src/Makefile create mode 100644 octanemech/src/MatrixUtils.hs create mode 100644 octanemech/src/MechDisplay.hs create mode 100644 octanemech/src/MechGLScreen.hs create mode 100644 octanemech/src/MechGenericObjects.hs create mode 100644 octanemech/src/MechKeys.hs create mode 100644 octanemech/src/MechTerrain.hs create mode 100644 octanemech/src/MechTests.hs create mode 100644 octanemech/src/OctaneMech.hs create mode 100644 octanemech/src/Tests/GLTests.hs create mode 100644 octanemech/src/Tests/GLTestsExample.hs create mode 100644 octanemech/src/example/BasicMechs.hs create mode 100644 octanemech/src/example/ColorDefs.hs create mode 100644 octanemech/src/example/Makefile create mode 100644 octanemech/src/example/MatrixUtils.hs create mode 100644 octanemech/src/example/MechDisplay.hs create mode 100644 octanemech/src/example/MechGLScreen.hs create mode 100644 octanemech/src/example/MechGenericObjects.hs create mode 100644 octanemech/src/example/MechKeys.hs create mode 100644 octanemech/src/example/MechTerrain.hs create mode 100644 octanemech/src/example/OctaneMech.hs create mode 100644 octanemech/src/example/README.txt create mode 100644 octanemech/src/misc/Test1.hs create mode 100644 octanemech/src/misc/Test2.hs create mode 100644 octanemech/src/misc/camera/DisplayLoop.hs create mode 100644 octanemech/src/misc/camera/Makefile create mode 100644 octanemech/src/misc/camera/MechCamera.hs create mode 100644 octanemech/src/misc/camera/MechGenericObjects.hs create mode 100644 octanemech/src/misc/camera/README.txt create mode 100644 octanemech/src/misc/camera/csrc/Makefile create mode 100644 octanemech/src/misc/camera/csrc/MechCamera.c create mode 100644 octanemech/src/misc/camera/media/camera_demo.png create mode 100644 octanemech/src/misc/camera/package.sh create mode 100644 octanemech/src/misc/server/ProxyServer.hs create mode 100644 octanemech/src/misc/server/SimpleClient.hs create mode 100644 octanemech/src/misc/textmenu/DisplayLoop.hs create mode 100644 octanemech/src/misc/textmenu/Makefile create mode 100644 octanemech/src/misc/textmenu/MechGenericObjects.hs create mode 100644 octanemech/src/misc/textmenu/MechTextDemo.hs create mode 100644 octanemech/src/misc/textmenu/README.txt create mode 100644 octanemech/src/misc/textmenu/ScreenSettings.hs create mode 100644 octanemech/src/misc/textmenu/Text/ByteFontData.hs create mode 100644 octanemech/src/misc/textmenu/Text/TextUtil.hs create mode 100644 octanemech/src/misc/textmenu/csrc/Makefile create mode 100644 octanemech/src/misc/textmenu/csrc/MechTextDemo.c create mode 100644 octanemech/src/misc/textmenu/csrc/TextData.c create mode 100644 octanemech/src/misc/textmenu/package.sh diff --git a/glants_mech/linux/CHANGES b/glants_mech/linux/CHANGES new file mode 100644 index 0000000..7cb3621 --- /dev/null +++ b/glants_mech/linux/CHANGES @@ -0,0 +1,11 @@ +** CHANGES ** +** Berlin Brown ** +bigbinc@hotmail.com + +10/22/2002: + still working on the network code + the client and server are working + I only need to fix the messages + and matching up who is the client + and who is server. + It is at 85% \ No newline at end of file diff --git a/glants_mech/linux/Makefile b/glants_mech/linux/Makefile new file mode 100644 index 0000000..46c7e03 --- /dev/null +++ b/glants_mech/linux/Makefile @@ -0,0 +1,18 @@ +# +## +# Main Makefile for glants +# +# - Berlin Brown +# bigbinc@hotmail.com +# +DIR = src/ +PRG = glants + +all: + (cd $(DIR); make) + (cp -f src/$(PRG) ./) + +clean: + rm -f *~ + rm -f $(PRG) + (cd $(DIR); make clean) diff --git a/glants_mech/linux/README b/glants_mech/linux/README new file mode 100644 index 0000000..9ec244a --- /dev/null +++ b/glants_mech/linux/README @@ -0,0 +1,42 @@ +** GLANTS FOR LINUX ** +v0.6 + +Berlin Brown +bigbinc@hotmail.com + +10/27/2002 + - Added simple networking and sound support. + In order to get network working, you pretty much have to follow + these steps exactly. + Oh yeah, the server doesnt display the client movements(not done yet) + 1. on client side: start glants + 2. on server side: start glants + 3. on server side: select settings->start server->wait for connects + 4. on client side: connect to server + 5. on server side: press esc->select new game, server is in motion + 6. play game, that is it + +10/2/2002 + +visit http://glants.sourceforge.net for more information + +** Instructions ** +There is a pre-compiled version of glants in this directory. +It probably will not work, but you can try it with + + ./glants + +Or the best way is to do a clean and then make with + make clean + make + +and run ./glants again. + +Of course you have to make sure that OPENGL/MESA is installed +as well as GLX and of course update xwindows. I installed +the nvidia drivers for opengl and the program ran ok on +my 400mhz machine. I think the linux version runs a little better +than the windows version. + +You can edit the config.ini file to change the speed of the game +or how many characters you fight against. diff --git a/glants_mech/linux/config.ini b/glants_mech/linux/config.ini new file mode 100644 index 0000000..72309cb --- /dev/null +++ b/glants_mech/linux/config.ini @@ -0,0 +1,176 @@ +# +# glAnts - original config.ini +# file, change at your own risk +# +# if you remove this file, the program +# will create another one with the defaults +# so removing this file can be a good thing +# +# +# Also of note, if the system finds an error +# it goes with the default variable +# +# FORMAT has to be [VARIABLE_NAME]=VALUE; +# oh yeah, add the 'f' tag for float +# +# [VARIABLE_NAME]=VALUEf; +# +# COMMENTS are '#' +# +# Remove the comments below are your own risk +# they basically just define the default values +# used, if you remove them then you wont know +# what good values will look like +# +# The only things that really need changing +# are: +# +# USE_ANT_ENGINE: take out the little ants +# +# MAX_FIRE_ANTS: max fighter ants +# +# MAX_BOTS: number of worker ants +# +# INITIAL_ANT_FOOD: the health of the fighter +# ants and the workers +# try 10,000 and they will never die +# +# Also, you may comment one of the variables +# and get the default once the program runs +# + +[GLANTS CONFIG] +# los default is 14.0 +[LINE_OF_SIGHT]=125.0f; + +# Used with the ai, it attacks at any point given +# this radius +# default is 4.0 +[ATTACK_RADIUS]=4.0f; + +# The amount of damage a bullet will inflict +# the damage is reduced considerably +# at a greater distance and its impact +# is great at short distances +# try 5000, hehe +# default = 280 +[BULLET_DAMAGE]=420.0f; + +# defaut is 4.90 +[MIN_BULLET_SPEED]=7.20f; + +# You can get rid of the worker ant +# engine and just shoot stuff +[USE_ANT_ENGINE]=0; + +# the number of attack ants +# default is 4, but that is on a +# slow machine, try 50 for a 1ghz machine +[MAX_FIRE_ANTS]=14; + +# number of worker ants, default=120 +[MAX_BOTS]=1; + +# 0 = place food in random spot +# 1 = place food in centralized spots +[USE_GARDEN_AREA]=1; + +# the max number of pheromones +# an ant can leave +# default: 300 +[MAX_TRAIL_STACK]=300; + +# used with AI, if the ant life reaches +# this point, the ai goes berzerk +# and he will move a little faster +# default: 390 +[DYING_STATE]=390; + +# the number of pheromones +# the ants can leave on the grid +# default: 200, make sure not more than +# max_trail_stack +[MAX_PHEROMONES]=200; + +# default: 1000 +[PHEROMONE_LIFE]=1000; + +# the time before an ant drops a pheromone +# default: 40 +[PHEROMONE_DROP]=40; + +# the number of bullets +# the ai has before recycle +# this doesnt effect that much +# default: 20 +[MAX_BULLETS]=20; + +# this is reduce rapid-fire effect +# slows down the rate for firing speed +# default: 10 +[MAX_FIRE_SPEED]=10; + +# the amount of food that is on the grid +# default: 35 +[MAX_GARDENS]=35; + +# the bot's speed, need I say more +# the fire_ants travel at a little +# slower speed +# default: 0.09 +[BOT_SPEED]=2.29f; + +# when the bots accelerate +# this the top speed +# default: 0.14 +[BOT_MAX_SPEED]=3.04f; + +# default: 1.1 +[MIN_TURN_SPEED]=1.5f; + +# default: 600 +[CHECK_RESPAWN]=600; + +# the max amount of food +# that can respawn at +# any given point in time +# default: 15 +[GARD_RESPAWN_RATE]=15; + +# default: 60 +[MIN_STRAIGHT_STEPS]=60; + +# default: 200 +[MAX_STRAIGHT_STEPS]=200; + +# default: 150 +[MIN_STRAIGHT_STEPS_2]=150; + +# default: 360 +[MAX_STRAIGHT_STEPS_2]=360; + +# +# this is the amount of food +# the ants get as well as the fire_ants +# default: 1000 +[INITIAL_ANT_FOOD]=1000; + +# the amount of food inside +# a block of food in the garden +# default: 7000 +[INITIAL_GARD_FOOD]=7000; + +# default: 0.3 +[FOOD_WIDTH]=0.3f; + +# default: 480 +[INIT_FOOD_RATE]=480; + +# default: 850 +[MAX_FOOD_RATE]=850; + +# default: 1.7 +[MOVE_FOOD_RATE]=1.7f; + +# default: 0.4 +[FOOD_RATE]=0.4f; diff --git a/glants_mech/linux/data/title1.ilf b/glants_mech/linux/data/title1.ilf new file mode 100644 index 0000000000000000000000000000000000000000..7992c768aaddaadf34e7aadbe89f638a18ad91e1 GIT binary patch literal 196664 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 ddB?L$2qA1H9JwX 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

Uao7JYqo1%@zfc) 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 +#include +#include +#include +#include + +#include +#include +#include + + +#include "gldrawlib.h" +#include "objects.h" +#include "lights.h" + +#undef CURRENT_OBJECT +#define CURRENT_OBJECT ant + +static void init_ant(int list_id); +static void compile_ant(void); +static void draw_ant(void); +static void render_ant(void); +static void draw_ant(void); + + +GLfloat xmat_ambient[] = { 0.0f, 0.9f, 0.0f, 1.0f }; +GLfloat xmat_diffuse[] = { 0.9f, 0.8f, 0.8f, 1.0f }; +GLfloat xmat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; +GLfloat xno_shininess[] = { 0.0f }; +GLfloat xlow_shininess[] = { 5.0f }; +GLfloat xhigh_shininess[] = { 100.0f}; +GLfloat xmat_emission[] = {0.3f, 0.2f, 0.2f, 0.0f}; + +// +// simple objects library +// - make sure to change the number of objects +// in objects.h +// +DriverObjects CURRENT_OBJECT = +{ + init_ant, // init, must be called first + compile_ant, // compile + draw_ant, // draw + render_ant, // render to scene + 0 // loaded by INIT +}; + + +//========================================================= +//========================================================= +static void draw_ant(void) +{ + float v[3][3]; + float size = 1.0f; + float height = 0.6f; + + float n[3]; // remember to free + +#if ENABLE_LIGHTS + // set the material for this object + setmaterial(xmat_ambient, xmat_diffuse, + xmat_specular, xlow_shininess, xmat_emission); + + +#endif + + + // change the size here + // Note: starts from ground + + glBegin(GL_TRIANGLES); + + + // Get the top + v[0][0] = -size; + v[0][1] = height; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = height; + v[1][2] = size; + + v[2][0] = 0.0; + v[2][1] = height; + v[2][2] = -size; + + N_0; + glNormal3fv(n); + + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + + // left bottom front + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = size; + + v[2][0] = size; + v[2][1] = height; + v[2][2] = size; + + MED_BLUE; + // Calc normal and draw + N_1; + glNormal3fv(n); + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = -size; + v[1][1] = height; + v[1][2] = size; + + v[2][0] = size; + v[2][1] = height; + v[2][2] = size; + + MED_BLUE; + // Calc normal and draw + N_0; + glNormal3fv(n); + + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + + + + // BOTTOM + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = size; + + v[2][0] = 0.0f; + v[2][1] = 0.0f; + v[2][2] = -size; + + MED_YELLOW; + // Calc normal and draw] + N_0; + glNormal3fv(n); + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + + // right side + v[0][0] = size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = 0.0f; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = 0.0f; + v[2][1] = height; + v[2][2] = -size; + + MED_CYAN; + // Calc normal and draw + N_1; + glNormal3fv(n); + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + // still right side + v[0][0] = size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = height; + v[1][2] = size; + + v[2][0] = 0.0f; + v[2][1] = height; + v[2][2] = -size; + + MED_CYAN; + // Calc normal and draw + N_0; + glNormal3fv(n); + + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + + // right side + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = 0.0f; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = 0.0f; + v[2][1] = height; + v[2][2] = -size; + + MED_PURPLE; + N_2; + glNormal3fv(n); + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + // still right side + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = -size; + v[1][1] = height; + v[1][2] = size; + + v[2][0] = 0.0f; + v[2][1] = height; + v[2][2] = -size; + + MED_PURPLE; + N_1; + glNormal3fv(n); + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + + + glEnd(); + +} // end of the function + + +// +// init +// - load anything special about the +// one important function +// +static void init_ant(int list_id) +{ + + CURRENT_OBJECT.visible = 1; + + // store the id through the function + // there is probably a better way to do this + CURRENT_OBJECT.call_id = list_id; + +} // end of the functino + + +//========================================================= +// Now the function to actually draw it +//========================================================= +static void render_ant(void) +{ + //glPushMatrix(); + + glCallList(CURRENT_OBJECT.call_id); + + //glPopMatrix(); + +} // end of the function + +//========================================================= +// compile +//========================================================= +static void compile_ant(void) +{ + int id; + // setup a spot for display list for background + //object = getcurrentobject(); + id = CURRENT_OBJECT.call_id; + + // apply list + glNewList(id, GL_COMPILE); + + // call drawing function + // but this may method make it a little better + CURRENT_OBJECT.draw(); + + glEndList(); + +} // end of the function + diff --git a/glants_mech/linux/src/backup.ini b/glants_mech/linux/src/backup.ini new file mode 100644 index 0000000..86acbc6 --- /dev/null +++ b/glants_mech/linux/src/backup.ini @@ -0,0 +1,176 @@ +# +# glAnts - original config.ini +# file, change at your own risk +# +# if you remove this file, the program +# will create another one with the defaults +# so removing this file can be a good thing +# +# +# Also of note, if the system finds an error +# it goes with the default variable +# +# FORMAT has to be [VARIABLE_NAME]=VALUE; +# oh yeah, add the 'f' tag for float +# +# [VARIABLE_NAME]=VALUEf; +# +# COMMENTS are '#' +# +# Remove the comments below are your own risk +# they basically just define the default values +# used, if you remove them then you wont know +# what good values will look like +# +# The only things that really need changing +# are: +# +# USE_ANT_ENGINE: take out the little ants +# +# MAX_FIRE_ANTS: max fighter ants +# +# MAX_BOTS: number of worker ants +# +# INITIAL_ANT_FOOD: the health of the fighter +# ants and the workers +# try 10,000 and they will never die +# +# Also, you may comment one of the variables +# and get the default once the program runs +# + +[GLANTS CONFIG] +# los default is 14.0 +[LINE_OF_SIGHT]=14.0f; + +# Used with the ai, it attacks at any point given +# this radius +# default is 4.0 +[ATTACK_RADIUS]=4.0f; + +# The amount of damage a bullet will inflict +# the damage is reduced considerably +# at a greater distance and its impact +# is great at short distances +# try 5000, hehe +# default = 280 +[BULLET_DAMAGE]=280.0f; + +# defaut is 0.30 +[MIN_BULLET_SPEED]=0.30f; + +# You can get rid of the worker ant +# engine and just shoot stuff +[USE_ANT_ENGINE]=0; + +# the number of attack ants +# default is 4, but that is on a +# slow machine, try 50 for a 1ghz machine +[MAX_FIRE_ANTS]=4; + +# number of worker ants, default=120 +[MAX_BOTS]=120; + +# 0 = place food in random spot +# 1 = place food in centralized spots +[USE_GARDEN_AREA]=1; + +# the max number of pheromones +# an ant can leave +# default: 300 +[MAX_TRAIL_STACK]=300; + +# used with AI, if the ant life reaches +# this point, the ai goes berzerk +# and he will move a little faster +# default: 390 +[DYING_STATE]=390; + +# the number of pheromones +# the ants can leave on the grid +# default: 200, make sure not more than +# max_trail_stack +[MAX_PHEROMONES]=200; + +# default: 1000 +[PHEROMONE_LIFE]=1000; + +# the time before an ant drops a pheromone +# default: 40 +[PHEROMONE_DROP]=40; + +# the number of bullets +# the ai has before recycle +# this doesnt effect that much +# default: 20 +[MAX_BULLETS]=20; + +# this is reduce rapid-fire effect +# slows down the rate for firing speed +# default: 10 +[MAX_FIRE_SPEED]=10; + +# the amount of food that is on the grid +# default: 35 +[MAX_GARDENS]=35; + +# the bot's speed, need I say more +# the fire_ants travel at a little +# slower speed +# default: 0.09 +[BOT_SPEED]=0.09f; + +# when the bots accelerate +# this the top speed +# default: 0.14 +[BOT_MAX_SPEED]=0.14f; + +# default: 1.1 +[MIN_TURN_SPEED]=1.1f; + +# default: 600 +[CHECK_RESPAWN]=600; + +# the max amount of food +# that can respawn at +# any given point in time +# default: 15 +[GARD_RESPAWN_RATE]=15; + +# default: 60 +[MIN_STRAIGHT_STEPS]=60; + +# default: 200 +[MAX_STRAIGHT_STEPS]=200; + +# default: 150 +[MIN_STRAIGHT_STEPS_2]=150; + +# default: 360 +[MAX_STRAIGHT_STEPS_2]=360; + +# +# this is the amount of food +# the ants get as well as the fire_ants +# default: 1000 +[INITIAL_ANT_FOOD]=1000; + +# the amount of food inside +# a block of food in the garden +# default: 7000 +[INITIAL_GARD_FOOD]=7000; + +# default: 0.3 +[FOOD_WIDTH]=0.3f; + +# default: 480 +[INIT_FOOD_RATE]=480; + +# default: 850 +[MAX_FOOD_RATE]=850; + +# default: 1.7 +[MOVE_FOOD_RATE]=1.7f; + +# default: 0.4 +[FOOD_RATE]=0.4f; diff --git a/glants_mech/linux/src/bitmap.c b/glants_mech/linux/src/bitmap.c new file mode 100644 index 0000000..88134dc --- /dev/null +++ b/glants_mech/linux/src/bitmap.c @@ -0,0 +1,979 @@ +//========================================================= +// Berlin Brown +// - Sept 18, 2002 +// +// +// bitmap.cpp +// +// for some odd reason I placed some of the menu functions +// here as well +// +// This source loads images in opengl +// one functino will be from glaux, I will +// include my own loader when I find the time +// Note: for reasons you can see you probably +// dont want to change an image in realtime +// - you should be able to copy/paste +// these to other workspaces +//========================================================= +//--------------------------------------------------------- +// INCLUDES +//--------------------------------------------------------- + +#include +#include // math libraries +#include +#include // used for randomizing +#include // used for _control + +#include // OpenGl includes +#include + + +#include "globals.h" +#include "gldrawlib.h" +#include "objects.h" +#include "bot.h" +#include "menu.h" +#include "camera.h" +#include "fireants.h" +#include "network/include/connect.h" + +static float mTextHeight = 36.0f; + + +// Note: the terrain should be about 1/2 what the +// perspective z view angle is +// terrain = 10000 then perspective z = 2000 +#define TERRAINVIEW 24.0f // distance from database + + +static float m_size_z = 0.01f; + + +//--------------------------------------------------------- +// Main globals +//========================================================= +static unsigned int texture[MAX_TEXTURES]; +static int textureindex=0; // counter of what textures are available + +static int funky_texture=0; + +static unsigned int titlesID = 5; + + +// +// cursor_heights +// +#define MAX_MENU_ITEMS 5 +#define NEW_GAME_H 140 +#define EXIT_H 171 +#define HELP_H 205 +#define SETTINGS_H 239 +#define DEMO_H 273 + +static int cursor_heights[MAX_MENU_ITEMS] = + { NEW_GAME_H , + EXIT_H, + HELP_H, + SETTINGS_H, + DEMO_H }; +static int cursor_index = NEW_GAME_ID; + + +// +// Texture Image +// +typedef struct { + + int width; + int height; + unsigned char *data; + +} textureImage; + + + +// +// Reset_DeadText +// +void Reset_DeadText(void) +{ + m_size_z = 0.01f; +} // end of the function + +// +// SetFunkyTexture +// - must be placed right after loadTexture +// but I didnt want to put it in the actual function +// +void SetFunkyTexture(void) +{ + + LoadTexture("data/tile.bmp"); + + funky_texture = textureindex - 1; + +} // end of the function + +// +// GetFunkyTexture +// +int GetFunkyTexture(void) +{ + return funky_texture; +} // end of the function + +// +// NewTexure +// +void NextTexture(void) +{ + + textureindex++; // up the index + if (textureindex > MAX_TEXTURES) + textureindex = MAX_TEXTURES; + +} // end of the function + +//========================================================= +// loadbmp +// - load a bitmap using aux library +// removed AUX bitmap stuff +//========================================================= +void *LoadBitmap(char *filename) +{ +#if 0 + FILE *f=fopen(filename,"r"); // open the image file for reading + + + // check for the file + if (f) + { + fclose(f); // Close the handel + return auxDIBImageLoad(filename); // load using the glaux lib + } // end of the if + +#endif + + return NULL; +} // end of the function + + +// +// GetTexture +// +unsigned int GetTexture(int index) +{ + return texture[index]; + +} // end of the function + + +// +// +// LoadBitmap for linux +// +int LoadBitmap_Lin(char *filename, textureImage *texture) +{ + FILE *file; + + unsigned short int bfType; + long int bfOffBits; + short int biPlanes; + short int biBitCount; + long int biSizeImage; + int i; + unsigned char temp; + + + /* make sure the file is there and open it read-only (binary) */ + if ((file = fopen(filename, "rb")) == NULL) + { + printf("File not found : %s\n", filename); + return 0; + } + if(!fread(&bfType, sizeof(short int), 1, file)) + { + printf("Error reading file!\n"); + return 0; + } + /* check if file is a bitmap */ + if (bfType != 19778) + { + printf("Not a Bitmap-File!\n"); + return 0; + } + /* get the file size */ + /* skip file size and reserved fields of bitmap file header */ + fseek(file, 8, SEEK_CUR); + /* get the position of the actual bitmap data */ + if (!fread(&bfOffBits, sizeof(long int), 1, file)) + { + printf("Error reading file!\n"); + return 0; + } + //printf("Data at Offset: %ld\n", bfOffBits); + + /* skip size of bitmap info header */ + fseek(file, 4, SEEK_CUR); + /* get the width of the bitmap */ + fread(&texture->width, sizeof(int), 1, file); + //printf("Width of Bitmap: %d\n", texture->width); + + + /* get the height of the bitmap */ + fread(&texture->height, sizeof(int), 1, file); + //printf("Height of Bitmap: %d\n", texture->height); + + + /* get the number of planes (must be set to 1) */ + fread(&biPlanes, sizeof(short int), 1, file); + if (biPlanes != 1) + { + printf("Error: number of Planes not 1!\n"); + return 0; + } + /* get the number of bits per pixel */ + if (!fread(&biBitCount, sizeof(short int), 1, file)) + { + printf("Error reading file!\n"); + return 0; + } + + + //printf("Bits per Pixel: %d\n", biBitCount); + if (biBitCount != 24) + { + printf("Bits per Pixel not 24\n"); + return 0; + } + /* calculate the size of the image in bytes */ + biSizeImage = texture->width * texture->height * 3; + //printf("Size of the image data: %ld\n", biSizeImage); + texture->data = malloc(biSizeImage); + /* seek to the actual data */ + fseek(file, bfOffBits, SEEK_SET); + if (!fread(texture->data, biSizeImage, 1, file)) + { + printf("Error loading file!\n"); + return 0; + } + /* swap red and blue (bgr -> rgb) */ + for (i = 0; i < biSizeImage; i += 3) + { + temp = texture->data[i]; + texture->data[i] = texture->data[i + 2]; + texture->data[i + 2] = temp; + } + return 1; + +} // end of teh function + + + + + +//========================================================= +// loadtexture +// - load a texture based on glaux load bitmap +//--------------------------------------------------------- +void LoadTexture(char *filename) +{ + + textureImage *texture_image; + texture_image = malloc(sizeof(textureImage)); + + // load the bitmap, from the file + if (LoadBitmap_Lin(filename, texture_image)) + { + // Bind the texture + glBindTexture(GL_TEXTURE_2D, GetTexture(0)); + glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_image->width, + texture_image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image->data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + } // end of the if + + + // free the memory we just allocated, it is probably going in vram + if (texture_image) + { + if (texture_image->data) + free(texture_image->data); + + free(texture_image); + } // end of the if + + + + NextTexture(); + +} // end of the function + + + + +// +// LoadTitleBitmap +// +void Load_Titles(void) +{ + + textureImage *texture_image; + texture_image = malloc(sizeof(textureImage)); + + // load the bitmap, from the file + if (LoadBitmap_Lin("data/title1.ilf", texture_image)) + { + //glGenTextures(1, &titlesID); + titlesID = 8; + glBindTexture(GL_TEXTURE_2D, titlesID); + + // GL_LUMINANCE_ALPHA + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + texture_image->width, + texture_image->height, 0, + GL_RGB, GL_UNSIGNED_BYTE, + texture_image->data); + + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, + GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + } // end of the if + + + // free the memory we just allocated, it is probably going in vram + if (texture_image) + { + if (texture_image->data) + free(texture_image->data); + + free(texture_image); + } // end of the if + + +} // end of the function + +// +// Title_Begin +// +static void Title_Begin(void) +{ + // Push the neccessary Matrices on the stack + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0.0, SCREEN_WIDTH, SCREEN_HEIGHT, + 0.0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + + glPushMatrix(); + glLoadIdentity(); + + // Push the neccessary Attributes on the stack + glPushAttrib(GL_TEXTURE_BIT | GL_ENABLE_BIT); + + glBindTexture(GL_TEXTURE_2D, titlesID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // Always Draw in Front + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + + glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +} // end of the function + +// +// TitleEnd +// +static void Title_End(void) +{ + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + +} // end of the function + +// +// Render_Name +// - the title of the game +// +void Render_BText(int val, float x, float y, float Yoffset) +{ + float t_offset; + float t_height; + float tex_y_1, tex_y_2; + + t_offset = 256.0f - 244.0f; + t_offset = t_offset / 256.0f; + + // get f height + t_height = mTextHeight / 256.0f; + + tex_y_2 = (1.0f - t_offset) - + (((float)val * t_height)+0.0f)+Yoffset; + tex_y_1 = (1.0f - t_offset) - + (((float)val * t_height)+t_height)+Yoffset; + + glBegin(GL_QUADS); + + glTexCoord2f(0,-tex_y_1); // Texture Coord (Bottom Left) + glVertex3i(x+0,y, 0); // Vertex Coord (Bottom Left) + + glTexCoord2f(1,-tex_y_1); // Texture Coord (Bottom Right) + glVertex3i(x+256,y, 0); // Vertex Coord (Bottom Right) + + glTexCoord2f(1,-tex_y_2); // Texture Coord (Top Right) + glVertex3i(x+256,y+mTextHeight, 0); // Vertex Coord (Top Right) + + glTexCoord2f(0,-tex_y_2); // Texture Coord (Top Left) + glVertex3i(x+0,y+mTextHeight, 0); // Vertex Coord (Top Left) + + glEnd(); + +} // end of the function + + +//** +// Render _ Trick +// - the title of the game !!!! +//** +void Render_BTrick(int val, float perc, float x, float y, float Yoffset) +{ + float t_offset; + float t_height; + float tex_y_1, tex_y_2; + + float t_size = 0.0f; + + t_offset = 256.0f - 244.0f; + t_offset = t_offset / 256.0f; + + // get f height + t_height = mTextHeight / 256.0f; + + tex_y_2 = (1.0f - t_offset) - + (((float)val * t_height)+0.0f)+Yoffset; + tex_y_1 = (1.0f - t_offset) - + (((float)val * t_height)+t_height)+Yoffset; + + t_size = 256.0f * 1.0f; + + + glBegin(GL_QUADS); + + glTexCoord2f(0,-tex_y_1); // Texture Coord (Bottom Left) + glVertex3i(x+0,y, 0); // Vertex Coord (Bottom Left) + + glTexCoord2f(perc,-tex_y_1); // Texture Coord (Bottom Right) + glVertex3i(x+t_size,y, 0); // Vertex Coord (Bottom Right) + + glTexCoord2f(perc,-tex_y_2); // Texture Coord (Top Right) + glVertex3i(x+t_size,y+mTextHeight, 0); // Vertex Coord (Top Right) + + glTexCoord2f(0,-tex_y_2); // Texture Coord (Top Left) + glVertex3i(x+0,y+mTextHeight, 0); // Vertex Coord (Top Left) + + glEnd(); + + + glDisable(GL_TEXTURE_2D); + glColor3ub(255, 255, 255); + glBegin(GL_LINE_LOOP); + + glVertex3i(x, y, 0); + glVertex3i(x, y+mTextHeight, 0); + + glEnd(); + + + glBegin(GL_LINE_LOOP); + + glVertex3i(x+t_size, y, 0); + glVertex3i(x+t_size, y+mTextHeight, 0); + + glEnd(); + + // Bottom + glBegin(GL_LINE_LOOP); + + glVertex3i(x, y+mTextHeight, 0); + glVertex3i(x+t_size, y+mTextHeight, 0); + + glEnd(); + + // Top + glBegin(GL_LINE_LOOP); + + glVertex3i(x, y, 0); + glVertex3i(x+t_size, y, 0); + + glEnd(); + +} // end of the function + + + + + + + + +// +// Draw_Shadow +// +void Draw_Shadow(void) +{ + int dx = 2; + int box_top = (SCREEN_HEIGHT / 2) + 100; + int box_bottom = (SCREEN_HEIGHT / 2) + 200; + + glDisable(GL_TEXTURE_2D); + + // Draw the shadow box + glColor4ub(205, 205, 205, 200); + glBegin(GL_QUADS); + glVertex3i(172+dx,100+dx, 0); // Vertex Coord (Bottom Left) + glVertex3i(468-dx,100+dx, 0); // Vertex Coord (Bottom Right) + glVertex3i(468-dx,310-dx, 0); // Vertex Coord (Top Right) + glVertex3i(172+dx,310-dx, 0); // Vertex Coord (Top Left) + glEnd(); + + + glEnable(GL_TEXTURE_2D); + +} // end of the function + +// +// Draw_Cursor +// +void Draw_Cursor(int y) +{ + + int left_far; + int left_mid; + int left_inside; + int height_1; + int height_2; + int height_3; + + // now the other side + int right_far; + int right_mid; + int right_inside; + + // right side + right_far = 600; + right_mid = 500; + right_inside = 360; + + // left + left_far = 30; + left_mid = 140; + left_inside = 200; + + height_1 = y; + height_2 = y - 8; + height_3 = y + 8; + + glDisable(GL_TEXTURE_2D); + + glColor4ub(255, 255, 255, 205); + glBegin(GL_LINE_LOOP); + + glVertex3i(left_far, height_1, 0); + glVertex3i(left_mid, height_1, 0); + + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(left_mid, height_2, 0); + glVertex3i(left_mid, height_3, 0); + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(left_mid, height_2, 0); + glVertex3i(left_inside, height_2, 0); + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(left_mid, height_3, 0); + glVertex3i(left_inside, height_3, 0); + glEnd(); + + + // + // handle right side + glBegin(GL_LINE_LOOP); + + glVertex3i(right_far, height_1, 0); + glVertex3i(right_mid, height_1, 0); + + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(right_mid, height_2, 0); + glVertex3i(right_mid, height_3, 0); + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(right_mid, height_2, 0); + glVertex3i(right_inside, height_2, 0); + glEnd(); + + glBegin(GL_LINE_LOOP); + glVertex3i(right_mid, height_3, 0); + glVertex3i(right_inside, height_3, 0); + glEnd(); + + + + // For pure effect + // draw lines connect to the end of the screen + glBegin(GL_LINE_LOOP); + glVertex3i(right_far, 0, 0); + glVertex3i(right_far, height_1, 0); + glEnd(); + + + glBegin(GL_LINE_LOOP); + glVertex3i(left_far, SCREEN_HEIGHT, 0); + glVertex3i(left_far, height_1, 0); + glEnd(); + + + // + // draw a bounding box + // + glBegin(GL_LINE_LOOP); + glVertex3i(192, 120, 0); + glVertex3i(448, 120, 0); + + glVertex3i(448, 120, 0); + glVertex3i(448, 294, 0); + + glVertex3i(192, 294, 0); + glVertex3i(192, 294, 0); + glEnd(); + + glEnable(GL_TEXTURE_2D); + +} // end of the function + + + +// +// Draw_GameOver +// +void Draw_GameOver(void) +{ + float offset= 34.0f; + float begin = 120.0f; + float t; + + // based on the frame rate + if (framerate <= 8.0f) + framerate = 30.0f; + + t = 0.007f / framerate; + t = framerate * t; + + + m_size_z += t; + if (m_size_z >= 1.0f) + m_size_z = 1.0f; + + + Title_Begin(); + + glColor3ub(255, 255, 0); + Render_BTrick(2, m_size_z, 192.0f, 220.0f, 0.034f); + + Title_End(); + +} // end of the function + +// +// Draw_Title +// +void Draw_Title(void) +{ + float offset = 34.0f; + float begin = 120.0f; + + + // Also draw game over + // if it is turned on + if (ant_globals->_menu_state == MENU_DEAD_MODE) { + + Draw_GameOver(); + } // end of the if + + + switch(ant_globals->menu_mode) + { + + case MENU_HELP_MODE: + + glLineWidth(2.0f); + + Title_Begin(); + + Draw_HelpScreen(); + + + glDisable(GL_LIGHTING); + + Draw_IntroScreen(); + + glEnable(GL_LIGHTING); + + + Title_End(); + glLineWidth(1.0f); + + break; + + + + case MENU_SETTINGS_MODE: + + glLineWidth(2.0f); + + + Title_Begin(); + Draw_NetworkScreen(); + Title_End(); + + + glLineWidth(1.0f); + + break; + + + + + case MENU_TITLE_MODE: + glLineWidth(2.0f); + + Title_Begin(); + + Draw_Shadow(); + + glColor4ub(255,255,255,255); + + // title, newgame, exit, demo + if (cursor_index == 0) + glColor4ub(255,255,0,255); + Render_BText(6, 192.0f, begin+(0*offset), 0.03f); + + glColor4ub(255,255,255,255); + if (cursor_index == 1) + glColor4ub(255,255,0,255); + Render_BText(5, 192.0f, begin+(1*offset), 0.016f); + + glColor4ub(255,255,255,255); + if (cursor_index == 2) + glColor4ub(255,255,0,255); + Render_BText(4, 192.0f, begin+(2*offset), -0.015f); + + glColor4ub(255,255,255,255); + if (cursor_index == 3) + glColor4ub(255,255,0,255); + Render_BText(3, 192.0f, begin+(3*offset), -0.041f); + + glColor4ub(255,255,255,255); + if (cursor_index == 4) + glColor4ub(255,255,0,255); + Render_BText(1, 192.0f, begin+(4*offset), 0.01f); + + // draw the selection tool -- + Draw_Cursor(cursor_heights[cursor_index]); + + //Draw_HelpScreen(); + Draw_IntroScreen(); + + Title_End(); + + glLineWidth(1.0f); + + break; + + default: break; + }; + +} // end of the function + +// +// Toggle_MenuItems +// +void Toggle_MenuItems(int dir) +{ + + if (ant_globals->menu_mode == MENU_TITLE_MODE) + { + + if (dir == 1) + { + cursor_index++; + if (cursor_index >= MAX_MENU_ITEMS) + cursor_index = 0; + } else if (dir == -1) { + + cursor_index--; + if (cursor_index < 0) + cursor_index = MAX_MENU_ITEMS-1; + + } // end of if-else + + } // end of main if + +} // end of the functoin + +// +// Set_MenuMode +// +bool Set_MenuMode(void) +{ + + if (ant_globals->menu_mode == MENU_TITLE_MODE) + { + switch(cursor_index) + { + case NEW_GAME_ID: + + if (CHECK_NET_SERVER) + { + if (ant_globals->_menu_state == FIRST_TIME_TRUE) + cursor_index = NEW_GAME_ID; + else + cursor_index = HELP_ID; + + // redundant code + cursor_index = HELP_ID; + + Build_StartMsg(); + + ant_globals->paused = 0; + ant_globals->menu_mode = MENU_RUN_MODE; + + // NOTE NOTE NOTE NOTE! + // reset the bots here + // this may take a while + Reset_NetworkBots(); + + + + return false; + + } else { + + if (ant_globals->_menu_state == FIRST_TIME_TRUE) + cursor_index = NEW_GAME_ID; + else + cursor_index = HELP_ID; + + // redundant code + cursor_index = HELP_ID; + + ant_globals->paused = 0; + + ant_globals->menu_mode = MENU_RUN_MODE; + + // Not the first time any more + ant_globals->_menu_state = FIRST_TIME_FALSE; + + // NOTE NOTE NOTE NOTE! + // reset the bots here + // this may take a while + Reset_FireAnts(); + + return false; + + } // end of if-else + + break; + + case SETTINGS_ID: + + if (ant_globals->_menu_state == FIRST_TIME_TRUE) + cursor_index = NEW_GAME_ID; + else + cursor_index = HELP_ID; + + ant_globals->paused = 1; + ant_globals->menu_mode = MENU_SETTINGS_MODE; + + break; + + case HELP_ID: + + if (ant_globals->_menu_state == FIRST_TIME_TRUE) + cursor_index = NEW_GAME_ID; + else + cursor_index = HELP_ID; + + ant_globals->paused = 1; + ant_globals->menu_mode = MENU_HELP_MODE; + break; + + case DEMO_ID: + + if (ant_globals->_menu_state == FIRST_TIME_TRUE) + cursor_index = NEW_GAME_ID; + else + cursor_index = HELP_ID; + + // redundant code + cursor_index = HELP_ID; + + ant_globals->paused = 0; + + ant_globals->menu_mode = MENU_RUN_MODE; + + // Not the first time any more + ant_globals->_menu_state = FIRST_TIME_FALSE; + + // NOTE NOTE NOTE NOTE! + // reset the bots here + // this may take a while + Prepare_DemoMode(); + + return false; + + break; + + case EXIT_ID: + + return true; // we are done here + break; + + default: break; + }; + + } // end of the if -- + + return false; + +} // end of the function diff --git a/glants_mech/linux/src/bot.c b/glants_mech/linux/src/bot.c new file mode 100644 index 0000000..5239ed3 --- /dev/null +++ b/glants_mech/linux/src/bot.c @@ -0,0 +1,829 @@ +// +// bot.cpp +// +// - This really should be called +// objects but it was taken up already +// +// basically bots have attributes and +// use objects for drawing +// +// - This is the meat and potatoes of the +// artificial control +// + +#include +#include + +#include +#include + +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library + + +#include "camera.h" +#include "bot.h" +#include "objects.h" +#include "gldrawlib.h" +#include "world.h" +#include "globals.h" +#include "octree.h" +#include "plist.h" +#include "collision.h" + +void ProcessBotEvent(DriverBotPtr bot); + +static DriverBotPtr *bot_cluster; + +// created with the bots +PtrList *trail_stack; + + +// +// Super_LoadBots +// - if this is not loaded +// we have major problems +// +void Super_LoadBots(void) +{ + bot_cluster = (DriverBotPtr *)malloc(MAX_BOTS * + sizeof(DriverBotPtr)); +} // end of the function + +// +// Super_KillBots( +// +void Super_KillBots(void) +{ + RELEASE_OBJECT(bot_cluster); + +} // end of the function + +// +// Create So many ants +// - you can use a constant or +// some form of percentage based on the total +// ants that are on the grid +// if you use a food constant, the ants will +// die off quicker, if you use a percentage +// then the ants will respawn at random points +// default is 5%, constant is 10,000 +// +void CreateAnts(int food) +{ + int i = 0; + float tmp=0; + int food_tol = 0; + float perct=0; + +#if USE_FOOD_RESPAWN + food_tol = FOOD_RESPAWN +#else + perct = 0.05f * (float)GetAnts(); + + if (perct > 1) { + food_tol = (int)perct * INITIAL_ANT_FOOD; + } else { + return; // cant create any ants at the time + + } // end of if-else + +#endif + + if (food >= food_tol) + { + + // generate more ants + // depending how many ants have died + for (i = 0; i < MAX_BOTS; i++) + { + // look for dead slot + if (bot_cluster[i]->alive == DEAD_STATE) + { + + //DestroyBot(bot_cluster[i]); + //bot_cluster[i] = CreateBot(i); + ResetBot(bot_cluster[i]); + + GetAntFood(bot_cluster[i]); + + AddAnts(1); + + // dont want to over do it + tmp += INITIAL_ANT_FOOD; + if (tmp >= food_tol) + break; + + } // end of the if + + } // end of the for + + } // end of the if + +} // end of the functino + + +// +// Find Angle +// - FindAngle between two points with -z = -y, x=x +// (depending on the bots direction) +// +float FindAngle(float dir, float x1, float y1, float x2, float y2) +{ + + float dx; + float dy; + float dist; + float angle; + + + if (x1 < x2) { + + dx = x2 - x1; + dy = (-y2) - (-y1); // reverse direction of y + + dist = (float)sqrt((dx * dx)+(dy*dy)); + angle = (float)asin(dy / dist); + + angle = RAD_TO_DEG * angle; + + if (angle < 0) + angle += 360.0f; + + // convert to GL cartesian plane, 0 = 90 + // subtract 90 degrees + angle -= 90.0f; + if (angle < 0) + angle += 360.0f; + + return angle; + + } else { + + dx = x2 - x1; + dy = y2 - y1; // reverse direction of y + + dist = (float)sqrt((dx * dx)+(dy*dy)); + angle = (float)asin(dy / dist); + + angle = RAD_TO_DEG * angle; + + if (angle < 0) + angle += 360.0f; + + // convert to GL cartesian plane, 0 = 90 + // subtract 90 degrees + angle -= 90.0f; + if (angle < 0) + angle += 360.0f; + + // step 3: add 180 because bot has to move toward nest + angle += 180.0f; + + if (angle >= 360) + angle -= 360; + + return angle; + + } // end if + + return 0; +} // end of the function + +// +// Method to draw food on the ant +// - semi-simple +// +void RenderFood(DriverBotPtr bot) +{ + + if (bot->foodstore > 0) + { + + BEGIN_BOT; + + // place over the ant -- + glTranslatef(bot->x, 0.15f, bot->y); + + glScalef(0.1f, 0.1f, 0.1f); + + driver_objects[NORM_CUBE_OBJECT]->render(); + + END_BOT; + + } // end of the if + +} // end of the function + +// +// GetAntFood +// - intially +// +void GetAntFood(DriverBotPtr bot) +{ + + float food; + float tmp; + + // make sure nest's food is loaded + bot->food = 0; + + food = INITIAL_ANT_FOOD; + + tmp = nest.objects[0]->food - food; + if (tmp <= 0) + { + // find how much food nest can give + food = nest.objects[0]->food; + + if (food <= 0) + { + nest.objects[0]->food; + bot->food = 0; + + return; + } // end of if + + } // end of the if + + bot->food += food; + + // detract from nests pile + nest.objects[0]->food -= food; + +} // end of the function + + +// +// Once the ant can carry food he should be able +// to eat it on his way back to the nest +// +void EatFood(DriverBotPtr bot, float food_rate) +{ + float food_amt; + + if (bot->foodstore > 0) + { + food_amt = food_rate; + + if ((bot->foodstore - food_amt) < 0) + { + // try to found how much food is left + food_amt = bot->foodstore; + + bot->foodstore = 0; // thats all + + // add the foodstore to the edible food + bot->food += food_amt; + + return; + + } // end of the if + + // add the food store to edible food + bot->foodstore -= food_amt; + bot->food += food_amt; + + } // end of the if + else + bot->foodstore = 0; + +} // end of the function + +// +// Metabolize +// - burn food +// +void Metabolize(DriverBotPtr bot, float food_rate) +{ + // no point subtracting when dead + if (bot->alive == DEAD_STATE) + return; + + bot->food -= food_rate; + + // you are dead + if (bot->food <= 0) { + bot->alive = DEAD_STATE; + + SubtractAnts(1); + } // end of the if + +} // end of the function + +// +// I really like the idea of a simple state machine for +// the ants, a central processing, queue thing +// a little better device than using a bunch of ifs +// - see state.h +// + +// +// ChangeDirection +// - should only be called every once in a while +// +void ChangeDirection(DriverBotPtr bot) +{ + if (bot->go_home == true) { + bot->turn_rand = 3; + + bot->straightSteps = (rand()%__go_home_steps_2) + + MIN_STRAIGHT_STEPS_2; + } + else { + + bot->turn_rand = 30; + + // remove if you dont like calling rand + bot->straightSteps = (rand()%__straight_steps) + + MIN_STRAIGHT_STEPS; + } // end of the if + + + bot->target_dir = bot->heading; + + // pick a random direction + bot->target_dir += rand()%bot->turn_rand; // 30 degrees ok? + + if (bot->target_dir >= 360) + bot->target_dir -= 360; + + bot->state = TURN_STATE; + +} // end of the function + +// +// Turn +// +void TurnBot(DriverBotPtr bot) +{ + + float tol; + float tmp; + float target_tmp; + + // hmm, turning speed // + tol = bot->turning_speed+(2.0f*bot->turning_speed); + + bot->heading += bot->turning_speed; + + if (bot->heading >= 360) + bot->heading -= 360; + + tmp = ABS(bot->heading); + target_tmp = ABS(bot->target_dir); + + // reached target direction + if ( (tmp > (target_tmp - tol)) && (tmp < (target_tmp + tol)) ) + { + // change state + bot->state = MOVE_STATE; + + return; + } // end of the if + + bot->state = TURN_STATE; + + return; + + +} // end of the function + + + +// +// MoveBot +// +void MoveBot(DriverBotPtr bot) +{ + + int id=0; + float *last_heading = NULL; + float tmp_heading = 0.0f; + + CollisionPtr col_ptr; + + + // if we have our max food move on + if (bot->foodstore <= MAX_FOOD_RATE) + { + + id = BruteCheckFood(bot); + + // check if we have found food + if (id > 0) + { + + DropFood(bot, (id-1), INIT_FOOD_RATE); + + // return home with the food + bot->go_home = true; + bot->target_dir = + FindAngle(bot->heading, bot->x, bot->y, 0.0f, 0.0f); + + bot->state = TURN_STATE; + + return; + } // end of the if + + } // end of the if + + // check if we are ok to deposit food + if (bot->foodstore > 0) + { + // check if in the nest area + if ((bot->x > -GET_NEST_HWID) && + (bot->x < GET_NEST_HWID) && + (bot->y > -GET_NEST_HWID) && + (bot->y < GET_NEST_HWID)) + { + NEST_FOOD_OBJECT += bot->foodstore; + bot->foodstore = 0; + bot->go_home = false; + + // Since the bot found food + // add the direction so that other bots + // can use it + // + // Note: test code, may not use in final + // implementation + + // get the new heading first + last_heading = (float *)POP_STACK(trail_stack); + + if (trail_stack->items < MAX_TRAIL_STACK) + PUSH_STACK(trail_stack, (float *)&bot->heading); + + + // Once we have enough food + // create a new ant + CreateAnts(NEST_FOOD_OBJECT); + +#if HUD_NEST_FOOD + SetNestFood(NEST_FOOD_OBJECT); +#endif + + + } // end of the if + + } // end of the if + + bot->numSteps++; + + // when to change direction + if ((bot->numSteps % bot->straightSteps) == 0) + { + + bot->state = CHANGE_DIR_STATE; + + return; // process state else where + + } // end of the if + + // Also We need to drop pheromones on the way home + // Note: pretty slow algo + if (bot->go_home) + { + if ((bot->numSteps % PHEROMONE_DROP) == 0) + { + ActivatePheromone(bot->x, bot->y, bot->heading); + } // end of the if + + } // end of the if + + + // If we have a new heading change direction + if (last_heading) + { + tmp_heading = *last_heading; + + tmp_heading += 180.0f; + if (tmp_heading > 360.0f) + tmp_heading -= 360.0f; + + // change direction + bot->target_dir = tmp_heading; + bot->turn_rand = 15; + + bot->straightSteps = (rand()%__go_home_steps_2) + + MIN_STRAIGHT_STEPS_2; + + bot->state = TURN_STATE; + + return; + + } // end of the if + + + bot->x -= (float)sin(bot->heading*PI_180) * bot->linearv; + bot->y -= (float)cos(bot->heading*PI_180) * bot->linearv; + +#if 0 + // perform collision test using driver + col_ptr = CheckCollisionList((DriverBotPtr)bot, FREE_OBJECT); + + // we have a hit + if (col_ptr != NULL) + { + // check for wall first + if (col_ptr->move_type == STATIC_OBJECT) + { + // change state + bot->state = CHANGE_DIR_STATE; + + // reset back + bot->x += (float)sin(bot->heading*PI_180) * bot->linearv; + bot->y += (float)cos(bot->heading*PI_180) * bot->linearv; + + return; + } // end of the if + + } // end of the if +#endif + + bot->state = MOVE_STATE; + + return; + +} // end of the function + +// +// ProcessBotEvent +// - to keep everything in sync, +// process all bot actions in one fell swoop +// +void ProcessBotEvent(DriverBotPtr bot) +{ + // Eat food first then metabolize + EatFood(bot, MOVE_FOOD_RATE); + + // burn some food + Metabolize(bot, FOOD_RATE); + + // bot is dead cant do too much + if (bot->alive == DEAD_STATE) + return; + + switch(bot->state) + { + case MOVE_STATE: + MoveBot(bot); + break; + + case CHANGE_DIR_STATE: + ChangeDirection(bot); + break; + + case TURN_STATE: + TurnBot(bot); + break; + + default:break; + }; // end switch + + +} // end of the function + +// +// LoadBotParms +// - used by create and reset +// +void LoadBotParms(DriverBotPtr bot_ptr) +{ + // I like to be extra careful + ZeroMemory((DriverBotPtr)bot_ptr, + sizeof(DriverBots)); + + bot_ptr->heading = (float)(rand()%360); + bot_ptr->target_dir = bot_ptr->heading; + + bot_ptr->linearv=BOT_SPEED; + + bot_ptr->size[0]=0.2f; // scale + bot_ptr->size[1]=0.2f; + bot_ptr->size[2]=0.2f; + + bot_ptr->color[0]=0.8f; + bot_ptr->color[1]=((float)(rand()%1000)/2000.0f)+0.2f; + bot_ptr->color[2]=((float)(rand()%1000)/2000.0f)+0.2f; + + + bot_ptr->turning_speed = ((float)(rand()%1000)/2000.0f) + +MIN_TURN_SPEED; + + bot_ptr->numSteps = 0; + bot_ptr->straightSteps = (rand()%__straight_steps) + + MIN_STRAIGHT_STEPS; + + bot_ptr->state = MOVE_STATE; + bot_ptr->alive = ALIVE_STATE; + + // for simplicity, we assume nest is at the center + // start off the bots at that location + bot_ptr->x = ((rand()%1000)/200.0f)-2.5f; + bot_ptr->y = ((rand()%1000)/200.0f)-2.5f; + + // food bot is holding + bot_ptr->foodstore = 0; + + bot_ptr->turn_rand= 30; + + bot_ptr->go_home = false; + + bot_ptr->score = 0.0f; + + bot_ptr->kills = 0; + + // + // Crosshair object + // + // the crosshairs expand from 1.0f + // to some value when alive + // + bot_ptr->crosshair_state = DEAD_STATE; + bot_ptr->crosshair_scale = 1.0f; + +} // end of the function + +// +// CreateBot +// - allocate memory for bot +// +DriverBotPtr CreateBot(int bot_id) +{ + DriverBotPtr bot_ptr; + + bot_ptr = (DriverBotPtr)malloc(sizeof(DriverBots)); + + LoadBotParms(bot_ptr); + + bot_ptr->id=bot_id; + + return bot_ptr; + +} // end of the function + +// +// ResetBot +// +// +// ResetBot +// - allocate memory for bot +// +void ResetBot(DriverBotPtr bot_ptr) +{ + + float *last_heading = NULL; + float tmp_heading = 0; + + int bot_id = bot_ptr->id; + + // I like to be extra careful + ZeroMemory((DriverBotPtr)bot_ptr, + sizeof(DriverBots)); + + LoadBotParms(bot_ptr); + + bot_ptr->id=bot_id; + + + // automatically generate a new heading + last_heading = (float *)POP_STACK(trail_stack); + + // If we have a new heading change direction + if (last_heading) + { + tmp_heading = *last_heading; + + tmp_heading += 180.0f; + if (tmp_heading > 360.0f) + tmp_heading -= 360.0f; + + // change direction + bot_ptr->target_dir = tmp_heading; + bot_ptr->heading = tmp_heading; + bot_ptr->turn_rand = 15; + + bot_ptr->straightSteps = (rand()%__go_home_steps_2) + + MIN_STRAIGHT_STEPS_2; + + + } // end of the if + + +} // end of the function + + +// +// DestroyBot +// +void DestroyBot(DriverBotPtr b) +{ + RELEASE_OBJECT(b); + +} // end of the functino + +// +// RenderBot +// +void RenderBot(DriverBotPtr boid) +{ + + if (boid->alive == ALIVE_STATE) + { + + // If there is food, draw that also + RenderFood(boid); + + + BEGIN_BOT; + + // Translate then rotate + glTranslatef(boid->x,0,boid->y); + + // rotate based on the ship struct + glRotatef(boid->heading, 0.0f, 1.0f, 0.0f); + + // Scale accordingly + glScalef(boid->size[0], boid->size[1], boid->size[2]); + + // This may or may not change the color + glColor3f(boid->color[0], boid->color[1], boid->color[2]); + + // draw the object to screen + driver_objects[ANT_OBJECT]->render(); + + END_BOT; + + } // end of the if + +} // end of the function + +// +// GenerateBots +// +void GenerateBots(void) +{ + int index = 0; + + for (index = 0; index < MAX_BOTS; index++) + { + bot_cluster[index] = CreateBot(index); + + } // end of the for + + // create a stack for adding pheromone trails + trail_stack = CREATE_STACK; + +} // end of the function + + +// +// InitFood +// - called after the nest has been loaded +// +void InitFood(void) +{ + int index = 0; + + for (index = 0; index < MAX_BOTS; index++) + { + GetAntFood(bot_cluster[index]); + + } // end of the for + +} // end of the function + +// +// ShutdownBots +// +void ShutdownBots(void) +{ + int index = 0; + + for (index = 0; index < MAX_BOTS; index++) + { + DestroyBot(bot_cluster[index]); + } // end of the for + + // destroy the pheromone trail stack + DESTROY_STACK(trail_stack); + +} // end of the function + +// +// Draw Bots +// +void DrawBots(void) +{ + int index = 0; + + for (index = 0; index < MAX_BOTS; index++) + { + ProcessBotEvent(bot_cluster[index]); + + RenderBot(bot_cluster[index]); + + } // end of the for + +} // end of the function diff --git a/glants_mech/linux/src/bot.h b/glants_mech/linux/src/bot.h new file mode 100644 index 0000000..9b23339 --- /dev/null +++ b/glants_mech/linux/src/bot.h @@ -0,0 +1,305 @@ +// +// bot.h +// +#ifndef _BOT_H_ +#define _BOT_H_ + +// used for network +#define __VERSION__ 6 +#define __OS__ "LIN" + +typedef unsigned long DWORD; +typedef int bool; + +#define ZeroMemory(S, N) memset((S), 0, (N)) + +#define true 1 +#define false 0 + +// the number of commands in the +// command process +// +#define ATTACK_COMMAND 1 +#define WANDER_COMMAND 2 +#define MOVE_COMMAND 3 + +// +// use TAB to toggle between modes +// +#define THIRD_PERSON_MODE 1 +#define FIRST_PERSON_MODE 2 + +// +// crosshairs +// +#define CROSSHAIRS_SCALE 4.5f +#define CROSSHAIRS_GROWTH 1.3f + +#define LOOKAT_OFFSET 5.0f +#define CAMERA_BOT_OFFSET 8.0f +#define CAMERA_HEIGHT 3.2f + +#define RELEASE_OBJECT(x) \ + if (x != NULL) \ + free(x); \ + x = NULL \ + +// +// The multiplier for kills or +// just normal hits +// +#define SCORE_NORMAL 2.0f +#define SCORE_KILL 10.0f + + +// stars.cpp +// +#define MAX_RAND 4096 // 4096? +#define MAX_STARS 1200 // 2000 +#define STAR_RADIUS 710.0 +#define STAR_ROT_SPEED 0.1f; + + +#define __straight_steps (MAX_STRAIGHT_STEPS-MIN_STRAIGHT_STEPS) + +#define __go_home_steps_2 (MAX_STRAIGHT_STEPS_2-MIN_STRAIGHT_STEPS_2) + +// +// based on how much food is avaible +// respawn so many ants +#define USE_FOOD_RESPAWN 0 +#define ANT_RESPAWN 8 +#define FOOD_RESPAWN (ANT_RESPAWN * INITIAL_ANT_FOOD) + + +#define BEGIN_BOT glPushMatrix() +#define END_BOT glPopMatrix() + +#define TURN_RIGHT 1 +#define TURN_LEFT 2 + + +#define MOVE_STATE 0 +#define TURN_STATE 1 +#define CHANGE_DIR_STATE 2 +#define MOUNT_STATE 3 +#define SHOOT_STATE 4 +#define SET_TURN_STATE 6 +#define SET_MOUNT_STATE 7 +#define GENERATE_STATE 8 +#define GENERATE_TURN 9 +#define RECHECK_STATE 10 + +#define TEMP_STATE 99 +#define GO_MOVE_COMMAND 999 +#define GO_ATTACK_COMMAND 998 +#define GO_WANDER_COMMAND 997 +#define EXPLODE_STATE 995 + +#define ALIVE_STATE 1 +#define DEAD_STATE 0 +#define READY_STATE 2 + + +#define GET_NEST_WIDTH (1.5f*nest.objects[0]->size[0]) +#define GET_NEST_HWID (GET_NEST_WIDTH/2.0f) +#define NEST_FOOD_OBJECT nest.objects[0]->food + +#define INVALID_BOT -1 + +// static bot +// +typedef struct tagStaticBot { + + int list_id; + float position[3]; + float rotation[3]; + float size[3]; + float color[3]; + float state; + + float food; + + bool delete_flag; // deleted from pheromone list + + float heading; // you can use rotation or heading + float linearv; + + // + // for the collision + // + float travel; // distance traveled + float final_x; + float final_y; + float max_dist; + + + // + // + float old_x; + float old_y; // for drawing a line strip + + // used with bullets + float virt_x; + float virt_y; + float virt_heading; + int owner; // owner of this bullet + + struct tagStaticBot *next; + +} StaticBot, *StaticBotPtr; + +// functions for static bot +typedef struct tagDriverSentinel { + + StaticBotPtr (*create)(int bot_id); + void (*destroy)(StaticBotPtr b); + void (*render)(StaticBotPtr boid); + void (*process)(StaticBotPtr b); + + void (*generate)(void); + void (*shutdown)(void); + void (*drawall)(void); + + StaticBot **objects; + + int max_items; + +} DriverSentinel, *DriverSentinelPtr; + + +typedef struct tagDriverBots { + + float x; + float y; + float linearv; // speed + float size[3]; // scale + float heading; // direction + float target_dir; // target heading + float color[3]; + int id; + int alive; + int numSteps; // how many steps ant has moved + float turning_speed; + + int state; // what is bot doing + int straightSteps; // steps before changing direction + float food; + float foodstore; + int turn_rand; + int turn_direction; + + bool go_home; + + int gun_reset; // delay befor firing + int gun_index; + + bool move_back; // for move and turn + + + // camera helper variables + float look_x; + float look_y; + float look_h; // look height, actually the y + float cam_x; + float cam_y; + int view_mode; // first or third person + + float score; + int kills; + + // + // the rectangle of the bot + // Note: you have to add + // the x,y to this value, but dont + // do to this variable, use temps + float x_min; + float x_max; + float y_min; + float y_max; + + // + // crosshair object + // + int crosshair_state; + float crosshair_scale; + + // Add the fire ant bullets + //StaticBot bullets[MAX_BULLETS]; + StaticBot *bullets; + + // Command interface + void (*run)(struct tagDriverBots *bot); + + int last_command; + int command; + float attack_angle; + int target_moves; + int move_index; + int enemy_id; + +} DriverBots, *DriverBotPtr; + +void Super_LoadBots(void); +void Super_KillBots(void); + +void Super_FireAnts(void); +void Super_KillFires(void); + +// fireants.cpp +void Reset_FireAnts(void); +void Player_Control(bool *keys); + +void LoadBotParms(DriverBotPtr bot_ptr); + +void Wander_Command(DriverBotPtr bot); +void Move_Command(DriverBotPtr bot); +void Attack_Command(DriverBotPtr bot); + +int GetStartState(int cmd); +int GetLastState(int cmd); +void Generate_Command(DriverBotPtr bot, int cmd); + +void GenerateBots(void); +void ShutdownBots(void); + +void DrawBots(void); +void InitFood(void); + +int BruteCheckFood(DriverBotPtr bot); +void DropFood(DriverBotPtr bot, int id, float food_rate); + +void CreateAnts(int food); + +float FindAngle(float dir, float x1, float y1, float x2, float y2); + +void CheckRespawn(void); + +void ActivatePheromone(float x, float y, float dir); + +DriverBotPtr CreateBot(int bot_id); +void DestroyBot(DriverBotPtr b); +void GetAntFood(DriverBotPtr bot); +void ResetBot(DriverBotPtr bot_ptr); + +void GenerateFireAnts(void); +void ShutdownFireAnts(void); +void DrawFireAnts(void); +void AnimFireAnts(void); + +bool CheckSight(DriverBotPtr bot, DriverBotPtr nme); + +void MoveFire0(int dir, int turn); + +void PositionBot(DriverBotPtr bot); + +void AnimNetworkBots(void); + + +extern DriverSentinel nest; +extern DriverSentinel garden; +extern DriverSentinel trail_set; + + +#endif + diff --git a/glants_mech/linux/src/camera.c b/glants_mech/linux/src/camera.c new file mode 100644 index 0000000..64f10bc --- /dev/null +++ b/glants_mech/linux/src/camera.c @@ -0,0 +1,819 @@ +// +// Berlin Brown +// bigbinc@hotmail.com +// +// camera.cpp +// +#include +#include +#include + +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library + + +#include "camera.h" +#include "bot.h" +#include "gldrawlib.h" +#include "globals.h" +#include "fireants.h" +#include "menu.h" + + +static int mouse_x = SCREEN_WIDTH / 2; +static int mouse_y = SCREEN_HEIGHT / 2; + +static float mCameraAng = 0.0f; + +// +// Follow this object +static DriverBotPtr camera_bot; + +void GetCameraBot(DriverBotPtr bot) +{ + camera_bot = bot; +} // end of the functino + +// +// GetBotX +// +float GetBotX(void){ + return camera_bot->x; +} + +float GetBotY(void) { + return camera_bot->y; +} + +// with +static float camera_speed = 0.6f; +static float turning_speed= 1.6f; + +// this is another of keeping track of the camera position +// a little simpler than a driver objects + + +int current_camera = 0; + +static DriverCamera camera0; +static DriverCamera camera1; +static DriverCamera camera2; +static DriverCamera camera3; + +static float fTime; + +// +// Array of camera objects +// +DriverCamera *driver_camera[MAX_CAMERAS] = +{ + &camera0, + &camera1, + &camera2, + &camera3, +}; + + +// +// Vector_Minus +// +void Vector_Minus(Vector a, Vector b, Vector res) +{ + res[0] = a[0] - b[0]; + res[1] = a[1] - b[1]; + res[2] = a[2] - b[2]; + +} // end of the function + +// +// Vector_Add +// +void Vector_Add(Vector a, Vector b, Vector res) +{ + res[0] = a[0] + b[0]; + res[1] = a[1] + b[1]; + res[2] = a[2] + b[2]; + +} // end of the function + + +// +// Vector_Length +// +float Vector_Length(Vector a) +{ + return (float)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); + +} // end of the function + +// +// DotProduct +// +float DotProduct(Vector a, Vector b) +{ + return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; +} // end of the function + +// +// Vector_Normalize +// +void Vector_Normalize(Vector a, Vector res) +{ + float len; + + len = Vector_Length(a); + + if (len > 0.0f) + len = 1.0f / len; + else + len = 0.0f; + + res[0] = a[0] * len; + res[1] = a[1] * len; + res[2] = a[2] * len; + +} // end of the function + + +// +// Vector_Multiply +// +void Vector_Multiply(Vector a, Vector res, float b) +{ + res[0] = a[0] * b; + res[1] = a[1] * b; + res[2] = a[2] * b; + +} // end of the functiona + +// +// A spring dampening function +// for the camera +// +void SpringDamp( + Vector currPos, + Vector trgPos, // Target Position + Vector prevTrgPos, // Previous Target Position + Vector result, + + float springConst, // Hooke's Constant + float dampConst, // Damp Constant + float springLen) +{ + Vector disp; // Displacement + Vector velocity; // Velocity + Vector mx; + Vector z; + + float len; + + float dot; + float forceMag; // Force Magnitude + + + // Calculate Spring Force + Vector_Minus(currPos, trgPos, disp); + + Vector_Minus(prevTrgPos, trgPos, velocity); + + len = Vector_Length(disp); + + // get dot product + dot = DotProduct(disp, velocity); + + forceMag = springConst * (springLen - len) + + dampConst * (dot / len); + + Vector_Normalize(disp, z); + + //disp *= forceMag; + Vector_Multiply(z, mx, forceMag); + + printf("%0.2f %0.2f\n", mx[0], currPos[0]); + + Vector_Add(currPos, mx, result); + + //result[0] = currPos[0]; + //result[1] = currPos[1]; + //result[2] = currPos[2]; + +} // end of the function + + +// +// For each specific camera +// place in a particular position +// +static void SetupCamera(void) +{ + + // start at zero + SELECT_CAMERA(0); + PosCamera(0.0f, 2.0f, -10.0f); + + CAMERA->type = CAMERA_WALKING; + + CAMERA->rotation[1] = OFFSET_ROTATION; + + // make sure to reset when done + SELECT_CAMERA(0); + +} // end of the if + + +// +// Mouse_Movement +// - handle mouse movement +// +void Mouse_Movement(void) +{ + //POINT mouse_pos; + float ang_z = 0.0f; + + mouse_x = SCREEN_WIDTH / 2; + mouse_y = SCREEN_HEIGHT / 2; + + // Get the mouse's current X,Y position + //GetCursorPos(&mouse_pos); + + // If our cursor is still in the middle, we never moved... so don't update the screen + //if((mouse_pos.x == mouse_x) && (mouse_pos.y == mouse_y)) + // return; + + // Set the mouse position to the middle of our window + //SetCursorPos(mouse_x, mouse_y); + + //ang_z = (float)((mouse_y - mouse_pos.y)) / 50.0f; + + // The Angle camera is a little flaky + //AngleCamera(0.0f, ang_y, 0.0f); + + // increase the zoom also + CAMERA->zoom_factor -= ang_z; + + if (CAMERA->zoom_factor < 3.0) + CAMERA->zoom_factor = 3.0f; + + +} // end of the if + +// +// Load Cameras +// - basically a constructor for +// the camera objects +// reset variables all to zero, etc +// +void LoadCameras(void) +{ + + int index = 0; + int i = 0; + current_camera = 0; + + for (index = 0; index < MAX_CAMERAS; index++) + { + for (i = 0; i < 3; i++) + { + driver_camera[index]->angle[i] = 0.0f; + driver_camera[index]->position[i] = 0.0f; + driver_camera[index]->rotation[i] = 0.0f; + } // end of the for + + + driver_camera[index]->id = index; + driver_camera[index]->type = CAMERA_STATIC; + + driver_camera[index]->centerx = 0.0f; + driver_camera[index]->centery = 0.0f; + driver_camera[index]->centerz = 0.0f; + + driver_camera[index]->zoom_factor = 3.2f; + + } // end of the functino + + // perform camera specific operations + SetupCamera(); + + +} // end of the function + +// +// Toggle Camera +// - switch to a different camera using +// a simple iterator, basically cycle through +// the cameras +// +void ToggleCamera(void) +{ + current_camera++; + + if (current_camera >= MAX_CAMERAS) + current_camera = 0; + +} // end of the function + +//========================================================= +// positioncamera +// - setup the camera +// this should be called before all drawing code +// NOTE: there is a load id, that is important +// - this is the main matrix, everything it must be +// restored so everything else should have a push or pop +//========================================================= +void SetCamera(void) +{ + + glRotatef(CAMERA->angle[1], + 0.0f, 1.0f, 0.0f); + glRotatef(CAMERA->angle[0], + 1.0f, 0.0f, 0.0f); + glRotatef(CAMERA->angle[2], + 0.0f, 0.0f, 1.0f); + + glTranslatef(CAMERA->position[0], + CAMERA->position[1], + CAMERA->position[2]); + + // move camera to according position + glRotatef(CAMERA->rotation[1], + 0.0f, 1.0f, 0.0f); + glRotatef(CAMERA->rotation[0], + 1.0f, 0.0f, 0.0f); + glRotatef(CAMERA->rotation[2], + 0.0f, 0.0f, 1.0f); + +} // end of the functino + + + +//========================================================= +// movecamera +// - basically translate camera +// Note: this should only be called once dont put in loop +//========================================================= +void TranslateCamera(float x, float y, float z) +{ + // move camera to according position + CAMERA->position[0] += x; + CAMERA->position[1] += y; + CAMERA->position[2] += z; + +} // end of the function + + +//========================================================= +// check angle +//--------------------------------------------------------- +void checkangle(void) +{ + int index=0; + // check the bounds + + for (index=0; index < 3; index++) + { + + if (CAMERA->angle[index] < 0) + { + CAMERA->angle[index] += 360; + } // end of the + + if (CAMERA->angle[index] >= 360) + { + CAMERA->angle[index] -= 360; + } // end of the + + } // end of the for + +} // end of the functino + + +//========================================================= +// check rotation +//--------------------------------------------------------- +void checkrotation(void) +{ + int index=0; + for (index=0; index < 3; index++) + { + if (CAMERA->rotation[index] < 0) + { + CAMERA->rotation[index] += 360; + } // end of the + + if (CAMERA->rotation[index] >= 360) + { + CAMERA->rotation[index] -= 360; + } // end of the + + } // end of the for + +} // end of the functino + + +//--------------------------------------------------------- +// angle camera +// - aim the camera a given directino +// Note: this should only be called once, dont put in loop +//========================================================= +void AngleCamera(float x, float y, float z) +{ + + // this may be a little tricky to understand + // but rotate around own axis if angle flag of + CAMERA->rotation[0] += x; + CAMERA->rotation[1] += y; + CAMERA->rotation[2] += z; + checkrotation(); // check bounds 0->359 + +} // end of the functino + + + +//========================================================= +// turn camera +// - similar to rotate camera +//========================================================= +void TurnCamera(float x, float y, float z) +{ + CAMERA->angle[0] += x; // rotation around own axis + CAMERA->angle[1] -= y; + CAMERA->angle[2] += z; + checkangle(); // check bounds 0->359 + +} // end of the function + +//========================================================= +// put camera +// - give a solid constant position +// might be used at the beginning of the main drawing loop +//========================================================= +void PosCamera(float x, float y, float z) +{ + // move camera to according position + CAMERA->position[0] = x; + CAMERA->position[1] = -y; + CAMERA->position[2] = z; +} // end of the function + +//========================================================= +// put camera +// - give a solid constant position +// might be used at the beginning of the main drawing loop +//========================================================= +void Pos_Camera(float x, float y, float z) +{ + // move camera to according position + CAMERA->position[0] = x; + CAMERA->position[1] = y; + CAMERA->position[2] = z; +} // end of the function + +//========================================================= +// set the rotation angles of the cameras +///======================================================== +void SetCameraRot(float x, float y, float z) +{ + // setup the camera rotations + // The trick is figure out which rotation + // to use (angle or rotation) + CAMERA->rotation[0] = x; + CAMERA->rotation[1] = y; + CAMERA->rotation[2] = z; + +} // end of the functino + +//========================================================= +// set angles of the camera +// interesting +//========================================================= +void SetCameraAngle(float x, float y, float z) +{ + CAMERA->angle[0] = x; + CAMERA->angle[1] = y; + CAMERA->angle[2] = z; +} // end of the funtino + + +// +// Move Forward +// +void MoveForward(void) +{ + + float heading=0; + float xpos,zpos; + + float speed = camera_speed; + float new_speed; + + if (CAMERA->type == CAMERA_WALKING) + { + + heading = CAMERA->angle[1]; + + new_speed = fTime * speed; + xpos = (float)sin(heading*PI_180) * new_speed; + zpos = (float)cos(heading*PI_180) * new_speed; + + TranslateCamera(-xpos, 0.0f, zpos); + + + } else { + TranslateCamera(0.0f, 0.0f, camera_speed); + } // end of if + +} // end of the functino + + +// +// Move Backwards +// +void MoveBackward(void) +{ + + float heading=0; + float xpos, zpos; + + float speed = camera_speed; + float new_speed; + + if (CAMERA->type == CAMERA_WALKING) + { + + heading = CAMERA->angle[1]; + + + heading = CAMERA->angle[1]; + new_speed = fTime * speed; + + xpos = (float)sin(heading*PI_180) * new_speed; + zpos = (float)cos(heading*PI_180) * new_speed; + + TranslateCamera(xpos, 0.0f, -zpos); + + } else { + TranslateCamera(0.0f, 0.0f, -camera_speed); + } // end of if + +} // end of the functino + +// +// MoveLeft +// +void MoveLeft(void) +{ + + float angle; + + + if (CAMERA->type == CAMERA_WALKING) + { + angle = fTime * turning_speed; + TurnCamera(0.0f, angle, 0.0f); + + } else { + angle = fTime * camera_speed; + TranslateCamera(camera_speed, 0.0f, 0.0f); + } // end of if + +} // end of the functino + +// +// SyncCamera +// +void SyncCamera(void) +{ + // sync the camera with the timing + +} // end of the function + +// +// MoveRight +// +void MoveRight(void) +{ + + float angle; + + if (CAMERA->type == CAMERA_WALKING) + { + + angle = fTime * turning_speed; + TurnCamera(0.0f, -angle, 0.0f); + + } else { + + + angle = fTime * camera_speed; + TranslateCamera(-angle, 0.0f, 0.0f); + } // end of if + +} // end of the functino + +// +// Paused_Camera +// - gives kind of a matrix effect +// - not really, but at least I tried +// +void Paused_Camera(void) +{ + float ang; + float rad; + float tmp_heading; + float tmp_x; + float tmp_y; + + float lookat_x; + float lookat_y; + float cam_x, cam_y; + float x,y; + float t; + + // + // calculate the lookat point + // + ang = CAMERA->rotation[1] + + camera_bot->heading + mCameraAng; + + // now the next point of the triangle + // shift by 45 degrees + tmp_heading = ang + 90.0f; + if (tmp_heading > 360.0f) + tmp_heading -= 360.0f; + + rad = tmp_heading / RAD_TO_DEG; + + // also include the zoom + tmp_x = LOOKAT_OFFSET * (float)cos(rad) * CAMERA->zoom_factor; + tmp_y = LOOKAT_OFFSET * (float)sin(rad) * CAMERA->zoom_factor; + + tmp_x = tmp_x + camera_bot->x; + tmp_y = (-tmp_y) + camera_bot->y; + + lookat_x = tmp_x; + lookat_y = tmp_y; + + // get the camera position now + + tmp_heading = ang + 270.0f; + if (tmp_heading > 360.0f) + tmp_heading -= 360.0f; + + rad = tmp_heading / RAD_TO_DEG; + + tmp_x = CAMERA_BOT_OFFSET * (float)cos(rad) * CAMERA->zoom_factor; + tmp_y = CAMERA_BOT_OFFSET * (float)sin(rad) * CAMERA->zoom_factor; + + cam_x = tmp_x + camera_bot->x; + cam_y = (-tmp_y) + camera_bot->y; + + + // must be paused + + x = lookat_x; + y = lookat_y; + + // Of course you can replace glulookat + // with your own function + gluLookAt(cam_x, (CAMERA_HEIGHT*CAMERA->zoom_factor), cam_y, + x, 0.0f, y, 0.0f, 1.0f, 0.0f); + + // Rotate the paused camera a bot + // based on the frame rate + if (framerate <= 8.0f) + framerate = 30.0f; + + t = 0.38f / framerate; + t = framerate * t; + + mCameraAng += t; + if (mCameraAng > 360.0f) + mCameraAng -= 360.0f; + +} // end of the function + + + +// +// FirstPersonMode +// +static void FirstPersonMode(bool *keys) +{ + float x, y; + float h; + float cam_x; + float cam_y; + + x = camera_bot->look_x; + y = camera_bot->look_y; + h = camera_bot->look_h; + + cam_x = camera_bot->cam_x; + cam_y = camera_bot->cam_y; + + Pos_Camera(cam_x, FIRST_HEIGHT, cam_y); + + // Of course you can replace glulookat + // with your own function + gluLookAt(CAMERA->position[0], CAMERA->position[1], + CAMERA->position[2], + x, h, y, 0.0f, 1.0f, 0.0f); + + // player control, strange place I know + Player_Control(keys); + +} // end of the function + + + +// +// ThirdPersonMode +// +static void ThirdPersonMode(bool *keys) +{ + float x, y; + float cam_x; + float cam_y; + + // process the mouse moves around + // our axis + Mouse_Movement(); + + x = camera_bot->look_x; + y = camera_bot->look_y; + + cam_x = camera_bot->cam_x; + cam_y = camera_bot->cam_y; + + Pos_Camera(cam_x, (CAMERA_HEIGHT*CAMERA->zoom_factor), cam_y); + + // Of course you can replace glulookat + // with your own function + gluLookAt(CAMERA->position[0], CAMERA->position[1], + CAMERA->position[2], + x, 0.0f, y, 0.0f, 1.0f, 0.0f); + + // player control, strange place I know + Player_Control(keys); + +} // end of the function + +// +// ToggleViewMode +// +// Note: this should be called in WinProc, Winmain +// +void ToggleViewMode(void) +{ + + // cant change mode while paused + if (ant_globals->paused == 1) + return; + + if (camera_bot->id == PLAYER_0) + { + if (camera_bot->alive == DEAD_STATE) { + camera_bot->view_mode = THIRD_PERSON_MODE; + return; + } // end of the if + + if (camera_bot->view_mode == THIRD_PERSON_MODE) + camera_bot->view_mode = FIRST_PERSON_MODE; + else + camera_bot->view_mode = THIRD_PERSON_MODE; + + } // end of the if + else { + + camera_bot->view_mode = THIRD_PERSON_MODE; + + } // end of the if -else + +} // end of the function + +// +// Handle Camera Keys +// +// - also handles the following camera +// +void HandleCameraKeys(bool *keys) +{ + if (ant_globals->paused == 0) + { + + if (camera_bot->view_mode == THIRD_PERSON_MODE) + { + ThirdPersonMode(keys); + + } else if (camera_bot->view_mode == FIRST_PERSON_MODE) { + + FirstPersonMode(keys); + + } // end of the if -- + + } else { + Paused_Camera(); + + } // end of the if else + +} // end of the functino diff --git a/glants_mech/linux/src/camera.h b/glants_mech/linux/src/camera.h new file mode 100644 index 0000000..5723d18 --- /dev/null +++ b/glants_mech/linux/src/camera.h @@ -0,0 +1,99 @@ +// +// Berlin Brown +// bigbinc@hotmail.com +// +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#include "bot.h" + +#define MAX_ZOOM 45.2f + +#define OFFSET_ROTATION 8.0f + +#define PI_1 3.141592654f + +#define PI (3.14159265358f) +#define PI_180 (PI_1 / 180.0f) + +#define CAMERA driver_camera[current_camera] + +typedef float Vector[3]; + +#define MAX_CAMERAS 4 + + +#define BEGIN_CAMERA glPushMatrix(); SetCamera(); +#define END_CAMERA glPopMatrix(); + +#define SELECT_CAMERA(cam_id) current_camera = cam_id + +#define CAMERA_STATIC 0 +#define CAMERA_WALKING 1 + +//---------------------------------- +// define a camera struct +//.................................. +typedef struct tagCamera +{ + + float position[3]; // current location + float angle[3]; // angle camera is pointing + float rotation[3]; // rotation around the world + float centerx; // center axis + float centery; + float centerz; // center axis x, y, z + + float Yaw; + float Pitch; + float Roll; + + float zoom_factor; + float old_zoom; // save zoom + + int id; // id number for camera + int type; // camera TYPE + +} DriverCamera; + + +void Vector_Normalize(Vector a, Vector res); + +void HandleCameraKeys(bool *keys); + + +float GetBotX(void); +float GetBotY(void); + +void LoadCameras(void); +void ToggleCamera(void); +void SetCamera(void); + +void TranslateCamera(float x, float y, float z); +void AngleCamera(float x, float y, float z); +void TurnCamera(float x, float y, float z); + +void PosCamera(float x, float y, float z); + +void SyncCamera(void); + +void GetCameraBot(DriverBotPtr bot); + +void SpringDamp( + Vector currPos, + Vector trgPos, // Target Position + Vector prevTrgPos, // Previous Target Position + Vector result, + + float springConst, // Hooke's Constant + float dampConst, // Damp Constant + float springLen); + +extern DriverCamera *driver_camera[MAX_CAMERAS]; +extern int current_camera; + +void ToggleViewMode(void); + + +#endif + diff --git a/glants_mech/linux/src/collision.c b/glants_mech/linux/src/collision.c new file mode 100644 index 0000000..4bea8c2 --- /dev/null +++ b/glants_mech/linux/src/collision.c @@ -0,0 +1,953 @@ +// +// collision.cpp +// +// - test a collision against any object +// +// +// +// At present, everything is based on +// ray and line intersection +// +// For example, once a bullet is fired +// it generates a ray, and the ray is tested +// against the lines that make up the wall +// +// A moving object for example one of the +// ships has a +// +// There may several different functions +// to check for collisions +// +// There may also be several different +// ways to insert a segment to perform +// a collision against +// - Berlin Brown +// +#include +#include +#include +#include + +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library + + +#include "collision.h" +#include "gldrawlib.h" +#include "camera.h" +#include "fireants.h" + +static void Reset_DistStack(void); +static void Insert_DistStack(CollisionPtr ptr); +static CollisionPtr Find_DistStack(float x, float y); + +static bool CheckLineHit(CollisionPtr ptr, + float x_1, float y_1, float x_2, float y_2); + + +static void Intersect_Lines(float x0,float y0,float x1,float y1, + float x2,float y2,float x3,float y3, + float *xi,float *yi); +// +// insert +static void InsertFront(CollisionList *list, CollisionObj *col_obj); + +// +// We have a little problem +// since we doing a lot of line collision algorithms +// we need to find the closest collision +// by using a stack and then finding the +// shortest distance on the stack +// +// allocate an array of ptrs +// +static CollisionPtr dist_stack[MAX_DIST_STACK]; +static int dist_stack_ctr = 0; + + +static float mOrig_x=0, mOrig_y=0; +static float mDest_x=0, mDest_y=0; +static float mCol_x = 0, mCol_y=0; + +#define CLOCKWISE -1 +#define COUNTER_CLOCKWISE 1 +#define LINE 0 + + +#define BOT_LIST moving_list + +// main list for collision objects +// +CollisionList *collision_list; + +// +// another list for moving objects +// +CollisionList *moving_list; + + + +// Note: insert and delete are the two most dangerous +// functions + +// +// similar to plist.cpp, except uses CollisionObj +// + + +// +// Reset_DistStack(void) +static void Reset_DistStack(void) +{ + dist_stack_ctr = 0; +} // end of the functino + +// Insert_DistStack +// +static void Insert_DistStack(CollisionPtr ptr) +{ + dist_stack[dist_stack_ctr] = ptr; + + // Note: we are not checking for the max, sorry + dist_stack_ctr++; + +} // end of the function + +// +// Find_DistStack +// - find the shortest from the given +// point +// +static CollisionPtr Find_DistStack(float x, float y) +{ + float min = 10000; + float res; + int i = 0; + float x2, y2; + float tmp1, tmp2; + int min_id=-1; + + CollisionPtr ptr; + + for (i = 0; i < dist_stack_ctr; i++) + { + ptr = dist_stack[i]; + + x2 = ptr->collision_x; + y2 = ptr->collision_y; + + tmp1 = x2 - x; + tmp2 = y2 - y; + + // get the distance + res = (float)sqrt((tmp1 * tmp1)+(tmp2 * tmp2)); + + if (res < min) + { + // get new min + min = res; + min_id = i; + + dist_stack[min_id]->dist = res; + } // end of the if + + } // end of the function + + + return dist_stack[min_id]; + +} // end of the functino + +// +// IsEmpty +// +int IsEmpty(CollisionList *list) +{ + + if (list->front == NULL) + return 1; /* first pointer null, list is empty */ + else + return 0; + +} /* end of the fcuntion */ + +// +// Create CollisionList +// +CollisionList *CreateCollisionList(void) { + + CollisionList *result = (CollisionList *)malloc( + sizeof(CollisionList)); + + result->front = NULL; + result->objects = 0; + + return result; + +} // end of the function + +// +// DestroyColList +// +void DestroyColList(CollisionList *list) { + + CollisionObj *pos, *next; + pos = list->front; + + while(pos != NULL) { + + next = pos->next; + + // need deletecollisionobject + DeleteCollisionObj(pos); + + pos = next; + + } // end of the while + + RELEASE_OBJECT(list); + +} // end of the function + +// +// Insert Front +// - we will assume that you are created the object +// +void InsertColFront(CollisionList *list, CollisionObj *col_obj) +{ + CollisionObj *new_node = NULL; + + new_node = col_obj; + + if (IsEmpty(list)) + + list->front = new_node; + + else { + + new_node->next = list->front; + list->front = new_node; + + } // end if + + list->objects++; + +} // end of the function + +// +// void InsertCol +// - normal setup function +void SetupInsert(CollisionObj **ptr) +{ + (*ptr) = CreateCollisionObj(); + + (*ptr)->id = collision_list->objects; + + InsertColFront(collision_list, *ptr); + +} // end of the function + + +// +// Note: use this with the moving collision +// objects list +// +// Setup_Moving +// +void Setup_Moving(CollisionObj **ptr) +{ + + + (*ptr) = CreateCollisionObj(); + + (*ptr)->id = BOT_LIST->objects; + + InsertColFront(BOT_LIST, *ptr); + + +} // end of the function + +// +// Insert_MovingObj +// +void Insert_MovingObj(DriverBotPtr bot) +{ + + + // set up the struct + CollisionObj *ptr = NULL; + + Setup_Moving(&ptr); // insert into moving obj list + + ptr->movement_type = MOVING_COL_TYPE; // moves + + ptr->bot_ptr = bot; + + +} // end of the function + +// +// Next Library function +// +// Check_MovingHit +// - check a moving object against a bullet +// +bool Check_MovingHit(CollisionPtr ptr, StaticBotPtr boid) +{ + float orig[2]; + float dest[2]; + float res_x, res_y; + float x, y; + float dv; + int i = 0; + float o[2]; + float d[2]; + + + // this value + // can changed to get a more accurate + // collision + + // This value is too high, but it + // almost works -- + dv = 1.1f * BULLET_LEN; + + x = (float)sin(boid->virt_heading*PI_180) * dv; + y = (float)cos(boid->virt_heading*PI_180) * dv; + + // build first line -- + orig[0] = boid->position[0]; + orig[1] = boid->position[2]; + + dest[0] = boid->position[0] - x; + dest[1] = boid->position[2] - y; + + + if (ptr->bot_ptr->alive == DEAD_STATE) + return false; + + // perform two different tests + // + for (i = 0; i < 2; i++) + { + + switch(ptr->movement_type) + { + // we already know the type + // but to be consistent + case MOVING_COL_TYPE: + + // change some of the parms in the ptr + // depending which iteration + if (i == 0) { + // build second line + o[0] = ptr->bot_ptr->x + ptr->bot_ptr->x_min; + o[1] = ptr->bot_ptr->y + + ptr->bot_ptr->y_max; + + d[0] = ptr->bot_ptr->x + ptr->bot_ptr->x_max; + d[1] = ptr->bot_ptr->y + ptr->bot_ptr->y_min; + + } else { + + // build line + o[0] = ptr->bot_ptr->x + ptr->bot_ptr->x_min; + o[1] = ptr->bot_ptr->y + + ptr->bot_ptr->y_min; + + d[0] = ptr->bot_ptr->x + ptr->bot_ptr->x_max; + d[1] = ptr->bot_ptr->y + ptr->bot_ptr->y_max; + + } // end of the if + + ptr->pos_0[0] = o[0]; + ptr->pos_0[1] = o[1]; + + ptr->pos_1[0] = d[0]; + ptr->pos_1[1] = d[1]; + + + if (CheckLineHit(ptr, orig[0], orig[1], + dest[0], dest[1])) + { + + // also get the point of intersection + Intersect_Lines( + ptr->pos_0[0],ptr->pos_0[1], + ptr->pos_1[0],ptr->pos_1[1], + orig[0], orig[1], + dest[0], dest[1], + &res_x, &res_y); + + ptr->collision_x = res_x; + ptr->collision_y = res_y; + + return true; + + } // end of the if + + break; + + + default: break; + }; + + } // end of the for + + return false; + +} // end of the function + + +// +// CheckCollisionMoving +// - check for bullets versus moving ships +// +CollisionPtr CheckCollisionMoving(StaticBotPtr test_obj) +{ + + CollisionObj *current_ptr; + + // we should never assume list is empty but, ahh.. + if (IsEmpty(BOT_LIST)) + return NULL; + + current_ptr = BOT_LIST->front; + + // sorry have to seek down the entire list + while(current_ptr != NULL) + { + if (Check_MovingHit(current_ptr, test_obj)) + { + + return current_ptr; + + } // end of the if + + current_ptr = current_ptr->next; + + } // end of while + + return NULL; + +} // end of the function + + + + + + + + + + + +// +// Insert a Line segment +// +// we are working in 2d space pretty much +// A line segment can be a wall and this +// function converts that wall into a plane +// +// you need to provide the normal +// +void InsertColSegment(float x_1, float y_1, float x_2, float y_2) +{ + + // set up the struct + CollisionObj *ptr = NULL; + + SetupInsert(&(ptr)); // inserted into standard list + + + ptr->pos_0[0] = x_1; + ptr->pos_0[1] = y_1; + + ptr->pos_1[0] = x_2; + ptr->pos_1[1] = y_2; + + // calculate distance from 0,0 + ptr->movement_type = PLANE_COL_TYPE; // does not move + +} // end of the function + +// +// Test for intersection of the line +// assuming they intersect +// +void Intersect_Lines(float x0,float y0,float x1,float y1, + float x2,float y2,float x3,float y3, + float *xi,float *yi) +{ + +float a1,b1,c1, + a2,b2,c2, + det_inv, + m1,m2; + + if ((x1-x0)!=0) + m1 = (y1-y0)/(x1-x0); + else + m1 = (float)90000; + + if ((x3-x2)!=0) + m2 = (y3-y2)/(x3-x2); + else + m2 = (float)1e+10; // close enough to infinity + + // compute constants + + a1 = m1; + a2 = m2; + + b1 = -1; + b2 = -1; + + c1 = (y0-m1*x0); + c2 = (y2-m2*x2); + + // compute the inverse of the determinate + + det_inv = 1/(a1*b2 - a2*b1); + + // use Kramers rule to compute xi and yi + + *xi=((b1*c2 - b2*c1)*det_inv); + *yi=((a2*c1 - a1*c2)*det_inv); + +} // end Intersect_Lines + + +// +// Check for Clock direction +// +int CheckClockDir(float pt1[2], float pt2[2], float pt3[2]) +{ + float test=0; + float tmp1; + float tmp2; + float tmp3; + float tmp4; + + tmp1 = (pt2[0] - pt1[0]); + tmp2 = (pt3[1] - pt1[1]); + tmp3 = (pt3[0] - pt1[0]); + tmp4 = (pt2[1] - pt1[1]); + + test = ( (tmp1 * tmp2) - (tmp3 * tmp4) ); + + if (test > 0) + return COUNTER_CLOCKWISE; + else if(test < 0) + return CLOCKWISE; + else + return LINE; + + return -99; + +} // end of the function + + +// +// CheckLineHit +// +bool CheckLineHit(CollisionPtr ptr, + float x_1, float y_1, float x_2, float y_2) +{ + int test1_a, test1_b, test2_a, test2_b; + + float p0_x, p0_y; + float p1_x, p1_y; + + float a_1p1[2], a_1p2[2], a_2p1[2], a_2p2[2]; + + p0_x = ptr->pos_0[0]; + p0_y = ptr->pos_0[1]; + + p1_x = ptr->pos_1[0]; + p1_y = ptr->pos_1[1]; + + a_1p1[0] = p0_x; + a_1p1[1] = p0_y; // point 1 + + a_1p2[0] = p1_x; // point 2 + a_1p2[1] = p1_y; + + // -- next line -- + a_2p1[0] = x_1; // point 1 + a_2p1[1] = y_1; + + a_2p2[0] = x_2; // point 2 + a_2p2[1] = y_2; + + test1_a = CheckClockDir(a_1p1, a_1p2, a_2p1); + test1_b = CheckClockDir(a_1p1, a_1p2, a_2p2); + + if (test1_a != test1_b) + { + test2_a = CheckClockDir(a_2p1, a_2p2, a_1p1); + test2_b = CheckClockDir(a_2p1, a_2p2, a_1p2); + + if (test2_a != test2_b) + { + + return true; + } // end of the if + + } // end of the if + + return false; + +} // end of the function + + +// +// CheckHitBot +// - check for a collision with a wall and a bot +// +// we assume that the type is a moving bot +// +// with this function, we are testing +// two lines, the lines are a cross over the +// the bot +// +bool CheckHitBot(CollisionPtr ptr, DriverBotPtr bot) +{ + float orig[2]; + float dest[2]; + + int i = 0; + + // perform two different calculations + + // save some calculations if dead + if (bot->alive == DEAD_STATE) + return false; + + for (i = 0; i < 2; i++) + { + + if (i == 0) + { + // build first line -- + orig[0] = (bot->x+bot->x_min); + orig[1] = (bot->y_min+bot->y); + dest[0] = bot->x+bot->x_max; + dest[1] = bot->y_max+bot->y; + } else { + + // build second line + orig[0] = bot->x + bot->x_min; + orig[1] = bot->y + bot->y_max; + + dest[0] = bot->x + bot->x_max; + dest[1] = bot->y + bot->y_min; + + } // end of the if + + switch(ptr->movement_type) + { + case PLANE_COL_TYPE: + + if (CheckLineHit(ptr, orig[0], orig[1], + dest[0], dest[1])) + { + return true; + + } // end of the if + + break; + + + default: break; + }; + + } // end of the for + + return false; + +} // end of the function + + + + + +// +// CheckHitLines +// +bool CheckHitLines(CollisionPtr ptr, void *test_obj, int type) +{ + StaticBotPtr static_ptr=NULL; + float orig[2]; + float dest[2]; + float dx, dy; + float res_x, res_y; + + int owner=-1; + + if (type == RAY_COL_TYPE) { + + static_ptr = (StaticBotPtr)test_obj; + + orig[0] = static_ptr->virt_x; + orig[1] = static_ptr->virt_y; + + // get the next point + dx = (float)sin(static_ptr->virt_heading*PI_180) + * MAX_BULLET_DEST; + dy = (float)cos(static_ptr->virt_heading*PI_180) + * MAX_BULLET_DEST; + + dest[0] = orig[0] - dx; + dest[1] = orig[1] - dy; + + owner = static_ptr->owner; + + } // end of the if + + + switch(ptr->movement_type) + { + case PLANE_COL_TYPE: + + if (CheckLineHit(ptr, orig[0], orig[1], + dest[0], dest[1])) + { + // find the point of intersection + // + Intersect_Lines( + ptr->pos_0[0],ptr->pos_0[1], + ptr->pos_1[0],ptr->pos_1[1], + orig[0], orig[1], + dest[0], dest[1], + &res_x, &res_y); + + ptr->collision_x = res_x; + ptr->collision_y = res_y; + + return true; + + } // end of the if + + break; + + + default: break; + }; + + + return false; + +} // end of the function + + +// +// CheckCollisionList +// - the meat and potatoes of the function +// - check for a collision with our list +// +// returns: NULL means no collision +// - cpu intensive function +// +CollisionPtr CheckCollisionList(void *test_obj, int type) +{ + + CollisionObj *current_ptr; + + StaticBotPtr static_ptr=NULL; + float x=0, y=0; + + // we should never assume list is empty but, ahh.. + if (IsEmpty(collision_list)) + return NULL; + + current_ptr = collision_list->front; + + Reset_DistStack(); + // sorry have to seek down the entire list + while(current_ptr != NULL) + { + if (CheckHitLines(current_ptr, test_obj, type)) + { + // we have a hit, abandon ship + Insert_DistStack(current_ptr); + + } // end of the if + + current_ptr = current_ptr->next; + + } // end of while + + // NULL means no collision + if (dist_stack_ctr == 0) + return NULL; + + + // Now check for the shortest collision + + if (type == RAY_COL_TYPE) { + + static_ptr = (StaticBotPtr)test_obj; + + x = static_ptr->virt_x; + y = static_ptr->virt_y; + + } // end of the if + + current_ptr = Find_DistStack(x, y); + + return current_ptr; + +} // end of the function + + + + +// +//** +// Next Collision Test +// for bot with walls +//** +// +bool CheckCollisionBot(DriverBotPtr test_obj) +{ + + CollisionObj *current_ptr; + + // we should never assume list is empty but, ahh.. + if (IsEmpty(collision_list)) + return NULL; + + current_ptr = collision_list->front; + + // sorry have to seek down the entire list + while(current_ptr != NULL) + { + if (CheckHitBot(current_ptr, test_obj)) + { + + return true; + + } // end of the if + + current_ptr = current_ptr->next; + + } // end of while + + return false; + +} // end of the function + + +// +// Remove Front +// +void RemoveFront(CollisionList *list) +{ + + CollisionObj *temp_ptr = NULL; + + if (IsEmpty(list)) + return; + else { + temp_ptr = list->front; + + if (list->front->next == NULL) + list->front = NULL; // reset + else + list->front = list->front->next; + + //free(temp_ptr); + RELEASE_OBJECT(temp_ptr); + + list->objects--; + + } // end of the if-else + +} // end of the function + +// +// PrintList +// +void PrintCollisionList(CollisionList *list) +{ + + CollisionObj *current_ptr; + + CollisionObj *x=NULL; + + if (IsEmpty(list)) + return; + + current_ptr = list->front; + + while(current_ptr != NULL) + { + // interesting + x = current_ptr; + + printf("ID: %d\n", x->id); + + current_ptr = current_ptr->next; + + } // end of while + +} // end of the function + +// +// CreateCollisionObj +// +CollisionPtr CreateCollisionObj(void) +{ + CollisionPtr ptr = NULL; + + ptr = (CollisionPtr)malloc(sizeof(CollisionObj)); + + ZeroMemory(ptr, sizeof(CollisionObj)); + + ptr->movement_type = PLANE_COL_TYPE; // static or moving + + ptr->next = NULL; + ptr->static_ptr = NULL; + + return ptr; + +} // end of the function + +// +// DeleteCollisionObj +// +void DeleteCollisionObj(CollisionObj *ptr) +{ + RELEASE_OBJECT(ptr); +} // end of the function + +// +// WRAPPER FUNCTIONS +// +void Create_Col_List(void) +{ + collision_list = CreateCollisionList(); + + // also create the moving list + moving_list = CreateCollisionList(); +} // end + +// +// Delelet Col List +// +void Delete_Col_List(void) +{ + DestroyColList(collision_list); + + DestroyColList(moving_list); + +} // end of the function + +// +// Print_Col_List +// +void Print_Col_List(void) +{ + PrintCollisionList(collision_list); +} // end of the function diff --git a/glants_mech/linux/src/collision.h b/glants_mech/linux/src/collision.h new file mode 100644 index 0000000..583b223 --- /dev/null +++ b/glants_mech/linux/src/collision.h @@ -0,0 +1,121 @@ +// +// collision.h +// +#ifndef _COLLISION_H_ +#define _COLLISION_H_ +#include "bot.h" + +#define MOVING_COL_TYPE 3 +#define PLANE_COL_TYPE 1 // i.e a wall +#define RAY_COL_TYPE 2 // i.e a bullet shot + + +#define INWARD_TYPE 1 // wall type +#define OUTWARD_TYPE 2 // box or something + +#define LINE_NO_INTERSECTION 1 +#define LINE_INTERSECTION 2 + +// +// max number of line segments for testing +// +#define MAX_DIST_STACK 250 + +// +// The bullet has to stop somewhere, so +// create some insane value for the desination +#define MAX_BULLET_DEST 2000.0f + +// +// collisionobj +// - for now only handle +// objects with a width and position +// +typedef struct tagCollisionObj { + + int id; + + // used for a line segment + // + float pos_0[2]; + float pos_1[2]; + + // + // collision x,y + // the predicted positions + float collision_x; + float collision_y; + float dist; // distance of collision + + // + // + int movement_type; + + // + // drawing plane object + float box_x; + float box_y; + float size[3]; + + // object can be a driverbot or staticbot + StaticBotPtr static_ptr; + + DriverBotPtr bot_ptr; + + // we need to stop using static arrays + struct tagCollisionObj *next; + +} CollisionObj, *CollisionPtr; + + +void Build_DistStack(void); + +// +// CollisionList +// +typedef struct tagCollisionList { + CollisionObj *front; + int objects; +} CollisionList; + + +// +// Library functions +// +CollisionPtr CreateCollisionObj(void); +void DeleteCollisionObj(CollisionObj *ptr); + +CollisionList *CreateCollisionList(void); +void DestroyColList(CollisionList *list); +void PrintCollisionList(CollisionList *list); +void InsertColFront(CollisionList *list, CollisionObj *col_obj); + +// +// NOTE: in order to use this collision object +// only use the following functions +// + +// for outward objects +void InsertColSegment(float x_1, float y_1, float x_2, float y_2); + +// call in main.cpp/glAnt.cpp, wherever main is +void Create_Col_List(void); +void Delete_Col_List(void); +void Print_Col_List(void); + +// used to perform the check +CollisionPtr CheckCollisionList(void *test_obj, int type); + +// another member function for collision test +bool CheckCollisionBot(DriverBotPtr test_obj); + + +// +// For moving objects here is the library +// +CollisionPtr CheckCollisionMoving(StaticBotPtr test_obj); +void Insert_MovingObj(DriverBotPtr bot); + +#endif + + diff --git a/glants_mech/linux/src/commands.c b/glants_mech/linux/src/commands.c new file mode 100644 index 0000000..865f4aa --- /dev/null +++ b/glants_mech/linux/src/commands.c @@ -0,0 +1,74 @@ +// +// commands.cpp +// +// The command interface +// to have a LaunchCommand +// + +#include +#include + +#include + +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library + +#include "bot.h" + + +// +// GetStartCommand +// +int GetStartState(int cmd) +{ + switch(cmd) + { + case ATTACK_COMMAND: + return RECHECK_STATE; + break; + + case WANDER_COMMAND: + return MOVE_STATE; + break; + + case MOVE_COMMAND: + return GENERATE_STATE; + break; + + default: break; + }; + + return MOVE_STATE; +} // end of the function + + +// +// GenerateCommand +// +// +void Generate_Command(DriverBotPtr bot, int cmd) +{ + + switch(cmd) + { + case ATTACK_COMMAND: + bot->run = Attack_Command; + break; + + case WANDER_COMMAND: + bot->run = Wander_Command; + break; + + case MOVE_COMMAND: + bot->run = Move_Command; + break; + + default: break; + }; + + bot->state = GetStartState(cmd); + + bot->last_command = bot->command; + bot->command = cmd; + +} // end of the function diff --git a/glants_mech/linux/src/config.ini b/glants_mech/linux/src/config.ini new file mode 100644 index 0000000..72309cb --- /dev/null +++ b/glants_mech/linux/src/config.ini @@ -0,0 +1,176 @@ +# +# glAnts - original config.ini +# file, change at your own risk +# +# if you remove this file, the program +# will create another one with the defaults +# so removing this file can be a good thing +# +# +# Also of note, if the system finds an error +# it goes with the default variable +# +# FORMAT has to be [VARIABLE_NAME]=VALUE; +# oh yeah, add the 'f' tag for float +# +# [VARIABLE_NAME]=VALUEf; +# +# COMMENTS are '#' +# +# Remove the comments below are your own risk +# they basically just define the default values +# used, if you remove them then you wont know +# what good values will look like +# +# The only things that really need changing +# are: +# +# USE_ANT_ENGINE: take out the little ants +# +# MAX_FIRE_ANTS: max fighter ants +# +# MAX_BOTS: number of worker ants +# +# INITIAL_ANT_FOOD: the health of the fighter +# ants and the workers +# try 10,000 and they will never die +# +# Also, you may comment one of the variables +# and get the default once the program runs +# + +[GLANTS CONFIG] +# los default is 14.0 +[LINE_OF_SIGHT]=125.0f; + +# Used with the ai, it attacks at any point given +# this radius +# default is 4.0 +[ATTACK_RADIUS]=4.0f; + +# The amount of damage a bullet will inflict +# the damage is reduced considerably +# at a greater distance and its impact +# is great at short distances +# try 5000, hehe +# default = 280 +[BULLET_DAMAGE]=420.0f; + +# defaut is 4.90 +[MIN_BULLET_SPEED]=7.20f; + +# You can get rid of the worker ant +# engine and just shoot stuff +[USE_ANT_ENGINE]=0; + +# the number of attack ants +# default is 4, but that is on a +# slow machine, try 50 for a 1ghz machine +[MAX_FIRE_ANTS]=14; + +# number of worker ants, default=120 +[MAX_BOTS]=1; + +# 0 = place food in random spot +# 1 = place food in centralized spots +[USE_GARDEN_AREA]=1; + +# the max number of pheromones +# an ant can leave +# default: 300 +[MAX_TRAIL_STACK]=300; + +# used with AI, if the ant life reaches +# this point, the ai goes berzerk +# and he will move a little faster +# default: 390 +[DYING_STATE]=390; + +# the number of pheromones +# the ants can leave on the grid +# default: 200, make sure not more than +# max_trail_stack +[MAX_PHEROMONES]=200; + +# default: 1000 +[PHEROMONE_LIFE]=1000; + +# the time before an ant drops a pheromone +# default: 40 +[PHEROMONE_DROP]=40; + +# the number of bullets +# the ai has before recycle +# this doesnt effect that much +# default: 20 +[MAX_BULLETS]=20; + +# this is reduce rapid-fire effect +# slows down the rate for firing speed +# default: 10 +[MAX_FIRE_SPEED]=10; + +# the amount of food that is on the grid +# default: 35 +[MAX_GARDENS]=35; + +# the bot's speed, need I say more +# the fire_ants travel at a little +# slower speed +# default: 0.09 +[BOT_SPEED]=2.29f; + +# when the bots accelerate +# this the top speed +# default: 0.14 +[BOT_MAX_SPEED]=3.04f; + +# default: 1.1 +[MIN_TURN_SPEED]=1.5f; + +# default: 600 +[CHECK_RESPAWN]=600; + +# the max amount of food +# that can respawn at +# any given point in time +# default: 15 +[GARD_RESPAWN_RATE]=15; + +# default: 60 +[MIN_STRAIGHT_STEPS]=60; + +# default: 200 +[MAX_STRAIGHT_STEPS]=200; + +# default: 150 +[MIN_STRAIGHT_STEPS_2]=150; + +# default: 360 +[MAX_STRAIGHT_STEPS_2]=360; + +# +# this is the amount of food +# the ants get as well as the fire_ants +# default: 1000 +[INITIAL_ANT_FOOD]=1000; + +# the amount of food inside +# a block of food in the garden +# default: 7000 +[INITIAL_GARD_FOOD]=7000; + +# default: 0.3 +[FOOD_WIDTH]=0.3f; + +# default: 480 +[INIT_FOOD_RATE]=480; + +# default: 850 +[MAX_FOOD_RATE]=850; + +# default: 1.7 +[MOVE_FOOD_RATE]=1.7f; + +# default: 0.4 +[FOOD_RATE]=0.4f; diff --git a/glants_mech/linux/src/cube.c b/glants_mech/linux/src/cube.c new file mode 100644 index 0000000..518e07f --- /dev/null +++ b/glants_mech/linux/src/cube.c @@ -0,0 +1,342 @@ +// +// Berlin Brown +// bigbinc@hotmail.com +// +// cube.cpp +// +#include +#include + +#include // Header File For The OpenGL32 Library +#include // Header File For The GLu32 Library + + +#include "objects.h" + +static void compilecube(void); +static void drawcube(void); +static void init_cube(int list_id); +static void rendercube(void); + +#undef CURRENT_OBJECT +#define CURRENT_OBJECT colorcube + +// +// simple objects library +// +DriverObjects colorcube = +{ + init_cube, // init, must be called first + compilecube, // compile + drawcube, // draw + rendercube, // render to scene + 0 // loaded by INIT +}; + +// +// init cube +// - load anything special about the cube +// one important function +// +static void init_cube(int list_id) +{ + + CURRENT_OBJECT.visible = 0; + + // store the id through the function + // there is probably a better way to do this + CURRENT_OBJECT.call_id = list_id; + +} // end of the functino + +//========================================================= +// draw cube with normals turned on +// Note: have to use triangles, (dope!) +// - also no particular order when drawing triangles +//========================================================= +static void drawcube(void) +{ + float v[3][3] = { 0 }; + float size = 1.0f; + + // change the size here + // Note: starts from ground + + glBegin(GL_TRIANGLES); + + // left bottom front + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = size; + + v[2][0] = size; + v[2][1] = size; + v[2][2] = size; + + glColor3f(1.0f,0.0f,0.0f); + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + // Finish the front + v[0][0] = size; + v[0][1] = size; + v[0][2] = size; + + v[1][0] = -size; + v[1][1] = size; + v[1][2] = size; + + v[2][0] = -size; + v[2][1] = 0.0f; + v[2][2] = size; + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + // Draw the back triangle + //----------------------------- + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = -size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = size; + v[2][1] = size; + v[2][2] = -size; + + + glColor3f(1.0f,1.0f,0.0f); + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom bac + + // Finish the back + v[0][0] = size; + v[0][1] = size; + v[0][2] = -size; + + v[1][0] = -size; + v[1][1] = size; + v[1][2] = -size; + + v[2][0] = -size; + v[2][1] = 0.0f; + v[2][2] = -size; + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom front + + //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx? + // Draw the right side + // Triangle + v[0][0] = size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = size; + v[2][1] = size; + v[2][2] = size; + + + + glColor3f(0.0f,0.5f,1.0f); + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom bac + + // FINISh the right side of the box + v[0][0] = size; + v[0][1] = 0.0f; + v[0][2] = -size; + + v[1][0] = size; + v[1][1] = size; + v[1][2] = -size; + + v[2][0] = size; + v[2][1] = size; + v[2][2] = size; + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom bac + + // FINISh the left side of the box + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = -size; + + v[1][0] = -size; + v[1][1] = size; + v[1][2] = -size; + + v[2][0] = -size; + v[2][1] = size; + v[2][2] = size; + + glColor3f(1.0f,0.5f,1.0f); + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left bottom bac + + // Draw the left side + // Triangle + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = -size; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = -size; + v[2][1] = size; + v[2][2] = size; + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left side + + // Draw the top and bottom + v[0][0] = size; + v[0][1] = size; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = size; + v[1][2] = -size; + + v[2][0] = -size; + v[2][1] = size; + v[2][2] = -size; + + glColor3f(0.6f,0.6f,0.6f); + // Calc normal and dra + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left side + + // Draw one of the bottom triangles + v[0][0] = size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = -size; + + v[2][0] = -size; + v[2][1] = 0.0f; + v[2][2] = -size; + + // Calc normal and draw + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left side + + // Lets finish the bottom with the second triangle + v[0][0] = -size; + v[0][1] = 0.0f; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = 0.0f; + v[1][2] = size; + + v[2][0] = -size; + v[2][1] = 0.0f; + v[2][2] = -size; + + + glColor3f(0.03f,0.3f,0.3f); + // Calc normal and dra + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left side + + // Go back and finish the top + v[0][0] = -size; + v[0][1] = size; + v[0][2] = size; + + v[1][0] = size; + v[1][1] = size; + v[1][2] = size; + + v[2][0] = -size; + v[2][1] = size; + v[2][2] = -size; + + // Calc normal and dra + glVertex3fv(v[0]); + glVertex3fv(v[1]); + glVertex3fv(v[2]); // triangle left side + + glEnd(); + +} // end of the function + + +//========================================================= +// Now the function to actually draw it +//========================================================= +static void rendercube(void) +{ + static float x=0.0f; + + if (CURRENT_OBJECT.visible) + { + glPushMatrix(); + + glRotatef(x, 0.0f, 1.0f, 0.0f); + glCallList(colorcube.call_id); + x+=2.1f; + glPopMatrix(); + } // end of the if + +} // end of the function + + +//========================================================= +// compile cube +//========================================================= +static void compilecube(void) +{ + int cube_id; + // setup a spot for display list for background + //cubeobject = getcurrentobject(); + cube_id = colorcube.call_id; + + // apply list + glNewList(cube_id, GL_COMPILE); + + // call drawing function + // we could use (drawcube) + // but this may method make it a little better + colorcube.draw(); + + glEndList(); + +} // end of the function diff --git a/glants_mech/linux/src/data/title1.ilf b/glants_mech/linux/src/data/title1.ilf new file mode 100644 index 0000000000000000000000000000000000000000..7992c768aaddaadf34e7aadbe89f638a18ad91e1 GIT binary patch literal 196664 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 ddB?L$2qA

    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