diff --git a/CHANGELOG b/CHANGELOG index eb6924b..1d2f1b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,18 @@ Changelog +0.7 + + * Added trophies + * New campaign missions + * New challenges + * Added new INF fighter: the Angel (rarely used) + * Messagebox speakers are now highlighted + * New Capital Ships + 0.6 * New Campaign missions - * Added new fighters: Blizzard, Razor, Shale, SK-31, and SK-34, part of the troublesome Nation of Tzac + * Added new fighters: Blizzard, Razor, Shale, SK-31, and SK-34, part of the troublesome Kingdom of Tzac * Added control remapping * Added mines * New game mode: Challenges diff --git a/README.md b/README.md index 35db3f7..cf040b1 100644 --- a/README.md +++ b/README.md @@ -2,74 +2,90 @@ 2D mission-based space shooter, based on the Battle for the Solar System space opera novel trilogy. -The develop branch on GitHub (https://github.com/stephenjsweeney/tbftss) is where all the dev work happens. Stable(ish) releases will go in to master. +The develop branch on GitHub (https://github.com/stephenjsweeney/tbftss/tree/develop) is where all the dev work happens. Stable(ish) releases will go in to master (https://github.com/stephenjsweeney/tbftss/tree/master). You can support development of this game by purchasing one of the books in the trilogy: www.battleforthesolarsystem.com/purchase/ Website: www.battleforthesolarsystem.com Email: stephenjsweeney@battleforthesolarsystem.com +## SCREENSHOTS + +Screenshots from various versions can be found here: https://github.com/stephenjsweeney/tbftss/tree/master/dev/screenshots + ## CREDITS ### GRAPHICS -gfx/planets/earth.png - modified from the the Blue Marble NASA photograph: http://visibleearth.nasa.gov/view.php?id=57723 +gfx/planets/earth.png - derived from the the Blue Marble NASA photograph: http://visibleearth.nasa.gov/view.php?id=57723 +gfx/trophies/bronze.png - dervied from Trophy icon, by Lorc (CC BY 3.0): http://game-icons.net/lorc/originals/trophy.html +gfx/trophies/gold.png - dervied from Trophy icon, by Lorc (CC BY 3.0): http://game-icons.net/lorc/originals/trophy.html +gfx/trophies/platinum.png - dervied from Trophy icon, by Lorc (CC BY 3.0): http://game-icons.net/lorc/originals/trophy.html +gfx/trophies/silver.png - dervied from Trophy icon, by Lorc (CC BY 3.0): http://game-icons.net/lorc/originals/trophy.html +gfx/trophies/unearned.png - dervied from Trophy icon, by Lorc (CC BY 3.0): http://game-icons.net/lorc/originals/trophy.html All other graphics are CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J Sweeney | www.battleforthesolarsystem.com -### DATA FILES (with the exception of Roboto font) +### DATA FILES -CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J Sweeney | www.battleforthesolarsystem.com +data/fonts/Roboto-Medium.ttf, by Christian Robertson. Licensed under the Apache License, version 2.0 + +All other data files are CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J Sweeney | www.battleforthesolarsystem.com ### SOUND -* 000000_large_explosion.ogg - created by combining https://freesound.org/people/dkmedic/sounds/104447/ and https://freesound.org/people/CGEffex/sounds/100772/ -* 18380__inferno__hvrl.ogg - hvrl, by inferno - https://freesound.org/people/inferno/sounds/18380/ -* 18382__inferno__hvylas.ogg - hvylas, by inferno - https://freesound.org/people/inferno/sounds/18382/ -* 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/ -* 49678__ejfortin__energy-short-sword-7.ogg - Energy Short Sword, by ejfortin - https://freesound.org/people/ejfortin/sounds/49678/ -* 56246__q-k__latch-04.ogg - Latch_04, by Q.K. - https://freesound.org/people/Q.K./sounds/56246/ -* 65787__iwilldstroyu__laserrocket.ogg - laserrocket, by iwilldstroyu - https://freesound.org/people/iwilldstroyu/sounds/65787/ -* 77087__supraliminal__laser-short.ogg - Laser short, by Supraliminal - https://freesound.org/people/Supraliminal/sounds/77087/ -* 88275__s-dij__gbc-reload-06.ogg - GBC_Reload_06, by S_Dij - https://freesound.org/people/S_Dij/sounds/88275/ -* 146725__fins__laser.ogg - laser, by fins - https://freesound.org/people/fins/sounds/146725/ -* 162265__qubodup__explosive.ogg - Explosive, by qubodup - https://freesound.org/people/qubodup/sounds/162265/ -* 178064__jorickhoofd__slam-door-shut.ogg - Slam door shut, by jorickhoofd - https://freesound.org/people/jorickhoofd/sounds/178064/ -* 207322__animationisaac__short-explosion.ogg - Short explosion, by animationIsaac - https://freesound.org/people/animationIsaac/sounds/207322/ -* 242856__plasterbrain__nuclear-alarm.ogg - Nuclear Alarm, by plasterbrain - https://freesound.org/people/plasterbrain/sounds/242856/ -* 249300__suntemple__access-denied.ogg - Access Denied, by suntemple - https://freesound.org/people/suntemple/sounds/249300/ -* 254071__tb0y298__firework-explosion.ogg - Firework Explosion, by TB0Y298 - https://freesound.org/people/TB0Y298/sounds/254071/ -* 257786__xtrgamr__mouse-click.ogg - Mouse click, by xtrgamr - https://freesound.org/people/xtrgamr/sounds/257786/ -* 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/ -* 321104__nsstudios__blip2.ogg - blip2, by nsstudios - https://freesound.org/people/nsstudios/sounds/321104/ -* 321906__bruce965__walkie-talkie-roger-beep.ogg - Walkie Talkie - Roger Beep, by bruce965 - https://freesound.org/people/bruce965/sounds/321906/ -* 322603__clippysounds__glass-break.ogg - Glass Break, by clippysounds - https://freesound.org/people/clippysounds/sounds/322603/ -* 276912__pauldihor__transform.ogg - transform, by PaulDihor - https://freesound.org/people/PaulDihor/sounds/276912/ -* 329359__bassoonrckr__reed-guillotine.ogg - Bassoon Reed Making Tool Sounds, by Reed Guillotine.wav - https://freesound.org/people/bassoonrckr/sounds/329359/ -* 251431__onlytheghosts__fusion-gun-flash0-by-onlytheghosts.ogg - fusion-gun_flash0_by_OnlyTheGhosts.wav, by OnlyTheGhosts - https://freesound.org/people/OnlyTheGhosts/sounds/251431/ -* 172591__timbre__zapitydooda.ogg - d1clsstf.wav, by wildweasel - https://freesound.org/people/wildweasel/sounds/39030/ -* 39030__wildweasel__d1clsstf.ogg - push_button_switch_07.wav, by joedeshon - https://freesound.org/people/joedeshon/sounds/139061/ -* 278142__ricemaster__effect-notify.ogg - effect_notify.wav, by ricemaster - https://freesound.org/people/ricemaster/sounds/278142/ -* 254174__kwahmah-02__s.ogg - s.wav, by kwahmah_02 - https://freesound.org/people/kwahmah_02/sounds/254174/ -* 172870__escortmarius__carbidexplosion.ogg - carbidexplosion.wav, by escortmarius - https://freesound.org/people/escortmarius/sounds/172870/ -* 320181__dland__hint.ogg - hint.wav, by dland - https://freesound.org/people/dland/sounds/320181/ +* 000000_large_explosion.ogg - created by combining + * EXPLODE.WAV, by dkmedic (CC-0) - https://freesound.org/people/dkmedic/sounds/104447/ + * Huge rocket launcher.wav, by CGEffex (CC-BY) https://freesound.org/people/CGEffex/sounds/100772/ +* 18380__inferno__hvrl.ogg - hvrl, by inferno (CC-Sampling+) - https://freesound.org/people/inferno/sounds/18380/ +* 18382__inferno__hvylas.ogg - hvylas, by inferno (CC-Sampling+) - https://freesound.org/people/inferno/sounds/18382/ +* 42106__marcuslee__laser-wrath-4.ogg - Laser Wrath 4, by marcusless (CC-Sampling+) - https://freesound.org/people/marcuslee/sounds/42106/ +* 47252__nthompson__bad-explosion.ogg - bad explosion, by nthompson (CC-0) - https://freesound.org/people/nthompson/sounds/47252/ +* 49678__ejfortin__energy-short-sword-7.ogg - Energy Short Sword, by ejfortin (CC-Sampling+) - https://freesound.org/people/ejfortin/sounds/49678/ +* 56246__q-k__latch-04.ogg - Latch_04, by Q.K. (CC-0) - https://freesound.org/people/Q.K./sounds/56246/ +* 65787__iwilldstroyu__laserrocket.ogg - laserrocket, by iwilldstroyu (CC-0) - https://freesound.org/people/iwilldstroyu/sounds/65787/ +* 77087__supraliminal__laser-short.ogg - Laser short, by Supraliminal (CC-0) - https://freesound.org/people/Supraliminal/sounds/77087/ +* 88275__s-dij__gbc-reload-06.ogg - GBC_Reload_06, by S_Dij (CC-BY) - https://freesound.org/people/S_Dij/sounds/88275/ +* 146725__fins__laser.ogg - laser, by fins (CC-0) - https://freesound.org/people/fins/sounds/146725/ +* 162265__qubodup__explosive.ogg - Explosive, by qubodup (CC-0) - https://freesound.org/people/qubodup/sounds/162265/ +* 178064__jorickhoofd__slam-door-shut.ogg - Slam door shut, by jorickhoofd (CC-BY) - https://freesound.org/people/jorickhoofd/sounds/178064/ +* 207322__animationisaac__short-explosion.ogg - Short explosion, by animationIsaac (CC-0) - https://freesound.org/people/animationIsaac/sounds/207322/ +* 242856__plasterbrain__nuclear-alarm.ogg - Nuclear Alarm, by plasterbrain (CC-0) - https://freesound.org/people/plasterbrain/sounds/242856/ +* 249300__suntemple__access-denied.ogg - Access Denied, by suntemple (CC-0) - https://freesound.org/people/suntemple/sounds/249300/ +* 254071__tb0y298__firework-explosion.ogg - Firework Explosion, by TB0Y298 (CC-BY) - https://freesound.org/people/TB0Y298/sounds/254071/ +* 257786__xtrgamr__mouse-click.ogg - Mouse click, by xtrgamr (CC-BY) - https://freesound.org/people/xtrgamr/sounds/257786/ +* 263621__jamesabdulrahman__permission-to-panic.ogg - Permission to panic?, by jamesabdulrahman (CC-BY) - https://freesound.org/people/jamesabdulrahman/sounds/263621/ +* 268344__julien-matthey__jm-noiz-laser-01.ogg - JM_NOIZ_Laser 01.wav, by Julien Matthey (CC-0) - https://freesound.org/people/Julien%20Matthey/sounds/268344/ +* 275151__bird-man__gun-shot.ogg - Gun Shot.wav, by Bird_man (CC-0) - https://freesound.org/people/Bird_man/sounds/275151/ +* 321104__nsstudios__blip2.ogg - blip2, by nsstudios (CC-BY) - https://freesound.org/people/nsstudios/sounds/321104/ +* 321906__bruce965__walkie-talkie-roger-beep.ogg - Walkie Talkie - Roger Beep, by bruce965 (CC-0) - https://freesound.org/people/bruce965/sounds/321906/ +* 322603__clippysounds__glass-break.ogg - Glass Break, by clippysounds (CC-BY) - https://freesound.org/people/clippysounds/sounds/322603/ +* 276912__pauldihor__transform.ogg - transform, by PaulDihor (CC-0) - https://freesound.org/people/PaulDihor/sounds/276912/ +* 329359__bassoonrckr__reed-guillotine.ogg - Reed Guillotine.wav, by bassoonrckr (CC-0) - https://freesound.org/people/bassoonrckr/sounds/329359/ +* 251431__onlytheghosts__fusion-gun-flash0-by-onlytheghosts.ogg - fusion-gun_flash0_by_OnlyTheGhosts.wav, by OnlyTheGhosts (CC-BY) - https://freesound.org/people/OnlyTheGhosts/sounds/251431/ +* 172591__timbre__zapitydooda.ogg - d1clsstf.wav, by wildweasel (CC-BY) - https://freesound.org/people/wildweasel/sounds/39030/ +* 39030__wildweasel__d1clsstf.ogg - push_button_switch_07.wav, by joedeshon (CC-BY) - https://freesound.org/people/joedeshon/sounds/139061/ +* 278142__ricemaster__effect-notify.ogg - effect_notify.wav, by ricemaster (CC-0) - https://freesound.org/people/ricemaster/sounds/278142/ +* 254174__kwahmah-02__s.ogg - s.wav, by kwahmah_02 (CC-0) - https://freesound.org/people/kwahmah_02/sounds/254174/ +* 172870__escortmarius__carbidexplosion.ogg - carbidexplosion.wav, by escortmarius (CC-BY) - https://freesound.org/people/escortmarius/sounds/172870/ +* 320181__dland__hint.ogg - hint.wav, by dland (CC-0) - https://freesound.org/people/dland/sounds/320181/ ### 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 -* InnerCore_Low.ogg - Gundatsch - https://soundcloud.com/gundatsch -* 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 -* track-1.mp3, by Alexandr Zhelanov - https://soundcloud.com/alexandr-zhelanov -* track-3.mp3, by Alexandr Zhelanov - https://soundcloud.com/alexandr-zhelanov -* track-4.mp3, by Alexandr Zhelanov - https://soundcloud.com/alexandr-zhelanov -* DST-RailJet-LongSeamlessLoop.ogg, by Deceased Superior Technician - http://opengameart.org/content/railjet-long-seamless-loop -* covert_operations.mp3, by artisticdude - http://opengameart.org/content/covert-operations -* Tactical Pursuit.mp3, by Matthew Pablo - http://opengameart.org/content/tactical-pursuit +* Battle in the winter.mp3, by Johan Brodd (CC-BY) - http://opengameart.org/content/battle-in-the-winter +* battleThemeA.mp3, by cynicmusic.com | pixelsphere.org (CC-0) - http://opengameart.org/content/battle-theme-a +* determination.mp3, by artisticdude (CC-0) - http://opengameart.org/content/determination +* heroism.ogg, by Edward J. Blakeley (GPL 3.0) - http://opengameart.org/content/heroism +* InnerCore_Low.ogg - Gundatsch (CC-BY) - https://soundcloud.com/gundatsch +* Pressure.ogg, by yd (CC-0) - http://opengameart.org/content/pressure +* Rise of Spirit, by Alexandr Zhelanov (CC-0) - https://soundcloud.com/alexandr-zhelanov +* Showdown.mp3, by el-corleo (CC-BY) - http://opengameart.org/content/showdown +* track-3.mp3, by Alexandr Zhelanov (CC-BY) - https://soundcloud.com/alexandr-zhelanov +* track-4.mp3, by Alexandr Zhelanov (CC-BY) - https://soundcloud.com/alexandr-zhelanov +* DST-RailJet-LongSeamlessLoop.ogg, by Deceased Superior Technician (CC-BY) - http://opengameart.org/content/railjet-long-seamless-loop +* covert_operations.mp3, by artisticdude (CC-0) - http://opengameart.org/content/covert-operations +* Tactical Pursuit.mp3, by Matthew Pablo (CC-BY) - http://opengameart.org/content/tactical-pursuit + +## ABOUT + +This is a work of fiction. Names, characters, businesses, places, events and incidents are either the products of the author's imagination or used in a fictitious manner. Any resemblance to actual persons, living or dead, or actual events is purely coincidental. The Battle for the Solar System : The Pandoran War is © 2015-2016, Stephen J Sweeney, All Rights Reserved. The Battle for the Solar System and all related materials (including, but not limited to, characters, setting, and story elements) are © 2009-2016, Stephen J Sweeney, All Rights Reserved. diff --git a/STATS.md b/STATS.md new file mode 100644 index 0000000..35dc384 --- /dev/null +++ b/STATS.md @@ -0,0 +1,17 @@ +# Statistics + +* Lines of code: 17876 +* Size of source: 548K +* Size of data: 622K +* Size of graphics: 3.6M +* Size of sound: 638K +* Size of music: 51M + +* Number of missions: 65 (inc. Sol) +* Number of challenges: 66 +* Number of spacecraft: 49 +* Number of trophies: 39 + +* Translatable strings: 770 + +* Number of GIT revisions: 1133 diff --git a/common.mk b/common.mk index e79496f..a1f0bef 100644 --- a/common.mk +++ b/common.mk @@ -1,4 +1,4 @@ -VERSION = 0.6 +VERSION = 0.7 REVISION = $(shell date +"%y%m%d") LOCALE_MO = $(patsubst %.po,%.mo,$(wildcard locale/*.po)) diff --git a/data/app/config.json b/data/app/config.json index 8642c09..3f0ccb9 100644 --- a/data/app/config.json +++ b/data/app/config.json @@ -33,5 +33,11 @@ "CONTROL_NEXT_FIGHTER" : 5, "CONTROL_SCREENSHOT" : 0 } + }, + "gameplay" : { + "friendlyFire" : 0, + "autoSwitchPlayerTarget" : 1, + "missileReTarget" : 0, + "healthBars" : 1 } } diff --git a/data/battle/items.json b/data/battle/items.json index cb4ed55..0fd98d9 100644 --- a/data/battle/items.json +++ b/data/battle/items.json @@ -1,10 +1,67 @@ [ { - "name" : "crate", + "defName" : "crate", + "name" : "a crate", "texture" : "gfx/items/crate.png" }, { - "name" : "smallCrate", + "defName" : "smallCrate", + "name" : "a small crate", "texture" : "gfx/items/smallCrate.png" + }, + { + "defName" : "powerCore01", + "name" : "a power core", + "texture" : "gfx/items/powerCore01.png" + }, + { + "defName" : "powerCore02", + "name" : "a power core", + "texture" : "gfx/items/powerCore02.png" + }, + { + "defName" : "powerCore03", + "name" : "a power core", + "texture" : "gfx/items/powerCore03.png" + }, + { + "defName" : "coin01", + "name" : "a coin", + "texture" : "gfx/items/coin01.png" + }, + { + "defName" : "coin02", + "name" : "a coin", + "texture" : "gfx/items/coin02.png" + }, + { + "defName" : "diamond01", + "name" : "a diamond", + "texture" : "gfx/items/diamond01.png" + }, + { + "defName" : "diamond02", + "name" : "a diamond", + "texture" : "gfx/items/diamond02.png" + }, + { + "defName" : "diamond03", + "name" : "a diamond", + "texture" : "gfx/items/diamond03.png" + }, + { + "defName" : "gem01", + "name" : "a gem", + "texture" : "gfx/items/gem01.png" + }, + { + "defName" : "gem02", + "name" : "a gem", + "texture" : "gfx/items/gem02.png" + }, + { + "defName" : "gem03", + "name" : "a gem", + "texture" : "gfx/items/gem03.png" } ] diff --git a/data/capitalShips/hmsCorvette01.json b/data/capitalShips/hmsCorvette01.json new file mode 100644 index 0000000..3b9d0d5 --- /dev/null +++ b/data/capitalShips/hmsCorvette01.json @@ -0,0 +1,156 @@ +{ + "name" : "HMS Corvette 01", + "health" : 0, + "shield" : 500, + "shieldRechargeRate" : 60, + "texture" : "gfx/capitalShips/hmsCorvette01/body.png", + "components" : [ + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette01/core.png", + "x" : 0, + "y" : -140, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component1.png", + "x" : 16, + "y" : -38, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component1.png", + "x" : -16, + "y" : -38, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component2.png", + "x" : -44, + "y" : 4, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component2.png", + "x" : 44, + "y" : 4, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component2.png", + "x" : 43, + "y" : 75, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette01/component2.png", + "x" : -43, + "y" : 75, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + } + ], + "engines" : [ + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette01/engine1.png", + "x" : -112, + "y" : 295, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette01/engine1.png", + "x" : 112, + "y" : 295, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette01/engine2.png", + "x" : -25, + "y" : 120, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette01/engine3.png", + "x" : 25, + "y" : 120, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + } + ], + "guns" : [ + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : -75, + "y" : -50, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 75, + "y" : -50, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : -125, + "y" : 200, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 125, + "y" : 200, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 0, + "y" : -250, + "reloadTime" : 40, + "type" : "BT_ROCKET", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 0, + "y" : 70, + "reloadTime" : 40, + "type" : "BT_ROCKET", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + } + ] +} diff --git a/data/capitalShips/hmsCorvette02.json b/data/capitalShips/hmsCorvette02.json new file mode 100644 index 0000000..01f9dab --- /dev/null +++ b/data/capitalShips/hmsCorvette02.json @@ -0,0 +1,156 @@ +{ + "name" : "HMS Corvette 02", + "health" : 0, + "shield" : 500, + "shieldRechargeRate" : 60, + "texture" : "gfx/capitalShips/hmsCorvette02/body.png", + "components" : [ + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette02/core.png", + "x" : 0, + "y" : -110, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component1.png", + "x" : -28, + "y" : -16, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component1.png", + "x" : 28, + "y" : -16, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component2.png", + "x" : -182, + "y" : -40, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component2.png", + "x" : 182, + "y" : -40, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component3.png", + "x" : -122, + "y" : 165, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 100, + "texture" : "gfx/capitalShips/hmsCorvette02/component3.png", + "x" : 122, + "y" : 165, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + } + ], + "engines" : [ + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette02/engine01.png", + "x" : -125, + "y" : 200, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette02/engine01.png", + "x" : 125, + "y" : 200, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette02/engine01.png", + "x" : -178, + "y" : 20, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + }, + { + "health" : 150, + "texture" : "gfx/capitalShips/hmsCorvette02/engine01.png", + "x" : 178, + "y" : 20, + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_STATIC" + } + ], + "guns" : [ + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : -218, + "y" : -90, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 218, + "y" : -90, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : -200, + "y" : 150, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 200, + "y" : 150, + "reloadTime" : 10, + "type" : "BT_PLASMA", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : -50, + "y" : -120, + "reloadTime" : 40, + "type" : "BT_ROCKET", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + }, + { + "health" : 250, + "texture" : "gfx/capitalShips/common/cannon01.png", + "x" : 50, + "y" : -120, + "reloadTime" : 40, + "type" : "BT_ROCKET", + "flags" : "EF_NO_MT_BOX+EF_NO_KILL_INC+EF_TAKES_DAMAGE+EF_SECONDARY_TARGET", + "aiFlags" : "AIF_AGGRESSIVE+AIF_LONG_RANGE_FIRE", + "missiles" : 9999 + } + ] +} diff --git a/data/challenges/01.json b/data/challenges/01.json index 0d6042d..378035c 100644 --- a/data/challenges/01.json +++ b/data/challenges/01.json @@ -1,6 +1,6 @@ { - "name" : "Destroy all Darts", - "description" : "Destroy all Darts", + "name" : "Destroy all Darts #1", + "description" : "Destroy all Darts #1", "background" : "AUTO", "planet" : "AUTO", "music" : "AUTO", diff --git a/data/challenges/02.json b/data/challenges/02.json index 1fe703a..32efc63 100644 --- a/data/challenges/02.json +++ b/data/challenges/02.json @@ -1,6 +1,6 @@ { - "name" : "Destroy all Darts", - "description" : "Destroy all Darts", + "name" : "Destroy all Darts #2", + "description" : "Destroy all Darts #2", "background" : "AUTO", "planet" : "AUTO", "music" : "AUTO", diff --git a/data/challenges/03.json b/data/challenges/03.json index b0a0652..3907207 100644 --- a/data/challenges/03.json +++ b/data/challenges/03.json @@ -1,6 +1,6 @@ { - "name" : "Destroy all Darts", - "description" : "Destroy all Darts", + "name" : "Destroy all Darts #3", + "description" : "Destroy all Darts #3", "background" : "AUTO", "planet" : "AUTO", "music" : "AUTO", diff --git a/data/challenges/15.json b/data/challenges/15.json new file mode 100644 index 0000000..2cdb845 --- /dev/null +++ b/data/challenges/15.json @@ -0,0 +1,84 @@ +{ + "name" : "Piracy", + "description" : "Piracy", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Dart", + "side" : "SIDE_PIRATE", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25, + "flags" : "+EF_COLLECTS_ITEMS" + }, + "challenge" : { + "timeLimit" : 300, + "itemLimit" : 25, + "allowPlayerDeath" : 1, + "challenges" : [ + { + "type" : "CHALLENGE_ITEMS", + "value" : 25 + }, + { + "type" : "CHALLENGE_TIME", + "value" : 240 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 15 + } + ] + }, + "spawners" : [ + { + "name" : "spawner", + "types" : "Shuttle", + "side" : "SIDE_ALLIES", + "interval" : 10, + "total" : -1, + "step" : 2, + "offscreen" : 1, + "flags" : "+EF_DROPS_ITEMS+EF_MISSION_TARGET", + "aiFlags" : "AIF_DEFENSIVE" + }, + { + "name" : "spawner", + "types" : "Dart", + "side" : "SIDE_PIRATE", + "interval" : 5, + "total" : -1, + "step" : 1, + "offscreen" : 1, + "flags" : "+EF_COLLECTS_ITEMS", + "aiFlags" : "+AIF_UNLIMITED_RANGE+AIF_COLLECTS_ITEMS" + }, + { + "name" : "tafSpawner", + "types" : "TAF", + "side" : "SIDE_ALLIES", + "interval" : 12, + "total" : -1, + "step" : 1, + "offscreen" : 1, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Boss;Blow apart those shuttles and grab the spoils before the CSN gets here. No fighting over the packages, you dogs, this is a team effort." + ] + }, + { + "function" : "TIME 10", + "lines" : [ + "ACTIVATE_SPAWNER 1 tafSpawner" + ] + } + ] +} diff --git a/data/challenges/16.json b/data/challenges/16.json new file mode 100644 index 0000000..1dc6725 --- /dev/null +++ b/data/challenges/16.json @@ -0,0 +1,55 @@ +{ + "name" : "Swelling the Ranks", + "description" : "Swelling the Ranks", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Scarab", + "side" : "SIDE_PANDORAN", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "timeLimit" : 240, + "challenges" : [ + { + "type" : "CHALLENGE_TIME", + "value" : 120 + }, + { + "type" : "CHALLENGE_ROCKET_ACCURACY", + "value" : 75 + }, + { + "type" : "CHALLENGE_ARMOUR", + "value" : 80 + } + ] + }, + "capitalShips" : [ + { + "name" : "CSN Denier", + "types" : "CSN Corvette 01", + "side" : "SIDE_ALLIES", + "x" : 20, + "y" : 25 + } + ], + "script" : [ + { + "function" : "CAP_DISABLED CSN Denier", + "lines" : [ + "END_CHALLENGE" + ] + }, + { + "function" : "CAPITAL_SHIPS_DESTROYED 1", + "lines" : [ + "FAIL_CHALLENGE" + ] + } + ] +} diff --git a/data/challenges/17.json b/data/challenges/17.json new file mode 100644 index 0000000..268b2ba --- /dev/null +++ b/data/challenges/17.json @@ -0,0 +1,73 @@ +{ + "name" : "Most Wanted", + "description" : "Most Wanted", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Shale", + "side" : "SIDE_REBEL", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25, + "flags" : "+EF_MUST_DISABLE+EF_RETREATING" + }, + "challenge" : { + "timeLimit" : 120, + "challenges" : [ + { + "type" : "CHALLENGE_TIME", + "value" : 120 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 2 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 3 + } + ] + }, + "entities" : [ + { + "type" : "ET_JUMPGATE", + "side" : "SIDE_NONE", + "x" : 25, + "y" : 25, + "flags" : "EF_DISABLED+EF_NO_HEALTH_BAR" + } + ], + "spawners" : [ + { + "name" : "spawner", + "types" : "Ray", + "side" : "SIDE_ALLIES", + "interval" : 15, + "total" : 8, + "step" : 1, + "offscreen" : 1 + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Help;The jumpgate will come online in just under 2 minutes, for 5 SECONDS ONLY! Evade the CSN until then." + ] + }, + { + "function" : "TIME 114", + "lines" : [ + "ACTIVATE_JUMPGATE 1" + ] + }, + { + "function" : "TIME 119", + "lines" : [ + "ACTIVATE_JUMPGATE 0" + ] + } + ] +} diff --git a/data/challenges/18.json b/data/challenges/18.json new file mode 100644 index 0000000..49af697 --- /dev/null +++ b/data/challenges/18.json @@ -0,0 +1,72 @@ +{ + "name" : "Solo Patrol", + "description" : "Solo Patrol", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "waypointAutoAdvance" : 1, + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "timeLimit" : 240, + "waypointLimit" : 5, + "clearWaypointEnemies" : 1, + "challenges" : [ + { + "type" : "CHALLENGE_TIME", + "value" : 240 + }, + { + "type" : "CHALLENGE_TIME", + "value" : 180 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 19 + } + ] + }, + "spawners" : [ + { + "name" : "spawner", + "types" : "Dart", + "side" : "SIDE_PIRATE", + "interval" : 12, + "total" : -1, + "step" : 1, + "offscreen" : 1, + "aiFlags" : "AIF_UNLIMITED_RANGE", + "active" : 0 + } + ], + "entities" : [ + { + "type" : "ET_WAYPOINT", + "x" : 25, + "y" : 25, + "scatter" : 10000, + "number" : 5, + "active" : 0 + } + ], + "script" : [ + { + "function" : "Waypoint #1", + "lines" : [ + "ACTIVATE_SPAWNER 1 spawner" + ] + }, + { + "function" : "Waypoint #5", + "lines" : [ + "ACTIVATE_SPAWNER 0 spawner" + ] + } + ] +} diff --git a/data/challenges/19.json b/data/challenges/19.json new file mode 100644 index 0000000..349f1ae --- /dev/null +++ b/data/challenges/19.json @@ -0,0 +1,46 @@ +{ + "name" : "Set Phasers to Stun", + "description" : "Set Phasers to Stun", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Angel", + "side" : "SIDE_PANDORAN", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "allowPlayerDeath" : 1, + "disableLimit" : 5, + "timeLimit" : 180, + "eliminateThreats" : 1, + "challenges" : [ + { + "type" : "CHALLENGE_DISABLE", + "value" : 2 + }, + { + "type" : "CHALLENGE_DISABLE", + "value" : 4 + }, + { + "type" : "CHALLENGE_DISABLE", + "value" : 5 + } + ] + }, + "fighters" : [ + { + "types" : "Khepri", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "scatter" : 12000, + "number" : 5, + "aiFlags" : "+AIF_UNLIMITED_RANGE+AIF_DROPS_MINES" + } + ] +} diff --git a/data/challenges/20.json b/data/challenges/20.json new file mode 100644 index 0000000..96b800f --- /dev/null +++ b/data/challenges/20.json @@ -0,0 +1,43 @@ +{ + "name" : "No survivors", + "description" : "No survivors", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Scarab", + "side" : "SIDE_PANDORAN", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "killLimit" : 25, + "timeLimit" : 210, + "challenges" : [ + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 20 + }, + { + "type" : "CHALLENGE_PLAYER_KILLS", + "value" : 25 + }, + { + "type" : "CHALLENGE_ROCKET_ACCURACY", + "value" : 80 + } + ] + }, + "fighters" : [ + { + "types" : "Civilian", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "scatter" : 5000, + "number" : 25 + } + ] +} diff --git a/data/challenges/21.json b/data/challenges/21.json new file mode 100644 index 0000000..f16f569 --- /dev/null +++ b/data/challenges/21.json @@ -0,0 +1,57 @@ +{ + "name" : "Initiation", + "description" : "Initiation", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Dart", + "side" : "SIDE_PIRATE", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25, + "flags" : "+EF_COLLECTS_ITEMS" + }, + "challenge" : { + "timeLimit" : 120, + "playerItemLimit" : 8, + "allowPlayerDeath" : 1, + "isDeathMatch" : 1, + "challenges" : [ + { + "type" : "CHALLENGE_PLAYER_ITEMS", + "value" : 3 + }, + { + "type" : "CHALLENGE_PLAYER_ITEMS", + "value" : 6 + }, + { + "type" : "CHALLENGE_PLAYER_ITEMS", + "value" : 8 + } + ] + }, + "spawners" : [ + { + "name" : "spawner", + "types" : "Dart", + "side" : "SIDE_PIRATE", + "interval" : 5, + "total" : -1, + "step" : 1, + "offscreen" : 1, + "flags" : "+EF_COLLECTS_ITEMS+EF_DROPS_ITEMS", + "aiFlags" : "+AIF_UNLIMITED_RANGE+AIF_COLLECTS_ITEMS" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Boss;Three kills to join the team, dogs! Don't forget to collect the kill!" + ] + } + ] +} diff --git a/data/challenges/22.json b/data/challenges/22.json new file mode 100644 index 0000000..33d71a0 --- /dev/null +++ b/data/challenges/22.json @@ -0,0 +1,45 @@ +{ + "name" : "Destroy all Darts #4", + "description" : "Destroy all Darts #4", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Shale", + "side" : "SIDE_REBEL", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "timeLimit" : 30, + "killLimit" : 5, + "noMissiles" : 1, + "challenges" : [ + { + "type" : "CHALLENGE_TIME", + "value" : 30 + }, + { + "type" : "CHALLENGE_TIME", + "value" : 27 + }, + { + "type" : "CHALLENGE_SHOT_ACCURACY", + "value" : 55 + } + ] + }, + "fighters" : [ + { + "name" : "Dart", + "types" : "Dart", + "side" : "SIDE_PIRATE", + "x" : 25, + "y" : 22, + "number" : 5, + "scatter" : 1000 + } + ] +} diff --git a/data/fighters/angel.json b/data/fighters/angel.json new file mode 100644 index 0000000..aa01fc2 --- /dev/null +++ b/data/fighters/angel.json @@ -0,0 +1,33 @@ +{ + "name" : "Angel", + "health" : 80, + "shield" : 80, + "speed" : 1.8, + "reloadTime" : 15, + "shieldRechargeRate" : 55, + "texture" : "gfx/fighters/angel.png", + "guns" : [ + { + "type" : "BT_PLASMA", + "x" : -10, + "y" : 0 + }, + { + "type" : "BT_PLASMA", + "x" : 10, + "y" : 0 + }, + { + "type" : "BT_MAG", + "x" : -4, + "y" : -6 + }, + { + "type" : "BT_MAG", + "x" : 4, + "y" : -6 + } + ], + "missiles" : 3, + "flags" : "EF_TAKES_DAMAGE" +} diff --git a/data/galaxy/starSystems.json b/data/galaxy/starSystems.json index 2939a2e..76ee51f 100644 --- a/data/galaxy/starSystems.json +++ b/data/galaxy/starSystems.json @@ -121,7 +121,8 @@ "name": "Rothan", "side" : "SIDE_UNF", "x": 366, - "y": 298 + "y": 298, + "fallsToPandorans" : 1 }, { "name": "Donesta", @@ -143,9 +144,10 @@ }, { "name": "Mace", - "side" : "SIDE_UNF", + "side" : "SIDE_REBEL", "x": 444, - "y": 359 + "y": 359, + "fallsToPandorans" : 1 }, { "name": "Clarke", diff --git a/data/missions/alba/01 - patrol #1.json b/data/missions/alba/01 - patrol #1.json index bafb8eb..bf99424 100644 --- a/data/missions/alba/01 - patrol #1.json +++ b/data/missions/alba/01 - patrol #1.json @@ -23,6 +23,7 @@ }, "fighters" : [ { + "name" : "Wingmate #?", "types" : "Firefly;Nymph", "number" : 3, "side" : "SIDE_ALLIES", @@ -45,6 +46,7 @@ { "function" : "Waypoint #2", "lines" : [ + "WAIT 1", "MSG_BOX Rice;Anyone got anything to report?", "MSG_BOX Wingmate #1;You getting paranoid, Curtis?", "MSG_BOX Rice;You all saw what happened at Coyote." @@ -53,11 +55,12 @@ { "function" : "Waypoint #3", "lines" : [ + "WAIT 1", "MSG_BOX Wingmate #1;So, those Pandorans are, what, robots?", "MSG_BOX Wingmate #2;Alien-Human hybrid, I heard.", "MSG_BOX Wingmate #3;Hard to kill, whatever they are. Heard they'll still be coming at you even if you take both arms off.", "MSG_BOX Wingmate #2;And what'll they do then? Bite you to death?", - "MSG_BOX Rice;Eyes open, lads" + "MSG_BOX Rice;Eyes open, lads." ] }, { @@ -66,7 +69,7 @@ "WAIT 1", "MSG_BOX Rice;We're done. Anyone detect anything unusual?", "MSG_BOX Wingmate #2;Same old, same old.", - "MSG_BOX Rice;Believe me, that's a good thing. Right, let's head home and report in", + "MSG_BOX Rice;Believe me, that's a good thing. Right, let's head home and report in.", "WAIT_MSG_BOX", "COMPLETE_MISSION" ] diff --git a/data/missions/alba/03 - patrol #3.json b/data/missions/alba/03 - patrol #3.json index e94e5ea..29d6f3b 100644 --- a/data/missions/alba/03 - patrol #3.json +++ b/data/missions/alba/03 - patrol #3.json @@ -4,7 +4,7 @@ ], "name" : "Patrol #3", "description" : "Following the devastating loss of the Iliad system, we need to continue to be vigilant against incursion into the Alba system. Check all five waypoints, and report immediate any unusual or suspicious activity you encounter.", - "requires" : 28, + "requires" : 27, "background" : "gfx/backgrounds/background03.jpg", "planet" : "gfx/planets/torelli.png", "music" : "", @@ -26,8 +26,18 @@ }, "fighters" : [ { + "name" : "Wingmate #?", + "types" : "Firefly;Nymph", + "number" : 3, + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "scatter" : 500 + }, + { + "name" : "Wade", + "fullname" : "Frank Wade", "types" : "Firefly;Nymph", - "number" : 4, "side" : "SIDE_ALLIES", "x" : 25, "y" : 25, @@ -48,9 +58,9 @@ { "function" : "TIME 3", "lines" : [ - "MSG_BOX Wingmate #2;So, Iliad has fallen?", - "MSG_BOX Wingmate #4;From what I've heard.", - "MSG_BOX Wingmate #2;Did they retreat, or ...", + "MSG_BOX Wingmate #1;So, Iliad has fallen?", + "MSG_BOX Wingmate #2;From what I've heard.", + "MSG_BOX Wingmate #1;Did they retreat, or ...", "MSG_BOX Rice;They fought to the very last." ] }, @@ -58,11 +68,11 @@ "function" : "Waypoint #1", "lines" : [ "WAIT 3", - "MSG_BOX Wingmate #2;So that's it. The Pandorans have won?", + "MSG_BOX Wingmate #1;So that's it. The Pandorans have won?", "MSG_BOX Rice;At Iliad, yes. Unless the local forces there can somehow hold off the enemy's ground assault.", - "MSG_BOX Wingmate #4;It's ... possible, right?", + "MSG_BOX Wingmate #2;It's ... possible, right?", "MSG_BOX Rice;The Pandorans will just nuke the place when they're done. They'll take what they need, kill everyone who stands in their way ...", - "MSG_BOX Wingmate #2;And even those who don't.", + "MSG_BOX Wingmate #1;And even those who don't.", "MSG_BOX Rice;...and move on." ] }, @@ -70,12 +80,12 @@ "function" : "Waypoint #2", "lines" : [ "WAIT 3", - "MSG_BOX Wingmate #2;You're quiet, Wade.", + "MSG_BOX Wingmate #1;You're quiet, Wade.", "MSG_BOX Wade;Just thinking.", - "MSG_BOX Wingmate #4;What about?", + "MSG_BOX Wingmate #2;What about?", "MSG_BOX Wade;How long it'll be before the Pandorans show up here.", - "MSG_BOX Wingmate #2;They came by earlier, in case you don't remember.", - "MSG_BOX Wingmate #4;And haven't been back since. Maybe we scared them off.", + "MSG_BOX Wingmate #1;They came by earlier, in case you don't remember.", + "MSG_BOX Wingmate #2;And haven't been back since. Maybe we scared them off.", "MSG_BOX Rice;I doubt it, guys. They were probably just scouting." ] }, @@ -83,12 +93,12 @@ "function" : "Waypoint #3", "lines" : [ "WAIT 3", - "MSG_BOX Wingmate #2;Where the hell are the CSN? Why weren't they at Iliad?", + "MSG_BOX Wingmate #1;Where the hell are the CSN? Why weren't they at Iliad?", "MSG_BOX Rice;They weren't wanted, apparently. Iliad and the UNF aren't getting along so well at the moment.", - "MSG_BOX Wingmate #4;Something to do with Adrian Parsons?", - "MSG_BOX Wingmate #2;That bloody idiot? It wouldn't surprise me. He's the reason we're now in this mess! If I ever meet that guy, nothing'll stop me from-", + "MSG_BOX Wingmate #2;Something to do with Adrian Parsons?", + "MSG_BOX Wingmate #1;That bloody idiot? It wouldn't surprise me. He's the reason we're now in this mess! If I ever meet that guy, nothing'll stop me from-", "MSG_BOX Rice;Hey, mind what you say. All these communications are logged.", - "MSG_BOX Wingmate #2;(indecipherable muttering)" + "MSG_BOX Wingmate #1;(indecipherable muttering)" ] }, { @@ -96,10 +106,10 @@ "lines" : [ "WAIT 3", "MSG_BOX Wade;What do you mean, it's all Parsons' fault?", - "MSG_BOX Wingmate #2;He made an executive decision over in Coyote several months ago, that screwed everything up. Something about being charged with a super weapon.", + "MSG_BOX Wingmate #1;He made an executive decision over in Coyote several months ago, that screwed everything up. Something about being charged with a super weapon.", "MSG_BOX Wade;Grendel's Mother?", - "MSG_BOX Wingmate #2;No, something it was carrying. Linked to the ATAFs, apparently.", - "MSG_BOX Wingmate #4;The CSN built something that nuked a whole load of allied and Pandoran forces. It wasn't meant to be used in Coyote, though.", + "MSG_BOX Wingmate #1;No, something it was carrying. Linked to the ATAFs, apparently.", + "MSG_BOX Wingmate #2;The CSN built something that nuked a whole load of allied and Pandoran forces. It wasn't meant to be used in Coyote, though.", "MSG_BOX Wade;You don't say.", "MSG_BOX Rice;Okay, lads, let's wrap this topic up, eh?" ] @@ -110,8 +120,8 @@ "WAIT 1", "MSG_BOX Rice;That's it, all done. Anyone got anything to report?", "MSG_BOX Wade;Nothing.", + "MSG_BOX Wingmate #1;Nope.", "MSG_BOX Wingmate #2;Nope.", - "MSG_BOX Wingmate #4;Nope.", "MSG_BOX Rice;Okay, let's get home and report in.", "WAIT_MSG_BOX", "COMPLETE_MISSION" diff --git a/data/missions/alba/05 - alba defence #2.json b/data/missions/alba/05 - alba defence #2.json new file mode 100644 index 0000000..e250b0a --- /dev/null +++ b/data/missions/alba/05 - alba defence #2.json @@ -0,0 +1,209 @@ +{ + "name" : "Alba Defence #2", + "description" : "", + "requires" : 50, + "background" : "gfx/backgrounds/background03.jpg", + "planet" : "gfx/planets/torelli.png", + "music" : "music/battle/heroism.ogg", + "manualComplete" : 1, + "objectives" : [ + { + "description" : "Eliminate all enemy targets", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + }, + { + "description" : "Destroy HMS 821-283", + "targetName" : "HMS 821-283", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "active" : 0 + }, + { + "description" : "Destroy INF Burnside", + "targetName" : "INF Burnside", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "active" : 0 + } + ], + "player" : { + "type" : "Leopard", + "side" : "SIDE_ALLIES", + "pilot" : "1st Lt. Curtis Rice", + "squadron" : "Eightballers", + "x" : 25, + "y" : 5 + }, + "fighters" : [ + { + "types" : "Leopard;Firefly;Nymph", + "number" : 11, + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 5, + "scatter" : 500 + }, + { + "types" : "Shale;Razor;SK-31;SK-34", + "number" : 5, + "side" : "SIDE_REBEL", + "x" : 25, + "y" : 12, + "scatter" : 500 + }, + { + "groupName" : "Rebels-1", + "types" : "Shale;Razor;SK-31;SK-34", + "number" : 4, + "side" : "SIDE_REBEL", + "x" : 20, + "y" : -1, + "scatter" : 500, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "groupName" : "Rebels-1", + "types" : "Shale;Razor;SK-31;SK-34", + "number" : 4, + "side" : "SIDE_REBEL", + "x" : 30, + "y" : -1, + "scatter" : 500, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "groupName" : "Rebels-2", + "types" : "Shale;Razor;SK-31;SK-34", + "number" : 48, + "side" : "SIDE_REBEL", + "x" : -1, + "y" : 35, + "scatter" : 8500, + "flags" : "+EF_AI_TARGET", + "aiFlags" : "+AIF_MOVES_TO_LEADER", + "active" : 0 + }, + { + "groupName" : "Pandorans", + "name" : "Pandoran", + "types" : "Jackal;Sphinx;Mantis;Thunderhead", + "number" : 48, + "side" : "SIDE_PANDORAN", + "x" : 51, + "y" : 35, + "scatter" : 8500, + "flags" : "+EF_AI_TARGET", + "aiFlags" : "+AIF_MOVES_TO_LEADER", + "active" : 0 + }, + { + "groupName" : "White Knights", + "name" : "de Winter", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : -1, + "scatter" : 500, + "active" : 0 + }, + { + "groupName" : "White Knights", + "types" : "ATAF", + "number" : 4, + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : -1, + "scatter" : 500, + "active" : 0 + } + ], + "capitalShips" : [ + { + "groupName" : "CapShips", + "name" : "HMS 821-283", + "types" : "HMS Corvette 01", + "side" : "SIDE_REBEL", + "x" : -1, + "y" : 35, + "flags" : "+EF_AI_LEADER", + "active" : 0 + }, + { + "groupName" : "CapShips", + "name" : "INF Burnside", + "types" : "INF Corvette 02", + "side" : "SIDE_PANDORAN", + "x" : 51, + "y" : 35, + "flags" : "+EF_AI_LEADER", + "active" : 0 + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Rice;Break and attack, lads. Let's send these guys back home." + ] + }, + { + "function" : "ENEMIES_KILLED 5", + "lines" : [ + "WAIT 1", + "MSG_BOX Wingmate;More Tzac fighters incoming.", + "ACTIVATE_ENTITY_GROUPS Rebels-1" + ] + }, + { + "function" : "ENEMIES_KILLED 13", + "lines" : [ + "WAIT 1", + "ACTIVATE_ENTITY_GROUPS Rebels-2;Pandorans", + "MSG_BOX Rice;Steel yourself, lads. Even more Tzac forces are heading our way.", + "WAIT_MSG_BOX", + "ACTIVATE_OBJECTIVES Destroy HMS 821-283;Destroy INF Burnside", + "ACTIVATE_ENTITY_GROUPS CapShips", + "MSG_BOX Wingmate;Picking up two capital ships, moving in.", + "MSG_BOX Rice;Wait, those aren't only Tzac forces ... ", + "MSG_BOX Rice;Ah, hell! Now we've got Pandorans, too?!" + ] + }, + { + "function" : "ALLIES_KILLED 8", + "lines" : [ + "MSG_BOX Wingmate;Commander, we're getting shot to ribbons here! We need to fallback!", + "MSG_BOX Rice;We can't let EITHER of these two win! That would be a major loss for all of us." + ] + }, + { + "function" : "ALLIES_KILLED 11", + "lines" : [ + "WAIT 5", + "MSG_BOX de Winter;Eightballers, de Winter of the White Knights, here to assist.", + "MSG_BOX Rice;White Knights! Am I glad to see you. Your timing couldn't be better.", + "ACTIVATE_ENTITY_GROUPS White Knights" + ] + }, + { + "function" : "OBJECTIVES_COMPLETE 3", + "lines" : [ + "WAIT 1", + "MSG_BOX Rice;I owe you my life, Knights.", + "MSG_BOX de Winter;We're all in this together, Rice. I'm sorry we arrived too late to save your wingmates.", + "MSG_BOX Rice;They were good guys. They'll be missed.", + "WAIT_MSG_BOX", + "ACTIVATE_JUMPGATE 1", + "RETREAT_ALLIES", + "WAIT 3", + "MSG_BOX de Winter;We're needed elsewhere. We'll see you soon.", + "COMPLETE_MISSION" + ] + } + ] +} + diff --git a/data/missions/antomis/02 - antomis offence #2.json b/data/missions/antomis/02 - antomis offence #1.json similarity index 98% rename from data/missions/antomis/02 - antomis offence #2.json rename to data/missions/antomis/02 - antomis offence #1.json index 603190d..8991c46 100644 --- a/data/missions/antomis/02 - antomis offence #2.json +++ b/data/missions/antomis/02 - antomis offence #1.json @@ -1,10 +1,10 @@ { - "name" : "Antomis Offence #2", + "name" : "Antomis Offence #1", "description" : "With the mercenary threat seen off and Tzac's initial attacks thwarted, it's time to begin pushing back against Christabel's forces. We plan to capture a number of their commanders, to help build a better picture of the forces at Mace, before moving into the system. As always, mag the targets and do not allow them to be killed.", "background" : "gfx/backgrounds/background02.jpg", "planet" : "gfx/planets/bluePlanet.png", "music" : "music/battle/determination.mp3", - "requires" : 45, + "requires" : 44, "manualComplete" : 1, "objectives" : [ { diff --git a/data/missions/antomis/03 - antomis defence #2.json b/data/missions/antomis/03 - antomis defence #2.json new file mode 100644 index 0000000..11048b4 --- /dev/null +++ b/data/missions/antomis/03 - antomis defence #2.json @@ -0,0 +1,82 @@ +{ + "name" : "Antomis Defence #2", + "description" : "", + "background" : "gfx/backgrounds/background02.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/Tactical Pursuit.mp3", + "requires" : 44, + "epic" : { + "fighterLimit" : 12 + }, + "objectives" : [ + { + "description" : "Destroy INF Sharpfinger", + "targetName" : "INF Sharpfinger", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Destroy all enemy targets", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + } + ], + "player" : { + "type" : "TAF", + "side" : "SIDE_ALLIES", + "pilot" : "(Multiple)", + "squadron" : "(Multiple)", + "x" : 25, + "y" : 25 + }, + "fighters" : [ + { + "name" : "Wingmate #?", + "types" : "TAF;Ray;Kingfisher;Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "number" : 98, + "scatter" : 5000, + "flags" : "+EF_AI_TARGET" + }, + { + "name" : "Wing Commander", + "types" : "Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "scatter" : 5000, + "flags" : "+EF_AI_TARGET" + }, + { + "name" : "Pandoran", + "types" : "Jackal;Scarab;Mantis;Sphinx;Thunderhead", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 15, + "number" : 75, + "scatter" : 8000 + } + ], + "capitalShips" : [ + { + "name" : "INF Sharpfinger", + "types" : "INF Corvette 02", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 10 + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Wing Commander;People, divide yourselves between the fighters and the Sharpfinger.", + "MSG_BOX Wing Commander;We couldn't spare any bombers, so we just need to get in there and take them all on." + ] + } + ] +} diff --git a/data/missions/aster/04 - aster assault.json b/data/missions/aster/04 - aster assault.json new file mode 100644 index 0000000..6ca880e --- /dev/null +++ b/data/missions/aster/04 - aster assault.json @@ -0,0 +1,268 @@ +{ + "name" : "Aster Assault", + "description" : "", + "requires" : 54, + "background" : "gfx/backgrounds/background04.jpg", + "planet" : "gfx/planets/star.png", + "music" : "music/battle/Battle in the winter.mp3", + "manualComplete" : 1, + "objectives" : [ + { + "description" : "Disable all fighters", + "targetName" : "Rebels", + "targetValue" : 32, + "targetType" : "TT_DISABLE" + }, + { + "description" : "Disable all capital ships", + "targetName" : "CapShips", + "targetValue" : 4, + "targetType" : "TT_DISABLE" + }, + { + "description" : "Do not destroy any fighters", + "targetName" : "Rebels", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isCondition" : 1 + }, + { + "description" : "Do not destroy any capital ships", + "targetName" : "CapShips", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isCondition" : 1 + } + ], + "player" : { + "type" : "ATAF", + "side" : "SIDE_ALLIES", + "pilot" : "Lt. Cdr. Simon Dodds", + "squadron" : "White Knights", + "x" : 5, + "y" : 45 + }, + "fighters" : [ + { + "name" : "de Winter", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "flags" : "+EF_AI_LEADER", + "aiFlags" : "+AIF_UNLIMITED_RANGE" + }, + { + "name" : "Todd", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "name" : "Taylor", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "name" : "Koonan", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Shale;Razor", + "side" : "SIDE_REBEL", + "x" : 10, + "y" : 10, + "scatter" : 500, + "flags" : "+EF_MUST_DISABLE+EF_AI_LEADER", + "aiFlags" : "+AIF_WANDERS" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Shale;Razor", + "side" : "SIDE_REBEL", + "x" : 10, + "y" : 10, + "scatter" : 5000, + "number" : 7, + "flags" : "+EF_MUST_DISABLE", + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Shale;Razor", + "side" : "SIDE_REBEL", + "x" : 20, + "y" : 20, + "scatter" : 500, + "flags" : "+EF_MUST_DISABLE+EF_AI_LEADER", + "aiFlags" : "+AIF_WANDERS" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Razor", + "side" : "SIDE_REBEL", + "x" : 20, + "y" : 20, + "scatter" : 5000, + "number" : 7, + "flags" : "+EF_MUST_DISABLE", + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Shale;Razor", + "side" : "SIDE_REBEL", + "x" : 30, + "y" : 30, + "scatter" : 500, + "flags" : "+EF_MUST_DISABLE+EF_AI_LEADER", + "aiFlags" : "+AIF_WANDERS" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Razor", + "side" : "SIDE_REBEL", + "x" : 30, + "y" : 30, + "scatter" : 5000, + "number" : 7, + "flags" : "+EF_MUST_DISABLE", + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Shale;Razor", + "side" : "SIDE_REBEL", + "x" : 40, + "y" : 40, + "scatter" : 500, + "flags" : "+EF_MUST_DISABLE+EF_AI_LEADER", + "aiFlags" : "+AIF_WANDERS" + }, + { + "groupName" : "Rebels", + "types" : "SK-31;SK-34;Razor", + "side" : "SIDE_REBEL", + "x" : 40, + "y" : 40, + "scatter" : 5000, + "number" : 7, + "flags" : "+EF_MUST_DISABLE", + "aiFlags" : "+AIF_MOVES_TO_LEADER" + } + ], + "capitalShips" : [ + { + "groupName" : "CapShips", + "name" : "HMS 281-024", + "types" : "HMS Corvette 01", + "side" : "SIDE_REBEL", + "x" : 10, + "y" : 10, + "flags" : "+EF_AI_IGNORE+EF_AI_LEADER" + }, + { + "groupName" : "CapShips", + "name" : "HMS 121-008", + "types" : "HMS Corvette 02", + "side" : "SIDE_REBEL", + "x" : 20, + "y" : 20, + "flags" : "+EF_AI_IGNORE+EF_AI_LEADER" + }, + { + "groupName" : "CapShips", + "name" : "HMS 711-555", + "types" : "HMS Corvette 02", + "side" : "SIDE_REBEL", + "x" : 30, + "y" : 30, + "flags" : "+EF_AI_IGNORE+EF_AI_LEADER" + }, + { + "groupName" : "CapShips", + "name" : "HMS 613-910", + "types" : "HMS Corvette 01", + "side" : "SIDE_REBEL", + "x" : 40, + "y" : 40, + "flags" : "+EF_AI_IGNORE+EF_AI_LEADER" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX de Winter;Remember, guys: mags only against the fighters. We're not here to take any more lives.", + "MSG_BOX de Winter;For the corvettes, concentrate fire on the engines and the guns. Once it's out of the game, move onto the next one.", + "MSG_BOX Dodds;Got it." + ] + }, + { + "function" : "TIME 30", + "lines" : [ + "MSG_BOX Koonan;We should lure the fighters away from the capital ships. Stray fire against a disabled ship could destroy it.", + "MSG_BOX de Winter;Good point, Chaz, we should be mindful of friendly-fire." + ] + }, + { + "function" : "CAP_DISABLED HMS 121-008", + "lines" : [ + "WAIT 1", + "MSG_BOX Dodds;Brings back memories, doesn't it?", + "MSG_BOX Todd;So long as we don't end up back in Phylent after this." + ] + }, + { + "function" : "ENEMIES_DISABLED 20", + "lines" : [ + "WAIT 1", + "MSG_BOX Dodds;This going in your journal, Kelly?", + "MSG_BOX Taylor;Everything. It could be important one day.", + "MSG_BOX Todd;Have fun with the names of Tzac's cap ships.", + "MSG_BOX Taylor;I'll just refer to the battle logs. Military records tend to be accurate.", + "MSG_BOX Dodds;Most of the time." + ] + }, + { + "function" : "Disable all fighters", + "lines" : [ + "WAIT 1", + "MSG_BOX Koonan;All fighters disabled." + ] + }, + { + "function" : "Disable all capital ships", + "lines" : [ + "WAIT 1", + "MSG_BOX de Winter;Corvettes are all out of the game." + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 1", + "MSG_BOX de Winter;Griffin, this is de Winter. Opposing forces are no longer a threat.", + "MSG_BOX CSN Griffin;Any casualties?", + "MSG_BOX de Winter;No. All fighters and caps have been shutdown, and ready for pickup.", + "MSG_BOX CSN Griffin;Great work, Knights. Clean up will commence shortly. Standby for new instructions.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} diff --git a/data/missions/clarke/01 - clarke defence #1.json b/data/missions/clarke/01 - clarke defence #1.json index 4b98028..a272b67 100644 --- a/data/missions/clarke/01 - clarke defence #1.json +++ b/data/missions/clarke/01 - clarke defence #1.json @@ -11,9 +11,10 @@ "objectives" : [ { "description" : "Destroy all enemy targets", - "targetName" : "Pandoran", - "targetValue" : 80, - "targetType" : "TT_DESTROY" + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 } ], "player" : { diff --git a/data/missions/clarke/04 - clarke defence #4.json b/data/missions/clarke/04 - clarke defence #4.json index b9f930b..460877c 100644 --- a/data/missions/clarke/04 - clarke defence #4.json +++ b/data/missions/clarke/04 - clarke defence #4.json @@ -1,7 +1,7 @@ { "name" : "Clarke Defence #4", "description" : "White Knights, Commodore Parks has identified three enemy corvettes are high level targets. He wants Dodds, Koonan and Todd to take them down, as quickly as possible. There won't be any additional fighter support, but three ATAFs should be more than enough to get the job done. de Winter and Taylor are currently on another assignment. Dodds will lead the attack.", - "requires" : 29, + "requires" : 28, "background" : "gfx/backgrounds/background06.jpg", "planet" : "gfx/planets/bluePlanet.png", "music" : "music/battle/heroism.ogg", diff --git a/data/missions/clarke/06 - clarke defence #6.json b/data/missions/clarke/06 - clarke defence #6.json index c40caf7..4b1ef59 100644 --- a/data/missions/clarke/06 - clarke defence #6.json +++ b/data/missions/clarke/06 - clarke defence #6.json @@ -10,8 +10,9 @@ { "description" : "Destroy all enemy targets", "targetName" : "Pandoran", - "targetValue" : 150, - "targetType" : "TT_DESTROY" + "targetValue" : 999, + "targetType" : "TT_DESTROY", + "hideNumbers" : 1 } ], "epic" : { @@ -90,7 +91,7 @@ "function" : "TIME 2", "lines" : [ "MSG_BOX Wing Commander;The Twilight Lancers are on their way.", - "MSG_BOX Wingmate #62;Eight whole extra fighters? We might outnumber the enemy, but they still outgun us!", + "MSG_BOX Wingmate;Eight whole extra fighters? We might outnumber the enemy, but they still outgun us!", "MSG_BOX Wing Commander;At this point, any additional support is welcome. And we still have the support of Cleopatra and Artemis." ] }, @@ -106,17 +107,17 @@ "function" : "ENEMIES_KILLED 50", "lines" : [ "MSG_BOX Wing Commander;We're wearing them down. Keep up the pressure.", - "MSG_BOX Wingmate #31;Think they're pull back if we hit them hard enough?", + "MSG_BOX Wingmate;Think they're pull back if we hit them hard enough?", "MSG_BOX Wing Commander;Too early to speculate. Just concentrate on taking down their fighters." ] }, { "function" : "ENEMIES_KILLED 75", "lines" : [ - "MSG_BOX Wingmate #88;I've just been tailed by something I've never seen before! Small, highly maneuverable, rapid fire particle cannon.", + "MSG_BOX Wingmate;I've just been tailed by something I've never seen before! Small, highly maneuverable, rapid fire particle cannon.", "MSG_BOX Welch;Swarmers! The enemy have deployed them here, too!", "MSG_BOX Wing Commander;How many?", - "MSG_BOX Wingmate #82;Tracking a dozen, but the numbers are growing rapidly", + "MSG_BOX Wingmate;Tracking a dozen, but the numbers are growing rapidly", "WAIT_MSG_BOX", "ACTIVATE_SPAWNER 1 SwarmerSpawner" ] @@ -124,40 +125,16 @@ { "function" : "ALLIES_KILLED 150", "lines" : [ - "MSG_BOX Wingmate #88;I've lost count how many of these damn swarmers I've taken down.", - "MSG_BOX Wingmate #120;It's like fighting a hydra! You cut off one head, and two more spring up!" + "MSG_BOX Wingmate;I've lost count how many of these damn swarmers I've taken down.", + "MSG_BOX Wingmate;It's like fighting a hydra! You cut off one head, and two more spring up!" ] }, { "function" : "ALLIES_KILLED 195", "lines" : [ - "MSG_BOX Wingmate #181;There's too many of them!", - "MSG_BOX Wingmate #31;Keep fighting, we can still win this!", - "MSG_BOX Wingmate #111;They're everywhere! I--" - ] - }, - { - "function" : "CAP_ENGINES_DESTROYED UNF Cleopatra", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Cleopatra;This is UNF Cleopatra. We are engine crippled. Please provide cover support!" - ] - }, - { - "function" : "CAP_HEALTH UNF Cleopatra 3", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Cleopatra;Mayday! Mayday! We are taking heavy damage! Please assist ASAP!" - ] - }, - { - "function" : "CAP_ENGINES_DESTROYED UNF Artemis", - "lines" : [ - "IMPORTANT_MSG_BOX Wing Commander;Artemis has lost her engines. We need to keep those Pandorans off her!" - ] - }, - { - "function" : "CAP_HEALTH UNF Artemis 3", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Artemis;All fighters, we're taking a pounding here, we don't know how much longer we can survive this." + "MSG_BOX Wingmate;There's too many of them!", + "MSG_BOX Wingmate;Keep fighting, we can still win this!", + "MSG_BOX Wingmate;They're everywhere! I--" ] }, { diff --git a/data/missions/coyote/02 - coyote assault #2.json b/data/missions/coyote/02 - coyote assault #2.json index fa850e3..6d4a990 100644 --- a/data/missions/coyote/02 - coyote assault #2.json +++ b/data/missions/coyote/02 - coyote assault #2.json @@ -11,9 +11,10 @@ "objectives" : [ { "description" : "Destroy all enemy targets", - "targetName" : "Pandoran", - "targetValue" : 75, - "targetType" : "TT_DESTROY" + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 } ], "player" : { diff --git a/data/missions/donesta/02 - donesta offence #1.json b/data/missions/donesta/02 - donesta offence #1.json index becca43..cb753ef 100644 --- a/data/missions/donesta/02 - donesta offence #1.json +++ b/data/missions/donesta/02 - donesta offence #1.json @@ -1,7 +1,7 @@ { "name" : "Donesta Offence #1", "description" : "With the mercenary threat seen off and Tzac's initial attacks thwarted, it's time to begin pushing back against Christabel's forces. We plan to capture a number of their commanders, to help build a better picture of the forces at Mace, before moving into the system. As always, mag the targets and do not allow them to be killed.", - "requires" : 45, + "requires" : 44, "background" : "gfx/backgrounds/background01.jpg", "planet" : "gfx/planets/bluePlanet.png", "music" : "music/battle/heroism.ogg", diff --git a/data/missions/donesta/03 - donesta defence #2.json b/data/missions/donesta/03 - donesta defence #2.json new file mode 100644 index 0000000..538b441 --- /dev/null +++ b/data/missions/donesta/03 - donesta defence #2.json @@ -0,0 +1,69 @@ +{ + "name" : "Donesta Defence #2", + "description" : "", + "requires" : 44, + "background" : "gfx/backgrounds/background01.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/Tactical Pursuit.mp3", + "manualComplete" : 1, + "epic" : { + "fighterLimit" : 12 + }, + "objectives" : [ + { + "description" : "Destroy all enemy targets", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + } + ], + "player" : { + "type" : "Nymph", + "side" : "SIDE_ALLIES", + "pilot" : "(Multiple)", + "squadron" : "(Multiple)" + }, + "fighters" : [ + { + "name" : "ALLIES", + "types" : "Firefly;Nymph;TAF;Ray;Leopard;Hyena-A;Hyena-B;Kingfisher;Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "number" : 100, + "scatter" : 5000 + }, + { + "name" : "Pandoran", + "types" : "Firefly;Nymph;Nymph;Leopard;Hyena-A;Hyena-B", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 15, + "number" : 80, + "scatter" : 5000, + "flags" : "+EF_FRIENDLY_HEALTH_BAR" + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX Wing Commander;Remember everyone: the Pandorans are using UNF fighters.", + "MSG_BOX Wing Commander;Using your radar and HUD is the way to go in this fight." + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 1", + "MSG_BOX Wing Commander;All enemies down.", + "MSG_BOX Wingmate;Let's hope we never see the day when they get hold of one of the ATAFs.", + "MSG_BOX Wing Commander;Agreed. Let's regroup and prepare for whatever's coming next.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} + diff --git a/data/missions/iliad/02 - iliad defence #2.json b/data/missions/iliad/02 - iliad defence #2.json index 2164ee6..1c21712 100644 --- a/data/missions/iliad/02 - iliad defence #2.json +++ b/data/missions/iliad/02 - iliad defence #2.json @@ -11,9 +11,10 @@ "objectives" : [ { "description" : "Destroy all enemy targets", - "targetName" : "Pandoran", - "targetValue" : 50, - "targetType" : "TT_DESTROY" + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 } ], "player" : { diff --git a/data/missions/iliad/05 - iliad defence #5.json b/data/missions/iliad/05 - iliad defence #5.json index 73f74f7..91c1848 100644 --- a/data/missions/iliad/05 - iliad defence #5.json +++ b/data/missions/iliad/05 - iliad defence #5.json @@ -13,8 +13,9 @@ { "description" : "Destroy all enemy targets", "targetName" : "Pandoran", - "targetValue" : 500, - "targetType" : "TT_DESTROY" + "targetValue" : 999, + "targetType" : "TT_DESTROY", + "hideNumbers" : 1 } ], "player" : { @@ -83,8 +84,8 @@ "function" : "TIME 2", "lines" : [ "MSG_BOX Wing Commander;Stay sharp, people. We need to hold the line here!", - "MSG_BOX Wingmate #31;Oh my God, there's a lot of them ...", - "MSG_BOX Wingmate #82;Pair up, and take them down together. We stand a much better chance that way." + "MSG_BOX Wingmate;Oh my God, there's a lot of them ...", + "MSG_BOX Wingmate;Pair up, and take them down together. We stand a much better chance that way." ] }, { @@ -92,24 +93,24 @@ "lines" : [ "ACTIVATE_ENTITIES INF Qama;INF Seax;INF Mora;INF Sharpfinger", "MSG_BOX Wing Commander;Heads up, people. Four INF corvettes just entered the area.", - "MSG_BOX Wingmate #41;What's happened to all our own capital ships?!", + "MSG_BOX Wingmate;What's happened to all our own capital ships?!", "MSG_BOX Wing Commander;They've been scratched." ] }, { "function" : "ALLIES_KILLED 60", "lines" : [ - "MSG_BOX Wingmate #63;That Dust Brothers have been flagged." + "MSG_BOX Wingmate;That Dust Brothers have been flagged." ] }, { "function" : "ALLIES_KILLED 90", "lines" : [ - "MSG_BOX Wingmate #94;We have to sound the retreat!", + "MSG_BOX Wingmate;We have to sound the retreat!", "MSG_BOX Wing Commander;Mister, you remain where you are! We're not abando--", "WAIT_MSG_BOX", "WAIT 3", - "MSG_BOX Wingmate #98;The wing commander's dead." + "MSG_BOX Wingmate;The wing commander's dead." ] } ] diff --git a/data/missions/india/02 - india defence #2.json b/data/missions/india/02 - india defence #2.json index 7531eaf..a92031b 100644 --- a/data/missions/india/02 - india defence #2.json +++ b/data/missions/india/02 - india defence #2.json @@ -107,30 +107,6 @@ "WAIT_MSG_BOX", "COMPLETE_MISSION" ] - }, - { - "function" : "CAP_ENGINES_DESTROYED UNF Hopper", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Hopper;Our engines have been shot out! We're a sitting duck!" - ] - }, - { - "function" : "CAP_HEALTH UNF Hopper 6", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Hopper;We're taking damage here, guys! Please step it up." - ] - }, - { - "function" : "CAP_HEALTH UNF Hopper 3", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Hopper;We're sustaining heavy damage! All fighters, please assist, ASAP!" - ] - }, - { - "function" : "CAP_HEALTH UNF Hopper 1", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Hopper;Mayday! Mayday! Defences are critical. We can't hold out much longer!" - ] } ] } diff --git a/data/missions/mace/01 - mace assault #1.json b/data/missions/mace/01 - mace assault #1.json new file mode 100644 index 0000000..02a2259 --- /dev/null +++ b/data/missions/mace/01 - mace assault #1.json @@ -0,0 +1,168 @@ +{ + "name" : "Mace Assault #1", + "description" : "", + "requires" : 50, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/battleThemeA.mp3", + "manualComplete" : 1, + "player" : { + "type" : "Hammerhead", + "pilot" : "Lt. Cdr. Ian Barclay", + "squadron" : "Iron Wolves", + "side" : "SIDE_ALLIES", + "x" : 45, + "y" : 25 + }, + "objectives" : [ + { + "description" : "Knock jumpgate offline", + "targetName" : "Jumpgate", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Eliminate all enemies", + "targetName" : "ENEMY", + "targetType" : "TT_DESTROY", + "targetValue" : 1, + "isEliminateAll" : 1 + } + ], + "fighters" : [ + { + "name" : "Wolfenden", + "fullname" : "Tamara Wolfenden", + "types" : "Rook", + "side" : "SIDE_ALLIES", + "x" : 45, + "y" : 25, + "scatter" : 500, + "flags" : "+EF_AI_LEADER+EF_IMMORTAL", + "aiFlags" : "+AIF_UNLIMITED_RANGE" + }, + { + "types" : "TAF;Ray", + "number" : 6, + "side" : "SIDE_ALLIES", + "x" : 45, + "y" : 25, + "scatter" : 500, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "types" : "Rapid Plasma Turret", + "number" : 8, + "side" : "SIDE_REBEL", + "x" : 10, + "y" : 25, + "scatter" : 700 + }, + { + "types" : "Shale;Razor", + "number" : 7, + "side" : "SIDE_REBEL", + "x" : 30, + "y" : 28, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "scatter" : 500 + }, + { + "groupName" : "Rebels-1", + "types" : "SK-31;SK-34", + "number" : 7, + "side" : "SIDE_REBEL", + "x" : 25, + "y" : 28, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "scatter" : 500, + "active" : 0 + }, + { + "groupName" : "Rebels-2", + "types" : "Blizzard", + "number" : 5, + "side" : "SIDE_REBEL", + "x" : 20, + "y" : 25, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "scatter" : 500, + "active" : 0 + } + ], + "entities" : [ + { + "name" : "Jumpgate", + "type" : "ET_JUMPGATE", + "side" : "SIDE_REBEL", + "x" : 10, + "y" : 25 + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX Wolfenden;Our goal is the jumpgate. Expect a lot of resistance.", + "MSG_BOX Wolfenden;Once we're they, we need to destroy the control nodes to shut it down. Barclay, that's your job." + ] + }, + { + "function" : "ENEMIES_KILLED 7", + "lines" : [ + "WAIT 2", + "MSG_BOX Wingmate;More enemies incoming.", + "ACTIVATE_ENTITY_GROUPS Rebels-1" + ] + }, + { + "function" : "ENEMIES_KILLED 14", + "lines" : [ + "WAIT 5", + "MSG_BOX Wingmate;Commander, I'm detecting a wing of Blizzards, incoming.", + "MSG_BOX Wolfenden;Couldn't expect Tzac not to bring out the heavy guns. Let's take it to them, people.", + "ACTIVATE_ENTITY_GROUPS Rebels-2" + ] + }, + { + "function" : "ENEMIES_KILLED 19", + "lines" : [ + "WAIT 1", + "MSG_BOX Wolfenden;We're clear for the run against the gate.", + "MSG_BOX Wolfenden;It's guarded by several rapid-fire plasma turrets. Try not to let those things get a lock on you." + ] + }, + { + "function" : "JUMPGATE_HEALTH 5", + "lines" : [ + "MSG_BOX Barclay;Half the nodes are down.", + "MSG_BOX Wolfenden;Keep at it!" + ] + }, + { + "function" : "JUMPGATE_HEALTH 1", + "lines" : [ + "WAIT 1", + "MSG_BOX Barclay;Jumpgate is down." + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 1", + "MSG_BOX Wolfenden;Control, this is Wolfenden. Tzac's outer jumpgate is offline.", + "MSG_BOX Control;Acknowledged. Hold position there. We'll need you to guard that gate and prevent the enemy from affecting repairs.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + }, + { + "function" : "ALLIES_KILLED 6", + "lines" : [ + "WAIT 1", + "MSG_BOX Wolfenden;Dammit, the team's been cut down! Looks like it's up to you and me, Ian.", + "MSG_BOX Barclay;We'll make sure their deaths weren't in vain." + ] + } + ] +} diff --git a/data/missions/mace/01 - rebel assault #1.json b/data/missions/mace/01 - rebel assault #1.json deleted file mode 100644 index 11f2eb6..0000000 --- a/data/missions/mace/01 - rebel assault #1.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name" : "Rebel Assault #1", - "description" : "", - "requires" : 99, - "background" : "gfx/backgrounds/background03.jpg", - "planet" : "gfx/planets/spirit.png", - "music" : "music/battle/InnerCore_Low.ogg", - "player" : { - "type" : "TAF", - "pilot" : "", - "squadron" : "", - "side" : "SIDE_ALLIES", - "x" : 10, - "y" : 10 - }, - "capitalShips" : [ - { - "name" : "CSN Corvette", - "types" : "UNF Corvette 01", - "side" : "SIDE_ALLIES", - "x" : 11, - "y" : 11, - "flags" : "EF_AI_TARGET" - }, - { - "name" : "Rebel Corvette", - "types" : "UNF Corvette 01", - "side" : "SIDE_REBEL", - "x" : 25, - "y" : 25, - "flags" : "EF_AI_TARGET" - } - ], - "fighters" : [ - { - "types" : "TAF;Rook;Ray", - "number" : 12, - "side" : "SIDE_ALLIES", - "x" : 10, - "y" : 10, - "scatter" : 1000 - }, - { - "types" : "Firefly;Nymph;Leopard", - "number" : 12, - "side" : "SIDE_REBEL", - "x" : 20, - "y" : 20, - "scatter" : 500 - } - ], - "script" : [ - { - "function" : "CAP_HEALTH CSN Corvette 4", - "lines" : [ - "IMPORTANT_MSG_BOX CSN Corvette;We're taking a lot of damage here. Please assist." - ] - }, - { - "function" : "Rebel Corvette", - "lines" : [ - "RETREAT_ENEMIES" - ] - } - ] -} diff --git a/data/missions/mace/02 - mace assault #2.json b/data/missions/mace/02 - mace assault #2.json new file mode 100644 index 0000000..474a667 --- /dev/null +++ b/data/missions/mace/02 - mace assault #2.json @@ -0,0 +1,154 @@ +{ + "name" : "Mace Assault #2", + "description" : "", + "requires" : 50, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/DST-RailJet-LongSeamlessLoop.ogg", + "manualComplete" : 1, + "player" : { + "type" : "Leopard", + "pilot" : "Cdr. Chao Lee", + "squadron" : "The Infinites", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45 + }, + "objectives" : [ + { + "description" : "Destroy HMS 781-110", + "targetName" : "HMS 781-110", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Destroy HMS 781-041", + "targetName" : "HMS 781-041", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Eliminate all enemies", + "targetName" : "ENEMY", + "targetType" : "TT_DESTROY", + "targetValue" : 1, + "isEliminateAll" : 1 + } + ], + "fighters" : [ + { + "types" : "Rook", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500 + }, + { + "types" : "Hammerhead;Lynx", + "number" : 10, + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500 + }, + { + "types" : "Shale", + "number" : 5, + "side" : "SIDE_REBEL", + "x" : 15, + "y" : 35, + "scatter" : 600, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Cap02", + "types" : "Shale", + "number" : 5, + "side" : "SIDE_REBEL", + "x" : 15, + "y" : 35, + "scatter" : 600, + "aiFlags" : "+AIF_MOVES_TO_LEADER", + "active" : 0 + }, + { + "groupName" : "Rebels-2", + "types" : "Shale", + "number" : 15, + "side" : "SIDE_REBEL", + "x" : 15, + "y" : 51, + "scatter" : 600, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + } + ], + "capitalShips" : [ + { + "name" : "HMS 781-110", + "types" : "HMS Corvette 01", + "side" : "SIDE_REBEL", + "x" : 15, + "y" : 35, + "flags" : "+EF_AI_LEADER" + }, + { + "groupName" : "Cap02", + "name" : "HMS 781-041", + "types" : "HMS Corvette 02", + "side" : "SIDE_REBEL", + "x" : 15, + "y" : 51, + "flags" : "+EF_AI_LEADER", + "active" : 0 + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX Lee;HMS 781-110 sighted. All fighters free to engage at will. Follow my lead." + ] + }, + { + "function" : "Destroy HMS 781-110", + "lines" : [ + "WAIT 1", + "MSG_BOX Lee;Control, HMS 781-110 has been taken down.", + "WAIT_MSG_BOX", + "WAIT 5", + "ACTIVATE_ENTITY_GROUPS Cap02", + "MSG_BOX Control;Infinites, HMS 781-041 has arrived in the area. Engage and destroy.", + "MSG_BOX Lee;Acknowledged." + ] + }, + { + "function" : "CAP_HEALTH HMS 781-041 3", + "lines" : [ + "ACTIVATE_ENTITY_GROUPS Rebels-2" + ] + }, + { + "function" : "CAP_HEALTH HMS 781-041 1", + "lines" : [ + "IMPORTANT_MSG_BOX HMS 781-041;This is HMS 781-041 of the Nation of Tzac! We surrender! Repeat, we surrender!", + "MSG_BOX Wingmate;Did anyone else get that?", + "MSG_BOX Lee;HMS 781-041, please repeat." + ] + }, + { + "function" : "Destroy HMS 781-041", + "lines" : [ + "RETREAT_ENEMIES", + "WAIT 1", + "MSG_BOX Lee;Hell! Too late!", + "MSG_BOX Control;Infinites, it appears remaining enemy forces are retreating. Please stand down.", + "MSG_BOX Lee;Received.", + "MSG_BOX Wingmate;That was unexpected.", + "MSG_BOX Lee;Sure was. We'd better get to debriefing.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} diff --git a/data/missions/mace/03 - mace assault #3.json b/data/missions/mace/03 - mace assault #3.json new file mode 100644 index 0000000..60b91b1 --- /dev/null +++ b/data/missions/mace/03 - mace assault #3.json @@ -0,0 +1,118 @@ +{ + "name" : "Mace Assault #3", + "description" : "", + "requires" : 50, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/track-3.mp3", + "player" : { + "pilot" : "2nd Lt. Jim Goddard", + "squadron" : "Iron Patriots", + "type" : "Ray", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 25 + }, + "objectives" : [ + { + "description" : "Eliminate Tzac opposition", + "targetName" : "Destroy", + "targetValue" : 45, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Disable 50%% of Tzac craft", + "targetName" : "Disable", + "targetValue" : 20, + "targetType" : "TT_DISABLE" + }, + { + "description" : "Do not destroy tagged Tzac craft", + "targetName" : "Disable", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isCondition" : 1 + } + ], + "fighters" : [ + { + "name" : "Carr", + "types" : "Kingfisher", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 25, + "scatter" : 500, + "flags" : "+EF_AI_LEADER+EF_IMMORTAL", + "aiFlags" : "+AIF_UNLIMITED_RANGE" + }, + { + "types" : "TAF;Hyena-A", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 25, + "scatter" : 500, + "number" : 6, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Destroy", + "types" : "Shale;SK-31;SK-34;Razor", + "side" : "SIDE_REBEL", + "x" : 25, + "y" : 25, + "scatter" : 15000, + "number" : 20, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Disable", + "types" : "Shale;SK-31;SK-34;Razor", + "side" : "SIDE_REBEL", + "x" : 25, + "y" : 25, + "scatter" : 15000, + "number" : 20, + "flags" : "+EF_MUST_DISABLE+EF_MISSION_TARGET", + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "groupName" : "Destroy", + "types" : "Rapid Plasma Turret;Rocket Turret", + "side" : "SIDE_REBEL", + "x" : 25, + "y" : 25, + "scatter" : 8000, + "number" : 25, + "flags" : "+EF_AI_LEADER" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Carr;We're going to mag half of their forces and destroy the others. The ones to disable have been tagged. Everyone clear?", + "MSG_BOX Carr;Watch your fire: remember, a stray shot could easily destroy a disabled craft." + ] + }, + { + "function" : "Disable 50%% of Tzac craft", + "lines" : [ + "WAIT 1", + "MSG_BOX Wingmate;All tagged Tzac fighters have been disabled." + ] + }, + { + "function" : "Eliminate Tzac opposition", + "lines" : [ + "WAIT 1", + "MSG_BOX Wingmate;Tzac opposition has been destroyed." + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "MSG_BOX Carr;Great work, everyone. That should give the PR guys something to brag about." + ] + } + ] +} diff --git a/data/missions/mace/04 - mace assault #4.json b/data/missions/mace/04 - mace assault #4.json new file mode 100644 index 0000000..b4c8f3f --- /dev/null +++ b/data/missions/mace/04 - mace assault #4.json @@ -0,0 +1,257 @@ +{ + "name" : "Mace Assault #4", + "description" : "", + "requires" : 56, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/DST-RailJet-LongSeamlessLoop.ogg", + "manualComplete" : 1, + "player" : { + "pilot" : "2nd Lt. Jim Goddard", + "squadron" : "Iron Patriots", + "type" : "Ray", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45 + }, + "objectives" : [ + { + "description" : "Eliminate all opposing forces", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + }, + { + "description" : "Destroy HMS 881-491", + "targetName" : "HMS 881-491", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "active" : 0 + }, + { + "description" : "Disable Christabel's transport", + "targetName" : "Christabel", + "targetValue" : 1, + "targetType" : "TT_DISABLE" + }, + { + "description" : "Do not destroy Christabel's transport", + "targetName" : "Christabel", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isCondition" : 1 + }, + { + "description" : "Do not allow Christabel to escape", + "targetName" : "Christabel", + "targetValue" : 1, + "targetType" : "TT_ESCAPED", + "isCondition" : 1 + } + ], + "fighters" : [ + { + "name" : "de Winter", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "flags" : "+EF_AI_LEADER", + "aiFlags" : "+AIF_UNLIMITED_RANGE" + }, + { + "types" : "TAF;Hammerhead;Lynx;Firefly;Nymph;Leopard;Rook", + "side" : "SIDE_ALLIES", + "x" : 5, + "y" : 45, + "scatter" : 500, + "number" : 12, + "aiFlags" : "+AIF_MOVES_TO_LEADER" + }, + { + "types" : "Rapid Plasma Turret", + "side" : "SIDE_REBEL", + "x" : 35, + "y" : 25, + "scatter" : 1000, + "number" : 12 + }, + { + "types" : "Blizzard;Shale", + "side" : "SIDE_REBEL", + "x" : 35, + "y" : 25, + "scatter" : 500, + "number" : 12 + }, + { + "groupName" : "CapShip", + "types" : "Jackal;Scarab", + "side" : "SIDE_PANDORAN", + "x" : 51, + "y" : 25, + "scatter" : 500, + "number" : 6, + "aiFlags" : "+AIF_MOVES_TO_LEADER+AIF_ASSASSIN", + "active" : 0 + }, + { + "groupName" : "ChristabelGroup", + "name" : "Christabel", + "types" : "Shuttle", + "side" : "SIDE_REBEL", + "x" : 25, + "y" : -1, + "flags" : "+EF_RETREATING+EF_MUST_DISABLE+EF_NO_THREAT+EF_MISSION_TARGET+EF_AI_TARGET+EF_AI_LEADER", + "aiFlags" : "+AIF_GOAL_JUMPGATE+AIF_UNLIMITED_RANGE+AIF_DEFENSIVE", + "active" : 0 + }, + { + "groupName" : "ChristabelGroup", + "types" : "Shale", + "side" : "SIDE_REBEL", + "x" : 25, + "y" : -1, + "number" : 2, + "aiFlags" : "+AIF_MOVES_TO_LEADER", + "active" : 0 + } + ], + "capitalShips" : [ + { + "groupName" : "CapShip", + "name" : "HMS 881-491", + "types" : "HMS Corvette 02", + "side" : "SIDE_PANDORAN", + "x" : 51, + "y" : 25, + "flags" : "+EF_AI_LEADER", + "aiFlags" : "+AIF_ASSASSIN", + "active" : 0 + } + ], + "spawners" : [ + { + "name" : "rebelSpawner", + "types" : "Dart;Shale", + "side" : "SIDE_REBEL", + "interval" : 3, + "total" : 15, + "step" : 1, + "offscreen" : 1, + "active" : 0 + }, + { + "name" : "pandoranSpawner", + "types" : "Jackal;Thunderhead;Mantis;Sphinx;Scarab", + "side" : "SIDE_PANDORAN", + "interval" : 30, + "total" : -1, + "step" : 1, + "active" : 0, + "aiFlags" : "+AIF_UNLIMITED_RANGE" + } + ], + "entities" : [ + { + "name" : "Jumpgate", + "type" : "ET_JUMPGATE", + "side" : "SIDE_NONE", + "x" : 35, + "y" : 25, + "flags" : "EF_AI_IGNORE+EF_NO_HEALTH_BAR" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX de Winter;All, our mission parameters have changed. The Pandorans are making a move against Mace. We need to act quickly.", + "MSG_BOX de Winter;Therefore, you have permission to destroy any and all opposing forces, no need to mag these guys." + ] + }, + { + "function" : "TIME 20", + "lines" : [ + "MSG_BOX Wingmate;Commander, we've got Darts and Shales incoming.", + "MSG_BOX de Winter;Looks like some mercenaries decided to stick around. Let's show them why that was a bad move.", + "WAIT_MSG_BOX", + "ACTIVATE_SPAWNER 1 rebelSpawner" + ] + }, + { + "function" : "ENEMIES_KILLED 15", + "lines" : [ + "WAIT 1", + "MSG_BOX de Winter;That's them seen to. Onwards to the jumpgate.", + "WAIT_MSG_BOX", + "WAIT 2", + "MSG_BOX Wingmate;Got INF fighters incoming.", + "MSG_BOX de Winter;Knew it wouldn't be long.", + "WAIT_MSG_BOX", + "ACTIVATE_SPAWNER 1 pandoranSpawner" + ] + }, + { + "function" : "TIME 270", + "lines" : [ + "WAIT 1", + "ACTIVATE_ENTITY_GROUPS CapShip", + "MSG_BOX Control;Patriots, a Tzac warship just arrived in the area, but it has Imperial fighter escorts. Most likely it's been acquired by the Pandroans. It needs to be taken down before Cristabel makes her escape bid, as it might be here to kill her.", + "MSG_BOX de Winter;Got it. You all heard that. Let's get to it.", + "ACTIVATE_OBJECTIVES Destroy HMS 881-491" + ] + }, + { + "function" : "TIME 300", + "lines" : [ + "ACTIVATE_ENTITY_GROUPS ChristabelGroup", + "IMPORTANT_MSG_BOX Wingmate;I'm picking up a shuttle on radar. Looks like Christabel.", + "IMPORTANT_MSG_BOX de Winter;Goddard, you're up! Mag that shuttle before it gets away.", + "IMPORTANT_MSG_BOX Goddard;On it!" + ] + }, + { + "function" : "Disable Christabel's transport", + "lines" : [ + "WAIT 1", + "MSG_BOX Goddard;Christabel's shuttle has been disabled.", + "MSG_BOX de Winter;Excellent work! Now let's finish off the rest of these fighters.", + "ACTIVATE_SPAWNER 0 pandoranSpawner" + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 1", + "CREATE_CRISTABEL_LOCATION", + "MSG_BOX de Winter;All enemies down. Let's get over to Christabel's shuttle and secure the empress." + ] + }, + { + "function" : "CristabelLocation", + "lines" : [ + "MSG_BOX de Winter;Empress Christabel, this is Cdr. de Winter of the Confederation Stellar Navy.", + "MSG_BOX de Winter;Acting under the authority of the allied forces, I am hereby placing you under arrest, for breaches of intergalactic law.", + "MSG_BOX de Winter;You will be escorted to a neutral court, where you will be tried for your crimes.", + "MSG_BOX de Winter;If found guilty, the intergalactic community will decide on your punishment.", + "MSG_BOX de Winter;Sorry, your Highness. I wish it didn't have to go this way, but the galaxy has enough problems as it is.", + "WAIT_MSG_BOX", + "MSG_BOX de Winter;If--", + "KILL_ENTITY Christabel", + "MSG_BOX Wingmate;Woah! What the hell just happened?!", + "MSG_BOX de Winter;Did anyone fire?!", + "MSG_BOX Goddard;All guns cold, Commander. Looks like she might have self destructed her own ship.", + "MSG_BOX de Winter;Dammit!", + "WAIT_MSG_BOX", + "WAIT 2", + "MSG_BOX Goddard;Now what?", + "MSG_BOX de Winter;Nothing more we can do. We should evacuate the area before more Pandoran forces arrive.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} diff --git a/data/missions/rothan/01 - rothan defence #1.json b/data/missions/rothan/01 - rothan defence #1.json index 4f86644..8e4ca0f 100644 --- a/data/missions/rothan/01 - rothan defence #1.json +++ b/data/missions/rothan/01 - rothan defence #1.json @@ -4,7 +4,7 @@ "requires" : 29, "background" : "gfx/backgrounds/background05.jpg", "planet" : "gfx/planets/bluePlanet.png", - "music" : "music/battle/track-1.mp3", + "music" : "music/battle/track-4.mp3", "manualComplete" : 1, "objectives" : [ { diff --git a/data/missions/rothan/04 - rothan offence #1.json b/data/missions/rothan/04 - rothan offence #1.json index 9f09b28..ce75e1e 100644 --- a/data/missions/rothan/04 - rothan offence #1.json +++ b/data/missions/rothan/04 - rothan offence #1.json @@ -1,7 +1,7 @@ { "name" : "Rothan Offensive #1", "description" : "With the mercenary threat seen off and Tzac's initial attacks thwarted, it's time to begin pushing back against Christabel's forces. We plan to capture a number of their commanders, to help build a better picture of the forces at Mace, before moving into the system. As always, mag the targets and do not allow them to be killed.", - "requires" : 45, + "requires" : 44, "manualComplete" : 1, "background" : "gfx/backgrounds/background05.jpg", "planet" : "gfx/planets/bluePlanet.png", @@ -56,7 +56,8 @@ "scatter" : 500 }, { - "name" : "Roselyn Rose", + "name" : "Rose", + "fullname" : "Roselyn Rose", "types" : "Ray", "side" : "SIDE_ALLIES", "x" : 10, diff --git a/data/missions/rothan/05 - rothan defence #4.json b/data/missions/rothan/05 - rothan defence #4.json new file mode 100644 index 0000000..a659824 --- /dev/null +++ b/data/missions/rothan/05 - rothan defence #4.json @@ -0,0 +1,66 @@ +{ + "name" : "Rothan Defence #4", + "description" : "The Pandorans have launched a sudden attack against the system. It appears that they are capitalizing on the chaos that the Kingdom of Tzac has thrown us into. We need to repel this attack, as defeat here could mean a major setback in our struggle against both enemies.", + "requires" : 47, + "manualComplete" : 1, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/Tactical Pursuit.mp3", + "epic" : { + "fighterLimit" : 18 + }, + "objectives" : [ + { + "description" : "Destroy all enemy targets", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + } + ], + "player" : { + "type" : "Rook", + "side" : "SIDE_ALLIES", + "pilot" : "(Multiple)", + "squadron" : "(Multiple)" + }, + "fighters" : [ + { + "name" : "ALLIES", + "types" : "Firefly;Nymph;TAF;Ray;Leopard;Hyena-A;Hyena-B;Kingfisher;Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "number" : 50, + "scatter" : 5000 + }, + { + "name" : "Pandoran", + "types" : "Jackal;Scarab;Mantis;Swarmer;Swarmer", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 15, + "number" : 100, + "scatter" : 5000 + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX Wingmate;Hell, they're outnumbering us, a good two-to-one!", + "MSG_BOX Wing Commander;There are Swarmers in their ranks, making up the bulk. Don't lose faith people, we can do this." + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 1", + "MSG_BOX Wing Commander;That's the last of 'em. Not often we win an engagement like this.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} + diff --git a/data/missions/rothan/06 - rothan defence #5.json b/data/missions/rothan/06 - rothan defence #5.json new file mode 100644 index 0000000..866b88a --- /dev/null +++ b/data/missions/rothan/06 - rothan defence #5.json @@ -0,0 +1,159 @@ +{ + "name" : "Rothan Defence #5", + "description" : "", + "requires" : 54, + "manualComplete" : 1, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/Tactical Pursuit.mp3", + "unwinnable" : 1, + "epic" : { + "fighterLimit" : 18 + }, + "objectives" : [ + { + "description" : "Destroy all enemy targets", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1 + }, + { + "description" : "Destroy INF Mora", + "targetName" : "INF Mora", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Destroy INF Karambit", + "targetName" : "INF Karambit", + "targetValue" : 1, + "targetType" : "TT_DESTROY" + } + ], + "player" : { + "type" : "Rook", + "side" : "SIDE_ALLIES", + "pilot" : "(Multiple)", + "squadron" : "(Multiple)" + }, + "fighters" : [ + { + "types" : "Firefly;Nymph;TAF;Ray;Leopard;Hyena-A;Hyena-B;Kingfisher;Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "number" : 100, + "scatter" : 5000, + "flags" : "+EF_AI_TARGET" + }, + { + "name" : "Pandoran", + "types" : "Jackal;Scarab;Mantis;Thunderhead;Dart;Khepri;Swarmer", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 15, + "number" : 999, + "scatter" : 5000, + "flags" : "+EF_AI_TARGET" + } + ], + "capitalShips" : [ + { + "name" : "UNF Hopper", + "types" : "UNF Corvette 01", + "side" : "SIDE_ALLIES", + "x" : 20, + "y" : 20, + "flags" : "+EF_AI_TARGET" + }, + { + "name" : "UNF Blackburn", + "types" : "UNF Corvette 02", + "side" : "SIDE_ALLIES", + "x" : 20, + "y" : 40, + "flags" : "+EF_AI_TARGET" + }, + { + "name" : "INF Mora", + "types" : "INF Corvette 02", + "side" : "SIDE_PANDORAN", + "x" : 40, + "y" : 20, + "flags" : "+EF_MISSION_TARGET" + }, + { + "name" : "INF Karambit", + "types" : "INF Corvette 02", + "side" : "SIDE_PANDORAN", + "x" : 40, + "y" : 40, + "flags" : "+EF_MISSION_TARGET" + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX Wing Commander;Brace yourselves, lads.", + "MSG_BOX Wingmate;Picking up two Mitikas corvettes: Mora and Karambit.", + "MSG_BOX Wing Commander;We need to give Hopper and Blackburn support in dealing with them. Get to it." + ] + }, + { + "function" : "TIME 60", + "lines" : [ + "MSG_BOX Wingmate;Hell, where'd they get those Khepris from?", + "MSG_BOX Wingmate;Crystabel must've decided to try and attack the Pandorans directly. Went as well for her as it did for us." + ] + }, + { + "function" : "ALLIES_KILLED 30", + "lines" : [ + "MSG_BOX Wingmate;Commander, we're taking heavy losses!", + "MSG_BOX Wing Commander;We won before, we can win again! Keep up the fight!" + ] + }, + { + "function" : "ALLIES_KILLED 80", + "lines" : [ + "MSG_BOX Wingmate;Commander, I strongly suggest we pull back.", + "MSG_BOX Wing Commander;We can't keep running. We'll run out of places to run to." + ] + }, + { + "function" : "ALLIES_KILLED 90", + "lines" : [ + "MSG_BOX Wingmate;All fighters, be advised: the wing commander has been killed.", + "MSG_BOX Wingmate;Who's leading this operation now?", + "MSG_BOX Wingmate;We have to retreat!" + ] + }, + { + "function" : "ALLIES_KILLED 98", + "lines" : [ + "MSG_BOX Wingmate;This the end of the line, guys. It's been great serving with you." + ] + }, + { + "function" : "UNF Hopper", + "lines" : [ + "MSG_BOX Wingmate;Hopper is down!" + ] + }, + { + "function" : "UNF Blackburn", + "lines" : [ + "MSG_BOX Wingmate;They've taken out Blackburn!" + ] + }, + { + "function" : "CAPITAL_SHIPS_LOST 2", + "lines" : [ + "MSG_BOX Wingmate;That's both of our corvettes down. The rest is up to us." + ] + } + ] +} + diff --git a/data/missions/sol/03 - moving target.json b/data/missions/sol/03 - moving target.json index 096b3c3..1f95f79 100644 --- a/data/missions/sol/03 - moving target.json +++ b/data/missions/sol/03 - moving target.json @@ -24,7 +24,16 @@ "types" : "Unarmed Dart", "side" : "SIDE_PIRATE", "x" : 25, - "y" : 24 + "y" : 24, + "aiFlags" : "+AIF_DEFENSIVE" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Earth Orbital #1;This Dart has control over its engines, but not its weapons. Practice chasing it down and destroying it." + ] } ] } diff --git a/data/missions/sol/04 - armed target.json b/data/missions/sol/04 - armed target.json index 0d1a296..2251cae 100644 --- a/data/missions/sol/04 - armed target.json +++ b/data/missions/sol/04 - armed target.json @@ -26,5 +26,13 @@ "x" : 25, "y" : 24 } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Earth Orbital #1;This Dart is armed! Watch yourself." + ] + } ] } diff --git a/data/missions/sol/05 - ecm.json b/data/missions/sol/05 - ecm.json index 1705bef..ab2535d 100644 --- a/data/missions/sol/05 - ecm.json +++ b/data/missions/sol/05 - ecm.json @@ -26,5 +26,13 @@ "x" : 25, "y" : 24 } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Earth Orbital #1;Use your ECM to destroy the missiles fired at you. Remember, the ECM needs several seconds to recharge between uses." + ] + } ] } diff --git a/data/missions/sol/07 - wingmates.json b/data/missions/sol/07 - wingmates.json index d180ab1..a382d07 100644 --- a/data/missions/sol/07 - wingmates.json +++ b/data/missions/sol/07 - wingmates.json @@ -41,5 +41,13 @@ "x" : 26, "y" : 20 } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Earth Orbital #1;Wingmate will often assist you in battle. When you're ready, approach the Darts and engage." + ] + } ] } diff --git a/data/missions/sol/08 - final.json b/data/missions/sol/08 - final.json index cc90f1d..82e0b09 100644 --- a/data/missions/sol/08 - final.json +++ b/data/missions/sol/08 - final.json @@ -27,5 +27,13 @@ "x" : 26, "y" : 20 } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Earth Orbital #1;Final course. Use all your training to defeat the three opponents." + ] + } ] } diff --git a/data/missions/trilliack/02 - trilliack defence #2.json b/data/missions/trilliack/02 - trilliack defence #2.json index ec0949b..a78d1d6 100644 --- a/data/missions/trilliack/02 - trilliack defence #2.json +++ b/data/missions/trilliack/02 - trilliack defence #2.json @@ -100,30 +100,6 @@ "WAIT_MSG_BOX", "COMPLETE_MISSION" ] - }, - { - "function" : "CAP_ENGINES_DESTROYED UNF Lovelace", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Lovelace;Our engines have been shot out! We're a sitting duck!" - ] - }, - { - "function" : "CAP_HEALTH UNF Lovelace 6", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Lovelace;We're taking damage here, Sparrows. Please step it up." - ] - }, - { - "function" : "CAP_HEALTH UNF Lovelace 3", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Lovelace;We're sustaining heavy damage! All fighters, please assist, ASAP!" - ] - }, - { - "function" : "CAP_HEALTH UNF Lovelace 1", - "lines" : [ - "IMPORTANT_MSG_BOX UNF Lovelace;Mayday! Mayday! Defences are critical. We can't hold out much longer!" - ] } ] } diff --git a/data/trophies/trophies.json b/data/trophies/trophies.json index 3d529d1..9155b27 100644 --- a/data/trophies/trophies.json +++ b/data/trophies/trophies.json @@ -1,64 +1,16 @@ [ { - "id" : "PLATINUM", + "id" : "_PLATINUM", "title" : "One of the seven", "description" : "Earn all other trophies", "value" : "TROPHY_PLATINUM" }, { "id" : "CAMPAIGN_1", - "title" : "2nd Lieutenant", + "title" : "Gentle start", "description" : "Complete a campaign mission", "value" : "TROPHY_BRONZE" }, - { - "id" : "CAMPAIGN_10", - "title" : "1st Lieutenant", - "description" : "Complete 10% of all missions", - "value" : "TROPHY_BRONZE" - }, - { - "id" : "CAMPAIGN_20", - "title" : "Lieutenant Commander", - "description" : "Complete 20% of all missions", - "value" : "TROPHY_BRONZE" - }, - { - "id" : "CAMPAIGN_40", - "title" : "Commander", - "description" : "Complete 40% of all missions", - "value" : "TROPHY_BRONZE" - }, - { - "id" : "CAMPAIGN_50", - "title" : "Captain", - "description" : "Complete 50% of all missions", - "value" : "TROPHY_SILVER" - }, - { - "id" : "CAMPAIGN_60", - "title" : "Commodore", - "description" : "Complete 60% of all missions", - "value" : "TROPHY_SILVER" - }, - { - "id" : "CAMPAIGN_80", - "title" : "Rear Admiral", - "description" : "Complete 80% of all missions", - "value" : "TROPHY_SILVER" - }, - { - "id" : "CAMPAIGN_90", - "title" : "Admiral", - "description" : "Complete 90% of all missions", - "value" : "TROPHY_GOLD" - }, - { - "id" : "CAMPAIGN_100", - "title" : "Fleet Admiral", - "description" : "Complete all campaign missions", - "value" : "TROPHY_GOLD" - }, { "id" : "CAMPAIGN_SOL", "title" : "Ready for duty", @@ -95,11 +47,25 @@ }, { "id" : "CAMPAIGN_MACE", - "title" : "Going out with a bang.", + "title" : "Going out with a bang", "description" : "Complete all missions at Mace", "value" : "TROPHY_SILVER", "hidden" : 1 }, + { + "id" : "CAMPAIGN_ROTHAN", + "title" : "Back against the wall", + "description" : "Complete all missions at Rothan", + "value" : "TROPHY_SILVER", + "hidden" : 1 + }, + { + "id" : "CAMPAIGN_CLARKE", + "title" : "Now what do we do?", + "description" : "Complete all missions at Clarke", + "value" : "TROPHY_SILVER", + "hidden" : 1 + }, { "id" : "EPIC", "title" : "Truly epic", @@ -114,6 +80,14 @@ "stat" : "STAT_CAPITAL_SHIPS_DESTROYED", "statValue" : 1 }, + { + "id" : "GIANT_SLAYER", + "title" : "Giant Slayer", + "description" : "Destroy 25 enemy capital ships", + "value" : "TROPHY_GOLD", + "stat" : "STAT_CAPITAL_SHIPS_DESTROYED", + "statValue" : 25 + }, { "id" : "PANDORAN", "title" : "Plenty more where that came from, unfortunately", @@ -122,7 +96,7 @@ }, { "id" : "ATAF", - "title" : "Man, I gotta get me one of these!", + "title" : "Oh man, I gotta get me one of these!", "description" : "Pilot an ATAF during the campaign", "value" : "TROPHY_BRONZE" }, @@ -142,33 +116,65 @@ "id" : "TEAM_PLAYER", "title" : "Taking one for the team", "description" : "Be killed by a missile that was meant for someone else", - "value" : "TROPHY_SILVER" + "value" : "TROPHY_BRONZE", + "hidden" : 1 }, { - "id" : "CHALLENGE_25", - "title" : "", - "description" : "Complete 25% of all challenges", + "id" : "BODYGUARD", + "title" : "The bodyguard", + "description" : "Kill an enemy with a missile intended for their wing leader", + "value" : "TROPHY_BRONZE", + "hidden" : 1 + }, + { + "id" : "_CHALLENGE_25", + "title" : "Dedicated", + "description" : "Complete 25%% of all challenges", "value" : "TROPHY_BRONZE" }, { - "id" : "CHALLENGE_50", - "title" : "", - "description" : "Complete 50% of all challenges", + "id" : "_CHALLENGE_50", + "title" : "Obssessed", + "description" : "Complete 50%% of all challenges", "value" : "TROPHY_SILVER" }, { - "id" : "CHALLENGE_100", - "title" : "", - "description" : "Complete 100% of all challenges", + "id" : "_CHALLENGE_100", + "title" : "Completitonist", + "description" : "Complete 100%% of all challenges", "value" : "TROPHY_GOLD" }, + { + "id" : "ENEMY_50", + "title" : "Hero", + "description" : "Take down 50 enemies (player only)", + "value" : "TROPHY_BRONZE", + "stat" : "STAT_ENEMIES_KILLED_PLAYER", + "statValue" : 50 + }, + { + "id" : "ENEMY_500", + "title" : "Veteran", + "description" : "Take down 500 enemies (player only)", + "value" : "TROPHY_SILVER", + "stat" : "STAT_ENEMIES_KILLED_PLAYER", + "statValue" : 500 + }, + { + "id" : "ENEMY_5000", + "title" : "Legend", + "description" : "Take down 5,000 enemies (player only)", + "value" : "TROPHY_GOLD", + "stat" : "STAT_ENEMIES_KILLED_PLAYER", + "statValue" : 5000 + }, { "id" : "FIRE_100000", "title" : "Your name's on one of these!", "description" : "Fire 100,000 shots", "value" : "TROPHY_BRONZE", "stat" : "STAT_SHOTS_FIRED", - "statValue" : 10000 + "statValue" : 100000 }, { "id" : "MISSILE_1000", @@ -179,51 +185,97 @@ "statValue" : 1000 }, { - "id" : "ECM_100", + "id" : "ECM", "title" : "Isn't technology wonderful?", - "description" : "Use the ECM 100 times", + "description" : "Use the ECM 250 times", "value" : "TROPHY_BRONZE", "stat" : "STAT_ECM", - "statValue" : 100 + "statValue" : 250 }, { - "id" : "BOOST_100", + "id" : "BOOST", "title" : "Runaway!", - "description" : "Boost 100 times", + "description" : "Boost 250 times", "value" : "TROPHY_BRONZE", "stat" : "STAT_BOOST", + "statValue" : 250 + }, + { + "id" : "ITEMS", + "title" : "Hoarder", + "description" : "Collect 100 items", + "value" : "TROPHY_BRONZE", + "stat" : "STAT_ITEMS_COLLECTED_PLAYER", "statValue" : 100 }, { - "id" : "EVADE_50", + "id" : "EVADE", "title" : "Missed, you f**kers!", - "description" : "Evade 50 missiles", + "description" : "Evade 10 missiles", "value" : "TROPHY_BRONZE", "stat" : "STAT_MISSILES_EVADED", - "statValue" : 50, + "statValue" : 10, "hidden" : 1 }, { - "id" : "WAYPOINT_100", + "id" : "WAYPOINT", "title" : "Sightseer", "description" : "Visit 100 waypoints", "value" : "TROPHY_BRONZE", "stat" : "STAT_WAYPOINTS_VISITED", "statValue" : 100 }, + { + "id" : "MINESWEEPER", + "title" : "Minesweeper", + "description" : "Destroy 255 mines (player only)", + "value" : "TROPHY_BRONZE", + "stat" : "STAT_MINES_DESTROYED", + "statValue" : 255 + }, + { + "id" : "DISABLE", + "title" : "Get out and push", + "description" : "Disable 500 opponents", + "value" : "TROPHY_BRONZE", + "stat" : "STAT_ENEMIES_DISABLED", + "statValue" : 500 + }, { "id" : "EPIC_KILL_13", "title" : "Yippie-ki-yay", - "description" : "Destroy 13 or more enemies in an epic battle without being killed", + "description" : "Destroy 13 or more enemies in an epic battle, without being killed", "value" : "TROPHY_SILVER", "stat" : "STAT_EPIC_KILL_STREAK", - "statValue" : 13 + "statValue" : 13, + "hidden" : 1 + }, + { + "id" : "SURVIVOR", + "title" : "Survivor", + "description" : "Complete an epic battle without being killed", + "value" : "TROPHY_SILVER", + "hidden" : 1 }, { "id" : "ATAF_DESTROYED", - "title" : "Almost indestructable. Almost.", + "title" : "Almost indestructable. Almost", "description" : "Be destroyed while piloting an ATAF", "value" : "TROPHY_BRONZE", "hidden" : 1 + }, + { + "id" : "PACIFIST", + "title" : "Pacifist", + "description" : "Complete a fighter-based campaign mission without firing", + "value" : "TROPHY_BRONZE", + "hidden" : 1 + }, + { + "id" : "2_BIRDS", + "title" : "2 birds, 1 stone", + "description" : "Destroy two or more fighters by shooting one mine", + "value" : "TROPHY_BRONZE", + "hidden" : 1 } ] diff --git a/data/widgets/challenges.json b/data/widgets/challenges.json index c515f64..fc7b7b1 100644 --- a/data/widgets/challenges.json +++ b/data/widgets/challenges.json @@ -1,4 +1,54 @@ [ + { + "name" : "resume", + "group" : "challengesMenu", + "type" : "WT_BUTTON", + "text" : "Resume", + "x" : -1, + "y" : 170, + "w" : 200, + "h": 34 + }, + { + "name" : "stats", + "group" : "challengesMenu", + "type" : "WT_BUTTON", + "text" : "Stats", + "x" : -1, + "y" : 270, + "w" : 200, + "h": 34 + }, + { + "name" : "trophies", + "group" : "challengesMenu", + "type" : "WT_BUTTON", + "text" : "Trophies", + "x" : -1, + "y" : 370, + "w" : 200, + "h": 34 + }, + { + "name" : "options", + "group" : "challengesMenu", + "type" : "WT_BUTTON", + "text" : "Options", + "x" : -1, + "y" : 470, + "w" : 200, + "h": 34 + }, + { + "name" : "quit", + "group" : "challengesMenu", + "type" : "WT_BUTTON", + "text" : "Return to Title", + "x" : -1, + "y" : 570, + "w" : 200, + "h": 34 + }, { "name" : "start", "group" : "challenges", @@ -10,43 +60,23 @@ "h": 34 }, { - "name" : "resume", - "group" : "challengesMenu", - "type" : "WT_BUTTON", - "text" : "Resume", - "x" : -1, - "y" : 215, - "w" : 200, - "h": 34 + "name" : "prev", + "group" : "challenges", + "type" : "WT_IMG_BUTTON", + "x" : 540, + "y" : 110, + "w" : 150, + "h": 34, + "texture" : "gfx/widgets/optionsLeft.png" }, { - "name" : "stats", - "group" : "challengesMenu", - "type" : "WT_BUTTON", - "text" : "Stats", - "x" : -1, - "y" : 315, - "w" : 200, - "h": 34 - }, - { - "name" : "options", - "group" : "challengesMenu", - "type" : "WT_BUTTON", - "text" : "Options", - "x" : -1, - "y" : 415, - "w" : 200, - "h": 34 - }, - { - "name" : "quit", - "group" : "challengesMenu", - "type" : "WT_BUTTON", - "text" : "Return to Title", - "x" : -1, - "y" : 515, - "w" : 200, - "h": 34 + "name" : "next", + "group" : "challenges", + "type" : "WT_IMG_BUTTON", + "x" : 720, + "y" : 110, + "w" : 150, + "h": 34, + "texture" : "gfx/widgets/optionsRight.png" } ] diff --git a/data/widgets/galacticMap.json b/data/widgets/galacticMap.json index 60f2dd7..11302de 100644 --- a/data/widgets/galacticMap.json +++ b/data/widgets/galacticMap.json @@ -5,7 +5,7 @@ "type" : "WT_BUTTON", "text" : "Resume", "x" : -1, - "y" : 215, + "y" : 170, "w" : 200, "h": 34 }, @@ -15,7 +15,17 @@ "type" : "WT_BUTTON", "text" : "Stats", "x" : -1, - "y" : 315, + "y" : 270, + "w" : 200, + "h": 34 + }, + { + "name" : "trophies", + "group" : "galacticMap", + "type" : "WT_BUTTON", + "text" : "Trophies", + "x" : -1, + "y" : 370, "w" : 200, "h": 34 }, @@ -25,7 +35,7 @@ "type" : "WT_BUTTON", "text" : "Options", "x" : -1, - "y" : 415, + "y" : 470, "w" : 200, "h": 34 }, @@ -35,7 +45,7 @@ "type" : "WT_BUTTON", "text" : "Return to Title", "x" : -1, - "y" : 515, + "y" : 570, "w" : 200, "h": 34 }, diff --git a/data/widgets/title.json b/data/widgets/title.json index 9329241..0fb2002 100644 --- a/data/widgets/title.json +++ b/data/widgets/title.json @@ -5,7 +5,7 @@ "type" : "WT_BUTTON", "text" : "Campaign", "x" : -1, - "y" : 225, + "y" : 200, "w" : 200, "h": 34 }, @@ -15,7 +15,17 @@ "type" : "WT_BUTTON", "text" : "Challenges", "x" : -1, - "y" : 325, + "y" : 290, + "w" : 200, + "h": 34 + }, + { + "name" : "trophies", + "group" : "title", + "type" : "WT_BUTTON", + "text" : "Trophies", + "x" : -1, + "y" : 380, "w" : 200, "h": 34 }, @@ -25,7 +35,7 @@ "type" : "WT_BUTTON", "text" : "Stats", "x" : -1, - "y" : 425, + "y" : 470, "w" : 200, "h": 34 }, @@ -35,7 +45,7 @@ "type" : "WT_BUTTON", "text" : "Options", "x" : -1, - "y" : 525, + "y" : 560, "w" : 200, "h": 34 }, @@ -45,7 +55,7 @@ "type" : "WT_BUTTON", "text" : "Quit", "x" : -1, - "y" : 625, + "y" : 650, "w" : 200, "h": 34 } diff --git a/data/widgets/trophies.json b/data/widgets/trophies.json new file mode 100644 index 0000000..7011b99 --- /dev/null +++ b/data/widgets/trophies.json @@ -0,0 +1,32 @@ +[ + { + "name" : "ok", + "group" : "trophies", + "type" : "WT_BUTTON", + "text" : "OK", + "x" : -1, + "y" : 665, + "w" : 150, + "h": 34 + }, + { + "name" : "prev", + "group" : "trophies", + "type" : "WT_IMG_BUTTON", + "x" : 540, + "y" : 110, + "w" : 150, + "h": 34, + "texture" : "gfx/widgets/optionsLeft.png" + }, + { + "name" : "next", + "group" : "trophies", + "type" : "WT_IMG_BUTTON", + "x" : 720, + "y" : 110, + "w" : 150, + "h": 34, + "texture" : "gfx/widgets/optionsRight.png" + } +] diff --git a/dev/screenshots/v0.7-01.png b/dev/screenshots/v0.7-01.png new file mode 100644 index 0000000..8ed9a2e Binary files /dev/null and b/dev/screenshots/v0.7-01.png differ diff --git a/dev/screenshots/v0.7-02.png b/dev/screenshots/v0.7-02.png new file mode 100644 index 0000000..8e2bc13 Binary files /dev/null and b/dev/screenshots/v0.7-02.png differ diff --git a/dev/screenshots/v0.7-03.png b/dev/screenshots/v0.7-03.png new file mode 100644 index 0000000..0768b7a Binary files /dev/null and b/dev/screenshots/v0.7-03.png differ diff --git a/dev/screenshots/v0.7-04.png b/dev/screenshots/v0.7-04.png new file mode 100644 index 0000000..1768f0e Binary files /dev/null and b/dev/screenshots/v0.7-04.png differ diff --git a/dev/screenshots/v0.7-05.png b/dev/screenshots/v0.7-05.png new file mode 100644 index 0000000..f0cb347 Binary files /dev/null and b/dev/screenshots/v0.7-05.png differ diff --git a/dev/screenshots/v0.7-06.png b/dev/screenshots/v0.7-06.png new file mode 100644 index 0000000..210a128 Binary files /dev/null and b/dev/screenshots/v0.7-06.png differ diff --git a/dev/stats.sh b/dev/stats.sh index 5ce75db..948f5cc 100755 --- a/dev/stats.sh +++ b/dev/stats.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -STATS_FILE="stats.md" +STATS_FILE="STATS.md" cd .. @@ -14,7 +14,7 @@ SRC_LINES=`find src -name *.c | xargs wc -l | grep total | awk '{print $1}'` NUM_MISSIONS=`find data/missions -iname *.json | wc -l` NUM_CHALLENGES=`find data -name '*.json' -print0 | xargs -0 cat | grep "\"type\" : \"CHALLENGE_" | wc -l` -NUM_TROPHIES=`cat data/trophies/trophies.json | grep id | wc -l` +NUM_TROPHIES=`cat data/trophies/trophies.json | grep \"description\" | wc -l` NUM_CRAFT=`find data/craft/* | wc -l` NUM_FIGHTERS=`find data/fighters/* | wc -l` @@ -22,6 +22,8 @@ NUM_GUNS=`find data/turrets/* | wc -l` NUM_CAPS=`find data/capitalShips/* | wc -l` TOTAL_CRAFT=$(($NUM_CRAFT + $NUM_FIGHTERS + $NUM_GUNS + $NUM_CAPS)) +REVISIONS=`git rev-list --all --count` + LOCALE=`cat locale/tbftss.pot | grep msgid | wc -l` echo "# Statistics" > $STATS_FILE @@ -35,10 +37,13 @@ echo "* Size of sound: $SND_SIZE" >> $STATS_FILE echo "* Size of music: $MUSIC_SIZE" >> $STATS_FILE echo "" >> $STATS_FILE -echo "* Number of missions: $NUM_MISSIONS" >> $STATS_FILE +echo "* Number of missions: $NUM_MISSIONS (inc. Sol)" >> $STATS_FILE echo "* Number of challenges: $NUM_CHALLENGES" >> $STATS_FILE echo "* Number of spacecraft: $TOTAL_CRAFT" >> $STATS_FILE echo "* Number of trophies: $NUM_TROPHIES" >> $STATS_FILE echo "" >> $STATS_FILE echo "* Translatable strings: $LOCALE" >> $STATS_FILE +echo "" >> $STATS_FILE + +echo "* Number of GIT revisions: $REVISIONS" >> $STATS_FILE diff --git a/gfx/capitalShips/hmsCorvette01/body.png b/gfx/capitalShips/hmsCorvette01/body.png new file mode 100644 index 0000000..2ce07b3 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/body.png differ diff --git a/gfx/capitalShips/hmsCorvette01/component1.png b/gfx/capitalShips/hmsCorvette01/component1.png new file mode 100644 index 0000000..1e745f5 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/component1.png differ diff --git a/gfx/capitalShips/hmsCorvette01/component2.png b/gfx/capitalShips/hmsCorvette01/component2.png new file mode 100644 index 0000000..cdd84b0 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/component2.png differ diff --git a/gfx/capitalShips/hmsCorvette01/core.png b/gfx/capitalShips/hmsCorvette01/core.png new file mode 100644 index 0000000..30d2dd7 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/core.png differ diff --git a/gfx/capitalShips/hmsCorvette01/engine1.png b/gfx/capitalShips/hmsCorvette01/engine1.png new file mode 100644 index 0000000..c5a94ff Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/engine1.png differ diff --git a/gfx/capitalShips/hmsCorvette01/engine2.png b/gfx/capitalShips/hmsCorvette01/engine2.png new file mode 100644 index 0000000..ea0a8bf Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/engine2.png differ diff --git a/gfx/capitalShips/hmsCorvette01/engine3.png b/gfx/capitalShips/hmsCorvette01/engine3.png new file mode 100644 index 0000000..47e54ff Binary files /dev/null and b/gfx/capitalShips/hmsCorvette01/engine3.png differ diff --git a/gfx/capitalShips/hmsCorvette02/body.png b/gfx/capitalShips/hmsCorvette02/body.png new file mode 100644 index 0000000..c39346d Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/body.png differ diff --git a/gfx/capitalShips/hmsCorvette02/component1.png b/gfx/capitalShips/hmsCorvette02/component1.png new file mode 100644 index 0000000..5e66e32 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/component1.png differ diff --git a/gfx/capitalShips/hmsCorvette02/component2.png b/gfx/capitalShips/hmsCorvette02/component2.png new file mode 100644 index 0000000..f239c00 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/component2.png differ diff --git a/gfx/capitalShips/hmsCorvette02/component3.png b/gfx/capitalShips/hmsCorvette02/component3.png new file mode 100644 index 0000000..e6d8252 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/component3.png differ diff --git a/gfx/capitalShips/hmsCorvette02/core.png b/gfx/capitalShips/hmsCorvette02/core.png new file mode 100644 index 0000000..30d2dd7 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/core.png differ diff --git a/gfx/capitalShips/hmsCorvette02/engine01.png b/gfx/capitalShips/hmsCorvette02/engine01.png new file mode 100644 index 0000000..0f13d52 Binary files /dev/null and b/gfx/capitalShips/hmsCorvette02/engine01.png differ diff --git a/gfx/fighters/angel.png b/gfx/fighters/angel.png new file mode 100644 index 0000000..2aea0ba Binary files /dev/null and b/gfx/fighters/angel.png differ diff --git a/gfx/items/coin01.png b/gfx/items/coin01.png new file mode 100644 index 0000000..d815e83 Binary files /dev/null and b/gfx/items/coin01.png differ diff --git a/gfx/items/coin02.png b/gfx/items/coin02.png new file mode 100644 index 0000000..8297648 Binary files /dev/null and b/gfx/items/coin02.png differ diff --git a/gfx/items/diamond01.png b/gfx/items/diamond01.png new file mode 100644 index 0000000..239a025 Binary files /dev/null and b/gfx/items/diamond01.png differ diff --git a/gfx/items/diamond02.png b/gfx/items/diamond02.png new file mode 100644 index 0000000..4de9505 Binary files /dev/null and b/gfx/items/diamond02.png differ diff --git a/gfx/items/diamond03.png b/gfx/items/diamond03.png new file mode 100644 index 0000000..68adda5 Binary files /dev/null and b/gfx/items/diamond03.png differ diff --git a/gfx/items/gem01.png b/gfx/items/gem01.png new file mode 100644 index 0000000..96819f1 Binary files /dev/null and b/gfx/items/gem01.png differ diff --git a/gfx/items/gem02.png b/gfx/items/gem02.png new file mode 100644 index 0000000..5420d57 Binary files /dev/null and b/gfx/items/gem02.png differ diff --git a/gfx/items/gem03.png b/gfx/items/gem03.png new file mode 100644 index 0000000..07a574e Binary files /dev/null and b/gfx/items/gem03.png differ diff --git a/gfx/items/powerCore01.png b/gfx/items/powerCore01.png new file mode 100644 index 0000000..a3dc23e Binary files /dev/null and b/gfx/items/powerCore01.png differ diff --git a/gfx/items/powerCore02.png b/gfx/items/powerCore02.png new file mode 100644 index 0000000..3482fa4 Binary files /dev/null and b/gfx/items/powerCore02.png differ diff --git a/gfx/items/powerCore03.png b/gfx/items/powerCore03.png new file mode 100644 index 0000000..6dae933 Binary files /dev/null and b/gfx/items/powerCore03.png differ diff --git a/gfx/title/logo.png b/gfx/title/logo.png index 0d4d40e..2cb8112 100644 Binary files a/gfx/title/logo.png and b/gfx/title/logo.png differ diff --git a/gfx/trophies/alertSphere.png b/gfx/trophies/alertSphere.png new file mode 100644 index 0000000..ebcdbd7 Binary files /dev/null and b/gfx/trophies/alertSphere.png differ diff --git a/gfx/trophies/bronze.png b/gfx/trophies/bronze.png index 1935847..f477d39 100644 Binary files a/gfx/trophies/bronze.png and b/gfx/trophies/bronze.png differ diff --git a/gfx/trophies/gold.png b/gfx/trophies/gold.png index cb3d2c8..76c4430 100644 Binary files a/gfx/trophies/gold.png and b/gfx/trophies/gold.png differ diff --git a/gfx/trophies/platinum.png b/gfx/trophies/platinum.png index af3a96b..b90f557 100644 Binary files a/gfx/trophies/platinum.png and b/gfx/trophies/platinum.png differ diff --git a/gfx/trophies/silver.png b/gfx/trophies/silver.png index e61cd36..6d4ae0e 100644 Binary files a/gfx/trophies/silver.png and b/gfx/trophies/silver.png differ diff --git a/gfx/trophies/sparkle.png b/gfx/trophies/sparkle.png new file mode 100644 index 0000000..0f46185 Binary files /dev/null and b/gfx/trophies/sparkle.png differ diff --git a/gfx/trophies/unearned.png b/gfx/trophies/unearned.png new file mode 100644 index 0000000..5e19e54 Binary files /dev/null and b/gfx/trophies/unearned.png differ diff --git a/locale/tbftss.pot b/locale/tbftss.pot index 7e2817d..7430862 100644 --- a/locale/tbftss.pot +++ b/locale/tbftss.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: TBFTSS: The Pandoran War\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-04-23 08:08:20+0100\n" +"POT-Creation-Date: 2016-05-14 12:43:16+0100\n" "PO-Revision-Date: ???\n" "Last-Translator: ???\n" "Language-Team: ???\n" @@ -31,6 +31,21 @@ msgstr "" msgid "%s (Gun)" msgstr "" +msgid "We've lost engines! We're a sitting duck!" +msgstr "" + +msgid "Our guns have been shot out! We have no defences!" +msgstr "" + +msgid "Be advised, we're taking damage here. Please step up support." +msgstr "" + +msgid "We're sustaining heavy damage! All fighters, please assist, ASAP!" +msgstr "" + +msgid "Mayday! Mayday! Defences are critical. We can't hold out much longer!" +msgstr "" + msgid "Mission target has escaped." msgstr "" @@ -67,6 +82,12 @@ msgstr "" msgid "Missiles (%d)" msgstr "" +msgid "System Power : %d%%" +msgstr "" + +msgid "%s (Leader)" +msgstr "" + msgid "Target: %.2fkm" msgstr "" @@ -115,6 +136,9 @@ msgstr "" msgid "New Objective : %s" msgstr "" +msgid "Challenge Failed!" +msgstr "" + msgid "Target not in range" msgstr "" @@ -133,6 +157,9 @@ msgstr "" msgid "Cannot activate waypoint - outstanding objectives not yet complete" msgstr "" +msgid "Cannot activate waypoint - eliminate enemies first" +msgstr "" + msgid "Cannot activate waypoint - team mates too far away" msgstr "" @@ -151,6 +178,12 @@ msgstr "" msgid "Challenges" msgstr "" +msgid "Completed : %d / %d" +msgstr "" + +msgid "Page : %d / %d" +msgstr "" + msgid "[Locked]" msgstr "" @@ -199,6 +232,9 @@ msgstr "" msgid "Rescue %d civilians" msgstr "" +msgid "Complete challenge in %s or less" +msgstr "" + msgid "%s has fallen to the Pandorans" msgstr "" @@ -328,6 +364,15 @@ msgstr "" msgid "Page %d / %d" msgstr "" +msgid "Trophies" +msgstr "" + +msgid "Awarded : %d / %d" +msgstr "" + +msgid "[Hidden]" +msgstr "" + msgid "Fire" msgstr "" @@ -361,6 +406,9 @@ msgstr "" msgid "Previous Fighter" msgstr "" +msgid "Screenshot" +msgstr "" + msgid "Controls" msgstr "" @@ -391,15 +439,15 @@ msgstr "" msgid "Continue" msgstr "" -msgid "Start Challenge Mission" -msgstr "" - msgid "Resume" msgstr "" msgid "Return to Title" msgstr "" +msgid "Start Challenge Mission" +msgstr "" + msgid "OK" msgstr "" @@ -457,7 +505,7 @@ msgstr "" msgid "And what'll they do then? Bite you to death?" msgstr "" -msgid "Eyes open, lads" +msgid "Eyes open, lads." msgstr "" msgid "We're done. Anyone detect anything unusual?" @@ -466,7 +514,7 @@ msgstr "" msgid "Same old, same old." msgstr "" -msgid "Believe me, that's a good thing. Right, let's head home and report in" +msgid "Believe me, that's a good thing. Right, let's head home and report in." msgstr "" msgid "Patrols so far have not uncovered anything unusual, and it seems as though the increase in military presense is reducing the amount of illegal activity in this sector, with reported incidents down 80%. Still, we cannot afford to become complacent, and must continue with our sweeps." @@ -622,6 +670,48 @@ msgstr "" msgid "We'd better prepare ourselves for a major attack in the next few days. Hopefully not from both of them at once." msgstr "" +msgid "Break and attack, lads. Let's send these guys back home." +msgstr "" + +msgid "More Tzac fighters incoming." +msgstr "" + +msgid "Steel yourself, lads. Even more Tzac forces are heading our way." +msgstr "" + +msgid "Picking up two capital ships, moving in." +msgstr "" + +msgid "Wait, those aren't only Tzac forces ... " +msgstr "" + +msgid "Ah, hell! Now we've got Pandorans, too?!" +msgstr "" + +msgid "Commander, we're getting shot to ribbons here! We need to fallback!" +msgstr "" + +msgid "We can't let EITHER of these two win! That would be a major loss for all of us." +msgstr "" + +msgid "Eightballers, de Winter of the White Knights, here to assist." +msgstr "" + +msgid "White Knights! Am I glad to see you. Your timing couldn't be better." +msgstr "" + +msgid "I owe you my life, Knights." +msgstr "" + +msgid "We're all in this together, Rice. I'm sorry we arrived too late to save your wingmates." +msgstr "" + +msgid "They were good guys. They'll be missed." +msgstr "" + +msgid "We're needed elsewhere. We'll see you soon." +msgstr "" + msgid "Tzac fighers are moving in on the jumpgate. We need to stop them before they do any serious damage to it." msgstr "" @@ -667,6 +757,12 @@ msgstr "" msgid "Tugs are on the way. Should be here in the next few minutes" msgstr "" +msgid "People, divide yourselves between the fighters and the Sharpfinger." +msgstr "" + +msgid "We couldn't spare any bombers, so we just need to get in there and take them all on." +msgstr "" + msgid "We've received word from CSN Florin that they have suffered a power failure, affecting the entire ship. The stranded vessel has attracted the attention of the Pandorans, who have already deployed shuttles and tugs to absorb it into their ranks. The Salty Wildcats will intercept and provide cover until Florin can affect repairs." msgstr "" @@ -757,6 +853,60 @@ msgstr "" msgid "Tzac have never been known to deploy Darts, but that was an important observation. Provide us with as many details as possible during debriefing." msgstr "" +msgid "Remember, guys: mags only against the fighters. We're not here to take any more lives." +msgstr "" + +msgid "For the corvettes, concentrate fire on the engines and the guns. Once it's out of the game, move onto the next one." +msgstr "" + +msgid "Got it." +msgstr "" + +msgid "We should lure the fighters away from the capital ships. Stray fire against a disabled ship could destroy it." +msgstr "" + +msgid "Good point, Chaz, we should be mindful of friendly-fire." +msgstr "" + +msgid "Brings back memories, doesn't it?" +msgstr "" + +msgid "So long as we don't end up back in Phylent after this." +msgstr "" + +msgid "This going in your journal, Kelly?" +msgstr "" + +msgid "Everything. It could be important one day." +msgstr "" + +msgid "Have fun with the names of Tzac's cap ships." +msgstr "" + +msgid "I'll just refer to the battle logs. Military records tend to be accurate." +msgstr "" + +msgid "Most of the time." +msgstr "" + +msgid "All fighters disabled." +msgstr "" + +msgid "Corvettes are all out of the game." +msgstr "" + +msgid "Griffin, this is de Winter. Opposing forces are no longer a threat." +msgstr "" + +msgid "Any casualties?" +msgstr "" + +msgid "No. All fighters and caps have been shutdown, and ready for pickup." +msgstr "" + +msgid "Great work, Knights. Clean up will commence shortly. Standby for new instructions." +msgstr "" + msgid "The day that we have feared and the events that we attempted to avert are now upon us - the Pandoran army has commenced its push beyond Mitikas space, and is beginning to assault neighbouring Independent star systems. We need to fight back, in order to protect Clarke from becoming underrun by this menace. Take heed: this will not be an easy battle, but we have little choice and must secure victory here today." msgstr "" @@ -1033,6 +1183,21 @@ msgstr "" msgid "Secure the commander, and then take down those bombers. Just watch your fire." msgstr "" +msgid "Remember everyone: the Pandorans are using UNF fighters." +msgstr "" + +msgid "Using your radar and HUD is the way to go in this fight." +msgstr "" + +msgid "All enemies down." +msgstr "" + +msgid "Let's hope we never see the day when they get hold of one of the ATAFs." +msgstr "" + +msgid "Agreed. Let's regroup and prepare for whatever's coming next." +msgstr "" + msgid "A patrol group has sighted a number of crates drifting near to Alexandria. The contents of the crates is currently unknown, but they have been confirmed to be belong to the CSN. A shuttle has been dispatched to retrieve them, in case they should wander in to any shipping lanes. Once we have them in our possession, we will work to determine how they came to be here." msgstr "" @@ -1273,6 +1438,168 @@ msgstr "" msgid "Good work, everyone. We've sent both Tzac and those mercenaries a clear message today. I think its obvious what our next move should be ..." msgstr "" +msgid "Our goal is the jumpgate. Expect a lot of resistance." +msgstr "" + +msgid "Once we're they, we need to destroy the control nodes to shut it down. Barclay, that's your job." +msgstr "" + +msgid "More enemies incoming." +msgstr "" + +msgid "Commander, I'm detecting a wing of Blizzards, incoming." +msgstr "" + +msgid "Couldn't expect Tzac not to bring out the heavy guns. Let's take it to them, people." +msgstr "" + +msgid "We're clear for the run against the gate." +msgstr "" + +msgid "It's guarded by several rapid-fire plasma turrets. Try not to let those things get a lock on you." +msgstr "" + +msgid "Half the nodes are down." +msgstr "" + +msgid "Keep at it!" +msgstr "" + +msgid "Jumpgate is down." +msgstr "" + +msgid "Control, this is Wolfenden. Tzac's outer jumpgate is offline." +msgstr "" + +msgid "Acknowledged. Hold position there. We'll need you to guard that gate and prevent the enemy from affecting repairs." +msgstr "" + +msgid "Dammit, the team's been cut down! Looks like it's up to you and me, Ian." +msgstr "" + +msgid "We'll make sure their deaths weren't in vain." +msgstr "" + +msgid "HMS 781-110 sighted. All fighters free to engage at will. Follow my lead." +msgstr "" + +msgid "Control, HMS 781-110 has been taken down." +msgstr "" + +msgid "Infinites, HMS 781-041 has arrived in the area. Engage and destroy." +msgstr "" + +msgid "Acknowledged." +msgstr "" + +msgid "Did anyone else get that?" +msgstr "" + +msgid "HMS 781-041, please repeat." +msgstr "" + +msgid "Hell! Too late!" +msgstr "" + +msgid "Infinites, it appears remaining enemy forces are retreating. Please stand down." +msgstr "" + +msgid "Received." +msgstr "" + +msgid "That was unexpected." +msgstr "" + +msgid "Sure was. We'd better get to debriefing." +msgstr "" + +msgid "We're going to mag half of their forces and destroy the others. The ones to disable have been tagged. Everyone clear?" +msgstr "" + +msgid "Watch your fire: remember, a stray shot could easily destroy a disabled craft." +msgstr "" + +msgid "All tagged Tzac fighters have been disabled." +msgstr "" + +msgid "Tzac opposition has been destroyed." +msgstr "" + +msgid "Great work, everyone. That should give the PR guys something to brag about." +msgstr "" + +msgid "All, our mission parameters have changed. The Pandorans are making a move against Mace. We need to act quickly." +msgstr "" + +msgid "Therefore, you have permission to destroy any and all opposing forces, no need to mag these guys." +msgstr "" + +msgid "Commander, we've got Darts and Shales incoming." +msgstr "" + +msgid "Looks like some mercenaries decided to stick around. Let's show them why that was a bad move." +msgstr "" + +msgid "That's them seen to. Onwards to the jumpgate." +msgstr "" + +msgid "Got INF fighters incoming." +msgstr "" + +msgid "Knew it wouldn't be long." +msgstr "" + +msgid "Patriots, a Tzac warship just arrived in the area, but it has Imperial fighter escorts. Most likely it's been acquired by the Pandroans. It needs to be taken down before Cristabel makes her escape bid, as it might be here to kill her." +msgstr "" + +msgid "Got it. You all heard that. Let's get to it." +msgstr "" + +msgid "Christabel's shuttle has been disabled." +msgstr "" + +msgid "Excellent work! Now let's finish off the rest of these fighters." +msgstr "" + +msgid "All enemies down. Let's get over to Christabel's shuttle and secure the empress." +msgstr "" + +msgid "Empress Christabel, this is Cdr. de Winter of the Confederation Stellar Navy." +msgstr "" + +msgid "Acting under the authority of the allied forces, I am hereby placing you under arrest, for breaches of intergalactic law." +msgstr "" + +msgid "You will be escorted to a neutral court, where you will be tried for your crimes." +msgstr "" + +msgid "If found guilty, the intergalactic community will decide on your punishment." +msgstr "" + +msgid "Sorry, your Highness. I wish it didn't have to go this way, but the galaxy has enough problems as it is." +msgstr "" + +msgid "If--" +msgstr "" + +msgid "Woah! What the hell just happened?!" +msgstr "" + +msgid "Did anyone fire?!" +msgstr "" + +msgid "All guns cold, Commander. Looks like she might have self destructed her own ship." +msgstr "" + +msgid "Dammit!" +msgstr "" + +msgid "Now what?" +msgstr "" + +msgid "Nothing more we can do. We should evacuate the area before more Pandoran forces arrive." +msgstr "" + msgid "A distress call from a CSN squadron has been issued, who were engaging Pandoran targets. It appears as though the enemy have magged the fighters, rather than destroy them. INF tugs are preparing to lead them out of the system, via the jumpgate. We need to destroy those tugs, and get those men and women to safety. We cannot allow the Pandorans to get hold of any of our technology." msgstr "" @@ -1369,9 +1696,6 @@ msgstr "" msgid "Rose, we'll be relying on you to disable his fighter as soon as he puts in an appearance." msgstr "" -msgid "Acknowledged." -msgstr "" - msgid "Tzac commander sighted, Commander." msgstr "" @@ -1393,6 +1717,66 @@ msgstr "" msgid "Excellent work, Jesters. Everything looks clear, so we'll dispatch a tug to your location to bring him in. See you soon." msgstr "" +msgid "The Pandorans have launched a sudden attack against the system. It appears that they are capitalizing on the chaos that the Kingdom of Tzac has thrown us into. We need to repel this attack, as defeat here could mean a major setback in our struggle against both enemies." +msgstr "" + +msgid "Hell, they're outnumbering us, a good two-to-one!" +msgstr "" + +msgid "There are Swarmers in their ranks, making up the bulk. Don't lose faith people, we can do this." +msgstr "" + +msgid "That's the last of 'em. Not often we win an engagement like this." +msgstr "" + +msgid "Brace yourselves, lads." +msgstr "" + +msgid "Picking up two Mitikas corvettes: Mora and Karambit." +msgstr "" + +msgid "We need to give Hopper and Blackburn support in dealing with them. Get to it." +msgstr "" + +msgid "Hell, where'd they get those Khepris from?" +msgstr "" + +msgid "Crystabel must've decided to try and attack the Pandorans directly. Went as well for her as it did for us." +msgstr "" + +msgid "Commander, we're taking heavy losses!" +msgstr "" + +msgid "We won before, we can win again! Keep up the fight!" +msgstr "" + +msgid "Commander, I strongly suggest we pull back." +msgstr "" + +msgid "We can't keep running. We'll run out of places to run to." +msgstr "" + +msgid "All fighters, be advised: the wing commander has been killed." +msgstr "" + +msgid "Who's leading this operation now?" +msgstr "" + +msgid "We have to retreat!" +msgstr "" + +msgid "This the end of the line, guys. It's been great serving with you." +msgstr "" + +msgid "Hopper is down!" +msgstr "" + +msgid "They've taken out Blackburn!" +msgstr "" + +msgid "That's both of our corvettes down. The rest is up to us." +msgstr "" + msgid "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." msgstr "" @@ -1459,9 +1843,6 @@ msgstr "" msgid "Seth, the lieutenant's Dart should be tagged on your HUD. Disable that ship as soon as possible." msgstr "" -msgid "Got it." -msgstr "" - msgid "The rest of us will take down his buddies. Watch your stray fire around the mission target." msgstr "" @@ -1642,7 +2023,13 @@ msgstr "" msgid "Likewise. Maybe we'll get it do it again some day, though a part of me really hopes we won't need to ...." msgstr "" -msgid "Destroy all Darts" +msgid "Destroy all Darts #1" +msgstr "" + +msgid "Destroy all Darts #2" +msgstr "" + +msgid "Destroy all Darts #3" msgstr "" msgid "Destroy all Lynxes" @@ -1678,66 +2065,42 @@ msgstr "" msgid "Swarms of Swarmers" msgstr "" +msgid "Piracy" +msgstr "" + +msgid "Swelling the Ranks" +msgstr "" + +msgid "Most Wanted" +msgstr "" + +msgid "Solo Patrol" +msgstr "" + +msgid "Set Phasers to Stun" +msgstr "" + +msgid "No survivors" +msgstr "" + +msgid "Initiation" +msgstr "" + +msgid "Destroy all Darts #4" +msgstr "" + msgid "One of the seven" msgstr "" msgid "Earn all other trophies" msgstr "" -msgid "2nd Lieutenant" +msgid "Gentle start" msgstr "" msgid "Complete a campaign mission" msgstr "" -msgid "1st Lieutenant" -msgstr "" - -msgid "Complete 10% of all missions" -msgstr "" - -msgid "Lieutenant Commander" -msgstr "" - -msgid "Complete 20% of all missions" -msgstr "" - -msgid "Commander" -msgstr "" - -msgid "Complete 40% of all missions" -msgstr "" - -msgid "Captain" -msgstr "" - -msgid "Complete 50% of all missions" -msgstr "" - -msgid "Commodore" -msgstr "" - -msgid "Complete 60% of all missions" -msgstr "" - -msgid "Rear Admiral" -msgstr "" - -msgid "Complete 80% of all missions" -msgstr "" - -msgid "Admiral" -msgstr "" - -msgid "Complete 90% of all missions" -msgstr "" - -msgid "Fleet Admiral" -msgstr "" - -msgid "Complete all campaign missions" -msgstr "" - msgid "Ready for duty" msgstr "" @@ -1768,12 +2131,24 @@ msgstr "" msgid "Complete all missions at Temper" msgstr "" -msgid "Going out with a bang." +msgid "Going out with a bang" msgstr "" msgid "Complete all missions at Mace" msgstr "" +msgid "Back against the wall" +msgstr "" + +msgid "Complete all missions at Rothan" +msgstr "" + +msgid "Now what do we do?" +msgstr "" + +msgid "Complete all missions at Clarke" +msgstr "" + msgid "Truly epic" msgstr "" @@ -1786,13 +2161,19 @@ msgstr "" msgid "Destroy an enemy capital ship" msgstr "" +msgid "Giant Slayer" +msgstr "" + +msgid "Destroy 25 enemy capital ships" +msgstr "" + msgid "Plenty more where that came from, unfortunately" msgstr "" msgid "Destroy a Pandoran-controlled craft" msgstr "" -msgid "Man, I gotta get me one of these!" +msgid "Oh man, I gotta get me one of these!" msgstr "" msgid "Pilot an ATAF during the campaign" @@ -1816,13 +2197,46 @@ msgstr "" msgid "Be killed by a missile that was meant for someone else" msgstr "" -msgid "Complete 25% of all challenges" +msgid "The bodyguard" msgstr "" -msgid "Complete 50% of all challenges" +msgid "Kill an enemy with a missile intended for their wing leader" msgstr "" -msgid "Complete 100% of all challenges" +msgid "Dedicated" +msgstr "" + +msgid "Complete 25%% of all challenges" +msgstr "" + +msgid "Obssessed" +msgstr "" + +msgid "Complete 50%% of all challenges" +msgstr "" + +msgid "Completitonist" +msgstr "" + +msgid "Complete 100%% of all challenges" +msgstr "" + +msgid "Hero" +msgstr "" + +msgid "Take down 50 enemies (player only)" +msgstr "" + +msgid "Veteran" +msgstr "" + +msgid "Take down 500 enemies (player only)" +msgstr "" + +msgid "Legend" +msgstr "" + +msgid "Take down 5,000 enemies (player only)" msgstr "" msgid "Your name's on one of these!" @@ -1840,13 +2254,19 @@ msgstr "" msgid "Isn't technology wonderful?" msgstr "" -msgid "Use the ECM 100 times" +msgid "Use the ECM 250 times" msgstr "" msgid "Runaway!" msgstr "" -msgid "Boost 100 times" +msgid "Boost 250 times" +msgstr "" + +msgid "Hoarder" +msgstr "" + +msgid "Collect 100 items" msgstr "" msgid "Missed, you f**kers!" @@ -1861,15 +2281,45 @@ msgstr "" msgid "Visit 100 waypoints" msgstr "" +msgid "Minesweeper" +msgstr "" + +msgid "Destroy 255 mines (player only)" +msgstr "" + +msgid "Get out and push" +msgstr "" + +msgid "Disable 500 opponents" +msgstr "" + msgid "Yippie-ki-yay" msgstr "" -msgid "Destroy 13 or more enemies in an epic battle without being killed" +msgid "Destroy 13 or more enemies in an epic battle, without being killed" msgstr "" -msgid "Almost indestructable. Almost." +msgid "Survivor" +msgstr "" + +msgid "Complete an epic battle without being killed" +msgstr "" + +msgid "Almost indestructable. Almost" msgstr "" msgid "Be destroyed while piloting an ATAF" msgstr "" +msgid "Pacifist" +msgstr "" + +msgid "Complete a fighter-based campaign mission without firing" +msgstr "" + +msgid "2 birds, 1 stone" +msgstr "" + +msgid "Destroy two or more fighters by shooting one mine" +msgstr "" + diff --git a/makefile b/makefile index e1453c8..43305eb 100644 --- a/makefile +++ b/makefile @@ -1,10 +1,18 @@ PROG = tbftss CC = gcc -BIN_DIR = /usr/bin -DATA_DIR = /opt/tbftss -LOCALE_DIR = /usr/share/locale -ICON_DIR = /usr/share/icons/hicolor -DESKTOP_DIR = /usr/share/applications +PREFIX ?= /usr +BIN_DIR ?= $(PREFIX)/bin +DATA_DIR ?= /opt/$(PROG) +LOCALE_DIR = $(PREFIX)/share/locale +ICON_DIR = $(PREFIX)/share/icons/hicolor +DESKTOP_DIR = $(PREFIX)/share/applications + +DESTDIR ?= +INST_BIN_DIR = $(DESTDIR)$(BIN_DIR) +INST_DATA_DIR = $(DESTDIR)$(DATA_DIR) +INST_LOCALE_DIR = $(DESTDIR)$(LOCALE_DIR) +INST_ICON_DIR = $(DESTDIR)$(ICON_DIR) +INST_DESKTOP_DIR = $(DESTDIR)$(DESKTOP_DIR) SEARCHPATH += src/plat/unix OBJS += unixInit.o @@ -12,7 +20,7 @@ OBJS += unixInit.o include common.mk CXXFLAGS += `sdl2-config --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -CXXFLAGS += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes +CXXFLAGS += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds CXXFLAGS += -g -lefence LFLAGS := `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm @@ -24,23 +32,29 @@ $(PROG): $(OBJS) $(CC) -o $@ $(OBJS) $(LFLAGS) install: - cp $(PROG) $(BIN_DIR) - mkdir -p $(DATA_DIR) - cp -r data $(DATA_DIR) - cp -r gfx $(DATA_DIR) - cp -r manual $(DATA_DIR) - cp -r music $(DATA_DIR) - cp -r sound $(DATA_DIR) - cp -p icons/$(PROG)-16x16.png $(ICON_DIR)/16x16/apps/$(PROG).png - cp -p icons/$(PROG)-32x32.png $(ICON_DIR)/32x32/apps/$(PROG).png - cp -p icons/$(PROG)-64x64.png $(ICON_DIR)/64x64/apps/$(PROG).png - cp -p icons/$(PROG)-128x128.png $(ICON_DIR)/128x128/apps/$(PROG).png - cp -p icons/$(PROG).desktop $(DESKTOP_DIR) + mkdir -p $(INST_BIN_DIR) + install -m 0755 $(PROG) $(INST_BIN_DIR) + mkdir -p $(INST_DATA_DIR) + cp -r data $(INST_DATA_DIR) + cp -r gfx $(INST_DATA_DIR) + cp -r manual $(INST_DATA_DIR) + cp -r music $(INST_DATA_DIR) + cp -r sound $(INST_DATA_DIR) + mkdir -p $(INST_ICON_DIR)/16x16/apps + mkdir -p $(INST_ICON_DIR)/32x32/apps + mkdir -p $(INST_ICON_DIR)/64x64/apps + mkdir -p $(INST_ICON_DIR)/128x128/apps + cp -p icons/$(PROG)-16x16.png $(INST_ICON_DIR)/16x16/apps/$(PROG).png + cp -p icons/$(PROG)-32x32.png $(INST_ICON_DIR)/32x32/apps/$(PROG).png + cp -p icons/$(PROG)-64x64.png $(INST_ICON_DIR)/64x64/apps/$(PROG).png + cp -p icons/$(PROG)-128x128.png $(INST_ICON_DIR)/128x128/apps/$(PROG).png + mkdir -p $(INST_DESKTOP_DIR) + cp -p icons/$(PROG).desktop $(INST_DESKTOP_DIR) @for f in $(LOCALE_MO); do \ lang=`echo $$f | sed -e 's/^locale\///;s/\.mo$$//'`; \ - mkdir -p $(LOCALE_DIR)/$$lang/LC_MESSAGES; \ - cp -v $$f $(LOCALE_DIR)/$$lang/LC_MESSAGES/$(PROG).mo; \ + mkdir -p $(INST_LOCALE_DIR)/$$lang/LC_MESSAGES; \ + cp -v $$f $(INST_LOCALE_DIR)/$$lang/LC_MESSAGES/$(PROG).mo; \ done uninstall: diff --git a/makefile.win32 b/makefile.win32 index b70a058..49b1185 100644 --- a/makefile.win32 +++ b/makefile.win32 @@ -8,8 +8,7 @@ SEARCHPATH += src/plat/win32 OBJS += win32Init.o CXXFLAGS += `$(SDLC) --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -CXXFLAGS += -Wall -ansi -pedantic -Werror -Wstrict-prototypes -CXXFLAGS += -g -lefence +CXXFLAGS += -ansi LFLAGS = `$(SDLC) --libs` -lm -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lSDL2main diff --git a/manual/index.html b/manual/index.html index 725c206..7773ca1 100644 --- a/manual/index.html +++ b/manual/index.html @@ -26,7 +26,7 @@ span.highlight {font-weight:bold; color: #0bf;}

-

Last updated: 21st April 2016

+

Last updated: 14th May 2016

@@ -350,6 +350,15 @@ To start challenge mission, click on the numbered mission box and then click on

+

Trophies

+

+The Pandoran War offers an optional achievement award system, in the form of trophies. Trophies are earned through various gameplay actions, such as completing missions, defeating enemies, and racking up stats. Earned and available trophies can be viewed in the menu from the title screen, the galactic map, and the challenges menu. A notification will be shown when a trophy is unlocked, sliding in from the left-hand side of the screen. So as not to interupt the game, potentially spoiling a hard-fought mission, notifications are only shown at certain points during the game. +

+ +

+Note that this is not an online system, and is local to the machine on which the game is saved. +

+

Misc. gameplay details

Shuttles

@@ -398,20 +407,40 @@ To change a control, click on the box and then press the key or mouse button you Controls be can restored to their default settings by clicking the "Restore Defaults" button.

+

Gameplay settings

+

+Some minor gameplay settings can be tweaked in the config.json save file: +

+

+

+

+

+To alter a gameplay element, update the setting and restart the game. It is not recommended that you fiddle with these settings unless you are comfortable editing such files, as it could result in the loss of data or the game not working properly. +

+

Misc. Information

-Saved game files are stored in: +The Pandoran War creates two save game files when run, config.json and game.save. Both files are human-readable and saved in JSON format. The files are stored in: +

-Note that as the source code for this game is freely available, these settings may have been changed. Typically on Windows $USERPROFILE is C:/Users/<userid>. +

+Note that as the source code for this game is freely available, these settings may have been changed. +

+

+$HOME on Linux will be /home/<userId>, where userId is your login username. Typically on Windows, $USERPROFILE is C:/Users/<userId>, where userId is your Windows login.

License

-

-See the LICENSE and README.md files that came with this game for information on the various copyrights of the source code, graphics, sound, and data. Additionally, you may visit https://github.com/stephenjsweeney/tbftss to get the source code itself, and view the files there. +Please refer to the LICENSE and README.md files that came with this game for information on the various copyrights of the source code, graphics, sound, and data. Additionally, you may visit https://github.com/stephenjsweeney/tbftss to get the source code itself, and view the files there.

About

diff --git a/manual/logo.png b/manual/logo.png index 0d4d40e..2cb8112 100644 Binary files a/manual/logo.png and b/manual/logo.png differ diff --git a/manual/trophies.png b/manual/trophies.png new file mode 100644 index 0000000..d976a66 Binary files /dev/null and b/manual/trophies.png differ diff --git a/music/battle/track-1.mp3 b/music/battle/track-1.mp3 deleted file mode 100644 index f5aa62e..0000000 Binary files a/music/battle/track-1.mp3 and /dev/null differ diff --git a/src/battle/ai.c b/src/battle/ai.c index 8b46cf0..ff6e7a0 100644 --- a/src/battle/ai.c +++ b/src/battle/ai.c @@ -148,7 +148,7 @@ static void doFighterAI(void) self->target = NULL; } - if (!self->target || self->target->systemPower <= 0) + if (!self->target || (self->target->systemPower <= 0 && (self->target->flags & EF_MUST_DISABLE))) { findTarget(); @@ -159,7 +159,7 @@ static void doFighterAI(void) { if (!lookForLeader()) { - if (self->aiFlags & AIF_MOVES_TO_PLAYER && player != NULL) + if (self->aiFlags & AIF_MOVES_TO_PLAYER && player->alive == ALIVE_ALIVE) { moveToPlayer(); } @@ -173,7 +173,7 @@ static void doFighterAI(void) { doWander(); } - else if (self->aiFlags & AIF_MOVES_TO_PLAYER && player != NULL) + else if (self->aiFlags & AIF_MOVES_TO_PLAYER && player->alive == ALIVE_ALIVE) { moveToPlayer(); } @@ -194,7 +194,8 @@ static void doFighterAI(void) return; } - r = rand() % 100; + /* if your target is disabled, just shoot it..! */ + r = (self->target->flags & EF_DISABLED) ? 100 : rand() % 100; if (r <= getActionChance(AI_EVADE)) { @@ -311,9 +312,9 @@ static void findTarget(void) Entity *e, **candidates; unsigned int dist, closest; - dist = closest = (battle.isEpic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : 1000; + dist = closest = (battle.isEpic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : SCREEN_WIDTH; - candidates = getAllEntsWithin(self->x - (self->w / 2) - dist, self->y - (self->h / 2) - dist, self->w + (dist * 2), self->h + (dist * 2), self); + candidates = getAllEntsInRadius(self->x, self->y, dist, self); self->target = NULL; @@ -344,18 +345,26 @@ static int canAttack(Entity *e) return 0; } - if (!(e->flags & EF_AI_TARGET)) + if (!(self->aiFlags & AIF_ASSASSIN)) { - if (e->aiFlags & (AIF_AVOIDS_COMBAT | AIF_EVADE) || e->flags & EF_SECONDARY_TARGET) + if (e->flags & EF_MUST_DISABLE) { - return !(rand() % 5); + return e->systemPower > 0; + } + + if (!(e->flags & EF_AI_TARGET)) + { + if (e->aiFlags & (AIF_AVOIDS_COMBAT | AIF_EVADE) || e->flags & EF_SECONDARY_TARGET) + { + return !(rand() % 5); + } + } + + /* low chance of attacking something else */ + if ((self->aiFlags & AIF_TARGET_FOCUS) && (!(e->flags & EF_AI_TARGET))) + { + return !(rand() % 100); } - } - - /* low chance of attacking something else */ - if ((self->aiFlags & AIF_TARGET_FOCUS) && (!(e->flags & EF_AI_TARGET))) - { - return !(rand() % 100); } return 1; @@ -370,12 +379,7 @@ static int selectWeaponForTarget(Entity *e) { if (e->flags & EF_MUST_DISABLE) { - if (e->systemPower > 0) - { - return selectWeapon(BT_MAG); - } - - return 0; + return selectWeapon(BT_MAG); } if (e->flags & EF_NO_KILL) @@ -482,7 +486,7 @@ static void preAttack(void) { fireGuns(self); } - else if (self->missiles && (!(self->target->flags & EF_NO_KILL)) && getDistance(self->x, self->y, self->target->x, self->target->y) >= 350) + else if (self->missiles && (!(self->target->flags & (EF_NO_KILL|EF_MUST_DISABLE))) && getDistance(self->x, self->y, self->target->x, self->target->y) >= 350) { fireMissile(self); @@ -584,7 +588,7 @@ static int nearEnemies(void) int i, numEnemies, x, y; Entity *e, **candidates; - candidates = getAllEntsWithin(self->x - 500, self->y - 500, 1000, 1000, self); + candidates = getAllEntsInRadius(self->x, self->y, SCREEN_WIDTH, self); self->target = NULL; x = y = 0; @@ -600,7 +604,7 @@ static int nearEnemies(void) continue; } - if (getDistance(e->x, e->y, self->x, self->y) < 1000) + if (getDistance(e->x, e->y, self->x, self->y) <= SCREEN_WIDTH) { x += e->x; y += e->y; @@ -654,7 +658,7 @@ static int nearMines(void) int i, numMines; Entity *e, **candidates; - candidates = getAllEntsWithin(self->x - 500, self->y - 500, 1000, 1000, self); + candidates = getAllEntsInRadius(self->x, self->y, SCREEN_HEIGHT, self); self->targetLocation.x = self->targetLocation.y = 0; @@ -662,7 +666,7 @@ static int nearMines(void) for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { - if (e->side != self->side && e->type == ET_MINE && getDistance(e->x, e->y, self->x, self->y) < 500) + if (e->side != self->side && e->type == ET_MINE && getDistance(e->x, e->y, self->x, self->y) <= SCREEN_HEIGHT) { self->targetLocation.x += e->x; self->targetLocation.y += e->y; @@ -701,22 +705,18 @@ static void moveToPlayer(void) { int wantedAngle; int dist = getDistance(self->x, self->y, player->x, player->y); - float oldSpeed; if (dist <= 250) { - wantedAngle = getAngle(player->x, player->y, player->x + (player->dx * 1000), player->y + (player->dy * 1000)); - - turnToFace(wantedAngle); - if (player->thrust > 0.1) { - if (self->speed > player->speed) + wantedAngle = getAngle(player->x, player->y, player->x + (player->dx * 1000), player->y + (player->dy * 1000)); + + turnToFace(wantedAngle); + + if (self->thrust > player->thrust) { - oldSpeed = self->speed; - self->speed = sqrt(player->thrust); - applyFighterThrust(); - self->speed = oldSpeed; + applyFighterBrakes(); } else { @@ -759,6 +759,8 @@ static int nearJumpgate(void) static void moveToJumpgate(void) { + self->target = battle.jumpgate; + faceTarget(self->target); applyFighterThrust(); @@ -774,7 +776,7 @@ static int nearItems(void) closest = MAX_TARGET_RANGE; - candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self); + candidates = getAllEntsInRadius(self->x, self->y, SCREEN_WIDTH / 2, self); self->target = NULL; @@ -822,7 +824,7 @@ static int nearTowableCraft(void) dist = closest = (battle.isEpic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : 2000; - candidates = getAllEntsWithin(self->x - (self->w / 2) - dist, self->y - (self->h / 2) - dist, self->w + (dist * 2), self->h + (dist * 2), self); + candidates = getAllEntsInRadius(self->x, self->y, dist, self); self->target = NULL; @@ -862,7 +864,7 @@ static int lookForPlayer(void) { int range = (self->aiFlags & AIF_MOVES_TO_PLAYER) ? MAX_TARGET_RANGE : 2000; - if (player != NULL && getDistance(self->x, self->y, player->x, player->y) < range) + if (player->alive == ALIVE_ALIVE && getDistance(self->x, self->y, player->x, player->y) < range) { moveToPlayer(); return 1; @@ -908,7 +910,6 @@ static void moveToLeader(void) { int wantedAngle; int dist = getDistance(self->x, self->y, self->leader->x, self->leader->y); - float oldSpeed; if (dist <= ((self->leader->type != ET_CAPITAL_SHIP) ? 350 : 550)) { @@ -918,12 +919,9 @@ static void moveToLeader(void) turnToFace(wantedAngle); - if (self->speed > self->leader->speed) + if (self->thrust > self->leader->thrust) { - oldSpeed = self->speed; - self->speed = sqrt(self->leader->thrust); - applyFighterThrust(); - self->speed = oldSpeed; + applyFighterBrakes(); } else { diff --git a/src/battle/ai.h b/src/battle/ai.h index 28823bb..202f8ed 100644 --- a/src/battle/ai.h +++ b/src/battle/ai.h @@ -36,7 +36,7 @@ extern float getAngle(int x1, int y1, int x2, int y2); extern void applyFighterThrust(void); extern void applyFighterBrakes(void); extern void addHudMessage(SDL_Color c, char *format, ...); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern char *getTranslatedString(char *string); extern Entity *spawnMine(int type); diff --git a/src/battle/battle.c b/src/battle/battle.c index 6e67df6..f9c43d7 100644 --- a/src/battle/battle.c +++ b/src/battle/battle.c @@ -110,6 +110,11 @@ static void logic(void) doPlayerSelect(); } } + + if (battle.status != MS_IN_PROGRESS && battle.missionFinishedTimer <= -FPS * 2) + { + doTrophyAlerts(); + } } doWidgets(); @@ -117,7 +122,7 @@ static void logic(void) static void doBattle(void) { - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { ssx = player->dx; ssy = player->dy; @@ -150,7 +155,7 @@ static void doBattle(void) doPlayer(); - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { doSpawners(); @@ -177,21 +182,21 @@ static void doBattle(void) if (battle.status != MS_IN_PROGRESS) { battle.missionFinishedTimer--; - } + + if (battle.unwinnable && battle.missionFinishedTimer <= -FPS * 6) + { + postBattle(); - if (battle.unwinnable && battle.missionFinishedTimer <= -FPS * 6) - { - postBattle(); + destroyBattle(); - destroyBattle(); - - initGalacticMap(); + initGalacticMap(); + } } } static void draw(void) { - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { battle.camera.x = player->x - (SCREEN_WIDTH / 2); battle.camera.y = player->y - (SCREEN_HEIGHT / 2); @@ -218,7 +223,7 @@ static void draw(void) drawHud(); - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { drawMessageBox(); } @@ -235,6 +240,11 @@ static void draw(void) drawOptions(); break; } + + if (battle.status != MS_IN_PROGRESS && battle.status != MS_PAUSED && battle.missionFinishedTimer <= -FPS * 2) + { + drawTrophyAlert(); + } } static void drawMenu(void) @@ -373,21 +383,14 @@ static void postBattle(void) game.stats[i] += battle.stats[i]; } } + + game.stats[STAT_EPIC_KILL_STREAK] = MAX(game.stats[STAT_EPIC_KILL_STREAK], battle.stats[STAT_EPIC_KILL_STREAK]); updateAccuracyStats(game.stats); - - if (!game.currentMission->challengeData.isChallenge) - { - if (game.currentMission && !game.currentMission->completed) - { - game.currentMission->completed = (battle.status == MS_COMPLETE || !battle.numObjectivesTotal); - - if (game.currentMission->completed) - { - awardPostMissionTrophies(); - } - } - } + + game.currentMission->completed = (battle.status == MS_COMPLETE || !battle.numObjectivesTotal); + + app.saveGame = 1; } void destroyBattle(void) diff --git a/src/battle/battle.h b/src/battle/battle.h index 96bfbb6..855d871 100644 --- a/src/battle/battle.h +++ b/src/battle/battle.h @@ -85,7 +85,8 @@ extern void updateAccuracyStats(unsigned int *stats); extern void clearInput(void); extern void runScriptFunction(const char *format, ...); extern void doSpawners(void); -extern void awardPostMissionTrophies(void); +extern void doTrophyAlerts(void); +extern void drawTrophyAlert(void); extern App app; extern Battle battle; diff --git a/src/battle/bullets.c b/src/battle/bullets.c index b080181..9fa27e1 100644 --- a/src/battle/bullets.c +++ b/src/battle/bullets.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void huntTarget(Bullet *b); static void checkCollisions(Bullet *b); static void resizeDrawList(void); +static void selectNewTarget(Bullet *b); static Bullet bulletDef[BT_MAX]; static Bullet **bulletsToDraw; @@ -93,9 +94,12 @@ void doBullets(void) { addMissileEngineEffect(b); - huntTarget(b); + if (b->life < MISSILE_LIFE - (FPS / 4)) + { + huntTarget(b); + } - if (b->target == player && player != NULL && player->health > 0) + if (b->target == player && player->alive == ALIVE_ALIVE && player->health > 0) { incomingMissile = 1; } @@ -105,11 +109,6 @@ void doBullets(void) if (--b->life <= 0) { - if (player != NULL && player->alive == ALIVE_ALIVE && b->type == BT_MISSILE && b->damage > 0 && b->target == player) - { - battle.stats[STAT_MISSILES_EVADED]++; - } - if (b == battle.bulletTail) { battle.bulletTail = prev; @@ -167,7 +166,7 @@ static void checkCollisions(Bullet *b) if (b->owner != e && e->health > 0 && collision(b->x - b->w / 2, b->y - b->h / 2, b->w, b->h, e->x - e->w / 2, e->y - e->h / 2, e->w, e->h)) { - if (b->owner->side == e->side) + if (b->owner->side == e->side && !app.gameplay.friendlyFire && (!(e->flags & EF_DISABLED)) && e->type != ET_MINE) { b->damage = 0; } @@ -203,15 +202,28 @@ static void checkCollisions(Bullet *b) battle.stats[STAT_MISSILES_STRUCK]++; } } - + + /* missile was targetting player, but hit something else */ + if (b->type == BT_MISSILE && b->target == player && e != player) + { + battle.stats[STAT_MISSILES_EVADED]++; + } + /* assuming that health <= 0 will always mean killed */ if (e->health <= 0) { e->killedBy = b->owner; - if (b->type == BT_MISSILE && e == player && b->target != player) + if (b->type == BT_MISSILE && b->target != e) { - awardTrophy("TEAM_PLAYER"); + if (e == player) + { + awardTrophy("TEAM_PLAYER"); + } + else if (b->owner == player && (e->aiFlags & AIF_MOVES_TO_LEADER) && (b->target->flags & EF_AI_LEADER)) + { + awardTrophy("BODYGUARD"); + } } } @@ -244,22 +256,34 @@ void drawBullets(void) static void faceTarget(Bullet *b) { - int dir; - int wantedAngle = getAngle(b->x, b->y, b->target->x, b->target->y); - - wantedAngle %= 360; + int dir, wantedAngle, dist; + + wantedAngle = (int)getAngle(b->x, b->y, b->target->x, b->target->y) % 360; if (fabs(wantedAngle - b->angle) > TURN_THRESHOLD) { dir = (wantedAngle - b->angle + 360) % 360 > 180 ? -1 : 1; b->angle += dir * TURN_SPEED; + + dist = getDistance(b->x, b->y, b->target->x, b->target->y); + + if (dist < 250) + { + dist = 250 - dist; + + while (dist > 0) + { + b->angle += dir; + + dist -= 50; + } + } b->angle = mod(b->angle, 360); - - /* lower your speed while you're not at the correct angle */ - b->dx *= 0.38; - b->dy *= 0.38; + + b->dx *= 0.5; + b->dy *= 0.5; } } @@ -300,10 +324,43 @@ static void huntTarget(Bullet *b) } else { - b->target = NULL; + selectNewTarget(b); } } +static void selectNewTarget(Bullet *b) +{ + int i; + Entity *e, **candidates; + + if (app.gameplay.missileReTarget) + { + b->target = NULL; + + candidates = getAllEntsInRadius(b->x, b->y, SCREEN_HEIGHT, NULL); + + for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) + { + if (e->type == ET_FIGHTER && e->side != b->owner->side && e->health > 0) + { + b->target = e; + + if (b->target == player) + { + playSound(SND_INCOMING); + } + + return; + } + } + } + + /* no target, just explode */ + b->life = 0; + addMissileExplosion(b); + playBattleSound(SND_EXPLOSION_1, b->x, b->y); +} + static Bullet *createBullet(int type, int x, int y, Entity *owner) { Bullet *b; @@ -335,10 +392,12 @@ void fireGuns(Entity *owner) int i; float x, y; float c, s; + + b = NULL; for (i = 0 ; i < MAX_FIGHTER_GUNS ; i++) { - if (owner->guns[i].type == owner->selectedGunType || (owner->guns[i].type != BT_NONE && owner->combinedGuns)) + if (owner->guns[i].type != BT_NONE && (owner->guns[i].type == owner->selectedGunType || owner->combinedGuns)) { s = sin(TO_RAIDANS(owner->angle)); c = cos(TO_RAIDANS(owner->angle)); @@ -360,7 +419,10 @@ void fireGuns(Entity *owner) owner->reload = owner->reloadTime; - playBattleSound(b->sound, owner->x, owner->y); + if (b) + { + playBattleSound(b->sound, owner->x, owner->y); + } } void fireRocket(Entity *owner) @@ -384,8 +446,11 @@ void fireMissile(Entity *owner) Bullet *b; b = createBullet(BT_MISSILE, owner->x, owner->y, owner); + + b->dx *= 0.5; + b->dy *= 0.5; - b->life = FPS * 30; + b->life = MISSILE_LIFE; owner->missiles--; @@ -396,7 +461,7 @@ void fireMissile(Entity *owner) playBattleSound(b->sound, owner->x, owner->y); - if (owner->target == player) + if (b->target == player) { playSound(SND_INCOMING); } diff --git a/src/battle/bullets.h b/src/battle/bullets.h index 2ea155f..a7868d7 100644 --- a/src/battle/bullets.h +++ b/src/battle/bullets.h @@ -26,6 +26,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TURN_THRESHOLD 3 #define INITIAL_BULLET_DRAW_CAPACITY 32 +#define MISSILE_LIFE (FPS * 30) + extern SDL_Texture *getTexture(char *filename); extern void blitRotated(SDL_Texture *texture, int x, int y, float angle); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); @@ -39,13 +41,16 @@ extern void addMissileEngineEffect(Bullet *b); extern float mod(float n, float x); extern void addMissileExplosion(Bullet *b); extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); extern void playSound(int id); extern char *getTranslatedString(char *string); extern void *resize(void *array, int oldSize, int newSize); extern void awardTrophy(char *id); extern int isOnBattleScreen(int x, int y, int w, int h); +extern int getDistance(int x1, int y1, int x2, int y2); +extern App app; extern Battle battle; extern Colors colors; extern Entity *player; diff --git a/src/battle/capitalShips.c b/src/battle/capitalShips.c index 126658a..ede669d 100644 --- a/src/battle/capitalShips.c +++ b/src/battle/capitalShips.c @@ -33,6 +33,10 @@ static void loadCapitalShipDef(char *filename); static void loadComponents(Entity *parent, cJSON *components); static void loadGuns(Entity *parent, cJSON *guns); static void loadEngines(Entity *parent, cJSON *engines); +static void disable(void); +static void issueEnginesDestroyedMessage(Entity *cap); +static void issueGunsDestroyedMessage(Entity *cap); +static void issueDamageMessage(Entity *cap); static Entity defHead, *defTail; @@ -93,7 +97,7 @@ void doCapitalShip(void) battle.missionTarget = NULL; } - if (self->side == SIDE_ALLIES) + if (self->side != player->side) { battle.stats[STAT_CAPITAL_SHIPS_LOST]++; @@ -105,6 +109,8 @@ void doCapitalShip(void) runScriptFunction("CAPITAL_SHIPS_DESTROYED %d", battle.stats[STAT_CAPITAL_SHIPS_DESTROYED]); } + + runScriptFunction(self->name); } } } @@ -187,7 +193,7 @@ static int steer(void) count = 0; force = 0; - candidates = getAllEntsWithin(self->x - 1000, self->y - 1000, 2000, 2000, self); + candidates = getAllEntsInRadius(self->x, self->y, 2000, self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { @@ -251,15 +257,42 @@ static void componentDie(void) if (self->owner->health > 0) { runScriptFunction("CAP_HEALTH %s %d", self->owner->name, self->owner->health); + + if (self->side == player->side) + { + issueDamageMessage(self->owner); + } } } static void gunDie(void) { + Entity *e; + self->alive = ALIVE_DEAD; addSmallExplosion(); playBattleSound(SND_EXPLOSION_1 + rand() % 4, self->x, self->y); addDebris(self->x, self->y, 3 + rand() % 4); + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) + { + if (e != self && e->health > 0 && e->owner == self->owner && e->type == ET_COMPONENT_GUN) + { + return; + } + } + + runScriptFunction("CAP_GUNS_DESTROYED %s", self->owner->name); + + if (self->side == player->side) + { + issueGunsDestroyedMessage(self->owner); + } + + if (--self->owner->systemPower == 1) + { + disable(); + } } static void engineThink(void) @@ -280,7 +313,7 @@ static void engineDie(void) for (e = battle.entityHead.next ; e != NULL ; e = e->next) { - if (e != self && e->owner == self->owner && e->type == ET_COMPONENT_ENGINE) + if (e != self && e->health > 0 && e->owner == self->owner && e->type == ET_COMPONENT_ENGINE) { return; } @@ -294,6 +327,16 @@ static void engineDie(void) self->owner->dx = self->owner->dy = 0; runScriptFunction("CAP_ENGINES_DESTROYED %s", self->owner->name); + + if (self->side == player->side) + { + issueEnginesDestroyedMessage(self->owner); + } + } + + if (--self->owner->systemPower == 1) + { + disable(); } } @@ -318,8 +361,10 @@ static void die(void) } updateObjective(self->name, TT_DESTROY); + updateObjective(self->groupName, TT_DESTROY); updateCondition(self->name, TT_DESTROY); + updateCondition(self->groupName, TT_DESTROY); } static void handleDisabled(void) @@ -334,6 +379,25 @@ static void handleDisabled(void) } } +static void disable(void) +{ + Entity *e; + + runScriptFunction("CAP_DISABLED %s", self->owner->name); + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) + { + if (e->owner == self->owner) + { + e->systemPower = 0; + e->flags |= EF_DISABLED; + } + } + + updateObjective(self->owner->name, TT_DISABLE); + updateObjective(self->owner->groupName, TT_DISABLE); +} + void loadCapitalShipDefs(void) { char **filenames; @@ -385,7 +449,8 @@ static void loadCapitalShipDef(char *filename) e->shieldRechargeRate = cJSON_GetObjectItem(root, "shieldRechargeRate")->valueint; e->texture = getTexture(cJSON_GetObjectItem(root, "texture")->valuestring); e->speed = 1; - e->systemPower = MAX_SYSTEM_POWER; + e->systemPower = 3; + e->flags = EF_NO_HEALTH_BAR; e->action = think; e->die = die; @@ -561,16 +626,25 @@ void updateCapitalShipComponentProperties(Entity *parent, long flags) { Entity *e; - flags &= ~EF_AI_LEADER; + if (flags != -1) + { + flags &= ~EF_AI_LEADER; + } for (e = battle.entityHead.next ; e != NULL ; e = e->next) { if (e->owner == parent) { + if (flags != -1) + { + e->flags |= flags; + } + switch (e->type) { case ET_COMPONENT_ENGINE: sprintf(e->name, _("%s (Engine)"), parent->name); + e->flags &= ~EF_AI_IGNORE; break; case ET_COMPONENT: @@ -579,12 +653,15 @@ void updateCapitalShipComponentProperties(Entity *parent, long flags) case ET_COMPONENT_GUN: sprintf(e->name, _("%s (Gun)"), parent->name); + e->flags &= ~EF_AI_IGNORE; + if (parent->aiFlags & AIF_ASSASSIN) + { + e->aiFlags |= AIF_ASSASSIN; + } break; } e->active = parent->active; - - e->flags |= flags; } } } @@ -659,10 +736,10 @@ void loadCapitalShips(cJSON *node) SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for '%s' (%s) replaced", e->name, e->defName); } - - updateCapitalShipComponentProperties(e, flags); } + updateCapitalShipComponentProperties(e, flags); + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "%s (%d / %d)", e->name, e->health, e->maxHealth); } @@ -678,6 +755,32 @@ void loadCapitalShips(cJSON *node) } } +static void issueEnginesDestroyedMessage(Entity *cap) +{ + addMessageBox(cap->name, _("We've lost engines! We're a sitting duck!"), 1); +} + +static void issueGunsDestroyedMessage(Entity *cap) +{ + addMessageBox(cap->name, _("Our guns have been shot out! We have no defences!"), 1); +} + +static void issueDamageMessage(Entity *cap) +{ + if (cap->health == cap->maxHealth - 1) + { + addMessageBox(cap->name, _("Be advised, we're taking damage here. Please step up support."), 1); + } + else if (cap->health == cap->maxHealth / 2) + { + addMessageBox(cap->name, _("We're sustaining heavy damage! All fighters, please assist, ASAP!"), 1); + } + else if (cap->health == 1) + { + addMessageBox(cap->name, _("Mayday! Mayday! Defences are critical. We can't hold out much longer!"), 1); + } +} + void destroyCapitalShipDefs(void) { Entity *e; diff --git a/src/battle/capitalShips.h b/src/battle/capitalShips.h index b69ad41..2f232e6 100644 --- a/src/battle/capitalShips.h +++ b/src/battle/capitalShips.h @@ -21,8 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TURN_SPEED 0.1 #define TURN_THRESHOLD 2 -#define AVOID_FORCE 500 - #include "../common.h" #include "../json/cJSON.h" @@ -36,12 +34,10 @@ extern char *readFile(char *filename); extern long flagsToLong(char *flags, int *add); extern long lookup(char *name); extern void doAI(void); -extern float getAngle(int x1, int y1, int x2, int y2); -extern float mod(float n, float x); extern void applyFighterThrust(void); extern void addLargeEngineEffect(void); extern int getDistance(int x1, int y1, int x2, int y2); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern void addDebris(int x, int y, int amount); extern void runScriptFunction(char *format, ...); extern void updateObjective(char *name, int type); @@ -52,6 +48,8 @@ extern char *getTranslatedString(char *string); extern void addLargeExplosion(void); extern char **toTypeArray(char *types, int *numTypes); extern void updateCondition(char *name, int type); +extern void addMessageBox(char *title, char *body, int important); extern Battle battle; +extern Entity *player; extern Entity *self; diff --git a/src/battle/effects.c b/src/battle/effects.c index 8a86644..b0f0efb 100644 --- a/src/battle/effects.c +++ b/src/battle/effects.c @@ -648,7 +648,10 @@ static void setRandomShieldHue(Effect *e) void destroyEffects(void) { - free(effectsToDraw); + if (effectsToDraw) + { + free(effectsToDraw); + } effectsToDraw = NULL; } diff --git a/src/battle/entities.c b/src/battle/entities.c index 3c0fe86..2c45a53 100644 --- a/src/battle/entities.c +++ b/src/battle/entities.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void drawEntity(Entity *e); static void doEntity(void); static void alignComponents(void); -static void activateEpicFighters(int n, int side); +static void activateEpicFighters(int side); static void restrictToBattleArea(Entity *e); static void drawTargetRects(Entity *e); static void drawHealthBar(Entity *e); @@ -67,7 +67,7 @@ void doEntities(void) prev = &battle.entityHead; - numAllies = numEnemies = numActiveAllies = numActiveEnemies = 0; + battle.hasThreats = numAllies = numEnemies = numActiveAllies = numActiveEnemies = numSpawnedEnemies = 0; if (dev.playerImmortal) { @@ -178,8 +178,6 @@ void doEntities(void) if (e == player) { - player = NULL; - battle.playerSelect = battle.isEpic; } @@ -198,7 +196,7 @@ void doEntities(void) if (e->type == ET_FIGHTER || e->type == ET_CAPITAL_SHIP) { - if (e->side == SIDE_ALLIES) + if (e->side == player->side) { numAllies++; @@ -220,6 +218,11 @@ void doEntities(void) numSpawnedEnemies++; } } + + if (e->health > 0 && !(e->flags & EF_DISABLED)) + { + battle.hasThreats = 1; + } } } @@ -231,16 +234,16 @@ void doEntities(void) if (battle.isEpic && battle.stats[STAT_TIME] % FPS == 0) { - numActiveEnemies -= numSpawnedEnemies; - - if (numAllies > battle.epicFighterLimit) + if (numActiveAllies < battle.epicFighterLimit) { - activateEpicFighters(battle.epicFighterLimit - numActiveAllies, SIDE_ALLIES); + activateEpicFighters(SIDE_ALLIES); } + + numActiveEnemies -= numSpawnedEnemies; - if (numEnemies > battle.epicFighterLimit) + if (numActiveEnemies < battle.epicFighterLimit) { - activateEpicFighters(battle.epicFighterLimit - numActiveEnemies, SIDE_NONE); + activateEpicFighters(SIDE_NONE); } } @@ -425,14 +428,14 @@ static void drawHealthBar(Entity *e) { SDL_Rect r; - if (e != player && e->type == ET_FIGHTER && e->health > 0) + if (app.gameplay.healthBars && !(e->flags & EF_NO_HEALTH_BAR) && e->health > 0) { r.x = e->x - (e->w / 2) - battle.camera.x; r.y = e->y - e->h - battle.camera.y; r.w = 32; r.h = 1; - if (e->side == SIDE_ALLIES) + if (e->side == player->side || e->flags & EF_FRIENDLY_HEALTH_BAR) { SDL_SetRenderDrawColor(app.renderer, 0, 128, 0, 255); } @@ -445,7 +448,7 @@ static void drawHealthBar(Entity *e) r.w = 32 * (e->health * 1.0f / e->maxHealth); - if (e->side == SIDE_ALLIES) + if (e->side == player->side || e->flags & EF_FRIENDLY_HEALTH_BAR) { SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255); } @@ -464,7 +467,7 @@ static void drawTargetRects(Entity *e) int size = MAX(e->w, e->h) + 16; - if (player != NULL && e == player->target) + if (player->alive == ALIVE_ALIVE && e == player->target) { r.x = e->x - (size / 2) - battle.camera.x; r.y = e->y - (size / 2) - battle.camera.y; @@ -485,6 +488,17 @@ static void drawTargetRects(Entity *e) SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255); SDL_RenderDrawRect(app.renderer, &r); } + + if (e == battle.messageSpeaker && e != player && battle.stats[STAT_TIME] % 40 < 20) + { + r.x = e->x - (size / 2) - battle.camera.x; + r.y = e->y - (size / 2) - battle.camera.y; + r.w = size; + r.h = size; + + SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); + SDL_RenderDrawRect(app.renderer, &r); + } } void activateEntities(char *names) @@ -528,8 +542,10 @@ void activateEntityGroups(char *groupNames) { if (strcmp(e->groupName, groupName) == 0) { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Activated %s (%s)", e->name, groupName); + e->active = 1; - + if (e->type == ET_CAPITAL_SHIP) { updateCapitalShipComponentProperties(e, 0); @@ -560,23 +576,27 @@ static void notifyNewArrivals(void) } } -static void activateEpicFighters(int n, int side) +static void activateEpicFighters(int side) { Entity *e; - - if (n > 0) + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) { - for (e = battle.entityHead.next ; e != NULL ; e = e->next) + if (!e->active && e->type == ET_FIGHTER && !(e->flags & EF_NO_EPIC) && ((side == SIDE_ALLIES && e->side == SIDE_ALLIES) || (side != SIDE_ALLIES && e->side != SIDE_ALLIES))) { - if (!e->active && e->type == ET_FIGHTER && !(e->flags & EF_NO_EPIC) && ((side == SIDE_ALLIES && e->side == SIDE_ALLIES) || (side != SIDE_ALLIES && e->side != SIDE_ALLIES))) + e->active = 1; + + /* don't spring into existence in front of the player */ + if (isOnBattleScreen(e->x, e->y, e->w, e->h)) { - e->active = 1; - - if (--n <= 0) - { - return; - } + e->x = player->x; + e->y = player->y; + + e->x += (rand() % 2) ? -SCREEN_WIDTH : SCREEN_WIDTH; + e->y += (rand() % 2) ? -SCREEN_HEIGHT : SCREEN_HEIGHT; } + + return; } } } @@ -587,7 +607,7 @@ void countNumEnemies(void) for (e = battle.entityHead.next ; e != NULL ; e = e->next) { - if (e->side != SIDE_ALLIES && e->type == ET_FIGHTER) + if (e->side != SIDE_ALLIES && (e->type == ET_FIGHTER || e->type == ET_CAPITAL_SHIP) && (!(e->flags & EF_NO_THREAT))) { battle.numInitialEnemies++; } @@ -617,6 +637,24 @@ static int drawComparator(const void *a, const void *b) return e2->type - e1->type; } +void killEntity(char *name) +{ + Entity *e; + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) + { + if (strcmp(e->name, name) == 0) + { + e->health = 0; + e->deathType = DT_INSTANT; + + /* prevent objectives and conditions from firing */ + strcpy(e->name, ""); + strcpy(e->groupName, ""); + } + } +} + void destroyEntities(void) { Entity *e; diff --git a/src/battle/entities.h b/src/battle/entities.h index 67f801a..a9b99ac 100644 --- a/src/battle/entities.h +++ b/src/battle/entities.h @@ -35,6 +35,7 @@ extern void removeFromQuadtree(Entity *e, Quadtree *root); extern void addToQuadtree(Entity *e, Quadtree *root); extern void updateCapitalShipComponentProperties(Entity *parent, long flags); extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern int isOnBattleScreen(int x, int y, int w, int h); extern App app; extern Battle battle; diff --git a/src/battle/fighters.c b/src/battle/fighters.c index 3632ff0..c5c8cb5 100644 --- a/src/battle/fighters.c +++ b/src/battle/fighters.c @@ -95,6 +95,11 @@ Entity *spawnFighter(char *name, int x, int y, int side) e->action = doAI; e->die = die; + + if (game.currentMission->challengeData.isDeathMatch) + { + e->side = SDL_GetTicks(); + } return e; } @@ -231,8 +236,9 @@ void doFighter(void) battle.stats[STAT_ENEMIES_DISABLED]++; updateObjective(self->name, TT_DISABLE); + updateObjective(self->groupName, TT_DISABLE); - if (self->side != SIDE_ALLIES) + if (self->side != player->side) { runScriptFunction("ENEMIES_DISABLED %d", battle.stats[STAT_ENEMIES_DISABLED]); } @@ -252,12 +258,12 @@ void doFighter(void) if (self->alive == ALIVE_ESCAPED) { - if (self == player) + if (self == player && !game.currentMission->challengeData.isChallenge) { completeMission(); } - if (self->side != SIDE_ALLIES && (!(self->flags & EF_DISABLED))) + if (self->side != player->side && (!(self->flags & EF_DISABLED))) { addHudMessage(colors.red, _("Mission target has escaped.")); battle.stats[STAT_ENEMIES_ESCAPED]++; @@ -283,50 +289,50 @@ void doFighter(void) if (self->alive == ALIVE_DEAD) { - if (player != NULL && self != player) + if (player->alive == ALIVE_ALIVE && self != player) { - if (player->alive == ALIVE_ALIVE) + if (self->side != player->side) { - if (self->side != SIDE_ALLIES) + if (!(self->flags & EF_NO_KILL_INC)) { - if (!(self->flags & EF_NO_KILL_INC)) - { - battle.stats[STAT_ENEMIES_KILLED]++; + battle.stats[STAT_ENEMIES_KILLED]++; - runScriptFunction("ENEMIES_KILLED %d", battle.stats[STAT_ENEMIES_KILLED]); + runScriptFunction("ENEMIES_KILLED %d", battle.stats[STAT_ENEMIES_KILLED]); + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Enemies killed [%d / %d]", battle.stats[STAT_ENEMIES_KILLED], battle.numInitialEnemies); + } + } + else + { + if (strcmp(self->name, "Civilian") == 0) + { + battle.stats[STAT_CIVILIANS_KILLED]++; + if (!battle.isEpic || game.currentMission->challengeData.isChallenge) + { + addHudMessage(colors.red, _("Civilian has been killed")); } + + runScriptFunction("CIVILIANS_KILLED %d", battle.stats[STAT_CIVILIANS_KILLED]); } else { - if (strcmp(self->name, "Civilian") == 0) + battle.stats[STAT_ALLIES_KILLED]++; + if (!battle.isEpic && !game.currentMission->challengeData.isChallenge) { - battle.stats[STAT_CIVILIANS_KILLED]++; - if (!battle.isEpic || game.currentMission->challengeData.isChallenge) - { - addHudMessage(colors.red, _("Civilian has been killed")); - } - - runScriptFunction("CIVILIANS_KILLED %d", battle.stats[STAT_CIVILIANS_KILLED]); + addHudMessage(colors.red, _("Ally has been killed")); } - else - { - battle.stats[STAT_ALLIES_KILLED]++; - if (!battle.isEpic || game.currentMission->challengeData.isChallenge) - { - addHudMessage(colors.red, _("Ally has been killed")); - } - runScriptFunction("ALLIES_KILLED %d", battle.stats[STAT_ALLIES_KILLED]); - } + runScriptFunction("ALLIES_KILLED %d", battle.stats[STAT_ALLIES_KILLED]); } } - + updateObjective(self->name, TT_DESTROY); updateObjective(self->groupName, TT_DESTROY); adjustObjectiveTargetValue(self->name, TT_ESCAPED, -1); updateCondition(self->name, TT_DESTROY); + updateCondition(self->groupName, TT_DESTROY); } } } @@ -344,7 +350,7 @@ static void separate(void) count = 0; force = 0; - candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self); + candidates = getAllEntsInRadius(self->x, self->y, self->separationRadius, self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { @@ -409,19 +415,34 @@ void damageFighter(Entity *e, int amount, long flags) e->aiDamageTimer = FPS; e->aiDamagePerSec += amount; - + if (flags & BF_SYSTEM_DAMAGE) { - playBattleSound(SND_MAG_HIT, e->x, e->y); - - e->systemPower = MAX(0, e->systemPower - amount); - - e->systemHit = 255; - - if (e->systemPower == 0) + if (e->shield > 0) { - e->shield = e->maxShield = 0; - e->action = NULL; + amount /= 2; + + e->shield -= amount; + + if (e->shield < 0) + { + amount = -e->shield; + } + } + + if (amount >= 0) + { + e->systemPower = MAX(0, e->systemPower - amount); + + e->systemHit = 255; + + if (e->systemPower == 0) + { + e->shield = e->maxShield = 0; + e->action = NULL; + } + + playBattleSound(SND_MAG_HIT, e->x, e->y); } } else if (flags & BF_SHIELD_DAMAGE) @@ -442,11 +463,14 @@ void damageFighter(Entity *e, int amount, long flags) if (e->shield > 0) { e->shield -= amount; - - if (e->shield < 0) + + if (e->shield <= 0) { + e->armourHit = 255; e->health += e->shield; e->shield = 0; + + playBattleSound(SND_ARMOUR_HIT, e->x, e->y); } } else @@ -462,11 +486,11 @@ void damageFighter(Entity *e, int amount, long flags) { e->shieldHit = 255; - /* don't allow the shield to recharge immediately after taking a hit */ - e->shieldRecharge = e->shieldRechargeRate; - playBattleSound(SND_SHIELD_HIT, e->x, e->y); } + + /* don't allow the shield to recharge immediately after taking a hit */ + e->shieldRecharge = e->shieldRechargeRate; /* * Sometimes run away if you take too much damage in a short space of time @@ -541,6 +565,11 @@ static void die(void) awardTrophy("PANDORAN"); } } + + if (self->flags & EF_DROPS_ITEMS) + { + addRandomItem(self->x, self->y); + } } static void immediateDie(void) @@ -610,14 +639,18 @@ void retreatEnemies(void) for (e = battle.entityHead.next ; e != NULL ; e = e->next) { - if (e->type == ET_FIGHTER && e->side != SIDE_ALLIES) + if (e->type == ET_FIGHTER && e->side != player->side) { e->flags |= EF_RETREATING; e->aiFlags |= AIF_AVOIDS_COMBAT; e->aiFlags |= AIF_UNLIMITED_RANGE; - e->aiFlags |= AIF_GOAL_JUMPGATE; e->aiFlags &= ~AIF_MOVES_TO_LEADER; + + if (!game.currentMission->challengeData.isChallenge) + { + e->aiFlags |= AIF_GOAL_JUMPGATE; + } } } } @@ -628,16 +661,20 @@ void retreatAllies(void) for (e = battle.entityHead.next ; e != NULL ; e = e->next) { - if (e->type == ET_FIGHTER && e->side == SIDE_ALLIES) + if (e->type == ET_FIGHTER && e->side == player->side) { e->flags |= EF_RETREATING; e->aiFlags |= AIF_AVOIDS_COMBAT; e->aiFlags |= AIF_UNLIMITED_RANGE; - e->aiFlags |= AIF_GOAL_JUMPGATE; e->aiFlags &= ~AIF_FOLLOWS_PLAYER; e->aiFlags &= ~AIF_MOVES_TO_PLAYER; e->aiFlags &= ~AIF_MOVES_TO_LEADER; + + if (!game.currentMission->challengeData.isChallenge) + { + e->aiFlags |= AIF_GOAL_JUMPGATE; + } } } } @@ -780,14 +817,16 @@ static void loadFighterDef(char *filename) void loadFighters(cJSON *node) { Entity *e; - char **types, *name, *groupName, *type; + char **types, *name, *groupName, *type, *strpos; int side, scatter, number, active; - int i, numTypes, addFlags, addAIFlags; + int i, numTypes, addFlags, addAIFlags, id; long flags, aiFlags; float x, y; if (node) { + id = 0; + node = node->child; while (node) @@ -867,6 +906,14 @@ void loadFighters(cJSON *node) if (name) { STRNCPY(e->name, name, MAX_NAME_LENGTH); + + /* update 'name #?' to 'name #1', etc. */ + strpos = strstr(e->name, "#?"); + + if (strpos) + { + *(++strpos) = ('0' + ++id); + } } if (groupName) diff --git a/src/battle/fighters.h b/src/battle/fighters.h index c263834..31e328d 100644 --- a/src/battle/fighters.h +++ b/src/battle/fighters.h @@ -33,7 +33,7 @@ extern void playBattleSound(int id, int x, int y); extern void updateObjective(char *name, int type); extern void updateCondition(char *name, int type); extern void addHudMessage(SDL_Color c, char *format, ...); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern Entity *spawnEntity(void); extern void adjustObjectiveTargetValue(char *name, int type, int amount); extern void attachRope(void); @@ -50,8 +50,8 @@ extern int getJSONValue(cJSON *node, char *name, int defValue); extern char **toTypeArray(char *types, int *numTypes); extern char *getJSONValueStr(cJSON *node, char *name, char *defValue); extern void awardTrophy(char *id); +extern void addRandomItem(int x, int y); -extern App app; extern Battle battle; extern Colors colors; extern Entity *player; diff --git a/src/battle/hud.c b/src/battle/hud.c index 22bf94a..c355283 100644 --- a/src/battle/hud.c +++ b/src/battle/hud.c @@ -138,7 +138,7 @@ void addHudMessage(SDL_Color c, char *format, ...) void drawHud(void) { - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { drawHealthBars(); @@ -330,7 +330,7 @@ static void drawPlayerTargeter(void) float angle; int x, y; - if (player->target || battle.missionTarget || jumpgateEnabled()) + if (player->target || battle.missionTarget || jumpgateEnabled() || battle.messageSpeaker) { if (player->target) { @@ -340,6 +340,10 @@ static void drawPlayerTargeter(void) { SDL_SetTextureColorMod(targetCircle, 0, 255, 0); } + else if (battle.messageSpeaker) + { + SDL_SetTextureColorMod(targetCircle, 255, 255, 255); + } else { SDL_SetTextureColorMod(targetCircle, 255, 255, 0); @@ -389,6 +393,20 @@ static void drawPlayerTargeter(void) blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle); } + + if (battle.messageSpeaker && battle.messageSpeaker != player) + { + angle = getAngle(player->x, player->y, battle.messageSpeaker->x, battle.messageSpeaker->y); + x = player->x; + y = player->y; + + x += sin(TO_RAIDANS(angle)) * 45; + y += -cos(TO_RAIDANS(angle)) * 45; + + SDL_SetTextureColorMod(targetPointer, 255, 255, 255); + + blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle); + } } static void drawNumFighters(void) @@ -428,14 +446,30 @@ static void drawObjectives(void) blit(clock, (SCREEN_WIDTH / 2) - 50, 14, 0); } - if (game.currentMission->challengeData.itemLimit) + if (game.currentMission->challengeData.killLimit) + { + drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ENEMIES_KILLED_PLAYER] + battle.stats[STAT_ENEMIES_DISABLED], game.currentMission->challengeData.killLimit); + } + else if (game.currentMission->challengeData.itemLimit) { drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ITEMS_COLLECTED] + battle.stats[STAT_ITEMS_COLLECTED_PLAYER], game.currentMission->challengeData.itemLimit); } + else if (game.currentMission->challengeData.playerItemLimit) + { + drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ITEMS_COLLECTED_PLAYER], game.currentMission->challengeData.playerItemLimit); + } else if (game.currentMission->challengeData.rescueLimit) { drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_CIVILIANS_RESCUED], game.currentMission->challengeData.rescueLimit); } + else if (game.currentMission->challengeData.disableLimit) + { + drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ENEMIES_DISABLED], game.currentMission->challengeData.disableLimit); + } + else if (player->flags & EF_MUST_DISABLE) + { + drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, _("System Power : %d%%"), player->systemPower); + } } } @@ -462,7 +496,14 @@ static void drawDistancesInfo(void) if (player->target) { - drawText(SCREEN_WIDTH - 15, y, 18, TA_RIGHT, colors.red, player->target->name); + if (player->target->flags & EF_AI_LEADER && player->target->speed > 0) + { + drawText(SCREEN_WIDTH - 15, y, 18, TA_RIGHT, colors.red, _("%s (Leader)"), player->target->name); + } + else + { + drawText(SCREEN_WIDTH - 15, y, 18, TA_RIGHT, colors.red, player->target->name); + } y += 30; @@ -490,6 +531,15 @@ static void drawDistancesInfo(void) y += 25; } + + if (battle.messageSpeaker) + { + distance = distanceToKM(player->x, player->y, battle.messageSpeaker->x, battle.messageSpeaker->y); + + drawText(SCREEN_WIDTH - 15, y, 14, TA_RIGHT, colors.white, "%s: %.2fkm", battle.messageSpeaker->name, distance); + + y += 25; + } } static void drawHudMessages(void) diff --git a/src/battle/items.c b/src/battle/items.c index fdec377..90e1099 100644 --- a/src/battle/items.c +++ b/src/battle/items.c @@ -46,11 +46,11 @@ void loadItemDefs(void) e->type = ET_ITEM; e->active = 1; STRNCPY(e->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); - STRNCPY(e->defName, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); + STRNCPY(e->defName, cJSON_GetObjectItem(node, "defName")->valuestring, MAX_NAME_LENGTH); e->texture = getTexture(cJSON_GetObjectItem(node, "texture")->valuestring); - e->health = e->maxHealth = FPS; - + e->flags = EF_NO_HEALTH_BAR; + SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h); defTail->next = e; @@ -70,29 +70,57 @@ Entity *spawnItem(char *name) def = getItemDef(name); memcpy(item, def, sizeof(Entity)); - - item->dx = rand() % 100 - rand() % 100; - item->dx *= 0.01; - item->dy = rand() % 100 - rand() % 100; - item->dy *= 0.01; + + item->next = NULL; + item->action = action; return item; } -static Entity *getItemDef(char *name) +void addRandomItem(int x, int y) +{ + Entity *e, *def, *item; + + def = item = e = NULL; + + for (e = defHead.next ; e != NULL ; e = e->next) + { + if (!def || rand() % 2) + { + def = e; + } + } + + item = spawnEntity(); + + memcpy(item, def, sizeof(Entity)); + + item->next = NULL; + + item->x = x; + item->y = y; + item->speed = 1; + item->dx = rand() % 200 - rand() % 200; + item->dy = rand() % 200 - rand() % 200; + item->dx *= 0.01; + item->dy *= 0.01; + item->action = action; +} + +static Entity *getItemDef(char *defName) { Entity *e; for (e = defHead.next ; e != NULL ; e = e->next) { - if (strcmp(e->name, name) == 0) + if (strcmp(e->defName, defName) == 0) { return e; } } - printf("Error: no such item '%s'\n", name); + printf("Error: no such item '%s'\n", defName); exit(1); } @@ -101,11 +129,11 @@ static void action(void) Entity *e, **candidates; int i; - candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self); + candidates = getAllEntsInRadius(self->x, self->y, MAX(self->w, self->h), self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { - if ((e->flags & EF_COLLECTS_ITEMS) && collision(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h)) + if (e->alive == ALIVE_ALIVE && (e->flags & EF_COLLECTS_ITEMS) && collision(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h)) { self->health = 0; playBattleSound(SND_GET_ITEM, self->x, self->y); diff --git a/src/battle/items.h b/src/battle/items.h index 5d54998..3be5f74 100644 --- a/src/battle/items.h +++ b/src/battle/items.h @@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern char *readFile(char *filename); extern SDL_Texture *getTexture(char *filename); extern Entity *spawnEntity(void); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); extern void playBattleSound(int id, int x, int y); extern void addHudMessage(SDL_Color c, char *format, ...); diff --git a/src/battle/jumpgate.c b/src/battle/jumpgate.c index 706dd11..b2fd7a9 100644 --- a/src/battle/jumpgate.c +++ b/src/battle/jumpgate.c @@ -47,7 +47,8 @@ Entity *spawnJumpgate(int side, long flags) jumpgate->action = think; jumpgate->draw = draw; jumpgate->side = side; - jumpgate->flags = EF_NO_MT_BOX+EF_IMMORTAL+EF_AI_IGNORE+EF_NON_SOLID; + jumpgate->flags = EF_NO_MT_BOX+EF_IMMORTAL+EF_AI_IGNORE+EF_NON_SOLID+EF_NO_HEALTH_BAR; + if (flags != -1 && flags & EF_DISABLED) { jumpgate->flags |= EF_DISABLED; @@ -88,6 +89,11 @@ static void addNodes(Entity *jumpgate, long flags) node->die = nodeDie; SDL_QueryTexture(node->texture, NULL, NULL, &node->w, &node->h); + if (jumpgate->side == SIDE_NONE) + { + node->flags |= EF_NO_HEALTH_BAR; + } + if (flags != -1) { node->flags = flags; @@ -166,11 +172,11 @@ static void handleFleeingEntities(void) Entity *e, **candidates; int i; - candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self); + candidates = getAllEntsInRadius(self->x, self->y, ESCAPE_DISTANCE * 2, self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { - if (e->health > 0 && e->flags & EF_RETREATING && getDistance(self->x, self->y, e->x, e->y) <= 255) + if (e->health > 0 && (e->flags & EF_RETREATING) && getDistance(self->x, self->y, e->x, e->y) <= ESCAPE_DISTANCE) { e->alive = ALIVE_ESCAPED; diff --git a/src/battle/jumpgate.h b/src/battle/jumpgate.h index 860c56d..cbb8b8e 100644 --- a/src/battle/jumpgate.h +++ b/src/battle/jumpgate.h @@ -20,15 +20,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" +#define ESCAPE_DISTANCE 256 + extern SDL_Texture *getTexture(char *filename); extern Entity *spawnEntity(void); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern int getDistance(int x1, int y1, int x2, int y2); extern void playBattleSound(int id, int x, int y); extern void blitRotated(SDL_Texture *texture, int x, int y, float angle); extern char *getTranslatedString(char *string); extern void addSmallExplosion(void); -extern void playBattleSound(int id, int x, int y); extern void addDebris(int x, int y, int amount); extern void runScriptFunction(char *format, ...); extern void updateObjective(char *name, int type); diff --git a/src/battle/locations.c b/src/battle/locations.c index c01d0c9..c3fa399 100644 --- a/src/battle/locations.c +++ b/src/battle/locations.c @@ -75,6 +75,37 @@ void activateLocations(char *locations) } } +/* + * Literally only used when Christabel's shuttle is disabled + */ +void createChristabelLocation(void) +{ + Location *l; + Entity *e; + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) + { + if (strcmp(e->name, "Christabel") == 0) + { + l = malloc(sizeof(Location)); + memset(l, 0, sizeof(Location)); + battle.locationTail->next = l; + battle.locationTail = l; + + STRNCPY(l->name, "CristabelLocation", MAX_NAME_LENGTH); + l->x = e->x; + l->y = e->y; + l->size = 500; + l->active = 1; + + l->x -= l->size / 2; + l->y -= l->size / 2; + + return; + } + } +} + void loadLocations(cJSON *node) { int active; diff --git a/src/battle/messageBox.c b/src/battle/messageBox.c index 29dc97d..7fbd4bf 100644 --- a/src/battle/messageBox.c +++ b/src/battle/messageBox.c @@ -21,25 +21,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "messageBox.h" static void calculateMessageBoxHeight(MessageBox *msg); +static void nextMessage(void); static MessageBox head; static MessageBox *tail; +static Entity *lastWingmate; void initMessageBox(void) { memset(&head, 0, sizeof(MessageBox)); tail = &head; + + lastWingmate = NULL; } void addMessageBox(char *title, char *body, int important) { MessageBox *msg; + int isFirst; float time; - if (tail == &head) - { - playSound(SND_RADIO); - } + isFirst = (tail == &head); msg = malloc(sizeof(MessageBox)); memset(msg, 0, sizeof(MessageBox)); @@ -53,6 +55,11 @@ void addMessageBox(char *title, char *body, int important) STRNCPY(msg->body, body, MAX_DESCRIPTION_LENGTH); msg->time = time * FPS; msg->important = important; + + if (isFirst) + { + nextMessage(); + } } void doMessageBox(void) @@ -74,9 +81,11 @@ void doMessageBox(void) free(msg); msg = &head; + battle.messageSpeaker = NULL; + if (head.next) { - playSound(SND_RADIO); + nextMessage(); } } } @@ -139,6 +148,43 @@ void drawMessageBox(void) } } +static void nextMessage(void) +{ + Entity *e, *wingmate; + int isWingmate; + + wingmate = NULL; + + isWingmate = strcmp(head.next->title, "Wingmate") == 0; + + playSound(SND_RADIO); + + for (e = battle.entityHead.next ; e != NULL ; e = e->next) + { + if (e->active && e != player) + { + if (strcmp(e->name, head.next->title) == 0) + { + battle.messageSpeaker = e; + return; + } + + if (isWingmate && e->type == ET_FIGHTER && e->speed > 0) + { + wingmate = e; + + if (rand() % 2 && e != lastWingmate) + { + battle.messageSpeaker = lastWingmate = e; + return; + } + } + } + } + + battle.messageSpeaker = wingmate; +} + void resetMessageBox(void) { MessageBox *messageBox; diff --git a/src/battle/messageBox.h b/src/battle/messageBox.h index 9a8ac86..1a0c2ac 100644 --- a/src/battle/messageBox.h +++ b/src/battle/messageBox.h @@ -26,4 +26,6 @@ extern void limitTextWidth(int width); extern void playSound(int sound); extern App app; +extern Battle battle; extern Colors colors; +extern Entity *player; diff --git a/src/battle/mine.c b/src/battle/mine.c index 12969ab..151c6f1 100644 --- a/src/battle/mine.c +++ b/src/battle/mine.c @@ -49,7 +49,7 @@ Entity *spawnMine(int type) mine->texture = (type == ET_MINE) ? mineNormal : shadowMine; mine->action = think; mine->die = die; - mine->flags = EF_TAKES_DAMAGE+EF_NO_PLAYER_TARGET+EF_SHORT_RADAR_RANGE+EF_NON_SOLID; + mine->flags = EF_TAKES_DAMAGE+EF_NO_PLAYER_TARGET+EF_SHORT_RADAR_RANGE+EF_NON_SOLID+EF_NO_HEALTH_BAR; if (type == ET_SHADOW_MINE) { @@ -99,7 +99,7 @@ static void lookForFighters(void) Entity *e, **candidates; int i; - candidates = getAllEntsWithin(self->x - (self->w / 2) - DAMAGE_RANGE, self->y - (self->h / 2) - DAMAGE_RANGE, self->w + DAMAGE_RANGE, self->h + DAMAGE_RANGE, self); + candidates = getAllEntsInRadius(self->x, self->y, DAMAGE_RANGE, self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { @@ -124,7 +124,7 @@ static void lookForPlayer(void) float dx, dy, norm; int distance; - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { distance = getDistance(self->x, self->y, player->x, player->y); @@ -196,10 +196,12 @@ static void die(void) static void doSplashDamage(void) { Entity *e, **candidates; - int i, dist; + int i, dist, kills; float damage, percent; - candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self); + candidates = getAllEntsInRadius(self->x, self->y, DAMAGE_RANGE, self); + + kills = 0; for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { @@ -213,12 +215,17 @@ static void doSplashDamage(void) percent /= DAMAGE_RANGE; percent = 1 - percent; - damage = 255; + damage = DAMAGE_RANGE; damage *= percent; if (e->type == ET_FIGHTER) { damageFighter(e, damage, 0); + + if (self->killedBy == player && e != player && e->health <= 0) + { + kills++; + } } else if (e->type == ET_MINE) { @@ -231,4 +238,9 @@ static void doSplashDamage(void) } } } + + if (kills >= 2) + { + awardTrophy("2_BIRDS"); + } } diff --git a/src/battle/mine.h b/src/battle/mine.h index b83ba95..aeeadd8 100644 --- a/src/battle/mine.h +++ b/src/battle/mine.h @@ -21,18 +21,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" #define TRIGGER_RANGE 150 -#define DAMAGE_RANGE 255 +#define DAMAGE_RANGE 250 #define SYSTEM_POWER 50 extern Entity *spawnEntity(void); extern SDL_Texture *getTexture(char *filename); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern int getDistance(int x1, int y1, int x2, int y2); extern void addMineExplosion(void); extern void damageFighter(Entity *e, int amount, long flags); extern void playBattleSound(int id, int x, int y); extern void updateObjective(char *name, int type); extern void runScriptFunction(const char *format, ...); +extern void awardTrophy(char *id); extern Battle battle; extern Entity *player; diff --git a/src/battle/objectives.c b/src/battle/objectives.c index b6ac80c..94f8371 100644 --- a/src/battle/objectives.c +++ b/src/battle/objectives.c @@ -82,35 +82,49 @@ void updateObjective(char *name, int type) Objective *o; int completed, hasHidden; - completed = battle.numObjectivesComplete; - - hasHidden = 0; - - for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + if (strlen(name)) { - if (o->active && o->status != OS_COMPLETE) + completed = battle.numObjectivesComplete; + + hasHidden = 0; + + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { - if (!o->isEliminateAll && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) + if (o->active && o->status != OS_COMPLETE) { - o->currentValue++; - - if (!o->hideNumbers) + if (!o->isEliminateAll && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) { - if (o->targetValue - o->currentValue <= 10) + o->currentValue++; + + if (!o->hideNumbers) { - addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + 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); + } } - else if (o->currentValue % 10 == 0) + + if (o->currentValue == o->targetValue) { - addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); + + runScriptFunction(o->description); + + o->status = OS_COMPLETE; + + runScriptFunction("OBJECTIVES_COMPLETE %d", ++completed); } } - if (o->currentValue == o->targetValue) + if (o->isEliminateAll && o->status != OS_COMPLETE && !battle.hasThreats) { addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); - runScriptFunction(o->description); + o->currentValue = o->targetValue; o->status = OS_COMPLETE; @@ -118,28 +132,17 @@ void updateObjective(char *name, int type) } } - if (o->isEliminateAll && o->status != OS_COMPLETE && battle.stats[STAT_ENEMIES_KILLED] == battle.numInitialEnemies) + if (!o->active) { - addHudMessage(colors.green, _("%s - Objective Complete!"), o->description); - - o->currentValue = o->targetValue; - - o->status = OS_COMPLETE; - - runScriptFunction("OBJECTIVES_COMPLETE %d", ++completed); + hasHidden = 1; } } - if (!o->active) + if (completed == battle.numObjectivesTotal && !hasHidden) { - hasHidden = 1; + runScriptFunction("ALL_OBJECTIVES_COMPLETE"); } } - - if (completed == battle.numObjectivesTotal && !hasHidden) - { - runScriptFunction("ALL_OBJECTIVES_COMPLETE"); - } } void adjustObjectiveTargetValue(char *name, int type, int amount) @@ -166,20 +169,23 @@ void updateCondition(char *name, int type) { Objective *o; - for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) + if (strlen(name)) { - if (o->active && o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) + for (o = battle.objectiveHead.next ; o != NULL ; o = o->next) { - o->currentValue++; - - if (o->currentValue == o->targetValue) + if (o->active && o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0) { - o->status = OS_FAILED; - addHudMessage(colors.red, _("%s - Objective Failed!"), o->description); - } - else if (!o->hideNumbers) - { - addHudMessage(colors.red, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + o->currentValue++; + + if (o->currentValue == o->targetValue) + { + o->status = OS_FAILED; + addHudMessage(colors.red, _("%s - Objective Failed!"), o->description); + } + else if (!o->hideNumbers) + { + addHudMessage(colors.red, "%s - %d / %d", o->description, o->currentValue, o->targetValue); + } } } } diff --git a/src/battle/player.c b/src/battle/player.c index f845d43..a210789 100644 --- a/src/battle/player.c +++ b/src/battle/player.c @@ -35,6 +35,7 @@ static void handleMouse(void); static void preFireMissile(void); static void applyRestrictions(void); static int isPriorityMissionTarget(Entity *e, int dist, int closest); +static int targetOutOfRange(void); static int selectedPlayerIndex; static int availableGuns[BT_MAX]; @@ -83,10 +84,8 @@ void initPlayer(void) battle.boostTimer = BOOST_RECHARGE_TIME; battle.ecmTimer = ECM_RECHARGE_TIME; - - game.stats[STAT_EPIC_KILL_STREAK] = MAX(game.stats[STAT_EPIC_KILL_STREAK], battle.stats[STAT_EPIC_KILL_STREAK]); - - battle.stats[STAT_EPIC_KILL_STREAK] = 0; + + player->flags |= EF_NO_HEALTH_BAR; } void doPlayer(void) @@ -94,64 +93,71 @@ void doPlayer(void) battle.boostTimer = MIN(battle.boostTimer + 1, BOOST_RECHARGE_TIME); battle.ecmTimer = MIN(battle.ecmTimer + 1, ECM_RECHARGE_TIME); - if (player != NULL) + self = player; + + if (game.currentMission->challengeData.isChallenge) { - self = player; + applyRestrictions(); + } + + if (player->alive == ALIVE_ALIVE && player->systemPower > 0) + { + handleKeyboard(); + + handleMouse(); + + if (!player->target || player->target->health <= 0 || player->target->systemPower <= 0 || targetOutOfRange()) + { + selectTarget(); + } + } + + player->angle = ((int)player->angle) % 360; + + if (player->health <= 0 && battle.status == MS_IN_PROGRESS) + { + battle.stats[STAT_PLAYER_KILLED]++; + + /* the player is known as "Player", so we need to check the craft they were assigned to */ + if (strcmp(game.currentMission->craft, "ATAF") == 0) + { + awardTrophy("ATAF_DESTROYED"); + } if (game.currentMission->challengeData.isChallenge) { - applyRestrictions(); - } - - if (player->alive == ALIVE_ALIVE) - { - handleKeyboard(); - - handleMouse(); - - if (!player->target || player->target->health <= 0 || player->target->systemPower <= 0) - { - selectTarget(); - } - } - - player->angle = ((int)player->angle) % 360; - - if (player->health <= 0 && battle.status == MS_IN_PROGRESS) - { - battle.stats[STAT_PLAYER_KILLED]++; - - /* the player is known as "Player", so we need to check the craft they were assigned to */ - if (strcmp(game.currentMission->craft, "ATAF") == 0) - { - awardTrophy("ATAF_DESTROYED"); - } - - if (game.currentMission->challengeData.isChallenge) - { - if (!game.currentMission->challengeData.allowPlayerDeath) - { - failMission(); - } - } - else if (!battle.isEpic) + if (!game.currentMission->challengeData.allowPlayerDeath) { failMission(); } - else if (player->health == -FPS) - { - initPlayerSelect(); - } } - - if (battle.status == MS_IN_PROGRESS) + else if (!battle.isEpic) { - selectMissionTarget(); + failMission(); } - - if (dev.playerUnlimitedMissiles) + else if (player->health == -FPS) { - player->missiles = 999; + initPlayerSelect(); + } + } + + if (battle.status == MS_IN_PROGRESS) + { + selectMissionTarget(); + } + + if (dev.playerUnlimitedMissiles) + { + player->missiles = 999; + } + + /* really only used in challenge mode */ + if (player->systemPower <= 0 && battle.status == MS_IN_PROGRESS) + { + if (game.currentMission->challengeData.isChallenge) + { + addHudMessage(colors.red, _("Challenge Failed!")); + failMission(); } } @@ -161,6 +167,11 @@ void doPlayer(void) } } +static int targetOutOfRange(void) +{ + return (app.gameplay.autoSwitchPlayerTarget && getDistance(player->x, player->y, player->target->x, player->target->y) > SCREEN_WIDTH * 2); +} + static void applyRestrictions(void) { if (game.currentMission->challengeData.noMissiles) @@ -255,8 +266,7 @@ static void handleKeyboard(void) } else { - player->dx *= 0.99; - player->dy *= 0.99; + applyFighterBrakes(); } } @@ -403,6 +413,8 @@ void doPlayerSelect(void) static void selectNewPlayer(int dir) { + player = NULL; + do { selectedPlayerIndex += dir; @@ -610,10 +622,12 @@ int playerHasGun(int type) void loadPlayer(cJSON *node) { char *type; - int side; + int side, addFlags; + long flags; type = cJSON_GetObjectItem(node, "type")->valuestring; side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); + flags = -1; player = spawnFighter(type, 0, 0, side); player->x = BATTLE_AREA_WIDTH / 2; @@ -624,6 +638,25 @@ void loadPlayer(cJSON *node) player->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH; player->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT; } + + if (cJSON_GetObjectItem(node, "flags")) + { + flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags); + } + + if (flags != -1) + { + if (addFlags) + { + player->flags |= flags; + } + else + { + player->flags = flags; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for Player replaced"); + } + } if (strcmp(type, "Tug") == 0) { diff --git a/src/battle/player.h b/src/battle/player.h index 7f39fb5..071ff89 100644 --- a/src/battle/player.h +++ b/src/battle/player.h @@ -45,6 +45,7 @@ extern Entity *spawnFighter(char *name, int x, int y, int side); extern int isAcceptControl(void); extern void resetAcceptControls(void); extern void awardTrophy(char *id); +extern long flagsToLong(char *flags, int *add); extern App app; extern Battle battle; diff --git a/src/battle/quadtree.c b/src/battle/quadtree.c index 76e644d..cecb6c4 100644 --- a/src/battle/quadtree.c +++ b/src/battle/quadtree.c @@ -233,6 +233,11 @@ Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore) return candidates; } +Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore) +{ + return getAllEntsWithin(x - radius / 2, y - radius / 2, radius, radius, ignore); +} + static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root) { int index, i; diff --git a/src/battle/radar.c b/src/battle/radar.c index cd5649c..c82c964 100644 --- a/src/battle/radar.c +++ b/src/battle/radar.c @@ -34,7 +34,7 @@ void drawRadar(void) { SDL_Rect r; Entity *e; - int dist, inRange; + int dist, inRange, blink; blit(radarTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 1); @@ -42,6 +42,8 @@ void drawRadar(void) r.w = r.h = 3; + blink = battle.stats[STAT_TIME] % 60 < 30; + for (e = battle.entityHead.next ; e != NULL ; e = e->next) { dist = getDistance(e->x, e->y, player->x, player->y); @@ -61,38 +63,37 @@ void drawRadar(void) r.x--; r.y--; - switch (e->side) - { - case SIDE_ALLIES: - SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255); - break; - - case SIDE_PIRATE: - case SIDE_PANDORAN: - case SIDE_REBEL: - SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255); - break; - - case SIDE_NONE: - SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); - break; - } - - if (e == player->target) - { - SDL_SetRenderDrawColor(app.renderer, 255, 255, 0, 255); - } - - if (e == battle.missionTarget) + if (e->side == SIDE_NONE) { SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); } + else if (e->side == player->side) + { + SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255); + } + else + { + SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255); + } if (e->type == ET_MINE || e->type == ET_SHADOW_MINE || e->type == ET_JUMPGATE || (e->owner && e->owner->type == ET_JUMPGATE)) { SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255); } + if (blink) + { + if (e == player->target || e == battle.missionTarget) + { + SDL_SetRenderDrawColor(app.renderer, 255, 255, 0, 255); + } + + if (e->flags & EF_DISABLED) + { + SDL_SetRenderDrawColor(app.renderer, 0, 192, 255, 255); + } + } + SDL_RenderFillRect(app.renderer, &r); } } diff --git a/src/battle/rope.c b/src/battle/rope.c index 83ad9ce..2e577a2 100644 --- a/src/battle/rope.c +++ b/src/battle/rope.c @@ -27,7 +27,7 @@ void attachRope(void) if ((self->flags & EF_HAS_ROPE) && self->towing == NULL) { - candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self); + candidates = getAllEntsInRadius(self->x, self->y, self->separationRadius, self); for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { diff --git a/src/battle/rope.h b/src/battle/rope.h index 39d76ff..c8dc18e 100644 --- a/src/battle/rope.h +++ b/src/battle/rope.h @@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern float getAngle(int x1, int y1, int x2, int y2); extern int getDistance(int x1, int y1, int x2, int y2); -extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); +extern Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore); extern void addHudMessage(SDL_Color c, char *format, ...); extern void runScriptFunction(char *format, ...); extern char *getTranslatedString(char *string); diff --git a/src/battle/script.c b/src/battle/script.c index bc0e02a..a3d57b8 100644 --- a/src/battle/script.c +++ b/src/battle/script.c @@ -22,18 +22,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void executeNextLine(ScriptRunner *runner); -static cJSON *scriptJSON; +static cJSON *scriptJSON, *rootJSON; static ScriptRunner head; static ScriptRunner *tail; -void initScript(cJSON *scriptNode) +void initScript(cJSON *root) { cJSON *function; memset(&head, 0, sizeof(ScriptRunner)); tail = &head; + + rootJSON = root; - scriptJSON = scriptNode; + scriptJSON = cJSON_GetObjectItem(root, "script"); if (scriptJSON) { @@ -181,7 +183,7 @@ void runScriptTimeFunctions(void) static void executeNextLine(ScriptRunner *runner) { char *line; - char command[24]; + char command[32]; char strParam[3][256]; int intParam[2]; @@ -253,9 +255,14 @@ static void executeNextLine(ScriptRunner *runner) addHudMessage(colors.red, _("Mission Failed!")); failMission(); } + else if (strcmp(command, "FAIL_CHALLENGE") == 0) + { + addHudMessage(colors.red, _("Challenge Failed!")); + failMission(); + } else if (strcmp(command, "END_CHALLENGE") == 0) { - game.currentMission->challengeData.scriptedEnd = 1; + battle.scriptedEnd = 1; } else if (strcmp(command, "RETREAT_ALLIES") == 0) { @@ -267,6 +274,15 @@ static void executeNextLine(ScriptRunner *runner) battle.isEpic = 0; retreatEnemies(); } + else if (strcmp(command, "CREATE_CRISTABEL_LOCATION") == 0) + { + createChristabelLocation(); + } + else if (strcmp(command, "KILL_ENTITY") == 0) + { + sscanf(line, "%*s %[^\n]", strParam[0]); + killEntity(strParam[0]); + } else { printf("ERROR: Unrecognised script command '%s'\n", command); @@ -281,11 +297,11 @@ void destroyScript(void) { ScriptRunner *scriptRunner; - if (scriptJSON) + if (rootJSON) { - cJSON_Delete(scriptJSON); + cJSON_Delete(rootJSON); - scriptJSON = NULL; + rootJSON = NULL; } while (head.next) diff --git a/src/battle/script.h b/src/battle/script.h index 8b07f1d..01c5f0d 100644 --- a/src/battle/script.h +++ b/src/battle/script.h @@ -38,7 +38,8 @@ extern void activateNextWaypoint(void); extern void activateJumpgate(int activate); extern void activateSpawner(char *name, int active); extern void completeAllObjectives(void); +extern void createChristabelLocation(void); +extern void killEntity(char *name); extern Battle battle; extern Colors colors; -extern Game game; diff --git a/src/battle/waypoints.c b/src/battle/waypoints.c index 74f1c4b..11e086c 100644 --- a/src/battle/waypoints.c +++ b/src/battle/waypoints.c @@ -44,9 +44,8 @@ Entity *spawnWaypoint(void) waypoint->active = 0; waypoint->health = waypoint->maxHealth = FPS; waypoint->texture = getTexture("gfx/entities/waypoint.png"); - waypoint->flags = EF_MISSION_TARGET; + waypoint->flags = EF_NO_MT_BOX+EF_MISSION_TARGET+EF_NO_HEALTH_BAR; waypoint->action = think; - waypoint->flags |= EF_NO_MT_BOX; SDL_QueryTexture(waypoint->texture, NULL, NULL, &waypoint->w, &waypoint->h); @@ -68,7 +67,7 @@ static void think(void) { self->aiActionTime = 0; - if (self->health && player != NULL && getDistance(player->x, player->y, self->x, self->y) <= 128 && isCurrentObjective() && teamMatesClose()) + if (self->health && player->alive == ALIVE_ALIVE && getDistance(player->x, player->y, self->x, self->y) <= 128 && isCurrentObjective() && teamMatesClose()) { self->health = 0; @@ -97,6 +96,13 @@ static int isCurrentObjective(void) return 0; } + if (game.currentMission->challengeData.isChallenge && game.currentMission->challengeData.clearWaypointEnemies && battle.numEnemies > 0) + { + addHudMessage(colors.cyan, _("Cannot activate waypoint - eliminate enemies first")); + self->aiActionTime = FPS; + return 0; + } + return 1; } diff --git a/src/battle/waypoints.h b/src/battle/waypoints.h index 63862c8..00cfd14 100644 --- a/src/battle/waypoints.h +++ b/src/battle/waypoints.h @@ -32,3 +32,4 @@ extern Battle battle; extern Colors colors; extern Entity *self; extern Entity *player; +extern Game game; diff --git a/src/challenges/challengeHome.c b/src/challenges/challengeHome.c index 595bf1a..67f06b9 100644 --- a/src/challenges/challengeHome.c +++ b/src/challenges/challengeHome.c @@ -29,28 +29,36 @@ static void startChallengeMission(void); static void drawMenu(void); static void resume(void); static void stats(void); +static void trophies(void); static void options(void); -static void statsOK(void); +static void ok(void); static void returnFromOptions(void); static void unlockChallenges(void); static void quit(void); static void updateChallengeMissionData(void); static char *listRestrictions(void); +static void prevPage(void); +static void nextPage(void); static SDL_Texture *background; static SDL_Texture *planetTexture; static SDL_Texture *challengeIcon; static SDL_Texture *challengeIconHighlight; -static int startIndex; static Widget *start; static PointF planet; static int show; +static int page; +static float maxPages; static char timeLimit[MAX_DESCRIPTION_LENGTH]; static char restrictions[MAX_DESCRIPTION_LENGTH]; static int hasRestrictions; +static Widget *prev; +static Widget *next; void initChallengeHome(void) { + Mission *m; + startSectionTransition(); stopMusic(); @@ -63,7 +71,7 @@ void initChallengeHome(void) awardStatsTrophies(); - saveGame(); + app.saveGame = 1; app.delegate.logic = &logic; app.delegate.draw = &draw; @@ -78,8 +86,16 @@ void initChallengeHome(void) planet.x = rand() % SCREEN_WIDTH; planet.y = rand() % SCREEN_HEIGHT; - - startIndex = 0; + + maxPages = page = 0; + + for (m = game.challengeMissionHead.next ; m != NULL ; m = m->next) + { + maxPages++; + } + + maxPages /= CHALLENGES_PER_PAGE; + maxPages = ceil(maxPages); show = SHOW_CHALLENGES; @@ -90,10 +106,20 @@ void initChallengeHome(void) getWidget("resume", "challengesMenu")->action = resume; getWidget("stats", "challengesMenu")->action = stats; + getWidget("trophies", "challengesMenu")->action = trophies; getWidget("options", "challengesMenu")->action = options; getWidget("quit", "challengesMenu")->action = quit; - getWidget("ok", "stats")->action = statsOK; + getWidget("ok", "stats")->action = ok; + getWidget("ok", "trophies")->action = ok; + + prev = getWidget("prev", "challenges"); + prev->action = prevPage; + prev->visible = 0; + + next = getWidget("next", "challenges"); + next->action = nextPage; + next->visible = 1; /* select first challenge if none chosen */ if (!game.currentMission) @@ -107,6 +133,22 @@ void initChallengeHome(void) playMusic("music/main/covert_operations.mp3"); } +static void nextPage(void) +{ + page = MIN(page + 1, maxPages - 1); + + next->visible = page < maxPages - 1; + prev->visible = 1; +} + +static void prevPage(void) +{ + page = MAX(0, page - 1); + + next->visible = 1; + prev->visible = page > 0; +} + static void unlockChallenges(void) { Mission *m; @@ -160,18 +202,25 @@ static void logic(void) break; } - doTrophies(); + doTrophyAlerts(); doWidgets(); + + doTrophies(); } static void doChallenges(void) { Mission *c; - + int i, startIndex, end; + + i = 0; + startIndex = page * CHALLENGES_PER_PAGE; + end = startIndex + CHALLENGES_PER_PAGE; + for (c = game.challengeMissionHead.next ; c != NULL ; c = c->next) { - if (app.mouse.button[SDL_BUTTON_LEFT] && collision(app.mouse.x, app.mouse.y, 3, 3, c->rect.x, c->rect.y, c->rect.w, c->rect.h)) + if (i >= startIndex && i < end && app.mouse.button[SDL_BUTTON_LEFT] && collision(app.mouse.x, app.mouse.y, 3, 3, c->rect.x, c->rect.y, c->rect.w, c->rect.h)) { if (c->available) { @@ -186,6 +235,8 @@ static void doChallenges(void) app.mouse.button[SDL_BUTTON_LEFT] = 0; } + + i++; } } @@ -233,10 +284,10 @@ static void draw(void) blit(planetTexture, planet.x, planet.y, 1); drawStars(); - - drawText(SCREEN_WIDTH / 2, 50, 30, TA_CENTER, colors.white, _("Challenges")); - - drawText(SCREEN_WIDTH / 2, 100, 24, TA_CENTER, colors.white, "%d / %d", game.completedChallenges, game.totalChallenges); + + drawText(SCREEN_WIDTH / 2, 40, 28, TA_CENTER, colors.white, _("Challenges")); + drawText(SCREEN_WIDTH / 2, 83, 16, TA_CENTER, colors.lightGrey, _("Completed : %d / %d"), game.completedChallenges, game.totalChallenges); + drawText(SCREEN_WIDTH / 2, 110, 16, TA_CENTER, colors.lightGrey, _("Page : %d / %d"), page + 1, (int)maxPages); drawChallenges(); @@ -253,6 +304,10 @@ static void draw(void) case SHOW_STATS: drawStats(); break; + + case SHOW_TROPHIES: + drawTrophies(); + break; case SHOW_OPTIONS: drawOptions(); @@ -267,20 +322,22 @@ static void drawChallenges(void) Mission *m; Challenge *c; SDL_Rect r; - int i, endIndex; + int i, start, end; r.x = 135; r.y = 165; r.w = r.h = 96; - endIndex = startIndex + MAX_ITEMS; + start = page * CHALLENGES_PER_PAGE; + end = start + CHALLENGES_PER_PAGE; + i = 0; for (m = game.challengeMissionHead.next ; m != NULL ; m = m->next) { m->rect = r; - if (i >= startIndex && i <= endIndex) + if (i >= start && i < end) { if (game.currentMission == m) { @@ -367,7 +424,7 @@ static void drawMenu(void) SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); r.w = 400; - r.h = 400; + r.h = 500; r.x = (SCREEN_WIDTH / 2) - r.w / 2; r.y = (SCREEN_HEIGHT / 2) - r.h / 2; @@ -400,7 +457,16 @@ static void stats(void) initStatsDisplay(); } -static void statsOK(void) +static void trophies(void) +{ + selectWidget("ok", "trophies"); + + show = SHOW_TROPHIES; + + initTrophiesDisplay(); +} + +static void ok(void) { selectWidget("resume", "challengesMenu"); @@ -437,6 +503,7 @@ static void handleKeyboard(void) case SHOW_OPTIONS: case SHOW_STATS: + case SHOW_TROPHIES: show = SHOW_MENU; selectWidget("resume", "challengesMenu"); break; diff --git a/src/challenges/challengeHome.h b/src/challenges/challengeHome.h index 94e752a..741e619 100644 --- a/src/challenges/challengeHome.h +++ b/src/challenges/challengeHome.h @@ -20,12 +20,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" -#define MAX_ITEMS 14 +#define CHALLENGES_PER_PAGE 14 #define SHOW_CHALLENGES 0 #define SHOW_MENU 1 #define SHOW_OPTIONS 2 #define SHOW_STATS 3 +#define SHOW_TROPHIES 4 extern void startSectionTransition(void); extern void endSectionTransition(void); @@ -43,7 +44,6 @@ extern void drawText(int x, int y, int size, int align, SDL_Color c, const char extern void drawWidgets(char *groupName); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); extern Widget *getWidget(const char *name, const char *group); -extern void saveGame(void); extern void initTitle(void); extern void initStatsDisplay(void); extern void drawOptions(void); @@ -60,10 +60,13 @@ extern void playMusic(char *filename); extern char *timeToString(long millis, int showHours); extern char *getChallengeDescription(Challenge *c); extern void clearInput(void); -extern void doTrophies(void); +extern void doTrophyAlerts(void); extern void drawTrophyAlert(void); extern void awardStatsTrophies(void); extern void awardChallengeTrophies(void); +extern void initTrophiesDisplay(void); +extern void drawTrophies(void); +extern void doTrophies(void); extern App app; extern Battle battle; diff --git a/src/challenges/challenges.c b/src/challenges/challenges.c index 2116e81..114dbf9 100644 --- a/src/challenges/challenges.c +++ b/src/challenges/challenges.c @@ -59,6 +59,7 @@ void initChallenges(void) challengeDescription[CHALLENGE_PLAYER_KILLS] = _("Take down %d enemy targets"); challengeDescription[CHALLENGE_DISABLE] = _("Disable %d or more enemy fighters"); challengeDescription[CHALLENGE_ITEMS] = _("Collect %d packages"); + challengeDescription[CHALLENGE_PLAYER_ITEMS] = _("Collect %d packages"); challengeDescription[CHALLENGE_RESCUE] = _("Rescue %d civilians"); tail = &game.challengeMissionHead; @@ -96,7 +97,9 @@ void loadChallenge(Mission *mission, cJSON *node) mission->challengeData.escapeLimit = getJSONValue(node, "escapeLimit", 0); mission->challengeData.waypointLimit = getJSONValue(node, "waypointLimit", 0); mission->challengeData.itemLimit = getJSONValue(node, "itemLimit", 0); + mission->challengeData.playerItemLimit = getJSONValue(node, "playerItemLimit", 0); mission->challengeData.rescueLimit = getJSONValue(node, "rescueLimit", 0); + mission->challengeData.disableLimit = getJSONValue(node, "disableLimit", 0); /* restrictions */ mission->challengeData.noMissiles = getJSONValue(node, "noMissiles", 0); @@ -111,6 +114,9 @@ void loadChallenge(Mission *mission, cJSON *node) /* misc */ mission->challengeData.allowPlayerDeath = getJSONValue(node, "allowPlayerDeath", 0); + mission->challengeData.clearWaypointEnemies = getJSONValue(node, "clearWaypointEnemies", 0); + mission->challengeData.eliminateThreats = getJSONValue(node, "eliminateThreats", 0); + mission->challengeData.isDeathMatch = getJSONValue(node, "isDeathMatch", 0); node = cJSON_GetObjectItem(node, "challenges"); @@ -145,7 +151,12 @@ void doChallenges(void) { if (challengeFinished()) { - passed = updateChallenges(); + passed = 0; + + if (player->health > 0 || (player->health <= 0 && game.currentMission->challengeData.allowPlayerDeath)) + { + passed = updateChallenges(); + } if (passed) { @@ -187,22 +198,22 @@ static int challengeFinished(void) return 1; } + if (game.currentMission->challengeData.playerItemLimit > 0 && battle.stats[STAT_ITEMS_COLLECTED_PLAYER] >= game.currentMission->challengeData.playerItemLimit) + { + return 1; + } + if (game.currentMission->challengeData.rescueLimit > 0 && (battle.stats[STAT_CIVILIANS_RESCUED] + battle.stats[STAT_CIVILIANS_KILLED]) >= game.currentMission->challengeData.rescueLimit) { return 1; } - if (game.currentMission->challengeData.scriptedEnd) + if (game.currentMission->challengeData.eliminateThreats && !battle.hasThreats) { return 1; } - if (player->health <= 0) - { - return 1; - } - - return 0; + return (player->health <= 0 || player->alive == ALIVE_ESCAPED || battle.scriptedEnd); } static int updateChallenges(void) @@ -257,6 +268,7 @@ static int updateChallenges(void) break; case CHALLENGE_ITEMS: + case CHALLENGE_PLAYER_ITEMS: updateItemsChallenge(c); break; } @@ -384,12 +396,31 @@ static void updateItemsChallenge(Challenge *c) { if (!c->passed) { - c->passed = battle.stats[STAT_ITEMS_COLLECTED] + battle.stats[STAT_ITEMS_COLLECTED_PLAYER] >= c->value; + if (c->type == CHALLENGE_ITEMS) + { + c->passed = battle.stats[STAT_ITEMS_COLLECTED] + battle.stats[STAT_ITEMS_COLLECTED_PLAYER] >= c->value; + } + else + { + c->passed = battle.stats[STAT_ITEMS_COLLECTED_PLAYER] >= c->value; + } } } char *getChallengeDescription(Challenge *c) { + if (c->type == CHALLENGE_TIME) + { + if (c->value <= 90) + { + return getFormattedChallengeDescription(challengeDescription[CHALLENGE_TIME], c->value); + } + else + { + return getFormattedChallengeDescription(_("Complete challenge in %s or less"), timeToString(c->value * FPS, 0)); + } + } + return getFormattedChallengeDescription(challengeDescription[c->type], c->value); } @@ -461,11 +492,13 @@ static void completeChallenge(void) game.stats[STAT_CHALLENGES_COMPLETED]++; - retreatAllies(); - - retreatEnemies(); - player->flags |= EF_IMMORTAL; + + retreatAllies(); + + retreatEnemies(); + + awardStatsTrophies(); } } @@ -477,16 +510,18 @@ static void failChallenge(void) battle.missionFinishedTimer = FPS; selectWidget("retry", "battleLost"); - retreatAllies(); - - retreatEnemies(); - player->flags |= EF_IMMORTAL; if (alreadyPassed()) { battle.status = MS_TIME_UP; } + + retreatAllies(); + + retreatEnemies(); + + awardStatsTrophies(); } } diff --git a/src/challenges/challenges.h b/src/challenges/challenges.h index dfcb995..169073c 100644 --- a/src/challenges/challenges.h +++ b/src/challenges/challenges.h @@ -24,15 +24,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern Mission *loadMissionMeta(char *filename); extern char **getFileList(char *dir, int *count); extern void selectWidget(const char *name, const char *group); -extern void retreatAllies(void); -extern void retreatEnemies(void); extern char *getTranslatedString(char *string); extern char *getLookupName(char *prefix, long num); extern char *timeToString(long millis, int showHours); extern void updateAccuracyStats(unsigned int *stats); -extern char *timeToString(long millis, int showHours); extern int getJSONValue(cJSON *node, char *name, int defValue); extern long lookup(char *name); +extern void awardStatsTrophies(void); +extern void retreatAllies(void); +extern void retreatEnemies(void); extern Dev dev; extern Battle battle; diff --git a/src/defs.h b/src/defs.h index aa0004e..17b6908 100644 --- a/src/defs.h +++ b/src/defs.h @@ -46,7 +46,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SCREEN_HEIGHT 720 #define MAX_KEYBOARD_KEYS 350 -#define MAX_MOUSE_BUTTONS 5 +#define MAX_MOUSE_BUTTONS 6 #define FPS 60 #define LOGIC_RATE (1000 / FPS) @@ -104,6 +104,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EF_NO_PLAYER_TARGET (2 << 18) #define EF_AI_IGNORE (2 << 19) #define EF_NON_SOLID (2 << 20) +#define EF_NO_HEALTH_BAR (2 << 21) +#define EF_FRIENDLY_HEALTH_BAR (2 << 22) +#define EF_NO_THREAT (2 << 23) +#define EF_DROPS_ITEMS (2 << 24) #define AIF_NONE 0 #define AIF_FOLLOWS_PLAYER (2 << 0) @@ -160,9 +164,9 @@ enum ET_FIGHTER, ET_ITEM, ET_WAYPOINT, - ET_COMPONENT, ET_COMPONENT_GUN, ET_COMPONENT_ENGINE, + ET_COMPONENT, ET_CAPITAL_SHIP, ET_JUMPGATE, ET_MINE, @@ -313,6 +317,7 @@ enum CHALLENGE_PLAYER_KILLS, CHALLENGE_DISABLE, CHALLENGE_ITEMS, + CHALLENGE_PLAYER_ITEMS, CHALLENGE_RESCUE, CHALLENGE_SURVIVE, CHALLENGE_MAX @@ -367,5 +372,6 @@ enum TROPHY_SILVER, TROPHY_GOLD, TROPHY_PLATINUM, + TROPHY_UNEARNED, TROPHY_MAX }; diff --git a/src/galaxy/galacticMap.c b/src/galaxy/galacticMap.c index dac56d4..b54cef1 100644 --- a/src/galaxy/galacticMap.c +++ b/src/galaxy/galacticMap.c @@ -38,8 +38,9 @@ static void addPulses(void); static void drawMenu(void); static void resume(void); static void stats(void); +static void trophies(void); static void options(void); -static void statsOK(void); +static void ok(void); static void quit(void); static void startMission(void); static void returnFromOptions(void); @@ -92,11 +93,13 @@ void initGalacticMap(void) awardStatsTrophies(); - saveGame(); + app.saveGame = 1; pulseTimer = 0; arrowPulse = 0; + + selectedStarSystem = NULL; /* clear the pulses */ destroyGalacticMap(); @@ -108,10 +111,12 @@ void initGalacticMap(void) getWidget("resume", "galacticMap")->action = resume; getWidget("stats", "galacticMap")->action = stats; + getWidget("trophies", "galacticMap")->action = trophies; getWidget("options", "galacticMap")->action = options; getWidget("quit", "galacticMap")->action = quit; - getWidget("ok", "stats")->action = statsOK; + getWidget("ok", "stats")->action = ok; + getWidget("ok", "trophies")->action = ok; getWidget("ok", "fallen")->action = fallenOK; @@ -174,9 +179,11 @@ static void logic(void) arrowPulse += 0.1; - doTrophies(); - doWidgets(); + + doTrophyAlerts(); + + doTrophies(); } static void doStarSystems(void) @@ -360,6 +367,10 @@ static void draw(void) case SHOW_STATS: drawStats(); break; + + case SHOW_TROPHIES: + drawTrophies(); + break; case SHOW_OPTIONS: drawOptions(); @@ -616,6 +627,7 @@ static void handleKeyboard(void) case SHOW_OPTIONS: case SHOW_STATS: + case SHOW_TROPHIES: show = SHOW_MENU; selectWidget("resume", "galacticMap"); break; @@ -659,7 +671,7 @@ static void drawMenu(void) SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE); r.w = 400; - r.h = 400; + r.h = 500; r.x = (SCREEN_WIDTH / 2) - r.w / 2; r.y = (SCREEN_HEIGHT / 2) - r.h / 2; @@ -692,7 +704,16 @@ static void stats(void) initStatsDisplay(); } -static void statsOK(void) +static void trophies(void) +{ + selectWidget("ok", "trophies"); + + show = SHOW_TROPHIES; + + initTrophiesDisplay(); +} + +static void ok(void) { selectWidget("resume", "galacticMap"); diff --git a/src/galaxy/galacticMap.h b/src/galaxy/galacticMap.h index ca97173..f4a9079 100644 --- a/src/galaxy/galacticMap.h +++ b/src/galaxy/galacticMap.h @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SHOW_MENU 2 #define SHOW_OPTIONS 3 #define SHOW_STATS 4 +#define SHOW_TROPHIES 5 extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); extern void initBattle(void); @@ -32,7 +33,6 @@ extern void loadMission(char *filename); extern SDL_Texture *getTexture(char *filename); extern void startSectionTransition(void); extern void endSectionTransition(void); -extern void saveGame(void); 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 drawCircle(int cx, int cy, int radius, int r, int g, int b, int a); @@ -60,10 +60,13 @@ extern StarSystem *getStarSystem(char *name); extern void showOKDialog(void (*callback)(void), const char *format, ...); extern char *getTranslatedString(char *string); extern void clearInput(void); -extern void doTrophies(void); +extern void doTrophyAlerts(void); extern void drawTrophyAlert(void); extern void awardCampaignTrophies(void); extern void awardStatsTrophies(void); +extern void initTrophiesDisplay(void); +extern void drawTrophies(void); +extern void doTrophies(void); extern App app; extern Colors colors; diff --git a/src/galaxy/mission.c b/src/galaxy/mission.c index ecb39c1..6ebb636 100644 --- a/src/galaxy/mission.c +++ b/src/galaxy/mission.c @@ -126,7 +126,7 @@ void loadMission(char *filename) battle.unwinnable = getJSONValue(root, "unwinnable", 0); battle.waypointAutoAdvance = getJSONValue(root, "waypointAutoAdvance", 0); - initScript(cJSON_GetObjectItem(root, "script")); + initScript(root); /* music, planet, and background loading must come last, so AUTO works properly */ @@ -201,7 +201,7 @@ void loadMission(char *filename) static char *getAutoBackground(char *filename) { - int hash; + unsigned long hash; if (!game.currentMission->challengeData.isChallenge) { @@ -217,7 +217,7 @@ static char *getAutoBackground(char *filename) static char *getAutoPlanet(char *filename) { - int hash; + unsigned long hash; if (!game.currentMission->challengeData.isChallenge) { @@ -233,7 +233,7 @@ static char *getAutoPlanet(char *filename) static char *getAutoMusic(char *filename) { - int hash; + unsigned long hash; if (!game.currentMission->challengeData.isChallenge) { @@ -241,7 +241,7 @@ static char *getAutoMusic(char *filename) } else { - hash = hashcode(filename); + hash = hashcode(game.currentMission->description); } return getMusicFilename(hash); @@ -262,6 +262,13 @@ void completeMission(void) retreatEnemies(); player->flags |= EF_IMMORTAL; + + awardStatsTrophies(); + + if (!game.currentMission->challengeData.isChallenge) + { + awardPostMissionTrophies(); + } } } @@ -276,6 +283,8 @@ void failMission(void) failIncompleteObjectives(); player->flags |= EF_IMMORTAL; + + awardStatsTrophies(); } } diff --git a/src/galaxy/mission.h b/src/galaxy/mission.h index 90ddc91..2329592 100644 --- a/src/galaxy/mission.h +++ b/src/galaxy/mission.h @@ -44,9 +44,9 @@ extern void initMissionInfo(void); extern char *getTranslatedString(char *string); extern void updateStarSystemMissions(void); extern void updateChallengeMissions(void); -extern char *getBackgroundTextureName(int n); -extern char *getPlanetTextureName(int n); -extern char *getMusicFilename(int n); +extern char *getBackgroundTextureName(unsigned long n); +extern char *getPlanetTextureName(unsigned long n); +extern char *getMusicFilename(unsigned long n); extern int getJSONValue(cJSON *node, char *name, int defValue); extern char *getJSONValueStr(cJSON *node, char *name, char *defValue); extern void addAllToQuadtree(void); @@ -60,6 +60,8 @@ extern void loadSpawners(cJSON *node); extern void loadChallenge(Mission *mission, cJSON *node); extern Entity *spawnMine(int type); extern void activateNextWaypoint(void); +extern void awardStatsTrophies(void); +extern void awardPostMissionTrophies(void); extern Battle battle; extern Dev dev; diff --git a/src/galaxy/starSystems.c b/src/galaxy/starSystems.c index 6afaeaa..ad8bc8a 100644 --- a/src/galaxy/starSystems.c +++ b/src/galaxy/starSystems.c @@ -148,7 +148,7 @@ void updateStarSystemMissions(void) } } - if (strcmp(starSystem->name, "Sol") != 0) + if (!starSystem->isSol) { game.totalMissions += starSystem->totalMissions; game.completedMissions += starSystem->completedMissions; @@ -161,7 +161,7 @@ void updateStarSystemMissions(void) for (mission = starSystem->missionHead.next ; mission != NULL ; mission = mission->next) { - mission->available = strcmp(starSystem->name, "Sol") == 0 || isMissionAvailable(mission, prev); + mission->available = starSystem->isSol || isMissionAvailable(mission, prev); if (mission->available) { @@ -171,7 +171,7 @@ void updateStarSystemMissions(void) prev = mission; } - if (strcmp(starSystem->name, "Sol") != 0) + if (!starSystem->isSol) { game.availableMissions += starSystem->availableMissions; } diff --git a/src/galaxy/stats.c b/src/game/stats.c similarity index 99% rename from src/galaxy/stats.c rename to src/game/stats.c index 847c689..9e6732d 100644 --- a/src/galaxy/stats.c +++ b/src/game/stats.c @@ -86,6 +86,7 @@ void initStatsDisplay(void) next = getWidget("next", "stats"); next->action = nextPage; + next->visible = 1; calculatePercentComplete(); @@ -102,7 +103,7 @@ static void calculatePercentComplete(void) for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) { - if (strcmp(starSystem->name, "Sol")) + if (!starSystem->isSol) { completed += starSystem->completedMissions; total += starSystem->totalMissions; diff --git a/src/galaxy/stats.h b/src/game/stats.h similarity index 100% rename from src/galaxy/stats.h rename to src/game/stats.h diff --git a/src/game/title.c b/src/game/title.c index 2cc2a11..31078c6 100644 --- a/src/game/title.c +++ b/src/game/title.c @@ -28,8 +28,9 @@ static void doFighters(void); static void drawFighters(void); static void campaign(void); static void challenges(void); +static void trophies(void); static void stats(void); -static void statsOK(void); +static void ok(void); static void options(void); static void quit(void); static void returnFromOptions(void); @@ -78,11 +79,13 @@ void initTitle(void) getWidget("campaign", "title")->action = campaign; getWidget("challenges", "title")->action = challenges; + getWidget("trophies", "title")->action = trophies; getWidget("stats", "title")->action = stats; getWidget("options", "title")->action = options; getWidget("quit", "title")->action = quit; - getWidget("ok", "stats")->action = statsOK; + getWidget("ok", "stats")->action = ok; + getWidget("ok", "trophies")->action = ok; show = SHOW_TITLE; @@ -128,6 +131,8 @@ static void logic(void) doEffects(); + doTrophies(); + doWidgets(); } @@ -190,6 +195,10 @@ static void draw(void) case SHOW_OPTIONS: drawOptions(); break; + + case SHOW_TROPHIES: + drawTrophies(); + break; } } @@ -216,16 +225,29 @@ static void handleKeyboard(void) static void campaign(void) { + destroyBattle(); + initGalacticMap(); } static void challenges(void) { + destroyBattle(); + game.currentMission = NULL; initChallengeHome(); } +static void trophies(void) +{ + selectWidget("ok", "trophies"); + + show = SHOW_TROPHIES; + + initTrophiesDisplay(); +} + static void options(void) { selectWidget("ok", "options"); @@ -244,7 +266,7 @@ static void stats(void) initStatsDisplay(); } -static void statsOK(void) +static void ok(void) { selectWidget("stats", "title"); diff --git a/src/game/title.h b/src/game/title.h index 818165e..0a1df9e 100644 --- a/src/game/title.h +++ b/src/game/title.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SHOW_TITLE 0 #define SHOW_STATS 1 #define SHOW_OPTIONS 2 +#define SHOW_TROPHIES 3 #define NUM_FIGHTERS 12 @@ -56,6 +57,9 @@ extern void selectWidget(const char *name, const char *group); extern void drawStats(void); extern void updateAllMissions(void); extern void clearInput(void); +extern void initTrophiesDisplay(void); +extern void drawTrophies(void); +extern void doTrophies(void); extern App app; extern Battle battle; diff --git a/src/game/trophies.c b/src/game/trophies.c index f7e93ac..c8884d1 100644 --- a/src/game/trophies.c +++ b/src/game/trophies.c @@ -20,15 +20,28 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "trophies.h" +static void prevPage(void); +static void nextPage(void); static void loadTrophyData(char *filename); static void resetAlert(void); static void awardCraftTrophy(void); +static void setSparkleColor(Trophy *t); +static void nextAlert(void); static Trophy *alertTrophy; static SDL_Texture *trophyIcons[TROPHY_MAX]; +static SDL_Texture *sparkle; +static SDL_Texture *alertSphere; static SDL_Rect alertRect; -static float alertDX; static int alertTimer; +static int page; +static int awarded; +static int total; +static int boxWidth; +static float sparkleAngle; +static float maxPages; +static Widget *prev; +static Widget *next; void initTrophies(void) { @@ -38,14 +51,164 @@ void initTrophies(void) trophyIcons[TROPHY_SILVER] = getTexture("gfx/trophies/silver.png"); trophyIcons[TROPHY_GOLD] = getTexture("gfx/trophies/gold.png"); trophyIcons[TROPHY_PLATINUM] = getTexture("gfx/trophies/platinum.png"); + trophyIcons[TROPHY_UNEARNED] = getTexture("gfx/trophies/unearned.png"); + sparkle = getTexture("gfx/trophies/sparkle.png"); + alertSphere = getTexture("gfx/trophies/alertSphere.png"); + + alertRect.h = 90; + alertRect.y = 10; resetAlert(); } +void initTrophiesDisplay(void) +{ + int w, h; + Trophy *t; + + boxWidth = total = awarded = 0; + + for (t = game.trophyHead.next ; t != NULL ; t = t->next) + { + total++; + + if (t->awarded) + { + awarded++; + + STRNCPY(t->awardDateStr, timeToDate(t->awardDate), MAX_NAME_LENGTH); + } + + textSize(t->description, 18, &w, &h); + + boxWidth = MAX(boxWidth, w); + } + + boxWidth += 125; + + page = 0; + + maxPages = total; + maxPages /= TROPHIES_PER_PAGE; + maxPages = ceil(maxPages); + + prev = getWidget("prev", "trophies"); + prev->action = prevPage; + prev->visible = 0; + + next = getWidget("next", "trophies"); + next->action = nextPage; + next->visible = 1; + + sparkleAngle = 0; +} + +static void nextPage(void) +{ + page = MIN(page + 1, maxPages - 1); + + next->visible = page < maxPages - 1; + prev->visible = 1; +} + +static void prevPage(void) +{ + page = MAX(0, page - 1); + + next->visible = 1; + prev->visible = page > 0; +} + +void doTrophies(void) +{ + sparkleAngle += 0.25; + if (sparkleAngle >= 360) + { + sparkleAngle = 0; + } +} + +void drawTrophies(void) +{ + Trophy *t; + SDL_Rect r; + int start, end, i, x, y; + + 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 = boxWidth; + r.h = 650; + 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, 40, 28, TA_CENTER, colors.white, _("Trophies")); + drawText(SCREEN_WIDTH / 2, 83, 16, TA_CENTER, colors.lightGrey, _("Awarded : %d / %d"), awarded, total); + drawText(SCREEN_WIDTH / 2, 110, 16, TA_CENTER, colors.lightGrey, _("Page : %d / %d"), page + 1, (int)maxPages); + + SDL_SetRenderDrawColor(app.renderer, 128, 128, 128, 255); + SDL_RenderDrawLine(app.renderer, r.x, 150, r.x + r.w, 150); + + x = r.x + 15; + y = 180; + start = page * TROPHIES_PER_PAGE; + end = start + TROPHIES_PER_PAGE; + i = 0; + + for (t = game.trophyHead.next ; t != NULL ; t = t->next) + { + if (i >= start && i < end) + { + if (t->awarded) + { + setSparkleColor(t); + blitRotated(sparkle, x + 32, y + 32, sparkleAngle); + blitRotated(sparkle, x + 32, y + 32, -sparkleAngle); + + blitScaled(trophyIcons[t->value], x, y, 64, 64); + drawText(x + 85, y - 10, 20, TA_LEFT, colors.yellow, t->title); + drawText(x + 85, y + 20, 18, TA_LEFT, colors.white, t->description); + drawText(x + 85, y + 48, 18, TA_LEFT, colors.white, t->awardDateStr); + } + else + { + blitScaled(trophyIcons[TROPHY_UNEARNED], x, y, 64, 64); + + if (!t->hidden) + { + drawText(x + 85, y - 10, 20, TA_LEFT, colors.lightGrey, t->title); + drawText(x + 85, y + 20, 18, TA_LEFT, colors.darkGrey, t->description); + drawText(x + 85, y + 48, 18, TA_LEFT, colors.darkGrey, "-"); + } + else + { + drawText(x + 85, y + 20, 20, TA_LEFT, colors.darkGrey, _("[Hidden]")); + } + } + + y += 120; + } + + i++; + } + + drawWidgets("trophies"); +} + void awardTrophy(char *id) { Trophy *t; - + int numRemaining; + + numRemaining = 0; + for (t = game.trophyHead.next ; t != NULL ; t = t->next) { if (!t->awarded && strcmp(t->id, id) == 0) @@ -53,55 +216,90 @@ void awardTrophy(char *id) t->awarded = 1; t->awardDate = time(NULL); t->notify = 1; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Awarding trophy '%s'", t->id); + + app.saveGame = 1; } + + if (!t->awarded) + { + numRemaining++; + } + } + + /* the Platinum will always be the last trophy to unlock */ + if (numRemaining == 1) + { + awardTrophy("PLATINUM"); } } -void doTrophies(void) +void doTrophyAlerts(void) { + if (!alertTrophy) + { + nextAlert(); + } + else if (alertTrophy) + { + alertRect.x = MIN(alertRect.x + 24, -1); + + if (alertRect.x > -150) + { + alertTimer--; + } + + if (alertTimer <= 0) + { + alertTrophy->notify = 0; + resetAlert(); + } + + /* do the sparkle rotation */ + doTrophies(); + } +} + +static void nextAlert(void) +{ + int w, h; Trophy *t; for (t = game.trophyHead.next ; t != NULL ; t = t->next) { if (t->notify) { - if (alertTrophy != t) + if (!alertTrophy || t->awardDate < alertTrophy->awardDate) { alertTrophy = t; - playSound(SND_TROPHY); } - - alertRect.x += alertDX; - - if (alertRect.x > -50) - { - alertDX *= 0.9; - } - - if (--alertTimer <= 0) - { - t->notify = 0; - resetAlert(); - } - - return; } } + + if (alertTrophy) + { + playSound(SND_TROPHY); + + textSize(alertTrophy->title, 30, &alertRect.w, &h); + textSize(alertTrophy->description, 20, &w, &h); + + alertRect.w = MAX(alertRect.w, w); + alertRect.w += 125; + alertRect.x = -alertRect.w; + } } static void resetAlert(void) { - alertRect.w = 300; - alertRect.h = 100; - alertRect.x = -alertRect.w; - alertRect.y = 10; - - alertDX = 3; alertTimer = FPS * 3; + alertTrophy = NULL; } void drawTrophyAlert(void) { + int x, y; + if (alertTrophy) { SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); @@ -110,17 +308,21 @@ void drawTrophyAlert(void) SDL_SetRenderDrawColor(app.renderer, 64, 64, 64, SDL_ALPHA_OPAQUE); SDL_RenderDrawRect(app.renderer, &alertRect); - drawText(alertRect.x + 5, alertRect.y + 5, 30, TA_LEFT, colors.white, alertTrophy->title); - drawText(alertRect.x + 5, alertRect.y + 45, 20, TA_LEFT, colors.white, alertTrophy->description); + drawText(alertRect.x + 15, alertRect.y + 5, 30, TA_LEFT, colors.white, alertTrophy->title); + drawText(alertRect.x + 15, alertRect.y + 45, 20, TA_LEFT, colors.white, alertTrophy->description); + + setSparkleColor(alertTrophy); + + x = alertRect.x + alertRect.w - 72; + y = alertRect.y + 20; - blit(trophyIcons[alertTrophy->value], alertRect.x + alertRect.w - 64, alertRect.y + 10, 0); + blit(alertSphere, x + 24, y + 24, 1); + blitRotated(sparkle, x + 24, y + 24, sparkleAngle); + blitRotated(sparkle, x + 24, y + 24, -sparkleAngle); + blitScaled(trophyIcons[alertTrophy->value], x, y, 48, 48); } } -void drawTrophies(void) -{ -} - Trophy *getTrophy(char *id) { Trophy *t; @@ -138,7 +340,6 @@ Trophy *getTrophy(char *id) static void loadTrophyData(char *filename) { - /* cJSON *root, *node; char *text; Trophy *t, *tail; @@ -152,29 +353,33 @@ static void loadTrophyData(char *filename) for (node = root->child ; node != NULL ; node = node->next) { - t = malloc(sizeof(Trophy)); - memset(t, 0, sizeof(Trophy)); - - STRNCPY(t->id, cJSON_GetObjectItem(node, "id")->valuestring, MAX_NAME_LENGTH); - STRNCPY(t->title, _(cJSON_GetObjectItem(node, "title")->valuestring), MAX_DESCRIPTION_LENGTH); - STRNCPY(t->description, _(cJSON_GetObjectItem(node, "description")->valuestring), MAX_DESCRIPTION_LENGTH); - t->value = lookup(cJSON_GetObjectItem(node, "value")->valuestring); - t->hidden = getJSONValue(node, "hidden", 0); - - // can't use the getJSONValue here, as it could lead to false positives - if (cJSON_GetObjectItem(node, "stat")) + if (cJSON_GetObjectItem(node, "id")->valuestring[0] != '_') { - t->stat = lookup(cJSON_GetObjectItem(node, "stat")->valuestring); - t->statValue = cJSON_GetObjectItem(node, "statValue")->valueint; - } + t = malloc(sizeof(Trophy)); + memset(t, 0, sizeof(Trophy)); - tail->next = t; - tail = t; + STRNCPY(t->id, cJSON_GetObjectItem(node, "id")->valuestring, MAX_NAME_LENGTH); + STRNCPY(t->title, _(cJSON_GetObjectItem(node, "title")->valuestring), MAX_DESCRIPTION_LENGTH); + STRNCPY(t->description, _(cJSON_GetObjectItem(node, "description")->valuestring), MAX_DESCRIPTION_LENGTH); + t->value = lookup(cJSON_GetObjectItem(node, "value")->valuestring); + t->hidden = getJSONValue(node, "hidden", 0); + + t->stat = -1; + + /* can't use the getJSONValue here, as it could lead to false positives */ + if (cJSON_GetObjectItem(node, "stat")) + { + t->stat = lookup(cJSON_GetObjectItem(node, "stat")->valuestring); + t->statValue = cJSON_GetObjectItem(node, "statValue")->valueint; + } + + tail->next = t; + tail = t; + } } cJSON_Delete(root); free(text); - */ } void awardStatsTrophies(void) @@ -183,11 +388,15 @@ void awardStatsTrophies(void) for (t = game.trophyHead.next ; t != NULL ; t = t->next) { - if (!t->awarded && game.stats[t->stat] >= t->statValue) + if (t->stat != -1 && !t->awarded && (game.stats[t->stat] + battle.stats[t->stat]) >= t->statValue) { t->awarded = 1; t->awardDate = time(NULL); t->notify = 1; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Awarding trophy '%s'", t->id); + + app.saveGame = 1; } } } @@ -196,13 +405,13 @@ void awardCampaignTrophies(void) { char trophyId[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH]; - int completed, i, len; + int i, len; StarSystem *starSystem; - - /* check % of missions completed */ - completed = getPercent(game.completedMissions, game.totalMissions); - sprintf(trophyId, "CAMPAIGN_%d", completed); - awardTrophy(trophyId); + + if (game.completedMissions) + { + awardTrophy("CAMPAIGN_1"); + } /* check if all star system missions are completed */ for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) @@ -217,6 +426,7 @@ void awardCampaignTrophies(void) { name[i] = toupper(starSystem->name[i]); } + sprintf(trophyId, "CAMPAIGN_%s", name); awardTrophy(trophyId); } @@ -228,8 +438,8 @@ void awardChallengeTrophies(void) char trophyId[MAX_NAME_LENGTH]; int completed; - /* check % of challenges completed */ - completed = getPercent(game.completedChallenges, game.totalChallenges); + /* check % of challenges completed - 25% increments*/ + completed = (getPercent(game.completedChallenges, game.totalChallenges) / 25) * 25; sprintf(trophyId, "CHALLENGE_%d", completed); awardTrophy(trophyId); } @@ -241,6 +451,19 @@ void awardPostMissionTrophies(void) if (game.currentMission->epic) { awardTrophy("EPIC"); + + if (battle.stats[STAT_PLAYER_KILLED] == 0) + { + awardTrophy("SURVIVOR"); + } + } + + /* + * Must be a non-challenge mission, a fighter-type (has guns and missiles), must not be Sol, and must not have fired any shots or missiles + */ + if (!game.currentMission->challengeData.isChallenge && player->guns[0].type && player->missiles && strcmp(game.selectedStarSystem, "Sol") && !battle.stats[STAT_SHOTS_FIRED] && !battle.stats[STAT_MISSILES_FIRED]) + { + awardTrophy("PACIFIST"); } } @@ -261,3 +484,25 @@ static void awardCraftTrophy(void) awardTrophy(trophyId); } + +static void setSparkleColor(Trophy *t) +{ + switch (t->value) + { + case TROPHY_BRONZE: + SDL_SetTextureColorMod(sparkle, 255, 128, 0); + break; + + case TROPHY_SILVER: + SDL_SetTextureColorMod(sparkle, 192, 192, 192); + break; + + case TROPHY_GOLD: + SDL_SetTextureColorMod(sparkle, 255, 255, 0); + break; + + case TROPHY_PLATINUM: + SDL_SetTextureColorMod(sparkle, 0, 128, 255); + break; + } +} diff --git a/src/game/trophies.h b/src/game/trophies.h index ef5b084..fa06a85 100644 --- a/src/game/trophies.h +++ b/src/game/trophies.h @@ -18,6 +18,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#define TROPHIES_PER_PAGE 4 + #include "../common.h" #include "../json/cJSON.h" @@ -28,11 +30,19 @@ extern char *readFile(char *filename); extern int getJSONValue(cJSON *node, char *name, int defValue); extern int getPercent(float current, float total); extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); -extern void blit(SDL_Texture *t, int x, int y, int center); +extern void blit(SDL_Texture *texture, int x, int y, int centered); +extern void blitRotated(SDL_Texture *texture, int x, int y, float angle); +extern void blitScaled(SDL_Texture *t, int x, int y, int w, int h); extern char *getTranslatedString(char *string); extern SDL_Texture *getTexture(char *filename); extern void playSound(int id); +extern Widget *getWidget(const char *name, const char *group); +extern void drawWidgets(char *groupName); +extern char *timeToDate(long millis); +extern void textSize(char *text, int size, int *w, int *h); extern App app; +extern Battle battle; extern Colors colors; +extern Entity *player; extern Game game; diff --git a/src/main.c b/src/main.c index 63039e4..c3ce317 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "main.h" -static void handleArguments(int argc, char *argv[]); +static void handleMissionArgs(int argc, char *argv[]); +static void handleLoggingArgs(int argc, char *argv[]); int main(int argc, char *argv[]) { @@ -29,11 +30,11 @@ int main(int argc, char *argv[]) long expireTextTimer; SDL_Event event; - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN); - memset(&app, 0, sizeof(App)); memset(&dev, 0, sizeof(Dev)); + handleLoggingArgs(argc, argv); + atexit(cleanup); srand(time(NULL)); @@ -48,7 +49,12 @@ int main(int argc, char *argv[]) createScreenshotFolder(); - handleArguments(argc, argv); + if (fileExists(getSaveFilePath(SAVE_FILENAME))) + { + loadGame(); + } + + handleMissionArgs(argc, argv); dev.fps = frames = td = 0; then = SDL_GetTicks(); @@ -103,8 +109,16 @@ int main(int argc, char *argv[]) while (td >= LOGIC_RATE) { app.delegate.logic(); + td -= LOGIC_RATE; + if (app.resetTimeDelta) + { + td = 0; + then = SDL_GetTicks(); + app.resetTimeDelta = 0; + } + game.stats[STAT_TIME]++; } @@ -149,6 +163,13 @@ int main(int argc, char *argv[]) expireTextTimer = SDL_GetTicks() + (1000 * 10); } + /* trophy unlocks might cause the game to save several times in one frame */ + if (app.saveGame) + { + saveGame(); + app.saveGame = 0; + } + /* always zero the mouse motion */ app.mouse.dx = app.mouse.dy = 0; @@ -158,7 +179,34 @@ int main(int argc, char *argv[]) return 0; } -static void handleArguments(int argc, char *argv[]) +static void handleLoggingArgs(int argc, char *argv[]) +{ + int i; + + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + for (i = 1 ; i < argc ; i++) + { + if (strcmp(argv[i], "-debug") == 0) + { + dev.debug = 1; + + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); + } + + if (strcmp(argv[i], "-warn") == 0) + { + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN); + } + + if (strcmp(argv[i], "-info") == 0) + { + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + } + } +} + +static void handleMissionArgs(int argc, char *argv[]) { int i; int testingMission = 0; @@ -172,29 +220,10 @@ static void handleArguments(int argc, char *argv[]) testingMission = 1; } - else - { - if (strcmp(argv[i], "-debug") == 0) - { - dev.debug = 1; - - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); - } - - if (strcmp(argv[i], "-info") == 0) - { - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); - } - } } if (!testingMission) { - if (fileExists(getSaveFilePath(SAVE_FILENAME))) - { - loadGame(); - } - initTitle(); } } diff --git a/src/main.h b/src/main.h index a792f1b..727f219 100644 --- a/src/main.h +++ b/src/main.h @@ -45,12 +45,12 @@ extern int fileExists(char *filename); extern char *getSaveFilePath(char *filename); extern void init18N(int argc, char *argv[]); extern void initLookups(void); -extern void initGame(void); extern void doKeyDown(SDL_KeyboardEvent *event); extern void doKeyUp(SDL_KeyboardEvent *event); extern void createScreenshotFolder(void); extern int isControl(int type); extern void clearControl(int type); +extern void saveGame(void); App app; Colors colors; diff --git a/src/structs.h b/src/structs.h index ca87ab3..c3fa52d 100644 --- a/src/structs.h +++ b/src/structs.h @@ -253,15 +253,19 @@ typedef struct { int killLimit; int lossLimit; int itemLimit; + int playerItemLimit; int escapeLimit; int waypointLimit; int rescueLimit; + int disableLimit; int noMissiles; int noBoost; int noECM; int noGuns; - int scriptedEnd; int allowPlayerDeath; + int clearWaypointEnemies; + int eliminateThreats; + int isDeathMatch; Challenge *challenges[MAX_CHALLENGES]; } ChallengeData; @@ -342,8 +346,11 @@ typedef struct { int radarRange; int numPlayerGuns; int numObjectivesComplete, numObjectivesTotal, numConditions; + int scriptedEnd; + int hasThreats; Entity *missionTarget; Entity *jumpgate; + Entity *messageSpeaker; SDL_Texture *background, *planetTexture; PointF planet; int planetWidth, planetHeight; @@ -370,6 +377,7 @@ struct Trophy { char id[MAX_NAME_LENGTH]; char title[MAX_DESCRIPTION_LENGTH]; char description[MAX_DESCRIPTION_LENGTH]; + char awardDateStr[MAX_NAME_LENGTH]; int value; int hidden; int stat; @@ -380,6 +388,13 @@ struct Trophy { Trophy *next; }; +typedef struct { + int friendlyFire; + int autoSwitchPlayerTarget; + int missileReTarget; + int healthBars; +} Gameplay; + typedef struct { StarSystem starSystemHead; Mission challengeMissionHead; @@ -441,7 +456,9 @@ typedef struct { } Mouse; typedef struct { + int resetTimeDelta; char saveDir[MAX_FILENAME_LENGTH]; + int saveGame; int winWidth; int winHeight; float scaleX; @@ -449,6 +466,7 @@ typedef struct { int fullscreen; int musicVolume; int soundVolume; + Gameplay gameplay; Mouse mouse; int keyboard[MAX_KEYBOARD_KEYS]; SDL_Texture *backBuffer; diff --git a/src/system/init.c b/src/system/init.c index 4845b4c..347ce4e 100644 --- a/src/system/init.c +++ b/src/system/init.c @@ -155,7 +155,7 @@ void initGameSystem(void) for (i = 0 ; i < numInitFuns ; i++) { - showLoadingStep(i, numInitFuns); + showLoadingStep(i + 1, numInitFuns); initFuncs[i](); } @@ -216,12 +216,15 @@ static void loadConfig(void) { loadConfigFile(configFilename); } + + /* so that the player doesn't get confused if this is a new game */ + saveConfig(); } static void loadConfigFile(char *filename) { int i; - cJSON *root, *controlsJSON, *node; + cJSON *root, *controlsJSON, *node, *gameplayJSON; char *text; text = readFile(filename); @@ -257,19 +260,25 @@ static void loadConfigFile(char *filename) node = node->next; } } + + gameplayJSON = cJSON_GetObjectItem(root, "gameplay"); + if (gameplayJSON) + { + app.gameplay.friendlyFire = cJSON_GetObjectItem(gameplayJSON, "friendlyFire")->valueint; + app.gameplay.autoSwitchPlayerTarget = cJSON_GetObjectItem(gameplayJSON, "autoSwitchPlayerTarget")->valueint; + app.gameplay.missileReTarget = cJSON_GetObjectItem(gameplayJSON, "missileReTarget")->valueint; + app.gameplay.healthBars = cJSON_GetObjectItem(gameplayJSON, "healthBars")->valueint; + } cJSON_Delete(root); free(text); - - /* so that the player doesn't get confused if this is a new game */ - saveConfig(); } void saveConfig(void) { int i; char *out, *configFilename; - cJSON *root, *controlsJSON, *keysJSON, *mouseJSON; + cJSON *root, *controlsJSON, *keysJSON, *mouseJSON, *gameplayJSON; configFilename = getSaveFilePath(CONFIG_FILENAME); @@ -297,8 +306,14 @@ void saveConfig(void) controlsJSON = cJSON_CreateObject(); cJSON_AddItemToObject(controlsJSON, "keys", keysJSON); cJSON_AddItemToObject(controlsJSON, "mouse", mouseJSON); - cJSON_AddItemToObject(root, "controls", controlsJSON); + + gameplayJSON = cJSON_CreateObject(); + cJSON_AddNumberToObject(gameplayJSON, "friendlyFire", app.gameplay.friendlyFire); + cJSON_AddNumberToObject(gameplayJSON, "autoSwitchPlayerTarget", app.gameplay.autoSwitchPlayerTarget); + cJSON_AddNumberToObject(gameplayJSON, "missileReTarget", app.gameplay.missileReTarget); + cJSON_AddNumberToObject(gameplayJSON, "healthBars", app.gameplay.healthBars); + cJSON_AddItemToObject(root, "gameplay", gameplayJSON); out = cJSON_Print(root); diff --git a/src/system/init.h b/src/system/init.h index 97f9767..baf6729 100644 --- a/src/system/init.h +++ b/src/system/init.h @@ -74,4 +74,3 @@ extern void initTrophies(void); extern App app; extern Colors colors; -extern Game game; diff --git a/src/system/load.c b/src/system/load.c index 1e527e8..24e07be 100644 --- a/src/system/load.c +++ b/src/system/load.c @@ -24,6 +24,7 @@ static void loadStats(cJSON *statsJSON); static void loadStarSystems(cJSON *starSystemsJSON); static void loadMissions(cJSON *missionsCJSON); static void loadChallenges(cJSON *challengesCJSON); +static void loadTrophies(cJSON *trophiesJSON); void loadGame(void) { @@ -42,6 +43,8 @@ void loadGame(void) loadChallenges(cJSON_GetObjectItem(gameJSON, "challenges")); loadStats(cJSON_GetObjectItem(gameJSON, "stats")); + + loadTrophies(cJSON_GetObjectItem(gameJSON, "trophies")); cJSON_Delete(root); free(text); @@ -70,7 +73,11 @@ static void loadMissions(cJSON *missionsJSON) for (missionJSON = missionsJSON->child ; missionJSON != NULL ; missionJSON = missionJSON->next) { mission = getMission(cJSON_GetObjectItem(missionJSON, "filename")->valuestring); - mission->completed = cJSON_GetObjectItem(missionJSON, "completed")->valueint; + + if (mission) + { + mission->completed = cJSON_GetObjectItem(missionJSON, "completed")->valueint; + } } } @@ -118,3 +125,23 @@ static void loadStats(cJSON *statsJSON) } } } + +static void loadTrophies(cJSON *trophiesJSON) +{ + Trophy *t; + cJSON *trophyJSON; + + if (trophiesJSON) + { + for (trophyJSON = trophiesJSON->child ; trophyJSON != NULL ; trophyJSON = trophyJSON->next) + { + t = getTrophy(cJSON_GetObjectItem(trophyJSON, "id")->valuestring); + + if (t) + { + t->awardDate = cJSON_GetObjectItem(trophyJSON, "awardDate")->valueint; + t->awarded = 1; + } + } + } +} diff --git a/src/system/load.h b/src/system/load.h index b0543fe..262578a 100644 --- a/src/system/load.h +++ b/src/system/load.h @@ -29,5 +29,6 @@ extern int lookup(char *lookup); extern char *getSaveFilePath(char *filename); extern char *getLookupName(char *prefix, long num); extern StarSystem *getStarSystem(char *name); +extern Trophy *getTrophy(char *id); extern Game game; diff --git a/src/system/lookup.c b/src/system/lookup.c index acb27cf..da8210b 100644 --- a/src/system/lookup.c +++ b/src/system/lookup.c @@ -65,6 +65,11 @@ void initLookups(void) addLookup("EF_AI_LEADER", EF_AI_LEADER); addLookup("EF_NO_KILL_INC", EF_NO_KILL_INC); addLookup("EF_NO_MT_BOX", EF_NO_MT_BOX); + addLookup("EF_FRIENDLY_HEALTH_BAR", EF_FRIENDLY_HEALTH_BAR); + addLookup("EF_AI_IGNORE", EF_AI_IGNORE); + addLookup("EF_NO_THREAT", EF_NO_THREAT); + addLookup("EF_NO_HEALTH_BAR", EF_NO_HEALTH_BAR); + addLookup("EF_DROPS_ITEMS", EF_DROPS_ITEMS); addLookup("AIF_NONE", AIF_NONE); addLookup("AIF_MOVES_TO_PLAYER", AIF_MOVES_TO_PLAYER); @@ -144,6 +149,7 @@ void initLookups(void) addLookup("CHALLENGE_PLAYER_KILLS", CHALLENGE_PLAYER_KILLS); addLookup("CHALLENGE_DISABLE", CHALLENGE_DISABLE); addLookup("CHALLENGE_ITEMS", CHALLENGE_ITEMS); + addLookup("CHALLENGE_PLAYER_ITEMS", CHALLENGE_PLAYER_ITEMS); addLookup("CHALLENGE_RESCUE", CHALLENGE_RESCUE); addLookup("STAT_PERCENT_COMPLETE", STAT_PERCENT_COMPLETE); diff --git a/src/system/resources.c b/src/system/resources.c index ba88d56..34f6b63 100644 --- a/src/system/resources.c +++ b/src/system/resources.c @@ -81,17 +81,17 @@ void initResources(void) free(filenames); } -char *getBackgroundTextureName(int i) +char *getBackgroundTextureName(unsigned long i) { return backgrounds[i % numBackgrounds]; } -char *getPlanetTextureName(int i) +char *getPlanetTextureName(unsigned long i) { return planets[i % numPlanets]; } -char *getMusicFilename(int i) +char *getMusicFilename(unsigned long i) { return musicFiles[i % numMusicFiles]; } diff --git a/src/system/save.c b/src/system/save.c index 3b568d2..83ce48b 100644 --- a/src/system/save.c +++ b/src/system/save.c @@ -24,6 +24,7 @@ static void saveStarSystems(cJSON *gameJSON); static void saveChallenges(cJSON *gameJSON); static cJSON *getMissionsJSON(StarSystem *starSystem); static void saveStats(cJSON *gameJSON); +static void saveTrophies(cJSON *gameJSON); void saveGame(void) { @@ -43,6 +44,8 @@ void saveGame(void) saveChallenges(gameJSON); saveStats(gameJSON); + + saveTrophies(gameJSON); out = cJSON_Print(root); @@ -61,13 +64,16 @@ static void saveStarSystems(cJSON *gameJSON) for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next) { - starSystemJSON = cJSON_CreateObject(); + if (starSystem->totalMissions > 0) + { + starSystemJSON = cJSON_CreateObject(); - cJSON_AddStringToObject(starSystemJSON, "name", starSystem->name); - cJSON_AddStringToObject(starSystemJSON, "side", getLookupName("SIDE_", starSystem->side)); - cJSON_AddItemToObject(starSystemJSON, "missions", getMissionsJSON(starSystem)); + cJSON_AddStringToObject(starSystemJSON, "name", starSystem->name); + cJSON_AddStringToObject(starSystemJSON, "side", getLookupName("SIDE_", starSystem->side)); + cJSON_AddItemToObject(starSystemJSON, "missions", getMissionsJSON(starSystem)); - cJSON_AddItemToArray(starSystemsJSON, starSystemJSON); + cJSON_AddItemToArray(starSystemsJSON, starSystemJSON); + } } cJSON_AddItemToObject(gameJSON, "starSystems", starSystemsJSON); @@ -146,3 +152,26 @@ static void saveStats(cJSON *gameJSON) cJSON_AddItemToObject(gameJSON, "stats", stats); } + +static void saveTrophies(cJSON *gameJSON) +{ + Trophy *t; + cJSON *trophiesJSON, *trophyJSON; + + trophiesJSON = cJSON_CreateArray(); + + for (t = game.trophyHead.next ; t != NULL ; t = t->next) + { + if (t->awarded) + { + trophyJSON = cJSON_CreateObject(); + + cJSON_AddStringToObject(trophyJSON, "id", t->id); + cJSON_AddNumberToObject(trophyJSON, "awardDate", t->awardDate); + + cJSON_AddItemToArray(trophiesJSON, trophyJSON); + } + } + + cJSON_AddItemToObject(gameJSON, "trophies", trophiesJSON); +} diff --git a/src/system/sound.c b/src/system/sound.c index 429f628..13e0cfd 100644 --- a/src/system/sound.c +++ b/src/system/sound.c @@ -67,7 +67,7 @@ void playBattleSound(int id, int x, int y) int channel; float vol; - if (player != NULL) + if (player->alive == ALIVE_ALIVE) { lastPlayerX = player->x; lastPlayerY = player->y; diff --git a/src/system/transition.c b/src/system/transition.c index 06991b6..c9d74b2 100644 --- a/src/system/transition.c +++ b/src/system/transition.c @@ -43,4 +43,6 @@ void endSectionTransition(void) { SDL_Delay(elasped); } + + app.resetTimeDelta = 1; } diff --git a/src/system/transition.h b/src/system/transition.h index c6fd9b3..9b79f94 100644 --- a/src/system/transition.h +++ b/src/system/transition.h @@ -24,3 +24,5 @@ extern void prepareScene(void); extern void presentScene(void); extern void clearInput(void); extern void expireTexts(int all); + +extern App app; diff --git a/src/system/util.c b/src/system/util.c index 2d9f409..948570e 100644 --- a/src/system/util.c +++ b/src/system/util.c @@ -128,6 +128,19 @@ char *timeToString(long millis, int showHours) return TIME; } +char *timeToDate(long millis) +{ + static char DATE[MAX_NAME_LENGTH]; + + struct tm *timeinfo; + + timeinfo = localtime(&millis); + + strftime(DATE, MAX_NAME_LENGTH, "%d %b %Y, %I:%M%p", timeinfo); + + return DATE; +} + char *getJSONValueStr(cJSON *node, char *name, char *defValue) { cJSON *child; diff --git a/src/system/util.h b/src/system/util.h index 667646c..1f43fb9 100644 --- a/src/system/util.h +++ b/src/system/util.h @@ -20,3 +20,4 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" #include "../json/cJSON.h" +#include "time.h" diff --git a/src/system/widgets.h b/src/system/widgets.h index e78cd21..1c1f502 100644 --- a/src/system/widgets.h +++ b/src/system/widgets.h @@ -25,7 +25,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); extern char *readFile(char *filename); extern long lookup(char *name); -extern float mod(float n, float x); extern void blit(SDL_Texture *texture, int x, int y, int centered); extern SDL_Texture *getTexture(char *filename); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); diff --git a/stats.md b/stats.md deleted file mode 100644 index d1ce28a..0000000 --- a/stats.md +++ /dev/null @@ -1,15 +0,0 @@ -# Statistics - -* Lines of code: 16847 -* Size of source: 523K -* Size of data: 478K -* Size of graphics: 3.2M -* Size of sound: 638K -* Size of music: 53M - -* Number of missions: 56 -* Number of challenges: 42 -* Number of spacecraft: 46 -* Number of trophies: 41 - -* Translatable strings: 620 diff --git a/tools/tidyHeaders.sh b/tools/tidyHeaders.sh index 08e9114..9d2dc53 100755 --- a/tools/tidyHeaders.sh +++ b/tools/tidyHeaders.sh @@ -30,6 +30,7 @@ function cleanHeader($headerFile) $func_pattern = "/(([A-Z0-9_]+)\\()/i"; $struct_pattern = "/([A-Z]+);/i"; + $define_pattern = "/#define ([A-Z]+)/i"; $bodyFile = $headerFile; $bodyFile[strlen($bodyFile) - 1] = 'c'; @@ -38,21 +39,37 @@ function cleanHeader($headerFile) { $header = file($headerFile); $body = file_get_contents($bodyFile); + $lines = []; $i = 0; $hasChanges = false; foreach ($header as $line) { - if (strstr($line, "extern") !== FALSE && strstr($line, "getTranslatedString") === FALSE) + if (preg_match("/extern|define/", $line) && strstr($line, "getTranslatedString") === FALSE) { preg_match($func_pattern, $line, $matches); - + if (count($matches) == 3) { $extern = $matches[2]; - - if (strstr($body, $extern) === FALSE) + + if (!preg_match_all("/\b[(]?${extern}[\\(;,)\\n]/", $body)) + { + if (!$hasChanges) + { + echo "$headerFile\n"; + $hasChanges = true; + } + echo "\t- $line"; + unset($header[$i]); + } + + if (!in_array($line, $lines)) + { + $lines[] = $line; + } + else { if (!$hasChanges) { @@ -70,6 +87,43 @@ function cleanHeader($headerFile) { $extern = $matches[1]; + $externs[] = $extern; + + if (!preg_match_all("/\b${extern}[\\.\\-\\)]/", $body)) + { + if (!$hasChanges) + { + echo "$headerFile\n"; + $hasChanges = true; + } + echo "\t- $line"; + unset($header[$i]); + } + + if (!in_array($line, $lines)) + { + $lines[] = $line; + } + else + { + if (!$hasChanges) + { + echo "$headerFile\n"; + $hasChanges = true; + } + echo "\t- $line"; + unset($header[$i]); + } + } + + preg_match($define_pattern, $line, $matches); + + if (count($matches) == 2) + { + $extern = $matches[1]; + + $externs[] = $extern; + if (strstr($body, "$extern") === FALSE) { if (!$hasChanges) @@ -80,6 +134,21 @@ function cleanHeader($headerFile) echo "\t- $line"; unset($header[$i]); } + + if (!in_array($line, $lines)) + { + $lines[] = $line; + } + else + { + if (!$hasChanges) + { + echo "$headerFile\n"; + $hasChanges = true; + } + echo "\t- $line"; + unset($header[$i]); + } } } @@ -95,17 +164,20 @@ function cleanHeader($headerFile) function recurseDir($dir) { - $files = array_diff(scandir($dir), array('..', '.')); - - foreach ($files as $file) + if ($dir != "../src/json") { - if (is_dir("$dir/$file")) + $files = array_diff(scandir($dir), array('..', '.')); + + foreach ($files as $file) { - recurseDir("$dir/$file"); - } - else if (strstr($file, ".h") !== FALSE) - { - cleanHeader("$dir/$file"); + if (is_dir("$dir/$file")) + { + recurseDir("$dir/$file"); + } + else if (strstr($file, ".h") !== FALSE) + { + cleanHeader("$dir/$file"); + } } } }