Compare commits

...

33 Commits

Author SHA1 Message Date
George Sokianos c9462d0617 Some more changes and prepared the release files 2022-08-23 00:04:28 +01:00
George Sokianos 52e45ff1cb Fixed the screenshot save path 2022-08-22 22:13:12 +01:00
George Sokianos 29dd25a23a Cleaned up the effects reduction code and moved it to a separate method 2022-08-22 22:11:45 +01:00
George Sokianos 0ab9bfac9d Fixed the controls crash 2022-08-22 19:40:53 +01:00
George Sokianos 3b3fe085fa Added effects reduction option for game speed up 2022-08-21 23:49:36 +01:00
George Sokianos 69b714860b Fixes and setup to compile under AmigaOS 4 2022-08-21 23:47:37 +01:00
Steve 82af33d075 Windows make file update. 2019-11-22 07:30:03 +00:00
Steve 3329d1375a Trim all whitespace. 2019-11-07 08:13:57 +00:00
Steve 98274ffa34 Slightly modified UTF-8 handling. Based on http://man7.org/linux/man-pages/man7/utf-8.7.html. 2019-11-06 19:18:03 +00:00
Steve cbd7425a31 Stale bot config. 2019-10-23 18:43:30 +01:00
Steve ca36f8163b Typo fix. 2019-10-23 18:43:19 +01:00
Steve f7d1d3dadb Compile fixes. 2019-10-22 18:48:11 +01:00
Steve 85507506f9 Updated credits. 2019-10-22 18:47:55 +01:00
Steve 0e1b412bd4 README update. 2019-10-22 18:47:08 +01:00
Stephen J Sweeney 19ab4c72be
Merge pull request #51 from oriolhub/patch-1
Update ca.po
2019-10-22 17:55:47 +01:00
oriolhub 6ec06b3c5e
Update ca.po 2019-10-22 13:02:23 +02:00
Stephen J Sweeney 89190cde92
Update README.md 2019-08-17 17:27:44 +01:00
Steve 6430217bcb Decreased file size of atlas image. 2019-04-08 11:37:22 +01:00
Steve 5f6c872075 Bit of tidying. 2019-04-08 11:35:44 +01:00
Steve eb5fbb8824 Use all available threads to compile. 2019-04-08 11:34:06 +01:00
Steve 02bea0492a Only award Revenge trophy if epic battle. 2019-04-08 11:33:52 +01:00
Steve c453074778 Slightly increase remainder resolution. 2019-04-08 11:33:38 +01:00
Steve 43b9e9ff32 Readme format update. 2019-01-16 08:30:16 +00:00
Steve 44c7f6c372 New close button. 2019-01-16 08:30:08 +00:00
Steve 4887fd2a6c Don't retain highlighted widget. 2019-01-16 08:30:01 +00:00
Steve d8aa7f70f2 Updated copyright. 2019-01-01 16:14:11 +00:00
Steve db10231eeb Fixed credits memory leak. 2019-01-01 16:10:28 +00:00
Steve d4f4fdb0c8 Darken screen correctly on challenge home. 2018-12-31 16:46:44 +00:00
Steve 5f15797043 Move planet slightly faster than background. 2018-12-31 16:46:13 +00:00
Steve 8dfaefd992 Removed redundant color parameters. 2018-12-23 15:52:38 +00:00
Steve 38ca6c24fe Use pre-calculated UI offset values. 2018-12-22 15:07:55 +00:00
Steve cc4829a3a6 Draw dark overlay on main screen. 2018-12-21 07:27:47 +00:00
Steve 0ef2cda22e v1.5.1 2018-12-21 07:27:28 +00:00
141 changed files with 3644 additions and 4252 deletions

16
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,16 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 335
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:
- help+wanted
# Label to use when marking an issue as stale
staleLabel: invalid
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: true

View File

@ -1,5 +1,10 @@
Changelog
1.5.1
* Updated Catalan translation (thanks, oriolhub)
* Misc bug and compile fixes.
1.5
* Game now renders at chosen resolution instead of scaling up from 1280 x 720
@ -37,7 +42,7 @@ Changelog
* Epic missions now have limited "lives". A player can only be killed a certain number of times before they automatically fail the mission. This is to discourage reckless play.
1.01
* Corrected "Nation of Tzac" to "Kingdom of Tzac" in a few cases
* Fixed broken REVISION makefile macro when git is not available
@ -69,7 +74,7 @@ Changelog
* Campaign tweaks and bugs fixes
0.95
* AI fixes
* Campaign tweaks and bugs fixes
* Reset entity owner when detaching tow rope
@ -87,11 +92,11 @@ Changelog
* Lowered difficulty of some missions
0.92
* Campaign tweaks and bug fixes
0.91
* New music track by Vehicle
* Added effects when bullets hit targets
* Updated Mantis sprite
@ -101,7 +106,7 @@ Changelog
* Misc. tweaks and fixes
0.9
* Added final campaign missions
* Added final challenges
* Enabled all trophies
@ -151,7 +156,7 @@ Changelog
* Misc. AI, mission, and bug fixes
0.4
* Added mouse + keyboard controls (replaces keyboard-only method)
* Added new craft: Kingfisher, Mantis, Rook, Hammerhead, Khepri, Scarab, Thunderhead.
* Added laser cannon - highly effective against shields

50
README-OS4.md Normal file
View File

@ -0,0 +1,50 @@
# The Battle for the Solar System : The Pandoran War
This is the port of the "The Battle for the Solar System : The Pandoran War"
v1.50.1 for the AmigaOS 4.
The Pandoran War is a 2D mission-based space shooter based on the BATTLE FOR
THE SOLAR SYSTEM space opera and set between books two and three: THE THIRD
SIDE and THE ATTTRIBUTE OF THE STRONG. The game features many missions,
with many different objectives and craft.
It requires a fast system to play the game as fast as possible, and a
graphics card that supports either opengl/opengles2 with SDL2.
It is tested and runs well on X5000/40 with a RadeonRX 550.
This archive does not contain any data files. In order to play the game, you
need to download the data separately. From the following website download
the "tbftss-1.5.1.linux-x86_64.tar.gz" file.
https://www.battleforthesolarsystem.com/games/pw/#downloads
To install it, extract the data file anywhere at you hard disk
and copy over all the files from this archive. A requester will show up
to replace some files, which you need to confirm for all of them.
If you like the game and would like to support its developer, you can go and
buy it at:
https://parallelrealities.itch.io/tbftss-the-pandoran-war
### How to make it faster
The game should run in 60fps but on my test system I get around 30fps with all
the effects enabled. That's why I introduced an option at the Options screen,
named "Effects Reduction" with values from 0 to 3. With 0 you have full effects
everywhere, and with 3 you have less effects shown. That increases a lot the
speed, but you might still see slowdowns in situations where there is a lot of
action on the screen.
It is recommended to open the SDL2 prefs and set the Driver to opengl/opengl2
depending your gfx card and the drivers you have installed.
On my system "Batching Mode: enabled" leads to some crashes. I recommend you
to set this to default. But feel free to experiment with it, in case it
works better for you.
I'd love to hear how it works on your system.
### Changelog
1.50.1r1 (2022-08-22)
* First release

View File

