diff --git a/.gitignore b/.gitignore index bbf313b..0953dc0 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,11 @@ *.i*86 *.x86_64 *.hex +tbftss # Debug files *.dSYM/ + +# folders +dist +dev diff --git a/README.md b/README.md index dcd5c07..f31642d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,33 @@ # tbftss 2D mission-based space shooter, based on the Battle for the Solar System space opera trilogy. + +CREDITS + +GRAPHICS + +gfx/planets/earth.png - modified from the the Blue Marble NASA photograph: http://visibleearth.nasa.gov/view.php?id=57723 + +All other graphics are CC BY-NC-SA 3.0, with the following attribution: Copyright 2015, Stephen J Sweeney | www.battleforthesolarsystem.com + +SOUND + +35677__jobro__laser1.ogg - Laser 1, by jobro - https://freesound.org/people/jobro/sounds/35677/ +42106__marcuslee__laser-wrath-4.ogg - Laser Wrath 4, by marcusless - https://freesound.org/people/marcuslee/sounds/42106/ +47252__nthompson__bad-explosion.ogg - bad explosion, by nthompson - https://freesound.org/people/nthompson/sounds/47252/ +77087__supraliminal__laser-short.ogg - Laser short, by Supraliminal - https://freesound.org/people/Supraliminal/sounds/77087/ +162265__qubodup__explosive.ogg - Explosive, by qubodup - https://freesound.org/people/qubodup/sounds/162265/ +207322__animationisaac__short-explosion.ogg - Short explosion, by animationIsaac - https://freesound.org/people/animationIsaac/sounds/207322/ +254071__tb0y298__firework-explosion.ogg - Firework Explosion, by TB0Y298 - https://freesound.org/people/TB0Y298/sounds/254071/ +263621__jamesabdulrahman__permission-to-panic.ogg - Permission to panic?, by jamesabdulrahman - https://freesound.org/people/jamesabdulrahman/sounds/263621/ +268344__julien-matthey__jm-noiz-laser-01.ogg - JM_NOIZ_Laser 01.wav, by Julien Matthey - https://freesound.org/people/Julien%20Matthey/sounds/268344/ +275151__bird-man__gun-shot.ogg - Gun Shot.wav, by Bird_man - https://freesound.org/people/Bird_man/sounds/275151/ + +MUSIC + +Battle in the winter.mp3, by Johan Brodd - http://opengameart.org/content/battle-in-the-winter +battleThemeA.mp3, by cynicmusic.com | pixelsphere.org - http://opengameart.org/content/battle-theme-a +determination.mp3, by artisticdude - http://opengameart.org/content/determination +heroism.ogg, by Edward J. Blakeley (http://www.edwardblakeley.com/) - http://opengameart.org/content/heroism +Pressure.ogg, by yd - http://opengameart.org/content/pressure +Rise of Spirit, by Alexandr Zhelanov - https://soundcloud.com/alexandr-zhelanov +Showdown.mp3, by el-corleo - http://opengameart.org/content/showdown diff --git a/data/app/config.json b/data/app/config.json new file mode 100644 index 0000000..ba00589 --- /dev/null +++ b/data/app/config.json @@ -0,0 +1,8 @@ +{ + "winWidth" : 1280, + "winHeight" : 720, + "vSync" : 1, + "fullscreen" : 0, + "musicVolume" : 8, + "soundVolume" : 10 +} diff --git a/data/battle/bullets.json b/data/battle/bullets.json new file mode 100644 index 0000000..025d012 --- /dev/null +++ b/data/battle/bullets.json @@ -0,0 +1,25 @@ +[ + { + "type" : "BT_PARTICLE", + "damage" : 1, + "textureName" : "gfx/bullets/particleBolt.png", + "sound" : "SND_PARTICLE", + "flags" : "BF_NONE" + }, + + { + "type" : "BT_PLASMA", + "damage" : 3, + "textureName" : "gfx/bullets/plasmaBolt.png", + "sound" : "SND_PLASMA", + "flags" : "BF_NONE" + }, + + { + "type" : "BT_MISSILE", + "damage" : 25, + "textureName" : "gfx/bullets/missile.png", + "sound" : "SND_PLASMA", + "flags" : "BF_ENGINE" + } +] diff --git a/data/fighters/ataf.json b/data/fighters/ataf.json new file mode 100644 index 0000000..e690c39 --- /dev/null +++ b/data/fighters/ataf.json @@ -0,0 +1,41 @@ +{ + "name" : "ATAF", + "health" : 50, + "shield" : 9999, + "speed" : 3, + "reloadTime" : 6, + "shieldRechargeRate" : 5, + "textureName" : "gfx/fighters/ataf.png", + "guns" : [ + { + "type" : "BT_PLASMA", + "x" : -5, + "y" : 0 + }, + { + "type" : "BT_PLASMA", + "x" : 5, + "y" : 0 + }, + { + "type" : "BT_PLASMA", + "x" : 9, + "y" : -4 + }, + { + "type" : "BT_PLASMA", + "x" : -9, + "y" : -4 + }, + { + "type" : "BT_PLASMA", + "x" : 13, + "y" : -8 + }, + { + "type" : "BT_PLASMA", + "x" : -13, + "y" : -8 + } + ] +} diff --git a/data/fighters/dart.json b/data/fighters/dart.json new file mode 100644 index 0000000..085c9af --- /dev/null +++ b/data/fighters/dart.json @@ -0,0 +1,21 @@ +{ + "name" : "Dart", + "health" : 10, + "shield" : 0, + "speed" : 3, + "reloadTime" : 24, + "shieldRechargeRate" : 0, + "textureName" : "gfx/fighters/dart01.png", + "guns" : [ + { + "type" : "BT_PARTICLE", + "x" : -8, + "y" : 0 + }, + { + "type" : "BT_PARTICLE", + "x" : 8, + "y" : 0 + } + ] +} diff --git a/data/fighters/jackal.json b/data/fighters/jackal.json new file mode 100644 index 0000000..7135812 --- /dev/null +++ b/data/fighters/jackal.json @@ -0,0 +1,16 @@ +{ + "name" : "Jackal", + "health" : 50, + "shield" : 50, + "speed" : 2, + "reloadTime" : 14, + "shieldRechargeRate" : 45, + "textureName" : "gfx/fighters/jackal.png", + "guns" : [ + { + "type" : "BT_PLASMA", + "x" : 0, + "y" : 0 + } + ] +} diff --git a/data/fighters/list.json b/data/fighters/list.json new file mode 100644 index 0000000..f97b142 --- /dev/null +++ b/data/fighters/list.json @@ -0,0 +1,10 @@ +[ + "data/fighters/ataf.json", + "data/fighters/dart.json", + "data/fighters/jackal.json", + "data/fighters/simpleDart.json", + "data/fighters/sphinx.json", + "data/fighters/staticDart.json", + "data/fighters/taf.json", + "data/fighters/unarmedDart.json" +] diff --git a/data/fighters/simpleDart.json b/data/fighters/simpleDart.json new file mode 100644 index 0000000..12535d0 --- /dev/null +++ b/data/fighters/simpleDart.json @@ -0,0 +1,21 @@ +{ + "name" : "SimpleDart", + "health" : 10, + "shield" : 0, + "speed" : 3, + "reloadTime" : 24, + "shieldRechargeRate" : 0, + "textureName" : "gfx/fighters/dart01.png", + "guns" : [ + { + "type" : "BT_PARTICLE", + "x" : -8, + "y" : 0 + }, + { + "type" : "BT_PARTICLE", + "x" : 8, + "y" : 0 + } + ] +} diff --git a/data/fighters/sphinx.json b/data/fighters/sphinx.json new file mode 100644 index 0000000..2fb6b1e --- /dev/null +++ b/data/fighters/sphinx.json @@ -0,0 +1,16 @@ +{ + "name" : "Sphinx", + "health" : 75, + "shield" : 50, + "speed" : 1.75, + "reloadTime" : 14, + "shieldRechargeRate" : 60, + "textureName" : "gfx/fighters/sphinx.png", + "guns" : [ + { + "type" : "BT_PLASMA", + "x" : 0, + "y" : 0 + } + ] +} diff --git a/data/fighters/staticDart.json b/data/fighters/staticDart.json new file mode 100644 index 0000000..b0a493c --- /dev/null +++ b/data/fighters/staticDart.json @@ -0,0 +1,9 @@ +{ + "name" : "StaticDart", + "health" : 10, + "shield" : 0, + "speed" : 0, + "reloadTime" : 24, + "shieldRechargeRate" : 0, + "textureName" : "gfx/fighters/dart01.png" +} diff --git a/data/fighters/taf.json b/data/fighters/taf.json new file mode 100644 index 0000000..b1ac1b0 --- /dev/null +++ b/data/fighters/taf.json @@ -0,0 +1,25 @@ +{ + "name" : "TAF", + "health" : 25, + "shield" : 25, + "speed" : 2, + "reloadTime" : 16, + "shieldRechargeRate" : 50, + "textureName" : "gfx/fighters/taf.png", + "guns" : [ + { + "type" : "BT_PLASMA", + "x" : -12, + "y" : -12 + }, + { + "type" : "BT_PLASMA", + "x" : 12, + "y" : -12 + } + ], + "missiles" : { + "type" : "MISSILE_MISSILE", + "ammo" : 4 + } +} diff --git a/data/fighters/unarmedDart.json b/data/fighters/unarmedDart.json new file mode 100644 index 0000000..ea82551 --- /dev/null +++ b/data/fighters/unarmedDart.json @@ -0,0 +1,9 @@ +{ + "name" : "UnarmedDart", + "health" : 10, + "shield" : 0, + "speed" : 3, + "reloadTime" : 24, + "shieldRechargeRate" : 0, + "textureName" : "gfx/fighters/dart01.png" +} diff --git a/data/fonts/Roboto-Medium.ttf b/data/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000..aa00de0 Binary files /dev/null and b/data/fonts/Roboto-Medium.ttf differ diff --git a/data/galaxy/starSystems.json b/data/galaxy/starSystems.json new file mode 100644 index 0000000..a3e6a64 --- /dev/null +++ b/data/galaxy/starSystems.json @@ -0,0 +1,280 @@ +{ + "starSystems": [ + { + "name": "Sol", + "side" : "SIDE_CSN", + "x": 840, + "y": 425, + "missions" : [ + "data/missions/sol/01 - free flight.json", + "data/missions/sol/02 - weapons.json", + "data/missions/sol/03 - moving target.json", + "data/missions/sol/04 - real target.json", + "data/missions/sol/05 - wingmates.json", + "data/missions/sol/06 - final.json" + ] + }, + { + "name": "Alpha Centauri", + "side" : "SIDE_CSN", + "x": 860, + "y": 404, + "missions" : [] + }, + { + "name": "Ecuador Minor", + "side" : "SIDE_CSN", + "x": 831, + "y": 333, + "missions" : [] + }, + { + "name": "Angel", + "side" : "SIDE_CSN", + "x": 690, + "y": 305, + "missions" : [] + }, + { + "name": "Indigo", + "side" : "SIDE_CSN", + "x": 760, + "y": 270, + "missions" : [] + }, + { + "name": "Rex", + "side" : "SIDE_CSN", + "x": 834, + "y": 276, + "missions" : [] + }, + { + "name": "Gabriel", + "side" : "SIDE_CSN", + "x": 860, + "y": 170, + "missions" : [] + }, + { + "name": "Darlon", + "side" : "SIDE_CSN", + "x": 808, + "y": 190, + "missions" : [] + }, + { + "name": "Granada", + "side" : "SIDE_CSN", + "x": 741, + "y": 221, + "missions" : [] + }, + { + "name": "Parish", + "side" : "SIDE_CSN", + "x": 666, + "y": 261, + "missions" : [] + }, + { + "name": "Temper", + "side" : "SIDE_CSN", + "x": 595, + "y": 260, + "missions" : [ + "data/missions/temper/01 - pirate uprising #1.json", + "data/missions/temper/02 - pirate uprising #2.json" + ] + }, + { + "name": "Lenon", + "side" : "SIDE_CSN", + "x": 655, + "y": 180, + "missions" : [] + }, + { + "name": "HD 21563010", + "side" : "SIDE_CSN", + "x": 813, + "y": 54, + "missions" : [] + }, + { + "name": "Trilliack", + "side" : "SIDE_UNF", + "x": 501, + "y": 312, + "missions" : [] + }, + { + "name": "Alba", + "side" : "SIDE_UNF", + "x": 465, + "y": 235, + "missions" : [] + }, + { + "name": "Aster", + "side" : "SIDE_UNF", + "x": 445, + "y": 145, + "missions" : [] + }, + { + "name": "Iliad", + "side" : "SIDE_UNF", + "x": 335, + "y": 135, + "missions" : [] + }, + { + "name": "Warro", + "side" : "SIDE_UNF", + "x": 289, + "y": 216, + "missions" : [] + }, + { + "name": "Coyote", + "side" : "SIDE_UNF", + "x": 325, + "y": 385, + "missions" : [] + }, + { + "name": "Rothan", + "side" : "SIDE_UNF", + "x": 366, + "y": 298, + "missions" : [] + }, + { + "name": "Donesta", + "side" : "SIDE_UNF", + "x": 527, + "y": 161, + "missions" : [] + }, + { + "name": "India", + "side" : "SIDE_UNF", + "x": 539, + "y": 427, + "missions" : [] + }, + { + "name": "Antomis", + "side" : "SIDE_UNF", + "x": 582, + "y": 115, + "missions" : [] + }, + { + "name": "Mace", + "side" : "SIDE_UNF", + "x": 444, + "y": 359, + "missions" : [] + }, + { + "name": "Clarke", + "side" : "SIDE_UNF", + "x": 398, + "y": 84, + "missions" : [] + }, + { + "name": "Adetton", + "side" : "SIDE_INF", + "x": 228, + "y": 228, + "missions" : [] + }, + { + "name": "Atlante", + "side" : "SIDE_INF", + "x": 212, + "y": 85, + "missions" : [] + }, + { + "name": "Carthege", + "side" : "SIDE_INF", + "x": 163, + "y": 122, + "missions" : [] + }, + { + "name": "Codexa", + "side" : "SIDE_INF", + "x": 195, + "y": 101, + "missions" : [] + }, + { + "name": "Haylahe", + "side" : "SIDE_INF", + "x": 204, + "y": 132, + "missions" : [] + }, + { + "name": "Kethlan", + "side" : "SIDE_INF", + "x": 95, + "y": 95, + "missions" : [] + }, + { + "name": "Krasst", + "side" : "SIDE_INF", + "x": 135, + "y": 305, + "missions" : [] + }, + { + "name": "Mekel", + "side" : "SIDE_INF", + "x": 228, + "y": 113, + "missions" : [] + }, + { + "name": "Phylent", + "side" : "SIDE_INF", + "x": 275, + "y": 165, + "missions" : [] + }, + { + "name": "Sampi-Persei VII", + "side" : "SIDE_INF", + "x": 342, + "y": 182, + "missions" : [] + }, + { + "name": "Tigris", + "side" : "SIDE_INF", + "x": 269, + "y": 274, + "missions" : [] + }, + { + "name": "Troy", + "side" : "SIDE_INF", + "x": 107, + "y": 269, + "missions" : [] + }, + { + "name": "Pearl", + "side" : "SIDE_INF", + "x": 133, + "y": 215, + "missions" : [] + } + ] +} diff --git a/data/missions/sol/01 - free flight.json b/data/missions/sol/01 - free flight.json new file mode 100644 index 0000000..18ff9ab --- /dev/null +++ b/data/missions/sol/01 - free flight.json @@ -0,0 +1,13 @@ +{ + "name" : "Free Flight", + "description" : "A simple test flight. Get used to piloting your fighter, without threat of attack or any other dangers to face. There are no objectives to complete in this mission, so you may quit it at any time and move on to the next one.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + } +} diff --git a/data/missions/sol/02 - weapons.json b/data/missions/sol/02 - weapons.json new file mode 100644 index 0000000..26eca49 --- /dev/null +++ b/data/missions/sol/02 - weapons.json @@ -0,0 +1,29 @@ +{ + "name" : "Weapons Training", + "description" : "Practice using your fighter's weapons against a stationary target.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "objectives" : [ + { + "description" : "Destroy Dart", + "targetName" : "Dart", + "targetValue" : 1 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + }, + "fighters" : [ + { + "name" : "Dart", + "type" : "StaticDart", + "side" : "SIDE_PIRATE", + "x" : 800, + "y" : 200 + } + ] +} diff --git a/data/missions/sol/03 - moving target.json b/data/missions/sol/03 - moving target.json new file mode 100644 index 0000000..07106a2 --- /dev/null +++ b/data/missions/sol/03 - moving target.json @@ -0,0 +1,29 @@ +{ + "name" : "Moving Target", + "description" : "Most targets you face in the field will be moving. This course gives you the chance to practice taking down an enemy that moves around.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "objectives" : [ + { + "description" : "Eliminate Dart", + "targetName" : "Dart", + "targetValue" : 1 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + }, + "fighters" : [ + { + "name" : "Dart", + "type" : "UnarmedDart", + "side" : "SIDE_PIRATE", + "x" : 640, + "y" : 0 + } + ] +} diff --git a/data/missions/sol/04 - real target.json b/data/missions/sol/04 - real target.json new file mode 100644 index 0000000..69d875d --- /dev/null +++ b/data/missions/sol/04 - real target.json @@ -0,0 +1,29 @@ +{ + "name" : "Active Target", + "description" : "Face off against an opponent that is armed. The enemy in this course is a Dart, kitted out with twin particle cannons. It shouldn't prove too difficult a challenge.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "objectives" : [ + { + "description" : "Eliminate Dart", + "targetName" : "Dart", + "targetValue" : 1 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + }, + "fighters" : [ + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 640, + "y" : -1000 + } + ] +} diff --git a/data/missions/sol/05 - wingmates.json b/data/missions/sol/05 - wingmates.json new file mode 100644 index 0000000..ad3514e --- /dev/null +++ b/data/missions/sol/05 - wingmates.json @@ -0,0 +1,57 @@ +{ + "name" : "Wingmates", + "description" : "Battle along side two team mates to take on 3 enemy fighters.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "objectives" : [ + { + "description" : "Eliminate Darts", + "targetName" : "Dart", + "targetValue" : 3 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + }, + "fighters" : [ + { + "name" : "TAF", + "type" : "TAF", + "side" : "SIDE_ALLIES", + "x" : 440, + "y" : 480 + }, + { + "name" : "TAF", + "type" : "TAF", + "side" : "SIDE_ALLIES", + "x" : 840, + "y" : 480 + }, + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 2640, + "y" : -1500 + }, + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 2640, + "y" : -1500 + }, + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 2640, + "y" : -1500 + } + ] +} diff --git a/data/missions/sol/06 - final.json b/data/missions/sol/06 - final.json new file mode 100644 index 0000000..a396c18 --- /dev/null +++ b/data/missions/sol/06 - final.json @@ -0,0 +1,57 @@ +{ + "name" : "3 Against 1", + "description" : "Take on three enemy targets single handedly. Once again, these are Darts equipped with simple particle cannons. A single TAF should not find itself outclassed here, so long as the enemy are not allowed to gain the upper hand.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/earth.png", + "music" : "music/Battle in the winter.mp3", + "objectives" : [ + { + "description" : "Eliminate Darts", + "targetName" : "Dart", + "targetValue" : 3 + } + ], + "challenges" : [ + { + "type" : "CHALLENGE_ARMOUR", + "targetValue" : 100 + }, + { + "type" : "CHALLENGE_TIME", + "targetValue" : 30 + }, + { + "type" : "CHALLENGE_ACCURACY", + "targetValue" : 25 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Jim Goddard", + "squadron" : "Midnight Runners" + }, + "fighters" : [ + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 640, + "y" : -1500 + }, + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 640, + "y" : -1500 + }, + { + "name" : "Dart", + "type" : "SimpleDart", + "side" : "SIDE_PIRATE", + "x" : 640, + "y" : -1500 + } + ] +} diff --git a/data/missions/temper/01 - pirate uprising #1.json b/data/missions/temper/01 - pirate uprising #1.json new file mode 100644 index 0000000..7732fa7 --- /dev/null +++ b/data/missions/temper/01 - pirate uprising #1.json @@ -0,0 +1,68 @@ +{ + "name" : "Pirate Uprising #1", + "description" : "The Pandoran's push in to Independent space has led to a surge in pirate activity along the Confederation border. The threat needs to be dealt with immediately, starting with cutting back on the enemy presense at Temper.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/spirit.png", + "music" : "music/battleThemeA.mp3", + "objectives" : [ + { + "description" : "Eliminate Darts", + "targetName" : "Dart", + "targetValue" : 30 + } + ], + "challenges" : [ + { + "type" : "CHALLENGE_NO_LOSSES", + "targetValue" : 0 + }, + { + "type" : "CHALLENGE_ARMOUR", + "targetValue" : 100 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "targetValue" : 15 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Katherine Strickland", + "squadron" : "Steel Bulls" + }, + "fighterGroups" : [ + { + "name" : "Ally", + "type" : "TAF", + "number" : 4, + "side" : "SIDE_ALLIES", + "x" : 0, + "y" : 0 + }, + { + "type" : "SimpleDart", + "name" : "Dart", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : 1000, + "y" : 5000 + }, + { + "type" : "SimpleDart", + "name" : "Dart", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : -3000, + "y" : -3000 + }, + { + "type" : "Dart", + "name" : "Dart", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : 0, + "y" : -6000 + } + ] +} diff --git a/data/missions/temper/02 - pirate uprising #2.json b/data/missions/temper/02 - pirate uprising #2.json new file mode 100644 index 0000000..555182b --- /dev/null +++ b/data/missions/temper/02 - pirate uprising #2.json @@ -0,0 +1,68 @@ +{ + "name" : "Pirate Uprising #2", + "description" : "Despite recent efforts, the pirate and insurgent activity shows no sign of abating. We need to continue to smash the rings as we find them and prevent them from gaining a foothold in Temper, as this could only be bad for morale and the war effort. While we still face Darts, the modifications to these craft are becoming more prevelant, and there are more shielded and plasma-equipped fighters to be found in their ranks.", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/spirit.png", + "music" : "music/battleThemeA.mp3", + "objectives" : [ + { + "description" : "Eliminate Darts", + "targetName" : "Dart", + "targetValue" : 36 + } + ], + "challenges" : [ + { + "type" : "CHALLENGE_1_LOSS", + "targetValue" : 0 + }, + { + "type" : "CHALLENGE_ARMOUR", + "targetValue" : 80 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "targetValue" : 10 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "Katherine Strickland", + "squadron" : "Steel Bulls" + }, + "fighterGroups" : [ + { + "name" : "Ally", + "type" : "TAF", + "number" : 4, + "side" : "SIDE_ALLIES", + "x" : 0, + "y" : 0 + }, + { + "type" : "Dart", + "name" : "Dart", + "number" : 12, + "side" : "SIDE_PIRATE", + "x" : -3000, + "y" : 0 + }, + { + "type" : "Dart", + "name" : "Dart", + "number" : 12, + "side" : "SIDE_PIRATE", + "x" : 4000, + "y" : 0 + }, + { + "type" : "Dart", + "name" : "Dart", + "number" : 12, + "side" : "SIDE_PIRATE", + "x" : 0, + "y" : 6000 + } + ] +} diff --git a/data/missions/test/test.json b/data/missions/test/test.json new file mode 100644 index 0000000..439bf2f --- /dev/null +++ b/data/missions/test/test.json @@ -0,0 +1,90 @@ +{ + "name" : "Operation Menelaus", + "description" : "", + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/spirit.png", + "music" : "music/battleThemeA.mp3", + "objectives" : [ + { + "description" : "Eliminate Enemies", + "targetName" : "Enemy", + "targetValue" : 100 + } + ], + "challenges" : [ + { + "type" : "CHALLENGE_NO_LOSSES", + "targetValue" : 0 + }, + { + "type" : "CHALLENGE_ARMOUR", + "targetValue" : 80 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "targetValue" : 25 + } + ], + "player" : { + "type" : "ATAF", + "side" : "SIDE_CSN" + }, + "fighterGroups" : [ + { + "name" : "Ally", + "type" : "TAF", + "number" : 16, + "side" : "SIDE_CSN", + "x" : 0, + "y" : 0 + }, + { + "type" : "Jackal", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : 1000, + "y" : 5000 + }, + { + "type" : "Jackal", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : 2500, + "y" : 5000 + }, + { + "type" : "Jackal", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : 4000, + "y" : 5000 + }, + { + "type" : "Sphinx", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : -1000, + "y" : 5000 + }, + { + "type" : "Sphinx", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : -2500, + "y" : 5000 + }, + { + "type" : "Sphinx", + "name" : "Enemy", + "number" : 10, + "side" : "SIDE_PIRATE", + "x" : -5000, + "y" : 5000 + } + ] +} diff --git a/data/widgets/battleLost.json b/data/widgets/battleLost.json new file mode 100644 index 0000000..4c6f187 --- /dev/null +++ b/data/widgets/battleLost.json @@ -0,0 +1,22 @@ +[ + { + "name" : "retry", + "group" : "battleLost", + "type" : "WT_BUTTON", + "text" : "Retry", + "x" : 490, + "y" : 680, + "w" : 150, + "h": 34 + }, + { + "name" : "quit", + "group" : "battleLost", + "type" : "WT_BUTTON", + "text" : "Quit", + "x" : 790, + "y" : 680, + "w" : 150, + "h": 34 + } +] diff --git a/data/widgets/battleWon.json b/data/widgets/battleWon.json new file mode 100644 index 0000000..555b657 --- /dev/null +++ b/data/widgets/battleWon.json @@ -0,0 +1,22 @@ +[ + { + "name" : "continue", + "group" : "battleWon", + "type" : "WT_BUTTON", + "text" : "Continue", + "x" : 490, + "y" : 680, + "w" : 150, + "h": 34 + }, + { + "name" : "retry", + "group" : "battleWon", + "type" : "WT_BUTTON", + "text" : "Retry", + "x" : 790, + "y" : 680, + "w" : 150, + "h": 34 + } +] diff --git a/data/widgets/galacticMap.json b/data/widgets/galacticMap.json new file mode 100644 index 0000000..0fa2b92 --- /dev/null +++ b/data/widgets/galacticMap.json @@ -0,0 +1,43 @@ +[ + { + "name" : "resume", + "group" : "galacticMap", + "type" : "WT_BUTTON", + "text" : "Resume", + "x" : -1, + "y" : 215, + "w" : 200, + "h": 34 + }, + { + "name" : "stats", + "group" : "galacticMap", + "type" : "WT_BUTTON", + "text" : "Stats", + "x" : -1, + "y" : 315, + "w" : 200, + "h": 34 + }, + { + "name" : "options", + "group" : "galacticMap", + "type" : "WT_BUTTON", + "text" : "Options", + "x" : -1, + "y" : 415, + "w" : 200, + "h": 34 + }, + { + "name" : "quit", + "group" : "galacticMap", + "type" : "WT_BUTTON", + "text" : "Return to Title", + "x" : -1, + "y" : 515, + "w" : 200, + "h": 34 + } + +] diff --git a/data/widgets/inBattle.json b/data/widgets/inBattle.json new file mode 100644 index 0000000..471540c --- /dev/null +++ b/data/widgets/inBattle.json @@ -0,0 +1,43 @@ +[ + { + "name" : "resume", + "group" : "inBattle", + "type" : "WT_BUTTON", + "text" : "Resume", + "x" : -1, + "y" : 215, + "w" : 200, + "h": 34 + }, + { + "name" : "options", + "group" : "inBattle", + "type" : "WT_BUTTON", + "text" : "Options", + "x" : -1, + "y" : 315, + "w" : 200, + "h": 34 + }, + { + "name" : "restart", + "group" : "inBattle", + "type" : "WT_BUTTON", + "text" : "Restart", + "x" : -1, + "y" : 415, + "w" : 200, + "h": 34 + }, + { + "name" : "quit", + "group" : "inBattle", + "type" : "WT_BUTTON", + "text" : "Quit", + "x" : -1, + "y" : 515, + "w" : 200, + "h": 34 + } + +] diff --git a/data/widgets/list.json b/data/widgets/list.json new file mode 100644 index 0000000..9244008 --- /dev/null +++ b/data/widgets/list.json @@ -0,0 +1,11 @@ +[ + "data/widgets/galacticMap.json", + "data/widgets/okCancel.json", + "data/widgets/startBattle.json", + "data/widgets/inBattle.json", + "data/widgets/battleWon.json", + "data/widgets/battleLost.json", + "data/widgets/title.json", + "data/widgets/options.json", + "data/widgets/stats.json" +] diff --git a/data/widgets/okCancel.json b/data/widgets/okCancel.json new file mode 100644 index 0000000..ea43dc4 --- /dev/null +++ b/data/widgets/okCancel.json @@ -0,0 +1,22 @@ +[ + { + "name" : "ok", + "group" : "okCancel", + "type" : "WT_BUTTON", + "text" : "OK", + "x" : 490, + "y" : 680, + "w" : 150, + "h": 34 + }, + { + "name" : "cancel", + "group" : "okCancel", + "type" : "WT_BUTTON", + "text" : "Cancel", + "x" : 790, + "y" : 680, + "w" : 150, + "h": 34 + } +] diff --git a/data/widgets/options.json b/data/widgets/options.json new file mode 100644 index 0000000..e477a1c --- /dev/null +++ b/data/widgets/options.json @@ -0,0 +1,67 @@ +[ + { + "name" : "windowSize", + "group" : "options", + "type" : "WT_SELECT", + "text" : "Window Size", + "options" : "640 x 360;1280 x 720;1600 x 900;1920 x 1080", + "x" : -1, + "y" : 175, + "w" : 400, + "h": 34 + }, + { + "name" : "soundVolume", + "group" : "options", + "type" : "WT_SELECT", + "text" : "Sound Volume", + "options" : "0;1;2;3;4;5;6;7;8;9;10", + "x" : -1, + "y" : 250, + "w" : 400, + "h": 34 + }, + { + "name" : "musicVolume", + "group" : "options", + "type" : "WT_SELECT", + "text" : "Music Volume", + "options" : "0;1;2;3;4;5;6;7;8;9;10", + "x" : -1, + "y" : 325, + "w" : 400, + "h": 34 + }, + { + "name" : "fullscreen", + "group" : "options", + "type" : "WT_SELECT", + "text" : "Fullscreen", + "options" : "Off;On", + "x" : -1, + "y" : 400, + "w" : 400, + "h": 34 + }, + { + "name" : "vSync", + "group" : "options", + "type" : "WT_SELECT", + "text" : "VSync", + "options" : "Off;On", + "x" : -1, + "y" : 475, + "w" : 400, + "h": 34 + }, + { + "name" : "ok", + "group" : "options", + "type" : "WT_BUTTON", + "text" : "OK", + "x" : -1, + "y" : 625, + "w" : 100, + "h": 34 + } +] diff --git a/data/widgets/startBattle.json b/data/widgets/startBattle.json new file mode 100644 index 0000000..4a5d69d --- /dev/null +++ b/data/widgets/startBattle.json @@ -0,0 +1,12 @@ +[ + { + "name" : "ok", + "group" : "startBattle", + "type" : "WT_BUTTON", + "text" : "OK", + "x" : 640, + "y" : 680, + "w" : 150, + "h": 34 + } +] diff --git a/data/widgets/stats.json b/data/widgets/stats.json new file mode 100644 index 0000000..7744ba5 --- /dev/null +++ b/data/widgets/stats.json @@ -0,0 +1,12 @@ +[ + { + "name" : "ok", + "group" : "stats", + "type" : "WT_BUTTON", + "text" : "OK", + "x" : 640, + "y" : 635, + "w" : 150, + "h": 34 + } +] diff --git a/data/widgets/title.json b/data/widgets/title.json new file mode 100644 index 0000000..1712fd3 --- /dev/null +++ b/data/widgets/title.json @@ -0,0 +1,42 @@ +[ + { + "name" : "newGame", + "group" : "title", + "type" : "WT_BUTTON", + "text" : "New Game", + "x" : -1, + "y" : 250, + "w" : 200, + "h": 34 + }, + { + "name" : "continue", + "group" : "title", + "type" : "WT_BUTTON", + "text" : "Continue", + "x" : -1, + "y" : 350, + "w" : 200, + "h": 34 + }, + { + "name" : "options", + "group" : "title", + "type" : "WT_BUTTON", + "text" : "Options", + "x" : -1, + "y" : 450, + "w" : 200, + "h": 34 + }, + { + "name" : "quit", + "group" : "title", + "type" : "WT_BUTTON", + "text" : "Quit", + "x" : -1, + "y" : 550, + "w" : 200, + "h": 34 + } +] diff --git a/gfx/backgrounds/background01.jpg b/gfx/backgrounds/background01.jpg new file mode 100644 index 0000000..c2a3b0a Binary files /dev/null and b/gfx/backgrounds/background01.jpg differ diff --git a/gfx/backgrounds/background02.jpg b/gfx/backgrounds/background02.jpg new file mode 100644 index 0000000..575ec4d Binary files /dev/null and b/gfx/backgrounds/background02.jpg differ diff --git a/gfx/backgrounds/background03.jpg b/gfx/backgrounds/background03.jpg new file mode 100644 index 0000000..bf74df5 Binary files /dev/null and b/gfx/backgrounds/background03.jpg differ diff --git a/gfx/backgrounds/background04.jpg b/gfx/backgrounds/background04.jpg new file mode 100644 index 0000000..582dae4 Binary files /dev/null and b/gfx/backgrounds/background04.jpg differ diff --git a/gfx/battle/explosion.png b/gfx/battle/explosion.png new file mode 100644 index 0000000..f3bb539 Binary files /dev/null and b/gfx/battle/explosion.png differ diff --git a/gfx/battle/halo.png b/gfx/battle/halo.png new file mode 100644 index 0000000..b40fcfa Binary files /dev/null and b/gfx/battle/halo.png differ diff --git a/gfx/battle/missionComplete.png b/gfx/battle/missionComplete.png new file mode 100644 index 0000000..8a2c4f9 Binary files /dev/null and b/gfx/battle/missionComplete.png differ diff --git a/gfx/battle/missionFailed.png b/gfx/battle/missionFailed.png new file mode 100644 index 0000000..6b4047f Binary files /dev/null and b/gfx/battle/missionFailed.png differ diff --git a/gfx/battle/missionInProgress.png b/gfx/battle/missionInProgress.png new file mode 100644 index 0000000..3939a3e Binary files /dev/null and b/gfx/battle/missionInProgress.png differ diff --git a/gfx/battle/missionStart.png b/gfx/battle/missionStart.png new file mode 100644 index 0000000..70285ba Binary files /dev/null and b/gfx/battle/missionStart.png differ diff --git a/gfx/battle/shieldHit.png b/gfx/battle/shieldHit.png new file mode 100644 index 0000000..9d457aa Binary files /dev/null and b/gfx/battle/shieldHit.png differ diff --git a/gfx/bullets/magBolt.png b/gfx/bullets/magBolt.png new file mode 100644 index 0000000..c037ad0 Binary files /dev/null and b/gfx/bullets/magBolt.png differ diff --git a/gfx/bullets/missile.png b/gfx/bullets/missile.png new file mode 100644 index 0000000..f87ed13 Binary files /dev/null and b/gfx/bullets/missile.png differ diff --git a/gfx/bullets/particleBolt.png b/gfx/bullets/particleBolt.png new file mode 100644 index 0000000..4c0adb5 Binary files /dev/null and b/gfx/bullets/particleBolt.png differ diff --git a/gfx/bullets/plasmaBolt.png b/gfx/bullets/plasmaBolt.png new file mode 100644 index 0000000..6c2b83e Binary files /dev/null and b/gfx/bullets/plasmaBolt.png differ diff --git a/gfx/fighters/acceleratorODP.png b/gfx/fighters/acceleratorODP.png new file mode 100644 index 0000000..59e345c Binary files /dev/null and b/gfx/fighters/acceleratorODP.png differ diff --git a/gfx/fighters/ataf.png b/gfx/fighters/ataf.png new file mode 100644 index 0000000..26c8c21 Binary files /dev/null and b/gfx/fighters/ataf.png differ diff --git a/gfx/fighters/dart01.png b/gfx/fighters/dart01.png new file mode 100644 index 0000000..7e50369 Binary files /dev/null and b/gfx/fighters/dart01.png differ diff --git a/gfx/fighters/dart02.png b/gfx/fighters/dart02.png new file mode 100644 index 0000000..bacd590 Binary files /dev/null and b/gfx/fighters/dart02.png differ diff --git a/gfx/fighters/dart03.png b/gfx/fighters/dart03.png new file mode 100644 index 0000000..3b61fe5 Binary files /dev/null and b/gfx/fighters/dart03.png differ diff --git a/gfx/fighters/dart04.png b/gfx/fighters/dart04.png new file mode 100644 index 0000000..fc5e24a Binary files /dev/null and b/gfx/fighters/dart04.png differ diff --git a/gfx/fighters/dart05.png b/gfx/fighters/dart05.png new file mode 100644 index 0000000..e3ed507 Binary files /dev/null and b/gfx/fighters/dart05.png differ diff --git a/gfx/fighters/dart06.png b/gfx/fighters/dart06.png new file mode 100644 index 0000000..9e54209 Binary files /dev/null and b/gfx/fighters/dart06.png differ diff --git a/gfx/fighters/dart07.png b/gfx/fighters/dart07.png new file mode 100644 index 0000000..6981bb3 Binary files /dev/null and b/gfx/fighters/dart07.png differ diff --git a/gfx/fighters/firefly.png b/gfx/fighters/firefly.png new file mode 100644 index 0000000..edff0ed Binary files /dev/null and b/gfx/fighters/firefly.png differ diff --git a/gfx/fighters/hammerhead.png b/gfx/fighters/hammerhead.png new file mode 100644 index 0000000..9d82b63 Binary files /dev/null and b/gfx/fighters/hammerhead.png differ diff --git a/gfx/fighters/hyena.png b/gfx/fighters/hyena.png new file mode 100644 index 0000000..486c1ab Binary files /dev/null and b/gfx/fighters/hyena.png differ diff --git a/gfx/fighters/jackal.png b/gfx/fighters/jackal.png new file mode 100644 index 0000000..4d865f3 Binary files /dev/null and b/gfx/fighters/jackal.png differ diff --git a/gfx/fighters/khepri.png b/gfx/fighters/khepri.png new file mode 100644 index 0000000..d3494ce Binary files /dev/null and b/gfx/fighters/khepri.png differ diff --git a/gfx/fighters/kingfisher.png b/gfx/fighters/kingfisher.png new file mode 100644 index 0000000..5ff0eac Binary files /dev/null and b/gfx/fighters/kingfisher.png differ diff --git a/gfx/fighters/leopard.png b/gfx/fighters/leopard.png new file mode 100644 index 0000000..463949a Binary files /dev/null and b/gfx/fighters/leopard.png differ diff --git a/gfx/fighters/mantis.png b/gfx/fighters/mantis.png new file mode 100644 index 0000000..cea2961 Binary files /dev/null and b/gfx/fighters/mantis.png differ diff --git a/gfx/fighters/nymph.png b/gfx/fighters/nymph.png new file mode 100644 index 0000000..ba87df4 Binary files /dev/null and b/gfx/fighters/nymph.png differ diff --git a/gfx/fighters/plasmaODP.png b/gfx/fighters/plasmaODP.png new file mode 100644 index 0000000..db9b5ee Binary files /dev/null and b/gfx/fighters/plasmaODP.png differ diff --git a/gfx/fighters/ray.png b/gfx/fighters/ray.png new file mode 100644 index 0000000..eedf5a8 Binary files /dev/null and b/gfx/fighters/ray.png differ diff --git a/gfx/fighters/rocketODP.png b/gfx/fighters/rocketODP.png new file mode 100644 index 0000000..31c729a Binary files /dev/null and b/gfx/fighters/rocketODP.png differ diff --git a/gfx/fighters/rook.png b/gfx/fighters/rook.png new file mode 100644 index 0000000..aa7489a Binary files /dev/null and b/gfx/fighters/rook.png differ diff --git a/gfx/fighters/scarab.png b/gfx/fighters/scarab.png new file mode 100644 index 0000000..f46ba11 Binary files /dev/null and b/gfx/fighters/scarab.png differ diff --git a/gfx/fighters/sphinx.png b/gfx/fighters/sphinx.png new file mode 100644 index 0000000..0c4110e Binary files /dev/null and b/gfx/fighters/sphinx.png differ diff --git a/gfx/fighters/taf.png b/gfx/fighters/taf.png new file mode 100644 index 0000000..55b689a Binary files /dev/null and b/gfx/fighters/taf.png differ diff --git a/gfx/fighters/thunderhead.png b/gfx/fighters/thunderhead.png new file mode 100644 index 0000000..402eab1 Binary files /dev/null and b/gfx/fighters/thunderhead.png differ diff --git a/gfx/galaxy/starSystem.png b/gfx/galaxy/starSystem.png new file mode 100644 index 0000000..44b22bc Binary files /dev/null and b/gfx/galaxy/starSystem.png differ diff --git a/gfx/hud/smallFighter.png b/gfx/hud/smallFighter.png new file mode 100644 index 0000000..4479e43 Binary files /dev/null and b/gfx/hud/smallFighter.png differ diff --git a/gfx/hud/targetCircle.png b/gfx/hud/targetCircle.png new file mode 100644 index 0000000..924ef0e Binary files /dev/null and b/gfx/hud/targetCircle.png differ diff --git a/gfx/hud/targetPointer.png b/gfx/hud/targetPointer.png new file mode 100644 index 0000000..6f6ff7d Binary files /dev/null and b/gfx/hud/targetPointer.png differ diff --git a/gfx/planets/adelaide.png b/gfx/planets/adelaide.png new file mode 100755 index 0000000..117d538 Binary files /dev/null and b/gfx/planets/adelaide.png differ diff --git a/gfx/planets/al-Elfia.png b/gfx/planets/al-Elfia.png new file mode 100755 index 0000000..b37414e Binary files /dev/null and b/gfx/planets/al-Elfia.png differ diff --git a/gfx/planets/arlos.png b/gfx/planets/arlos.png new file mode 100755 index 0000000..32b3ebe Binary files /dev/null and b/gfx/planets/arlos.png differ diff --git a/gfx/planets/bluePlanet.png b/gfx/planets/bluePlanet.png new file mode 100755 index 0000000..b7dfe0e Binary files /dev/null and b/gfx/planets/bluePlanet.png differ diff --git a/gfx/planets/diso.png b/gfx/planets/diso.png new file mode 100755 index 0000000..ae1b988 Binary files /dev/null and b/gfx/planets/diso.png differ diff --git a/gfx/planets/earth.png b/gfx/planets/earth.png new file mode 100755 index 0000000..c8e8c7a Binary files /dev/null and b/gfx/planets/earth.png differ diff --git a/gfx/planets/henninger.png b/gfx/planets/henninger.png new file mode 100755 index 0000000..74546d9 Binary files /dev/null and b/gfx/planets/henninger.png differ diff --git a/gfx/planets/hyanik.png b/gfx/planets/hyanik.png new file mode 100755 index 0000000..10cd014 Binary files /dev/null and b/gfx/planets/hyanik.png differ diff --git a/gfx/planets/kaiser.png b/gfx/planets/kaiser.png new file mode 100755 index 0000000..5616b52 Binary files /dev/null and b/gfx/planets/kaiser.png differ diff --git a/gfx/planets/kethlan.png b/gfx/planets/kethlan.png new file mode 100755 index 0000000..356888e Binary files /dev/null and b/gfx/planets/kethlan.png differ diff --git a/gfx/planets/mythos.png b/gfx/planets/mythos.png new file mode 100755 index 0000000..dbcc133 Binary files /dev/null and b/gfx/planets/mythos.png differ diff --git a/gfx/planets/oracleIX.png b/gfx/planets/oracleIX.png new file mode 100755 index 0000000..d850c2d Binary files /dev/null and b/gfx/planets/oracleIX.png differ diff --git a/gfx/planets/peri.png b/gfx/planets/peri.png new file mode 100755 index 0000000..80abf3c Binary files /dev/null and b/gfx/planets/peri.png differ diff --git a/gfx/planets/sky.png b/gfx/planets/sky.png new file mode 100755 index 0000000..b644898 Binary files /dev/null and b/gfx/planets/sky.png differ diff --git a/gfx/planets/spirit.png b/gfx/planets/spirit.png new file mode 100755 index 0000000..61beb96 Binary files /dev/null and b/gfx/planets/spirit.png differ diff --git a/gfx/planets/tigibel.png b/gfx/planets/tigibel.png new file mode 100755 index 0000000..aa55a2a Binary files /dev/null and b/gfx/planets/tigibel.png differ diff --git a/gfx/planets/tilli.png b/gfx/planets/tilli.png new file mode 100755 index 0000000..df158ce Binary files /dev/null and b/gfx/planets/tilli.png differ diff --git a/gfx/planets/torelli.png b/gfx/planets/torelli.png new file mode 100755 index 0000000..0795b77 Binary files /dev/null and b/gfx/planets/torelli.png differ diff --git a/gfx/planets/xalan.png b/gfx/planets/xalan.png new file mode 100755 index 0000000..9f900fe Binary files /dev/null and b/gfx/planets/xalan.png differ diff --git a/gfx/title/logo.png b/gfx/title/logo.png new file mode 100644 index 0000000..0361b25 Binary files /dev/null and b/gfx/title/logo.png differ diff --git a/gfx/title/pandoran.png b/gfx/title/pandoran.png new file mode 100644 index 0000000..eae30cc Binary files /dev/null and b/gfx/title/pandoran.png differ diff --git a/gfx/widgets/optionsLeft.png b/gfx/widgets/optionsLeft.png new file mode 100644 index 0000000..29da76b Binary files /dev/null and b/gfx/widgets/optionsLeft.png differ diff --git a/gfx/widgets/optionsRight.png b/gfx/widgets/optionsRight.png new file mode 100644 index 0000000..4a0d7fe Binary files /dev/null and b/gfx/widgets/optionsRight.png differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..9325176 --- /dev/null +++ b/makefile @@ -0,0 +1,51 @@ +PROG = tbftss + +VERSION = 0.1 +RELEASE = 1 + +CXXFLAGS += `sdl2-config --cflags` -DVERSION=$(VERSION) -DRELEASE=$(RELEASE) -DUNIX=1 +CXXFLAGS += -DUNIX +CXXFLAGS += $(CFLAGS) -Wall -ansi -pedantic -Werror -Wstrict-prototypes +CXXFLAGS += -g -lefence + +LIBS = `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm + +SEARCHPATH += src/ src/battle src/draw src/game src/galaxy src/json src/system +vpath %.c $(SEARCHPATH) +vpath %.h $(SEARCHPATH) + +DEPS += defs.h structs.h + +OBJS += ai.o +OBJS += battle.o bullets.o +OBJS += challenges.o cJSON.o +OBJS += draw.o +OBJS += effects.o +OBJS += fighters.o fighterDefs.o +OBJS += galacticMap.o game.o +OBJS += hud.o +OBJS += init.o io.o +OBJS += load.o lookup.o +OBJS += main.o mission.o missionInfo.o +OBJS += objectives.o options.o +OBJS += player.o +OBJS += radar.o +OBJS += save.o sound.o starfield.o starSystems.o stats.o +OBJS += textures.o text.o title.o transition.o +OBJS += util.o +OBJS += widgets.o + +# top-level rule to create the program. +all: $(PROG) + +# compiling other source files. +%.o: %.c %.h $(DEPS) + $(CC) $(CXXFLAGS) -c $< + +# linking the program. +$(PROG): $(OBJS) + $(CC) -o $(PROG) $(OBJS) $(LIBS) + +# cleaning everything that can be automatically recreated with "make". +clean: + $(RM) $(OBJS) $(PROG) $(SERVEROBJS) $(SERVER) diff --git a/manual/index.html b/manual/index.html new file mode 100644 index 0000000..e41413f --- /dev/null +++ b/manual/index.html @@ -0,0 +1,64 @@ + + +
++The Battle for the Solar System - The Pandoran War is a 2D space shooter, based on the space opera novels by Stephen J Sweeney. +
+Note: this game is still under heavy development and will feature bugs, incomplete sections, and a numerous other issues until it reaches v1.0. Likewise, this gameplay manually will evolve over time, to become more detailed and helpful.
+ ++This is the main mission select screen. Here, you can move around and select star systems in which to undertake missions. Star Systems that have missions will emit red circles at regular intervals. Yellow circles will be emitted by star systems that have no active missions, but still have challenges that can be attempted. +
+ +Controls
+Arrow keys | Scroll galactic map |
Return | Select Star System |
Escape | Menu |
+The Star System view shows a list of missions available for that star system. Missions must be played sequentially, with the next available mission being highlighted in yellow. The right-hand side of the star system view displays an overview of the mission, including the class of craft the player will be piloting, and the name of the pilot and their squadron. +
+ +Controls
+Arrow keys | Scroll galactic map |
Return | Select Star System |
Escape | Menu |
+Each mission has various objectives that the player must finish in order to complete the mission successfully. The mission ends when the player either successfully completes all the objectives, or is killed. +
+ +Controls
+Left arrow | Rotate anti-clockwise |
Right arrow | Rotate clockwise |
Up arrow | Accelerate |
Down arrow | Decelerate |
Left control | Fire main cannons |
Return | Launch missile |
Tab | Display objectives |
Escape | Menu |
+This game is based on the Battle for the Solar System novel trilogy by Stephen J Sweeney. You can learn more about the trilogy by visiting: +
+ +www.battleforthesolarsystem.com
+ +The Battle for the Solar System and related related materials are Copyright ©2009-2015, Stephen J Sweeney. All Rights Reserved.
+ + + diff --git a/music/Battle in the winter.mp3 b/music/Battle in the winter.mp3 new file mode 100644 index 0000000..fcb98c4 Binary files /dev/null and b/music/Battle in the winter.mp3 differ diff --git a/music/Pressure.ogg b/music/Pressure.ogg new file mode 100644 index 0000000..922b0d3 Binary files /dev/null and b/music/Pressure.ogg differ diff --git a/music/Rise of spirit.ogg b/music/Rise of spirit.ogg new file mode 100644 index 0000000..c31277c Binary files /dev/null and b/music/Rise of spirit.ogg differ diff --git a/music/Showdown.mp3 b/music/Showdown.mp3 new file mode 100644 index 0000000..a8164bf Binary files /dev/null and b/music/Showdown.mp3 differ diff --git a/music/battleThemeA.mp3 b/music/battleThemeA.mp3 new file mode 100644 index 0000000..d22aa61 Binary files /dev/null and b/music/battleThemeA.mp3 differ diff --git a/music/determination.mp3 b/music/determination.mp3 new file mode 100644 index 0000000..0449c63 Binary files /dev/null and b/music/determination.mp3 differ diff --git a/music/heroism.ogg b/music/heroism.ogg new file mode 100644 index 0000000..279c48c Binary files /dev/null and b/music/heroism.ogg differ diff --git a/sound/162265__qubodup__explosive.ogg b/sound/162265__qubodup__explosive.ogg new file mode 100644 index 0000000..3126c69 Binary files /dev/null and b/sound/162265__qubodup__explosive.ogg differ diff --git a/sound/178064__jorickhoofd__slam-door-shut.ogg b/sound/178064__jorickhoofd__slam-door-shut.ogg new file mode 100644 index 0000000..df74680 Binary files /dev/null and b/sound/178064__jorickhoofd__slam-door-shut.ogg differ diff --git a/sound/207322__animationisaac__short-explosion.ogg b/sound/207322__animationisaac__short-explosion.ogg new file mode 100644 index 0000000..55a756f Binary files /dev/null and b/sound/207322__animationisaac__short-explosion.ogg differ diff --git a/sound/249300__suntemple__access-denied.ogg b/sound/249300__suntemple__access-denied.ogg new file mode 100644 index 0000000..0460b8c Binary files /dev/null and b/sound/249300__suntemple__access-denied.ogg differ diff --git a/sound/254071__tb0y298__firework-explosion.ogg b/sound/254071__tb0y298__firework-explosion.ogg new file mode 100644 index 0000000..3570832 Binary files /dev/null and b/sound/254071__tb0y298__firework-explosion.ogg differ diff --git a/sound/257786__xtrgamr__mouse-click.ogg b/sound/257786__xtrgamr__mouse-click.ogg new file mode 100644 index 0000000..66cd162 Binary files /dev/null and b/sound/257786__xtrgamr__mouse-click.ogg differ diff --git a/sound/263621__jamesabdulrahman__permission-to-panic.ogg b/sound/263621__jamesabdulrahman__permission-to-panic.ogg new file mode 100644 index 0000000..22a380b Binary files /dev/null and b/sound/263621__jamesabdulrahman__permission-to-panic.ogg differ diff --git a/sound/268344__julien-matthey__jm-noiz-laser-01.ogg b/sound/268344__julien-matthey__jm-noiz-laser-01.ogg new file mode 100644 index 0000000..46bd87d Binary files /dev/null and b/sound/268344__julien-matthey__jm-noiz-laser-01.ogg differ diff --git a/sound/275151__bird-man__gun-shot.ogg b/sound/275151__bird-man__gun-shot.ogg new file mode 100644 index 0000000..687c660 Binary files /dev/null and b/sound/275151__bird-man__gun-shot.ogg differ diff --git a/sound/321104__nsstudios__blip2.ogg b/sound/321104__nsstudios__blip2.ogg new file mode 100644 index 0000000..acd92eb Binary files /dev/null and b/sound/321104__nsstudios__blip2.ogg differ diff --git a/sound/35677__jobro__laser1.ogg b/sound/35677__jobro__laser1.ogg new file mode 100644 index 0000000..1f7bf2b Binary files /dev/null and b/sound/35677__jobro__laser1.ogg differ diff --git a/sound/42106__marcuslee__laser-wrath-4.ogg b/sound/42106__marcuslee__laser-wrath-4.ogg new file mode 100644 index 0000000..d2cde08 Binary files /dev/null and b/sound/42106__marcuslee__laser-wrath-4.ogg differ diff --git a/sound/47252__nthompson__bad-explosion.ogg b/sound/47252__nthompson__bad-explosion.ogg new file mode 100644 index 0000000..0762ece Binary files /dev/null and b/sound/47252__nthompson__bad-explosion.ogg differ diff --git a/sound/77087__supraliminal__laser-short.ogg b/sound/77087__supraliminal__laser-short.ogg new file mode 100644 index 0000000..6e554d8 Binary files /dev/null and b/sound/77087__supraliminal__laser-short.ogg differ diff --git a/src/battle/ai.c b/src/battle/ai.c new file mode 100644 index 0000000..bb5111b --- /dev/null +++ b/src/battle/ai.c @@ -0,0 +1,293 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "ai.h" + +static int aggression[][5] = +{ + {25, 35, 35, 40, 50}, + {20, 30, 30, 35, 40}, + {15, 20, 25, 30, 35}, + {10, 15, 20, 25, 30}, + {5, 10, 15, 20, 25} +}; + +static void faceTarget(Fighter *f); +static int isInFOV(Fighter *f, int fov); +static void preAttack(void); +static void huntTarget(void); +static void huntAndAttackTarget(void); +static void flyStraight(void); +static void dodge(void); +static void nextAction(void); +static void findTarget(void); +static int hasClearShot(void); +static void boost(void); +static void slow(void); +static int targetOutOfRange(void); +static void moveToPlayer(void); + +void doAI(void) +{ + int r; + + if (!self->target || targetOutOfRange()) + { + findTarget(); + + if (self->target == NULL) + { + if (player != NULL && self->side == player->side) + { + moveToPlayer(); + } + else + { + applyFighterBrakes(); + } + return; + } + } + + r = rand() % 100; + + if (r <= aggression[self->aggression][0]) + { + self->action = dodge; + self->aiActionTime = FPS * 2; + } + else if (r <= aggression[self->aggression][1]) + { + self->action = boost; + self->aiActionTime = FPS * 1; + } + else if (r <= aggression[self->aggression][2]) + { + self->action = slow; + self->aiActionTime = FPS * 1; + } + else if (r <= aggression[self->aggression][3]) + { + self->action = flyStraight; + self->aiActionTime = FPS * 1; + } + else if (r <= aggression[self->aggression][4]) + { + self->action = huntTarget; + self->aiActionTime = FPS * 2; + } + else + { + self->action = huntAndAttackTarget; + self->aiActionTime = FPS * 1; + } +} + +static int targetOutOfRange(void) +{ + return getDistance(self->x, self->y, self->target->x, self->target->y) > 2000; +} + +static void huntTarget(void) +{ + faceTarget(self->target); + + applyFighterThrust(); + + nextAction(); +} + +static void huntAndAttackTarget(void) +{ + int dist = getDistance(self->x, self->y, self->target->x, self->target->y); + + faceTarget(self->target); + + if (dist <= 500 && hasClearShot()) + { + preAttack(); + } + + if (dist <= 250) + { + applyFighterBrakes(); + self->aiActionTime = MIN(FPS, self->aiActionTime); + } + else + { + applyFighterThrust(); + } + + nextAction(); +} + +static void findTarget(void) +{ + Fighter *f; + int closest = 2000; + int dist = 2000; + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + if (f->side != self->side && f->health > 0) + { + dist = getDistance(self->x, self->y, f->x, f->y); + if (dist < closest) + { + self->target = f; + closest = dist; + } + } + } +} + +static void faceTarget(Fighter *f) +{ + int dir; + int wantedAngle = getAngle(self->x, self->y, f->x, f->y); + + wantedAngle %= 360; + + if (fabs(wantedAngle - self->angle) > TURN_THRESHOLD) + { + dir = (wantedAngle - self->angle + 360) % 360 > 180 ? -1 : 1; + + self->angle += dir * TURN_SPEED; + + self->angle = mod(self->angle, 360); + + applyFighterBrakes(); + } +} + +static int isInFOV(Fighter *f, int fov) +{ + int angle, a, b; + + a = mod(self->angle - fov, 360); + b = mod(self->angle + fov, 360); + angle = getAngle(self->x, self->y, f->x, f->y); + + return (a < b) ? (a <= angle && angle <= b) : (a <= angle || angle <= b); +} + +static void boost(void) +{ + self->dx *= 1.001; + self->dy *= 1.001; + + nextAction(); +} + +static void slow(void) +{ + self->dx *= 0.95; + self->dy *= 0.95; + + nextAction(); +} + +static int hasClearShot(void) +{ + int dist; + Fighter *f; + + if (isInFOV(self->target, 4)) + { + dist = getDistance(self->x, self->y, self->target->x, self->target->y); + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + if (f != self && f != self->target && (getDistance(self->x, self->y, f->x, f->y) < dist)) + { + if (isInFOV(f, 8)) + { + return 0; + } + } + } + + return 1; + } + + return 0; +} + +static void preAttack(void) +{ + if (!self->reload && self->guns[0].type) + { + fireGuns(self); + } +} + +static void flyStraight(void) +{ + applyFighterThrust(); + + nextAction(); +} + +static void dodge(void) +{ + int dir; + int wantedAngle = 180 + getAngle(self->x, self->y, self->target->x, self->target->y); + + wantedAngle %= 360; + + if (fabs(wantedAngle - self->angle) > TURN_THRESHOLD) + { + dir = (wantedAngle - self->angle + 360) % 360 > 180 ? -1 : 1; + + self->angle += dir * TURN_SPEED; + + self->angle = mod(self->angle, 360); + } + + applyFighterThrust(); + + nextAction(); +} + +static void nextAction(void) +{ + if (--self->aiActionTime <= 0) + { + self->action = doAI; + } +} + +static void moveToPlayer(void) +{ + int dist = getDistance(self->x, self->y, player->x, player->y); + + if (dist <= 250) + { + applyFighterBrakes(); + + self->aiActionTime = MIN(FPS, self->aiActionTime); + } + else + { + faceTarget(player); + + applyFighterThrust(); + } +} diff --git a/src/battle/ai.h b/src/battle/ai.h new file mode 100644 index 0000000..b606de0 --- /dev/null +++ b/src/battle/ai.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +#define TURN_SPEED 4 +#define TURN_THRESHOLD 2 + +extern int mod(int n, int x); +extern int getDistance(int x1, int y1, int x2, int y2); +extern void fireGuns(Fighter *owner); +extern float getAngle(int x1, int y1, int x2, int y2); +extern void applyFighterThrust(void); +extern void applyFighterBrakes(void); + +extern Battle battle; +extern Fighter *self; +extern Fighter *player; diff --git a/src/battle/battle.c b/src/battle/battle.c new file mode 100644 index 0000000..bf623ef --- /dev/null +++ b/src/battle/battle.c @@ -0,0 +1,355 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "battle.h" + +static void logic(void); +static void draw(void); +static void handleKeyboard(void); +static void postBattle(void); +void destroyBattle(void); +static void doBattle(void); +static void quitBattle(void); +static void drawMenu(void); +static void continueGame(void); +static void resume(void); +static void retry(void); +static void start(void); +static void options(void); +static void returnFromOptions(void); + +static int show; + +void initBattle(void) +{ + memset(&battle, 0, sizeof(Battle)); + battle.bulletTail = &battle.bulletHead; + battle.fighterTail = &battle.fighterHead; + battle.effectTail = &battle.effectHead; + battle.objectiveTail = &battle.objectiveHead; + + app.delegate.logic = &logic; + app.delegate.draw = &draw; + memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + initStars(); + + initBackground(); + + initHud(); + + initMissionInfo(); + + show = SHOW_BATTLE; + + getWidget("ok", "startBattle")->action = start; + + getWidget("resume", "inBattle")->action = resume; + getWidget("options", "inBattle")->action = options; + getWidget("restart", "inBattle")->action = retry; + getWidget("quit", "inBattle")->action = quitBattle; + + getWidget("continue", "battleWon")->action = continueGame; + getWidget("retry", "battleWon")->action = retry; + + getWidget("retry", "battleLost")->action = retry; + getWidget("quit", "battleLost")->action = quitBattle; + + selectWidget("ok", "startBattle"); + + /* only increment the missions started if there are objectives (Free Flight) */ + if (battle.objectiveHead.next) + { + game.stats.missionsStarted++; + } +} + +static void logic(void) +{ + if (battle.status == MS_IN_PROGRESS || battle.status == MS_COMPLETE || battle.status == MS_FAILED) + { + handleKeyboard(); + + if (show == SHOW_BATTLE) + { + doBattle(); + } + } + + doWidgets(); +} + +static void doBattle(void) +{ + scrollBackground(-battle.ssx * 0.1, -battle.ssy * 0.1); + + doHud(); + + doObjectives(); + + if (player != NULL) + { + battle.ssx = player->dx; + battle.ssy = player->dy; + } + else + { + battle.ssx *= 0.99; + battle.ssy *= 0.99; + } + + battle.planet.x -= (battle.ssx * 0.25); + battle.planet.y -= (battle.ssy * 0.25); + + doStars(battle.ssx, battle.ssy); + + doBullets(); + + doFighters(); + + doEffects(); + + doPlayer(); + + if (battle.status != MS_IN_PROGRESS) + { + battle.missionFinishedTimer--; + + if (battle.missionFinishedTimer == 0) + { + if (battle.status == MS_COMPLETE) + { + selectWidget("continue", "battleWon"); + } + else + { + selectWidget("retry", "battleLost"); + } + } + } +} + +static void draw(void) +{ + prepareScene(); + + drawBackground(battle.background); + + drawStars(); + + blit(battle.planetTexture, battle.planet.x, battle.planet.y, 1); + + drawBullets(); + + drawFighters(); + + drawEffects(); + + drawHud(); + + drawMissionInfo(); + + switch (show) + { + case SHOW_MENU: + drawMenu(); + break; + + case SHOW_OPTIONS: + drawOptions(); + break; + } + + presentScene(); +} + +static void drawMenu(void) +{ + SDL_Rect r; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128); + SDL_RenderFillRect(app.renderer, NULL); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + r.w = 400; + r.h = 400; + r.x = (SCREEN_WIDTH / 2) - r.w / 2; + r.y = (SCREEN_HEIGHT / 2) - r.h / 2; + + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 0); + SDL_RenderFillRect(app.renderer, &r); + SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255); + SDL_RenderDrawRect(app.renderer, &r); + + drawWidgets("inBattle"); +} + +static void handleKeyboard(void) +{ + if (app.keyboard[SDL_SCANCODE_ESCAPE]) + { + switch (show) + { + case SHOW_BATTLE: + case SHOW_OPTIONS: + selectWidget("resume", "inBattle"); + show = SHOW_MENU; + break; + + case SHOW_MENU: + show = SHOW_BATTLE; + break; + + case SHOW_OBJECTIVES: + show = SHOW_BATTLE; + break; + } + + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + playSound(SND_GUI_CLOSE); + } + + if (app.keyboard[SDL_SCANCODE_TAB]) + { + battle.status = MS_PAUSED; + } +} + +static void start(void) +{ + battle.status = MS_IN_PROGRESS; +} + +static void resume(void) +{ + show = SHOW_BATTLE; + + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); +} + +static void continueGame(void) +{ + postBattle(); + + destroyBattle(); + + resetHud(); + + initGalacticMap(); +} + +static void options(void) +{ + show = SHOW_OPTIONS; + + initOptions(returnFromOptions); +} + +static void returnFromOptions(void) +{ + show = SHOW_MENU; + + selectWidget("resume", "inBattle"); +} + +static void retry(void) +{ + postBattle(); + + destroyBattle(); + + resetHud(); + + initBattle(); + + loadMission(game.currentMission->filename); +} + +static void quitBattle(void) +{ + postBattle(); + + destroyBattle(); + + resetHud(); + + initGalacticMap(); +} + +static void postBattle(void) +{ + game.stats.shotsFired += battle.stats.shotsFired; + game.stats.shotsHit += battle.stats.shotsHit; + game.stats.missilesFired += battle.stats.missilesFired; + game.stats.missilesHit += battle.stats.missilesHit; + game.stats.enemiesKilled += battle.stats.enemiesKilled; + game.stats.alliesKilled += battle.stats.alliesKilled; + game.stats.playerKilled += battle.stats.playerKilled; + game.stats.playerKills += battle.stats.playerKills; + game.stats.time += battle.stats.time; + + if (game.currentMission && !game.currentMission->completed) + { + game.currentMission->completed = (battle.status == MS_COMPLETE || !battle.numObjectivesTotal); + } + +} + +void destroyBattle(void) +{ + Fighter *f; + Bullet *b; + Effect *e; + Objective *o; + + while (battle.fighterHead.next) + { + f = battle.fighterHead.next; + battle.fighterHead.next = f->next; + free(f); + } + battle.fighterTail = &battle.fighterHead; + + while (battle.bulletHead.next) + { + b = battle.bulletHead.next; + battle.bulletHead.next = b->next; + free(b); + } + battle.bulletTail = &battle.bulletHead; + + while (battle.effectHead.next) + { + e = battle.effectHead.next; + battle.effectHead.next = e->next; + free(e); + } + battle.effectTail = &battle.effectHead; + + while (battle.objectiveHead.next) + { + o = battle.objectiveHead.next; + battle.objectiveHead.next = o->next; + free(o); + } + battle.objectiveTail = &battle.objectiveHead; +} diff --git a/src/battle/battle.h b/src/battle/battle.h new file mode 100644 index 0000000..200f220 --- /dev/null +++ b/src/battle/battle.h @@ -0,0 +1,69 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +#define SHOW_BATTLE 0 +#define SHOW_MENU 1 +#define SHOW_OBJECTIVES 2 +#define SHOW_OPTIONS 3 + +extern void prepareScene(void); +extern void presentScene(void); +extern void doBullets(void); +extern void drawBullets(void); +extern void doStars(float dx, float dy); +extern void drawStars(void); +extern void doFighters(void); +extern void drawFighters(void); +extern void initStars(void); +extern void doPlayer(void); +extern void drawHud(void); +extern void drawEffects(void); +extern void doEffects(void); +extern void doObjectives(void); +extern void blit(SDL_Texture *texture, int x, int y, int centered); +extern void initHud(void); +extern void initGalacticMap(void); +extern void drawWidgets(char *groupName); +extern void selectWidget(const char *name, const char *group); +extern Widget *getWidget(const char *name, const char *group); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern void doWidgets(void); +extern void loadMission(char *filename); +extern void resetHud(void); +extern void doHud(void); +extern void initMissionInfo(void); +extern void drawMissionInfo(void); +extern void drawBackground(SDL_Texture *texture); +extern void initBackground(void); +extern void scrollBackground(float x, float y); +extern void initOptions(void (*returnFromOptions)(void)); +extern void drawOptions(void); +extern void playSound(int id); + +extern App app; +extern Battle battle; +extern Colors colors; +extern Fighter *player; +extern Game game; diff --git a/src/battle/bullets.c b/src/battle/bullets.c new file mode 100644 index 0000000..4528051 --- /dev/null +++ b/src/battle/bullets.c @@ -0,0 +1,271 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "bullets.h" + +static void huntTarget(Bullet *b); +static void checkCollisions(Bullet *b); + +static Bullet bulletDef[BT_MAX]; + +void initBulletDefs(void) +{ + cJSON *root, *node; + char *text; + int type; + Bullet *def; + + memset(&bulletDef, 0, sizeof(Bullet) * BT_MAX); + + text = readFile("data/battle/bullets.json"); + + root = cJSON_Parse(text); + + for (node = root->child ; node != NULL ; node = node->next) + { + type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); + + def = &bulletDef[type]; + def->type = type; + def->damage = cJSON_GetObjectItem(node, "damage")->valueint; + def->texture = getTexture(cJSON_GetObjectItem(node, "textureName")->valuestring); + def->sound = lookup(cJSON_GetObjectItem(node, "sound")->valuestring); + def->flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring); + } + + cJSON_Delete(root); + free(text); +} + +void doBullets(void) +{ + Bullet *b; + Bullet *prev = &battle.bulletHead; + + for (b = battle.bulletHead.next ; b != NULL ; b = b->next) + { + b->x += b->dx; + b->y += b->dy; + + b->x -= battle.ssx; + b->y -= battle.ssy; + + if (b->type == BT_MISSILE) + { + addMissileEngineEffect(b); + + huntTarget(b); + } + + checkCollisions(b); + + if (--b->life <= 0) + { + if (b == battle.bulletTail) + { + battle.bulletTail = prev; + } + + prev->next = b->next; + free(b); + b = prev; + } + + prev = b; + } +} + +static void checkCollisions(Bullet *b) +{ + Fighter *f; + int bw, bh, ew, eh; + + SDL_QueryTexture(b->texture, NULL, NULL, &bw, &bh); + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + SDL_QueryTexture(f->texture, NULL, NULL, &ew, &eh); + + if (b->owner != f && f->health > 0 && collision(b->x - bw / 2, b->y - bh / 2, bw, bh, f->x - ew / 2, f->y - eh / 2, ew, eh)) + { + if (b->owner->side == f->side) + { + b->damage = 0; + } + else if (b->owner == player) + { + battle.stats.shotsHit++; + } + + damageFighter(f, b->damage); + b->life = 0; + + /* assuming that health <= 0 will always mean killed */ + if (f->health <= 0 && b->owner == player) + { + battle.stats.playerKills++; + } + + return; + } + } +} + +void drawBullets(void) +{ + Bullet *b; + + for (b = battle.bulletHead.next ; b != NULL ; b = b->next) + { + blitRotated(b->texture, b->x, b->y, b->angle); + } +} + +static void faceTarget(Bullet *b) +{ + int dir; + int wantedAngle = getAngle(b->x, b->y, b->target->x, b->target->y); + + wantedAngle %= 360; + + if (fabs(wantedAngle - b->angle) > TURN_THRESHOLD) + { + dir = (wantedAngle - b->angle + 360) % 360 > 180 ? -1 : 1; + + b->angle += dir * TURN_SPEED; + + b->angle = mod(b->angle, 360); + + b->dx *= 0.35; + b->dy *= 0.35; + } + else + { + b->angle = wantedAngle; + } +} + +static void applyMissileThrust(Bullet *b) +{ + int maxSpeed; + float v, thrust; + + b->dx += sin(TO_RAIDANS(b->angle)) * 0.5; + b->dy += -cos(TO_RAIDANS(b->angle)) * 0.5; + + maxSpeed = MAX(MIN(b->target->speed + 1, 999), 3); + + thrust = sqrt((b->dx * b->dx) + (b->dy * b->dy)); + + if (thrust > maxSpeed) + { + v = (maxSpeed / sqrt(thrust)); + b->dx = v * b->dx; + b->dy = v * b->dy; + } +} + +static void huntTarget(Bullet *b) +{ + if (b->target != NULL && b->target->health > 0) + { + faceTarget(b); + + applyMissileThrust(b); + } + else + { + b->target = b->owner->target; + } +} + +Bullet *createBullet(int type, int x, int y, Fighter *owner) +{ + Bullet *b; + + b = malloc(sizeof(Bullet)); + memset(b, 0, sizeof(Bullet)); + battle.bulletTail->next = b; + battle.bulletTail = b; + + memcpy(b, &bulletDef[type], sizeof(Bullet)); + + b->next = NULL; + + b->x = x; + b->y = y; + b->dx += sin(TO_RAIDANS(owner->angle)) * 16; + b->dy += -cos(TO_RAIDANS(owner->angle)) * 16; + b->life = FPS * 2; + b->angle = owner->angle; + b->owner = owner; + b->target = owner->target; + + return b; +} + +void fireGuns(Fighter *owner) +{ + Bullet *b; + int i; + float x, y; + float c, s; + + for (i = 0 ; i < MAX_FIGHTER_GUNS ; i++) + { + if (owner->guns[i].type) + { + s = sin(TO_RAIDANS(owner->angle)); + c = cos(TO_RAIDANS(owner->angle)); + + x = (owner->guns[i].x * c) - (owner->guns[i].y * s); + y = (owner->guns[i].x * s) + (owner->guns[i].y * c); + + x += owner->x; + y += owner->y; + + b = createBullet(owner->guns[i].type, x, y, owner); + + if (owner == player) + { + battle.stats.shotsFired++; + } + } + } + + owner->reload = owner->reloadTime; + + playBattleSound(b->sound, owner->x, owner->y); +} + +void fireMissile(Fighter *owner) +{ + Bullet *b; + + b = createBullet(BT_ROCKET + owner->missiles.type, owner->x, owner->y, owner); + + b->life = FPS * 30; + + owner->missiles.ammo--; +} + +void destroyBulletDefs(void) +{ +} diff --git a/src/battle/bullets.h b/src/battle/bullets.h new file mode 100644 index 0000000..7b10524 --- /dev/null +++ b/src/battle/bullets.h @@ -0,0 +1,43 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" +#include "../json/cJSON.h" + +#define TURN_SPEED 2 +#define TURN_THRESHOLD 8 + +extern SDL_Texture *getTexture(char *filename); +extern void blitRotated(SDL_Texture *texture, int x, int y, int angle); +extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); +extern void damageFighter(Fighter *f, int damage); +extern void playBattleSound(int id, int x, int y); +extern long flagsToLong(char *flags); +extern long lookup(char *name); +extern char *readFile(char *filename); +extern float getAngle(int x1, int y1, int x2, int y2); +extern void addMissileEngineEffect(Bullet *b); +extern int mod(int n, int x); + +extern Battle battle; +extern Fighter *player; diff --git a/src/battle/challenges.c b/src/battle/challenges.c new file mode 100644 index 0000000..1ce0055 --- /dev/null +++ b/src/battle/challenges.c @@ -0,0 +1,162 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "challenges.h" + +static void updateTimeChallenge(Challenge *c); +static void updateAccuracyChallenge(Challenge *c); +static void updateArmourChallenge(Challenge *c); +static void updateLossesChallenge(Challenge *c); +static void updatePlayerKillsChallenge(Challenge *c); +static char *getFormattedChallengeDescription(const char *format, ...); +char *getChallengeDescription(Challenge *c); + +static char descriptionBuffer[MAX_DESCRIPTION_LENGTH]; + +static char *challengeDescription[] = { + "Retain at least %d%% armour", + "Finish mission in %d seconds or less", + "Attain a %d%% hit accuracy", + "Do not lose any team mates", + "Do not lose more than 1 team mate", + "Do not lose more than %d team mates", + "Take down %d enemy targets" +}; + +void updateChallenges(void) +{ + Challenge *c; + + for (c = game.currentMission->challengeHead.next ; c != NULL ; c = c->next) + { + if (!c->passed) + { + switch (c->type) + { + case CHALLENGE_TIME: + updateTimeChallenge(c); + break; + + case CHALLENGE_ACCURACY: + updateAccuracyChallenge(c); + break; + + case CHALLENGE_ARMOUR: + updateArmourChallenge(c); + break; + + case CHALLENGE_NO_LOSSES: + case CHALLENGE_1_LOSS: + case CHALLENGE_LOSSES: + updateLossesChallenge(c); + break; + + case CHALLENGE_PLAYER_KILLS: + updatePlayerKillsChallenge(c); + break; + } + } + } +} + +static void updateTimeChallenge(Challenge *c) +{ + if (battle.stats.time / FPS <= c->targetValue) + { + c->passed = 1; + } +} + +static void updateAccuracyChallenge(Challenge *c) +{ + float percent; + + percent = battle.stats.shotsHit; + percent /= battle.stats.shotsFired; + percent *= 100; + + if (percent >= c->targetValue) + { + c->passed = 1; + } +} + +static void updateArmourChallenge(Challenge *c) +{ + float percent; + + percent = player->health; + percent /= player->maxHealth; + percent *= 100; + + if (percent >= c->targetValue) + { + c->passed = 1; + } +} + +static void updateLossesChallenge(Challenge *c) +{ + if (!c->passed) + { + c->passed = battle.stats.alliesKilled <= c->targetValue; + } +} + +static void updatePlayerKillsChallenge(Challenge *c) +{ + if (!c->passed) + { + c->passed = battle.stats.playerKills >= c->targetValue; + } +} + +char *getChallengeDescription(Challenge *c) +{ + return getFormattedChallengeDescription(challengeDescription[c->type], c->targetValue); +} + +Challenge *getChallenge(Mission *mission, int type) +{ + Challenge *challenge; + + for (challenge = mission->challengeHead.next ; challenge != NULL ; challenge = challenge->next) + { + if (challenge->type == type) + { + return challenge; + } + } + + return NULL; +} + +static char *getFormattedChallengeDescription(const char *format, ...) +{ + va_list args; + + memset(&descriptionBuffer, '\0', sizeof(descriptionBuffer)); + + va_start(args, format); + vsprintf(descriptionBuffer, format, args); + va_end(args); + + return descriptionBuffer; +} diff --git a/src/battle/challenges.h b/src/battle/challenges.h new file mode 100644 index 0000000..d30318c --- /dev/null +++ b/src/battle/challenges.h @@ -0,0 +1,28 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern Battle battle; +extern Fighter *player; +extern Game game; diff --git a/src/battle/effects.c b/src/battle/effects.c new file mode 100644 index 0000000..b3f2015 --- /dev/null +++ b/src/battle/effects.c @@ -0,0 +1,256 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "effects.h" + +static void setRandomFlameHue(Effect *e); + +void doEffects(void) +{ + Effect *e; + Effect *prev = &battle.effectHead; + + for (e = battle.effectHead.next ; e != NULL ; e = e->next) + { + e->x += e->dx; + e->y += e->dy; + + e->x -= battle.ssx; + e->y -= battle.ssy; + + e->health--; + + if (e->health <= 0) + { + if (--e->a <= 0) + { + if (e == battle.effectTail) + { + battle.effectTail = prev; + } + + prev->next = e->next; + free(e); + e = prev; + } + } + + prev = e; + } +} + +void drawEffects(void) +{ + Effect *e; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + + for (e = battle.effectHead.next ; e != NULL ; e = e->next) + { + SDL_SetRenderDrawColor(app.renderer, e->r, e->g, e->b, e->a); + + SDL_SetTextureBlendMode(e->texture, SDL_BLENDMODE_ADD); + SDL_SetTextureAlphaMod(e->texture, e->a); + + switch (e->type) + { + case EFFECT_LINE: + SDL_RenderDrawLine(app.renderer, e->x, e->y, e->x + (e->dx * 3), e->y + (e->dy * 3)); + break; + + case EFFECT_TEXTURE: + SDL_SetTextureColorMod(e->texture, e->r, e->g, e->b); + blitScaled(e->texture, e->x, e->y, e->size, e->size); + break; + + case EFFECT_HALO: + break; + } + } + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); +} + +void addSmallFighterExplosion(void) +{ + Effect *e; + SDL_Texture *t = getTexture("gfx/battle/explosion.png"); + + e = malloc(sizeof(Effect)); + memset(e, 0, sizeof(Effect)); + battle.effectTail->next = e; + battle.effectTail = e; + + e->type = EFFECT_TEXTURE; + + e->x = self->x + (rand() % 16 - rand() % 16); + e->y = self->y + (rand() % 16 - rand() % 16); + e->texture = t; + e->health = 0; + e->size = 32; + + setRandomFlameHue(e); + + e->a = 128 + (rand() % 128); + + e->x -= e->size / 2; + e->y -= e->size / 2; +} + +void addFighterExplosion(void) +{ + int i; + Effect *e; + SDL_Texture *t = getTexture("gfx/battle/explosion.png"); + + for (i = 0 ; i < 32 ; i++) + { + e = malloc(sizeof(Effect)); + memset(e, 0, sizeof(Effect)); + battle.effectTail->next = e; + battle.effectTail = e; + + e->type = EFFECT_TEXTURE; + + e->x = self->x; + e->y = self->y; + e->dx = (rand() % 25) - (rand() % 25); + e->dx *= 0.025; + e->dy = (rand() % 25) - (rand() % 25); + e->dy *= 0.025; + e->texture = t; + e->health = 0; + e->size = 32 + (rand() % 64); + e->r = 255; + + setRandomFlameHue(e); + + e->a = 128 + (rand() % 128); + + e->x -= e->size / 2; + e->y -= e->size / 2; + } + + for (i = 0 ; i < 96 ; i++) + { + e = malloc(sizeof(Effect)); + memset(e, 0, sizeof(Effect)); + battle.effectTail->next = e; + battle.effectTail = e; + + e->type = EFFECT_LINE; + e->x = self->x; + e->y = self->y; + e->dx = rand() % 64 - rand() % 64; + e->dx *= 0.1; + e->dy = rand() % 64 - rand() % 64; + e->dy *= 0.1; + e->health = FPS / 2; + + e->a = 128; + + setRandomFlameHue(e); + } +} + +static void setRandomFlameHue(Effect *e) +{ + e->r = 255; + + switch (rand() % 4) + { + case 0: + break; + + case 1: + e->g = 128; + break; + + case 2: + e->g = 255; + break; + + case 3: + e->g = e->b = 255; + break; + } +} + +void addEngineEffect(void) +{ + Effect *e; + + e = malloc(sizeof(Effect)); + memset(e, 0, sizeof(Effect)); + battle.effectTail->next = e; + battle.effectTail = e; + + e->type = EFFECT_TEXTURE; + + e->x = self->x; + e->y = self->y; + + e->x -= sin(TO_RAIDANS(self->angle)) * 16; + e->y -= -cos(TO_RAIDANS(self->angle)) * 16; + + e->x += rand() % 4; + e->x -= rand() % 4; + + e->texture = getTexture("gfx/battle/explosion.png"); + e->health = 0; + e->size = 16; + e->r = 128; + e->g = 128; + e->b = 255; + e->a = 64; + + e->x -= e->size / 2; + e->y -= e->size / 2; +} + +void addMissileEngineEffect(Bullet *b) +{ + Effect *e; + + e = malloc(sizeof(Effect)); + memset(e, 0, sizeof(Effect)); + battle.effectTail->next = e; + battle.effectTail = e; + + e->type = EFFECT_TEXTURE; + + e->x = b->x; + e->y = b->y; + + e->x -= sin(TO_RAIDANS(b->angle)) * 10; + e->y -= -cos(TO_RAIDANS(b->angle)) * 10; + + e->x += rand() % 4; + e->x -= rand() % 4; + + e->texture = getTexture("gfx/battle/explosion.png"); + e->health = 0; + e->size = 12; + setRandomFlameHue(e); + e->a = 128; + + e->x -= e->size / 2; + e->y -= e->size / 2; +} diff --git a/src/battle/effects.h b/src/battle/effects.h new file mode 100644 index 0000000..e2d738c --- /dev/null +++ b/src/battle/effects.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void blitScaled(SDL_Texture *texture, int x, int y, int w, int h); +extern SDL_Texture *getTexture(char *name); + +extern App app; +extern Battle battle; +extern Fighter *self; diff --git a/src/battle/fighterDefs.c b/src/battle/fighterDefs.c new file mode 100644 index 0000000..7bd8402 --- /dev/null +++ b/src/battle/fighterDefs.c @@ -0,0 +1,135 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "fighterDefs.h" + +static void loadFighterDef(char *filename); + +static Fighter defHead, *defTail; + +Fighter *getFighterDef(char *name) +{ + Fighter *f; + + for (f = defHead.next ; f != NULL ; f = f->next) + { + if (strcmp(f->name, name) == 0) + { + return f; + } + } + + printf("Error: no such fighter '%s'\n", name); + exit(1); +} + +void loadFighterDefs(void) +{ + cJSON *root, *node; + char *text; + + text = readFile("data/fighters/list.json"); + root = cJSON_Parse(text); + + memset(&defHead, 0, sizeof(Fighter)); + defTail = &defHead; + + for (node = root->child ; node != NULL ; node = node->next) + { + loadFighterDef(node->valuestring); + } + + cJSON_Delete(root); + free(text); +} + +static void loadFighterDef(char *filename) +{ + cJSON *root, *node; + char *text; + Fighter *f; + int i, w, h; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", filename); + + text = readFile(filename); + + f = malloc(sizeof(Fighter)); + memset(f, 0, sizeof(Fighter)); + defTail->next = f; + defTail = f; + + root = cJSON_Parse(text); + + STRNCPY(f->name, cJSON_GetObjectItem(root, "name")->valuestring, MAX_NAME_LENGTH); + f->health = f->maxHealth = cJSON_GetObjectItem(root, "health")->valueint; + f->shield = f->maxShield = cJSON_GetObjectItem(root, "shield")->valueint; + f->speed = cJSON_GetObjectItem(root, "speed")->valueint; + f->reloadTime = cJSON_GetObjectItem(root, "reloadTime")->valueint; + f->shieldRechargeRate = cJSON_GetObjectItem(root, "shieldRechargeRate")->valueint; + f->texture = getTexture(cJSON_GetObjectItem(root, "textureName")->valuestring); + + if (cJSON_GetObjectItem(root, "guns")) + { + i = 0; + + for (node = cJSON_GetObjectItem(root, "guns")->child ; node != NULL ; node = node->next) + { + f->guns[i].type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); + f->guns[i].x = cJSON_GetObjectItem(node, "x")->valueint; + f->guns[i].y = cJSON_GetObjectItem(node, "y")->valueint; + + i++; + + if (i >= MAX_FIGHTER_GUNS) + { + printf("ERROR: cannot assign more than %d guns to a fighter\n", MAX_FIGHTER_GUNS); + exit(1); + } + } + } + + if (cJSON_GetObjectItem(root, "missiles")) + { + node = cJSON_GetObjectItem(root, "missiles"); + + f->missiles.type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); + f->missiles.ammo = f->missiles.maxAmmo = cJSON_GetObjectItem(node, "ammo")->valueint; + } + + SDL_QueryTexture(f->texture, NULL, NULL, &w, &h); + f->separationRadius = MAX(w, h); + f->separationRadius *= 2; + + cJSON_Delete(root); + free(text); +} + +void destroyFighterDefs(void) +{ + Fighter *f; + + while (defHead.next) + { + f = defHead.next; + defHead.next = f->next; + free(f); + } +} diff --git a/src/battle/fighterDefs.h b/src/battle/fighterDefs.h new file mode 100644 index 0000000..57d2506 --- /dev/null +++ b/src/battle/fighterDefs.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" +#include "../json/cJSON.h" + +extern char *readFile(char *filename); +extern SDL_Texture *getTexture(char *filename); +extern long lookup(char *name); + diff --git a/src/battle/fighters.c b/src/battle/fighters.c new file mode 100644 index 0000000..ac470f6 --- /dev/null +++ b/src/battle/fighters.c @@ -0,0 +1,478 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "fighters.h" + +static void separate(void); +static void die(void); +static void immediateDie(void); +static void spinDie(void); +static void straightDie(void); +static void randomizeDart(Fighter *dart); +static void randomizeDartGuns(Fighter *dart); + +Fighter *spawnFighter(char *name, int x, int y, int side) +{ + Fighter *f, *def; + + f = malloc(sizeof(Fighter)); + memset(f, 0, sizeof(Fighter)); + + def = getFighterDef(name); + + memcpy(f, def, sizeof(Fighter)); + + f->next = NULL; + + battle.fighterTail->next = f; + battle.fighterTail = f; + + f->x = x; + f->y = y; + f->side = side; + + switch (side) + { + case SIDE_ALLIES: + f->aggression = 1 + rand() % 3; + break; + + case SIDE_PIRATE: + f->aggression = rand() % 3; + break; + + case SIDE_PANDORAN: + f->aggression = 3 + rand() % 2; + break; + } + + if (strcmp(name, "ATAF") == 0) + { + f->aggression = 4; + } + + if (strcmp(name, "Dart") == 0) + { + randomizeDart(f); + } + + f->defaultAction = doAI; + f->die = die; + + return f; +} + +static void randomizeDart(Fighter *dart) +{ + char textureName[MAX_DESCRIPTION_LENGTH]; + + if (rand() % 5 == 0) + { + dart->health = dart->maxHealth = 5 + (rand() % 21); + } + + if (rand() % 5 == 0) + { + dart->shield = dart->maxShield = 1 + (rand() % 16); + dart->shieldRechargeRate = 30 + (rand() % 90); + } + + if (rand() % 5 == 0) + { + dart->speed = 2 + (rand() % 3); + } + + if (rand() % 5 == 0) + { + dart->reloadTime = 24 + (rand() % 11); + } + + randomizeDartGuns(dart); + + sprintf(textureName, "gfx/fighters/dart0%d.png", 1 + rand() % 7); + + dart->texture = getTexture(textureName); +} + +static void randomizeDartGuns(Fighter *dart) +{ + int i; + + switch (rand() % 4) + { + /* Single plasma gun */ + case 0: + dart->guns[0].type = BT_PLASMA; + dart->guns[0].x = dart->guns[0].y = 0; + + for (i = 1 ; i < MAX_FIGHTER_GUNS ; i++) + { + if (dart->guns[i].type) + { + dart->guns[i].type = BT_NONE; + } + } + break; + + /* Dual plasma guns */ + case 1: + dart->guns[0].type = BT_PLASMA; + dart->guns[1].type = BT_PLASMA; + + for (i = 2 ; i < MAX_FIGHTER_GUNS ; i++) + { + if (dart->guns[i].type) + { + dart->guns[i].type = BT_NONE; + } + } + break; + + /* Triple particle guns */ + case 2: + dart->guns[2].type = BT_PARTICLE; + dart->guns[2].y = -10; + break; + } +} + +void doFighters(void) +{ + Fighter *f, *prev; + + battle.numAllies = battle.numEnemies = 0; + + prev = &battle.fighterHead; + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + self = f; + + if (player != NULL) + { + if (f != player && f->health > 0) + { + separate(); + } + + if (f->side == player->side) + { + battle.numAllies++; + } + else + { + battle.numEnemies++; + } + } + + if (self->target != NULL && self->target->health <= 0) + { + self->action = self->defaultAction; + self->target = NULL; + } + + f->x += f->dx; + f->y += f->dy; + + if (f != player) + { + f->x -= battle.ssx; + f->y -= battle.ssy; + } + + if (f->health > 0) + { + f->reload = MAX(f->reload - 1, 0); + f->shieldRecharge = MAX(f->shieldRecharge - 1, 0); + f->armourHit = MAX(f->armourHit - 25, 0); + f->shieldHit = MAX(f->shieldHit - 5, 0); + + if (self->thrust > 0.25) + { + addEngineEffect(); + } + + if (!f->shieldRecharge) + { + f->shield = MIN(f->shield + 1, f->maxShield); + f->shieldRecharge = f->shieldRechargeRate; + } + + if (f->action == NULL && f->defaultAction != NULL) + { + f->action = f->defaultAction; + } + } + + if (f->action != NULL) + { + if (--f->thinkTime <= 0) + { + f->thinkTime = 0; + f->action(); + } + } + + if (f->health <= 0 && f->alive == ALIVE_ALIVE) + { + f->health = 0; + f->alive = ALIVE_DYING; + f->die(); + } + + if (f->alive == ALIVE_DEAD) + { + if (f == player) + { + battle.stats.playerKilled++; + } + else if (player != NULL) + { + if (player->alive == ALIVE_ALIVE) + { + if (f->side != player->side) + { + battle.stats.enemiesKilled++; + } + else + { + battle.stats.alliesKilled++; + + addHudMessage(colors.red, "Ally has been killed"); + } + } + + updateObjective(f->name); + } + + if (f == battle.fighterTail) + { + battle.fighterTail = prev; + } + + if (f == player) + { + player = NULL; + } + + prev->next = f->next; + free(f); + f = prev; + } + + prev = f; + } +} + +static void separate(void) +{ + int angle; + int distance; + float dx, dy, force; + int count; + Fighter *f; + + dx = dy = 0; + count = 0; + force = 0; + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + if (f != self) + { + distance = getDistance(f->x, f->y, self->x, self->y); + + if (distance > 0 && distance < self->separationRadius) + { + angle = getAngle(self->x, self->y, f->x, f->y); + + dx += sin(TO_RAIDANS(angle)); + dy += -cos(TO_RAIDANS(angle)); + force += (self->separationRadius - distance) * 0.005; + + count++; + } + } + } + + if (count > 0) + { + dx /= count; + dy /= count; + + dx *= force; + dy *= force; + + self->dx -= dx; + self->dy -= dy; + } +} + +void drawFighters(void) +{ + Fighter *f; + SDL_Rect r; + SDL_Texture *shieldHitTexture = getTexture("gfx/battle/shieldHit.png"); + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + SDL_SetTextureColorMod(f->texture, 255, 255, 255); + + if (f->armourHit > 0) + { + SDL_SetTextureColorMod(f->texture, 255, 255 - f->armourHit, 255 - f->armourHit); + } + + blitRotated(f->texture, f->x, f->y, f->angle); + + if (f->shieldHit > 0) + { + SDL_SetTextureBlendMode(shieldHitTexture, SDL_BLENDMODE_BLEND); + SDL_SetTextureAlphaMod(shieldHitTexture, f->shieldHit); + blit(shieldHitTexture, f->x, f->y, 1); + } + + if (player != NULL && f == player->target) + { + r.x = f->x - 32; + r.y = f->y - 32; + r.w = 64; + r.h = 64; + + SDL_SetRenderDrawColor(app.renderer, 255, 64, 0, 255); + SDL_RenderDrawRect(app.renderer, &r); + } + } +} + +void applyFighterThrust(void) +{ + float v; + + self->dx += sin(TO_RAIDANS(self->angle)) * 0.1; + self->dy += -cos(TO_RAIDANS(self->angle)) * 0.1; + self->thrust = sqrt((self->dx * self->dx) + (self->dy * self->dy)); + + if (self->thrust > self->speed * self->speed) + { + v = (self->speed / sqrt(self->thrust)); + self->dx = v * self->dx; + self->dy = v * self->dy; + } +} + +void applyFighterBrakes(void) +{ + self->dx *= 0.95; + self->dy *= 0.95; + + self->thrust = sqrt((self->dx * self->dx) + (self->dy * self->dy)); +} + +void damageFighter(Fighter *f, int damage) +{ + f->shield -= damage; + + if (f->shield < 0) + { + f->health -= abs(f->shield); + f->shield = 0; + f->armourHit = 255; + + playBattleSound(SND_ARMOUR_HIT, f->x, f->y); + } + else if (f->shield > 0) + { + f->shieldHit = 255; + } +} + +static void die(void) +{ + int n = rand() % 3; + if (self == player) + { + n = rand() % 2; + } + + switch (n) + { + case 0: + self->action = straightDie; + break; + + case 1: + self->action = spinDie; + break; + + case 2: + self->action = immediateDie; + break; + } +} + +static void immediateDie(void) +{ + self->alive = ALIVE_DEAD; + addFighterExplosion(); + playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y); +} + +static void spinDie(void) +{ + self->health--; + self->thinkTime = 0; + self->armourHit = 0; + self->shieldHit = 0; + + self->angle += 8; + + if (rand() % 2 == 0) + { + addSmallFighterExplosion(); + } + + if (self->health <= -FPS) + { + self->alive = ALIVE_DEAD; + addFighterExplosion(); + playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y); + } +} + +static void straightDie(void) +{ + self->health--; + self->thinkTime = 0; + self->armourHit = 0; + self->shieldHit = 0; + + if (rand() % 2 == 0) + { + addSmallFighterExplosion(); + } + + if (self->health <= -FPS) + { + self->alive = ALIVE_DEAD; + addFighterExplosion(); + playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y); + } +} diff --git a/src/battle/fighters.h b/src/battle/fighters.h new file mode 100644 index 0000000..594d838 --- /dev/null +++ b/src/battle/fighters.h @@ -0,0 +1,44 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern SDL_Texture *getTexture(char *filename); +extern void doAI(void); +extern void blitRotated(SDL_Texture *t, int x, int y, int angle); +extern void blit(SDL_Texture *t, int x, int y, int center); +extern float getAngle(int x1, int y1, int x2, int y2); +extern int getDistance(int x1, int y1, int x2, int y2); +extern void addEngineEffect(void); +extern void addFighterExplosion(void); +extern void addSmallFighterExplosion(void); +extern void playBattleSound(int id, int x, int y); +extern void updateObjective(char *name); +extern Fighter *getFighterDef(char *name); +extern void addHudMessage(SDL_Color c, char *format, ...); + +extern App app; +extern Battle battle; +extern Colors colors; +extern Fighter *player; +extern Fighter *self; diff --git a/src/battle/hud.c b/src/battle/hud.c new file mode 100644 index 0000000..2abfd25 --- /dev/null +++ b/src/battle/hud.c @@ -0,0 +1,312 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "hud.h" + +static void drawHealthShieldBar(int current, int max, int x, int y, int r, int g, int b); +static void drawPlayerTargeter(void); +static void drawNumAllies(void); +static void drawNumEnemies(void); +static void drawHealthBars(void); +static void drawMissileAmmoBar(void); +static void drawObjectives(void); +static void drawTargetDistance(void); +static void drawHudMessages(void); + +static HudMessage hudMessageHead; +static HudMessage *hudMessageTail; + +static int healthWarning; + +void initHud(void) +{ + healthWarning = 0; + + memset(&hudMessageHead, 0, sizeof(HudMessage)); + hudMessageTail = &hudMessageHead; +} + +void doHud(void) +{ + HudMessage *hudMessage, *prev; + + healthWarning++; + healthWarning %= FPS; + + prev = &hudMessageHead; + + for (hudMessage = hudMessageHead.next ; hudMessage != NULL ; hudMessage = hudMessage->next) + { + hudMessage->life--; + + if (hudMessage->life <= 0) + { + if (hudMessage == hudMessageTail) + { + hudMessageTail = prev; + } + + prev->next = hudMessage->next; + free(hudMessage); + hudMessage = prev; + } + + prev = hudMessage; + } +} + +void addHudMessage(SDL_Color c, char *format, ...) +{ + va_list args; + + HudMessage *hudMessage = malloc(sizeof(HudMessage)); + memset(hudMessage, 0, sizeof(HudMessage)); + hudMessageTail->next = hudMessage; + hudMessageTail = hudMessage; + + va_start(args, format); + vsprintf(hudMessageTail->message, format, args); + va_end(args); + + hudMessage->color = c; + hudMessage->life = FPS * 5; +} + +void drawHud(void) +{ + if (player != NULL) + { + drawHealthBars(); + + drawMissileAmmoBar(); + + drawNumAllies(); + + drawNumEnemies(); + + drawObjectives(); + + drawRadar(); + } + + drawHudMessages(); +} + +static void drawHealthBars(void) +{ + float p; + int r, g, b; + + drawPlayerTargeter(); + + r = g = b = 0; + p = player->health; + p /= player->maxHealth; + + if (p <= 0.25) + { + r = 255; + } + else if (p <= 0.5) + { + r = 255; + g = 255; + } + else + { + g = 200; + } + + drawHealthShieldBar(player->health, player->maxHealth, 10, 10, r, g, b); + drawHealthShieldBar(player->shield, player->maxShield, 10, 30, 0, 200, 255); + + if (player->target) + { + drawHealthShieldBar(player->target->health, player->target->maxHealth, SCREEN_WIDTH - 260, 10, 0, 200, 0); + drawHealthShieldBar(player->target->shield, player->target->maxShield, SCREEN_WIDTH - 260, 30, 0, 200, 255); + drawTargetDistance(); + } +} + +static void drawHealthShieldBar(int current, int max, int x, int y, int r, int g, int b) +{ + SDL_Rect rect; + float percent = 0; + + if (max > 0) + { + percent = current; + percent /= max; + } + + rect.x = x; + rect.y = y; + rect.w = 250; + rect.h = 12; + + SDL_SetRenderDrawColor(app.renderer, r / 2, g / 2, b / 2, 255); + SDL_RenderFillRect(app.renderer, &rect); + + SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(app.renderer, &rect); + + if (current > 0) + { + rect.x += 2; + rect.y += 2; + rect.w -= 4; + rect.h -= 4; + + rect.w *= percent; + + SDL_SetRenderDrawColor(app.renderer, r, g, b, 255); + SDL_RenderFillRect(app.renderer, &rect); + } +} + +static void drawMissileAmmoBar(void) +{ + int w; + float i, percent, step; + SDL_Rect rect; + + rect.x = 10; + rect.y = 50; + rect.w = 250; + rect.h = 12; + + SDL_SetRenderDrawColor(app.renderer, 128, 64, 32, 255); + SDL_RenderFillRect(app.renderer, &rect); + + SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(app.renderer, &rect); + + rect.x += 2; + rect.y += 2; + rect.w -= 4; + rect.h -= 4; + + percent = player->missiles.ammo; + percent /= player->missiles.maxAmmo; + + step = rect.w; + step /= player->missiles.maxAmmo; + + w = rect.w; + + rect.w *= percent; + + SDL_SetRenderDrawColor(app.renderer, 255, 128, 0, 255); + SDL_RenderFillRect(app.renderer, &rect); + + for (i = step ; i < w ; i += step) + { + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 0); + SDL_RenderDrawLine(app.renderer, rect.x + i, rect.y, rect.x + i, rect.y + rect.h); + } +} + +static void drawPlayerTargeter(void) +{ + float angle; + int x, y; + + if (player->target) + { + angle = getAngle(player->x, player->y, player->target->x, player->target->y); + x = player->x; + y = player->y; + + x += sin(TO_RAIDANS(angle)) * 44; + y += -cos(TO_RAIDANS(angle)) * 44; + + blitRotated(getTexture("gfx/hud/targetPointer.png"), x, y, angle); + + blitRotated(getTexture("gfx/hud/targetCircle.png"), player->x, player->y, angle); + } +} + +static void drawNumAllies(void) +{ + SDL_Texture *t = getTexture("gfx/hud/smallFighter.png"); + + SDL_SetTextureColorMod(t, 150, 200, 255); + + blit(t, 400, 15, 0); + + drawText(435, 11, 14, TA_CENTER, colors.white, "(%d)", battle.numAllies); +} + +static void drawNumEnemies(void) +{ + SDL_Texture *t = getTexture("gfx/hud/smallFighter.png"); + + SDL_SetTextureColorMod(t, 255, 100, 100); + + blit(t, SCREEN_WIDTH - 410, 15, 0); + + drawText(SCREEN_WIDTH - 430, 11, 14, TA_CENTER, colors.white, "(%d)", battle.numEnemies); +} + +static void drawObjectives(void) +{ + drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, "%d / %d", battle.numObjectivesComplete, battle.numObjectivesTotal); +} + +static void drawTargetDistance(void) +{ + float distance; + + if (player->target != NULL) + { + distance = getDistance(player->x, player->y, player->target->x, player->target->y); + distance /= 50; + + distance = (int)distance; + distance /= 10; + + drawText(SCREEN_WIDTH - 15, 50, 14, TA_RIGHT, colors.red, "Target: %.2fkm", distance); + } +} + +static void drawHudMessages(void) +{ + HudMessage *hudMessage; + int y = SCREEN_HEIGHT - 25; + + for (hudMessage = hudMessageHead.next ; hudMessage != NULL ; hudMessage = hudMessage->next) + { + drawText(10, y, 14, TA_LEFT, hudMessage->color, hudMessage->message); + + y -= 25; + } +} + +void resetHud(void) +{ + HudMessage *hudMessage; + + while (hudMessageHead.next) + { + hudMessage = hudMessageHead.next; + hudMessageHead.next = hudMessage->next; + free(hudMessage); + } +} diff --git a/src/battle/hud.h b/src/battle/hud.h new file mode 100644 index 0000000..993f2e8 --- /dev/null +++ b/src/battle/hud.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern SDL_Texture *getTexture(char *filename); +extern void blitRotated(SDL_Texture *texture, int x, int y, int angle); +extern void blit(SDL_Texture *texture, int x, int y, int center); +extern float getAngle(int x1, int y1, int x2, int y2); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern int getDistance(int x1, int y1, int x2, int y2); +extern void drawRadar(void); + +extern App app; +extern Battle battle; +extern Colors colors; +extern Fighter *player; diff --git a/src/battle/missionInfo.c b/src/battle/missionInfo.c new file mode 100644 index 0000000..664b3da --- /dev/null +++ b/src/battle/missionInfo.c @@ -0,0 +1,153 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "missionInfo.h" + +static void drawMissionSummary(SDL_Texture *title); + +static SDL_Texture *missionStartTexture; +static SDL_Texture *missionInProgressTexture; +static SDL_Texture *missionCompleteTexture; +static SDL_Texture *missionFailedTexture; +static const char *objectiveStatus[] = {"Incomplete", "Complete", "Failed", "Condition"}; + +void initMissionInfo(void) +{ + missionStartTexture = getTexture("gfx/battle/missionStart.png"); + missionInProgressTexture = getTexture("gfx/battle/missionInProgress.png"); + missionCompleteTexture = getTexture("gfx/battle/missionComplete.png"); + missionFailedTexture = getTexture("gfx/battle/missionFailed.png"); +} + +void drawMissionInfo(void) +{ + switch (battle.status) + { + case MS_START: + drawMissionSummary(missionStartTexture); + drawWidgets("startBattle"); + break; + + case MS_PAUSED: + drawMissionSummary(missionInProgressTexture); + drawWidgets("startBattle"); + break; + + case MS_COMPLETE: + case MS_FAILED: + if (battle.missionFinishedTimer <= -FPS) + { + drawMissionSummary(battle.status == MS_COMPLETE ? missionCompleteTexture : missionFailedTexture); + + if (battle.missionFinishedTimer <= -(FPS * 2)) + { + drawWidgets(battle.status == MS_COMPLETE ? "battleWon" : "battleLost"); + } + } + break; + } +} + +static void drawMissionSummary(SDL_Texture *header) +{ + Objective *o; + Challenge *c; + int y; + SDL_Color color; + char *challengeStatus; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128); + SDL_RenderFillRect(app.renderer, NULL); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + blit(header, SCREEN_WIDTH / 2, 150, 1); + + y = 215; + + drawText(SCREEN_WIDTH / 2, 215, 28, TA_CENTER, colors.white, "OBJECTIVES"); + + y += 10; + + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + { + y += 50; + + switch (o->status) + { + case OS_INCOMPLETE: + color = colors.white; + break; + + case OS_COMPLETE: + color = colors.green; + break; + + case OS_FAILED: + color = colors.red; + break; + } + + drawText(SCREEN_WIDTH / 2 - 100, y, 22, TA_RIGHT, colors.white, o->description); + drawText(SCREEN_WIDTH / 2, y, 22, TA_CENTER, colors.white, "%d / %d", o->currentValue, o->targetValue); + drawText(SCREEN_WIDTH / 2 + 100, y, 22, TA_LEFT, color, objectiveStatus[o->status]); + } + + if (!battle.objectiveHead.next) + { + y += 50; + + drawText(SCREEN_WIDTH / 2, y, 22, TA_CENTER, colors.white, "(none)"); + } + + if (game.currentMission && game.currentMission->challengeHead.next) + { + y += 100; + + drawText(SCREEN_WIDTH / 2, y, 28, TA_CENTER, colors.white, "CHALLENGES"); + + y += 10; + + for (c = game.currentMission->challengeHead.next ; c != NULL ; c = c->next) + { + y += 50; + + color = colors.white; + + challengeStatus = "Incomplete"; + + if (c->passed) + { + color = colors.green; + + challengeStatus = "Complete"; + } + else if (battle.status == MS_COMPLETE ||battle.status == MS_FAILED) + { + color = colors.red; + + challengeStatus = "Failed"; + } + + drawText(SCREEN_WIDTH / 2 - 25, y, 22, TA_RIGHT, colors.white, "%s", getChallengeDescription(c)); + drawText(SCREEN_WIDTH / 2 + 25, y, 22, TA_LEFT, color, challengeStatus); + } + } +} diff --git a/src/battle/missionInfo.h b/src/battle/missionInfo.h new file mode 100644 index 0000000..042ec34 --- /dev/null +++ b/src/battle/missionInfo.h @@ -0,0 +1,35 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void blit(SDL_Texture *texture, int x, int y, int center); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern SDL_Texture *getTexture(char *filename); +extern char *getChallengeDescription(Challenge *c); +extern void drawWidgets(char *groupName); + +extern App app; +extern Battle battle; +extern Colors colors; +extern Game game; diff --git a/src/battle/objectives.c b/src/battle/objectives.c new file mode 100644 index 0000000..b995505 --- /dev/null +++ b/src/battle/objectives.c @@ -0,0 +1,103 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "objectives.h" + +void failIncompleteObjectives(void); + +void doObjectives(void) +{ + Objective *o; + + battle.numObjectivesComplete = battle.numObjectivesTotal = 0; + + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + { + battle.numObjectivesTotal++; + + if (o->currentValue == o->targetValue) + { + battle.numObjectivesComplete++; + } + } + + if (battle.numObjectivesTotal > 0 && battle.numObjectivesComplete == battle.numObjectivesTotal && battle.status == MS_IN_PROGRESS) + { + battle.status = MS_COMPLETE; + battle.missionFinishedTimer = FPS; + + game.stats.missionsCompleted++; + + updateChallenges(); + } +} + +void updateObjective(char *name) +{ + Objective *o; + + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + { + if (strcmp(o->targetName, name) == 0) + { + o->currentValue = MIN(o->targetValue, o->currentValue + 1); + + if (o->targetValue - o->currentValue <= 10) + { + addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + } + else if (o->currentValue % 10 == 0) + { + addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + } + + if (o->currentValue == o->targetValue) + { + switch (o->status) + { + case OS_INCOMPLETE: + o->status = OS_COMPLETE; + addHudMessage(colors.green, "%s - Objective Complete!", o->description); + break; + + case OS_CONDITIONAL: + o->status = OS_FAILED; + battle.status = MS_FAILED; + battle.missionFinishedTimer = FPS; + failIncompleteObjectives(); + break; + } + } + } + } +} + +void failIncompleteObjectives(void) +{ + Objective *o; + + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + { + if (o->status != OS_COMPLETE) + { + o->status = OS_FAILED; + } + } +} diff --git a/src/battle/objectives.h b/src/battle/objectives.h new file mode 100644 index 0000000..bc8252f --- /dev/null +++ b/src/battle/objectives.h @@ -0,0 +1,31 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void updateChallenges(void); +extern void addHudMessage(SDL_Color c, char *format, ...); + +extern Battle battle; +extern Colors colors; +extern Game game; diff --git a/src/battle/player.c b/src/battle/player.c new file mode 100644 index 0000000..95dc1a4 --- /dev/null +++ b/src/battle/player.c @@ -0,0 +1,106 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "player.h" + +static void selectTarget(void); + +void doPlayer(void) +{ + if (player != NULL) + { + self = player; + + if (player->alive == ALIVE_ALIVE) + { + if (app.keyboard[SDL_SCANCODE_LEFT]) + { + player->angle -= 4; + } + + if (app.keyboard[SDL_SCANCODE_RIGHT]) + { + player->angle += 4; + } + + if (app.keyboard[SDL_SCANCODE_UP]) + { + applyFighterThrust(); + } + + if (app.keyboard[SDL_SCANCODE_DOWN]) + { + applyFighterBrakes(); + } + + if (app.keyboard[SDL_SCANCODE_LCTRL] && !player->reload && player->guns[0].type) + { + fireGuns(player); + } + + if (app.keyboard[SDL_SCANCODE_RETURN] && player->missiles.ammo && player->target) + { + fireMissile(player); + + app.keyboard[SDL_SCANCODE_RETURN] = 0; + } + + if (!player->target || player->target->health <= 0 || getDistance(player->x, player->y, player->target->x, player->target->y) > 1000) + { + selectTarget(); + } + } + + player->angle = player->angle % 360; + + player->x = SCREEN_WIDTH / 2; + player->y = SCREEN_HEIGHT / 2; + + if (player->health <= 0 && battle.status == MS_IN_PROGRESS) + { + failIncompleteObjectives(); + + battle.status = MS_FAILED; + battle.missionFinishedTimer = FPS; + } + } +} + +static void selectTarget(void) +{ + unsigned int closest = 65535; + unsigned int dist = 65535; + Fighter *f; + + player->target = NULL; + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + if (f != player && f->side != player->side && f->alive == ALIVE_ALIVE) + { + dist = getDistance(self->x, self->y, f->x, f->y); + if (dist < closest) + { + player->target = f; + closest = dist; + } + } + } +} diff --git a/src/battle/player.h b/src/battle/player.h new file mode 100644 index 0000000..5e4ee36 --- /dev/null +++ b/src/battle/player.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void fireGuns(Fighter *owner); +extern void fireMissile(Fighter *owner); +extern void applyFighterThrust(void); +extern void applyFighterBrakes(void); +extern int getDistance(int x1, int y1, int x2, int y2); +extern void failIncompleteObjectives(void); + +extern App app; +extern Battle battle; +extern Fighter *player; +extern Fighter *self; diff --git a/src/battle/radar.c b/src/battle/radar.c new file mode 100644 index 0000000..2494147 --- /dev/null +++ b/src/battle/radar.c @@ -0,0 +1,74 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "radar.h" + +void drawRadar(void) +{ + SDL_Rect r; + Fighter *f; + + drawFilledCircle(SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 75, 0, 128, 0, 32); + + drawCircle(SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 25, 0, 255, 0, 64); + drawCircle(SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 50, 0, 255, 0, 64); + + r.w = r.h = 3; + + for (f = battle.fighterHead.next ; f != NULL ; f = f->next) + { + if (getDistance(f->x, f->y, player->x, player->y) / 15 < 70) + { + r.x = SCREEN_WIDTH - 85; + r.y = SCREEN_HEIGHT - 85; + + r.x -= (player->x - f->x) / 15; + r.y -= (player->y - f->y) / 15; + + r.x--; + r.y--; + + switch (f->side) + { + case SIDE_ALLIES: + SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255); + break; + + case SIDE_PIRATE: + case SIDE_PANDORAN: + SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255); + break; + + case SIDE_NONE: + SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); + break; + } + + if (player->target == f) + { + SDL_SetRenderDrawColor(app.renderer, 255, 255, 0, 255); + } + + SDL_RenderFillRect(app.renderer, &r); + } + } + + drawCircle(SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 75, 0, 255, 0, 128); +} diff --git a/src/battle/radar.h b/src/battle/radar.h new file mode 100644 index 0000000..237161d --- /dev/null +++ b/src/battle/radar.h @@ -0,0 +1,32 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void drawCircle(int cx, int cy, int radius, int r, int g, int b, int a); +extern void drawFilledCircle(int cx, int cy, int radius, int r, int g, int b, int a); +extern int getDistance(int x1, int y1, int x2, int y2); + +extern App app; +extern Battle battle; +extern Fighter *player; diff --git a/src/battle/starfield.c b/src/battle/starfield.c new file mode 100644 index 0000000..fe569e9 --- /dev/null +++ b/src/battle/starfield.c @@ -0,0 +1,85 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "starfield.h" + +Star stars[MAX_STARS]; + +void initStars(void) +{ + int i; + + memset(stars, 0, sizeof(Star) * MAX_STARS); + + for (i = 0 ; i < MAX_STARS ; i++) + { + stars[i].x = rand() % SCREEN_WIDTH; + stars[i].y = rand() % SCREEN_HEIGHT; + stars[i].speed = 10 + rand() % 30; + + stars[i].speed *= 0.1; + } +} + +void doStars(float dx, float dy) +{ + int i; + + for (i = 0 ; i < MAX_STARS ; i++) + { + stars[i].x -= (dx * stars[i].speed); + stars[i].y -= (dy * stars[i].speed); + + if (stars[i].x >= SCREEN_WIDTH) + { + stars[i].x = 0; + } + + if (stars[i].x < 0) + { + stars[i].x = SCREEN_WIDTH - 1; + } + + if (stars[i].y >= SCREEN_HEIGHT) + { + stars[i].y = 0; + } + + if (stars[i].y < 0) + { + stars[i].y = SCREEN_HEIGHT - 1; + } + } +} + +void drawStars(void) +{ + int i; + int c; + + for (i = 0 ; i < MAX_STARS ; i++) + { + c = 85 * stars[i].speed; + + SDL_SetRenderDrawColor(app.renderer, c, c, c, 255); + + SDL_RenderDrawPoint(app.renderer, stars[i].x, stars[i].y); + } +} diff --git a/src/battle/starfield.h b/src/battle/starfield.h new file mode 100644 index 0000000..ce53166 --- /dev/null +++ b/src/battle/starfield.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern App app; diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 0000000..456842a --- /dev/null +++ b/src/defs.h @@ -0,0 +1,154 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define PI 3.14159265358979323846 +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define STRNCPY(dest, src, n) strncpy(dest, src, n); dest[n - 1] = '\0' +#define TO_RAIDANS(angleDegrees) (angleDegrees * PI / 180.0) +#define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI) + +#define SCREEN_WIDTH 1280 +#define SCREEN_HEIGHT 720 + +#define MAX_KEYBOARD_KEYS 350 + +#define LOGIC_RATE 16 +#define FPS (1000 / LOGIC_RATE) + +#define MAX_NAME_LENGTH 32 +#define MAX_DESCRIPTION_LENGTH 512 +#define MAX_FILENAME_LENGTH 1024 + +#define NUM_TEXTURE_BUCKETS 32 + +#define MAX_STARS 500 + +#define MAX_FONTS 32 +#define NUM_TEXT_BUCKETS 64 + +#define MAX_FIGHTER_GUNS 12 + +#define BF_NONE 0 +#define BF_ENGINE (2 << 0) + +enum +{ + TA_LEFT, + TA_RIGHT, + TA_CENTER +}; + +enum +{ + ALIVE_ALIVE, + ALIVE_DYING, + ALIVE_DEAD +}; + +enum +{ + SIDE_NONE, + SIDE_ALLIES, + SIDE_PANDORAN, + SIDE_PIRATE, + SIDE_CSN, + SIDE_INF, + SIDE_UNF +}; + +enum +{ + BT_NONE, + BT_PARTICLE, + BT_PLASMA, + BT_LASER, + BT_MAG, + BT_ROCKET, + BT_MISSILE, + BT_FF, + BT_MAX +}; + +enum +{ + MISSILE_ROCKET, + MISSILE_MISSILE, + MISSILE_FF, + MISSILE_MAX +}; + +enum +{ + EFFECT_LINE, + EFFECT_TEXTURE, + EFFECT_HALO +}; + +enum +{ + SND_PARTICLE, + SND_PLASMA, + SND_MAG, + SND_ARMOUR_HIT, + SND_SHIELD_HIT, + SND_EXPLOSION_1, + SND_EXPLOSION_2, + SND_EXPLOSION_3, + SND_EXPLOSION_4, + SND_GUI_CLICK, + SND_GUI_SELECT, + SND_GUI_CLOSE, + SND_GUI_DENIED, + SND_MAX +}; + +enum +{ + OS_INCOMPLETE, + OS_COMPLETE, + OS_FAILED, + OS_CONDITIONAL +}; + +enum +{ + MS_START, + MS_IN_PROGRESS, + MS_PAUSED, + MS_COMPLETE, + MS_FAILED +}; + +enum { + WT_BUTTON, + WT_SELECT +}; + +enum +{ + CHALLENGE_ARMOUR, + CHALLENGE_TIME, + CHALLENGE_ACCURACY, + CHALLENGE_NO_LOSSES, + CHALLENGE_1_LOSS, + CHALLENGE_LOSSES, + CHALLENGE_PLAYER_KILLS +}; diff --git a/src/draw/draw.c b/src/draw/draw.c new file mode 100644 index 0000000..3aa54c6 --- /dev/null +++ b/src/draw/draw.c @@ -0,0 +1,208 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "draw.h" + +static PointF backgroundPoint[4]; + +void initBackground(void) +{ + backgroundPoint[0].x = -SCREEN_WIDTH / 2; + backgroundPoint[0].y = -SCREEN_HEIGHT / 2; + + backgroundPoint[1].x = SCREEN_WIDTH / 2; + backgroundPoint[1].y = -SCREEN_HEIGHT / 2; + + backgroundPoint[2].x = -SCREEN_WIDTH / 2; + backgroundPoint[2].y = SCREEN_HEIGHT / 2; + + backgroundPoint[3].x = SCREEN_WIDTH / 2; + backgroundPoint[3].y = SCREEN_HEIGHT / 2; +} + +void prepareScene(void) +{ + SDL_SetRenderTarget(app.renderer, app.backBuffer); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(app.renderer); +} + +void presentScene(void) +{ + /*drawText(SCREEN_WIDTH - 5, 35, 14, TA_RIGHT, colors.white, "FPS: %d", app.fps);*/ + + SDL_SetRenderTarget(app.renderer, NULL); + SDL_RenderCopy(app.renderer, app.backBuffer, NULL, NULL); + SDL_RenderPresent(app.renderer); +} + +void blit(SDL_Texture *texture, int x, int y, int center) +{ + SDL_Rect dstRect; + + dstRect.x = x; + dstRect.y = y; + SDL_QueryTexture(texture, NULL, NULL, &dstRect.w, &dstRect.h); + + if (center) + { + dstRect.x -= (dstRect.w / 2); + dstRect.y -= (dstRect.h / 2); + } + + SDL_RenderCopy(app.renderer, texture, NULL, &dstRect); +} + +void blitScaled(SDL_Texture *texture, int x, int y, int w, int h) +{ + SDL_Rect dstRect; + + dstRect.x = x; + dstRect.y = y; + dstRect.w = w; + dstRect.h = h; + + SDL_RenderCopy(app.renderer, texture, NULL, &dstRect); +} + +void blitRotated(SDL_Texture *texture, int x, int y, int angle) +{ + SDL_Rect dstRect; + + dstRect.x = x; + dstRect.y = y; + SDL_QueryTexture(texture, NULL, NULL, &dstRect.w, &dstRect.h); + dstRect.x -= (dstRect.w / 2); + dstRect.y -= (dstRect.h / 2); + + SDL_RenderCopyEx(app.renderer, texture, NULL, &dstRect, angle, NULL, SDL_FLIP_NONE); +} + +void drawCircle(int cx, int cy, int radius, int r, int g, int b, int a) +{ + int x = radius; + int y = 0; + int radiusError = 1 - x; + + SDL_SetRenderDrawColor(app.renderer, r, g, b, a); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + + while (x >= y) + { + SDL_RenderDrawPoint(app.renderer, x + cx, y + cy); + SDL_RenderDrawPoint(app.renderer, y + cx, x + cy); + SDL_RenderDrawPoint(app.renderer,-x + cx, y + cy); + SDL_RenderDrawPoint(app.renderer,-y + cx, x + cy); + SDL_RenderDrawPoint(app.renderer,-x + cx, -y + cy); + SDL_RenderDrawPoint(app.renderer,-y + cx, -x + cy); + SDL_RenderDrawPoint(app.renderer, x + cx, -y + cy); + SDL_RenderDrawPoint(app.renderer, y + cx, -x + cy); + + y++; + + if (radiusError < 0) + { + radiusError += 2 * y + 1; + } + else + { + x--; + radiusError += 2 * (y - x) + 1; + } + } + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); +} + +void drawFilledCircle(int cx, int cy, int radius, int r, int g, int b, int a) +{ + int x, y; + + SDL_SetRenderDrawColor(app.renderer, r, g, b, a); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + + for (y = -radius ; y <= radius ; y++) + { + for (x =- radius; x <= radius ; x++) + { + if (x * x + y * y <= radius * radius) + { + SDL_RenderDrawPoint(app.renderer, cx + x, cy + y); + } + } + } + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); +} + +void scrollBackground(float x, float y) +{ + int i; + + for (i = 0 ; i < 4 ; i++) + { + backgroundPoint[i].x += x; + backgroundPoint[i].y += y; + + if (backgroundPoint[i].x < 0) + { + backgroundPoint[i].x += (SCREEN_WIDTH * 2); + } + + if (backgroundPoint[i].x >= SCREEN_WIDTH) + { + backgroundPoint[i].x -= (SCREEN_WIDTH * 2); + } + + if (backgroundPoint[i].y < 0) + { + backgroundPoint[i].y += (SCREEN_HEIGHT * 2); + } + + if (backgroundPoint[i].y >= SCREEN_HEIGHT) + { + backgroundPoint[i].y -= (SCREEN_HEIGHT * 2); + } + } +} + +void drawBackground(SDL_Texture *texture) +{ + int i; + + for (i = 0 ; i < 4 ; i++) + { + blitScaled(texture, backgroundPoint[i].x, backgroundPoint[i].y, SCREEN_WIDTH, SCREEN_HEIGHT); + } +} + +void saveScreenshot(void) +{ + static int i = 0; + char filename[MAX_NAME_LENGTH]; + SDL_Surface *sshot; + + sprintf(filename, "/home/steve/temp/screenshots/%d.bmp", ++i); + + sshot = SDL_CreateRGBSurface(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + SDL_RenderReadPixels(app.renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch); + SDL_SaveBMP(sshot, filename); + SDL_FreeSurface(sshot); +} diff --git a/src/draw/draw.h b/src/draw/draw.h new file mode 100644 index 0000000..8791ac1 --- /dev/null +++ b/src/draw/draw.h @@ -0,0 +1,29 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); + +extern App app; +extern Colors colors; diff --git a/src/draw/text.c b/src/draw/text.c new file mode 100644 index 0000000..7ca8e72 --- /dev/null +++ b/src/draw/text.c @@ -0,0 +1,266 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "text.h" + +static void loadFont(int size); +static SDL_Texture *getCachedText(unsigned long hash); +static void cacheText(unsigned long hash, SDL_Texture *t); +static unsigned long hashcode(const char *str, int size); +static void drawTextNormal(int x, int y, int size, int align, SDL_Color c, char *text); +static void drawTextSplit(int x, int y, int size, int align, SDL_Color c, char *text); +void textSize(char *text, int size, int *w, int *h); + +static char drawTextBuffer[MAX_DESCRIPTION_LENGTH]; +static TTF_Font *font[MAX_FONTS]; +static Texture textures[NUM_TEXT_BUCKETS]; +static int maxWidth = 0; + +void initFonts(void) +{ + memset(&font, 0, sizeof(TTF_Font*) * MAX_FONTS); + memset(&textures, 0, sizeof(Texture) * NUM_TEXT_BUCKETS); +} + +void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...) +{ + va_list args; + + memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); + + va_start(args, format); + vsprintf(drawTextBuffer, format, args); + va_end(args); + + if (maxWidth == 0) + { + drawTextNormal(x, y, size, align, c, drawTextBuffer); + } + else + { + drawTextSplit(x, y, size, align, c, drawTextBuffer); + } +} + +static void drawTextNormal(int x, int y, int size, int align, SDL_Color c, char *text) +{ + SDL_Surface *surface; + SDL_Texture *t; + int w, h; + long hash; + + if (size >= MAX_FONTS) + { + printf("ERROR: %d exceeds max font size index of %d\n", size, MAX_FONTS); + exit(1); + } + + if (!font[size]) + { + loadFont(size); + } + + hash = hashcode(text, size); + + t = getCachedText(hash); + + if (!t) + { + surface = TTF_RenderText_Blended(font[size], text, c); + t = SDL_CreateTextureFromSurface(app.renderer, surface); + SDL_FreeSurface(surface); + + cacheText(hash, t); + } + + SDL_QueryTexture(t, NULL, NULL, &w, &h); + + if (align == TA_CENTER) + { + x -= (w / 2); + } + else if (align == TA_RIGHT) + { + x -= w; + } + + SDL_SetTextureColorMod(t, c.r, c.g, c.b); + + blit(t, x, y, 0); +} + +static void drawTextSplit(int x, int y, int size, int align, SDL_Color c, char *text) +{ + char drawTextBuffer[MAX_DESCRIPTION_LENGTH]; + char *token; + int w, h, currentWidth; + + memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); + + token = strtok(text, " "); + + currentWidth = 0; + + while (token) + { + textSize(token, size, &w, &h); + + if (currentWidth + w > maxWidth) + { + drawTextNormal(x, y, size, align, c, drawTextBuffer); + + currentWidth = 0; + y += h; + memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); + } + + strcat(drawTextBuffer, token); + strcat(drawTextBuffer, " "); + + currentWidth += w; + + token = strtok(NULL, " "); + } + + drawTextNormal(x, y, size, align, c, drawTextBuffer); +} + +void textSize(char *text, int size, int *w, int *h) +{ + if (!font[size]) + { + loadFont(size); + } + + TTF_SizeText(font[size], text, w, h); +} + +void limitTextWidth(int width) +{ + maxWidth = width; +} + +static SDL_Texture *getCachedText(unsigned long hash) +{ + Texture *t; + int i; + + i = hash % NUM_TEXT_BUCKETS; + + t = textures[i].next; + + for (t = textures[i].next ; t != NULL ; t = t->next) + { + if (t->hash == hash) + { + return t->texture; + } + } + + return NULL; +} + +static void cacheText(unsigned long hash, SDL_Texture *texture) +{ + Texture *t, *new; + int i; + + i = hash % NUM_TEXT_BUCKETS; + + t = &textures[i]; + + /* horrible bit to find the tail */ + while (t->next) + { + t = t->next; + } + + new = malloc(sizeof(Texture)); + memset(new, 0, sizeof(Texture)); + + new->hash = hash; + new->texture = texture; + + t->next = new; +} + +void expireTexts(void) +{ + Texture *t; + int i, n; + + n = 0; + + for (i = 0 ; i < NUM_TEXT_BUCKETS ; i++) + { + while (textures[i].next) + { + t = textures[i].next; + textures[i].next = t->next; + SDL_DestroyTexture(t->texture); + free(t); + + n++; + } + + textures[i].next = NULL; + } + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Expired %d texts", n); +} + +static void loadFont(int size) +{ + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "loadFonts(%d)", size); + + font[size] = TTF_OpenFont("data/fonts/Roboto-Medium.ttf", size); +} + +static unsigned long hashcode(const char *str, int size) +{ + unsigned long hash = 5381; + int c; + + c = *str; + + while (c) + { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + c = *str++; + } + + hash = ((hash << 5) + hash) + size; + + return abs(hash); +} + +void destroyFonts(void) +{ + int i; + + for (i = 0 ; i < MAX_FONTS ; i++) + { + if (font[i]) + { + TTF_CloseFont(font[i]); + } + } +} diff --git a/src/draw/text.h b/src/draw/text.h new file mode 100644 index 0000000..7c5ef08 --- /dev/null +++ b/src/draw/text.h @@ -0,0 +1,29 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" +#include "SDL2/SDL_ttf.h" + +#include "../defs.h" +#include "../structs.h" + +extern void blit(SDL_Texture *texture, int x, int y, int centered); + +extern App app; diff --git a/src/galaxy/galacticMap.c b/src/galaxy/galacticMap.c new file mode 100644 index 0000000..431d965 --- /dev/null +++ b/src/galaxy/galacticMap.c @@ -0,0 +1,726 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "galacticMap.h" + +static void logic(void); +static void draw(void); +static void handleKeyboard(void); +static void drawStarSystemDetail(void); +static void prevMission(void); +static void nextMission(void); +static void selectStarSystem(void); +static void drawGalaxy(void); +static void handleGalaxyKB(void); +static void handleSelectedSystemKB(void); +static void centerOnSelectedStarSystem(void); +static void doStarSystems(void); +void destroyGalacticMap(void); +static void drawPulses(void); +static void doPulses(void); +static void addPulses(void); +static void drawMenu(void); +static void resume(void); +static void stats(void); +static void options(void); +static void statsOK(void); +static void quit(void); +static void returnFromOptions(void); + +static StarSystem *selectedStarSystem; +static Mission *selectedMission = {0}; +static int missionListStart, selectedMissionIndex; +static SDL_Texture *background; +static SDL_Texture *starSystemTexture; +static SDL_Point camera; +static int viewingSystem; +static Pulse pulseHead = {0}; +static Pulse *pulseTail; +static int pulseTimer; +static float ssx, ssy; +static int show; +static int completedMissions, totalMissions; +static int completedChallenges, totalChallenges; + +void initGalacticMap(void) +{ + startSectionTransition(); + + stopMusic(); + + app.delegate.logic = &logic; + app.delegate.draw = &draw; + memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + background = getTexture("gfx/backgrounds/background02.jpg"); + + starSystemTexture = getTexture("gfx/galaxy/starSystem.png"); + + if (!selectedStarSystem) + { + selectedStarSystem = game.starSystemHead.next; + } + + updateStarSystemDescriptions(); + + centerOnSelectedStarSystem(); + + saveGame(); + + viewingSystem = 0; + + pulseTimer = 0; + + show = SHOW_GALAXY; + + /* clear the pulses */ + destroyGalacticMap(); + + initBackground(); + + getWidget("resume", "galacticMap")->action = resume; + getWidget("stats", "galacticMap")->action = stats; + getWidget("options", "galacticMap")->action = options; + getWidget("quit", "galacticMap")->action = quit; + + getWidget("ok", "stats")->action = statsOK; + + endSectionTransition(); + + playMusic("music/Pressure.ogg"); +} + +static void logic(void) +{ + handleKeyboard(); + + doStarSystems(); + + scrollBackground(-ssx, -ssy); + + doPulses(); + + doStars(ssx, ssy); + + if (pulseTimer % FPS == 0) + { + addPulses(); + } + + pulseTimer++; + pulseTimer %= (FPS * 60); + + doWidgets(); +} + +static void doStarSystems(void) +{ + StarSystem *starSystem; + int cx, cy; + + completedMissions = totalMissions = completedChallenges = totalChallenges = 0; + + cx = (camera.x + SCREEN_WIDTH / 2) - 32; + cy = (camera.y + SCREEN_HEIGHT / 2) - 32; + + selectedStarSystem = NULL; + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + completedMissions += starSystem->completedMissions; + totalMissions += starSystem->totalMissions; + completedChallenges += starSystem->completedChallenges; + totalChallenges += starSystem->totalChallenges; + + if (starSystem->totalMissions > 0 && collision(cx, cy, 64, 64, starSystem->x, starSystem->y, 4, 4)) + { + if (selectedStarSystem != starSystem) + { + selectedStarSystem = starSystem; + } + } + } +} + +static void addPulses(void) +{ + Pulse *pulse; + StarSystem *starSystem; + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + if (starSystem->completedMissions < starSystem->totalMissions) + { + pulse = malloc(sizeof(Pulse)); + memset(pulse, 0, sizeof(Pulse)); + + pulse->x = starSystem->x; + pulse->y = starSystem->y; + pulse->life = 255; + pulse->r = 255; + + pulseTail->next = pulse; + pulseTail = pulse; + } + else if (starSystem->completedChallenges < starSystem->totalChallenges && pulseTimer % (FPS * 2) == 0) + { + pulse = malloc(sizeof(Pulse)); + memset(pulse, 0, sizeof(Pulse)); + + pulse->x = starSystem->x; + pulse->y = starSystem->y; + pulse->life = 255; + pulse->r = pulse->g = 255; + + pulseTail->next = pulse; + pulseTail = pulse; + } + } +} + +static void doPulses(void) +{ + Pulse *pulse, *prev; + + prev = &pulseHead; + + for (pulse = pulseHead.next ; pulse != NULL ; pulse = pulse->next) + { + pulse->size += 0.5; + pulse->life--; + + if (pulse->life <= 0) + { + if (pulse == pulseTail) + { + pulseTail = prev; + } + + prev->next = pulse->next; + free(pulse); + pulse = prev; + } + + prev = pulse; + } +} + +static void draw(void) +{ + prepareScene(); + + drawBackground(background); + + drawStars(); + + drawGalaxy(); + + drawPulses(); + + if (viewingSystem) + { + drawStarSystemDetail(); + } + + switch (show) + { + case SHOW_GALAXY: + break; + + case SHOW_MENU: + drawMenu(); + break; + + case SHOW_STATS: + drawStats(); + break; + + case SHOW_OPTIONS: + drawOptions(); + break; + } + + presentScene(); +} + +static void drawPulses(void) +{ + Pulse *pulse; + + for (pulse = pulseHead.next ; pulse != NULL ; pulse = pulse->next) + { + drawCircle(pulse->x - camera.x, pulse->y - camera.y, pulse->size, pulse->r, pulse->g, pulse->b, pulse->life); + } +} + +static void centerOnSelectedStarSystem(void) +{ + camera.x = selectedStarSystem->x; + camera.x -= SCREEN_WIDTH / 2; + + camera.y = selectedStarSystem->y; + camera.y -= SCREEN_HEIGHT / 2; +} + +static void drawGalaxy(void) +{ + SDL_Rect r; + StarSystem *starSystem; + SDL_Color color; + + r.w = r.h = 64; + r.x = (SCREEN_WIDTH / 2) - r.w / 2; + r.y = (SCREEN_HEIGHT / 2) - r.h / 2; + + if (selectedStarSystem) + { + SDL_SetRenderDrawColor(app.renderer, 64, 100, 128, 255); + SDL_RenderFillRect(app.renderer, &r); + } + + SDL_SetRenderDrawColor(app.renderer, 128, 200, 255, 255); + SDL_RenderDrawRect(app.renderer, &r); + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + blit(starSystemTexture, starSystem->x - camera.x, starSystem->y - camera.y, 1); + + switch (starSystem->side) + { + case SIDE_CSN: + color = colors.cyan; + break; + + case SIDE_UNF: + color = colors.white; + break; + + case SIDE_INF: + color = colors.red; + break; + } + + drawText(starSystem->x - camera.x, starSystem->y - camera.y + 12, 14, TA_CENTER, color, starSystem->name); + } + + if (!viewingSystem && selectedStarSystem != NULL) + { + r.x = 0; + r.y = SCREEN_HEIGHT - 35; + r.w = SCREEN_WIDTH; + r.h = 35; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 200); + SDL_RenderFillRect(app.renderer, &r); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + drawText(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 30, 18, TA_CENTER, colors.white, selectedStarSystem->description); + } + + r.x = 0; + r.y = 0; + r.w = SCREEN_WIDTH; + r.h = 35; + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 200); + SDL_RenderFillRect(app.renderer, &r); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + drawText((SCREEN_WIDTH / 2) - 50, 5, 18, TA_RIGHT, colors.white, "Missions %d / %d", completedMissions, totalMissions); + drawText((SCREEN_WIDTH / 2) + 50, 5, 18, TA_LEFT, colors.white, "Challenges %d / %d", completedChallenges, totalChallenges); +} + +static void selectStarSystem(void) +{ + Mission *mission, *prev; + + selectedMission = selectedStarSystem->missionHead.next; + + selectedStarSystem->completedMissions = selectedStarSystem->totalMissions = 0; + + prev = &selectedStarSystem->missionHead; + + for (mission = selectedStarSystem->missionHead.next ; mission != NULL ; mission = mission->next) + { + selectedStarSystem->totalMissions++; + + if (mission->completed) + { + selectedStarSystem->completedMissions++; + } + + mission->available = prev->completed; + + prev = mission; + } + + missionListStart = 0; + selectedMissionIndex = 0; + + viewingSystem = selectedStarSystem->totalMissions > 0; +} + +static void drawStarSystemDetail(void) +{ + int y, i; + Mission *mission; + Challenge *challenge; + SDL_Rect r; + + r.w = 900; + r.h = 600; + r.x = (SCREEN_WIDTH / 2) - (r.w / 2); + r.y = (SCREEN_HEIGHT / 2) - (r.h / 2); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 225); + SDL_RenderFillRect(app.renderer, &r); + + SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 200); + SDL_RenderDrawRect(app.renderer, &r); + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + y = 70; + + drawText(SCREEN_WIDTH / 2, y, 28, TA_CENTER, colors.cyan, "%s (%d / %d)", selectedStarSystem->name, selectedStarSystem->completedMissions, selectedStarSystem->totalMissions); + + SDL_RenderDrawLine(app.renderer, r.x, 120, r.x + r.w, 120); + + SDL_RenderDrawLine(app.renderer, 515, 120, 515, 660); + + y += 80; + + r.x = 200; + r.w = 300; + r.h = 40; + + i = 0; + + for (mission = selectedStarSystem->missionHead.next ; mission != NULL ; mission = mission->next) + { + if (i == selectedMissionIndex) + { + selectedMission = mission; + } + + if (i >= missionListStart && i < missionListStart + 10) + { + if (mission == selectedMission) + { + r.y = y - 2; + + SDL_SetRenderDrawColor(app.renderer, 32, 64, 128, 255); + SDL_RenderFillRect(app.renderer, &r); + + SDL_SetRenderDrawColor(app.renderer, 64, 96, 196, 255); + SDL_RenderDrawRect(app.renderer, &r); + } + + if (mission->available) + { + drawText(210, y, 24, TA_LEFT, mission->completed ? colors.white : colors.yellow, mission->name); + } + else + { + drawText(210, y, 24, TA_LEFT, colors.darkGrey, "[LOCKED]"); + } + + y += 50; + } + + i++; + } + + if (selectedMission->available) + { + drawText(525, 135, 18, TA_LEFT, colors.lightGrey, "Pilot: %s", selectedMission->pilot); + drawText(525, 160, 18, TA_LEFT, colors.lightGrey, "Craft: %s", selectedMission->craft); + drawText(525, 185, 18, TA_LEFT, colors.lightGrey, "Squadron: %s", selectedMission->squadron); + + limitTextWidth(500); + drawText(525, 230, 22, TA_LEFT, colors.white, selectedMission->description); + limitTextWidth(0); + } + else + { + drawText(525, 135, 18, TA_LEFT, colors.lightGrey, "Pilot: -"); + drawText(525, 160, 18, TA_LEFT, colors.lightGrey, "Craft: -"); + drawText(525, 185, 18, TA_LEFT, colors.lightGrey, "Squadron: -"); + + limitTextWidth(500); + drawText(525, 230, 22, TA_LEFT, colors.darkGrey, "You cannot play this mission yet. Complete the previous mission to unlock."); + limitTextWidth(0); + } + + if (selectedMission && selectedMission->available && selectedMission->challengeHead.next) + { + y = SCREEN_HEIGHT - 100; + + for (challenge = selectedMission->challengeHead.next ; challenge != NULL ; challenge = challenge->next) + { + y -= 25; + } + + drawText(525, y, 22, TA_LEFT, colors.yellow, "Challenges"); + + y += 30; + + for (challenge = selectedMission->challengeHead.next ; challenge != NULL ; challenge = challenge->next) + { + drawText(525, y, 18, TA_LEFT, challenge->passed ? colors.green : colors.lightGrey, "%s%s", getChallengeDescription(challenge), challenge->passed ? " - COMPLETE" : ""); + + y += 25; + } + } +} + +static void handleKeyboard(void) +{ + if (show == SHOW_GALAXY) + { + if (viewingSystem) + { + handleSelectedSystemKB(); + } + else + { + handleGalaxyKB(); + } + } + else if (app.keyboard[SDL_SCANCODE_ESCAPE]) + { + switch (show) + { + case SHOW_MENU: + show = SHOW_GALAXY; + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + break; + + case SHOW_OPTIONS: + case SHOW_STATS: + show = SHOW_MENU; + selectWidget("resume", "galacticMap"); + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + break; + } + + playSound(SND_GUI_CLOSE); + } +} + +static void handleGalaxyKB(void) +{ + int lastX, lastY; + + lastX = camera.x; + lastY = camera.y; + + ssx = ssy = 0; + + if (app.keyboard[SDL_SCANCODE_LEFT]) + { + ssx = -1; + camera.x -= CAMERA_SPEED; + } + + if (app.keyboard[SDL_SCANCODE_RIGHT]) + { + ssx = 1; + camera.x += CAMERA_SPEED; + } + + if (app.keyboard[SDL_SCANCODE_UP]) + { + ssy = -1; + camera.y -= CAMERA_SPEED; + } + + if (app.keyboard[SDL_SCANCODE_DOWN]) + { + ssy = 1; + camera.y += CAMERA_SPEED; + } + + if (app.keyboard[SDL_SCANCODE_RETURN]) + { + selectStarSystem(); + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + } + + camera.x = MAX(-800, MIN(camera.x, 2464)); + camera.y = MAX(-475, MIN(camera.y, 1235)); + + if (lastX == camera.x) + { + ssx = 0; + } + + if (lastY == camera.y) + { + ssy = 0; + } + + if (app.keyboard[SDL_SCANCODE_ESCAPE]) + { + selectWidget("resume", "galacticMap"); + show = SHOW_MENU; + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + playSound(SND_GUI_CLOSE); + } +} + +static void handleSelectedSystemKB(void) +{ + if (app.keyboard[SDL_SCANCODE_UP]) + { + prevMission(); + } + + if (app.keyboard[SDL_SCANCODE_DOWN]) + { + nextMission(); + } + + if (app.keyboard[SDL_SCANCODE_RETURN] && selectedMission->available) + { + if (selectedMission->available) + { + playSound(SND_GUI_SELECT); + + initBattle(); + game.currentMission = selectedMission; + loadMission(selectedMission->filename); + } + else + { + playSound(SND_GUI_DENIED); + } + } + + if (app.keyboard[SDL_SCANCODE_ESCAPE]) + { + viewingSystem = 0; + + playSound(SND_GUI_CLOSE); + } + + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); +} + +static void prevMission(void) +{ + selectedMissionIndex = MAX(0, selectedMissionIndex - 1); + + if (selectedMissionIndex <= missionListStart + 3) + { + missionListStart = MAX(0, missionListStart - 1); + } + + selectedMission = NULL; +} + +static void nextMission(void) +{ + selectedMissionIndex = MIN(selectedMissionIndex + 1, selectedStarSystem->totalMissions - 1); + + if (selectedMissionIndex >= missionListStart + 5) + { + missionListStart = MIN(missionListStart + 1, selectedStarSystem->totalMissions - 9); + } + + selectedMission = NULL; +} + +static void drawMenu(void) +{ + SDL_Rect r; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128); + SDL_RenderFillRect(app.renderer, NULL); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + r.w = 400; + r.h = 400; + r.x = (SCREEN_WIDTH / 2) - r.w / 2; + r.y = (SCREEN_HEIGHT / 2) - r.h / 2; + + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 0); + SDL_RenderFillRect(app.renderer, &r); + SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255); + SDL_RenderDrawRect(app.renderer, &r); + + drawWidgets("galacticMap"); +} + +static void resume(void) +{ + show = SHOW_GALAXY; +} + +static void options(void) +{ + show = SHOW_OPTIONS; + + initOptions(returnFromOptions); +} + +static void stats(void) +{ + selectWidget("ok", "stats"); + + show = SHOW_STATS; +} + +static void statsOK(void) +{ + selectWidget("resume", "galacticMap"); + + show = SHOW_MENU; +} + +static void returnFromOptions(void) +{ + show = SHOW_MENU; + + selectWidget("resume", "galacticMap"); +} + +static void quit(void) +{ + initTitle(); +} + +void destroyGalacticMap(void) +{ + Pulse *pulse; + + while (pulseHead.next) + { + pulse = pulseHead.next; + pulseHead.next = pulse->next; + free(pulse); + } + + pulseTail = &pulseHead; +} diff --git a/src/galaxy/galacticMap.h b/src/galaxy/galacticMap.h new file mode 100644 index 0000000..90c9965 --- /dev/null +++ b/src/galaxy/galacticMap.h @@ -0,0 +1,67 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +#define CAMERA_SPEED 8 + +#define SHOW_GALAXY 0 +#define SHOW_MENU 1 +#define SHOW_OPTIONS 2 +#define SHOW_STATS 3 + +extern void prepareScene(void); +extern void presentScene(void); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern void initBattle(void); +extern void loadMission(char *filename); +extern SDL_Texture *getTexture(char *filename); +extern void startSectionTransition(void); +extern void endSectionTransition(void); +extern void saveGame(void); +extern char *getChallengeDescription(Challenge *c); +extern void blit(SDL_Texture *t, int x, int y, int centered); +extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); +extern void updateStarSystemDescriptions(void); +extern void drawCircle(int cx, int cy, int radius, int r, int g, int b, int a); +extern void playMusic(char *filename); +extern void stopMusic(void); +extern void doStars(float dx, float dy); +extern void drawStars(void); +extern void limitTextWidth(int width); +extern void drawBackground(SDL_Texture *texture); +extern void initBackground(void); +extern void scrollBackground(float x, float y); +extern void drawWidgets(char *groupName); +extern void doWidgets(void); +extern Widget *getWidget(const char *name, const char *group); +extern void selectWidget(const char *name, const char *group); +extern void initTitle(void); +extern void drawOptions(void); +extern void initOptions(void (*returnFromOptions)(void)); +extern void drawStats(void); +extern void playSound(int id); + +extern App app; +extern Colors colors; +extern Game game; diff --git a/src/galaxy/mission.c b/src/galaxy/mission.c new file mode 100644 index 0000000..102ff33 --- /dev/null +++ b/src/galaxy/mission.c @@ -0,0 +1,199 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "mission.h" + +static void loadObjectives(cJSON *node); +static void loadPlayer(cJSON *node); +static void loadFighters(cJSON *node); +static void loadFighterGroups(cJSON *node); +static unsigned long hashcode(const char *str); + +void loadMission(char *filename) +{ + cJSON *root; + char *text, music[MAX_NAME_LENGTH]; + + startSectionTransition(); + + stopMusic(); + + text = readFile(filename); + + srand(hashcode(filename)); + + root = cJSON_Parse(text); + + battle.background = getTexture(cJSON_GetObjectItem(root, "background")->valuestring); + battle.planetTexture = getTexture(cJSON_GetObjectItem(root, "planet")->valuestring); + battle.planet.x = rand() % SCREEN_WIDTH - rand() % SCREEN_WIDTH; + battle.planet.y = rand() % SCREEN_HEIGHT - rand() % SCREEN_HEIGHT; + + loadObjectives(cJSON_GetObjectItem(root, "objectives")); + + loadPlayer(cJSON_GetObjectItem(root, "player")); + + loadFighters(cJSON_GetObjectItem(root, "fighters")); + + loadFighterGroups(cJSON_GetObjectItem(root, "fighterGroups")); + + STRNCPY(music, cJSON_GetObjectItem(root, "music")->valuestring, MAX_NAME_LENGTH); + + cJSON_Delete(root); + free(text); + + srand(time(NULL)); + + endSectionTransition(); + + if (!battle.objectiveHead.next) + { + battle.status = MS_IN_PROGRESS; + } + + playMusic(music); +} + +static void loadObjectives(cJSON *node) +{ + Objective *o; + + if (node) + { + node = node->child; + + while (node) + { + o = malloc(sizeof(Objective)); + memset(o, 0, sizeof(Objective)); + + STRNCPY(o->description, cJSON_GetObjectItem(node, "description")->valuestring, MAX_DESCRIPTION_LENGTH); + STRNCPY(o->targetName, cJSON_GetObjectItem(node, "targetName")->valuestring, MAX_NAME_LENGTH); + o->targetValue = cJSON_GetObjectItem(node, "targetValue")->valueint; + + battle.objectiveTail->next = o; + battle.objectiveTail = o; + + node = node->next; + } + } +} + +static void loadPlayer(cJSON *node) +{ + char *type; + int side; + + type = cJSON_GetObjectItem(node, "type")->valuestring; + side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); + + player = spawnFighter(type, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, side); + player->defaultAction = NULL; +} + +static void loadFighters(cJSON *node) +{ + Fighter *f; + char *type; + int side, x, y; + + if (node) + { + node = node->child; + + while (node) + { + type = cJSON_GetObjectItem(node, "type")->valuestring; + side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); + x = cJSON_GetObjectItem(node, "x")->valueint; + y = cJSON_GetObjectItem(node, "y")->valueint; + + f = spawnFighter(type, x, y, side); + + STRNCPY(f->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); + + node = node->next; + } + } +} + +static void loadFighterGroups(cJSON *node) +{ + Fighter *f; + char *type, *name; + int side, x, y; + int number, i; + + if (node) + { + node = node->child; + + while (node) + { + type = cJSON_GetObjectItem(node, "type")->valuestring; + side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); + number = cJSON_GetObjectItem(node, "number")->valueint; + x = cJSON_GetObjectItem(node, "x")->valueint; + y = cJSON_GetObjectItem(node, "y")->valueint; + name = cJSON_GetObjectItem(node, "name")->valuestring; + + for (i = 0 ; i < number ; i++) + { + f = spawnFighter(type, x, y, side); + + STRNCPY(f->name, name, MAX_NAME_LENGTH); + } + + node = node->next; + } + } +} + +Mission *getMission(StarSystem *starSystem, char *filename) +{ + Mission *mission; + + for (mission = starSystem->missionHead.next ; mission != NULL ; mission = mission->next) + { + if (strcmp(mission->filename, filename) == 0) + { + return mission; + } + } + + return NULL; +} + +static unsigned long hashcode(const char *str) +{ + unsigned long hash = 5381; + int c; + + c = *str; + + while (c) + { + hash = ((hash << 5) + hash) + c; + + c = *str++; + } + + return abs(hash); +} diff --git a/src/galaxy/mission.h b/src/galaxy/mission.h new file mode 100644 index 0000000..802cbfc --- /dev/null +++ b/src/galaxy/mission.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" +#include "time.h" + +#include "../defs.h" +#include "../structs.h" +#include "../json/cJSON.h" + +extern long lookup(char *name); +extern char *readFile(char *filename); +extern SDL_Texture *getTexture(char *filename); +extern Fighter *spawnFighter(char *name, int x, int y, int side); +extern void startSectionTransition(void); +extern void endSectionTransition(void); +extern void playMusic(char *filename); +extern void stopMusic(void); + +extern Battle battle; +extern Fighter *player; diff --git a/src/galaxy/starSystems.c b/src/galaxy/starSystems.c new file mode 100644 index 0000000..4dfd43f --- /dev/null +++ b/src/galaxy/starSystems.c @@ -0,0 +1,196 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "starSystems.h" + +static void loadStarSystem(cJSON *starSystemJSON); +static void loadMissionMeta(char *filename, StarSystem *starSystem); + +void initStarSystems(void) +{ + cJSON *root, *node; + char *text; + + text = readFile("data/galaxy/starSystems.json"); + root = cJSON_Parse(text); + + for (node = cJSON_GetObjectItem(root, "starSystems")->child ; node != NULL ; node = node->next) + { + loadStarSystem(node); + } + + cJSON_Delete(root); + free(text); +} + +static void loadStarSystem(cJSON *starSystemJSON) +{ + cJSON *node; + StarSystem *starSystem; + + starSystem = malloc(sizeof(StarSystem)); + memset(starSystem, 0, sizeof(StarSystem)); + game.starSystemTail->next = starSystem; + game.starSystemTail = starSystem; + + STRNCPY(starSystem->name, cJSON_GetObjectItem(starSystemJSON, "name")->valuestring, MAX_NAME_LENGTH); + starSystem->side = lookup(cJSON_GetObjectItem(starSystemJSON, "side")->valuestring); + starSystem->x = cJSON_GetObjectItem(starSystemJSON, "x")->valueint; + starSystem->y = cJSON_GetObjectItem(starSystemJSON, "y")->valueint; + + starSystem->missionHead.completed = 1; + starSystem->missionTail = &starSystem->missionHead; + + for (node = cJSON_GetObjectItem(starSystemJSON, "missions")->child ; node != NULL ; node = node->next) + { + loadMissionMeta(node->valuestring, starSystem); + } + + starSystem->x *= 3; + starSystem->y *= 3; +} + +static void loadMissionMeta(char *filename, StarSystem *starSystem) +{ + Mission *mission; + Challenge *challenge, *challengeTail; + cJSON *root, *node; + char *text; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", filename); + + text = readFile(filename); + + root = cJSON_Parse(text); + + mission = malloc(sizeof(Mission)); + memset(mission, 0, sizeof(Mission)); + starSystem->missionTail->next = mission; + starSystem->missionTail = mission; + + STRNCPY(mission->name, cJSON_GetObjectItem(root, "name")->valuestring, MAX_NAME_LENGTH); + STRNCPY(mission->description, cJSON_GetObjectItem(root, "description")->valuestring, MAX_DESCRIPTION_LENGTH); + STRNCPY(mission->filename, filename, MAX_DESCRIPTION_LENGTH); + + node = cJSON_GetObjectItem(root, "player"); + + if (node) + { + STRNCPY(mission->pilot, cJSON_GetObjectItem(node, "pilot")->valuestring, MAX_NAME_LENGTH); + STRNCPY(mission->squadron, cJSON_GetObjectItem(node, "squadron")->valuestring, MAX_NAME_LENGTH); + STRNCPY(mission->craft, cJSON_GetObjectItem(node, "type")->valuestring, MAX_NAME_LENGTH); + } + + challengeTail = &mission->challengeHead; + + node = cJSON_GetObjectItem(root, "challenges"); + + if (node) + { + node = node->child; + + while (node) + { + challenge = malloc(sizeof(Challenge)); + memset(challenge, 0, sizeof(Challenge)); + + challenge->type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); + challenge->targetValue = cJSON_GetObjectItem(node, "targetValue")->valueint; + + challengeTail->next = challenge; + challengeTail = challenge; + + node = node->next; + } + } + + cJSON_Delete(root); + free(text); +} + +StarSystem *getStarSystem(char *name) +{ + StarSystem *starSystem; + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + if (strcmp(starSystem->name, name) == 0) + { + return starSystem; + } + } + + return NULL; +} + +void updateStarSystemDescriptions(void) +{ + StarSystem *starSystem; + Mission *mission; + Challenge *challenge; + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + starSystem->completedMissions = starSystem->totalMissions = starSystem->completedChallenges = starSystem->totalChallenges = 0; + + for (mission = starSystem->missionHead.next ; mission != NULL ; mission = mission->next) + { + starSystem->totalMissions++; + + if (mission->completed) + { + starSystem->completedMissions++; + } + + for (challenge = mission->challengeHead.next ; challenge != NULL ; challenge = challenge->next) + { + starSystem->totalChallenges++; + + if (challenge->passed) + { + starSystem->completedChallenges++; + } + } + } + + sprintf(starSystem->description, "[ %s ] [ Missions %d / %d ] [ Challenges %d / %d ]", starSystem->name, starSystem->completedMissions, starSystem->totalMissions, starSystem->completedChallenges, starSystem->totalChallenges); + } +} + +void destroyStarSystems(void) +{ + StarSystem *starSystem; + Mission *mission; + + while (game.starSystemHead.next) + { + starSystem = game.starSystemHead.next; + + while (starSystem->missionHead.next) + { + mission = starSystem->missionHead.next; + starSystem->missionHead.next = mission->next; + free(mission); + } + + game.starSystemHead.next = starSystem->next; + free(starSystem); + } +} diff --git a/src/galaxy/starSystems.h b/src/galaxy/starSystems.h new file mode 100644 index 0000000..48a53b0 --- /dev/null +++ b/src/galaxy/starSystems.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" +#include "../json/cJSON.h" + +extern char *readFile(char *filename); +extern long lookup(char *name); + +extern Game game; diff --git a/src/galaxy/stats.c b/src/galaxy/stats.c new file mode 100644 index 0000000..e7a4da4 --- /dev/null +++ b/src/galaxy/stats.c @@ -0,0 +1,102 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "stats.h" + +void drawStats(void) +{ + int y, hours, minutes, seconds; + SDL_Rect r; + char timePlayed[MAX_NAME_LENGTH]; + + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128); + SDL_RenderFillRect(app.renderer, NULL); + SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); + + r.w = 500; + r.h = 600; + r.x = (SCREEN_WIDTH / 2) - r.w / 2; + r.y = (SCREEN_HEIGHT / 2) - r.h / 2; + + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 0); + SDL_RenderFillRect(app.renderer, &r); + SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255); + SDL_RenderDrawRect(app.renderer, &r); + + drawText(SCREEN_WIDTH / 2, 70, 28, TA_CENTER, colors.white, "Stats"); + + SDL_SetRenderDrawColor(app.renderer, 128, 128, 128, 255); + SDL_RenderDrawLine(app.renderer, r.x, 120, r.x + r.w, 120); + + y = 140; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Missions Started"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.missionsStarted); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Missions Completed"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.missionsCompleted); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Shots Fired"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.shotsFired); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Shots Hit"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.shotsHit); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Missiles Fired"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.missilesFired); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Missiles Hit"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.missilesHit); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Enemies Killed (Player)"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.playerKills); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Enemies Killed (All)"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.enemiesKilled); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Allies Lost"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.alliesKilled); + y += 40; + + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Times Killed"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats.playerKilled); + y += 40; + + seconds = game.stats.time / FPS; + minutes = (seconds / 60) % 60; + hours = seconds / (60 * 60); + + seconds %= 60; + + sprintf(timePlayed, "%dh:%02dm:%02ds", hours, minutes, seconds); + drawText(r.x + 20, y, 18, TA_LEFT, colors.white, "Time Played"); + drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, timePlayed); + + drawWidgets("stats"); +} diff --git a/src/galaxy/stats.h b/src/galaxy/stats.h new file mode 100644 index 0000000..2639869 --- /dev/null +++ b/src/galaxy/stats.h @@ -0,0 +1,33 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern void selectWidget(const char *name, const char *group); +extern Widget *getWidget(const char *name, const char *group); +extern void drawWidgets(char *groupName); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); + +extern App app; +extern Colors colors; +extern Game game; diff --git a/src/game/game.c b/src/game/game.c new file mode 100644 index 0000000..622df15 --- /dev/null +++ b/src/game/game.c @@ -0,0 +1,54 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "game.h" + +void initGame(void) +{ + memset(&game, 0, sizeof(Game)); + + game.starSystemTail = &game.starSystemHead; +} + +void resetGame(void) +{ + StarSystem *starSystem; + Mission *mission; + Challenge *challenge; + + memset(&game.stats, 0, sizeof(Stats)); + + for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) + { + for (mission = starSystem->missionHead.next ; mission != NULL ; mission = mission->next) + { + mission->completed = 0; + + for (challenge = mission->challengeHead.next ; challenge != NULL ; challenge = challenge->next) + { + challenge->passed = 0; + } + } + } +} + +void destroyGame(void) +{ +} diff --git a/src/game/game.h b/src/game/game.h new file mode 100644 index 0000000..56aae6b --- /dev/null +++ b/src/game/game.h @@ -0,0 +1,26 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +extern Game game; diff --git a/src/game/title.c b/src/game/title.c new file mode 100644 index 0000000..3d17a92 --- /dev/null +++ b/src/game/title.c @@ -0,0 +1,235 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "title.h" + +static void logic(void); +static void draw(void); +static void handleKeyboard(void); +static void initFighters(void); +static void doFighters(void); +static void drawFighters(void); +static void newGame(void); +static void continueGame(void); +static void options(void); +static void quit(void); +static void returnFromOptions(void); + +static SDL_Texture *background; +static SDL_Texture *logo; +static SDL_Texture *pandoranWar; +static SDL_Texture *earthTexture; +static PointF earth; +static Fighter fighters[NUM_FIGHTERS]; +static const char *fighterTextures[] = {"gfx/fighters/firefly.png", "gfx/fighters/hammerhead.png", "gfx/fighters/hyena.png", "gfx/fighters/khepri.png", "gfx/fighters/kingfisher.png", "gfx/fighters/leopard.png", "gfx/fighters/nymph.png", "gfx/fighters/ray.png", "gfx/fighters/rook.png", "gfx/fighters/taf.png"}; +static int showingOptions; + +void initTitle(void) +{ + startSectionTransition(); + + stopMusic(); + + app.delegate.logic = &logic; + app.delegate.draw = &draw; + memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + battle.ssx = battle.ssy = 0; + + destroyBattle(); + + logo = getTexture("gfx/title/logo.png"); + + pandoranWar = getTexture("gfx/title/pandoran.png"); + + background = getTexture("gfx/backgrounds/background02.jpg"); + + earthTexture = getTexture("gfx/planets/earth.png"); + + earth.x = rand() % SCREEN_WIDTH; + earth.y = -(128 + (rand() % 128)); + + initBackground(); + + initFighters(); + + selectWidget("newGame", "title"); + getWidget("newGame", "title")->action = newGame; + getWidget("continue", "title")->action = continueGame; + getWidget("options", "title")->action = options; + getWidget("quit", "title")->action = quit; + + showingOptions = 0; + + endSectionTransition(); + + playMusic("music/Rise of spirit.ogg"); +} + +static void initFighters(void) +{ + int i, numTextures; + + numTextures = sizeof(fighterTextures) / sizeof(char*); + + memset(&fighters, 0, sizeof(Fighter) * NUM_FIGHTERS); + + for (i = 0 ; i < NUM_FIGHTERS ; i++) + { + fighters[i].x = rand() % (SCREEN_WIDTH - 64); + fighters[i].y = SCREEN_HEIGHT + (rand() % SCREEN_HEIGHT); + fighters[i].texture = getTexture(fighterTextures[rand() % numTextures]); + fighters[i].dy = -(1 + rand() % 3); + } +} + +static void logic(void) +{ + handleKeyboard(); + + scrollBackground(0, 0.25); + + doStars(0, -0.5); + + earth.y += 0.1; + + if (earth.y > SCREEN_HEIGHT + 128) + { + earth.x = rand() % SCREEN_WIDTH; + earth.y = -(128 + (rand() % 128)); + } + + doFighters(); + + doEffects(); + + doWidgets(); +} + +static void doFighters(void) +{ + int i; + + for (i = 0 ; i < NUM_FIGHTERS ; i++) + { + fighters[i].y += fighters[i].dy; + + self = &fighters[i]; + + addEngineEffect(); + + if (fighters[i].y <= -64) + { + fighters[i].x = rand() % (SCREEN_WIDTH - 64); + fighters[i].y = SCREEN_HEIGHT + (rand() % SCREEN_HEIGHT); + } + } +} + +static void draw(void) +{ + prepareScene(); + + drawBackground(background); + + drawStars(); + + blit(earthTexture, earth.x, earth.y, 1); + + drawFighters(); + + drawEffects(); + + blit(logo, SCREEN_WIDTH / 2, 50, 1); + + blit(pandoranWar, SCREEN_WIDTH / 2, 110, 1); + + drawText(10, SCREEN_HEIGHT - 25, 14, TA_LEFT, colors.white, "Copyright Parallel Realities, 2015"); + drawText(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 25, 14, TA_RIGHT, colors.white, "Version %.2f-%d", VERSION, RELEASE); + + if (!showingOptions) + { + drawWidgets("title"); + } + else + { + drawOptions(); + } + + presentScene(); +} + +static void drawFighters(void) +{ + int i; + + for (i = 0 ; i < NUM_FIGHTERS ; i++) + { + blit(fighters[i].texture, fighters[i].x, fighters[i].y, 1); + } +} + +static void handleKeyboard(void) +{ + if (app.keyboard[SDL_SCANCODE_ESCAPE]) + { + returnFromOptions(); + + memset(app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); + + playSound(SND_GUI_CLOSE); + } +} + +static void newGame(void) +{ + resetGame(); + + initGalacticMap(); +} + +static void continueGame(void) +{ + if (fileExists(getSaveFilePath("game.save"))) + { + loadGame(); + } + + initGalacticMap(); +} + +static void options(void) +{ + showingOptions = 1; + + initOptions(returnFromOptions); +} + +static void returnFromOptions(void) +{ + showingOptions = 0; + + selectWidget("newGame", "title"); +} + +static void quit(void) +{ + exit(1); +} diff --git a/src/game/title.h b/src/game/title.h new file mode 100644 index 0000000..77e2535 --- /dev/null +++ b/src/game/title.h @@ -0,0 +1,63 @@ +/* +Copyright (C) 2015 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "SDL2/SDL.h" + +#include "../defs.h" +#include "../structs.h" + +#define NUM_FIGHTERS 12 + +extern void prepareScene(void); +extern void presentScene(void); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern SDL_Texture *getTexture(const char *filename); +extern void startSectionTransition(void); +extern void endSectionTransition(void); +extern void blit(SDL_Texture *t, int x, int y, int centered); +extern void stopMusic(void); +extern void doStars(float dx, float dy); +extern void drawStars(void); +extern void drawBackground(SDL_Texture *texture); +extern void initBackground(void); +extern void scrollBackground(float x, float y); +extern void addEngineEffect(void); +extern void doEffects(void); +extern void drawEffects(void); +extern void drawWidgets(char *groupName); +extern void doWidgets(void); +extern Widget *getWidget(const char *name, const char *group); +extern void selectWidget(const char *name, const char *group); +extern void loadGame(void); +extern int fileExists(char *filename); +extern void resetGame(void); +extern void initGalacticMap(void); +extern void initOptions(void (*returnFromOptions)(void)); +extern void drawOptions(void); +extern char *getSaveFilePath(char *filename); +extern void playMusic(char *filename); +extern void destroyBattle(void); +extern void playSound(int id); + +extern App app; +extern Battle battle; +extern Colors colors; +extern Game game; +extern Fighter *self; diff --git a/src/json/cJSON.c b/src/json/cJSON.c new file mode 100644 index 0000000..46cbf72 --- /dev/null +++ b/src/json/cJSON.c @@ -0,0 +1,750 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include