@ -2,9 +2,9 @@
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/tree/develop) is where all the dev work happens. Stable(ish) releases will go in to master (https://github.com/stephenjsweeney/tbftss/tree/master).
![Alt text](dev/screenshots/v0.6-06.png?raw=true "Screenshot")
You can support development of this game by purchasing one of the books in the trilogy: www.battleforthesolarsystem.com/purchase/
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).
Website: www.battleforthesolarsystem.com
Email: stephenjsweeney@battleforthesolarsystem.com
@ -17,22 +17,26 @@ Screenshots from various versions can be found here: https://github.com/stephenj
### GRAPHICS
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
* 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
<img src="gfx/by-nc-sa.png?raw=true" alt="CC BY-NC-SA logo" width="125">
### DATA FILES
data/fonts/Roboto-Medium.ttf, by Christian Robertson. Licensed under the Apache License, version 2.0
data/fonts/Khosrau.ttf, by Fereydoun Rostam. Free for non-commercial use (http://www.dafont.com/khosrau.font)
* data/fonts/Roboto-Medium.ttf, by Christian Robertson. Licensed under the Apache License, version 2.0
* data/fonts/Khosrau.ttf, by Fereydoun Rostam. Free for non-commercial use (http://www.dafont.com/khosrau.font)
All other data files are CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J Sweeney | www.battleforthesolarsystem.com
<img src="gfx/by-nc-sa.png?raw=true" alt="CC BY-NC-SA logo" width="125">
### SOUND
* 000000_large_explosion.ogg - created by combining

View File

@ -1,15 +1,16 @@
VERSION = 1.5
REVISION = 0
REVISION = 1
LOCALE_MO = $(patsubst %.po,%.mo,$(wildcard locale/*.po))
OUT = bin
SEARCHPATH += src/ src/battle
SEARCHPATH += src/challenges
SEARCHPATH += src/game
SEARCHPATH += src/galaxy
SEARCHPATH += src/json
SEARCHPATH += src/system
SEARCHPATH += src
SEARCHPATH += src/battle
SEARCHPATH += src/challenges
SEARCHPATH += src/game
SEARCHPATH += src/galaxy
SEARCHPATH += src/json
SEARCHPATH += src/system
SEARCHPATH += src/test
vpath %.c $(SEARCHPATH)
@ -49,8 +50,11 @@ $(OUT)/%.o: %.c %.h $(DEPS)
$(CC) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
%.mo: %.po
ifneq ($(shell uname), AmigaOS)
msgfmt -c -o $@ $<
endif
# cleaning everything that can be automatically recreated with "make".
clean:
$(RM) $(OBJS) $(PROG) $(LOCALE_MO)

View File

@ -1,6 +1,7 @@
{
"winWidth" : 1280,
"winHeight" : 720,
"effects" : 0,
"fullscreen" : 0,
"musicVolume" : 8,
"soundVolume" : 10,
@ -41,3 +42,4 @@
"healthBars" : 1
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +1,86 @@
[
"0 30 MAIN PROGRAMMING",
"0 24 Stephen J Sweeney",
"75 30 ADDITIONAL CODE",
"0 24 Richard Sweeney",
"75 30 GRAPHICS",
"30 24 Main Graphics",
"0 24 Stephen J Sweeney (CC BY-NC-SA 3.0)",
"30 24 gfx/planets/earth.png",
"0 24 Derived from the the Blue Marble NASA photograph",
"0 24 visibleearth.nasa.gov/view.php?id=57723",
"30 24 gfx/trophies/bronze.png",
"0 24 Dervied from Trophy icon, by Lorc (CC BY 3.0)",
"0 24 game-icons.net/lorc/originals/trophy.html",
"30 24 gfx/trophies/gold.png",
"0 24 Dervied from Trophy icon, by Lorc (CC BY 3.0)",
"0 24 game-icons.net/lorc/originals/trophy.html",
"30 24 gfx/trophies/platinum.png",
"0 24 Dervied from Trophy icon, by Lorc (CC BY 3.0)",
"0 24 game-icons.net/lorc/originals/trophy.html",
"30 24 gfx/trophies/silver.png",
"0 24 Dervied from Trophy icon, by Lorc (CC BY 3.0)",
"0 24 game-icons.net/lorc/originals/trophy.html",
"30 24 gfx/trophies/unearned.png",
"0 24 Dervied from Trophy icon, by Lorc (CC BY 3.0)",
"0 24 game-icons.net/lorc/originals/trophy.html",
"75 30 TRANSLATIONS",
"30 24 Lumidify Productions (German)",
"0 24 ekrempel (German)",
"0 24 oriolhub (Catalan)",
"75 30 DEVELOPMENT SOFTWARE",
"75 28 Simple DirectMedia Layer",
"0 24 Created by Sam Lantinga",
"0 24 Developed by the SDL Community",
"75 28 GCC",
"0 24 GNU Compiler Collection",
"0 24 Developed by the GNU Project",
"75 28 The GIMP",
"0 24 GNU Image Manipulation Program",
"0 24 Created by Spencer Kimball and Peter Mattis",
"0 24 Developed by The GIMP Development Team",
"75 28 Kate",
"0 24 KDE Advanced Text Editor",
"0 24 Developed by the KDE Team",
"75 28 Audacity",
"0 24 Created by Dominic Mazzoni and Roger Dannenberg",
"0 24 Developed by The Audacity Team",
"75 30 FONTS",
"30 24 data/fonts/Roboto-Medium.ttf",
"0 24 by Christian Robertson",
"0 24 Licensed under the Apache License, version 2.0",
"30 24 data/fonts/Khosrau.ttf",
"0 24 by Fereydoun Rostam.",
"0 24 www.dafont.com/khosrau.font",
"75 30 SOUND EFFECTS",
"30 24 000000_large_explosion.ogg",
"0 24 created by combining:",
"0 24 EXPLODE.WAV, by dkmedic (CC-0)",
"0 24 freesound.org/people/dkmedic/sounds/104447/",
"0 24 Huge rocket launcher.wav, by CGEffex (CC-BY)",
"0 24 freesound.org/people/CGEffex/sounds/100772/",
"30 24 18380__inferno__hvrl.ogg",
"0 24 hvrl, by inferno (CC-Sampling+)",
"0 24 freesound.org/people/inferno/sounds/18380/",
@ -207,7 +208,7 @@
"30 24 320181__dland__hint.ogg",
"0 24 hint.wav, by dland (CC-0)",
"0 24 freesound.org/people/dland/sounds/320181/",
"30 24 62491__benboncan__dslr-click.ogg",
"0 24 DSLR Click.wav, by Benboncan (CC-BY)",
"0 24 freesound.org/people/Benboncan/sounds/62491/",
@ -223,7 +224,7 @@
"30 24 33785__jobro__4-beep-b.ogg",
"0 24 4 beep b.wav, by jobro (CC-BY)",
"0 24 freesound.org/people/jobro/sounds/33785/",
"30 24 255729__manholo__inception-stab-l.ogg",
"0 24 inception-stab-l.wav, by manholo (CC-BY)",
"0 24 freesound.org/people/manholo/sounds/255729/",
@ -243,73 +244,73 @@
"30 24 146311__jgeralyn__shortailenliketone2-lower.ogg",
"0 24 shortailenliketone2_lower.aif, by jgeralyn (CC-BY)",
"0 24 freesound.org/people/jgeralyn/sounds/146311/",
"75 30 MUSIC",
"30 24 Battle in the winter.mp3",
"0 24 Johan Brodd (CC-BY)",
"0 24 opengameart.org/content/battle-in-the-winter",
"30 24 battleThemeA.mp3",
"0 24 cynicmusic.com | pixelsphere.org (CC-0)",
"0 24 opengameart.org/content/battle-theme-a",
"30 24 determination.mp3",
"0 24 artisticdude (CC-0)",
"0 24 opengameart.org/content/determination",
"30 24 heroism.ogg",
"0 24 Edward J. Blakeley (GPL 3.0)",
"0 24 opengameart.org/content/heroism",
"30 24 InnerCore_Low.ogg",
"0 24 Gundatsch (CC-BY)",
"0 24 soundcloud.com/gundatsch",
"30 24 Pressure.ogg",
"0 24 yd (CC-0)",
"0 24 opengameart.org/content/pressure",
"30 24 Rise of Spirit.ogg",
"0 24 Alexandr Zhelanov (CC-0)",
"0 24 soundcloud.com/alexandr-zhelanov",
"30 24 Showdown.mp3",
"0 24 el-corleo (CC-BY)",
"0 24 opengameart.org/content/showdown",
"30 24 track-3.mp3",
"0 24 Alexandr Zhelanov (CC-BY)",
"0 24 soundcloud.com/alexandr-zhelanov",
"30 24 track-4.mp3",
"0 24 Alexandr Zhelanov (CC-BY)",
"0 24 soundcloud.com/alexandr-zhelanov",
"30 24 DST-RailJet-LongSeamlessLoop.ogg",
"0 24 Deceased Superior Technician (CC-BY)",
"0 24 opengameart.org/content/railjet-long-seamless-loop",
"30 24 covert_operations.mp3",
"0 24 artisticdude (CC-0)",
"0 24 opengameart.org/content/covert-operations",
"30 24 Tactical Pursuit.mp3",
"0 24 Matthew Pablo (CC-BY)",
"0 24 opengameart.org/content/tactical-pursuit",
"30 24 Vehicle - OGA - Col Legno.ogg",
"0 24 Vehicle (CC-0)",
"0 24 opengameart.org/content/col-legno",
"30 24 Her Violet Eyes.mp3",
"0 24 tgfcoder (CC-BY)",
"0 24 twitter.com/tgfcoder",
"75 30 SPECIAL THANKS",
"0 24 akien-mga, bentley, Bertram25, ChliHug, Imerion, nnesse, ptitSeb, Szunti",
"150 24 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 (C) 2015-2016, Stephen J Sweeney, Some Rights Reserved. The Battle for the Solar System and all related materials (including, but not limited to, characters, setting, and story elements) are (C) 2009-2016, Stephen J Sweeney, All Rights Reserved.",
"150 24 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 (C) 2015-2019, Stephen J Sweeney, Some Rights Reserved. The Battle for the Solar System and all related materials (including, but not limited to, characters, setting, and story elements) are (C) 2009-2016, Stephen J Sweeney, All Rights Reserved.",
"500 30 www.battleforthesolarsystem.com"
]

View File

@ -10,6 +10,17 @@
"w" : 400,
"h": 34
},
{
"name" : "effects",
"group" : "options",
"type" : "WT_SELECT",
"text" : "Effects Reduction",
"options" : "0;1;2;3",
"x" : -1,
"y" : 225,
"w" : 400,
"h": 34
},
{
"name" : "soundVolume",
"group" : "options",
@ -17,7 +28,7 @@
"text" : "Sound Volume",
"options" : "0;1;2;3;4;5;6;7;8;9;10",
"x" : -1,
"y" : 250,
"y" : 275,
"w" : 400,
"h": 34
},
@ -64,3 +75,4 @@
"h": 34
}
]

View File

@ -12,11 +12,12 @@
{
"name" : "close",
"group" : "starSystem",
"type" : "WT_BUTTON",
"type" : "WT_IMG_BUTTON",
"text" : "X",
"x" : 1060,
"y" : 98,
"w" : 34,
"h": 34
"x" : 1040,
"y" : 75,
"w" : 32,
"h": 32,
"texture" : "gfx/widgets/close.png"
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
gfx/by-nc-sa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
icons/tbftss.info Normal file

Binary file not shown.

View File

@ -39,7 +39,7 @@ msgid "%s (Gun)"
msgstr "%s (arma)"
msgid "We've lost engines! We're a sitting duck!"
msgstr "Hem perdut motors! Som un ànec assegut!"
msgstr "Hem perdut motors! Som un blanc fàcil!"
msgid "Our guns have been shot out! We have no defences!"
msgstr "Les nostres armes s'han disparat! No tenim cap defensa!"
@ -48,7 +48,7 @@ msgid "Be advised, we're taking damage here. Please step up support."
msgstr "Tingueu en compte que estem fent mal aquí. Augmenta el suport."
msgid "We're sustaining heavy damage! All fighters, please assist, ASAP!"
msgstr "Estem patint danys greus! Tots els lluitadors, si us plau, ajuden, ¡AVANÇ!"
msgstr "Estem patint danys greus! A tots els lluitadors, si us plau ajudeu, RÀPID!"
msgid "Mayday! Mayday! Defences are critical. We can't hold out much longer!"
msgstr "Auxili! Auxili! Les defenses són crítiques. No podem aguantar molt més!"
@ -60,7 +60,7 @@ msgid "Civilian has been killed"
msgstr "Civil ha estat assassinat"
msgid "Ally has been killed"
msgstr "Ally ha estat assassinada"
msgstr "Un aliat ha estat assassinat"
msgid "Particle Cannon"
msgstr "Canó de partícules"
@ -72,10 +72,10 @@ msgid "Laser Cannon"
msgstr "Canó làser"
msgid "Mag Cannon"
msgstr "Mag Cannon"
msgstr "Can màgic"
msgid "Rockets"
msgstr "Rockets"
msgstr "Cohets"
msgid "Missiles"
msgstr "Míssils"
@ -102,10 +102,10 @@ msgid "Objective: %.2fkm"
msgstr "Objectiu:% .2fkm"
msgid "Jumpgate: %.2fkm"
msgstr "Jumpgate:% .2fkm"
msgstr "Porta de salt:% .2fkm"
msgid "SELECT NEW FIGHTER"
msgstr "SELECCIONEU NOU PERSONAL"
msgstr "SELECCIONEU NOU LLUITADOR"
msgid "Suspicion"
msgstr "Sospita"
@ -114,7 +114,7 @@ msgid "Remaining Pilots: %d"
msgstr "Pilots restants: %d"
msgid "WARNING: INCOMING MISSILE!"
msgstr "ADVERTIMENT: INCOMPLE MISSIL!"
msgstr "ADVERTIMENT: MÍSSIL ENTRANT!"
msgid "Picked up %s"
msgstr "S'ha escollit %s"
@ -159,16 +159,16 @@ msgid "Destroy at least %d enemy fighters"
msgstr "Destrueix com a mínim %d combatents enemics"
msgid "Challenge Failed!"
msgstr "El repte va fallar!"
msgstr "El repte no s'ha superat!"
msgid "Target not in range"
msgstr "Orientació no dins del rang"
msgstr "Orientació fora del rang"
msgid "Out of missiles"
msgstr "Fora de míssils"
msgstr "Sense míssils"
msgid "Caution: Leaving battle area - turn around."
msgstr "Precaució: deixar la zona de batalla: girar-se."
msgstr "Precaució: sortint de la zona de batalla - gira't."
msgid "Tow rope attached"
msgstr "Corda de remolc adjunta"
@ -183,7 +183,7 @@ msgid "Cannot activate waypoint - outstanding objectives not yet complete"
msgstr "No es pot activar el waypoint: els objectius pendents encara no s'han completat"
msgid "Cannot activate waypoint - eliminate enemies first"
msgstr "No es pot activar el waypoint: elimineu primer als enemics"
msgstr "No es pot activar el waypoint: elimineu primer els enemics"
msgid "Cannot activate waypoint - team mates too far away"
msgstr "No es pot activar el waypoint: companys d'equip massa lluny"
@ -240,7 +240,7 @@ msgid "Do not lose any team mates"
msgstr "No perdeu cap company d'equip"
msgid "Do not lose more than 1 team mate"
msgstr "No perdis més de 1 company d'equip"
msgstr "No perdis més d'1 company d'equip"
msgid "Do not lose more than %d team mates"
msgstr "No perdis més de %d companys d'equip"
@ -252,7 +252,7 @@ msgid "Disable %d or more enemy fighters"
msgstr "Desactiveu %d o més lluitadors enemics"
msgid "Collect %d packages"
msgstr "Recol·leu %d paquets"
msgstr "Recolliu %d paquets"
msgid "Rescue %d civilians"
msgstr "Rescata %d civils"
@ -330,16 +330,16 @@ msgid "Optional Missions Completed"
msgstr "S'han completat les missions opcionals"
msgid "Challenges Started"
msgstr "Els reptes van començar"
msgstr "Els reptes han començat"
msgid "Challenges Completed"
msgstr "Reptes finalitzats"
msgid "Shots Fired"
msgstr "Xuts disparats"
msgstr "Trets disparats"
msgid "Shots Hit"
msgstr "Xuts colpejar"
msgstr "Trets encertats"
msgid "Accuracy"
msgstr "Precisió"
@ -348,19 +348,19 @@ msgid "Rockets Fired"
msgstr "Coets llançats"
msgid "Rockets Hit"
msgstr "Rockets Hit"
msgstr "Cohets encertats"
msgid "Missiles Fired"
msgstr "Míssils acomiadats"
msgstr "Míssils llançats"
msgid "Missiles Hit"
msgstr "Míssils colpejar"
msgstr "Míssils encertats"
msgid "Enemies Killed"
msgstr "Enemics assassinats"
msgid "Enemies Killed (Player)"
msgstr "Enemics killed (Jugador)"
msgstr "Enemics assassinats (Jugador)"
msgid "Allies Killed"
msgstr "Aliats assassinats"
@ -417,7 +417,7 @@ msgid "Capital Ships Destroyed"
msgstr "Vaixells de capital destruïts"
msgid "Capital Ships Lost"
msgstr "Capital Ships Lost"
msgstr "Vaixells de capital perduts"
msgid "Mines Destroyed"
msgstr "Mines destruïdes"
@ -444,7 +444,7 @@ msgid "Fire"
msgstr "Foc"
msgid "Accelerate"
msgstr "Accelerate"
msgstr "Accelerar"
msgid "Boost"
msgstr "Estímul"
@ -507,7 +507,7 @@ msgid "Continue"
msgstr "Continua"
msgid "Resume"
msgstr "Resum"
msgstr "Reprèn"
msgid "Return to Title"
msgstr "Torna al títol"
@ -525,10 +525,10 @@ msgid "Restart"
msgstr "Reinicia"
msgid "Cancel"
msgstr "Cancel · lar"
msgstr "Cancel·lar"
msgid "Window Size"
msgstr "Mida de finestra"
msgstr "Mida de la finestra"
msgid "Sound Volume"
msgstr "Volum de so"
@ -555,7 +555,7 @@ msgid "Credits"
msgstr "Crèdits"
msgid "Patrol #1"
msgstr "Patrulla nº 1"
msgstr "Patrulla núm. 1"
msgid "With the Pandorans having invaded Independent systems boardering the Mitikas Empire, we need to become more vigilant. Patrols around Torelli are being stepped up. Ensure you hit all the waypoints, and report any unusual activity that you encounter."
msgstr "Quan els Pandorans havien envaït els sistemes independents que travessen l'Imperi Mitikas, hem de ser més vigilants. S'estan intensificant les patrulles de Torelli. Assegureu-vos que toqueu tots els punts de cerca i informeu sobre qualsevol activitat inusual que trobareu."
@ -567,13 +567,13 @@ msgid "Anyone got anything to report?"
msgstr "Algú ha rebut alguna cosa per informar?"
msgid "You getting paranoid, Curtis?"
msgstr "Et fas paranoico, Curtis?"
msgstr "T'ests tornant paranoic, Curtis?"
msgid "You all saw what happened at Coyote."
msgstr "Tots vèiem el que va passar al Coyote."
msgstr "Tots vam veure el que li va passar al Coyote."
msgid "So, those Pandorans are, what, robots?"
msgstr "Per tant, els Pandorans són, què, robots?"
msgstr "Per tant, els Pandorans són, què? robots?"
msgid "Alien-Human hybrid, I heard."
msgstr "Alien-Híbrid humà, he escoltat."
@ -582,22 +582,22 @@ msgid "Hard to kill, whatever they are. Heard they'll still be coming at you eve
msgstr "Difícil de matar, siguin quines siguin. Heu escoltat que encara us arribaran encara que treguis els dos braços."
msgid "And what'll they do then? Bite you to death?"
msgstr "I què faran llavors? Mosseguis a mort?"
msgstr "I què faran llavors? Et mossegaran fins a la mort?"
msgid "Eyes open, lads."
msgstr "Ulls oberts, nois."
msgstr "Obriu els ulls, nois."
msgid "We're done. Anyone detect anything unusual?"
msgstr "Estaven fets. Qualsevol persona detecta alguna cosa inusual?"
msgstr "Hem acabat. Qualsevol persona detecta alguna cosa inusual?"
msgid "Same old, same old."
msgstr "Mateix vell, igual antic."
msgstr "El mateix de sempre."
msgid "Believe me, that's a good thing. Right, let's head home and report in."
msgstr "Creieu-me, això és bo. Dret, anem a casa i ens informem."
msgstr "Creieu-me, això és bo. Correcte, anem a casa i ens informem."
msgid "Patrol #2"
msgstr "Patrulla nº 2"
msgstr "Patrulla núm. 2"
msgid "Patrols so far have not uncovered anything unusual, and it seems as though the increase in military presence 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."
msgstr "Les patrulles fins ara no han descobert res inusual, i sembla que l'augment de la presència militar és reduir la quantitat d'activitat il·legal en aquest sector, amb incidents denunciats un 80 %% menys. Tot i això, no podem permetre'ns tornar-nos complaents i continuar amb els nostres escombrats."
@ -606,10 +606,10 @@ msgid "Check all Waypoints"
msgstr "Marqueu tots els Waypoints"
msgid "Destroy Pandoran fighters"
msgstr "Destruir els lluitadors de Pandoran"
msgstr "Destruiu els lluitadors de Pandoran"
msgid "Eightballers, you have hostiles incoming. Identified as 3 Mitikas fighters; Jackals, possibly Pandoran. Engage, but exercise extreme caution."
msgstr "Obleballers, tens hostils entrants. Identificat com 3 lluitadors Mitikas; Jackals, possiblement Pandoran. Participa, però exerceix una gran precaució."
msgstr "Eightballers, tens hostils entrants. Identificats com 3 lluitadors Mitikas; Jackals, possiblement Pandoran. Participa, però exerceix una gran precaució."
msgid "Control, enemies have been dispatched. Wasn't a comfortable fight."
msgstr "Control, els enemics s'han enviat. No era una baralla confortable."
@ -621,7 +621,7 @@ msgid "Got it. See you soon."
msgstr "Ho tinc. Fins aviat."
msgid "Patrol #3"
msgstr "Patrulla nº 3"
msgstr "Patrulla núm. 3"
msgid "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."
msgstr "Després de la pèrdua devastadora del sistema Ilíada, hem de seguir vigilant contra la incursió al sistema Alba. Comproveu els cinc waypoints i informe immediatament qualsevol activitat inusual o sospitosa que trobeu."
@ -666,10 +666,10 @@ msgid "What about?"
msgstr "I què passa amb?"
msgid "How long it'll be before the Pandorans show up here."
msgstr "Quant de temps serà abans que els Pandorans apareguin aquí."
msgstr "Quant de temps passarà abans que els Pandorans apareguin aquí."
msgid "They came by earlier, in case you don't remember."
msgstr "Van venir abans, en cas que no us recordeu."
msgstr "Van venir abans, en cas que no us en recordeu."
msgid "And haven't been back since. Maybe we scared them off."
msgstr "I no he tornat des de llavors. Potser els hem espantat."
@ -681,10 +681,10 @@ msgid "Where the hell are the CSN? Why weren't they at Iliad?"
msgstr "On són els inferns el CSN? Per què no estaven a la Ilíada?"
msgid "They weren't wanted, apparently. Iliad and the UNF aren't getting along so well at the moment."
msgstr "No eren volguts, aparentment. La Ilíada i la UNF no estan aconseguint tan bé en aquest moment."
msgstr "No eren volguts, aparentment. La Ilíada i la UNF no estan tan bé en aquest moment."
msgid "Something to do with Adrian Parsons?"
msgstr "Alguna cosa que veure amb Adrian Parsons?"
msgstr "Alguna cosa a veure amb Adrian Parsons?"
msgid "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-"
msgstr "Aquest idiota sagnant? No m'estranyaria. Ell és el motiu pel qual estem ara en aquest embolic! Si alguna vegada conec a aquest noi,"
@ -750,7 +750,7 @@ msgid "Enemies sighted."
msgstr "Enemics observats."
msgid "Break and attack, people!"
msgstr "Trencar i atacar, gent!"
msgstr "Trenqueu i ataqueu, gent!"
msgid "That's the first group handled. Let's get to the next waypoint."
msgstr "Aquest és el primer grup manejat. Anem al següent punt de referència."
@ -792,7 +792,7 @@ msgid "Destroy INF Burnside"
msgstr "Destrueix INF Burnside"
msgid "Break and attack, lads. Let's send these guys back home."
msgstr "Trencar i atacar, nois. Anem a enviar aquests nois a casa seva."
msgstr "Trenqueu i ataqueu, nois. Enviem aquests nois a casa seva."
msgid "More Tzac fighters incoming."
msgstr "Més entrenadors de Tzac entrants."

View File

@ -19,6 +19,9 @@ _OBJS += unixInit.o
include common.mk
NPROCS = $(shell grep -c 'processor' /proc/cpuinfo)
MAKEFLAGS += -j$(NPROCS)
CXXFLAGS += `sdl2-config --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\"
CXXFLAGS += -ansi -pedantic
CXXFLAGS += -g -lefence

53
makefile.os4 Normal file
View File

@ -0,0 +1,53 @@
PROG = tbftss
CC = gcc-11
PREFIX ?= /usr
BIN_DIR ?= $(PREFIX)/bin
DATA_DIR ?= data
LOCALE_DIR = 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/os4
_OBJS += os4Init.o
include common.mk
CXXFLAGS += -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -D__USE_INLINE__
CXXFLAGS += -pedantic
CXXFLAGS += -g -lefence
CXXFLAGS += -Wall -Wempty-body -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
# CXXFLAGS += -gstabs
LDFLAGS += -lauto -lSDL2_image -lSDL2_ttf -lft2 -ltiff -lwebp -lpng -ljpeg -lz -lm
LDFLAGS += -lSDL2_mixer -lmikmod -lmodplug -lFLAC -lsmpeg2 -lvorbisfile -lvorbis -logg
LDFLAGS += -lSDL2 -lpthread -athread=native -lstdc++
# LDFLAGS += -gstabs
# linking the program.
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
# prepare an archive for the program
dist:
mkdir -p release/$(PROG)-$(VERSION).$(REVISION)/data/app
mkdir -p release/$(PROG)-$(VERSION).$(REVISION)/data/widgets
cp $(PROG) release/$(PROG)-$(VERSION).$(REVISION)/
strip release/$(PROG)-$(VERSION).$(REVISION)/$(PROG)
cp icons/tbftss.info release/$(PROG)-$(VERSION).$(REVISION)/$(PROG).info
cp data/app/config.json release/$(PROG)-$(VERSION).$(REVISION)/data/app/
cp data/widgets/options.json release/$(PROG)-$(VERSION).$(REVISION)/data/widgets/
cp LICENSE release/$(PROG)-$(VERSION).$(REVISION)/
cp README.md release/$(PROG)-$(VERSION).$(REVISION)/
cp README-OS4.md release/$(PROG)-$(VERSION).$(REVISION)/
lha -aeqr3 a $(PROG)-$(VERSION).$(REVISION).lha release/
.PHONY: dist

View File

@ -7,8 +7,11 @@ LOCALE_DIR = locale
SEARCHPATH += src/plat/win32
_OBJS += win32Init.o
NPROCS = $(shell grep -c 'processor' /proc/cpuinfo)
MAKEFLAGS += -j$(NPROCS)
CXXFLAGS += `$(SDLC) --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\"
CXXFLAGS += -ansi
CXXFLAGS += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
LDFLAGS += `$(SDLC) --libs` -lm -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lSDL2main

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -57,7 +57,7 @@ void initBattle(void)
app.delegate.logic = &logic;
app.delegate.draw = &draw;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
battle.hasThreats = 1;
initQuadtree(&battle.quadtree);
@ -96,7 +96,7 @@ void initBattle(void)
getWidget("quit", "battleLost")->action = quitBattle;
selectWidget("ok", "startBattle");
SDL_SetWindowGrab(app.window, 1);
}
@ -117,9 +117,9 @@ static void logic(void)
doPlayerSelect();
}
}
app.doTrophyAlerts = (battle.status != MS_IN_PROGRESS && battle.missionFinishedTimer <= -FPS * 2);
if (battle.campaignFinished)
{
endCampaign();
@ -143,8 +143,8 @@ static void doBattle(void)
scrollBackground(-ssx * 0.1, -ssy * 0.1);
battle.planet.x -= ssx * 0.1;
battle.planet.y -= ssy * 0.1;
battle.planet.x -= ssx * 0.15;
battle.planet.y -= ssy * 0.15;
doObjectives();
@ -163,9 +163,9 @@ static void doBattle(void)
doDebris();
doPlayer();
checkSuspicionLevel();
doTorelliFireStorm();
if (player->alive == ALIVE_ALIVE)
@ -175,7 +175,7 @@ static void doBattle(void)
doLocations();
doMessageBox();
if (battle.status == MS_IN_PROGRESS || battle.status == MS_COMPLETE)
{
doScript();
@ -186,7 +186,7 @@ static void doBattle(void)
if (battle.stats[STAT_TIME]++ % FPS == 0)
{
runScriptFunction("TIME %d", battle.stats[STAT_TIME] / FPS);
if (game.currentMission->challengeData.timeLimit && game.currentMission->challengeData.timeLimit - battle.stats[STAT_TIME] < 11 * FPS)
{
playSound(SND_TIME_WARNING);
@ -198,11 +198,11 @@ static void doBattle(void)
if (battle.status != MS_IN_PROGRESS)
{
battle.missionFinishedTimer--;
if (battle.unwinnable && battle.missionFinishedTimer <= -FPS * 6)
{
battle.status = MS_COMPLETE;
postBattle();
destroyBattle();
@ -221,11 +221,11 @@ static void draw(void)
}
drawBackground(battle.background);
setAtlasColor(255, 255, 255, 255);
blitScaled(battle.planetTexture, battle.planet.x, battle.planet.y, battle.planetWidth, battle.planetHeight, 0);
if (battle.destroyTorelli)
{
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
@ -273,14 +273,14 @@ static void draw(void)
static void drawMenu(void)
{
SDL_Rect r;
if (app.modalDialog.type == MD_NONE)
{
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);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 400;
@ -294,7 +294,7 @@ static void drawMenu(void)
SDL_RenderDrawRect(app.renderer, &r);
drawWidgets("inBattle");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
}
@ -331,9 +331,9 @@ static void handleKeyboard(void)
if (battle.status == MS_IN_PROGRESS && app.keyboard[SDL_SCANCODE_TAB])
{
battle.status = MS_PAUSED;
selectWidget("ok", "startBattle");
SDL_SetWindowGrab(app.window, 0);
}
}
@ -341,14 +341,14 @@ static void handleKeyboard(void)
static void start(void)
{
battle.status = MS_IN_PROGRESS;
SDL_SetWindowGrab(app.window, 1);
}
static void resume(void)
{
show = SHOW_BATTLE;
SDL_SetWindowGrab(app.window, 1);
clearInput();
@ -397,7 +397,7 @@ static void restart(void)
static void retry(void)
{
app.modalDialog.type = MD_NONE;
postBattle();
destroyBattle();
@ -415,7 +415,7 @@ static void optQuitBattle(void)
static void quitBattle(void)
{
app.modalDialog.type = MD_NONE;
postBattle();
destroyBattle();
@ -441,13 +441,13 @@ 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);
game.currentMission->completed = (game.currentMission->completed || battle.status == MS_COMPLETE || !battle.numObjectivesTotal);
app.saveGame = 1;
}
@ -456,11 +456,11 @@ static void checkSuspicionLevel(void)
if (battle.hasSuspicionLevel && battle.suspicionLevel >= MAX_SUSPICION_LEVEL)
{
cancelScript();
resetMessageBox();
runScriptFunction("MAX_SUSPICION_LEVEL");
battle.hasSuspicionLevel = 0;
}
}
@ -476,11 +476,11 @@ static void doTorelliFireStorm(void)
static void endCampaign(void)
{
awardTrophy("CAMPAIGN_COMPLETE");
postBattle();
destroyBattle();
initCredits();
}
@ -567,7 +567,7 @@ void destroyBattle(void)
destroyBullets();
destroyEffects();
memset(&battle, 0, sizeof(Battle));
battle.bulletTail = &battle.bulletHead;
battle.debrisTail = &battle.debrisHead;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -179,7 +179,7 @@ static void checkCollisions(Bullet *b)
{
battle.stats[STAT_ROCKETS_HIT]++;
}
if (battle.hasSuspicionLevel)
{
if (e->aiFlags & (AIF_AVOIDS_COMBAT|AIF_DEFENSIVE))
@ -192,14 +192,14 @@ static void checkCollisions(Bullet *b)
}
}
}
if (e->flags & EF_IMMORTAL)
{
b->damage = 0;
}
damageFighter(e, b->damage, b->flags);
doBulletHitEffect(b);
b->life = 0;
@ -215,13 +215,13 @@ 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]++;
}
if (b->type == BT_MISSILE && b->target != e)
{
if (e == player)
@ -233,23 +233,23 @@ static void checkCollisions(Bullet *b)
awardTrophy("BODYGUARD");
}
}
/* assuming that health <= 0 will always mean killed */
if (e->health <= 0)
{
e->killedBy = b->owner;
if (e == player)
{
battle.lastKilledPlayer = b->owner;
}
if (b->owner == player && e == battle.lastKilledPlayer)
if (battle.isEpic && b->owner == player && e == battle.lastKilledPlayer)
{
awardTrophy("REVENGE");
}
}
if (b->owner == player && b->type == BT_MISSILE)
{
battle.stats[STAT_MISSILES_HIT]++;
@ -268,19 +268,19 @@ void doBulletHitEffect(Bullet *b)
case BT_PARTICLE:
addBulletHitEffect(b->x, b->y, 255, 0, 255);
break;
case BT_PLASMA:
addBulletHitEffect(b->x, b->y, 0, 255, 0);
break;
case BT_LASER:
addBulletHitEffect(b->x, b->y, 255, 0, 0);
break;
case BT_MAG:
addBulletHitEffect(b->x, b->y, 196, 196, 255);
break;
default:
addBulletHitEffect(b->x, b->y, 255, 255, 255);
break;
@ -291,7 +291,7 @@ void drawBullets(void)
{
int i;
Bullet *b;
setAtlasColor(255, 255, 255, 255);
for (i = 0, b = bulletsToDraw[i] ; b != NULL ; b = bulletsToDraw[++i])
@ -303,7 +303,7 @@ void drawBullets(void)
static void faceTarget(Bullet *b)
{
int dir, wantedAngle, dist;
wantedAngle = (int)getAngle(b->x, b->y, b->target->x, b->target->y) % 360;
if (abs(wantedAngle - b->angle) > TURN_THRESHOLD)
@ -311,23 +311,23 @@ static void faceTarget(Bullet *b)
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);
b->dx *= 0.5;
b->dy *= 0.5;
}
@ -378,29 +378,29 @@ 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);
@ -438,7 +438,7 @@ void fireGuns(Entity *owner)
int i;
float x, y;
float c, s;
b = NULL;
for (i = 0 ; i < MAX_FIGHTER_GUNS ; i++)
@ -492,7 +492,7 @@ void fireMissile(Entity *owner)
Bullet *b;
b = createBullet(BT_MISSILE, owner->x, owner->y, owner);
b->dx *= 0.5;
b->dy *= 0.5;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -87,7 +87,7 @@ void doCapitalShip(void)
if (self->alive == ALIVE_ALIVE)
{
handleDisabled();
if (self->health <= 0)
{
self->health = 0;
@ -111,7 +111,7 @@ void doCapitalShip(void)
runScriptFunction("CAPITAL_SHIPS_DESTROYED %d", battle.stats[STAT_CAPITAL_SHIPS_DESTROYED]);
}
runScriptFunction(self->name);
}
}
@ -243,7 +243,7 @@ static int steer(void)
static void gunThink(void)
{
doAI();
handleDisabled();
}
@ -259,7 +259,7 @@ static void componentDie(void)
if (self->owner->health > 0)
{
runScriptFunction("CAP_HEALTH %s %d", self->owner->name, self->owner->health);
if (self->side != SIDE_PANDORAN && self->side == player->side)
{
issueDamageMessage(self->owner);
@ -270,12 +270,12 @@ static void componentDie(void)
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)
@ -283,14 +283,14 @@ static void gunDie(void)
return;
}
}
runScriptFunction("CAP_GUNS_DESTROYED %s", self->owner->name);
if (self->side != SIDE_PANDORAN && self->side == player->side)
{
issueGunsDestroyedMessage(self->owner);
}
if (--self->owner->systemPower == 1)
{
disable();
@ -300,7 +300,7 @@ static void gunDie(void)
static void engineThink(void)
{
handleDisabled();
addLargeEngineEffect();
}
@ -329,13 +329,13 @@ static void engineDie(void)
self->owner->dx = self->owner->dy = 0;
runScriptFunction("CAP_ENGINES_DESTROYED %s", self->owner->name);
if (self->side != SIDE_PANDORAN && self->side == player->side)
{
issueEnginesDestroyedMessage(self->owner);
}
}
if (--self->owner->systemPower == 1)
{
disable();
@ -347,11 +347,11 @@ static void die(void)
Entity *e;
self->alive = ALIVE_DEAD;
playBattleSound(SND_CAP_DEATH, self->x, self->y);
addLargeExplosion();
addDebris(self->x, self->y, 12);
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
@ -364,7 +364,7 @@ static void die(void)
updateObjective(self->name, TT_DESTROY);
updateObjective(self->groupName, TT_DESTROY);
updateCondition(self->name, TT_DESTROY);
updateCondition(self->groupName, TT_DESTROY);
}
@ -384,9 +384,9 @@ 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 == self->owner)
@ -395,7 +395,7 @@ static void disable(void)
e->flags |= EF_DISABLED;
}
}
updateObjective(self->owner->name, TT_DISABLE);
updateObjective(self->owner->groupName, TT_DISABLE);
}
@ -631,7 +631,7 @@ static void loadEngines(Entity *parent, cJSON *engines)
void updateCapitalShipComponentProperties(Entity *parent, long flags)
{
Entity *e;
if (flags != -1)
{
flags &= ~EF_AI_LEADER;
@ -645,7 +645,7 @@ void updateCapitalShipComponentProperties(Entity *parent, long flags)
{
e->flags |= flags;
}
switch (e->type)
{
case ET_COMPONENT_ENGINE:
@ -743,9 +743,9 @@ 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);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "%s (%d / %d)", e->name, e->health, e->maxHealth);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -24,6 +24,7 @@ static void setRandomFlameHue(Effect *e);
static void setRandomShieldHue(Effect *e);
static void resizeDrawList(void);
static int pointOnScreen(float x, float y);
static float calculateEffectsValue(unsigned int);
static AtlasImage *explosionTexture;
static AtlasImage *shieldHitTexture;
@ -48,9 +49,9 @@ void doEffects(void)
int i, onScreen;
Effect *e;
Effect *prev = &battle.effectHead;
i = 0;
memset(effectsToDraw, 0, sizeof(Effect*) * drawCapacity);
for (e = battle.effectHead.next ; e != NULL ; e = e->next)
@ -79,22 +80,22 @@ void doEffects(void)
else
{
onScreen = 0;
switch (e->type)
{
case EFFECT_LINE:
onScreen = pointOnScreen(e->x - battle.camera.x, e->y - battle.camera.y) || pointOnScreen(e->x + (e->dx * 3) - battle.camera.x, e->y + (e->dy * 3) - battle.camera.y);
break;
case EFFECT_POINT:
onScreen = pointOnScreen(e->x - battle.camera.x, e->y - battle.camera.y);
break;
default:
onScreen = isOnBattleScreen(e->x, e->y, e->size, e->size);
break;
}
if (onScreen)
{
effectsToDraw[i++] = e;
@ -124,7 +125,7 @@ static void resizeDrawList(void)
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing effect draw capacity: %d -> %d", drawCapacity, n);
effectsToDraw = resize(effectsToDraw, sizeof(Effect*) * drawCapacity, sizeof(Effect*) * n);
drawCapacity = n;
}
@ -169,20 +170,20 @@ void drawEffects(void)
blitScaled(e->texture, app.winWidth / 2 - (e->size / 2), app.winHeight / 2 - (e->size / 2), e->size, e->size, 0);
break;
}
if (e->texture != NULL)
{
SDL_SetTextureBlendMode(e->texture->texture, SDL_BLENDMODE_BLEND);
}
}
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
}
void drawShieldHitEffect(Entity *e)
{
int size = MAX(e->w, e->h) + 32;
SDL_SetTextureBlendMode(shieldHitTexture->texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(shieldHitTexture->texture, e->shieldHit);
blitScaled(shieldHitTexture, e->x - battle.camera.x, e->y - battle.camera.y, size, size, 1);
@ -192,7 +193,7 @@ void addBulletHitEffect(int x, int y, int r, int g, int b)
{
Effect *e;
int i;
for (i = 0 ; i < 4 ; i++)
{
e = malloc(sizeof(Effect));
@ -202,10 +203,10 @@ void addBulletHitEffect(int x, int y, int r, int g, int b)
e->type = EFFECT_TEXTURE;
e->texture = explosionTexture;
e->size = 16;
e->size = calculateEffectsValue(16);
e->x = x;
e->y = y;
e->dx = (rand() % 25) - (rand() % 25);
e->dx *= 0.01;
e->dy = (rand() % 25) - (rand() % 25);
@ -215,7 +216,7 @@ void addBulletHitEffect(int x, int y, int r, int g, int b)
e->g = g;
e->b = b;
e->a = 64;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
}
}
@ -233,12 +234,12 @@ void addSmallFighterExplosion(void)
e->x = self->x + (rand() % 16 - rand() % 16);
e->y = self->y + (rand() % 16 - rand() % 16);
e->texture = explosionTexture;
e->size = 32;
e->size = calculateEffectsValue(32);
setRandomFlameHue(e);
e->a = 128 + (rand() % 128);
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -258,12 +259,12 @@ void addDebrisFire(int x, int y)
e->x = x + (rand() % 8 - rand() % 8);
e->y = y + (rand() % 8 - rand() % 8);
e->texture = explosionTexture;
e->size = 4 + rand() % 12;
e->size = calculateEffectsValue(4 + rand() % 12);
setRandomFlameHue(e);
e->a = rand() % 256;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -290,13 +291,13 @@ void addSmallExplosion(void)
e->dy = (rand() % 25) - (rand() % 25);
e->dy *= 0.025;
e->texture = explosionTexture;
e->size = 32 + (rand() % 64);
e->size = calculateEffectsValue(32 + (rand() % 64));
e->r = 255;
setRandomFlameHue(e);
e->a = 128 + (rand() % 128);
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -318,7 +319,7 @@ void addSmallExplosion(void)
e->dy *= 0.1;
e->a = 128;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
setRandomFlameHue(e);
}
@ -341,13 +342,13 @@ void addMineExplosion(void)
e->x = self->x + rand() % 64 - rand() % 64;
e->y = self->y + rand() % 64 - rand() % 64;
e->texture = explosionTexture;
e->size = 64 + (rand() % 64);
e->size = calculateEffectsValue(64 + (rand() % 64));
e->r = 255;
setRandomFlameHue(e);
e->a = 32 + (rand() % 192);
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -362,7 +363,7 @@ void addMineExplosion(void)
e->type = EFFECT_HALO;
e->x = self->x;
e->y = self->y;
e->size = 64;
e->size = calculateEffectsValue(64);
e->scaleAmount = 6;
e->texture = haloTexture;
@ -371,7 +372,7 @@ void addMineExplosion(void)
e->b = 255;
e->a = 128;
e->health = 128;
e->health = calculateEffectsValue(128);
}
void addLargeExplosion(void)
@ -395,18 +396,18 @@ void addLargeExplosion(void)
e->dy = (rand() % 25) - (rand() % 25);
e->dy *= 0.01;
e->texture = explosionTexture;
e->size = 128 + (rand() % 512);
e->size = calculateEffectsValue(128 + (rand() % 512));
e->r = 255;
setRandomFlameHue(e);
e->a = 128 + (rand() % 128);
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
}
e = malloc(sizeof(Effect));
memset(e, 0, sizeof(Effect));
@ -416,7 +417,7 @@ void addLargeExplosion(void)
e->type = EFFECT_HALO;
e->x = self->x;
e->y = self->y;
e->size = 256;
e->size = calculateEffectsValue(256);
e->scaleAmount = 4;
e->texture = haloTexture;
@ -425,7 +426,7 @@ void addLargeExplosion(void)
e->b = 255;
e->a = 255;
e->health = 255;
e->health = calculateEffectsValue(255);
}
void addMissileExplosion(Bullet *b)
@ -449,13 +450,13 @@ void addMissileExplosion(Bullet *b)
e->dy = (rand() % 25) - (rand() % 25);
e->dy *= 0.025;
e->texture = explosionTexture;
e->size = 32 + (rand() % 64);
e->size = calculateEffectsValue(32 + (rand() % 64));
e->r = 255;
setRandomFlameHue(e);
e->a = 128 + (rand() % 128);
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -477,7 +478,7 @@ void addMissileExplosion(Bullet *b)
e->dy *= 0.1;
e->a = 128;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
setRandomFlameHue(e);
}
@ -507,13 +508,13 @@ void addEngineEffect(void)
e->x += rand() % 4 - rand() % 4;
e->texture = explosionTexture;
e->size = 16;
e->size = calculateEffectsValue(16);
e->r = 128;
e->g = 128;
e->b = 255;
e->a = 64;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -540,13 +541,13 @@ void addLargeEngineEffect(void)
e->x -= rand() % 4;
e->texture = explosionTexture;
e->size = 64;
e->size = calculateEffectsValue(64);
e->r = 128;
e->g = 128;
e->b = 255;
e->a = 64;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -573,11 +574,11 @@ void addMissileEngineEffect(Bullet *b)
e->x -= rand() % 4;
e->texture = explosionTexture;
e->size = 12;
e->size = calculateEffectsValue(12);
setRandomFlameHue(e);
e->a = 128;
e->health = e->a;
e->health = calculateEffectsValue(e->a);
e->x -= e->size / 2;
e->y -= e->size / 2;
@ -603,7 +604,7 @@ void addShieldSplinterEffect(Entity *ent)
e->dy = rand() % 64 - rand() % 64;
e->dy *= 0.1;
e->a = 255;
e->health = e->a;
setRandomShieldHue(e);
@ -695,3 +696,16 @@ void destroyEffects(void)
effectsToDraw = NULL;
}
static float calculateEffectsValue(unsigned int val)
{
#if defined(__amigaos4__)
if (app.effects)
{
return val / (app.effects * 2);
}
#endif
return (float)val;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -84,7 +84,7 @@ void doEntities(void)
e->health = e->maxHealth;
e->shield = e->maxShield;
}
if (e->active)
{
self = e;
@ -149,19 +149,19 @@ void doEntities(void)
e->action();
}
}
doRope(e);
restrictToBattleArea(e);
if (!e->speed)
{
e->dx = e->dy = 0;
}
e->x += e->dx;
e->y += e->dy;
addToQuadtree(e, &battle.quadtree);
}
else
@ -175,7 +175,7 @@ void doEntities(void)
{
battle.missionTarget = NULL;
}
if (e->killedBy == player && battle.hasSuspicionLevel)
{
if (e->aiFlags & (AIF_AVOIDS_COMBAT|AIF_DEFENSIVE))
@ -196,12 +196,12 @@ void doEntities(void)
cutRope(e);
prev->next = e->next;
e->next = NULL;
deadTail->next = e;
deadTail = e;
/* actually just creates another fighter in this one's place */
if (e->type == ET_FIGHTER && battle.isEpic && e->side != player->side && battle.unlimitedEnemies)
{
@ -230,13 +230,13 @@ void doEntities(void)
if (e->health > 0 && e->active)
{
numActiveEnemies++;
if (e->spawned)
{
numSpawnedEnemies++;
}
}
if (!(e->flags & EF_DISABLED) || battle.isEpic)
{
battle.hasThreats = 1;
@ -249,7 +249,7 @@ void doEntities(void)
battle.numAllies = (battle.isEpic) ? numAllies : numActiveAllies;
battle.numEnemies = (battle.isEpic) ? numEnemies : numActiveEnemies;
if (battle.status == MS_IN_PROGRESS && battle.stats[STAT_TIME] % (FPS * 30) == 0)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "numEnemies=%d, numActiveEnemies=%d, hasThreats=%d", numEnemies, numActiveEnemies, battle.hasThreats);
@ -261,7 +261,7 @@ void doEntities(void)
{
activateEpicFighters(SIDE_ALLIES);
}
numActiveEnemies -= numSpawnedEnemies;
if (numActiveEnemies < battle.epicFighterLimit)
@ -357,7 +357,7 @@ static void alignComponents(void)
if (isComponent(e))
{
removeFromQuadtree(e, &battle.quadtree);
s = sin(TO_RAIDANS(e->owner->angle));
c = cos(TO_RAIDANS(e->owner->angle));
@ -389,12 +389,12 @@ void drawEntities(void)
{
int i;
Entity *e, **candidates;
candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, app.winWidth, app.winHeight, NULL);
/* counting entities to draw */
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) {};
qsort(candidates, i, sizeof(Entity*), drawComparator);
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
@ -409,11 +409,11 @@ void drawEntities(void)
{
drawEntity(e);
}
drawHealthBar(e);
drawTargetRects(e);
drawRope(e);
}
}
@ -448,14 +448,14 @@ static void drawEntity(Entity *e)
static void drawHealthBar(Entity *e)
{
SDL_Rect r;
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 == player->side || e->flags & EF_FRIENDLY_HEALTH_BAR)
{
SDL_SetRenderDrawColor(app.renderer, 0, 128, 0, 255);
@ -464,11 +464,11 @@ static void drawHealthBar(Entity *e)
{
SDL_SetRenderDrawColor(app.renderer, 128, 0, 0, 255);
}
SDL_RenderFillRect(app.renderer, &r);
r.w = 32 * (e->health * 1.0f / e->maxHealth);
if (e->side == player->side || e->flags & EF_FRIENDLY_HEALTH_BAR)
{
SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255);
@ -477,7 +477,7 @@ static void drawHealthBar(Entity *e)
{
SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255);
}
SDL_RenderFillRect(app.renderer, &r);
}
}
@ -509,7 +509,7 @@ 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;
@ -564,9 +564,9 @@ 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);
@ -600,23 +600,23 @@ static void notifyNewArrivals(void)
static void activateEpicFighters(int side)
{
Entity *e;
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)))
{
e->active = 1;
/* don't spring into existence in front of the player */
if (isOnBattleScreen(e->x, e->y, e->w, e->h))
{
e->x = player->x;
e->y = player->y;
e->x += (rand() % 2) ? -app.winWidth : app.winWidth;
e->y += (rand() % 2) ? -app.winHeight : app.winHeight;
}
return;
}
}
@ -640,7 +640,7 @@ void countNumEnemies(void)
void addAllToQuadtree(void)
{
Entity *e;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active)
@ -661,14 +661,14 @@ static int drawComparator(const void *a, const void *b)
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, "");
@ -680,15 +680,15 @@ void updateEntitySide(char *sideStr, char *name)
{
Entity *e;
int side;
side = lookup(sideStr);
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (strcmp(e->name, name) == 0)
{
e->side = side;
if (e->side != player->side)
{
e->flags |= EF_MISSION_TARGET;
@ -700,7 +700,7 @@ void updateEntitySide(char *sideStr, char *name)
void awardPandoranCraftTrophy(void)
{
Entity *e;
for (e = deadHead.next ; e != NULL ; e = e->next)
{
if (e->killedBy == player && e->side == SIDE_PANDORAN)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -97,7 +97,7 @@ 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();
@ -193,14 +193,14 @@ static void randomizeDartGuns(Entity *dart)
void resetFighter(Entity *fighter)
{
Entity *e;
e = spawnFighter(fighter->defName, fighter->x, fighter->y, fighter->side);
e->x += (rand() % 7500) - (rand() % 7500);
e->y += (rand() % 7500) - (rand() % 7500);
e->active = 0;
if (rand() % 4)
{
e->aiFlags |= AIF_TARGET_FOCUS;
@ -251,7 +251,7 @@ void doFighter(void)
self->flags |= EF_DISABLED;
self->flags |= EF_SECONDARY_TARGET;
if (self->aiFlags & AIF_SURRENDERING)
{
self->aiFlags |= AIF_SURRENDERED;
@ -262,7 +262,7 @@ void doFighter(void)
updateObjective(self->name, TT_DISABLE);
updateObjective(self->groupName, TT_DISABLE);
if (self->side != player->side)
{
runScriptFunction("ENEMIES_DISABLED %d", battle.stats[STAT_ENEMIES_DISABLED]);
@ -279,12 +279,12 @@ void doFighter(void)
self->action = doAI;
}
}
if (self->aiFlags & AIF_SUSPICIOUS)
{
checkSuspicionLevel();
}
if (self->aiFlags & AIF_ZAK_SUSPICIOUS)
{
checkZackariaSuspicionLevel();
@ -296,7 +296,7 @@ void doFighter(void)
if (self == player && !game.currentMission->challengeData.isChallenge)
{
updateObjective("Player", TT_ESCAPED);
completeMission();
}
@ -346,7 +346,7 @@ void doFighter(void)
{
addHudMessage(colors.red, _("Civilian has been killed"));
}
runScriptFunction("CIVILIANS_KILLED %d", battle.stats[STAT_CIVILIANS_KILLED]);
}
else
@ -360,10 +360,10 @@ void doFighter(void)
runScriptFunction("ALLIES_KILLED %d", battle.stats[STAT_ALLIES_KILLED]);
}
}
updateObjective(self->name, TT_DESTROY);
updateObjective(self->groupName, TT_DESTROY);
if (battle.isEpic && self->killedBy == player)
{
updateObjective("EPIC_PLAYER_KILLS", TT_DESTROY);
@ -373,7 +373,7 @@ void doFighter(void)
updateCondition(self->name, TT_DESTROY);
updateCondition(self->groupName, TT_DESTROY);
/* don't fire if the opposing side is responsible */
if (self->aiFlags & AIF_SURRENDERED && self->killedBy->side == player->side)
{
@ -461,21 +461,21 @@ void damageFighter(Entity *e, int amount, long flags)
e->aiDamageTimer = FPS;
e->aiDamagePerSec += amount;
if (flags & BF_SYSTEM_DAMAGE)
{
if (e->shield > 0)
{
amount /= 2;
e->shield -= amount;
if (e->shield < 0)
{
amount = -e->shield;
}
}
if (amount >= 0)
{
e->systemPower = MAX(0, e->systemPower - amount);
@ -487,7 +487,7 @@ void damageFighter(Entity *e, int amount, long flags)
e->shield = e->maxShield = 0;
e->action = NULL;
}
playBattleSound(SND_MAG_HIT, e->x, e->y);
}
}
@ -509,13 +509,13 @@ void damageFighter(Entity *e, int amount, long flags)
if (e->shield > 0)
{
e->shield -= amount;
if (e->shield <= 0)
{
e->armourHit = 255;
e->health += e->shield;
e->shield = 0;
playBattleSound(SND_ARMOUR_HIT, e->x, e->y);
}
}
@ -534,7 +534,7 @@ void damageFighter(Entity *e, int amount, long flags)
playBattleSound(SND_SHIELD_HIT, e->x, e->y);
}
/* don't allow the shield to recharge immediately after taking a hit */
e->shieldRecharge = e->shieldRechargeRate;
@ -596,22 +596,22 @@ static void die(void)
self->action = simpleDie;
break;
}
if (self->killedBy == player && (!(self->flags & EF_NO_KILL_INC)))
{
battle.stats[STAT_ENEMIES_KILLED_PLAYER]++;
if (self->flags & EF_COMMON_FIGHTER)
{
incFighterStat(self->defName);
}
if (battle.isEpic && player->flags & EF_COMMON_FIGHTER)
{
battle.stats[STAT_EPIC_KILL_STREAK]++;
}
}
if (self->flags & EF_DROPS_ITEMS)
{
addRandomItem(self->x, self->y);
@ -688,14 +688,14 @@ void retreatEnemies(void)
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_MOVES_TO_LEADER;
e->aiFlags &= ~AIF_WANDERS;
e->aiActionTime = MIN(e->aiActionTime, FPS);
if (!game.currentMission->challengeData.isChallenge)
{
e->aiFlags |= AIF_GOAL_JUMPGATE;
@ -720,9 +720,9 @@ void retreatAllies(void)
e->aiFlags &= ~AIF_MOVES_TO_PLAYER;
e->aiFlags &= ~AIF_MOVES_TO_LEADER;
e->aiFlags &= ~AIF_WANDERS;
e->aiActionTime = MIN(e->aiActionTime, FPS);
if (!game.currentMission->challengeData.isChallenge)
{
e->aiFlags |= AIF_GOAL_JUMPGATE;
@ -751,7 +751,7 @@ Entity **getDBFighters(int *num)
{
Entity *e, **dbFighters;
int i;
i = *num = 0;
for (e = defHead.next ; e != NULL ; e = e->next)
@ -761,19 +761,19 @@ Entity **getDBFighters(int *num)
*num = *num + 1;
}
}
dbFighters = malloc(sizeof(Entity*) * *num);
for (e = defHead.next ; e != NULL ; e = e->next)
{
if (e->description != NULL)
{
dbFighters[i] = e;
i++;
}
}
return dbFighters;
}
@ -839,7 +839,7 @@ static void loadFighterDef(char *filename)
e->reloadTime = getJSONValue(root, "reloadTime", 0);
e->shieldRechargeRate = getJSONValue(root, "shieldRechargeRate", 0);
e->texture = getAtlasImage(cJSON_GetObjectItem(root, "texture")->valuestring);
if (strlen(cJSON_GetObjectItem(root, "description")->valuestring) > 0)
{
len = strlen(_(cJSON_GetObjectItem(root, "description")->valuestring)) + 1;
@ -890,7 +890,7 @@ static void loadFighterDef(char *filename)
{
e->deathType = lookup(cJSON_GetObjectItem(root, "deathType")->valuestring);
}
if (e->flags & EF_COMMON_FIGHTER)
{
addFighterStat(e->name);
@ -913,33 +913,33 @@ static void loadFighterDef(char *filename)
static void addFighterStat(char *key)
{
Tuple *t, *tail;
tail = &game.fighterStatHead;
for (t = game.fighterStatHead.next ; t != NULL ; t = t->next)
{
if (strcmp(t->key, key) == 0)
{
return;
}
tail = t;
}
t = malloc(sizeof(Tuple));
memset(t, 0, sizeof(Tuple));
tail->next = t;
STRNCPY(t->key, key, MAX_NAME_LENGTH);
t->value = 0;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Added '%s' to fighter stats", key);
}
static void incFighterStat(char *key)
{
Tuple *t;
for (t = game.fighterStatHead.next ; t != NULL ; t = t->next)
{
if (strcmp(t->key, key) == 0)
@ -962,7 +962,7 @@ void loadFighters(cJSON *node)
if (node)
{
id = 0;
node = node->child;
while (node)
@ -1018,7 +1018,7 @@ void loadFighters(cJSON *node)
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for '%s' (%s) replaced", e->name, e->defName);
}
if (e->flags & EF_DISABLED)
{
e->speed = 0;
@ -1042,10 +1042,10 @@ 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);
@ -1078,12 +1078,12 @@ void destroyFighterDefs(void)
{
e = defHead.next;
defHead.next = e->next;
if (e->description)
{
free(e->description);
}
free(e);
}
}
@ -1091,7 +1091,7 @@ void destroyFighterDefs(void)
void destroyFighterStats(void)
{
Tuple *t;
while (game.fighterStatHead.next)
{
t = game.fighterStatHead.next;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -68,7 +68,7 @@ void initHud(void)
{
memset(&hudMessageHead, 0, sizeof(HudMessage));
hudMessageTail = &hudMessageHead;
gunName[BT_NONE] = "";
gunName[BT_PARTICLE] = _("Particle Cannon");
gunName[BT_PLASMA] = _("Plasma Cannon");
@ -76,7 +76,7 @@ void initHud(void)
gunName[BT_MAG] = _("Mag Cannon");
gunName[BT_ROCKET] = _("Rockets");
gunName[BT_MISSILE] = _("Missiles");
MISSILES_TEXT = _("Missiles (%d)");
TARGET_TEXT = _("Target: %.2fkm");
NONE_TEXT = _("(None)");
@ -90,7 +90,7 @@ void initHud(void)
SUSPICION_TEXT = _("Suspicion");
REMAINING_PILOTS_TEXT = _("Remaining Pilots: %d");
WARNING_TEXT = _("WARNING: INCOMING MISSILE!");
targetPointer = getAtlasImage("gfx/hud/targetPointer.png");
targetCircle = getAtlasImage("gfx/hud/targetCircle.png");
smallFighter = getAtlasImage("gfx/hud/smallFighter.png");
@ -108,31 +108,31 @@ void initHud(void)
void doHud(void)
{
HudMessage *hudMessage, *prev;
numMessages = 0;
prev = &hudMessageHead;
for (hudMessage = hudMessageHead.next ; hudMessage != NULL ; hudMessage = hudMessage->next)
{
hudMessage->life--;
numMessages++;
if (hudMessage->life <= 0)
{
if (hudMessage == hudMessageTail)
{
hudMessageTail = prev;
}
prev->next = hudMessage->next;
free(hudMessage);
hudMessage = prev;
numMessages--;
}
prev = hudMessage;
}
}
@ -140,7 +140,7 @@ void doHud(void)
void addHudMessage(SDL_Color c, char *format, ...)
{
va_list args;
HudMessage *hudMessage = malloc(sizeof(HudMessage));
memset(hudMessage, 0, sizeof(HudMessage));
hudMessageTail->next = hudMessage;
@ -149,18 +149,18 @@ void addHudMessage(SDL_Color c, char *format, ...)
va_start(args, format);
vsprintf(hudMessageTail->message, format, args);
va_end(args);
hudMessage->color = c;
hudMessage->life = FPS * 5;
numMessages++;
while (numMessages > MAX_HUD_MESSAGES)
{
hudMessage = hudMessageHead.next;
hudMessageHead.next = hudMessage->next;
free(hudMessage);
numMessages--;
}
}
@ -170,30 +170,30 @@ void drawHud(void)
if (player->alive == ALIVE_ALIVE)
{
drawHealthBars();
drawAbilityBars();
drawPlayerTargeter();
drawWeaponInfo();
drawNumFighters();
drawObjectives();
drawDistancesInfo();
drawRadar();
drawRadarRangeWarning();
drawMissileWarning();
drawSuspicionLevel();
}
drawHudMessages();
if (battle.playerSelect)
{
drawPlayerSelect();
@ -204,11 +204,11 @@ static void drawHealthBars(void)
{
float p;
int r, g, b;
r = g = b = 0;
p = player->health;
p /= player->maxHealth;
if (p <= 0.25)
{
r = 255;
@ -222,12 +222,12 @@ static void drawHealthBars(void)
{
g = 200;
}
setAtlasColor(255, 255, 255, 255);
blit(armour, 6, 9, 0);
drawHealthShieldBar(player->health, player->maxHealth, 30, 10, r, g, b, 1);
blit(shield, 6, 29, 0);
drawHealthShieldBar(player->shield, player->maxShield, 30, 30, 0, 200, 255, 0);
}
@ -236,38 +236,38 @@ static void drawHealthShieldBar(int current, int max, int x, int y, int r, int g
{
SDL_Rect rect;
float percent = 0;
if (max > 0)
{
percent = current;
percent /= max;
if (flashLow && percent <= 0.25 && battle.stats[STAT_TIME] % FPS < 30)
{
percent = 0;
}
}
rect.x = x;
rect.y = y;
rect.w = 250;
rect.h = 12;
SDL_SetRenderDrawColor(app.renderer, r / 2, g / 2, b / 2, 255);
SDL_RenderFillRect(app.renderer, &rect);
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(app.renderer, &rect);
if (current > 0)
{
rect.x += 2;
rect.y += 2;
rect.w -= 4;
rect.h -= 4;
rect.w *= percent;
SDL_SetRenderDrawColor(app.renderer, r, g, b, 255);
SDL_RenderFillRect(app.renderer, &rect);
}
@ -276,10 +276,10 @@ static void drawHealthShieldBar(int current, int max, int x, int y, int r, int g
static void drawAbilityBars(void)
{
setAtlasColor(255, 255, 255, 255);
blit(boost, 6, 49, 0);
drawBoostECMBar(battle.boostTimer, BOOST_RECHARGE_TIME, 30, 50, 128, 128, 255);
blit(ecm, 155, 49, 0);
drawBoostECMBar(battle.ecmTimer, ECM_RECHARGE_TIME, 175, 50, 255, 128, 0);
}
@ -287,35 +287,35 @@ static void drawAbilityBars(void)
static void drawBoostECMBar(int current, int max, int x, int y, int r, int g, int b)
{
SDL_Rect rect;
float percent = current;
percent /= max;
rect.x = x;
rect.y = y;
rect.w = 105;
rect.h = 12;
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 255);
SDL_RenderFillRect(app.renderer, &rect);
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(app.renderer, &rect);
rect.x += 2;
rect.y += 2;
rect.w -= 4;
rect.h -= 4;
rect.w *= percent;
if (current < max)
{
r /= 2;
g /= 2;
b /= 2;
}
SDL_SetRenderDrawColor(app.renderer, r, g, b, 255);
SDL_RenderFillRect(app.renderer, &rect);
}
@ -323,15 +323,15 @@ static void drawBoostECMBar(int current, int max, int x, int y, int r, int g, in
static void drawWeaponInfo(void)
{
int i, y;
setAtlasColor(255, 255, 255, 255);
if (!player->combinedGuns)
{
if (battle.numPlayerGuns)
{
y = 70;
for (i = 0 ; i < BT_MAX ; i++)
{
if (playerHasGun(i))
@ -339,14 +339,14 @@ static void drawWeaponInfo(void)
if (player->selectedGunType == i)
{
drawText(30, y, 14, TA_LEFT, colors.green, "%s", gunName[i]);
blit(nextGun, 8, y + 5, 0);
}
else
{
drawText(30, y, 14, TA_LEFT, colors.darkGrey, "%s", gunName[i]);
}
y += 20;
}
}
@ -360,7 +360,7 @@ static void drawWeaponInfo(void)
{
drawText(30, 70, 14, TA_LEFT, colors.white, COMBINED_TEXT);
}
drawText(280, 70, 14, TA_RIGHT, colors.white, MISSILES_TEXT, player->missiles);
}
@ -368,7 +368,7 @@ static void drawPlayerTargeter(void)
{
float angle;
int x, y;
if (player->target || battle.missionTarget || jumpgateEnabled() || battle.messageSpeaker)
{
if (player->target)
@ -387,63 +387,63 @@ static void drawPlayerTargeter(void)
{
setAtlasColor(255, 255, 0, 255);
}
blit(targetCircle, player->x - battle.camera.x, player->y - battle.camera.y, 1);
}
if (player->target)
{
angle = getAngle(player->x, player->y, player->target->x, player->target->y);
x = player->x;
y = player->y;
x += sin(TO_RAIDANS(angle)) * 45;
y += -cos(TO_RAIDANS(angle)) * 45;
setAtlasColor(255, 0, 0, 255);
blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle);
}
if (battle.missionTarget)
{
angle = getAngle(player->x, player->y, battle.missionTarget->x, battle.missionTarget->y);
x = player->x;
y = player->y;
x += sin(TO_RAIDANS(angle)) * 45;
y += -cos(TO_RAIDANS(angle)) * 45;
setAtlasColor(0, 255, 0, 255);
blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle);
}
if (jumpgateEnabled())
{
angle = getAngle(player->x, player->y, battle.jumpgate->x, battle.jumpgate->y);
x = player->x;
y = player->y;
x += sin(TO_RAIDANS(angle)) * 45;
y += -cos(TO_RAIDANS(angle)) * 45;
setAtlasColor(255, 255, 0, 255);
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;
setAtlasColor(255, 255, 255, 255);
blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle);
}
}
@ -454,7 +454,7 @@ static void drawNumFighters(void)
setAtlasColor(150, 200, 255, 255);
blit(smallFighter, (app.winWidth / 2) - 185, 15, 0);
drawText((app.winWidth / 2) - 160, 11, 14, TA_LEFT, colors.white, battle.numAllies < 1000 ? "(%d)" : "(999+)", battle.numAllies);
/* Enemies */
setAtlasColor(255, 100, 100, 255);
blit(smallFighter, (app.winWidth / 2) + 170, 15, 0);
@ -464,14 +464,14 @@ static void drawNumFighters(void)
static void drawObjectives(void)
{
int timeRemaining;
setAtlasColor(255, 255, 255, 255);
if (!game.currentMission->challengeData.isChallenge)
{
blit(objectives, (app.winWidth / 2) - 50, 14, 0);
drawText(app.winWidth / 2, 10, 16, TA_CENTER, colors.white, "%d / %d", battle.numObjectivesComplete, (battle.numObjectivesTotal + battle.numConditions));
if (battle.isEpic && battle.epicLives > 0)
{
drawText(app.winWidth / 2, 35, 14, TA_CENTER, colors.white, REMAINING_PILOTS_TEXT, battle.epicLives - 1);
@ -482,7 +482,7 @@ static void drawObjectives(void)
if (game.currentMission->challengeData.timeLimit)
{
timeRemaining = game.currentMission->challengeData.timeLimit - battle.stats[STAT_TIME];
blit(clockIcon, (app.winWidth / 2) - 50, 14, 0);
drawText(app.winWidth / 2, 10, 16, TA_CENTER, (timeRemaining < 11 * FPS) ? colors.red : colors.white, timeToString(timeRemaining, 0));
}
@ -491,7 +491,7 @@ static void drawObjectives(void)
drawText(app.winWidth / 2, 10, 16, TA_CENTER, colors.white, timeToString(battle.stats[STAT_TIME], 0));
blit(clockIcon, (app.winWidth / 2) - 50, 14, 0);
}
if (game.currentMission->challengeData.killLimit)
{
drawText(app.winWidth / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ENEMIES_KILLED_PLAYER] + battle.stats[STAT_ENEMIES_DISABLED], game.currentMission->challengeData.killLimit);
@ -530,14 +530,14 @@ static void drawObjectives(void)
static float distanceToKM(int x1, int y1, int x2, int y2)
{
float distance;
distance = getDistance(x1, y1, x2, y2);
/* 2px = 1m approx */
distance /= 2;
distance = (int)distance;
distance /= 1000;
return distance;
}
@ -545,9 +545,9 @@ static void drawDistancesInfo(void)
{
int y;
float distance;
y = 11;
if (player->target)
{
if (player->target->flags & EF_AI_LEADER && player->target->speed > 0)
@ -558,40 +558,40 @@ static void drawDistancesInfo(void)
{
drawText(app.winWidth - 15, y, 18, TA_RIGHT, colors.red, player->target->name);
}
y += 30;
distance = distanceToKM(player->x, player->y, player->target->x, player->target->y);
drawText(app.winWidth - 15, y, 14, TA_RIGHT, colors.red, TARGET_DIST_TEXT, distance);
y += 25;
}
if (battle.missionTarget)
{
distance = distanceToKM(player->x, player->y, battle.missionTarget->x, battle.missionTarget->y);
drawText(app.winWidth - 15, y, 14, TA_RIGHT, colors.green, OBJECTIVE_DIST_TEXT, distance);
y += 25;
}
if (jumpgateEnabled())
{
distance = distanceToKM(player->x, player->y, battle.jumpgate->x, battle.jumpgate->y);
drawText(app.winWidth - 15, y, 14, TA_RIGHT, colors.yellow, JUMPGATE_DIST_TEXT, distance);
y += 25;
}
if (battle.messageSpeaker)
{
distance = distanceToKM(player->x, player->y, battle.messageSpeaker->x, battle.messageSpeaker->y);
drawText(app.winWidth - 15, y, 14, TA_RIGHT, colors.white, "%s: %.2fkm", battle.messageSpeaker->name, distance);
y += 25;
}
}
@ -600,11 +600,11 @@ static void drawHudMessages(void)
{
HudMessage *hudMessage;
int y = app.winHeight - 25;
for (hudMessage = hudMessageHead.next ; hudMessage != NULL ; hudMessage = hudMessage->next)
{
drawText(10, y, 14, TA_LEFT, hudMessage->color, hudMessage->message);
y -= 25;
}
}
@ -615,20 +615,20 @@ static void drawPlayerSelect(void)
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
setAtlasColor(0, 200, 255, 255);
blit(targetCircle, player->x - battle.camera.x, player->y - battle.camera.y, 1);
drawText(app.winWidth / 2, 500, 28, TA_CENTER, colors.white, NEW_FIGHTER_TEXT);
if (player->health > 0)
{
drawText(app.winWidth / 2, 540, 20, TA_CENTER, colors.white, "%s (%d%% / %d%%)", player->defName, getPercent(player->health, player->maxHealth), getPercent(player->shield, player->maxShield));
}
setAtlasColor(255, 255, 255, 255);
blit(arrowLeft, (app.winWidth / 2) - 200, 520, 1);
blit(arrowRight, (app.winWidth / 2) + 200, 520, 1);
}
@ -636,33 +636,33 @@ static void drawPlayerSelect(void)
static void drawSuspicionLevel(void)
{
SDL_Rect r;
if (battle.hasSuspicionLevel && !battle.incomingMissile)
{
battle.suspicionLevel = MIN(battle.suspicionLevel, MAX_SUSPICION_LEVEL);
drawText((app.winWidth / 2) - 150, app.winHeight - 60, 18, TA_RIGHT, colors.white, SUSPICION_TEXT);
r.x = (app.winWidth / 2) - 140;
r.y = app.winHeight - 58;
r.w = 400;
r.h = 20;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, &r);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(app.renderer, 192, 192, 192, 255);
SDL_RenderDrawRect(app.renderer, &r);
r.x += 2;
r.y += 2;
r.w -= 4;
r.h -= 4;
r.w = MAX((r.w / MAX_SUSPICION_LEVEL) * battle.suspicionLevel, 0);
if (battle.suspicionLevel < (MAX_SUSPICION_LEVEL * 0.5))
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
@ -675,9 +675,9 @@ static void drawSuspicionLevel(void)
{
SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255);
}
SDL_RenderFillRect(app.renderer, &r);
drawText(r.x + r.w + 7, app.winHeight - 57, 12, TA_LEFT, colors.white, "%d%%", (battle.suspicionLevel > 0) ? getPercent(battle.suspicionLevel, MAX_SUSPICION_LEVEL) : 0);
}
}
@ -693,7 +693,7 @@ static void drawMissileWarning(void)
void resetHud(void)
{
HudMessage *hudMessage;
while (hudMessageHead.next)
{
hudMessage = hudMessageHead.next;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -50,7 +50,7 @@ void loadItemDefs(void)
e->texture = getAtlasImage(cJSON_GetObjectItem(node, "texture")->valuestring);
e->health = e->maxHealth = FPS;
e->flags = EF_NO_HEALTH_BAR;
e->w = e->texture->rect.w;
e->h = e->texture->rect.h;
@ -65,7 +65,7 @@ void loadItemDefs(void)
Entity *spawnItem(char *name)
{
Entity *e, *def, *item;
def = NULL;
item = spawnEntity();
@ -86,9 +86,9 @@ Entity *spawnItem(char *name)
}
memcpy(item, def, sizeof(Entity));
item->next = NULL;
item->action = action;
return item;
@ -97,7 +97,7 @@ Entity *spawnItem(char *name)
void addRandomItem(int x, int y)
{
Entity *item;
item = spawnItem("RANDOM");
item->x = x;
item->y = y;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -33,13 +33,13 @@ static float portalAngle;
Entity *spawnJumpgate(int side, long flags)
{
Entity *jumpgate;
if (battle.jumpgate)
{
printf("ERROR: Only one jumpgate is allowed\n");
exit(1);
}
jumpgate = spawnEntity();
jumpgate->type = ET_JUMPGATE;
jumpgate->health = jumpgate->maxHealth = 1;
@ -48,20 +48,20 @@ Entity *spawnJumpgate(int side, long flags)
jumpgate->draw = draw;
jumpgate->side = side;
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;
}
addNodes(jumpgate, flags);
portal = getAtlasImage("gfx/entities/portal.png");
portalAngle = 0;
jumpgate->w = jumpgate->texture->rect.w;
jumpgate->h = jumpgate->texture->rect.h;
battle.jumpgate = jumpgate;
return jumpgate;
@ -72,9 +72,9 @@ static void addNodes(Entity *jumpgate, long flags)
Entity *node;
AtlasImage *nodeTexture;
int i;
nodeTexture = getAtlasImage("gfx/entities/jumpgateNode.png");
for (i = 0 ; i < 360 ; i += 36)
{
node = spawnEntity();
@ -90,20 +90,20 @@ static void addNodes(Entity *jumpgate, long flags)
node->die = nodeDie;
node->w = node->texture->rect.w;
node->h = node->texture->rect.h;
if (jumpgate->side == SIDE_NONE)
{
node->flags |= EF_NO_HEALTH_BAR;
}
if (flags != -1)
{
node->flags = flags;
}
jumpgate->maxHealth++;
}
jumpgate->health = jumpgate->maxHealth;
}
@ -117,7 +117,7 @@ static void nodeDie(void)
if (--battle.jumpgate->health == 1)
{
battle.jumpgate->flags |= EF_DISABLED;
updateObjective("Jumpgate", TT_DESTROY);
updateCondition("Jumpgate", TT_DESTROY);
}
@ -133,7 +133,7 @@ int jumpgateEnabled(void)
void activateJumpgate(int activate)
{
Entity *e;
if (battle.jumpgate && battle.jumpgate->health > 1)
{
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
@ -158,19 +158,19 @@ static void think(void)
self->thinkTime = 4;
self->angle += 0.1;
if (self->angle >= 360)
{
self->angle -= 360;
}
if (jumpgateEnabled())
{
handleFleeingEntities();
}
portalAngle += 2;
if (portalAngle >= 360)
{
portalAngle -= 360;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -23,20 +23,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void doLocations(void)
{
Location *l, *prev;
prev = &battle.locationHead;
for (l = battle.locationHead.next ; l != NULL ; l = l->next)
{
if (l->active && getDistance(player->x, player->y, l->x, l->y) <= l->size)
{
runScriptFunction(l->name);
prev->next = l->next;
free(l);
l = prev;
}
prev = l;
}
}
@ -44,7 +44,7 @@ void doLocations(void)
void drawLocations(void)
{
Location *l;
for (l = battle.locationHead.next ; l != NULL ; l = l->next)
{
if (l->active)
@ -58,9 +58,9 @@ void activateLocations(char *locations)
{
char *token;
Location *l;
token = strtok(locations, ";");
while (token)
{
for (l = battle.locationHead.next ; l != NULL ; l = l->next)
@ -70,7 +70,7 @@ void activateLocations(char *locations)
l->active = 1;
}
}
token = strtok(NULL, ";");
}
}
@ -82,7 +82,7 @@ void createChristabelLocation(void)
{
Location *l;
Entity *e;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (strcmp(e->name, "Christabel") == 0)
@ -100,7 +100,7 @@ void createChristabelLocation(void)
l->x -= l->size / 2;
l->y -= l->size / 2;
return;
}
}
@ -130,7 +130,7 @@ void loadLocations(cJSON *node)
l->x += (SCREEN_WIDTH / 2);
l->y += (SCREEN_HEIGHT / 2);
node = node->next;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -31,7 +31,7 @@ void initMessageBox(void)
{
memset(&head, 0, sizeof(MessageBox));
tail = &head;
lastWingmate = NULL;
}
@ -40,22 +40,22 @@ void addMessageBox(char *title, char *body, int type)
MessageBox *msg;
int isFirst;
float time;
isFirst = (tail == &head);
msg = malloc(sizeof(MessageBox));
memset(msg, 0, sizeof(MessageBox));
tail->next = msg;
tail = msg;
time = 0.075 * strlen(body);
time = MIN(MAX(time, 3), 7);
STRNCPY(msg->title, title, MAX_NAME_LENGTH);
STRNCPY(msg->body, body, MAX_DESCRIPTION_LENGTH);
msg->time = time * FPS;
msg->type = type;
if (isFirst)
{
nextMessage();
@ -65,9 +65,9 @@ void addMessageBox(char *title, char *body, int type)
void doMessageBox(void)
{
MessageBox *msg;
msg = head.next;
if (msg)
{
if (--msg->time <= -(FPS / 4))
@ -76,13 +76,13 @@ void doMessageBox(void)
{
tail = &head;
}
head.next = msg->next;
free(msg);
msg = &head;
battle.messageSpeaker = NULL;
if (head.next)
{
nextMessage();
@ -94,7 +94,7 @@ void doMessageBox(void)
static void calculateMessageBoxHeight(MessageBox *msg)
{
app.textWidth = MSG_BOX_TEXT_WIDTH;
if (msg->type == MB_PANDORAN)
{
useFont("khosrau");
@ -103,11 +103,11 @@ static void calculateMessageBoxHeight(MessageBox *msg)
{
useFont("roboto");
}
msg->height = getWrappedTextHeight(msg->body, 18);
app.textWidth = 0;
useFont("roboto");
}
@ -120,21 +120,21 @@ void drawMessageBox(void)
{
MessageBox *msg = head.next;
SDL_Rect r;
if (msg && msg->time > 0)
{
if (!msg->height)
{
calculateMessageBoxHeight(msg);
}
r.y = 50;
r.w = 650;
r.h = msg->height + 40;
r.x = (app.winWidth - r.w) / 2;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
if (msg->type == MB_IMPORTANT)
{
SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 64);
@ -144,15 +144,15 @@ void drawMessageBox(void)
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
}
SDL_RenderFillRect(app.renderer, &r);
SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 128);
SDL_RenderDrawRect(app.renderer, &r);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
drawText(r.x + 10, r.y + 5, 18, TA_LEFT, colors.cyan, msg->title);
app.textWidth = MSG_BOX_TEXT_WIDTH;
if (msg->type == MB_PANDORAN)
{
useFont("khosrau");
@ -161,12 +161,12 @@ void drawMessageBox(void)
{
useFont("roboto");
}
drawText(r.x + 10, r.y + 30, 18, TA_LEFT, (msg->type != MB_IMPORTANT) ? colors.white : colors.red, msg->body);
app.textWidth = 0;
}
useFont("roboto");
}
@ -174,13 +174,13 @@ 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)
@ -190,11 +190,11 @@ static void nextMessage(void)
battle.messageSpeaker = lastWingmate = e;
return;
}
if (isWingmate && e->side == player->side && e->type == ET_FIGHTER && e->speed > 0)
{
wingmate = e;
if (rand() % 2 && e != lastWingmate)
{
battle.messageSpeaker = lastWingmate = e;
@ -203,20 +203,20 @@ static void nextMessage(void)
}
}
}
battle.messageSpeaker = wingmate;
}
void resetMessageBox(void)
{
MessageBox *messageBox;
while (head.next)
{
messageBox = head.next;
head.next = messageBox->next;
free(messageBox);
}
tail = &head;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -33,7 +33,7 @@ static AtlasImage *shadowMine = NULL;
Entity *spawnMine(int type)
{
Entity *mine = spawnEntity();
if (!mineWarning)
{
shadowMine = getAtlasImage("gfx/entities/shadowMine.png");
@ -50,14 +50,14 @@ Entity *spawnMine(int type)
mine->action = think;
mine->die = die;
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)
{
mine->flags &= ~EF_NO_PLAYER_TARGET;
mine->speed = 100 + rand() % 100;
mine->speed *= 0.01;
}
mine->w = mine->texture->rect.w;
mine->h = mine->texture->rect.h;
@ -67,17 +67,17 @@ Entity *spawnMine(int type)
static void think(void)
{
self->texture = (self->type == ET_MINE) ? mineNormal : shadowMine;
self->angle += 0.1;
if (self->angle >= 360)
{
self->angle -= 360;
}
self->dx *= 0.99;
self->dy *= 0.99;
if (self->type == ET_MINE)
{
lookForFighters();
@ -86,11 +86,11 @@ static void think(void)
{
lookForPlayer();
}
if (self->systemPower < SYSTEM_POWER && battle.stats[STAT_TIME] % 8 < 4)
{
playBattleSound(SND_MINE_WARNING, self->x, self->y);
self->texture = mineWarning;
}
}
@ -107,16 +107,16 @@ static void lookForFighters(void)
if (e->side != self->side && e->health > 0 && e->type == ET_FIGHTER && getDistance(self->x, self->y, e->x, e->y) <= TRIGGER_RANGE)
{
self->systemPower--;
if (self->systemPower <= 0)
{
self->health = 0;
}
return;
}
}
self->systemPower = SYSTEM_POWER;
}
@ -124,11 +124,11 @@ static void lookForPlayer(void)
{
float dx, dy, norm;
int distance;
if (player->alive == ALIVE_ALIVE)
{
distance = getDistance(self->x, self->y, player->x, player->y);
if (distance < SCREEN_WIDTH * 2)
{
dx = player->x - self->x;
@ -140,37 +140,37 @@ static void lookForPlayer(void)
{
return;
}
dx = rand() % 1000;
dx -= rand() % 1000;
dy = rand() % 1000;
dy -= rand() % 1000;
self->aiActionTime = FPS * (5 + (rand() % 15));
}
norm = sqrt(dx * dx + dy * dy);
dx /= norm;
dy /= norm;
self->dx = dx * self->speed;
self->dy = dy * self->speed;
if (distance <= TRIGGER_RANGE)
{
self->systemPower--;
if (self->systemPower <= 0)
{
self->health = 0;
}
return;
}
}
self->systemPower = SYSTEM_POWER;
}
@ -180,17 +180,17 @@ static void die(void)
{
battle.stats[STAT_MINES_DESTROYED]++;
}
addMineExplosion();
doSplashDamage();
playBattleSound(SND_EXPLOSION_5, self->x, self->y);
self->alive = ALIVE_DEAD;
updateObjective(self->name, TT_DESTROY);
runScriptFunction("MINES_DESTROYED %d", battle.stats[STAT_MINES_DESTROYED]);
}
@ -201,7 +201,7 @@ static void doSplashDamage(void)
float damage, percent;
candidates = getAllEntsInRadius(self->x, self->y, DAMAGE_RANGE, self);
kills = 0;
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
@ -209,20 +209,20 @@ static void doSplashDamage(void)
if (e->health > 0 && (e->type == ET_FIGHTER || e->type == ET_MINE) && !(e->flags & EF_IMMORTAL))
{
dist = getDistance(self->x, self->y, e->x, e->y);
if (dist <= DAMAGE_RANGE)
{
percent = dist;
percent /= DAMAGE_RANGE;
percent = 1 - percent;
damage = DAMAGE_RANGE;
damage *= percent;
if (e->type == ET_FIGHTER)
{
damageFighter(e, damage, 0);
if (self->killedBy == player && e != player && e->health <= 0)
{
kills++;
@ -232,14 +232,14 @@ static void doSplashDamage(void)
{
e->dx = e->x - self->x;
e->dy = e->y - self->y;
e->dx *= 0.01;
e->dy *= 0.01;
}
}
}
}
if (kills >= 2)
{
awardTrophy("2_BIRDS");

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -37,16 +37,16 @@ static char *TIME_LIMIT_TEXT;
void initMissionInfo(void)
{
int isChallenge = game.currentMission->challengeData.isChallenge;
objectiveStatus[OS_INCOMPLETE] = _("Incomplete");
objectiveStatus[OS_COMPLETE] = _("Complete");
objectiveStatus[OS_FAILED] = _("Failed");
objectiveStatus[OS_CONDITION] = _("Condition");
OBJECTIVES_TEXT = _("OBJECTIVES");
NONE_TEXT = _("(none)");
TIME_LIMIT_TEXT = _("Time Limit: %s");
missionStartTexture = !isChallenge ? getAtlasImage("gfx/battle/missionStart.png") : getAtlasImage("gfx/battle/challengeStart.png");
missionInProgressTexture = !isChallenge ? getAtlasImage("gfx/battle/missionInProgress.png") : getAtlasImage("gfx/battle/challengeInProgress.png");
missionCompleteTexture = !isChallenge ? getAtlasImage("gfx/battle/missionComplete.png") : getAtlasImage("gfx/battle/challengeComplete.png");
@ -57,19 +57,19 @@ void initMissionInfo(void)
void drawMissionInfo(void)
{
setAtlasColor(255, 255, 255, 255);
switch (battle.status)
{
case MS_START:
drawMissionSummary(missionStartTexture);
drawWidgets("startBattle");
break;
case MS_PAUSED:
drawMissionSummary(missionInProgressTexture);
drawWidgets("startBattle");
break;
case MS_COMPLETE:
case MS_FAILED:
if (!battle.unwinnable)
@ -77,7 +77,7 @@ void drawMissionInfo(void)
if (battle.missionFinishedTimer <= -FPS)
{
drawMissionSummary(battle.status == MS_COMPLETE ? missionCompleteTexture : missionFailedTexture);
if (battle.missionFinishedTimer <= -(FPS * 2))
{
drawWidgets(battle.status == MS_COMPLETE ? "battleWon" : "battleLost");
@ -85,12 +85,12 @@ void drawMissionInfo(void)
}
}
break;
case MS_TIME_UP:
if (battle.missionFinishedTimer <= -FPS)
{
drawMissionSummary(timeUpTexture);
if (battle.missionFinishedTimer <= -(FPS * 2))
{
drawWidgets("battleWon");
@ -98,7 +98,7 @@ void drawMissionInfo(void)
}
break;
}
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -108,11 +108,11 @@ static void drawMissionSummary(AtlasImage *header)
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
blit(header, UI_WIDTH / 2, 150, 1);
if (!game.currentMission->challengeData.isChallenge)
{
drawObjectives();
@ -128,50 +128,50 @@ static void drawObjectives(void)
Objective *o;
SDL_Color color;
int y = 215;
drawText(UI_WIDTH / 2, y, 28, TA_CENTER, colors.white, OBJECTIVES_TEXT);
y += 10;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->active)
{
y += 50;
switch (o->status)
{
case OS_INCOMPLETE:
color = colors.white;
break;
case OS_COMPLETE:
color = colors.green;
break;
case OS_FAILED:
color = colors.red;
break;
}
drawText(UI_WIDTH / 2 - 100, y, 22, TA_RIGHT, colors.white, o->description);
if (o->targetValue > 1 && !o->hideNumbers)
{
drawText(UI_WIDTH / 2, y, 22, TA_CENTER, colors.white, "%d / %d", o->currentValue, o->targetValue);
}
drawText(UI_WIDTH / 2 + 100, y, 22, TA_LEFT, color, objectiveStatus[o->status]);
}
}
if (!battle.objectiveHead.next)
{
y += 50;
drawText(UI_WIDTH / 2, y, 22, TA_CENTER, colors.white, NONE_TEXT);
}
y += 75;
}
@ -182,43 +182,43 @@ static void drawChallenges(void)
char *challengeStatus;
SDL_Color color;
int y = 215;
drawText(UI_WIDTH / 2, y, 24, TA_CENTER, colors.white, game.currentMission->description);
if (battle.status == MS_START && game.currentMission->challengeData.timeLimit)
{
y+= 50;
drawText(UI_WIDTH / 2, y, 20, TA_CENTER, colors.white, TIME_LIMIT_TEXT, timeToString(game.currentMission->challengeData.timeLimit, 0));
}
y += 25;
for (i = 0 ; i < MAX_CHALLENGES ; i++)
{
c = game.currentMission->challengeData.challenges[i];
if (c)
{
y += 50;
color = colors.white;
challengeStatus = _("Incomplete");
if (c->passed)
{
color = colors.green;
challengeStatus = _("Complete");
}
else if (battle.status == MS_COMPLETE ||battle.status == MS_FAILED)
{
color = colors.red;
challengeStatus = _("Failed");
}
drawText(UI_WIDTH / 2 - 50, y, 22, TA_RIGHT, colors.white, "%s", getChallengeDescription(c));
drawText(UI_WIDTH / 2 + 50, y, 22, TA_LEFT, color, challengeStatus);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -27,11 +27,11 @@ void doObjectives(void)
int objectiveFailed;
int hasHidden;
Objective *o;
battle.numObjectivesComplete = battle.numObjectivesTotal = battle.numConditions = 0;
objectiveFailed = 0;
hasHidden = 0;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->active)
@ -44,17 +44,17 @@ void doObjectives(void)
{
battle.numConditions++;
}
if (o->isEliminateAll && o->status != OS_COMPLETE && !battle.hasThreats)
{
addHudMessage(colors.green, _("%s - Objective Complete!"), o->description);
o->currentValue = o->targetValue;
o->status = OS_COMPLETE;
runScriptFunction("OBJECTIVES_COMPLETE %d", battle.numObjectivesComplete + 1);
playSound(SND_OBJECTIVE_COMPLETE);
}
}
@ -62,7 +62,7 @@ void doObjectives(void)
{
hasHidden = 1;
}
if (o->currentValue == o->targetValue)
{
switch (o->status)
@ -70,14 +70,14 @@ void doObjectives(void)
case OS_COMPLETE:
battle.numObjectivesComplete++;
break;
case OS_FAILED:
objectiveFailed = 1;
break;
}
}
}
if (battle.status == MS_IN_PROGRESS)
{
if (!hasHidden && battle.numObjectivesTotal > 0 && battle.numObjectivesComplete == battle.numObjectivesTotal)
@ -85,16 +85,16 @@ void doObjectives(void)
if (fireObjectivesComplete)
{
fireObjectivesComplete = 0;
runScriptFunction("ALL_OBJECTIVES_COMPLETE");
}
if (!battle.manualComplete)
{
completeMission();
}
}
if (objectiveFailed)
{
failMission();
@ -106,13 +106,13 @@ void updateObjective(char *name, int type)
{
Objective *o;
int completed, hasHidden;
if (strlen(name))
{
completed = battle.numObjectivesComplete;
hasHidden = 0;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->active && o->status != OS_COMPLETE)
@ -120,7 +120,7 @@ void updateObjective(char *name, int type)
if (!o->isEliminateAll && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0)
{
o->currentValue++;
if (!o->hideNumbers)
{
if (o->targetValue - o->currentValue <= 10)
@ -132,32 +132,32 @@ void updateObjective(char *name, int type)
addHudMessage(colors.cyan, "%s - %d / %d", o->description, o->currentValue, o->targetValue);
}
}
if (o->currentValue == o->targetValue)
{
addHudMessage(colors.green, _("%s - Objective Complete!"), o->description);
runScriptFunction(o->description);
o->status = OS_COMPLETE;
runScriptFunction("OBJECTIVES_COMPLETE %d", ++completed);
playSound(SND_OBJECTIVE_COMPLETE);
}
}
}
if (!o->active)
{
hasHidden = 1;
}
}
if (completed == battle.numObjectivesTotal && !hasHidden && fireObjectivesComplete)
{
fireObjectivesComplete = 0;
runScriptFunction("ALL_OBJECTIVES_COMPLETE");
}
}
@ -166,20 +166,20 @@ void updateObjective(char *name, int type)
void adjustObjectiveTargetValue(char *name, int type, int amount)
{
Objective *o;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->active && !o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0)
{
o->targetValue += amount;
o->currentValue = MIN(o->currentValue, o->targetValue);
if (o->currentValue >= o->targetValue && o->targetValue > 0)
{
o->status = OS_COMPLETE;
addHudMessage(colors.green, _("%s - Objective Complete!"), o->description);
playSound(SND_OBJECTIVE_COMPLETE);
}
}
@ -189,7 +189,7 @@ void adjustObjectiveTargetValue(char *name, int type, int amount)
void updateCondition(char *name, int type)
{
Objective *o;
if (strlen(name))
{
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
@ -197,7 +197,7 @@ void updateCondition(char *name, int type)
if (o->active && o->isCondition && o->targetType == type && o->currentValue < o->targetValue && strcmp(o->targetName, name) == 0)
{
o->currentValue++;
if (o->currentValue == o->targetValue)
{
o->status = OS_FAILED;
@ -216,7 +216,7 @@ void updateCondition(char *name, int type)
void completeAllObjectives(void)
{
Objective *o;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
o->status = OS_COMPLETE;
@ -226,13 +226,13 @@ void completeAllObjectives(void)
void completeConditions(void)
{
Objective *o;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->isCondition)
{
o->currentValue = o->targetValue;
o->status = OS_COMPLETE;
}
}
@ -242,7 +242,7 @@ void completeConditions(void)
void failIncompleteObjectives(void)
{
Objective *o;
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
{
if (o->status != OS_COMPLETE)
@ -257,11 +257,11 @@ void activateObjectives(char *objectives)
char *token;
Objective *o;
int activated;
activated = 0;
token = strtok(objectives, ";");
while (token)
{
for (o = battle.objectiveHead.next ; o != NULL ; o = o->next)
@ -269,24 +269,24 @@ void activateObjectives(char *objectives)
if (strcmp(token, o->id) == 0)
{
addHudMessage(colors.cyan, _("New Objective : %s"), o->description);
o->active = 1;
/* prevent race condition */
doObjectives();
if (o->isEliminateAll)
{
updateObjective(o->targetName, o->targetType);
}
activated = 1;
}
}
token = strtok(NULL, ";");
}
if (activated)
{
playSound(SND_NEW_OBJECTIVE);
@ -326,7 +326,7 @@ void loadObjectives(cJSON *node)
node = node->next;
}
}
fireObjectivesComplete = 1;
}
@ -334,12 +334,12 @@ void addEpicLivesObjective(void)
{
Objective *o;
char id[MAX_DESCRIPTION_LENGTH];
o = malloc(sizeof(Objective));
memset(o, 0, sizeof(Objective));
battle.objectiveTail->next = o;
battle.objectiveTail = o;
sprintf(id, _("Do not lose more than %d pilots"), battle.epicLives);
STRNCPY(o->id, id, MAX_DESCRIPTION_LENGTH);
@ -355,12 +355,12 @@ void addEpicKillsObjective(void)
{
Objective *o;
char id[MAX_DESCRIPTION_LENGTH];
o = malloc(sizeof(Objective));
memset(o, 0, sizeof(Objective));
battle.objectiveTail->next = o;
battle.objectiveTail = o;
sprintf(id, _("Destroy at least %d enemy fighters"), battle.epicKills);
STRNCPY(o->id, id, MAX_DESCRIPTION_LENGTH);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -81,30 +81,30 @@ void initPlayer(void)
{
player->selectedGunType = 0;
}
setPilotName();
player->action = NULL;
battle.boostTimer = BOOST_RECHARGE_TIME;
battle.ecmTimer = ECM_RECHARGE_TIME;
player->flags |= EF_NO_HEALTH_BAR;
player->flags &= ~EF_IMMORTAL;
player->target = NULL;
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;
}
static void setPilotName(void)
{
int i, pos;
pos = -1;
for (i = 0 ; i < strlen(game.currentMission->pilot) ; i++)
{
if (game.currentMission->pilot[i] == ' ')
@ -112,34 +112,34 @@ static void setPilotName(void)
pos = i;
}
}
memset(player->name, '\0', MAX_NAME_LENGTH);
if (pos != -1)
{
memcpy(player->name, game.currentMission->pilot + pos + 1, strlen(game.currentMission->pilot) - pos - 1);
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Pilot name = '%s'", player->name);
}
void doPlayer(void)
{
self = player;
rechargeBoostECM();
if (game.currentMission->challengeData.isChallenge)
{
applyRestrictions();
}
if (player->alive == ALIVE_ALIVE && player->systemPower > 0)
{
handleKeyboard();
handleMouse();
handleSuspicionLevel();
if (!player->target || player->target->health <= 0 || player->target->systemPower <= 0 || targetOutOfRange())
@ -157,22 +157,22 @@ void doPlayer(void)
if (!game.currentMission->challengeData.allowPlayerDeath)
{
updateDeathStats();
failMission();
}
}
else if (!battle.isEpic)
{
updateDeathStats();
failMission();
}
else if (player->health == -FPS)
{
updateDeathStats();
updateCondition("PLAYER", TT_DESTROY);
if (battle.status == MS_IN_PROGRESS)
{
initPlayerSelect();
@ -189,7 +189,7 @@ void doPlayer(void)
{
player->missiles = 999;
}
/* really only used in challenge mode */
if (player->systemPower <= 0 && battle.status == MS_IN_PROGRESS)
{
@ -209,7 +209,7 @@ void doPlayer(void)
static void updateDeathStats(void)
{
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)
{
@ -220,14 +220,14 @@ static void updateDeathStats(void)
static void rechargeBoostECM(void)
{
int boostTimer, ecmTimer;
boostTimer = battle.boostTimer;
battle.boostTimer = MIN(battle.boostTimer + 1, BOOST_RECHARGE_TIME);
if (boostTimer < BOOST_RECHARGE_TIME && battle.boostTimer == BOOST_RECHARGE_TIME)
{
playSound(SND_RECHARGED);
}
ecmTimer = battle.ecmTimer;
battle.ecmTimer = MIN(battle.ecmTimer + 1, ECM_RECHARGE_TIME);
if (ecmTimer < ECM_RECHARGE_TIME && battle.ecmTimer == ECM_RECHARGE_TIME)
@ -247,17 +247,17 @@ static void applyRestrictions(void)
{
player->missiles = 0;
}
if (game.currentMission->challengeData.noBoost)
{
battle.boostTimer = 0;
}
if (game.currentMission->challengeData.noECM)
{
battle.ecmTimer = 0;
}
if (game.currentMission->challengeData.noGuns)
{
player->reload = 1;
@ -342,7 +342,7 @@ static void handleKeyboard(void)
static void handleMouse(void)
{
faceMouse();
if (battle.status == MS_IN_PROGRESS)
{
if (isControl(CONTROL_FIRE) && !player->reload && player->guns[0].type)
@ -355,13 +355,13 @@ static void handleMouse(void)
{
fireRocket(player);
}
if (battle.hasSuspicionLevel && !battle.numEnemies && !battle.suspicionCoolOff)
{
battle.suspicionLevel += (MAX_SUSPICION_LEVEL * 0.05);
}
}
if (isControl(CONTROL_ACCELERATE))
{
if (battle.boostTimer > BOOST_FINISHED_TIME || game.currentMission->challengeData.noBoost)
@ -369,25 +369,25 @@ static void handleMouse(void)
applyFighterThrust();
}
}
if (isControl(CONTROL_MISSILE))
{
preFireMissile();
app.mouse.button[SDL_BUTTON_MIDDLE] = 0;
}
if (isControl(CONTROL_GUNS))
{
switchGuns();
app.mouse.button[SDL_BUTTON_X1] = 0;
}
if (isControl(CONTROL_RADAR))
{
cycleRadarZoom();
app.mouse.button[SDL_BUTTON_X2] = 0;
}
}
@ -425,14 +425,14 @@ static void preFireMissile(void)
else
{
playSound(SND_GUI_DENIED);
addHudMessage(colors.white, _("Target not in range"));
}
}
else if (!player->missiles)
{
addHudMessage(colors.white, _("Out of missiles"));
playSound(SND_NO_MISSILES);
}
}
@ -440,11 +440,11 @@ static void preFireMissile(void)
static void initPlayerSelect(void)
{
Entity *e;
memset(&availablePlayerUnits, 0, sizeof(Entity*) * MAX_SELECTABLE_PLAYERS);
selectedPlayerIndex = 0;
if (battle.epicLives == 0 || (battle.epicLives > 0 && --battle.epicLives > 0))
{
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
@ -465,7 +465,7 @@ static void initPlayerSelect(void)
else
{
battle.isEpic = 0;
if (battle.epicKills > 0 && battle.stats[STAT_ENEMIES_KILLED_PLAYER] < battle.epicKills)
{
battle.unwinnable = 0;
@ -480,23 +480,23 @@ void doPlayerSelect(void)
if (isControl(CONTROL_PREV_FIGHTER))
{
selectNewPlayer(-1);
clearControl(CONTROL_PREV_FIGHTER);
}
if (isControl(CONTROL_NEXT_FIGHTER))
{
selectNewPlayer(1);
clearControl(CONTROL_NEXT_FIGHTER);
}
if (player->health > 0 && isAcceptControl())
{
battle.playerSelect = 0;
initPlayer();
resetAcceptControls();
}
}
@ -504,7 +504,7 @@ void doPlayerSelect(void)
static void selectNewPlayer(int dir)
{
player = NULL;
do
{
selectedPlayerIndex += dir;
@ -554,7 +554,7 @@ static void activateECM(void)
addECMEffect(player);
battle.stats[STAT_ECM]++;
if (battle.hasSuspicionLevel && !battle.numEnemies && !battle.suspicionCoolOff)
{
battle.suspicionLevel += (MAX_SUSPICION_LEVEL * 0.25);
@ -594,18 +594,18 @@ static void selectTarget(void)
i = 0;
near = NULL;
memset(targets, 0, sizeof(Entity*) * MAX_SELECTABLE_TARGETS);
if (player->target && (!player->target->health || !player->target->systemPower))
{
player->target = NULL;
}
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active && e != player && (e->flags & EF_TAKES_DAMAGE) && (!(e->flags & EF_NO_PLAYER_TARGET)) && e->side != player->side && e->alive == ALIVE_ALIVE && e->systemPower > 0 && i < MAX_SELECTABLE_TARGETS)
{
dist = getDistance(player->x, player->y, e->x, e->y);
if (dist < closest)
{
near = e;
@ -693,13 +693,13 @@ static int isPriorityMissionTarget(Entity *e, int dist, int closest)
{
return 1;
}
/* battle.missionTarget is not secondary, e is */
if ((battle.missionTarget->flags & EF_SECONDARY_TARGET) < (e->flags & EF_SECONDARY_TARGET))
{
return 0;
}
/* normal distance check */
return dist < closest;
}
@ -707,9 +707,9 @@ static int isPriorityMissionTarget(Entity *e, int dist, int closest)
void setInitialPlayerAngle(void)
{
Entity *e;
selectMissionTarget();
if (battle.missionTarget)
{
player->angle = getAngle(player->x, player->y, battle.missionTarget->x, battle.missionTarget->y);
@ -717,7 +717,7 @@ void setInitialPlayerAngle(void)
else
{
selectTarget();
if (player->target)
{
player->angle = getAngle(player->x, player->y, player->target->x, player->target->y);
@ -730,7 +730,7 @@ void setInitialPlayerAngle(void)
}
}
}
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->side == player->side)
@ -743,7 +743,7 @@ void setInitialPlayerAngle(void)
static void cycleRadarZoom(void)
{
battle.radarRange = (battle.radarRange + 1) % 3;
playSound(SND_ZOOM);
}
@ -780,12 +780,12 @@ 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)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -36,7 +36,7 @@ void initQuadtree(Quadtree *root)
{
Quadtree *node;
int i, w, h;
/* entire battlefield */
if (root->depth == 0)
{
@ -45,16 +45,16 @@ void initQuadtree(Quadtree *root)
root->capacity = QT_INITIAL_CAPACITY;
root->ents = malloc(sizeof(Entity*) * root->capacity);
memset(root->ents, 0, sizeof(Entity*) * root->capacity);
cIndex = 0;
cCapacity = QT_INITIAL_CAPACITY;
candidates = malloc(sizeof(Entity*) * cCapacity);
memset(candidates, 0, sizeof(Entity*) * cCapacity);
}
w = root->w / 2;
h = root->h / 2;
if (root->depth + 1 < QT_MAX_DEPTH)
{
for (i = 0 ; i < 4 ; i++)
@ -62,12 +62,12 @@ void initQuadtree(Quadtree *root)
node = malloc(sizeof(Quadtree));
memset(node, 0, sizeof(Quadtree));
root->node[i] = node;
node->depth = root->depth + 1;
node->capacity = QT_INITIAL_CAPACITY;
node->ents = malloc(sizeof(Entity*) * node->capacity);
memset(node->ents, 0, sizeof(Entity*) * node->capacity);
if (i == 0)
{
node->x = root->x;
@ -96,7 +96,7 @@ void initQuadtree(Quadtree *root)
node->w = w;
node->h = h;
}
initQuadtree(node);
}
}
@ -105,36 +105,36 @@ void initQuadtree(Quadtree *root)
void addToQuadtree(Entity *e, Quadtree *root)
{
int index;
root->addedTo = 1;
if (root->node[0])
{
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
if (index != -1)
{
addToQuadtree(e, root->node[index]);
return;
}
}
if (root->numEnts == root->capacity)
{
resizeQTEntCapacity(root);
}
root->ents[root->numEnts++] = e;
}
static void resizeQTEntCapacity(Quadtree *root)
{
int n;
n = root->capacity + QT_INITIAL_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing QT node: %d -> %d", root->capacity, n);
root->ents = resize(root->ents, sizeof(Entity*) * root->capacity, sizeof(Entity*) * n);
root->capacity = n;
}
@ -177,26 +177,26 @@ static int getIndex(Quadtree *root, int x, int y, int w, int h)
void removeFromQuadtree(Entity *e, Quadtree *root)
{
int index;
if (root->addedTo)
{
if (root->node[0])
{
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
if (index != -1)
{
removeFromQuadtree(e, root->node[index]);
return;
}
}
removeEntity(e, root);
if (root->numEnts == 0)
{
root->addedTo = 0;
if (root->node[0])
{
root->addedTo = root->node[0]->addedTo || root->node[1]->addedTo || root->node[2]->addedTo || root->node[3]->addedTo;
@ -208,9 +208,9 @@ void removeFromQuadtree(Entity *e, Quadtree *root)
static void removeEntity(Entity *e, Quadtree *root)
{
int i, n;
n = root->numEnts;
for (i = 0 ; i < root->capacity ; i++)
{
if (root->ents[i] == e)
@ -219,7 +219,7 @@ static void removeEntity(Entity *e, Quadtree *root)
root->numEnts--;
}
}
qsort(root->ents, n, sizeof(Entity*), candidatesComparator);
}
@ -227,9 +227,9 @@ Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore)
{
cIndex = 0;
memset(candidates, 0, sizeof(Entity*) * cCapacity);
getAllEntsWithinNode(x, y, w, h, ignore, &battle.quadtree);
return candidates;
}
@ -241,13 +241,13 @@ Entity **getAllEntsInRadius(int x, int y, int radius, Entity *ignore)
static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root)
{
int index, i;
if (root->addedTo)
{
if (root->node[0])
{
index = getIndex(root, x, y, w, h);
if (index != -1)
{
getAllEntsWithinNode(x, y, w, h, ignore, root->node[index]);
@ -260,11 +260,11 @@ static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Qua
}
}
}
for (i = 0 ; i < root->numEnts ; i++)
{
candidates[cIndex++] = root->ents[i];
if (cIndex == cCapacity)
{
resizeCandidates();
@ -276,11 +276,11 @@ static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Qua
static void resizeCandidates(void)
{
int n;
n = cCapacity + QT_INITIAL_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing candidates: %d -> %d", cCapacity, n);
candidates = resize(candidates, sizeof(Entity*) * cCapacity, sizeof(Entity*) * n);
cCapacity = n;
}
@ -288,11 +288,11 @@ static void resizeCandidates(void)
void destroyQuadtree(void)
{
destroyQuadtreeNode(&battle.quadtree);
if (candidates)
{
free(candidates);
candidates = NULL;
}
}
@ -300,19 +300,19 @@ void destroyQuadtree(void)
static void destroyQuadtreeNode(Quadtree *root)
{
int i;
free(root->ents);
root->ents = NULL;
if (root->node[0])
{
for (i = 0 ; i < 4 ; i++)
{
destroyQuadtreeNode(root->node[i]);
free(root->node[i]);
root->node[i] = NULL;
}
}
@ -322,7 +322,7 @@ static int candidatesComparator(const void *a, const void *b)
{
Entity *e1 = *((Entity**)a);
Entity *e2 = *((Entity**)b);
if (!e1)
{
return 1;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -29,10 +29,10 @@ void initRadar(void)
{
radarTexture = getAtlasImage("gfx/hud/radar.png");
radarWarningTexture = getAtlasImage("gfx/hud/radarWarning.png");
/* medium range by default */
battle.radarRange = 1;
CAUTION_TEXT = _("Caution: Leaving battle area - turn around.");
}
@ -41,34 +41,34 @@ void drawRadar(void)
SDL_Rect r;
Entity *e;
int dist, inRange, blink;
blit(radarTexture, app.winWidth - 85, app.winHeight - 85, 1);
drawText(app.winWidth - 160, app.winHeight - 30, 14, TA_RIGHT, colors.white, "%dx", battle.radarRange + 1);
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);
if (e->active)
{
inRange = (!(e->flags & EF_SHORT_RADAR_RANGE)) ? (dist / radarRanges[battle.radarRange]) < 70 : dist < 500;
if (inRange)
{
r.x = app.winWidth - 85;
r.y = app.winHeight - 85;
r.x -= (player->x - e->x) / radarRanges[battle.radarRange];
r.y -= (player->y - e->y) / radarRanges[battle.radarRange];
r.x--;
r.y--;
if (e->side == SIDE_NONE)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
@ -81,25 +81,25 @@ void drawRadar(void)
{
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);
}
}
@ -109,39 +109,39 @@ void drawRadar(void)
void drawRadarRangeWarning(void)
{
int x, y, leaving;
x = (int)player->x / (app.winWidth / 2);
y = (int)player->y / (app.winHeight / 2);
leaving = 0;
if (x <= 2 && player->dx < 0)
{
blitRotated(radarWarningTexture, app.winWidth - 85, app.winHeight - 85, 270);
leaving = 1;
}
if (y <= 3 && player->dy < 0)
{
blitRotated(radarWarningTexture, app.winWidth - 85, app.winHeight - 85, 0);
leaving = 1;
}
if (x >= BATTLE_AREA_CELLS - 2 && player->dx > 0)
{
blitRotated(radarWarningTexture, app.winWidth - 85, app.winHeight - 85, 90);
leaving = 1;
}
if (y >= BATTLE_AREA_CELLS - 3 && player->dy > 0)
{
blitRotated(radarWarningTexture, app.winWidth - 85, app.winHeight - 85, 180);
leaving = 1;
}
if (leaving && battle.stats[STAT_TIME] % FPS < 40)
{
drawText(app.winWidth / 2, app.winHeight - 30, 14, TA_CENTER, colors.white, CAUTION_TEXT);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -24,35 +24,35 @@ void attachRope(void)
{
int i, distance;
Entity *e, **candidates;
if ((self->flags & EF_HAS_ROPE) && self->towing == NULL)
{
candidates = getAllEntsInRadius(self->x, self->y, self->separationRadius, self);
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (!e->owner && e->type == ET_FIGHTER && (e->flags & EF_DISABLED) && (e->flags & EF_ROPED_ATTACHED) == 0 && e->alive == ALIVE_ALIVE)
{
distance = getDistance(e->x, e->y, self->x, self->y);
if (distance > 0 && distance <= self->separationRadius)
{
self->towing = e;
self->aiFlags |= AIF_GOAL_JUMPGATE;
e->owner = self;
e->speed = 1;
e->flags |= EF_RETREATING;
e->flags |= EF_ROPED_ATTACHED;
runScriptFunction("TOWING %s", e->name);
if (self == player)
{
battle.stats[STAT_NUM_TOWED]++;
addHudMessage(colors.white, _("Tow rope attached"));
}
playBattleSound(SND_TOW_ROPE, e->x, e->y);
}
}
@ -64,23 +64,23 @@ void doRope(Entity *owner)
{
float dx, dy, angle, force;
int distance;
if (owner->towing)
{
distance = getDistance(owner->towing->x, owner->towing->y, owner->x, owner->y);
if (distance > ROPE_DISTANCE)
{
angle = getAngle(owner->x, owner->y, owner->towing->x, owner->towing->y);
dx = sin(TO_RAIDANS(angle));
dy = -cos(TO_RAIDANS(angle));
force = (distance - ROPE_DISTANCE) * 0.02;
owner->towing->dx -= (dx * force);
owner->towing->dy -= (dy * force);
}
owner->towing->dx *= 0.985;
owner->towing->dy *= 0.985;
}
@ -91,7 +91,7 @@ void drawRope(Entity *e)
if (e->towing)
{
SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255);
SDL_RenderDrawLine(app.renderer, e->x - battle.camera.x, e->y - battle.camera.y, e->towing->x - battle.camera.x, e->towing->y - battle.camera.y);
}
}
@ -104,7 +104,7 @@ void cutRope(Entity *e)
e->owner->towing = NULL;
e->owner->aiFlags &= ~AIF_GOAL_JUMPGATE;
}
/* tug is dead - reset thing being tugged */
if (e->towing)
{

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -31,16 +31,16 @@ static int runScript;
void initScript(cJSON *root)
{
cJSON *function;
memset(&head, 0, sizeof(ScriptRunner));
tail = &head;
rootJSON = root;
runScript = 0;
scriptJSON = cJSON_GetObjectItem(root, "script");
if (scriptJSON)
{
function = scriptJSON->child;
@ -48,10 +48,10 @@ void initScript(cJSON *root)
while (function)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Found script function: '%s'", cJSON_GetObjectItem(function, "function")->valuestring);
function = function->next;
}
runScript = 1;
}
}
@ -128,7 +128,7 @@ void runScriptFunction(const char *format, ...)
tail = scriptRunner;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Running script '%s'", funcNameBuffer);
return;
}
@ -284,25 +284,25 @@ static void executeNextLine(ScriptRunner *runner)
void cancelScript(void)
{
ScriptRunner *runner;
while (head.next)
{
runner = head.next;
head.next = runner->next;
free(runner);
}
tail = &head;
}
void destroyScript(void)
{
ScriptRunner *scriptRunner;
if (rootJSON)
{
cJSON_Delete(rootJSON);
rootJSON = NULL;
}
@ -314,6 +314,6 @@ void destroyScript(void)
}
tail = &head;
scriptJSON = NULL;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -27,27 +27,27 @@ void doSpawners(void)
char *type;
int i, num, addFlags, addAIFlags;
long flags, aiFlags;
for (s = battle.spawnerHead.next ; s != NULL ; s = s->next)
{
if (s->active && --s->time <= 0)
{
aiFlags = flags = -1;
num = s->step;
if (s->total != -1)
{
num = MIN(s->step, s->total);
s->total -= num;
}
if (s->side != SIDE_ALLIES)
{
battle.numInitialEnemies += num;
}
if (strlen(s->flags))
{
flags = flagsToLong(s->flags, &addFlags);
@ -57,15 +57,15 @@ void doSpawners(void)
{
aiFlags = flagsToLong(s->aiFlags, &addAIFlags);
}
for (i = 0 ; i < num ; i++)
{
type = s->types[rand() % s->numTypes];
e = spawnFighter(type, 0, 0, s->side);
e->spawned = 1;
if (s->offscreen)
{
e->x = player->x;
@ -76,10 +76,10 @@ void doSpawners(void)
e->x = rand() % 2 ? 0 : BATTLE_AREA_WIDTH;
e->y = rand() % 2 ? 0 : BATTLE_AREA_HEIGHT;
}
e->x += (rand() % 2) ? -SCREEN_WIDTH * 3 : SCREEN_WIDTH * 3;
e->y += (rand() % 2) ? -SCREEN_HEIGHT * 3 : SCREEN_HEIGHT * 3;
if (flags != -1)
{
if (addFlags)
@ -91,7 +91,7 @@ void doSpawners(void)
e->flags = flags;
}
}
if (aiFlags != -1)
{
if (addAIFlags)
@ -104,7 +104,7 @@ void doSpawners(void)
}
}
}
s->time = s->interval;
}
}
@ -127,12 +127,12 @@ void activateTrespasserSpawner(void)
{
Spawner *s;
char types[MAX_DESCRIPTION_LENGTH];
s = malloc(sizeof(Spawner));
memset(s, 0, sizeof(Spawner));
battle.spawnerTail->next = s;
battle.spawnerTail = s;
STRNCPY(types, "Jackal;Mantis;Sphinx;Scarab", MAX_DESCRIPTION_LENGTH);
s->types = toTypeArray(types, &s->numTypes);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -25,15 +25,15 @@ static Star stars[MAX_STARS];
void initStars(void)
{
int i;
memset(stars, 0, sizeof(Star) * MAX_STARS);
for (i = 0 ; i < MAX_STARS ; i++)
{
stars[i].x = rand() % app.winWidth;
stars[i].y = rand() % app.winHeight;
stars[i].speed = 5 + rand() % 35;
stars[i].speed *= 0.1;
}
}
@ -41,12 +41,12 @@ void initStars(void)
void doStars(float dx, float dy)
{
int i;
for (i = 0 ; i < MAX_STARS ; i++)
{
stars[i].x -= (dx * stars[i].speed);
stars[i].y -= (dy * stars[i].speed);
stars[i].x = mod(stars[i].x, app.winWidth - 1);
stars[i].y = mod(stars[i].y, app.winHeight - 1);
}
@ -56,15 +56,15 @@ void drawStars(void)
{
int i;
int c;
for (i = 0 ; i < MAX_STARS ; i++)
{
c = 64 * stars[i].speed;
SDL_SetRenderDrawColor(app.renderer, c, c, c, 255);
SDL_RenderDrawPoint(app.renderer, stars[i].x, stars[i].y);
if (c >= 240)
{
SDL_RenderDrawPoint(app.renderer, stars[i].x + 1, stars[i].y + 1);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -37,7 +37,7 @@ void resetWaypoints(void)
Entity *spawnWaypoint(void)
{
Entity *waypoint = spawnEntity();
sprintf(waypoint->name, "Waypoint #%d", waypointId);
waypoint->id = waypointId;
waypoint->type = ET_WAYPOINT;
@ -46,43 +46,43 @@ Entity *spawnWaypoint(void)
waypoint->texture = getAtlasImage("gfx/entities/waypoint.png");
waypoint->flags = EF_NO_MT_BOX+EF_MISSION_TARGET+EF_NO_HEALTH_BAR;
waypoint->action = think;
waypoint->w = waypoint->texture->rect.w;
waypoint->h = waypoint->texture->rect.h;
waypointId++;
return waypoint;
}
static void think(void)
{
self->angle += 0.25;
if (self->angle >= 360)
{
self->angle -= 360;
}
if (--self->aiActionTime <= 0)
{
self->aiActionTime = 0;
if (self->health && player->alive == ALIVE_ALIVE && getDistance(player->x, player->y, self->x, self->y) <= 128 && isCurrentObjective() && teamMatesClose())
{
self->health = 0;
updateObjective("Waypoint", TT_WAYPOINT);
runScriptFunction(self->name);
if (battle.waypointAutoAdvance)
{
activateNextWaypoint();
}
battle.stats[STAT_WAYPOINTS_VISITED]++;
playSound(SND_WAYPOINT);
}
}
@ -91,28 +91,28 @@ static void think(void)
static int isCurrentObjective(void)
{
int numActiveObjectives = battle.numObjectivesTotal - battle.numObjectivesComplete;
if (numActiveObjectives > 1)
{
addHudMessage(colors.cyan, _("Cannot activate waypoint - outstanding objectives not yet complete"));
self->aiActionTime = FPS;
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;
}
static int teamMatesClose(void)
{
Entity *e;
if (player->side != SIDE_PANDORAN)
{
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
@ -128,7 +128,7 @@ static int teamMatesClose(void)
}
}
}
return 1;
}
@ -136,9 +136,9 @@ void activateNextWaypoint(void)
{
Entity *e;
Entity *nextWaypoint = NULL;
currentWaypointId++;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->type == ET_WAYPOINT && e->id == currentWaypointId)
@ -146,11 +146,11 @@ void activateNextWaypoint(void)
nextWaypoint = e;
}
}
if (nextWaypoint != NULL)
{
nextWaypoint->active = 1;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Activating %s", nextWaypoint->name);
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -66,7 +66,7 @@ static char *RESTRICTIONS_TEXT;
void initChallengeHome(void)
{
Mission *m;
startSectionTransition();
stopMusic();
@ -80,7 +80,7 @@ void initChallengeHome(void)
awardStatsTrophies();
app.saveGame = 1;
CHALLENGES_TEXT = _("Challenges");
COMPLETED_TEXT = _("Completed : %d / %d");
PAGE_TEXT = _("Page : %d / %d");
@ -102,14 +102,14 @@ void initChallengeHome(void)
planet.x = rand() % app.winWidth;
planet.y = rand() % app.winHeight;
maxPages = page = 0;
for (m = game.challengeMissionHead.next ; m != NULL ; m = m->next)
{
maxPages++;
}
maxPages /= CHALLENGES_PER_PAGE;
maxPages = ceil(maxPages);
@ -128,11 +128,11 @@ void initChallengeHome(void)
getWidget("ok", "stats")->action = ok;
getWidget("ok", "trophies")->action = ok;
getWidget("ok", "fighterDB")->action = ok;
prev = getWidget("prev", "challenges");
prev->action = prevPage;
prev->visible = 0;
next = getWidget("next", "challenges");
next->action = nextPage;
next->visible = 1;
@ -143,9 +143,9 @@ void initChallengeHome(void)
game.currentMission = game.challengeMissionHead.next;
updateChallengeMissionData();
}
SDL_SetWindowGrab(app.window, 0);
autoSizeWidgetButtons("challenges", 1);
endSectionTransition();
@ -156,7 +156,7 @@ void initChallengeHome(void)
static void nextPage(void)
{
page = MIN(page + 1, maxPages - 1);
next->visible = page < maxPages - 1;
prev->visible = 1;
}
@ -164,7 +164,7 @@ static void nextPage(void)
static void prevPage(void)
{
page = MAX(0, page - 1);
next->visible = 1;
prev->visible = page > 0;
}
@ -223,12 +223,12 @@ static void logic(void)
}
doWidgets();
if (show == SHOW_FIGHTER_DB)
{
doFighterDatabase();
}
app.doTrophyAlerts = 1;
}
@ -236,11 +236,11 @@ 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 (i >= startIndex && i < end && app.mouse.button[SDL_BUTTON_LEFT] && collision(app.uiMouse.x, app.uiMouse.y, 3, 3, c->rect.x, c->rect.y, c->rect.w, c->rect.h))
@ -258,7 +258,7 @@ static void doChallenges(void)
app.mouse.button[SDL_BUTTON_LEFT] = 0;
}
i++;
}
}
@ -307,9 +307,17 @@ static void draw(void)
blit(planetTexture, planet.x, planet.y, 1);
drawStars();
if (show == SHOW_MENU)
{
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);
}
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
drawText(UI_WIDTH / 2, 40, 28, TA_CENTER, colors.white, CHALLENGES_TEXT);
drawText(UI_WIDTH / 2, 83, 16, TA_CENTER, colors.lightGrey, COMPLETED_TEXT, game.completedChallenges, game.totalChallenges);
drawText(UI_WIDTH / 2, 110, 16, TA_CENTER, colors.lightGrey, PAGE_TEXT, page + 1, (int)maxPages);
@ -329,7 +337,7 @@ static void draw(void)
case SHOW_STATS:
drawStats();
break;
case SHOW_TROPHIES:
drawTrophies();
break;
@ -337,12 +345,12 @@ static void draw(void)
case SHOW_OPTIONS:
drawOptions();
break;
case SHOW_FIGHTER_DB:
drawFighterDatabase();
break;
}
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -359,7 +367,7 @@ static void drawChallenges(void)
start = page * CHALLENGES_PER_PAGE;
end = start + CHALLENGES_PER_PAGE;
i = 0;
for (m = game.challengeMissionHead.next ; m != NULL ; m = m->next)
@ -447,11 +455,6 @@ static void drawMenu(void)
{
SDL_Rect r;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
r.w = 400;
r.h = 500;
r.x = (UI_WIDTH / 2) - r.w / 2;
@ -489,7 +492,7 @@ static void stats(void)
static void fighterDatabase(void)
{
show = SHOW_FIGHTER_DB;
initFighterDatabaseDisplay();
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -76,13 +76,13 @@ void initChallenges(void)
sprintf(path, "data/challenges/%s", filenames[i]);
mission = loadMissionMeta(path);
if (mission)
{
tail->next = mission;
tail = mission;
}
free(filenames[i]);
}
@ -93,7 +93,7 @@ void loadChallenge(Mission *mission, cJSON *node)
{
int i;
Challenge *challenge;
mission->challengeData.isChallenge = 1;
/* limits */
@ -112,12 +112,12 @@ void loadChallenge(Mission *mission, cJSON *node)
mission->challengeData.noECM = getJSONValue(node, "noECM", 0);
mission->challengeData.noBoost = getJSONValue(node, "noBoost", 0);
mission->challengeData.noGuns = getJSONValue(node, "noGuns", 0);
if (getJSONValue(node, "noWeapons", 0))
{
mission->challengeData.noMissiles = mission->challengeData.noGuns = 1;
}
/* misc */
mission->challengeData.allowPlayerDeath = getJSONValue(node, "allowPlayerDeath", 0);
mission->challengeData.clearWaypointEnemies = getJSONValue(node, "clearWaypointEnemies", 0);
@ -152,18 +152,18 @@ void loadChallenge(Mission *mission, cJSON *node)
void doChallenges(void)
{
int passed;
if (game.currentMission->challengeData.isChallenge && battle.status == MS_IN_PROGRESS)
{
if (challengeFinished())
{
passed = 0;
if (player->health > 0 || (player->health <= 0 && game.currentMission->challengeData.allowPlayerDeath))
{
passed = updateChallenges();
}
if (passed)
{
completeChallenge();
@ -182,53 +182,53 @@ static int challengeFinished(void)
{
return 1;
}
/* disabled enemies count as killed during challenges - not player exclusive, but no need to worry about AI contributions here */
if (game.currentMission->challengeData.killLimit > 0 && (battle.stats[STAT_ENEMIES_KILLED_PLAYER] + battle.stats[STAT_CAPITAL_SHIPS_DESTROYED] + battle.stats[STAT_ENEMIES_DISABLED]) >= game.currentMission->challengeData.killLimit)
{
return 1;
}
if (game.currentMission->challengeData.escapeLimit > 0 && (battle.stats[STAT_ENEMIES_KILLED_PLAYER] + battle.stats[STAT_ENEMIES_ESCAPED]) >= game.currentMission->challengeData.escapeLimit)
{
return 1;
}
if (game.currentMission->challengeData.waypointLimit > 0 && battle.stats[STAT_WAYPOINTS_VISITED] >= game.currentMission->challengeData.waypointLimit)
{
return 1;
}
if (game.currentMission->challengeData.itemLimit > 0 && battle.stats[STAT_ITEMS_COLLECTED] + battle.stats[STAT_ITEMS_COLLECTED_PLAYER] >= game.currentMission->challengeData.itemLimit)
{
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.surrenderLimit > 0 && battle.stats[STAT_ENEMIES_SURRENDERED] >= game.currentMission->challengeData.surrenderLimit)
{
return 1;
}
if (game.currentMission->challengeData.waypointLimit > 0 && (battle.stats[STAT_WAYPOINTS_VISITED]) >= game.currentMission->challengeData.waypointLimit)
{
return 1;
}
if (game.currentMission->challengeData.eliminateThreats && !battle.hasThreats)
{
return 1;
}
return (player->health <= 0 || player->alive == ALIVE_ESCAPED || battle.scriptedEnd);
}
@ -238,7 +238,7 @@ static int updateChallenges(void)
Challenge *c;
updateAccuracyStats(battle.stats);
numPassed = 0;
for (i = 0 ; i < MAX_CHALLENGES ; i++)
@ -254,7 +254,7 @@ static int updateChallenges(void)
case CHALLENGE_TIME:
updateTimeChallenge(c);
break;
case CHALLENGE_SURVIVE:
updateSurvivalChallenge(c);
break;
@ -282,26 +282,26 @@ static int updateChallenges(void)
case CHALLENGE_DISABLE:
updateDisabledChallenge(c);
break;
case CHALLENGE_ITEMS:
case CHALLENGE_PLAYER_ITEMS:
updateItemsChallenge(c);
break;
case CHALLENGE_SURRENDER:
updateSurrenderChallenge(c);
break;
case CHALLENGE_WAYPOINTS:
updateWaypointChallenge(c);
break;
case CHALLENGE_RESCUE:
updateRescueChallenge(c);
break;
}
}
if (c->passed)
{
numPassed++;
@ -313,7 +313,7 @@ static int updateChallenges(void)
{
printStats();
}
return numPassed;
}
@ -472,7 +472,7 @@ char *getChallengeDescription(Challenge *c)
return getFormattedChallengeDescription(_("Complete challenge in %s or less"), timeToString(c->value * FPS, 0));
}
}
return getFormattedChallengeDescription(challengeDescription[c->type], c->value);
}
@ -545,13 +545,13 @@ static void completeChallenge(void)
game.stats[STAT_CHALLENGES_COMPLETED]++;
player->flags |= EF_IMMORTAL;
retreatAllies();
retreatEnemies();
awardStatsTrophies();
awardCraftTrophy();
}
}
@ -565,16 +565,16 @@ static void failChallenge(void)
selectWidget("retry", "battleLost");
player->flags |= EF_IMMORTAL;
if (alreadyPassed())
{
battle.status = MS_TIME_UP;
}
retreatAllies();
retreatEnemies();
awardStatsTrophies();
}
}
@ -593,6 +593,6 @@ static int alreadyPassed(void)
return 1;
}
}
return 0;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -80,7 +80,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define NUM_ATLAS_BUCKETS 64
#define NUM_GLYPH_BUCKETS 128
#define MAX_STARS 500
#define MAX_STARS 100
#define MAX_CHALLENGES 3
@ -421,3 +421,4 @@ enum
TROPHY_UNEARNED,
TROPHY_MAX
};

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -87,7 +87,7 @@ void initGalacticMap(void)
app.delegate.logic = &logic;
app.delegate.draw = &draw;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
MISSIONS_TEXT = _("Missions: %d / %d");
PILOT_TEXT = _("Pilot: %s");
CRAFT_TEXT = _("Craft: %s");
@ -113,9 +113,9 @@ void initGalacticMap(void)
awardCampaignTrophies();
awardStatsTrophies();
updateCampaignProgress();
hoverMission = NULL;
app.saveGame = 1;
@ -123,7 +123,7 @@ void initGalacticMap(void)
pulseTimer = 0;
arrowPulse = 0;
selectedStarSystem = NULL;
/* clear the pulses */
@ -145,11 +145,11 @@ void initGalacticMap(void)
getWidget("ok", "fighterDB")->action = ok;
getWidget("ok", "fallen")->action = fallenOK;
autoSizeWidgetButtons("galacticMap", 1);
endSectionTransition();
SDL_SetWindowGrab(app.window, 0);
playMusic("music/main/Pressure.ogg", 1);
@ -158,7 +158,7 @@ void initGalacticMap(void)
static void updateCampaignProgress(void)
{
StarSystem *starSystem;
if (!campaignComplete && game.completedMissions == game.totalMissions)
{
for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next)
@ -168,9 +168,9 @@ static void updateCampaignProgress(void)
starSystem->activeMission = starSystem->missionHead.next;
}
}
campaignComplete = 1;
showOKDialog(&campaignCompleteOK, _("Congratulations, you have completed the campaign! You may now replay past missions, for fun, to boost stats, or to earn missing trophies!"));
}
}
@ -230,12 +230,12 @@ static void logic(void)
arrowPulse += 0.1;
doWidgets();
if (show == SHOW_FIGHTER_DB)
{
doFighterDatabase();
}
app.doTrophyAlerts = 1;
}
@ -302,13 +302,13 @@ static void scrollGalaxy(void)
ssx = -app.mouse.dx;
ssx /= 3;
ssy = -app.mouse.dy;
ssy /= 3;
camera.x = MAX(cameraMin.x, MIN(camera.x, cameraMax.x));
camera.y = MAX(cameraMin.y, MIN(camera.y, cameraMax.y));
if (lastX == camera.x)
{
ssx = 0;
@ -330,7 +330,7 @@ static void doStarSystemView(void)
if (mission->available && collision(app.uiMouse.x - app.mouse.w / 2, app.uiMouse.y - app.mouse.h / 2, app.mouse.w, app.mouse.h, mission->rect.x, mission->rect.y, mission->rect.w, mission->rect.h))
{
hoverMission = mission;
if (app.mouse.button[SDL_BUTTON_LEFT])
{
if (game.currentMission != mission)
@ -343,12 +343,12 @@ static void doStarSystemView(void)
}
}
}
/* allow closing by pressing the right mouse button */
if (app.mouse.button[SDL_BUTTON_RIGHT])
{
show = SHOW_GALAXY;
playSound(SND_GUI_CLOSE);
}
}
@ -368,7 +368,7 @@ static void addPulses(void)
pulse->x = starSystem->x;
pulse->y = starSystem->y;
pulse->life = 255;
switch (starSystem->type)
{
case SS_NORMAL:
@ -383,18 +383,18 @@ static void addPulses(void)
pulse->b = 255;
}
break;
case SS_SOL:
pulse->g = 255;
break;
case SS_PANDORAN:
pulse->r = 128;
pulse->g = 128;
pulse->b = 255;
break;
}
pulseTail->next = pulse;
pulseTail = pulse;
}
@ -453,7 +453,7 @@ static void draw(void)
case SHOW_STATS:
drawStats();
break;
case SHOW_TROPHIES:
drawTrophies();
break;
@ -461,7 +461,7 @@ static void draw(void)
case SHOW_OPTIONS:
drawOptions();
break;
case SHOW_FIGHTER_DB:
drawFighterDatabase();
break;
@ -555,18 +555,18 @@ static void drawGalaxy(void)
case SS_NORMAL:
setAtlasColor(255, 0, 0, 255);
break;
case SS_SOL:
setAtlasColor(0, 255, 0, 255);
break;
case SS_PANDORAN:
setAtlasColor(64, 128, 255, 255);
break;
}
blitRotated(arrowTexture, ax, ay, aa);
setAtlasColor(255, 255, 255, 255);
}
}
@ -618,7 +618,7 @@ static void selectStarSystem(void)
static Mission *nextAvailableMission(StarSystem *starSystem)
{
Mission *m;
for (m = starSystem->missionHead.next ; m != NULL ; m = m->next)
{
if (m->available && !m->completed)
@ -626,7 +626,7 @@ static Mission *nextAvailableMission(StarSystem *starSystem)
return m;
}
}
return starSystem->missionHead.next;
}
@ -635,7 +635,7 @@ static void drawStarSystemDetail(void)
int y;
Mission *mission;
SDL_Rect r;
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 900;
@ -668,7 +668,7 @@ static void drawStarSystemDetail(void)
mission->rect.y = y - 2;
mission->rect.w = 300;
mission->rect.h = 38;
if (mission == hoverMission)
{
SDL_SetRenderDrawColor(app.renderer, 16, 32, 64, 255);
@ -690,7 +690,7 @@ static void drawStarSystemDetail(void)
if (mission->available)
{
drawText(210, y, 22, TA_LEFT, mission->completed ? colors.lightGrey : colors.yellow, mission->name);
y += 42;
}
}
@ -702,9 +702,9 @@ static void drawStarSystemDetail(void)
drawText(525, 185, 18, TA_LEFT, colors.lightGrey, SQUADRON_TEXT, game.currentMission->squadron);
app.textWidth = 525;
drawText(525, 230, 22, TA_LEFT, colors.white, game.currentMission->description);
app.textWidth = 0;
}
@ -724,7 +724,7 @@ static void drawStarSystemDetail(void)
startMissionButton->enabled = (!game.currentMission->completed || selectedStarSystem->type == SS_SOL || campaignComplete);
drawWidgets("starSystem");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -740,7 +740,7 @@ static void campaignCompleteOK(void)
show = SHOW_GALAXY;
app.modalDialog.type = MD_NONE;
campaignComplete = 2;
}
@ -791,7 +791,7 @@ static void handleMouse(void)
{
scrollingMap = 0;
}
setMouseCursor(app.mouse.button[SDL_BUTTON_LEFT] && show == SHOW_GALAXY);
}
@ -805,14 +805,14 @@ static void startMission(void)
static void drawMenu(void)
{
SDL_Rect r;
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
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);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 400;
r.h = 500;
r.x = (UI_WIDTH / 2) - r.w / 2;
@ -824,7 +824,7 @@ static void drawMenu(void)
SDL_RenderDrawRect(app.renderer, &r);
drawWidgets("galacticMap");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -843,7 +843,7 @@ static void options(void)
static void fighterDatabase(void)
{
show = SHOW_FIGHTER_DB;
initFighterDatabaseDisplay();
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -51,11 +51,11 @@ Mission *loadMissionMeta(char *filename)
STRNCPY(mission->filename, filename, MAX_DESCRIPTION_LENGTH);
mission->requires = getJSONValue(root, "requires", 0);
mission->isOptional = getJSONValue(root, "isOptional", 0);
mission->requiresOptional = getJSONValue(root, "requiresOptional", 0);
mission->expires = getJSONValue(root, "expires", 0);
if (cJSON_GetObjectItem(root, "epic"))
{
mission->epic = 1;
@ -154,27 +154,27 @@ void loadMission(char *filename)
{
planet = getAutoPlanet(filename);
}
battle.planetTexture = getAtlasImage(planet);
battle.fireStormTexture = getAtlasImage("gfx/misc/torelliFireStorm.png");
battle.planet.x = (app.winWidth / 2) - (rand() % app.winWidth) + (rand() % app.winWidth);
battle.planet.y = (app.winHeight / 2) - (rand() % app.winHeight) + (rand() % app.winHeight);
if (strcmp(planet, "gfx/planets/star.png") != 0)
{
battle.planetWidth = battle.planetTexture->rect.w;
battle.planetHeight = battle.planetTexture->rect.h;
planetScale = 75 + (rand() % 125);
planetScale *= 0.01;
if (getJSONValue(root, "largePlanet", 0))
{
battle.planet.x = (app.winWidth / 2);
battle.planet.y = (app.winHeight / 2);
planetScale = 5;
}
battle.planetWidth *= planetScale;
battle.planetHeight *= planetScale;
}
@ -198,7 +198,7 @@ void loadMission(char *filename)
{
battle.status = MS_IN_PROGRESS;
}
if (battle.waypointAutoAdvance)
{
activateNextWaypoint();
@ -209,7 +209,7 @@ void loadMission(char *filename)
initPlayer();
initMissionInfo();
setInitialPlayerAngle();
addAllToQuadtree();
@ -274,10 +274,10 @@ void completeMission(void)
selectWidget("continue", "battleWon");
game.stats[STAT_MISSIONS_COMPLETED]++;
if (game.currentMission->isOptional)
{
game.stats[STAT_OPTIONAL_COMPLETED]++;
game.stats[STAT_OPTIONAL_COMPLETED]++;
}
completeConditions();
@ -285,11 +285,11 @@ void completeMission(void)
retreatEnemies();
player->flags |= EF_IMMORTAL;
awardStatsTrophies();
awardPostMissionTrophies();
awardCraftTrophy();
}
}
@ -305,7 +305,7 @@ void failMission(void)
failIncompleteObjectives();
player->flags |= EF_IMMORTAL;
awardStatsTrophies();
}
}
@ -338,7 +338,7 @@ static void loadEntities(cJSON *node)
active = getJSONValue(node, "active", 1);
scatter = getJSONValue(node, "scatter", 1);
side = lookup(getJSONValueStr(node, "side", "SIDE_NONE"));
if (cJSON_GetObjectItem(node, "flags"))
{
flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags);
@ -356,7 +356,7 @@ static void loadEntities(cJSON *node)
case ET_JUMPGATE:
e = spawnJumpgate(side, flags);
break;
case ET_MINE:
case ET_SHADOW_MINE:
e = spawnMine(type);
@ -394,7 +394,7 @@ static void loadEntities(cJSON *node)
e->x = x;
e->y = y;
e->side = side;
if (scatter > 1)
@ -423,12 +423,12 @@ static void loadEpicData(cJSON *node)
battle.unlimitedEnemies = getJSONValue(node, "unlimitedEnemies", 0);
battle.epicLives = getJSONValue(node, "lives", 0);
battle.epicKills = getJSONValue(node, "kills", 0);
if (battle.epicLives > 0)
{
addEpicLivesObjective();
}
if (battle.epicKills != 0)
{
addEpicKillsObjective();
@ -490,7 +490,7 @@ int isMissionAvailable(Mission *mission, Mission *prev)
else
{
return mission->completed || (
game.completedMissions >= mission->requires &&
game.completedMissions >= mission->requires &&
game.stats[STAT_OPTIONAL_COMPLETED] >= mission->requiresOptional &&
game.completedMissions < mission->expires
) || dev.debug;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -57,7 +57,7 @@ static StarSystem *loadStarSystem(cJSON *starSystemJSON)
starSystem->x = cJSON_GetObjectItem(starSystemJSON, "x")->valueint;
starSystem->y = cJSON_GetObjectItem(starSystemJSON, "y")->valueint;
starSystem->fallsToPandorans = getJSONValue(starSystemJSON, "fallsToPandorans", 0);
starSystem->type = (starSystem->side != SIDE_PANDORAN) ? SS_NORMAL : SS_PANDORAN;
if (strcmp(starSystem->name, "Sol") == 0)
@ -91,26 +91,26 @@ static void loadMissions(StarSystem *starSystem)
{
name[i] = tolower(name[i]);
}
sprintf(path, "data/missions/%s", name);
filenames = getFileList(path, &count);
for (i = 0 ; i < count ; i++)
{
sprintf(path, "data/missions/%s/%s", name, filenames[i]);
mission = loadMissionMeta(path);
if (mission)
{
tail->next = mission;
tail = mission;
}
free(filenames[i]);
}
free(filenames);
}
@ -143,16 +143,16 @@ void updateStarSystemMissions(void)
for (mission = starSystem->missionHead.next ; mission != NULL ; mission = mission->next)
{
starSystem->totalMissions++;
if (starSystem->type == SS_NORMAL && !mission->isOptional)
{
game.totalMissions++;
}
if (mission->completed)
{
starSystem->completedMissions++;
if (starSystem->type == SS_NORMAL && !mission->isOptional)
{
game.completedMissions++;
@ -172,12 +172,12 @@ void updateStarSystemMissions(void)
if (mission->available)
{
starSystem->availableMissions++;
if (starSystem->type == SS_NORMAL && !mission->isOptional)
{
game.availableMissions++;
}
if (!mission->completed)
{
starSystem->activeMission = mission;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -24,6 +24,7 @@ static void loadCredits(void);
static void logic(void);
static void draw(void);
static void handleKeyboard(void);
void destroyCredits(void);
static SDL_Texture *background;
static AtlasImage *earthTexture;
@ -35,49 +36,51 @@ static int timeout;
void initCredits(void)
{
startSectionTransition();
stopMusic();
memset(&head, 0, sizeof(Credit));
tail = &head;
app.delegate.logic = &logic;
app.delegate.draw = &draw;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
background = getTexture("gfx/backgrounds/background02.jpg");
earthTexture = getAtlasImage("gfx/planets/earth.png");
loadCredits();
app.hideMouse = 1;
endSectionTransition();
playMusic("music/main/Her Violet Eyes.mp3", 0);
}
static void logic(void)
{
Credit *c;
handleKeyboard();
for (c = head.next ; c != NULL ; c = c->next)
{
c->y -= creditSpeed;
if (!c->next)
{
c->y = MAX(c->y, (app.winHeight - c->h) / 2);
}
}
if (--timeout <= 0)
{
app.hideMouse = 0;
destroyCredits();
initTitle();
}
}
@ -85,13 +88,13 @@ static void logic(void)
static void draw(void)
{
Credit *c;
drawBackground(background);
blit(earthTexture, app.winWidth - 200, (app.winHeight / 2) + 100, 1);
app.textWidth = CREDIT_LINE_LIMIT;
for (c = head.next ; c != NULL ; c = c->next)
{
if (c->y > -c->h && c->y < app.winHeight)
@ -99,7 +102,7 @@ static void draw(void)
drawText(app.winWidth / 2, (int)c->y, c->size, TA_CENTER, colors.white, c->text);
}
}
app.textWidth = 0;
}
@ -109,12 +112,12 @@ static void loadCredits(void)
int y, dist;
char *text;
Credit *c;
y = app.winHeight + 100;
text = readFile("data/credits/credits.json");
root = cJSON_Parse(text);
app.textWidth = CREDIT_LINE_LIMIT;
for (node = root->child ; node != NULL ; node = node->next)
@ -123,28 +126,28 @@ static void loadCredits(void)
memset(c, 0, sizeof(Credit));
tail->next = c;
tail = c;
c->y = y;
c->text = malloc(sizeof(char) * strlen(node->valuestring));
memset(c->text, '\0', sizeof(char) * strlen(node->valuestring));
sscanf(node->valuestring, "%d %d %[^\n]", &dist, &c->size, c->text);
c->y += dist;
c->h = getWrappedTextHeight(c->text, c->size);
y += c->h + dist;
}
app.textWidth = 0;
/* the music that plays over the credits is 2m 44s, so scroll credits roughly inline with that (plus 2 seconds) */
timeout = ((2 * 60) + 46) * FPS;
creditSpeed = y;
creditSpeed /= timeout;
cJSON_Delete(root);
free(text);
}
@ -160,7 +163,7 @@ static void handleKeyboard(void)
void destroyCredits(void)
{
Credit *c;
while (head.next)
{
c = head.next;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -48,7 +48,7 @@ void initFighterDatabase(void)
{
DB_TEXT = _("Fighter Database");
PAGE_TEXT = _("Page %d / %d");
COMMON_TEXT = _("(Common)");
DESTROYED_TEXT = _("Destroyed");
AFFILIATION_TEXT = _("Affiliation");
@ -57,9 +57,9 @@ void initFighterDatabase(void)
SPEED_TEXT = _("Speed");
MISSILES_TEXT = _("Missiles");
MISSILE_NUM_TEXT = _("Missiles x %d");
dbFighters = getDBFighters(&maxPages);
gunName[BT_NONE] = "";
gunName[BT_PARTICLE] = _("Particle Cannon");
gunName[BT_PLASMA] = _("Plasma Cannon");
@ -67,7 +67,7 @@ void initFighterDatabase(void)
gunName[BT_MAG] = _("Mag Cannon");
gunName[BT_ROCKET] = _("Rockets");
gunName[BT_MISSILE] = _("Missiles");
rotation = 0;
}
@ -79,13 +79,13 @@ void destroyFighterDatabase(void)
void initFighterDatabaseDisplay(void)
{
page = 0;
prev = getWidget("prev", "fighterDB");
prev->action = prevFighter;
next = getWidget("next", "fighterDB");
next->action = nextFighter;
setNumDestroyed();
}
@ -99,83 +99,83 @@ void drawFighterDatabase(void)
SDL_Rect r;
Entity *fighter;
int i, y, numCannons;
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);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 700;
r.h = 650;
r.x = (UI_WIDTH / 2) - r.w / 2;
r.y = (UI_HEIGHT / 2) - r.h / 2;
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 255);
SDL_RenderFillRect(app.renderer, &r);
SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255);
SDL_RenderDrawRect(app.renderer, &r);
drawText(UI_WIDTH / 2, 50, 28, TA_CENTER, colors.white, DB_TEXT);
drawText(UI_WIDTH / 2, 90, 16, TA_CENTER, colors.lightGrey, PAGE_TEXT, page + 1, (int)maxPages);
fighter = dbFighters[page];
drawText(UI_WIDTH / 2, 130, 28, TA_CENTER, colors.white, fighter->name);
blitRotated(fighter->texture, r.x + (r.w / 2), 250, rotation);
if (fighter->flags & EF_COMMON_FIGHTER)
{
drawText(UI_WIDTH / 2, 170, 18, TA_CENTER, colors.darkGrey, COMMON_TEXT);
drawText(r.x + (r.w / 2), 290, 18, TA_CENTER, colors.lightGrey, "%s: %d", DESTROYED_TEXT, numDestroyed);
}
drawText(r.x + 25, 200, 22, TA_LEFT, colors.white, "%s: %s", AFFILIATION_TEXT, fighter->affiliation);
drawText(r.x + 25, 240, 22, TA_LEFT, colors.white, "%s: %d", ARMOUR_TEXT, fighter->health);
drawText(r.x + 25, 280, 22, TA_LEFT, colors.white, "%s: %d", SHIELD_TEXT, fighter->shield);
drawText(r.x + 25, 320, 22, TA_LEFT, colors.white, "%s: %.0f", SPEED_TEXT, ((fighter->speed * fighter->speed) * FPS));
y = 200;
for (i = 1 ; i < BT_MAX ; i++)
{
numCannons = countFighterGuns(fighter, i);
if (numCannons > 0)
{
drawText(r.x + r.w - 25, y, 22, TA_RIGHT, colors.white, "%s x %d", gunName[i], numCannons);
y += 40;
}
}
if (fighter->missiles > 0)
{
drawText(r.x + r.w - 25, y, 22, TA_RIGHT, colors.white, MISSILE_NUM_TEXT, fighter->missiles);
}
y = MAX(y, 320) + 75;
app.textWidth = r.w - 50;
drawText(r.x + 25, y, 18, TA_LEFT, colors.white, fighter->description);
app.textWidth = 0;
drawWidgets("fighterDB");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
static int countFighterGuns(Entity *fighter, int type)
{
int i, num;
num = 0;
for (i = 0 ; i < MAX_FIGHTER_GUNS ; i++)
{
if (fighter->guns[i].type == type)
@ -183,21 +183,21 @@ static int countFighterGuns(Entity *fighter, int type)
num++;
}
}
return num;
}
static void prevFighter(void)
{
page = mod(page - 1, maxPages);
setNumDestroyed();
}
static void nextFighter(void)
{
page = mod(page + 1, maxPages);
setNumDestroyed();
}
@ -205,11 +205,11 @@ static void setNumDestroyed(void)
{
Tuple *t;
Entity *fighter;
fighter = dbFighters[page];
numDestroyed = 0;
for (t = game.fighterStatHead.next ; t != NULL ; t = t->next)
{
if (strcmp(t->key, fighter->name) == 0)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
void initGame(void)
{
memset(&game, 0, sizeof(Game));
STRNCPY(game.selectedStarSystem, "Sol", MAX_NAME_LENGTH);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -44,9 +44,9 @@ void loadGame(void)
loadChallenges(cJSON_GetObjectItem(gameJSON, "challenges"));
loadStats(cJSON_GetObjectItem(gameJSON, "stats"));
loadTrophies(cJSON_GetObjectItem(gameJSON, "trophies"));
loadFighterStats(cJSON_GetObjectItem(gameJSON, "fighterStats"));
cJSON_Delete(root);
@ -76,7 +76,7 @@ static void loadMissions(cJSON *missionsJSON)
for (missionJSON = missionsJSON->child ; missionJSON != NULL ; missionJSON = missionJSON->next)
{
mission = getMission(cJSON_GetObjectItem(missionJSON, "filename")->valuestring);
if (mission)
{
mission->completed = cJSON_GetObjectItem(missionJSON, "completed")->valueint;
@ -133,13 +133,13 @@ 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;
@ -153,21 +153,21 @@ static void loadFighterStats(cJSON *fighterStatsJSON)
{
Tuple *t, *tail;
cJSON *fighterStatJSON;
destroyFighterStats();
tail = &game.fighterStatHead;
if (fighterStatsJSON)
{
for (fighterStatJSON = fighterStatsJSON->child ; fighterStatJSON != NULL ; fighterStatJSON = fighterStatJSON->next)
{
t = malloc(sizeof(Tuple));
memset(t, 0, sizeof(Tuple));
STRNCPY(t->key, cJSON_GetObjectItem(fighterStatJSON, "key")->valuestring, MAX_NAME_LENGTH);
t->value = cJSON_GetObjectItem(fighterStatJSON, "value")->valueint;
tail->next = t;
tail = t;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "options.h"
static void changeWindowSize(char *value);
static void changeEffectsReduction(char *value);
static void changeSoundVolume(char *value);
static void changeMusicVolume(char *value);
static void changeFullscreen(char *value);
@ -41,6 +42,7 @@ void initOptions(void (*rtn)(void))
selectWidget("windowSize", "options");
getWidget("windowSize", "options")->onChange = changeWindowSize;
getWidget("effects", "options")->onChange = changeEffectsReduction;
getWidget("soundVolume", "options")->onChange = changeSoundVolume;
getWidget("musicVolume", "options")->onChange = changeMusicVolume;
getWidget("fullscreen", "options")->onChange = changeFullscreen;
@ -51,6 +53,9 @@ void initOptions(void (*rtn)(void))
sprintf(optionStr, "%d x %d", app.winWidth, app.winHeight);
setWidgetOption("windowSize", "options", optionStr);
sprintf(optionStr, "%d", app.effects);
setWidgetOption("effects", "options", optionStr);
sprintf(optionStr, "%d", app.soundVolume);
setWidgetOption("soundVolume", "options", optionStr);
@ -58,7 +63,7 @@ void initOptions(void (*rtn)(void))
setWidgetOption("musicVolume", "options", optionStr);
setWidgetOption("fullscreen", "options", app.fullscreen ? "On" : "Off");
OPTIONS_TEXT = _("Options");
RESOLUTION_TEXT = _("Note: you must restart the game for window size and fullscreen options to take effect.");
@ -69,7 +74,7 @@ void initOptions(void (*rtn)(void))
#endif
returnFromOptions = rtn;
show = SHOW_MAIN;
}
@ -80,7 +85,7 @@ void drawOptions(void)
case SHOW_MAIN:
drawMain();
break;
case SHOW_CONTROLS:
drawControls();
break;
@ -90,12 +95,12 @@ void drawOptions(void)
static void drawMain(void)
{
SDL_Rect r;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 500;
@ -117,10 +122,12 @@ static void drawMain(void)
app.textWidth = r.w - 100;
#if !defined(__amigaos4__)
drawText(UI_WIDTH / 2, r.y + r.h - 135, 16, TA_CENTER, colors.yellow, RESOLUTION_TEXT);
#endif
app.textWidth = 0;
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -129,11 +136,11 @@ void updateCustomResolutionOption(void)
Widget *w;
char value[MAX_NAME_LENGTH];
int i;
sprintf(value, "%d x %d", app.winWidth, app.winHeight);
w = getWidget("windowSize", "options");
for (i = 0 ; i < w->numOptions - 1 ; i++)
{
if (strcmp(w->options[i], value) == 0)
@ -142,7 +149,7 @@ void updateCustomResolutionOption(void)
return;
}
}
w->options[w->numOptions - 1] = malloc(strlen(value) + 1);
strcpy(w->options[w->numOptions - 1], value);
}
@ -150,28 +157,33 @@ void updateCustomResolutionOption(void)
static void controls(void)
{
initControlsDisplay();
show = SHOW_CONTROLS;
}
static void changeWindowSize(char *value)
{
sscanf(value, "%d x %d", &app.winWidth, &app.winHeight);
SDL_SetWindowSize(app.window, app.winWidth, app.winHeight);
app.uiOffset.x = (app.winWidth / 2) - (UI_WIDTH / 2);
app.uiOffset.y = (app.winHeight / 2) - (UI_HEIGHT / 2);
SDL_DestroyTexture(app.backBuffer);
app.backBuffer = SDL_CreateTexture(app.renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, app.winWidth, app.winHeight);
initGraphics();
initStars();
}
static void changeEffectsReduction(char *value)
{
app.effects = atoi(value);
}
static void changeSoundVolume(char *value)
{
app.soundVolume = atoi(value);
@ -189,7 +201,7 @@ static void changeMusicVolume(char *value)
static void changeFullscreen(char *value)
{
app.fullscreen = strcmp(value, "On") == 0;
SDL_SetWindowFullscreen(app.window, app.fullscreen? SDL_WINDOW_FULLSCREEN : 0);
}
@ -204,3 +216,4 @@ static void controlsOK(void)
{
show = SHOW_MAIN;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -45,9 +45,9 @@ void saveGame(void)
saveChallenges(gameJSON);
saveStats(gameJSON);
saveTrophies(gameJSON);
saveFighterStats(gameJSON);
out = cJSON_Print(root);
@ -118,18 +118,18 @@ static void saveChallenges(cJSON *gameJSON)
cJSON_AddStringToObject(missionJSON, "filename", mission->filename);
challengesJSON = cJSON_CreateArray();
for (i = 0 ; i < MAX_CHALLENGES ; i++)
{
c = mission->challengeData.challenges[i];
if (c)
{
challengeJSON = cJSON_CreateObject();
cJSON_AddStringToObject(challengeJSON, "type", getLookupName("CHALLENGE_", c->type));
cJSON_AddNumberToObject(challengeJSON, "value", c->value);
cJSON_AddNumberToObject(challengeJSON, "passed", c->passed);
cJSON_AddItemToArray(challengesJSON, challengeJSON);
}
}
@ -160,7 +160,7 @@ static void saveTrophies(cJSON *gameJSON)
{
Trophy *t;
cJSON *trophiesJSON, *trophyJSON;
trophiesJSON = cJSON_CreateArray();
for (t = game.trophyHead.next ; t != NULL ; t = t->next)
@ -168,14 +168,14 @@ static void saveTrophies(cJSON *gameJSON)
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);
}
@ -183,18 +183,18 @@ static void saveFighterStats(cJSON *gameJSON)
{
Tuple *t;
cJSON *fighterStatsJSON, *fighterStatJSON;
fighterStatsJSON = cJSON_CreateArray();
for (t = game.fighterStatHead.next ; t != NULL ; t = t->next)
{
fighterStatJSON = cJSON_CreateObject();
cJSON_AddStringToObject(fighterStatJSON, "key", t->key);
cJSON_AddNumberToObject(fighterStatJSON, "value", t->value);
cJSON_AddItemToArray(fighterStatsJSON, fighterStatJSON);
}
cJSON_AddItemToObject(gameJSON, "fighterStats", fighterStatsJSON);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -74,7 +74,7 @@ void initStats(void)
statDescription[STAT_MINES_DESTROYED] = _("Mines Destroyed");
statDescription[STAT_ENEMIES_SURRENDERED] = _("Enemies Surrendered");
statDescription[STAT_TIME] = _("Time Played");
STATS_TEXT = _("Stats");
PAGE_TEXT = _("Page %d / %d");
}
@ -82,21 +82,21 @@ void initStats(void)
void initStatsDisplay(void)
{
page = 0;
maxPages = STAT_TIME;
maxPages /= STATS_PER_PAGE;
maxPages = ceil(maxPages);
prev = getWidget("prev", "stats");
prev->action = prevPage;
prev->visible = 0;
next = getWidget("next", "stats");
next->action = nextPage;
next->visible = 1;
calculatePercentComplete();
updateAccuracyStats(game.stats);
}
@ -105,9 +105,9 @@ static void calculatePercentComplete(void)
StarSystem *starSystem;
Mission *mission;
int completed, total;
completed = total = 0;
for (starSystem = game.starSystemHead.next ; starSystem != NULL ; starSystem = starSystem->next)
{
if (starSystem->type == SS_NORMAL)
@ -116,13 +116,13 @@ static void calculatePercentComplete(void)
total += starSystem->totalMissions;
}
}
for (mission = game.challengeMissionHead.next ; mission != NULL ; mission = mission->next)
{
completed += mission->completedChallenges;
total += mission->totalChallenges;
}
game.stats[STAT_PERCENT_COMPLETE] = getPercent(completed, total);
}
@ -130,41 +130,41 @@ void drawStats(void)
{
int i, y, startIndex;
SDL_Rect r;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = 500;
r.h = 600;
r.x = (UI_WIDTH / 2) - r.w / 2;
r.y = (UI_HEIGHT / 2) - r.h / 2;
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 255);
SDL_RenderFillRect(app.renderer, &r);
SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255);
SDL_RenderDrawRect(app.renderer, &r);
drawText(UI_WIDTH / 2, 70, 28, TA_CENTER, colors.white, STATS_TEXT);
drawText(UI_WIDTH / 2, 110, 16, TA_CENTER, colors.lightGrey, PAGE_TEXT, page + 1, (int)maxPages);
SDL_SetRenderDrawColor(app.renderer, 128, 128, 128, 255);
SDL_RenderDrawLine(app.renderer, r.x, 150, r.x + r.w, 150);
y = 170;
startIndex = (page * STATS_PER_PAGE);
for (i = startIndex ; i < startIndex + STATS_PER_PAGE ; i++)
{
if (i < STAT_TIME)
{
drawText(r.x + 20, y, 18, TA_LEFT, colors.white, statDescription[i]);
switch (i)
{
case STAT_PERCENT_COMPLETE:
@ -173,28 +173,28 @@ void drawStats(void)
case STAT_MISSILE_ACCURACY:
drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d%%", game.stats[i]);
break;
default:
drawText(r.x + r.w - 20, y, 18, TA_RIGHT, colors.white, "%d", game.stats[i]);
break;
}
y += 40;
}
}
drawText(r.x + 20, 565, 18, TA_LEFT, colors.white, statDescription[STAT_TIME]);
drawText(r.x + r.w - 20, 565, 18, TA_RIGHT, colors.white, timeToString(game.stats[STAT_TIME], 1));
drawWidgets("stats");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
static void nextPage(void)
{
page = MIN(page + 1, maxPages - 1);
next->visible = page < maxPages - 1;
prev->visible = 1;
}
@ -202,7 +202,7 @@ static void nextPage(void)
static void prevPage(void)
{
page = MAX(0, page - 1);
next->visible = 1;
prev->visible = page > 0;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -49,35 +49,35 @@ static int show;
void initTitle(void)
{
startSectionTransition();
stopMusic();
app.delegate.logic = &logic;
app.delegate.draw = &draw;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
battle.camera.x = battle.camera.y = 0;
destroyBattle();
logo[0] = getAtlasImage("gfx/title/logo01.png");
logo[1] = getAtlasImage("gfx/title/logo02.png");
pandoranWar = getAtlasImage("gfx/title/pandoran.png");
background = getTexture("gfx/backgrounds/background02.jpg");
earthTexture = getAtlasImage("gfx/planets/earth.png");
earth.x = rand() % app.winWidth;
earth.y = -(128 + (rand() % 128));
initEffects();
initFighters();
updateAllMissions();
getWidget("campaign", "title")->action = campaign;
getWidget("challenges", "title")->action = challenges;
getWidget("trophies", "title")->action = trophies;
@ -86,28 +86,28 @@ void initTitle(void)
getWidget("options", "title")->action = options;
getWidget("credits", "title")->action = credits;
getWidget("quit", "title")->action = quit;
getWidget("ok", "stats")->action = ok;
getWidget("ok", "trophies")->action = ok;
getWidget("ok", "fighterDB")->action = ok;
autoSizeWidgetButtons("title", 1);
show = SHOW_TITLE;
endSectionTransition();
playMusic("music/main/Rise of spirit.ogg", 0);
}
static void initFighters(void)
{
int i, numTextures;
numTextures = sizeof(fighterTextures) / sizeof(char*);
memset(&fighters, 0, sizeof(Entity) * NUM_FIGHTERS);
for (i = 0 ; i < NUM_FIGHTERS ; i++)
{
fighters[i].x = rand() % (app.winWidth - 32);
@ -120,50 +120,50 @@ static void initFighters(void)
static void logic(void)
{
handleKeyboard();
scrollBackground(0, 0.25);
doStars(0, -0.5);
earth.y += 0.1;
if (earth.y > app.winHeight + 128)
{
earth.x = rand() % app.winWidth;
earth.y = -(128 + (rand() % 128));
}
doFighters();
doEffects();
app.doTrophyAlerts = 1;
if (show == SHOW_FIGHTER_DB)
{
doFighterDatabase();
}
doWidgets();
}
static void doFighters(void)
{
int i, numTextures;
numTextures = sizeof(fighterTextures) / sizeof(char*);
for (i = 0 ; i < NUM_FIGHTERS ; i++)
{
self = &fighters[i];
/* engine position hack, due to camera being fixed */
self->y += 16;
addEngineEffect();
self->y -= 16;
self->y += self->dy;
if (self->y <= -64)
{
self->x = rand() % (app.winWidth - 32);
@ -177,27 +177,27 @@ static void doFighters(void)
static void draw(void)
{
drawBackground(background);
drawStars();
setAtlasColor(255, 255, 255, 255);
blit(earthTexture, earth.x, earth.y, 1);
drawFighters();
drawEffects();
setAtlasColor(255, 255, 255, 255);
blit(logo[0], (app.winWidth / 2) - logo[0]->rect.w, 30, 0);
blit(logo[1], (app.winWidth / 2), 30, 0);
blit(pandoranWar, app.winWidth / 2, 110, 1);
drawText(10, app.winHeight - 25, 14, TA_LEFT, colors.white, "Copyright Parallel Realities, 2015-2018");
drawText(10, app.winHeight - 25, 14, TA_LEFT, colors.white, "Copyright Parallel Realities, 2015-2019");
drawText(app.winWidth - 10, app.winHeight - 25, 14, TA_RIGHT, colors.white, "Version %.2f.%d", VERSION, REVISION);
switch (show)
{
case SHOW_TITLE:
@ -205,19 +205,19 @@ static void draw(void)
drawWidgets("title");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
break;
case SHOW_STATS:
drawStats();
break;
case SHOW_OPTIONS:
drawOptions();
break;
case SHOW_TROPHIES:
drawTrophies();
break;
case SHOW_FIGHTER_DB:
drawFighterDatabase();
break;
@ -227,9 +227,9 @@ static void draw(void)
static void drawFighters(void)
{
int i;
setAtlasColor(255, 255, 255, 255);
for (i = 0 ; i < NUM_FIGHTERS ; i++)
{
blit(fighters[i].texture, fighters[i].x, fighters[i].y, 1);
@ -242,7 +242,7 @@ static void handleKeyboard(void)
{
returnFromOptions();
playSound(SND_GUI_CLOSE);
clearInput();
}
}
@ -250,57 +250,57 @@ 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 fighterDatabase(void)
{
show = SHOW_FIGHTER_DB;
initFighterDatabaseDisplay();
}
static void options(void)
{
selectWidget("ok", "options");
show = SHOW_OPTIONS;
initOptions(returnFromOptions);
}
static void stats(void)
{
selectWidget("ok", "stats");
show = SHOW_STATS;
initStatsDisplay();
}
static void ok(void)
{
selectWidget("stats", "title");
show = SHOW_TITLE;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -57,12 +57,12 @@ void initTrophies(void)
trophyIcons[TROPHY_UNEARNED] = getAtlasImage("gfx/trophies/unearned.png");
sparkle = getAtlasImage("gfx/trophies/sparkle.png");
alertSphere = getAtlasImage("gfx/trophies/alertSphere.png");
alertRect.h = 90;
alertRect.y = 10;
sparkleAngle = 0;
TROPHIES_TEXT = _("Trophies");
AWARDED_TEXT = _("Awarded : %d / %d");
PAGE_TEXT = _("Page : %d / %d");
@ -75,37 +75,37 @@ 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);
}
calcTextDimensions(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;
@ -114,7 +114,7 @@ void initTrophiesDisplay(void)
static void nextPage(void)
{
page = MIN(page + 1, maxPages - 1);
next->visible = page < maxPages - 1;
prev->visible = 1;
}
@ -122,7 +122,7 @@ static void nextPage(void)
static void prevPage(void)
{
page = MAX(0, page - 1);
next->visible = 1;
prev->visible = page > 0;
}
@ -132,37 +132,37 @@ 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);
SDL_SetRenderTarget(app.renderer, app.uiBuffer);
r.w = boxWidth;
r.h = 650;
r.x = (UI_WIDTH / 2) - r.w / 2;
r.y = (UI_HEIGHT / 2) - r.h / 2;
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 255);
SDL_RenderFillRect(app.renderer, &r);
SDL_SetRenderDrawColor(app.renderer, 200, 200, 200, 255);
SDL_RenderDrawRect(app.renderer, &r);
drawText(UI_WIDTH / 2, 40, 28, TA_CENTER, colors.white, TROPHIES_TEXT);
drawText(UI_WIDTH / 2, 83, 16, TA_CENTER, colors.lightGrey, AWARDED_TEXT, awarded, total);
drawText(UI_WIDTH / 2, 110, 16, TA_CENTER, colors.lightGrey, PAGE_TEXT, 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)
@ -172,7 +172,7 @@ void drawTrophies(void)
setSparkleColor(t);
blitRotated(sparkle, x + 32, y + 32, sparkleAngle);
blitRotated(sparkle, x + 32, y + 32, -sparkleAngle);
setAtlasColor(255, 255, 255, 255);
blitScaled(trophyIcons[t->value], x, y, 64, 64, 0);
drawText(x + 85, y - 10, 20, TA_LEFT, colors.yellow, t->title);
@ -195,15 +195,15 @@ void drawTrophies(void)
drawText(x + 85, y + 20, 20, TA_LEFT, colors.darkGrey, HIDDEN_TEXT);
}
}
y += 120;
}
i++;
}
drawWidgets("trophies");
SDL_SetRenderTarget(app.renderer, app.backBuffer);
}
@ -211,9 +211,9 @@ 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)
@ -221,21 +221,21 @@ void awardTrophy(char *id)
t->awarded = 1;
t->awardDate = time(NULL);
t->notify = SDL_GetTicks();
/* prevent race condition */
SDL_Delay(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)
{
@ -264,7 +264,7 @@ void doTrophyAlerts(void)
resetAlert();
}
}
sparkleAngle = mod(sparkleAngle + 0.25, 360);
}
@ -283,15 +283,15 @@ static void nextAlert(void)
}
}
}
if (alertTrophy)
{
playSound(SND_TROPHY);
calcTextDimensions(alertTrophy->title, 30, &alertRect.w, &h);
calcTextDimensions(alertTrophy->description, 20, &w, &h);
alertRect.w = MAX(alertRect.w, w);
alertRect.w = MAX(400, alertRect.w);
alertRect.w += 125;
@ -308,7 +308,7 @@ static void resetAlert(void)
void drawTrophyAlert(void)
{
int x, y;
if (alertTrophy)
{
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 255);
@ -319,9 +319,9 @@ void drawTrophyAlert(void)
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;
@ -360,7 +360,7 @@ static void loadTrophyData(char *filename)
root = cJSON_Parse(text);
tail = &game.trophyHead;
memset(count, 0, sizeof(int) * TROPHY_MAX);
for (node = root->child ; node != NULL ; node = node->next)
@ -375,16 +375,16 @@ static void loadTrophyData(char *filename)
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;
}
count[t->value]++;
count[TROPHY_UNEARNED]++;
@ -392,7 +392,7 @@ static void loadTrophyData(char *filename)
tail = t;
}
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Trophies (%d) [Bronze=%d, Silver=%d, Gold=%d, Platinum=%d]", count[TROPHY_UNEARNED], count[TROPHY_BRONZE], count[TROPHY_SILVER], count[TROPHY_GOLD], count[TROPHY_PLATINUM]);
cJSON_Delete(root);
@ -411,7 +411,7 @@ void awardStatsTrophies(void)
awardTrophy(t->id);
}
}
/* check to see if we've destroyed one of each common starfighter */
for (tp = game.fighterStatHead.next ; tp != NULL ; tp = tp->next)
{
@ -420,17 +420,17 @@ void awardStatsTrophies(void)
return;
}
}
awardTrophy("FREQUENT_FLYER");
}
void awardCampaignTrophies(void)
{
char trophyId[MAX_NAME_LENGTH];
char trophyId[MAX_NAME_LENGTH * 2];
char name[MAX_NAME_LENGTH];
int i, len;
StarSystem *starSystem;
if (game.completedMissions)
{
awardTrophy("CAMPAIGN_1");
@ -449,7 +449,7 @@ void awardCampaignTrophies(void)
{
name[i] = toupper(starSystem->name[i]);
}
sprintf(trophyId, "CAMPAIGN_%s", name);
awardTrophy(trophyId);
}
@ -472,13 +472,13 @@ void awardPostMissionTrophies(void)
if (game.currentMission->epic)
{
awardTrophy("EPIC");
if (battle.stats[STAT_PLAYER_KILLED] == 0 && player->flags & EF_COMMON_FIGHTER)
{
awardTrophy("SURVIVOR");
}
}
/*
* Must be a non-challenge mission, a common fighter, must not be Sol, and must not have fired any shots or missiles (and there should have been some enemies present)
*/
@ -508,7 +508,7 @@ void awardCraftTrophy(void)
awardTrophy("SHUTTLE");
}
}
awardPandoranCraftTrophy();
}
@ -519,17 +519,18 @@ static void setSparkleColor(Trophy *t)
case TROPHY_BRONZE:
setAtlasColor(255, 128, 0, 255);
break;
case TROPHY_SILVER:
setAtlasColor(192, 192, 192, 255);
break;
case TROPHY_GOLD:
setAtlasColor(255, 255, 0, 255);
break;
case TROPHY_PLATINUM:
setAtlasColor(0, 128, 255, 255);
break;
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View File

@ -1,16 +1,16 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -36,7 +36,7 @@ extern "C"
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
@ -83,7 +83,7 @@ extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
@ -113,7 +113,7 @@ extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -28,103 +28,103 @@ int main(int argc, char *argv[])
{
long then, lastFrameTime, frames;
float remainder;
memset(&app, 0, sizeof(App));
memset(&dev, 0, sizeof(Dev));
handleLoggingArgs(argc, argv);
atexit(cleanup);
srand(time(NULL));
init18N(argc, argv);
initLookups();
initSDL(argc, argv);
initGameSystem();
createScreenshotFolder();
if (fileExists(getSaveFilePath(SAVE_FILENAME)))
{
loadGame();
}
handleMissionArgs(argc, argv);
remainder = 0;
dev.fps = frames = 0;
then = SDL_GetTicks();
lastFrameTime = SDL_GetTicks() + 1000;
while (1)
{
capFrameRate(&then, &remainder);
doInput();
if (app.modalDialog.type != MD_NONE)
{
doModalDialog();
}
/* let the delegate decide during logic() */
app.doTrophyAlerts = 0;
app.delegate.logic();
if (app.doTrophyAlerts)
{
doTrophyAlerts();
}
game.stats[STAT_TIME]++;
/* always zero the mouse motion */
app.mouse.dx = app.mouse.dy = 0;
prepareScene();
app.delegate.draw();
if (app.doTrophyAlerts)
{
drawTrophyAlert();
}
if (app.modalDialog.type != MD_NONE)
{
drawModalDialog();
}
presentScene();
doDevKeys();
frames++;
if (SDL_GetTicks() > lastFrameTime)
{
dev.fps = frames;
frames = 0;
lastFrameTime = SDL_GetTicks() + 1000;
if (dev.takeScreenshots)
{
saveScreenshot();
}
}
if (isControl(CONTROL_SCREENSHOT))
{
saveScreenshot();
clearControl(CONTROL_SCREENSHOT);
}
/* don't save more than once per request, and not in the middle of battle */
if (app.saveGame && battle.status != MS_IN_PROGRESS)
{
@ -141,40 +141,40 @@ int main(int argc, char *argv[])
static void capFrameRate(long *then, float *remainder)
{
long wait;
wait = 16 + *remainder;
*remainder -= (int)*remainder;
wait -= (SDL_GetTicks() - *then);
if (wait < 1)
{
wait = 1;
}
SDL_Delay(wait);
*remainder += 0.667;
*remainder += 0.666667;
*then = SDL_GetTicks();
}
static void handleLoggingArgs(int argc, char *argv[])
{
int i;
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN);
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], "-info") == 0)
{
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
@ -185,25 +185,25 @@ static void handleLoggingArgs(int argc, char *argv[])
static void handleMissionArgs(int argc, char *argv[])
{
int i, testingMission, showCredits;
showCredits = testingMission = 0;
for (i = 1 ; i < argc ; i++)
{
/* assume this is filename for testing */
if (strcmp(argv[i], "-mission") == 0)
{
loadTestMission(argv[++i]);
testingMission = 1;
}
if (strcmp(argv[i], "-credits") == 0)
{
showCredits = 1;
}
}
if (showCredits)
{
initCredits();

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2015-2018 Parallel Realities
Copyright (C) 2015-2019 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

101
src/plat/os4/os4Init.c Normal file
View File

@ -0,0 +1,101 @@
/*
Copyright (C) 2015-2019,2022 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <errno.h>
#include <pwd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include "../../common.h"
#include "os4Init.h"
#define VSTRING "tbftss 1.50.1r1 (22.08.2022)"
#define VERSTAG "\0$VER: " VSTRING
static CONST_STRPTR stack USED = "$STACK:102400";
static CONST_STRPTR version USED = VERSTAG;
extern App app;
extern Dev dev;
void createSaveFolder(void)
{
// char *dir;
// int i;
BPTR savesPathLock = Lock("PROGDIR:saves", SHARED_LOCK);
if (!savesPathLock)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Saves folder not found. I am going to create it.");
// mkpath("PROGDIR:saves");
if (mkdir("PROGDIR:saves", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to create save dir.");
return;
}
}
else {
UnLock(savesPathLock);
}
// for (i = 0 ; i < MAX_SAVE_SLOTS ; i++)
// {
// dir = buildFormattedString("saves/%d", i);
// mkpath(dir);
// free(dir);
// }
// app.saveDir = "saves";
STRNCPY(app.saveDir, "saves", MAX_FILENAME_LENGTH);
// char *userHome;
// char dir[MAX_FILENAME_LENGTH];
// userHome = getenv("HOME");
// if (!userHome)
// {
// SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Unable to determine user save folder. Will save to current dir.");
// return;
// }
// SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "User home = %s", userHome);
// sprintf(dir, "%s/.local/share/tbftss", userHome);
// if (mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST)
// {
// SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to create save dir '%s'. Will save to current dir.", dir);
// return;
// }
// STRNCPY(app.saveDir, dir, MAX_FILENAME_LENGTH);
}
void createScreenshotFolder(void)
{
mkdir("PROGDIR:screenshots", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
dev.screenshotFolder = "screenshots";
}

22
src/plat/os4/os4Init.h Executable file
View File

@ -0,0 +1,22 @@
/*
Copyright (C) 2015-2019,2022 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
void createScreenshotFolder(void);
void createSaveFolder(void);

Some files were not shown because too many files have changed in this diff Show More