Compare commits

...

287 Commits

Author SHA1 Message Date
George Sokianos 877c78509d Prepare MorphOS release 2022-09-19 21:00:29 +01:00
George Sokianos 2672b953a3 A lot of changes for speed up, code clean up, new release preparation and MorphOS code added 2022-09-19 19:29:41 +01:00
George Sokianos d7363ad95f Some more changes preparing the release 2022-08-13 13:57:37 +01:00
George Sokianos 575b701190 Changes to compile and work under AmigaOS 4 2022-08-13 10:20:11 +01:00
Steve 1a684a9737 Report success for deleting files that don't exist! (save game regression). 2019-12-02 07:47:16 +00:00
Steve 13c8c9c05a Windows and Mac make files. 2019-12-01 11:57:04 +00:00
Steve 2fa40d8933 Delete temporary files before attempting to rename (Windows and some Unix fixes). 2019-12-01 11:56:49 +00:00
Steve e8a8e87666 Removed Windows and Mac builds. Too buggy in cross compile. 2019-06-02 17:32:26 +01:00
Steve 1093c16ed0 Atlas update. 2019-06-02 16:13:34 +01:00
Steve 9717047d47 Faster map loading. 2019-01-19 13:19:23 +00:00
Steve a064e3ed4c Don't use atlas for clouds. Helps to eliminate texture seam. 2018-12-28 11:00:45 +00:00
Steve a7310e43b1 Text rendering tweaks. 2018-12-23 15:32:33 +00:00
Steve fc0bcc998c Replaced cached text with font atlas. 2018-12-22 22:46:38 +00:00
Steve 86be9a25b9 Start of resolution updates. 2018-12-22 21:53:19 +00:00
Steve 9acb52163c Updated links from stephenjsweeney.com to parallelrealities.co.uk. 2018-07-17 09:17:01 +01:00
Steve 9bceef8044 Cap frame rate at 60fps. 2018-07-07 07:00:55 +01:00
Steve 08ef2920cf Don't treat warnings as errors. 2018-07-07 07:00:45 +01:00
Steve f6fd6b918d v1.1.1 2018-07-07 07:00:33 +01:00
Steve 986cb78d7b Freeplay manual updates. 2018-05-18 07:54:41 +01:00
Steve 49abba5faa Use a . in $VERSION.$REVISION instead of a -. 2018-05-18 07:42:14 +01:00
Steve f9064d26f7 Don't force mirroring in world test. 2018-05-16 08:16:54 +01:00
Steve c6aa5f60aa Additional mission configuration info text. 2018-05-16 08:06:52 +01:00
Steve 021a02f8e9 Correctly adjust teleporter destination when mirroring. 2018-05-16 08:06:37 +01:00
Steve 24f677236a Removed all objectives tweak, replaced with No Doors. Tweaks to item and pushblock mirroring. Other minor mission tweak fixes. 2018-05-15 08:32:16 +01:00
Steve 1ad4746a27 Merge branch 'develop' into plus 2018-05-15 07:46:53 +01:00
Steve 7598af42a0 GCC compile fix for fadeAmount not being initialized. 2018-05-15 07:37:27 +01:00
Steve 0395d25594 Use PLUS_ALL_OBJS to test for required objectives. 2018-05-14 08:32:45 +01:00
Steve 455db3d077 Correctly mirror doors in mirror mode. 2018-05-14 08:23:54 +01:00
Steve 230d28cef7 Mirror world tweaks. 2018-05-13 17:25:00 +01:00
Steve 0c631edd09 Start of map mirroring. 2018-05-13 08:59:30 +01:00
Steve 05e7fc7cad Updated mission config settings. 2018-05-12 11:50:49 +01:00
Steve 7eefeeed86 Set language size to be MAX_DESCRIPTION_LENGTH, not MAX_LINE_LENGTH. 2018-05-11 08:42:04 +01:00
Steve 181fc83632 Start of custom mission plus settings. 2018-05-11 08:09:15 +01:00
Steve 60d8020c4e Game plus tweaks. 2018-05-02 07:55:55 +01:00
Steve 693ed5f032 Exit if we try to load corrupt data (although we shouldn't really get this far). 2018-05-01 18:17:16 +01:00
Steve cdc69cc6a5 Various Game Plus tweaks. 2018-05-01 18:15:56 +01:00
Steve 3ae8a2a717 Give enemies more health in Plus mode. 2018-05-01 08:40:57 +01:00
Steve 6fe72e4b2a Start of experimental Mission Plus mode. 2018-05-01 08:38:46 +01:00
Steve 220525d6f8 Removed references to trophy screenshot, as this feature no longer exists. 2018-04-30 08:36:51 +01:00
Steve 224952a962 Check for possible corrupt save files and prevent loading. 2018-04-29 07:47:37 +01:00
Steve 3a99531a04 Don't include missions complete in % stats for save label. Correctly handle %. 2018-04-28 16:09:24 +01:00
Steve 01448698ad Item to reset items that are stuck in walls are mission start. 2018-04-28 15:55:01 +01:00
Steve 47ae458edd Memory corruption fix. 2018-04-28 09:50:01 +01:00
Steve bb054c28b4 v1.0.3 2018-04-28 09:46:26 +01:00
Steve cd8ee71c30 Save grenade combo value to correct stat slot. 2018-04-27 18:22:32 +01:00
Steve c4efe60abd Don't allow laser traps to keep victims alive indefinitely. 2018-04-26 09:07:32 +01:00
Steve 9bafce978f Don't save Teeka - there is never an instance in the game where he needs to be persisted. 2018-04-25 18:15:23 +01:00
Steve ceaced512f If Bob was stunned when the game is saving, set him back to normal facing so we don't error. 2018-04-25 08:17:49 +01:00
Steve 9c1b39179d Tidied up headers. 2018-04-25 07:56:06 +01:00
Steve 5120b6586b Updated POWs to MIAs. 2018-04-24 19:04:35 +01:00
Steve d4f310119f Centre bullets more inside shooter. 2018-04-24 19:04:08 +01:00
Steve 73e0e4b17a Attempt to save the game and world data atomically. 2018-04-24 08:27:42 +01:00
Steve 67a6ad5422 Don't hardcode Tab in the message. 2018-04-24 08:27:16 +01:00
Steve d642a72e3c Merge remote-tracking branch 'origin/master' into develop 2018-04-24 07:23:48 +01:00
Stephen J Sweeney 5b499b7be7
Merge pull request #10 from LeifAndersen/fixtext
Change prose since no longer on a touch screen.
2018-04-24 07:23:17 +01:00
Steve 5f212282b2 Added grenade combo counter HUD message and gameplay stat. 2018-04-24 07:17:05 +01:00
Leif Andersen 2b576c402b
Change prose since no longer on a touch screen. 2018-04-24 00:34:47 -04:00
Steve fab49ae250 Added missing Linux .desktop file. 2018-04-23 07:10:21 +01:00
Steve 7851495d28 v1.0.2. 2018-04-22 18:47:44 +01:00
Steve 38c47e2809 (some corrections from previous merge) 2018-04-22 18:47:10 +01:00
Steve dd521bdb6d Merge remote-tracking branch 'origin/master' into develop 2018-04-22 18:44:53 +01:00
Stephen J Sweeney d359b99e98
Merge pull request #7 from noahadvs/master
Change "blobWarsAttrition" to "blobwarsAttrition"
2018-04-22 18:44:15 +01:00
Noah Davis 85e66da367 Fix naming inconsistency
All instances of 'blobWarsAttrition' have been changed to 'blobwarsAttrition to match the name of the GitHub repository.

This also fixes an issue with the makefile for Unix-like systems with case sensitive file systems where it could not 'make install' because of the naming inconsistency.
2018-04-22 04:43:49 -04:00
Steve c2b2b86710 Merge branch 'paths' into develop 2018-04-22 09:11:25 +01:00
Steve 103aa91165 Only use *lang if not Windows. 2018-04-21 18:38:39 +01:00
Steve 5b6dfecebb We only need to use strtok here. 2018-04-21 18:35:16 +01:00
Steve 7633322d1e Avoid array (string) overlapping. 2018-04-21 17:21:10 +01:00
Steve c2712d8916 Don't save trophy screenshot - is too buggy and often crashes. 2018-04-21 12:43:50 +01:00
Steve 09afbfc0d9 Load and use correct save slot. 2018-04-21 12:13:29 +01:00
Steve f5bdb5e59a Use malloc to create some sprintf string values (long paths). 2018-04-21 11:54:06 +01:00
Steve c91aac41fe Don't sprintf into filename var. 2018-04-21 10:41:36 +01:00
Steve ead0c5335a Use MAX_PATH (4096) characters for save paths. 2018-04-21 10:10:58 +01:00
Steve 1566a9ea06 Only use the allowed joystick axis values (max is 2 - range check). 2018-04-21 09:41:46 +01:00
Steve 4c1bd993e4 Reset warning text on title screen. 2018-04-21 09:40:38 +01:00
Steve 7b49eb95d9 Save the jetpack control options. 2018-04-21 09:40:15 +01:00
Steve 494474205d 1.0 revision 1. 2018-04-21 09:40:02 +01:00
Steve 959621689f Add revision number to build folders. 2018-04-16 19:11:41 +01:00
Steve e140c525e2 Build system updates. 2018-04-15 18:52:13 +01:00
Steve 852e7ca93e Include mission descriptions in pot. 2018-04-15 12:32:57 +01:00
Steve deeaa596d1 Updated i18n. 2018-04-15 12:27:41 +01:00
Steve 775dc8d71d Create screenshot folder as needed. 2018-04-15 10:45:18 +01:00
Steve 2031d5a301 Correctly handle free play mode. 2018-04-15 09:26:29 +01:00
Steve 7cfac40aa8 Added game complete mission quit message. 2018-04-15 09:26:15 +01:00
Steve 8100c45446 Make heart and cell appear a little more often when game is complete. 2018-04-15 09:25:53 +01:00
Steve 1de2c09e00 Reduce tank turret height so that the laser doesn't hit it through the tracks. 2018-04-15 09:24:50 +01:00
Steve 630c01ac8b Don't draw negative health values. 2018-04-14 16:54:45 +01:00
Steve c1afe6af39 Formatting. 2018-04-12 16:05:48 +01:00
Steve 66681c94bc Report too many keys and items separately. 2018-04-12 16:05:41 +01:00
Steve ad74cab6bf i18n updates. 2018-04-12 16:05:13 +01:00
Steve 72ffa2a021 Don't add keys to stash if this is a training mission. 2018-04-07 10:19:28 +01:00
Steve 95eb5bd011 v1.0 2018-04-07 10:19:08 +01:00
Steve fe7636e925 Final manual updates. 2018-04-07 10:02:38 +01:00
Steve b082d9957b Spelling. 2018-04-07 09:48:54 +01:00
Steve 20175102f9 Added final manual information. 2018-04-07 09:45:08 +01:00
Steve 18e3e198c5 More gameplay manual updates. 2018-04-06 19:11:43 +01:00
Steve 2a43a563bb Further docs updates. 2018-04-05 08:31:35 +01:00
Steve bb5536e714 Manual updates. 2018-04-04 08:16:52 +01:00
Steve 6f49aa8717 Display "Controls" text on controls options screen. 2018-04-04 08:16:36 +01:00
Steve a7d18ca312 Gameplay manual updates. 2018-04-03 08:24:06 +01:00
Steve 780348d2d4 Start of gameplay manual. 2018-04-02 09:51:47 +01:00
Steve e6bf90a56b Widget creation crash fix. 2018-04-02 08:53:24 +01:00
Steve 73ace650e1 i18n updates. 2018-04-01 17:41:45 +01:00
Steve b395c7e8d2 Correctly clip narrow height levels. 2018-03-31 19:05:20 +01:00
Steve 55b163873d Bob's laser should ignore Teeka. 2018-03-31 19:04:34 +01:00
Steve 14dbe2b39c Count number of trophies during loading, to prevent amount from accumulating. 2018-03-31 18:41:22 +01:00
Steve ff9f3c5f61 v0.9 2018-03-30 19:25:32 +01:00
Steve 302997cb31 Code clean up. 2018-03-30 19:23:57 +01:00
Steve e59b0f9461 Add icons. 2018-03-30 19:22:57 +01:00
Steve 051ca6d790 Save world(!) 2018-03-30 13:35:51 +01:00
Steve f1b2e8df6d Ending tweaks. 2018-03-30 13:34:36 +01:00
Steve 39362061bf Save the game when exiting a previously visited level. 2018-03-30 11:23:36 +01:00
Steve 7c4da64c04 Drop carried items when game is complete. 2018-03-30 11:23:13 +01:00
Steve a01052b1e8 Correctly unlock all levels when game is complete. 2018-03-30 11:22:33 +01:00
Steve 8a61323362 MIsc bug fixes. 2018-03-29 08:21:36 +01:00
Steve ed8bc92ce1 Added Mac makefile. 2018-03-29 08:21:15 +01:00
Steve ce9db25ed7 When returning to a mission, use the full target value. 2018-03-25 15:28:20 +01:00
Steve 15043e7776 Create save directories recursively. 2018-03-25 09:25:46 +01:00
Steve e1992b8ce4 Windows build updates. 2018-03-24 16:58:04 +00:00
Steve 30103bde5c Only inc objective count if not already dead. 2018-03-24 16:57:48 +00:00
Steve 22f42294a8 Window build tweaks. 2018-03-24 08:35:28 +00:00
Steve 745075172b Make destructable objects throw debris when destroyed. 2018-03-24 08:16:33 +00:00
Steve 464874faa2 Start of Windows build. 2018-03-23 18:38:12 +00:00
Steve 0ddb167bb3 Extended timeout a little. 2018-03-23 08:39:15 +00:00
Steve 9cd0fc21f3 Make cannon scatter debris when it dies. 2018-03-23 08:39:03 +00:00
Steve 507327c853 Allow debris to live a little longer, so we can see it burning. 2018-03-23 08:06:11 +00:00
Steve 6044cbf957 Kill debris if it falls into liquid. 2018-03-23 08:05:41 +00:00
Steve 290613612e README.md update. 2018-03-22 18:23:33 +00:00
Steve 0224b2b3fe v0.8 2018-03-22 18:23:20 +00:00
Steve a841c661f8 v0.7-02 screenshot. 2018-03-21 18:32:38 +00:00
Steve 3c38c07cbb v0.7-01 screenshot. 2018-03-21 18:30:49 +00:00
Steve 28f84f5236 Tidied all headers. 2018-03-21 18:26:46 +00:00
Steve 726243fcfe Correctly delete save files. 2018-03-21 18:25:29 +00:00
Steve 8339109f58 Updated free play level description. 2018-03-21 18:07:28 +00:00
Steve 4d07b005f0 Remove info points if game is complete. 2018-03-21 18:07:15 +00:00
Steve 7f705a6641 Tidy. 2018-03-21 08:44:30 +00:00
Steve 4e7bbf7190 Use rising parameter for flames. 2018-03-21 08:20:34 +00:00
Steve a91cb02b5a Add extra blood when extra blood is turned on. 2018-03-21 08:14:50 +00:00
Steve 39573010b7 Add blood decal when Bob dies. 2018-03-21 08:14:29 +00:00
Steve c36c36dd60 Make Bob and enemies pop into white spheres when no blood option is selected. 2018-03-21 07:43:54 +00:00
Steve 96949ec97c Play pop sound when no blood option selected. 2018-03-21 07:29:04 +00:00
Steve 09487a5eb9 Escape to go back in title. 2018-03-21 07:26:11 +00:00
Steve d7672cd2cc Destroy credits data. 2018-03-21 07:25:54 +00:00
Steve 0605da87ee Handle end of game in post mission. 2018-03-20 19:26:14 +00:00
Steve 6d9264fbac Don't play credits music if invoked from title. 2018-03-20 19:19:18 +00:00
Steve 44dcd06221 Title music, title fade, and save slot usage. 2018-03-20 08:20:56 +00:00
Steve e0a7a3511e Updates to title screen. 2018-03-20 07:29:05 +00:00
Steve d43811a32d Allow data to be installed (will fail if dir doesn't exist). 2018-03-19 22:52:00 +00:00
Steve eae43acc73 Load / continue game updates. 2018-03-19 22:51:37 +00:00
Steve ea5e23d568 Don't use git rev list for revision number. 2018-03-19 22:51:20 +00:00
Steve cdf34e1c97 Cap time. 2018-03-19 22:50:56 +00:00
Steve 64c0a2bb74 Start of title screen. 2018-03-19 08:08:29 +00:00
Steve 25c3c499c5 Make droids and evil blobs more aggressive. 2018-03-19 08:08:18 +00:00
Steve 6cf315d3ef Set reappearing units to always process, so they don't vanish for good. 2018-03-18 12:55:51 +00:00
Steve 5828a660d3 Flag MIA as rescued immediately. 2018-03-18 12:48:52 +00:00
Steve e923f3286e Terminate Bob's jetpack upon return from teleporter. 2018-03-18 12:48:31 +00:00
Steve 32949a192c Start of multiple save support. 2018-03-18 09:42:34 +00:00
Steve c39974e2a7 Don't reset a unit's alive status if it's already dead. 2018-03-18 08:36:51 +00:00
Steve cf5939dd3c Trophy display bug fix. 2018-03-18 07:40:39 +00:00
Steve c0bcfca334 Tidied headers. 2018-03-17 17:33:09 +00:00
Steve 65b37c5221 Tidy headers fix. 2018-03-17 17:33:00 +00:00
Steve 09aa386c16 Render health / power with percentages. 2018-03-17 16:58:42 +00:00
Steve 151376fc52 Correcly unlock Teeka's mission. 2018-03-17 16:58:25 +00:00
Steve c240449530 Don't block keys from being picked up when inventory is full. 2018-03-17 16:58:14 +00:00
Steve 22a01ea5a0 Reset teleporter animation frames when activating. 2018-03-17 16:57:51 +00:00
Steve 12ce22fd57 Name "Lift" as "Platform", to be more generic. 2018-03-17 16:57:35 +00:00
Steve 1becdb42cc Reset Teeka's exit mission flag. 2018-03-17 16:57:11 +00:00
Steve 50aea7c890 Report entities being outside of game world. 2018-03-16 22:27:47 +00:00
Steve 513f7fdb58 1 in 5 chance of cell or heart being available when in free play mode. 2018-03-16 22:27:26 +00:00
Steve 0f768f593e Don't show blood if blood is off. 2018-03-16 22:26:42 +00:00
Steve 5bc3747198 Don't make the power and health bars too long. 2018-03-16 22:26:13 +00:00
Steve 22cc851a2a Base chance of cherry / battery drop on the levels of player health and power. 2018-03-16 22:25:45 +00:00
Steve 36c1d9cfe3 Code tidy. 2018-03-16 08:30:37 +00:00
Steve 930ca048a9 Unlock all missions when game is complete, for free play. Remove all cells and hearts. 2018-03-16 08:29:13 +00:00
Steve 8d54233df5 Start of credits. 2018-03-16 08:28:25 +00:00
Steve 2dcbeb368d Code tidy. 2018-03-15 08:01:04 +00:00
Steve fc2efeac31 Start of ending. 2018-03-15 08:00:00 +00:00
Steve 124122ed7f v0.7 2018-03-15 07:59:43 +00:00
Steve 2f2ee2a8cd Don't kill entity stuck inside another, just remove from quadtree. 2018-03-14 22:42:15 +00:00
Steve 370adf36b6 Don't stop music when game is complete. 2018-03-14 22:41:55 +00:00
Steve e585281716 README.md update. 2018-03-14 07:34:25 +00:00
Steve d7622f2739 Don't try to install data. 2018-03-14 07:34:12 +00:00
Steve 883d576ca7 Don't count enemy deaths more than once. 2018-03-13 08:25:57 +00:00
Steve 20acee4334 Store door closed X and Y. 2018-03-13 08:25:41 +00:00
Steve d6ec2dff08 Laser trap fix. 2018-03-13 08:25:16 +00:00
Steve 2e8af03b36 Fix for demo data. 2018-03-13 08:25:08 +00:00
Steve 698535344f Increase chance of battery being dropped. 2018-03-13 08:24:53 +00:00
Steve de2295efe9 Warn about missing atlas entries. 2018-03-13 08:24:41 +00:00
Steve 3b4b690ebf Start of README.md. 2018-03-13 08:24:23 +00:00
Steve 04416e52ab Fix for laser trap not killing some enemies. 2018-03-11 07:51:29 +00:00
Steve 60261932b0 Removed static cheat. 2018-03-09 18:26:44 +00:00
Steve cdb0230bc7 Save images as PNG (can be a bit slow). 2018-03-09 18:26:33 +00:00
Steve b4d681a4eb Process command line arguments. 2018-03-09 18:26:04 +00:00
Steve 61dd0ceb40 Autocomplete mission when Cell and Heart have been found, and we're in MS_MISSING_HEART_CELL. 2018-03-09 07:32:23 +00:00
Steve 0593bca212 Don't worry about item pads stuck in floors. 2018-03-09 07:31:50 +00:00
Steve 8be4f6c773 Show all direction markers on radar, instead of one single direction. 2018-03-08 07:54:20 +00:00
Steve cfd90c27c1 Don't move start position when carrying item. 2018-03-08 07:53:57 +00:00
Steve fdfd875d8a When player manually quits, don't show mission complete screen. 2018-03-08 07:53:26 +00:00
Steve 74383264c2 Use saveDelay, to prevent premature saving while manually quitting levels. 2018-03-08 07:52:42 +00:00
Steve 6b2139b6ce Remove EF_GONE flag from enemies when they are killed. 2018-03-08 07:32:04 +00:00
Steve 34df6121dd Warn about entities that are stuck in walls at start of level. 2018-03-07 21:38:18 +00:00
Steve e577d7e16f Don't allow Bob and Teeka to shoot one another. 2018-03-07 21:37:54 +00:00
Steve 9270607d6e Move carried item around with unit. 2018-03-07 21:37:31 +00:00
Steve 36b5265b08 INFO level logging. 2018-03-07 21:37:07 +00:00
Steve 9404312594 Set created keys to Bob's position. 2018-03-07 21:36:57 +00:00
Steve ea15674fd4 Slightly lower chance of dropping weapons. 2018-03-07 21:35:56 +00:00
Steve 22f7b02413 Mark carried items on radar, so they don't become invisible during clean up runs. 2018-03-07 07:51:40 +00:00
Steve 009bb74a95 Save type of destructable and exit. 2018-03-07 07:49:24 +00:00
Steve baabbbe31c Changed mission unlocking logic. Missions now specify their dependent mission. 2018-03-06 21:47:21 +00:00
Steve 1d033cf327 Don't allow Teeka's shots to hurt the player. 2018-03-06 08:24:45 +00:00
Steve 7b915a77a8 Show item pads on radar. 2018-03-05 08:39:54 +00:00
Steve 7dff960e42 Call change environment when finishing teleport, for instances where teleportation occurred in water. 2018-03-05 08:39:42 +00:00
Steve f720d9457c Set MIA to foreground when teleporting. 2018-03-05 08:38:59 +00:00
Steve 3a88c5163a Don't scale items in inventory screen if <= 40px. 2018-03-04 21:40:44 +00:00
Steve af35c426e9 Show destructables on radar as red markers. 2018-03-04 17:04:28 +00:00
Steve f9adb8d8b8 Crush faster. 2018-03-04 17:04:13 +00:00
Steve 83e7276fa9 Defend against divide by 0. 2018-03-04 17:03:11 +00:00
Steve 924978c2a0 Accuracy stat fix. 2018-03-04 17:02:53 +00:00
Steve 4c08307f18 Save game when awarding trophies in Hub. 2018-03-04 16:01:44 +00:00
Steve 222147665e Show oxygen level to 1 decimal place. 2018-03-04 13:36:11 +00:00
Steve 934dd431aa Allow some entities to be crushed, to prevent them blocking lifts, etc. 2018-03-04 13:36:00 +00:00
Steve 95a4131a99 Don't use the camera position for entity observation, as it might never finish, due to clipping. 2018-03-04 10:51:05 +00:00
Steve f3cf1ec945 Drop weapons a little more frequently. 2018-03-04 10:50:00 +00:00
Steve 3b88f1c973 Clip camera when observing entities. 2018-03-04 09:49:31 +00:00
Steve a3a4c01049 Play sound when recharging from power pool. 2018-03-04 09:49:16 +00:00
Steve 1073276c6f Fix for Bob taking slime / lava damage. 2018-03-04 09:48:33 +00:00
Steve 9a18d03a39 Mark item as collected, so that it doesn't bump objective counter. 2018-03-04 08:15:30 +00:00
Steve a08d52c2fb When dropping carried items, allow them to be picked up again(!) 2018-03-03 16:05:55 +00:00
Steve 836eaa5b50 Don't show items on radar that have been used. 2018-03-03 16:05:34 +00:00
Steve b4f9692f75 Make pistols appear a little less often. 2018-03-03 16:05:17 +00:00
Steve 8bbdeb9407 Don't scale objects if they already fit into the slot. 2018-03-03 16:05:04 +00:00
Steve fca87f6575 Use MAX_DESCRIPTION_LENGTH to prevent target name truncation. 2018-03-03 16:04:40 +00:00
Steve 6ba888436b Ensure Bob faces correct way at beginning of mission. 2018-03-03 16:04:18 +00:00
Steve 53ee605bd4 Pause sound when observing entity activation. 2018-03-03 07:41:51 +00:00
Steve 741efd01ad Set eliminate all enemies if we need to clear the level. 2018-03-03 07:41:38 +00:00
Steve 0c2f069fef Only count laser hits once. 2018-03-03 07:41:05 +00:00
Steve f634a28127 Scroll to observing entity. 2018-03-02 22:21:45 +00:00
Steve 7a79ef4b53 Tidied headers. 2018-03-02 08:30:39 +00:00
Steve 1d01bec093 Show fewer stats per page. 2018-03-02 08:29:36 +00:00
Steve 0a5d2d8cfb Show additional stats. 2018-03-02 08:09:04 +00:00
Steve eb6e653837 Cell and heart saving bug fix. 2018-03-01 22:30:33 +00:00
Steve 7037b40c7b Display time played correctly. 2018-03-01 08:24:05 +00:00
Steve 2634a6fd97 Tidied all header. 2018-03-01 07:52:50 +00:00
Steve a895dad6d9 Tidy headers update. 2018-03-01 07:51:39 +00:00
Steve dd7188afc7 Store Bob's facing, to restore when resetting. 2018-03-01 07:41:04 +00:00
Steve 4d086a5136 Show more entity location information on the radar. 2018-02-28 21:59:20 +00:00
Steve 7805a128ad Clear old message, to allow repeats. 2018-02-28 08:29:30 +00:00
Steve 695e1fc5da Don't observe entities that are close to another that is already being observed. 2018-02-28 08:00:24 +00:00
Steve c98e93ee2b Pause audio when pausing game / viewing radar. 2018-02-28 07:52:38 +00:00
Steve 6b246971b3 Tidied headers. 2018-02-27 22:35:31 +00:00
Steve 18fa11d278 Start of extra blood / explosions. 2018-02-27 21:55:15 +00:00
Steve d2bc37eebf Allow selection of screen resolution. 2018-02-27 21:54:52 +00:00
Steve 20d1548f42 Fully clean trophy bug fix. 2018-02-27 08:16:34 +00:00
Steve b31d061d42 Only print item quantity if it's more than 0. 2018-02-27 08:16:18 +00:00
Steve 4d41f7f56c Load new sounds. 2018-02-27 08:16:06 +00:00
Steve 938fbaf9e0 Destructable death bug fix. 2018-02-27 08:15:53 +00:00
Steve 24d26b094c Sort inventory when item is removed. 2018-02-27 08:14:54 +00:00
Steve a085a028b9 Laser trap and item pad sound effects. 2018-02-27 08:14:37 +00:00
Steve 80f8af703a Always play explosion sound in channel 0. 2018-02-27 08:14:21 +00:00
Steve af4ce38296 Added directional audio. 2018-02-26 18:56:13 +00:00
Steve a729bfe7ee Anchor radar at bottom of map. 2018-02-26 08:19:21 +00:00
Steve 42c6c43cd8 v0.6-01 screenshot. 2018-02-26 07:53:22 +00:00
Steve 583373402a Allow random screenshots to be taken. 2018-02-26 07:53:12 +00:00
Steve bf9ab57e2f Use specific collision bounds for certain objects. 2018-02-26 07:38:20 +00:00
Steve 5282345dc6 Misc. code fixes. 2018-02-25 17:32:29 +00:00
Steve df6bda4629 More variation in decoration movement. 2018-02-25 17:32:15 +00:00
Steve 89f2e399a5 Quadtree add / remove bug fixes. 2018-02-25 17:31:32 +00:00
Steve 4ff02a82e5 Don't allow weapon to be fired if owner's facing is FACING_DIE. 2018-02-25 17:30:05 +00:00
Steve 501db4420b Use entity id to play sounds. 2018-02-25 17:29:44 +00:00
Steve 5f7367403d Check for fully completed mission in PostMission. 2018-02-25 12:53:48 +00:00
Steve 443255baea Debugging stuff. 2018-02-25 12:36:34 +00:00
Steve 68fff35e1a Don't display blank messages. 2018-02-25 12:36:12 +00:00
Steve a13e22fb85 Play menu sounds. 2018-02-25 12:23:00 +00:00
Steve b3e87f8cfb Start of game over handling. 2018-02-25 12:12:31 +00:00
Steve befea2ac65 Allow entities to mostly go offscreen, but not enough to let the player cut across the level. 2018-02-25 08:36:40 +00:00
Steve 537f3c42ff Extern fixes. 2018-02-25 07:55:17 +00:00
Steve ada4768efd Implemented Tank Commander boss. 2018-02-25 07:55:06 +00:00
Steve 15d6ca5678 Added EyeDroid Commander boss battle. 2018-02-24 16:53:03 +00:00
Steve 1c149695e2 Use ints instead of float. 2018-02-24 16:01:36 +00:00
Steve db9cddb7e8 Load / save functions for weapon pickups. 2018-02-24 16:00:48 +00:00
Steve 234f8fe73c Show boss health bar on HUD. 2018-02-24 16:00:30 +00:00
Steve 997d423103 Don't show teleporting or gone entities on the radar. 2018-02-24 16:00:20 +00:00
Steve ef1d634057 Trigger gameplay message crash fix. 2018-02-24 16:00:04 +00:00
Steve 600032a41b Only mark Bob as gone if this isn't a boss mission. 2018-02-24 15:59:46 +00:00
Steve 9c279da3a2 Ensure that sprite frames don't overrun array bounds. 2018-02-24 15:59:26 +00:00
Steve 891d551179 Trophy screenshot update. 2018-02-24 15:58:33 +00:00
Steve 0d08f6096f Boss updates. 2018-02-24 15:58:14 +00:00
Steve 258afd624d v0.6 2018-02-24 11:23:44 +00:00
271 changed files with 9081 additions and 4027 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@ data
blobwarsAttrition
*.o
.DS_Store
dist/*
/blobwarsAttrition.exe
/.errors
build

53
README-Amiga.md Normal file
View File

@ -0,0 +1,53 @@
# Blob Wars : Attrition
This is the port of the Blob Wars Attrition 1.2.2 for the AmigaOS 4 and
MorphOS.
The AmigaOS 4 versions is tested and runs well on X5000/40. Also I tested
it on microAmigaOne but the lack of graphics memory (32MB total) makes it
really slow.
The MorphOS version was tested on PowerBook G4 and runs pretty fine and
quickly.
I'd love to hear how it works on your system.
### Installation
This archive does not contain any data files. In order to play the game, you
will need to purchase the data. You can do so here:
http://www.parallelrealities.co.uk/games/attrition/#purchase
To install it, extract all the files from the bought Linux archive
(blobwarsAttrition-1.2.2.linux-x86.tar.gz) anywhere at you hard disk
and copy over all the files from this archive. A requester will show up
to replace the blobwarsAttrition binary, which you need to confirm.
I do not recommend to use the demo data provided from the official website,
because they do not work correctly.
It is recommended to have the following SDL2 options enabled at its prefs:
- Driver: opengl/opengl2 depending your gfx card and the drivers you have
installed in your system
- Batching Mode: enabled
### Support
If you like what I am doing and my ports and you would like to support me,
and my future releases please visit https://ko-fi.com/walkero where you
can find all the latest updates by me and you can donate.
### Changelog
1.2.2r2 (2022-09-19)
* Did a few changes at the code that speeds up the game a lot
* Removed the white shadow from texts in some renderers
* Changed the freetype library with the latest version
* Removed the debug info at the start of the game
* MorphOS version released
* Some code cleanup at the repo
1.2.2r1 (2022-08-13)
* First release

306
README.md Normal file
View File

@ -0,0 +1,306 @@
# Blob Wars : Attrition
Blob Wars : Attrition is a 2D mission and objective-based platform game. It is the third game in the Blob Wars series.
The develop branch on GitHub (https://github.com/stephenjsweeney/blobwarsAttrition/tree/develop) is where all the dev work happens. Stable(ish) releases will go in to master (https://github.com/stephenjsweeney/blobwarsAttrition/tree/master).
The source code of this game (everything under the src directory) is licensed under the GPL. www.gnu.org/licenses/gpl-3.0.en.html
### IMPORTANT
This repo does not contain any data files (maps, sprite definitions, etc). In order to play the game, you will need to purchase the data. You can do so here:
http://www.parallelrealities.co.uk/games/attrition/#purchase
Demo data files are also available. See further below for more details.
### DATA INSTALLATION
The data folder should be placed alongside the gfx, sound, and music folders, so that the game can access it. By default, the "make install" step will place the data files into /opt/blobwarsAttrition. This is where you should copy the data folder, in order for the game to work. Or, after building, you can run the game in place.
### DEMO DATA
Demo data files are also available and can be installed in the same way. The demo data is limited to three maps and does not define all of the game's content. Note that if you test the game with this demo data and then upgrade to the full experience, you should remove both the demo data folder and also the save games that it creates. Otherwise, due to the persistent nature of the game, you may encounter game breaking bugs.
You can download the demo data here, as either a zip or a gzip:
http://www.parallelrealities.co.uk/downloads/blobWarsAttrition/blobWarsAttrition-demo-data.zip
http://www.parallelrealities.co.uk/downloads/blobWarsAttrition/blobWarsAttrition-demo-data.tar.gz
If you upgrade from the demo data files to the commercial ones, you should start the game from scratch, to prevent issues with the persistent world.
## SCREENSHOTS
Screenshots from various versions can be found here: https://github.com/stephenjsweeney/blobwarsAttrition/tree/master/dev/screenshots
## CREDITS
### GRAPHICS
* 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/hud/health.png - Hearts icon, by Skoll (CC BY 3.0): http://game-icons.net/skoll/originals/hearts.html
* gfx/hud/oxygen.png - Lungs icon, by Delapouite (CC BY 3.0): http://game-icons.net/delapouite/originals/lungs.html
* gfx/hud/power.png - Battery pack icon, by sbed (CC BY 3.0): http://game-icons.net/sbed/originals/battery-pack.html
All other graphics are CC BY-NC-SA 3.0, with the following attribution: Copyright 2014-2018, Parallel Realities
### SOUND
* 10 Gauge Shotgun
Copyright Soundbible.com
www.soundbible.com
* Hydraulic...Thing (12906)
Copyright 2005, Swelk
Licensed under Creative Commons
www.freesound.org
* Cardlock Open (39028)
Copyright 2007, Wildweasel
Licensed under Creative Commons
www.freesound.org
* Back Menu (50557)
Copyright 2008, Broumbroum
Licensed under Creative Commons
www.freesound.org
* Select Menu (50561)
Copyright 2008, Broumbroum
Licensed under Creative Commons
www.freesound.org
* Medium Slash 8 (50790)
Copyright 2008, Smcameron
Licensed under Creative Commons
www.freesound.org
* Missile Launch 2 (51468)
Copyright 2008, Smcameron
Licensed under Creative Commons
www.freesound.org
* Water Gulp (56271)
Copyright 2008, Q.K.
Licensed under Creative Commons
www.freesound.org
* Swosh 22 (60009)
Copyright 2008, Qubodup
Licensed under Creative Commons
www.freesound.org
* Submachinegun2 (67020)
Copyright 2009, Ls
Licensed under Creative Commons
www.freesound.org
* Blood Hitting Window (81042)
Copyright 2009, Rock Savage
Licensed under Creative Commons
www.freesound.org
* Item Respawn (83301)
Copyright 2009, Silencer1337
Licensed under Creative Commons
www.freesound.org
* Gbc Reload 06 (88275)
Copyright 2010, S_dij
Licensed under Creative Commons
www.freesound.org
* 60.wav (93017)
Copyright 2010, Cosmicd
Licensed under Creative Commons
www.freesound.org
* Punch.wav (104183)
Copyright 2010, Ekokubza123
Licensed under Creative Commons
www.freesound.org
* Water_splash.wav (110393)
Copyright 2010, Soundscalpel.com
Licensed under Creative Commons
www.freesound.org
* Gewonnen.mp3 (113989)
Copyright 2011, Kastenfrosch
Licensed under Creative Commons
www.freesound.org
* Transporter Beam.Flac (116505)
Copyright 2011, Owdeo
Licensed under Creative Commons
www.freesound.org
* Tink3d.wav (126531)
Copyright 2011, Sinkhole7
Licensed under Creative Commons
www.freesound.org
* Error.wav (142608)
Copyright 2012, Autistic Lucario
Licensed under Creative Commons
www.freesound.org
* Ricochet.mp3 (148840)
Copyright 2012, Cedarstudios
Licensed under Creative Commons
www.freesound.org
* Gulp (2) (151233)
Copyright 2012, Owlstorm
Licensed under Creative Commons
www.freesound.org
* Door-Handle-Jiggle-04.wav (151578)
Copyright 2012, D W
Licensed under Creative Commons
www.freesound.org
* 8bit Robot Sound (153445)
Copyright 2012, Lukechalaudio
Licensed under Creative Commons
www.freesound.org
* 8bit Robot Sound 2 (153446)
Copyright 2012, Lukechalaudio
Licensed under Creative Commons
www.freesound.org
* Gotitem.mp3 (162467)
Copyright 2012, Kastenfrosch
Licensed under Creative Commons
www.freesound.org
* Metal Clang.aif (170959)
Copyright 2012, Timgormly
Licensed under Creative Commons
www.freesound.org
* S_teleport_05.wav (178350)
Copyright 2013, Andromadax24
Licensed under Creative Commons
www.freesound.org
* Sad Cry 5 (180310)
Copyright 2013, Jorickhoofd
Licensed under Creative Commons
www.freesound.org
* 120110_15 Hot Plate (181490)
Copyright 2013, Toiletrolltube
Licensed under Creative Commons
www.freesound.org
* Scream 01 (219858)
Copyright 2014, Adriancalzon
Licensed under Creative Commons
www.freesound.org
* Screaming_male_painii.mp3 (220289)
Copyright 2014, Gabrielaupf
Licensed under Creative Commons
www.freesound.org
* Bomb
Copyright 2014, Partners In Rhyme Inc
www.freesoundeffects.com
* Gun 44 Magnum
Copyright 2014, Partners In Rhyme Inc
www.freesoundeffects.com
* Laser Cannon
Copyright Mike Koenig
Licensed under Creative Commons
soundbible.com
* Mortice_key_drop_on_concrete_floor
Copyright www.freesfx.co.uk
www.freesfx.co.uk
* Ray Gun
Copyright Mike Koenig
Licensed under Creative Commons
soundbible.com
* Shotgun
Copyright Soundbible.com
Licensed under Creative Commons
soundbible.com
* Pop.wav (83237)
Copyright 2009, mlestn1
Licensed under Creative Commons
www.freesound.org
* welder1.ogg (46501)
Copyright 2008, PhreaKsAccount
Licensed under Creative Commons
www.freesound.org
* Ratchet.wav (319996)
Copyright 2015, KenRT
Licensed under Creative Commons
www.freesound.org
* TF_Power-Tools.flac
Copyright 2014, copyc4t
Licensed under Creative Commons
www.freesound.org
### MUSIC
* Watching
Copyright Dj Sjors
Licensed under Creative Commons
* News Background
Copyright Mansardian
freesound.org/people/mansardian/sounds/61321
Licensed under Creative Commons
* The Assasins
Copyright Audionautix.com
Licensed under Creative Commons
* Delusion32
Copyright Audionautix.com
Licensed under Creative Commons
* Down The Way
Copyright Audionautix.com
Licensed under Creative Commons
* Boom
Copyright Audionautix.com
Licensed under Creative Commons
* Ectoplasm
Copyright Audionautix.com
Licensed under Creative Commons
* So Dramatic
Copyright Audionautix.com
Licensed under Creative Commons
* Eternal Whispers
Copyright Snabisch
Licensed under Creative Commons
### FONTS
data/fonts/Roboto-Medium.ttf, by Christian Robertson. Licensed under the Apache License, version 2.0
## ABOUT
Blob Wars is copyright Parallel Realities, 2002-2018, All Rights Reserved.

View File

@ -1,10 +1,12 @@
VERSION = 0.5
REVISION = $(shell git rev-list HEAD 2>/dev/null | wc -l)
VERSION = 1.2
REVISION = 2
LOCALE_MO = $(patsubst %.po,%.mo,$(wildcard locale/*.po))
SEARCHPATH += src
SEARCHPATH += src/combat
SEARCHPATH += src/entities
OUT = bin
SEARCHPATH += src
SEARCHPATH += src/combat
SEARCHPATH += src/entities
SEARCHPATH += src/entities/blobs
SEARCHPATH += src/entities/boss
SEARCHPATH += src/entities/bullets
@ -21,8 +23,8 @@ SEARCHPATH += src/hub
SEARCHPATH += src/json
SEARCHPATH += src/system
SEARCHPATH += src/test
SEARCHPATH += src/util
SEARCHPATH += src/widgets
SEARCHPATH += src/util
SEARCHPATH += src/widgets
SEARCHPATH += src/world
vpath %.c $(SEARCHPATH)
@ -30,9 +32,9 @@ vpath %.h $(SEARCHPATH)
DEPS += defs.h structs.h
_OBJS += atlas.o atlasTest.o aquaBlob.o
_OBJS += atlas.o aquaBlob.o
_OBJS += battery.o blaze.o bob.o boss.o blobBoss.o bullet.o
_OBJS += camera.o cannon.o cardReader.o cell.o cherry.o combat.o controls.o consumable.o
_OBJS += camera.o cannon.o cardReader.o cell.o cherry.o combat.o controls.o consumable.o credits.o
_OBJS += debris.o destructable.o door.o draw.o
_OBJS += effects.o ending.o entities.o entity.o entityFactory.o exit.o explosions.o eyeDroid.o eyeDroidCommander.o evilBlob.o
_OBJS += fleshChunk.o frost.o
@ -47,10 +49,10 @@ _OBJS += objectives.o options.o
_OBJS += particles.o player.o plasmaBlob.o plasmaDroid.o pistolBlob.o pistolDroid.o postMission.o powerPoint.o powerPool.o pressurePlate.o pushBlock.o
_OBJS += quadtree.o
_OBJS += radar.o
_OBJS += shotgunBlob.o shotgunDroid.o sound.o spreadGunBlob.o spreadGunDroid.o sprites.o stats.o structures.o
_OBJS += savepng.o shotgunBlob.o shotgunDroid.o sound.o spreadGunBlob.o spreadGunDroid.o sprites.o stats.o strings.o structures.o
_OBJS += tankCommander.o tankTrack.o teeka.o teleporter.o text.o textures.o title.o transition.o triggers.o trophies.o
_OBJS += unit.o util.o
_OBJS += weapons.o weaponPickup.o widgets.o world.o worldLoader.o worldSaver.o
_OBJS += weapons.o weaponPickup.o widgets.o world.o worldLoader.o worldSaver.o worldTest.o
OBJS = $(patsubst %,$(OUT)/%,$(_OBJS))
@ -61,10 +63,13 @@ all: $(PROG) $(LOCALE_MO)
$(OUT)/%.o: %.c %.h $(DEPS)
@mkdir -p $(OUT)
$(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)

BIN
dev/screenshots/v0.6-01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

BIN
dev/screenshots/v0.7-01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

BIN
dev/screenshots/v0.7-02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

After

Width:  |  Height:  |  Size: 3.3 MiB

BIN
gfx/hub/clouds.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

BIN
icons/blob.info Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,9 @@
[Desktop Entry]
Encoding=UTF-8
Categories=Game;ActionGame;
Name=Blob Wars : Attrition
Comment=Mission and Objective based 2D Platform Game
Icon=blobwarsAttrition
Exec=blobwarsAttrition
Terminal=false
Type=Application

View File

@ -0,0 +1,753 @@
# PO file for Blob Wars : Attrition
# Copyright 2018, Stephen J Sweeney
# This file is distributed under the GNU GPL 3.0
# Email: stephenjsweeney@battleforthesolarsystem.com
# https://github.com/stephenjsweeney/blobwarsAttrition
msgid ""
msgstr ""
"Project-Id-Version: Blob Wars : Attrition\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-12 11:50:05+0100\n"
"PO-Revision-Date: ???\n"
"Last-Translator: ???\n"
"Language-Team: ???\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Pistol"
msgstr ""
msgid "Plasma Rifle"
msgstr ""
msgid "Spread Gun"
msgstr ""
msgid "Laser Cannon"
msgstr ""
msgid "Grenades"
msgstr ""
msgid "Missions complete"
msgstr ""
msgid "Keys found"
msgstr ""
msgid "Power cells found"
msgstr ""
msgid "Hearts found"
msgstr ""
msgid "Targets defeated"
msgstr ""
msgid "MIAs rescued"
msgstr ""
msgid "Deaths"
msgstr ""
msgid "Shots fired"
msgstr ""
msgid "Shots hit"
msgstr ""
msgid "Accuracy"
msgstr ""
msgid "EyeDroid explosion kills"
msgstr ""
msgid "Best grenade combo"
msgstr ""
msgid "Time spent flying"
msgstr ""
msgid "Time spent swimming"
msgstr ""
msgid "Cherries picked up"
msgstr ""
msgid "Batteries picked up"
msgstr ""
msgid "Weapons picked up"
msgstr ""
msgid "Enemies killed"
msgstr ""
msgid "Missions played"
msgstr ""
msgid "Percent complete"
msgstr ""
msgid "Time played"
msgstr ""
msgid "Mission Complete!"
msgstr ""
msgid "Objectives"
msgstr ""
msgid "Incomplete"
msgstr ""
msgid "Complete"
msgstr ""
msgid "Press Fire to Continue"
msgstr ""
msgid "Options"
msgstr ""
msgid "Controls"
msgstr ""
msgid "Trophies"
msgstr ""
msgid "Page %d / %d"
msgstr ""
msgid "Hidden"
msgstr ""
msgid "Weapon: %s"
msgstr ""
msgid "Found a battery cell - Max power increased!"
msgstr ""
msgid "Found a heart - Max health increased!"
msgstr ""
msgid "Teleporter activated ..."
msgstr ""
msgid "Lasers disabled ..."
msgstr ""
msgid "Not enough power (%d units required)"
msgstr ""
msgid "Platform activated ..."
msgstr ""
msgid "Can't exit yet - required objectives not met"
msgstr ""
msgid "Door is locked"
msgstr ""
msgid "Door opened ..."
msgstr ""
msgid "Got some Grenades"
msgstr ""
msgid "Picked up a %s"
msgstr ""
msgid "%s removed"
msgstr ""
msgid "%s required"
msgstr ""
msgid "Can't carry any more keys"
msgstr ""
msgid "Can't carry any more items"
msgstr ""
msgid "Rescued %s"
msgstr ""
msgid "Not enough power for jetpack"
msgstr ""
msgid "Not enough power for aqualung"
msgstr ""
msgid "Quit and return to hub?"
msgstr ""
msgid "As this is a tutorial mission, you can skip it and move onto the main game."
msgstr ""
msgid "Your progress on this mission will be saved."
msgstr ""
msgid "Your progress on this mission will not be saved, but you will keep any keys, Hearts, and Cells that you have collected."
msgstr ""
msgid "Warning: if you quit now, you will lose all progress on this level."
msgstr ""
msgid "MIAs"
msgstr ""
msgid "Items"
msgstr ""
msgid "Targets"
msgstr ""
msgid "%s - Objective Complete!"
msgstr ""
msgid "bunch of cherries"
msgstr ""
msgid "pair of cherries"
msgstr ""
msgid "small cherry"
msgstr ""
msgid "full battery"
msgstr ""
msgid "battery"
msgstr ""
msgid "used battery"
msgstr ""
msgid "weak battery"
msgstr ""
msgid "Choose a save slot to use ..."
msgstr ""
msgid "Choose a save game to load ..."
msgstr ""
msgid "Are you sure you want to overwrite this game?"
msgstr ""
msgid "All progress will be lost!"
msgstr ""
msgid "As the game is now complete, free play for this mission has been unlocked. You may replay it as often as you wish. Hearts and Cells will be randomly available."
msgstr ""
msgid "All objectives for this misson have been completed. However, there is a Cell or a Heart left to find. See if you can locate it."
msgstr ""
msgid "Missions: %d / %d"
msgstr ""
msgid "MIAs: %d / %d"
msgstr ""
msgid "Targets: %d / %d"
msgstr ""
msgid "Keys: %d / %d"
msgstr ""
msgid "Hearts: %d / %d"
msgstr ""
msgid "Cells: %d / %d"
msgstr ""
msgid "Mission configuration"
msgstr ""
msgid "! Corrupt data"
msgstr ""
msgid "- empty -"
msgstr ""
msgid "Defeat enemies"
msgstr ""
msgid "This is an information point. Bob can stand by them for a few moments to see what they have to say. There are many scattered throughout this tutorial map, to help you learn how to play. They will also appear from time to time during the actual game. Stand by them for a short time, to get more information. If you get lost, tap the radar icon in the top left, to view a map of the local area."
msgstr ""
msgid "This is a door. To open it, simply walk into it. Most doors are locked, and some will require a key."
msgstr ""
msgid "This is an item. Walk into it to pick it up. Some items, such as keys, are carried between levels, while other items will form part of mission objectives, and must be collected."
msgstr ""
msgid "This is a pressure plate. Walking on it will cause things to happen, such as doors to open."
msgstr ""
msgid "Water. Bob can swim in water so long as he has oxygen. You can also activate your aqua lung, which will enable Bob to swim for longer. Your oxygen returns when Bob exits the water."
msgstr ""
msgid "This is slime. Falling into slime hurts Bob, and will deduct 1 point of health. Best avoided."
msgstr ""
msgid "This is lava. It hurts more than slime, causing 2 points of damage."
msgstr ""
msgid "There is a lift here, that Bob can ride. Lifts can also be used to transport things."
msgstr ""
msgid "This door is locked, and required a bronze key to open it."
msgstr ""
msgid "This is a teleporter. It can transport Bob (and other things) to a new location. Simply walk into it to use."
msgstr ""
msgid "These are POW blobs, that have been captured by the enemy. They need to be transported home. To do so, simply walk into them to initiate the teleportation process."
msgstr ""
msgid "This is a power point. It can recharge Bob's power. To use it, simply walk over it. It will stop working for a time once it has recharged Bob's power, and must be left alone before it can be used again."
msgstr ""
msgid "This is a Power Point. It is used to activate entities in the world, such as doors. Power Points require that Bob use a certain amount of power to activate them. To do so, stand over them for a short time."
msgstr ""
msgid "Another pressure plate. This one, however, requires constant pressure to be applied."
msgstr ""
msgid "This is a crate. It is heavy, and can be used to weigh down pressure plates. Bob will encounter many such crates and boulders throughout the game."
msgstr ""
msgid "You must go right, first."
msgstr ""
msgid "Stuck? You can either wait for the lift or activate your jetpack. Activating your jetpack underwater will activate your aqualung, instead. Both require Power to use."
msgstr ""
msgid "There are enemies here. Fire your weapon to attack them. Defeated enemies will drop cherries, weapons, and batteries, as well as many other items they are holding. You should collect health and batteries as often as possible."
msgstr ""
msgid "Collect all 5 Transmitters"
msgstr ""
msgid "Rescue 4 MIAs"
msgstr ""
msgid "Defeat all enemies"
msgstr ""
msgid "Find all keys and keycards"
msgstr ""
msgid "You're about to come across the detachment leader, marked with a red arrow above him. He has more energy than regular enemies, and may teleport away while you're battling him. Check surrounding area to find out where he has gone."
msgstr ""
msgid "Remember that you can use your aqualung underwater to swim for longer than your oxygen level could otherwise allow."
msgstr ""
msgid "A power cell! This will increase your overall power by 1 point, allowing you to use your jetpack and aqualung for 1 second longer. There are many more to be found."
msgstr ""
msgid "Find First Aid"
msgstr ""
msgid "Defeat detachment leader"
msgstr ""
msgid "Rescue MIAs"
msgstr ""
msgid "Defeat detachment leaders"
msgstr ""
msgid "Recover SD Card"
msgstr ""
msgid "Eliminate detachments leaders"
msgstr ""
msgid "Eliminate Detachment Leaders"
msgstr ""
msgid "Find Blueprints"
msgstr ""
msgid "Eliminate Specialist Leaders"
msgstr ""
msgid "Collect White Keycard from Teeka"
msgstr ""
msgid "Collect all First Aid"
msgstr ""
msgid "Defeat Blaze"
msgstr ""
msgid "Defeat Frost"
msgstr ""
msgid "Defeat EyeDroid Commander"
msgstr ""
msgid "Defeat Tank Commander"
msgstr ""
msgid "Eliminate Detachment Leader"
msgstr ""
msgid "Eliminate Detachment Sub Leader"
msgstr ""
msgid "Find Biomech Transmitter"
msgstr ""
msgid "Find Cheese"
msgstr ""
msgid "Find Grapes"
msgstr ""
msgid "Recover Wine"
msgstr ""
msgid "Collect all disks"
msgstr ""
msgid "CAUTION: the BioMechs in this (and all other outposts) are stronger than those found elsewhere. Unlike their comrades, many are capable of surviving more than one hit. Consider returning later when you have more health (find Hearts!)"
msgstr ""
msgid "Collect Bombs"
msgstr ""
msgid "Plant Bombs"
msgstr ""
msgid "Collect TNT"
msgstr ""
msgid "Plant TNT"
msgstr ""
msgid "Access to the upper floor is gained elsewhere"
msgstr ""
msgid "Find Teeka"
msgstr ""
msgid "Destroy Toxic Barrels"
msgstr ""
msgid "Locate the exit"
msgstr ""
msgid "Destroy Sentry Guns"
msgstr ""
msgid "Destroy all encrypted computer systems"
msgstr ""
msgid "Find the exit"
msgstr ""
msgid "Destroy all munitions crates"
msgstr ""
msgid "Get to the exit"
msgstr ""
msgid "This way is blocked. There is likely another way through, elsewhere."
msgstr ""
msgid "Teeka has relayed information that there are a lot of card readers here, but no keycards. They need to be obtained from other locations. Consider returning later, when you have a good stash of them to hand."
msgstr ""
msgid "Bob made his way through cherry fields as a fierce storm beat down, heading towards Teeka's last known position."
msgstr ""
msgid "But as he arrived in the vicinity, Bob found only the scout's teleporter belt. Teeka was nowhere to be seen."
msgstr ""
msgid "As the rain continued to fall, Bob couldn't help but feel that he had been lured away from home base on purpose."
msgstr ""
msgid "Bob knew he should get back to the Blobs' base as soon as possible. He made to leave, only to come face-to-face with a BioMech ambush."
msgstr ""
msgid "With his direct route home cut off, Bob would have no choice but to fight his way through."
msgstr ""
msgid "Something about all this made Bob feel very unsettled, and he only hoped that by the time he made it home, it wouldn't be too late ..."
msgstr ""
msgid "The bandana's not just for show"
msgstr ""
msgid "Earn all other trophies"
msgstr ""
msgid "Life's a beach"
msgstr ""
msgid "Complete all beach missions"
msgstr ""
msgid "The grass is always greener"
msgstr ""
msgid "Complete all greenland missions"
msgstr ""
msgid "As above, so below"
msgstr ""
msgid "Complete all underground missions"
msgstr ""
msgid "Bringing down the house"
msgstr ""
msgid "Complete all outpost missions"
msgstr ""
msgid "Power up!"
msgstr ""
msgid "Find a power cell"
msgstr ""
msgid "Over 9,000!"
msgstr ""
msgid "Find all power cells"
msgstr ""
msgid "You've got heart"
msgstr ""
msgid "Find a heart"
msgstr ""
msgid "King of hearts"
msgstr ""
msgid "Find all hearts"
msgstr ""
msgid "Tidy!"
msgstr ""
msgid "Fully complete a mission"
msgstr ""
msgid "No stone left unturned"
msgstr ""
msgid "Fully complete all missions"
msgstr ""
msgid "Hey, buddy!"
msgstr ""
msgid "Get a white keycard from Teeka"
msgstr ""
msgid "Blowing hot and cold"
msgstr ""
msgid "Defeat Blaze and Frost"
msgstr ""
msgid "Eye eye, captain!"
msgstr ""
msgid "Defeat the EyeDroid Commander"
msgstr ""
msgid "A Tank?!"
msgstr ""
msgid "Defeat the Biomech Tank"
msgstr ""
msgid "No time to reload"
msgstr ""
msgid "Fire 10,000 shots"
msgstr ""
msgid "One Blob Army"
msgstr ""
msgid "Defeat 1,000 enemies"
msgstr ""
msgid "How many of you are there?!"
msgstr ""
msgid "Defeat 2,000 enemies"
msgstr ""
msgid "Are we still keeping count?"
msgstr ""
msgid "Defeat 3,000 enemies"
msgstr ""
msgid "Locksmith"
msgstr ""
msgid "Find half the keys in the game"
msgstr ""
msgid "Keeper of keys"
msgstr ""
msgid "Find all the keys in the game"
msgstr ""
msgid "Medic!"
msgstr ""
msgid "Rescue half the MIAs in the game"
msgstr ""
msgid "Someone call Spielberg"
msgstr ""
msgid "Rescue all the MIAs in the game"
msgstr ""
msgid "I will find you ..."
msgstr ""
msgid "Eliminate half the targets in the game"
msgstr ""
msgid "... and I will kill you"
msgstr ""
msgid "Eliminate all the targets in the game"
msgstr ""
msgid "Air miles"
msgstr ""
msgid "Use the jetpack for 5 minutes"
msgstr ""
msgid "Bob B.S.C."
msgstr ""
msgid "Swim for 5 minutes"
msgstr ""
msgid "Boom goes the dynamite"
msgstr ""
msgid "Perform a 12-hit grenade combo"
msgstr ""
msgid "Death from above"
msgstr ""
msgid "Defeat 75 enemies with EyeDroid explosions"
msgstr ""
msgid "A good source of vitamin C"
msgstr ""
msgid "Consume 200 cherries"
msgstr ""
msgid "Don't forget to recycle those"
msgstr ""
msgid "Collect 500 batteries"
msgstr ""
msgid "Whatever works"
msgstr ""
msgid "Collect 500 weapon pickups"
msgstr ""
msgid "Following the defeat of Galdov, Bob has organised his fellow Blobs into ridding the world of the remaining enemy forces. He will begin his mission at the beach front. This is a tutorial mission, that will allow you to become familiar with the gameplay and controls."
msgstr ""
msgid "Arriving at the beach front, Bob begins his search for the first detachment leader. Eliminating the leaders will cause the others to expose themselves, and allow Bob to work his way deeper into enemy territory. The enemy have also left some first aid kits in the area, which will help the war effort. He should collect those, and rescue any MIAs in the area."
msgstr ""
msgid "A hard battle was fought on this beach, just some days ago. Not all of the Blobs made it back, however, and need to be rescued. In addition to this, an SD card holding valuable intelligence data has been lost. Bob needs to find this SD card and rescue the MIAs."
msgstr ""
msgid "This part of the coastline was unsuccessfully defended by the Blobs, and the BioMechs moved in to claim it for their own. Bob's mission is simple: rescue the MIAs and eliminate the detachment leader."
msgstr ""
msgid "Some days ago, a group of Blobs set out to steal the blueprints for a BioMech super weapon. Many of the Blobs made it back to base, however, a handful did not. Both the Blobs and the parts of the blueprints that they were carrying need to be recovered."
msgstr ""
msgid "Teeka the Scout has managed to acquire a white keycard, to grant Bob access to one of the BioMech training grounds. Bob should meet Teeka, and get the keycard from him. He also needs to acquire more first aid, and rescue any MIAs in the area."
msgstr ""
msgid "Like the grasslands, the greenlands are where the Blobs spend most of their time. This is also where most of the battles are fought. A transmitter has been lost in this area, which Bob must recover. He needs to also eliminate the detachment leader and sub leader, and rescue the MIAs in the area."
msgstr ""
msgid "Alien invaders might have arrived, assimilated a number of a the Blobs around the planet, and a fierce war might still be in progress, but it's almost time for the Blobs' annual Cheese and Wine party. As well as his other duties, Bob must find some cheese to bring to the celebrations."
msgstr ""
msgid "Though the war effort is going well, moral in the Blobs forces needs to remain high if they are to win the war against the BioMechs. Unfortunately, the BioMechs have attacked the Blobs' vineyards, and taken some of the workers prisoner. Bob must therefore not only eliminate the detachment leaders and rescue the MIAs, but also harvest the grapes himself."
msgstr ""
msgid "The grape harvest went well, and much wine has been fortified as a result. However, the BioMechs have raided the wine stores and made off with a number of bottles. Bob sets out to get the wine back, before the BioMechs drink it all themselves."
msgstr ""
msgid "Teeka has acquired a white keycard from the BioMechs, which will grant Bob access to one of their training and testing grounds. Bob needs to meet Teeka, to get the card from him. The BioMech detachment in the area has also been transporting recon data on 5 1/4 floppy disks. These need to be recovered, so that the Blobs can analyse it."
msgstr ""
msgid "The BioMechs have expanded their assault underground, using a series of tunnels to move their forces around undetected. There are no signs of any MIAs, but Bob needs to eliminate as many of the BioMechs in the area as possible. The BioMechs have also dumped a number of toxic barrels here. That's not good for the environment ..."
msgstr ""
msgid "The BioMechs have set up a number of sentry cannons in these tunnels, in an attempt to secure them. Bob needs to destroy these cannons, and make his way to the exit. There are also a handful of toxic barrels here, that need to be destroyed."
msgstr ""
msgid "It looks as though the BioMechs have moved some of their data systems to their underground network, turning it into a sort of disaster recovery site. These systems need to be destroyed, and the BioMechs in the area eliminated."
msgstr ""
msgid "Bob has stumbled upon an underground weapons store! The BioMechs have hidden some of their munitions here, likely hoping to keep it in reserve should their main supply line be hit. Bob will see about that, and clear away the BioMechs in the area, at the same time."
msgstr ""
msgid "Teeka has signalled that he has managed to acquire another white keycard from the enemy. Bob should retrieve it from him, as soon as possible. The scout has also warned Bob that the BioMechs have attempted to lock this area down tight, without a keycard in sight. Bob should consider only starting this mission with a good stock of cards."
msgstr ""
msgid "One of the five enemy outposts that has been identified. Bob will have to get in there and plant some bombs, to bring the place down. Find the bombs and set them onto the designation bomb spots. There are thought to be some MIAs in the outpost, too, taken as prison. They will need to be rescued. Exercise caution: the enemies within the outpost are reportedly more powerful than their cousins littered throughout the field."
msgstr ""
msgid "Another of the 5 outposts. As with the others, Bob will have to get in here and set some explosives. There are some MIAs in here that will need rescuing, too. As with all the other outposts, caution should be taken, as the enemies here are more powerful than those out in the field."
msgstr ""
msgid "The 3rd outpost! Get in there and plant some bombs, to bring the place down. And don't forget to rescue any MIAs that might be locked up. Expect heavier resistance compared to the outposts that have preceded this one."
msgstr ""
msgid "Outpost number 4! Bob's mission is simple: get in there, plant the explosives, rescue the MIAs, and get the hell out! Nothing much to see here. And once the bombs go off, even less!"
msgstr ""
msgid "Problem. This outpost is stuffed full of MIAs. Taking it down might not be such a good idea. Bob will instead have to go in there and rescue all the prisoners, and come back later to plant the bombs. Teeka has already infiltrated the outpost and is reporting that there are well over two dozen MIAs here. Best get cracking."
msgstr ""
msgid "This is one of the proving grounds that the BioMechs have been using to develop new troops. A white keycard is required to gain access. Anything could lie beyond. Bob should proceed with caution."
msgstr ""
msgid "Another proving ground, access restricted to those with a white keycard. Bob has few doubts that another testing battle will await him within."
msgstr ""
msgid "A proving ground resides within the BioMech's tunnel networks. Bob anticipates something extremely powerful down here. Why else would they want to keep it hidden from view?"
msgstr ""
msgid "Teeka has gone missing! The work of the resourceful Blob has been invaluable to the Blobs' fight back against the BioMech, and Bob knows that they cannot do without him. He sets out immediately to search for Teeka and bring him home before the worst happens."
msgstr ""

View File

@ -1,6 +1,5 @@
PROG = blobwarsAttrition
CC = gcc
OUT = bin
PREFIX ?= /usr
BIN_DIR ?= $(PREFIX)/bin
DATA_DIR ?= /opt/$(PROG)
@ -20,14 +19,19 @@ _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 += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
CXXFLAGS += -g -lefence
CXXFLAGS += -fms-extensions -std=gnu11
ifneq ("$(wildcard .errors)","")
CXXFLAGS += -Wall -Wempty-body -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
endif
LDFLAGS += `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm -lz
LDFLAGS += `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm -lz -lpng
SHARED_FILES = CHANGELOG LICENSE README.md data gfx manual music sound icons
SHARED_FILES = LICENSE README.md data gfx manual music sound icons
DIST_FILES = $(SHARED_FILES) locale $(PROG)
SRC_DIST_FILES = $(SHARED_FILES) src makefile* common.mk
@ -54,13 +58,13 @@ install:
cp -p icons/$(PROG)-128x128.png $(INST_ICON_DIR)/128x128/apps/$(PROG).png
mkdir -p $(INST_DESKTOP_DIR)
cp -p icons/$(PROG).desktop $(INST_DESKTOP_DIR)
@for f in $(LOCALE_MO); do \
lang=`echo $$f | sed -e 's/^locale\///;s/\.mo$$//'`; \
mkdir -p $(INST_LOCALE_DIR)/$$lang/LC_MESSAGES; \
cp -v $$f $(INST_LOCALE_DIR)/$$lang/LC_MESSAGES/$(PROG).mo; \
done
uninstall:
$(RM) $(BIN_DIR)/$(PROG)
$(RM) -rf $(DATA_DIR)
@ -69,7 +73,7 @@ uninstall:
$(RM) $(ICON_DIR)/64x64/apps/$(PROG).png
$(RM) $(ICON_DIR)/128x128/apps/$(PROG).png
$(RM) $(DESKTOP_DIR)/$(PROG).desktop
@for f in $(LOCALE_MO); do \
lang=`echo $$f | sed -e 's/^locale\///;s/\.mo$$//'`; \
$(RM) -v $(LOCALE_DIR)/$$lang/LC_MESSAGES/$(PROG).mo; \
@ -77,23 +81,23 @@ uninstall:
# prepare an archive for the program
dist:
$(RM) -rf $(PROG)-$(VERSION)
mkdir $(PROG)-$(VERSION)
cp -r $(DIST_FILES) $(PROG)-$(VERSION)
tar czf $(PROG)-$(VERSION)-$(REVISION).linux-x86.tar.gz $(PROG)-$(VERSION)
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
mkdir $(PROG)-$(VERSION).$(REVISION)
cp -rL $(DIST_FILES) $(PROG)-$(VERSION).$(REVISION)
tar czf $(PROG)-$(VERSION).$(REVISION).linux-x86.tar.gz $(PROG)-$(VERSION).$(REVISION)
mkdir -p dist
mv $(PROG)-$(VERSION)-$(REVISION).linux-x86.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION)
mv $(PROG)-$(VERSION).$(REVISION).linux-x86.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
# prepare an archive for the program
src-dist:
$(RM) -rf $(PROG)-$(VERSION)
mkdir $(PROG)-$(VERSION)
cp -r $(SRC_DIST_FILES) $(PROG)-$(VERSION)
git log --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=short >$(PROG)-$(VERSION)/CHANGELOG.raw
tar czf $(PROG)-$(VERSION)-$(REVISION).src.tar.gz $(PROG)-$(VERSION)
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
mkdir $(PROG)-$(VERSION).$(REVISION)
cp -rL $(SRC_DIST_FILES) $(PROG)-$(VERSION).$(REVISION)
git log --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=short >$(PROG)-$(VERSION).$(REVISION)/CHANGELOG.raw
tar czf $(PROG)-$(VERSION).$(REVISION).src.tar.gz $(PROG)-$(VERSION).$(REVISION)
mkdir -p dist
mv $(PROG)-$(VERSION)-$(REVISION).src.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION)
mv $(PROG)-$(VERSION).$(REVISION).src.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
.PHONY: dist

35
makefile.mac Normal file
View File

@ -0,0 +1,35 @@
PROG = blobwarsAttrition
CC = gcc
PREFIX ?= /usr
BIN_DIR ?= $(PREFIX)/bin
DATA_DIR ?= /opt/$(PROG)
LOCALE_DIR = $(PREFIX)/share/locale
ICON_DIR = $(PREFIX)/share/icons/hicolor
DESKTOP_DIR = $(PREFIX)/share/applications
DESTDIR ?=
INST_BIN_DIR = $(DESTDIR)$(BIN_DIR)
INST_DATA_DIR = $(DESTDIR)$(DATA_DIR)
INST_LOCALE_DIR = $(DESTDIR)$(LOCALE_DIR)
INST_ICON_DIR = $(DESTDIR)$(ICON_DIR)
INST_DESKTOP_DIR = $(DESTDIR)$(DESKTOP_DIR)
SEARCHPATH += src/plat/unix
_OBJS += unixInit.o
include common.mk
CXXFLAGS += `sdl2-config --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\"
CXXFLAGS += -fms-extensions
LDFLAGS += `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm -lz -lpng
SHARED_FILES = LICENSE README.md data gfx manual music sound icons
DIST_FILES = $(SHARED_FILES) locale $(PROG)
SRC_DIST_FILES = $(SHARED_FILES) src makefile* common.mk
# linking the program.
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
.PHONY: dist

65
makefile.mos Normal file
View File

@ -0,0 +1,65 @@
PROG = blobwarsAttrition
CC = gcc
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/mos
_OBJS += mosInit.o
include common.mk
CXXFLAGS += -O3 -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -D__USE_INLINE__
CXXFLAGS += -I/sdk/gg/usr/local/include -g -lefence
CXXFLAGS += -fms-extensions -std=gnu11 -noixemul
ifneq ("$(wildcard .errors)","")
CXXFLAGS += -Wall -Wempty-body -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
endif
LDFLAGS += -noixemul -lSDL2_image -lSDL2_ttf -lfreetype -ltiff -lpng16 -ljpeg -lz -lm
LDFLAGS += -lSDL2_mixer -lmikmod -lmodplug -lFLAC -lvorbisfile -lvorbis -logg
LDFLAGS += -lSDL2 -lstdc++
SHARED_FILES = LICENSE README.md data gfx manual music sound icons
DIST_FILES = $(SHARED_FILES) locale $(PROG)
SRC_DIST_FILES = $(SHARED_FILES) src makefile* common.mk
# linking the program.
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
# prepare an archive for the program
dist:
mkdir -p release/$(PROG)-$(VERSION).$(REVISION)
cp $(PROG) release/$(PROG)-$(VERSION).$(REVISION)/
strip release/$(PROG)-$(VERSION).$(REVISION)/$(PROG)
cp icons/blob.info release/$(PROG)-$(VERSION).$(REVISION)/$(PROG).info
cp LICENSE release/$(PROG)-$(VERSION).$(REVISION)/
cp README.md release/$(PROG)-$(VERSION).$(REVISION)/
cp README-Amiga.md release/$(PROG)-$(VERSION).$(REVISION)/
lha -aeqr3 a $(PROG)-MOS-$(VERSION).$(REVISION).lha release/
# prepare an archive for the program
src-dist:
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
mkdir $(PROG)-$(VERSION).$(REVISION)
cp -rL $(SRC_DIST_FILES) $(PROG)-$(VERSION).$(REVISION)
git log --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=short >$(PROG)-$(VERSION).$(REVISION)/CHANGELOG.raw
tar czf $(PROG)-$(VERSION).$(REVISION).src.tar.gz $(PROG)-$(VERSION).$(REVISION)
mkdir -p dist
mv $(PROG)-$(VERSION).$(REVISION).src.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
.PHONY: dist

65
makefile.os4 Normal file
View File

@ -0,0 +1,65 @@
PROG = blobwarsAttrition
CC = gcc
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 += -O3 -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -D__USE_INLINE__
CXXFLAGS += -g -lefence
CXXFLAGS += -fms-extensions -std=gnu11
ifneq ("$(wildcard .errors)","")
CXXFLAGS += -Wall -Wempty-body -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
endif
LDFLAGS += -lauto -lSDL2_image -lSDL2_ttf -lfreetype -ltiff -lwebp -lpng -ljpeg -lz -lm
LDFLAGS += -lSDL2_mixer -lmikmod -lmodplug -lFLAC -lsmpeg2 -lvorbisfile -lvorbis -logg
LDFLAGS += -lSDL2 -lpthread -athread=native -lstdc++
SHARED_FILES = LICENSE README.md data gfx manual music sound icons
DIST_FILES = $(SHARED_FILES) locale $(PROG)
SRC_DIST_FILES = $(SHARED_FILES) src makefile* common.mk
# linking the program.
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS)
# prepare an archive for the program
dist:
mkdir -p release/$(PROG)-$(VERSION).$(REVISION)
cp $(PROG) release/$(PROG)-$(VERSION).$(REVISION)/
strip release/$(PROG)-$(VERSION).$(REVISION)/$(PROG)
cp icons/blob.info release/$(PROG)-$(VERSION).$(REVISION)/$(PROG).info
cp LICENSE release/$(PROG)-$(VERSION).$(REVISION)/
cp README.md release/$(PROG)-$(VERSION).$(REVISION)/
cp README-Amiga.md release/$(PROG)-$(VERSION).$(REVISION)/
lha -aeqr3 a $(PROG)-OS4-$(VERSION).$(REVISION).lha release/
# prepare an archive for the program
src-dist:
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
mkdir $(PROG)-$(VERSION).$(REVISION)
cp -rL $(SRC_DIST_FILES) $(PROG)-$(VERSION).$(REVISION)
git log --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=short >$(PROG)-$(VERSION).$(REVISION)/CHANGELOG.raw
tar czf $(PROG)-$(VERSION).$(REVISION).src.tar.gz $(PROG)-$(VERSION).$(REVISION)
mkdir -p dist
mv $(PROG)-$(VERSION).$(REVISION).src.tar.gz dist
$(RM) -rf $(PROG)-$(VERSION).$(REVISION)
.PHONY: dist

23
makefile.win32 Normal file
View File

@ -0,0 +1,23 @@
PROG = blobwarsAttrition.exe
CC = x86_64-w64-mingw32-gcc
SDLC = /usr/x86_64-w64-mingw32/bin/sdl2-config
LOCALE_DIR = locale
SEARCHPATH += src/plat/win32
_OBJS += win32Init.o
include common.mk
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 += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes -Werror=maybe-uninitialized -Warray-bounds
CXXFLAGS += -g -lefence
CXXFLAGS += -fms-extensions -std=gnu11
LDFLAGS += `$(SDLC) --libs` -lm -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lSDL2main -lpng -lz
# linking the program.
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LDFLAGS) -L$(LIBPATH)

BIN
manual/controls.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
manual/gamePlus.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
manual/gameplay1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
manual/gameplay2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
manual/gameplay3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
manual/hub1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
manual/hub2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

320
manual/index.html Normal file
View File

@ -0,0 +1,320 @@
<html>
<head>
<title>Blob Wars : Attrition - Gameplay Manual</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div style="width: 1024px; margin-left: auto; margin-right: auto; background-color: #000; padding: 10px; border: 1px #555 solid">
<div style="text-align: center;">
<p>
<img src="title.png" /><br />
Gameplay Manual<br />
</p>
<p style="font-size: 14px">Last updated: 18th May 2018</p>
</div>
<div>
<p style="font-size: 14px">
Table of Contents
<ul id="toc">
</ul>
</p>
</div>
<h3>Introduction</h3>
<p>
Blob Wars : Attrition is a mission and objective-based 2D platformer. It is the third entry in the Blob Wars series and is set between the events of Metal Blob Solid and Blob and Conquer. The story centres around an alien invasion of the Blobs' homeworld and their fight back against the aggressors. Many of Bob's fellow blobs have been assimilated by alien technology and become evil. During the game, you take control of a blob named Bob, whose mission it is to rescue MIA and fight back against the enemy. The gameplay is non-linear, allowing the player to tackle missions in any order they like.
</p>
<h3>Quick Start Guide</h3>
<p>
To quickly start playing the game:
<ul>
<li>Run the Blob Wars executable (./blobwarsAttrition on Linux, blobwarsAttrition.exe) on Windows).</li>
<li>Choose New Game and select a save slot.</li>
<li>On the world map screen, use the mouse or keyboard control to select the Beach Approach tutorial mission.</li>
<li>Play and complete the training mission to proceed with the game (or quit the mission to proceed more quickly).</li>
</ul>
</p>
<h3>Controls</h3>
<p>
Blob Wars : Attrition supports both keyboard and joypad controls. A joypad must be connected to the machine before the game is started up in order for the game to correctly detect it.
</p>
<p>
The game's default controls are listed below. These can all be changed by going to the Options screen and selecting "Controls ...". See the Options section of this manual for more information.
</p>
<p>
<table>
<tr><td>Up</td><td>W</td></tr>
<tr><td>Down</td><td>S</td></tr>
<tr><td>Left</td><td>A</td></tr>
<tr><td>Right</td><td>D</td></tr>
<tr><td>Fire</td><td>J</td></tr>
<tr><td>Jump</td><td>I</td></tr>
<tr><td>Jetpack / Aqualung</td><td>L</td></tr>
<tr><td>Pause</td><td>P</td></tr>
<tr><td>Radar</td><td>Tab</td></tr>
</table>
</p>
<p>
Various menus can also be access by pressing Escape in individual game sections. See Hub and and Main Mission for more details.
</p>
<h3>Gameplay</h3>
<p>
Most missions in the game feature multiple objectives which are listed at the start of the level. Those objectives listed in red are required to be completed. Those listed in white are optional and can be completed at any other time. Once all the objectives have been completed, the mission will automatically end and the player will be returned to the World Map. They can then choose to return to the mission again, to complete all the outstanding objectives and collect keys that they missed before.
</p>
<div class='annotationContainer'>
<div class="annotation" style="left: 125px; top: 10px;">1</div>
<div class="annotation" style="left: 725px; top: 50px;">2</div>
<div class="annotation" style="left: 400px; top: 235px;">3</div>
<div class="annotation" style="left: 460px; top: 235px;">4</div>
<div class="annotation" style="left: 200px; top: 235px;">5</div>
<img src="gameplay1.jpg" class="screenshot" />
<ol>
<li>Health, Power, Oxygen, and Weapon</li>
<li>Inventory</li>
<li>Bob (the player)</li>
<li>An enemy Blob</li>
<li>An enemy EyeDroid</li>
</ol>
</div>
<p>
Bob starts the game with 10 health points, which are depleted as he takes damage. When Bob's health is reduced to 0, he is killed and the mission is failed. Picking up cherries will help to regain health (see further below for more information). Bob also has a power level, that is used by both the aqua lung and jetpack. This can be replenished by picking up batteries (see further below for more information). It also naturally regenerates over time.
</p>
<img src="gameplay3.jpg" class="screenshot" />
<p>
Pressing Escape anytime during gameplay will bring up a menu, allowing you to access options, stats, trophy information, and to also quit the mission.
</p>
<p>
<ul>
<li><span class="highlight">Resume</span>: continue playing the game.</li>
<li><span class="highlight">Options</span>: access the options screen.</li>
<li><span class="highlight">Stats</span>: view various gameplay stats.</li>
<li><span class="highlight">Trophies</span>: view the trophies earned and outstanding.</li>
<li><span class="highlight">Quit</span>: quit the current mission.</li>
</ul>
</p>
<p>
The result of quitting a mission and returning to the hub depends on the current status of the mission. If the mission has never been completed, all progress will be lost and the mission will need to be restarted. If the mission has been completed before, all progress will be saved and any keys found will be taken along with the player (note that some items will be dropped in place).
</p>
<h4>Weapons</h4>
<p>
A number of weapons are at Bob's disposal:
<ul>
<li><span class='highlight'>Pistol</span>: Bob's starting weapon. Slow to fire, but unlike all the rest can be used underwater.</li>
<li><span class='highlight'>Plasma Rifle</span>: A rapid-firing gun that does slightly more damage than other guns in the game.</li>
<li><span class='highlight'>Spread Gun</span>: Fires three shots in a spread effect. Most useful in wide open spaces and for hitting enemies that are slightly out of reach.</li>
<li><span class='highlight'>Laser</span>: Cuts through enemies and bounces off walls Causes tremendous amounts of damage.</li>
<li><span class='highlight'>Grenades</span>: Bounce and explode on contact with enemies. Causes plenty of damage (some enemies, such as cannons, are immune to the explosion).</li>
</ul>
<i>Be aware that due to the nature of the game, Bob can only change weapons by picking up a weapon icon.</i>
</p>
<h4>Cherries and Batteries</h4>
<p>
Cherries and batteries restore Bob's health and power respectively. Each come in different sizes, topping up the health and power by different amounts. A small cherry and a weak battery will refill Bob's gauges a small amount, while a bunch of berries and a full battery will restore much more. You should collect cherries and batteries as often as you can, to keep your health and power as high as possible.
</p>
<h4>Flying and Swimming</h4>
<p>
From the start of the game, Bob is equipped with a jetpack and aqualung. When activated, the jetpack will allow Bob to fly for a short period of time, allowing him to reach higher and more distant areas. The jetpack draws on power reserves when it is activated and will automatically cut out once the power levels reach 0. When in water, Bob can swim. Swimming will slowly reduce his oxygen levels. Once the level reaches 0, Bob's health will rapidly decrease. Getting out of the water will regenerate Bob's O2 levels. Bob can also activate his aqualung to swim for longer. The aqualung will draw on Bob's power reserves and will cut out as soon as the power levels reach 0.
</p>
<h4>Keys</h4>
<p>
Keys and keycards to open doors can be found scattered throughout the missions in Attrition. Spare keys not used in a level are carried between levels once the mission ends (or the player quits). This is important, as not all the doors on one level will have a matching key. For example, a level might contain two gold doors, but only one gold key. In this instance, the player would need to find a gold key on another level.
</p>
<h4>MIAs</h4>
<p>
In some missions, Bob will encounter MIA blobs. These are your war buddies who have become too shell shocked to return home and are in need of rescue. Returning them home is easy: just walk into them. MIA blob don't attack enemies and cannot be hurt by gun fire (friend or foe), so don't worry about stray fire hitting them!
</p>
<h4>Water, Slime, and Lava</h4>
<p>
Water, slime, and lava are present in the Blobs' world. While Bob can swim in water and not suffer any ill effects (aside from drowning, if his oxygen runs out), slime and lava will reduce Bob's health if he falls in it. Slime will reduce Bob's health by 1 point, while lava will remove 2 points of health. Both should be avoided.
</p>
<h4>Hearts and Cells</h4>
<p>
Hearts and cells are special items that will increase Bob's maximum health and power by 1 point each. These items are unique and can be found in most levels in the game. Upon collecting a heart or cell, Bob's health or power will be immediately increased and restored to the new maximum. Hearts and cells are often in difficult to reach or out-of-the-way areas. Even so, you should make an effort to find them as quickly as possible as the increases in health and power will aid Bob immensely on his quest.
</p>
<h4>Teeka</h4>
<p>
Teeka is a buddy of Bob's who sometimes accompanied him on missions. He can sometimes be found on missions guarding a white keycard that is needed for boss encounters. He will leave once you collect it. Teeka can't be hurt by gun fire, but will attack enemies on sight.
</p>
<h3>Title Screen</h3>
<p><img src="title.jpg" class="screenshot" /></p>
<p>
The title screen offers a range of options.
<ul>
<li><span class="highlight">New Game</span>: starts a new game. You will need to choose a save slot to use. A warning will be shown if you chose an existing save slot, as all of the data will be overwritten.</li>
<li><span class="highlight">Load Game</span>: choose a save game to load. The save slots will display the percentage of the game complete and the time played (in hours and minutes).</li>
<li><span class="highlight">Continue</span>: quickly continue playing the most recently saved game.</li>
<li><span class="highlight">Options</span>: view and configure the game's options. See the Options section for more information.</li>
<li><span class="highlight">Credits</span>: view the game's credits.</li>
<li><span class="highlight">Exit</span>: exit the game.</li>
</ul>
</p>
<h3>Hub / World Map</h3>
<p>
The Hub is where the player can select the next mission to play. A number of pulsing circles will indicate the availability of the mission, as well as the status. A red circle indicates that the mission has yet to be played, while a yellow circle shows that it is partially complete and can be revisited.
</p>
<div class='annotationContainer'>
<div class="annotation" style="left: 400px; top: 25px;">1</div>
<div class="annotation" style="left: 200px; top: 360px;">2</div>
<div class="annotation" style="left: 525px; top: 275px;">3</div>
<div class="annotation" style="left: 440px; top: 200px;">4</div>
<img src="hub1.jpg" class="screenshot" />
<ol>
<li>Progress statistics</li>
<li>An incomplete mission</li>
<li>A partially completed mission</li>
<li>Select cursor</li>
</ol>
</div>
<p>
To start a mission, use the left, right, up, and down controls to move the cursor around and press fire to select the mission (hint: you can also use the mouse here - left click on a mission to select). The mission screen will show a brief description of what will be involved, and also show any keys that are currently in your inventory. Click the Start Mission button to being the mission or Cancel to back out of the mission detail.
</p>
<div class='annotationContainer'>
<div class="annotation" style="left: 480px; top: 70px;">1</div>
<div class="annotation" style="left: 620px; top: 150px;">2</div>
<div class="annotation" style="left: 160px; top: 275px;">3</div>
<div class="annotation" style="left: 635px; top: 300px;">4</div>
<img src="hub2.jpg" class="screenshot" />
<ol>
<li>Mission name</li>
<li>Mission description</li>
<li>Available keys (including number of)</li>
<li>Inventory slots</li>
</ol>
</div>
<h3>Main Mission</h3>
<p>
Upon starting a mission, the objectives for that mission will be displayed. The required objectives for the mission must be completed in order for it to be passed. If the player is killed or the mission is quit, it must be replayed from the beginning.
</p>
<h4>Objectives / Inventory</h4>
<p>
At any time during gameplay, pressing Pause will display the mission's current objectives, as well as their progress. It will also display the inventory, showing items carried. Required objectives are displayed in red, completed objectives in green, and other objectives (non-required) in white. Bob may carry up to 14 items (keys only occupy one inventory slot, their numbers stacking). There is no way for Bob to drop items that he is carrying, other than to use them.
</p>
<div class='annotationContainer'>
<div class="annotation" style="left: 645px; top: 110px;">1</div>
<div class="annotation" style="left: 135px; top: 145px;">2</div>
<div class="annotation" style="left: 645px; top: 215px;">3</div>
<div class="annotation" style="left: 600px; top: 315px;">4</div>
<img src="gameplay2.jpg" class="screenshot" />
<ol>
<li>A completed objective</li>
<li>An incomplete (required) objective</li>
<li>Incomplete optional objectives</li>
<li>Inventory</li>
</ol>
</div>
<h4>Radar</h4>
<p>
Pressing the Radar key (Tab by default) during a mission will bring up the radar screen. This will show all an extended area map of the current region. Various blips will be present, marking the location of keys, required mission items, MIAs, and mission targets (such as enemies and objects that must be destroyed). Note that the radar map does not cover the entire mission map and only extends out a little way from Bob's present location. It cannot be scrolled. However, various arrows will point in the direction of out-of-range targets. Following these arrows will lead Bob to his objectives.
</p>
<div class='annotationContainer'>
<div class="annotation" style="left: 400px; top: 150px;">1</div>
<div class="annotation" style="left: 80px; top: 210px;">2</div>
<div class="annotation" style="left: 600px; top: 400px;">3</div>
<img src="radar.jpg" class="screenshot" />
<ol>
<li>Radar map area</li>
<li>Blip directional arrows</li>
<li>Blip legend</li>
</ol>
</div>
<h4>Ending the Game</h4>
<p>
If Bob loses all his health, the mission is failed. At this point, you will have the option to restart the mission or return to the hub. Restarting the mission will reset everything to the way it was when the mission began; keys, items, etc. will be reset to their previous state, including the player's inventory and health bonuses. In the case of a new mission, this will mean restarting from the beginning. If returning to the mission, the player will restart from that point.
</p>
<h4>Post Game</h4>
<p>
<img src="gamePlus.jpg" class="screenshot" />
Once all missions have been completed, the player will have the option to continue the game in Free Play mode. They may play any mission they like, at any time. The state of the mission will not be saved, however. A number of additional gameplay options will also become available.
<ul>
<li><span class='highlight'>No Doors</span>: Removes all doors from the mission (keys will remain).</li>
<li><span class='highlight'>Random Enemies</span>: Enemies will have random weapons, leading to slightly harder gameplay.</li>
<li><span class='highlight'>Tougher Enemies</span>: Enemies will require more hits to take them down.</li>
<li><span class='highlight'>Defeat All Enemies</span>: All enemies will need to be defeated in order to finish the mission. No new enemies will spawn.</li>
<li><span class='highlight'>Mirror World</span>: The layout of the level will be horizontally mirrored, with enemy placements, items, doors, structures, etc. all appearing in opposite way around.</li>
</ul>
</p>
<h3>Options</h3>
<p>
The options screen can be access at most times during the game. It allow you to set various preferences using the up, down, left, right controls.
</p>
<p>
<img src="options.jpg" class="screenshot" />
<ul>
<li><span class='highlight'>Fullscreen</span>: activate the fullscreen mode for the game. Note that you must exit and restart the game in order for this change to take effect.</li>
<li><span class='highlight'>Window Size</span>: select the window size of the game. Change this if things appear too big or too small. Note that you must exit and restart the game in order for this change to take effect.</li>
<li><span class='highlight'>Sound Volume</span>: change the volume of the sound effect. Use the left and right controls to change the levels.</li>
<li><span class='highlight'>Music Volume</span>: change the volume of the music. Use the left and right controls to change the levels.</li>
<li><span class='highlight'>Blood</span>: whether or not to show blood. When blood is off, enemy blobs won't scream when they die and will also disappear in a puff of white when they are defeated. Blood will not splatter the ground. The Extra option will do the opposite and leave more blood around for longer (this might clutter the screen a little, so be careful with this option).</li>
<li><span class='highlight'>Trophy Alert</span>: whether or not to show an in-game alert when a trophy is earned. Switching to to Restricted will mean that alerts are not shown during a mission. This option may be best if you find the alerts obscuring gameplay.</li>
<li><span class='highlight'>Hud Inventory</span>: whether to show the in-game inventory in the top right corner of the screen during a mission. Turn this off if you find it either distract or is obscuring the gameplay.</li>
<li><span class='highlight'>Controls</span>: go to the controls configuration screen. See below for more details.</li>
</ul>
</p>
<p>
<img src="controls.jpg" class="screenshot" />
</p>
<p>
To change a control, highlight the relevant options and press Return or Space, then press the keyboard control or joypad button of your choosing. Pressing backspace will clear a control setting. Note that menus can always be navigated by using the arrow keys, and by pressing Return or Space.
</p>
<h3>Hints and Tips</h3>
<p>
<ul>
<li>Seek out Hearts and Cells as much as possible, to increase your health and power.</li>
<li>You may exit a partially completed mission at any time. Your progress will be saved and any keys found will come with you.</li>
<li>Enemies in Outposts are stronger and require more hits to take down. Tackle these missions with care.</li>
<li>When swimming, wait until your oxygen is just about the run out before activating your aqualung. O2 recovers much faster than battery power.</li>
<li>The pistol is the only weapon that can be fired underwater.</li>
<li>Later in the game, it may be necessary to return to earlier levels to collect as many keys as possible, in order to proceed.</li>
</ul>
</p>
<h3>Misc. Game Info</h3>
<p>
Blob Wars : Attrition features an in-game trophy system, not unlike the achievement and trophy system found in Steam, Xbox Live, and PSN. This is entirely an offline system and exists purely for fun. Trophies are awarded for things such as completing missions, defeating a certain number of enemies, and rescuing MIAs. You can view the trophies you have earned and those that are outstanding in the hub and mission menus. When a trophy is earned, a notification will appear on the screen. If you find these distracting, you can switch them off in the options screen (or set them to be restricted, so that they do not appear during missions).
</p>
<h3>License</h3>
<p>
Please refer to the LICENSE and README.md files that came with this game for information on the various copyrights of the source code, graphics, sound, and data. Additionally, you may visit <a href="https://github.com/stephenjsweeney/blobwarsAttrition">https://github.com/stephenjsweeney/blobwarsAttrition</a> to get the source code itself, and view the files there.
</p>
<h3>About</h3>
<p>
Blob Wars : Attrition is a port of the Android game of the same name. It is the third game in the Blob Wars series of games, that began in 2002.
</p>
<p>
<a href="http://www.parallelrealities.co.uk/games/attrition">http://www.parallelrealities.co.uk/games/attrition</a>
</p>
</div>
<script src='jquery-2.1.3.min.js'></script>
<script src='toc.js'></script>
</body>
</html>

4
manual/jquery-2.1.3.min.js vendored Executable file

File diff suppressed because one or more lines are too long

BIN
manual/options.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
manual/radar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

11
manual/style.css Normal file
View File

@ -0,0 +1,11 @@
body {font-family: sans; font-size: 14px; background: #111; color: #fff; line-height: 24px;}
h3 {margin-top: 50px; background-color: #234; padding: 5px;}
h4 {background-color: #345; padding: 5px;}
a {color: #0af; text-decoration: none;}
a:hover {color: #0af; text-decoration: underline;}
table {border-collapse: collapse;}
table, th, td {border: 1px solid white; padding: 8px;}
span.highlight {color: #fb0; font-weight: bold;}
img.screenshot {width: 800px; padding: 2px; border: 1px solid #ccc; margin-left: auto; margin-right: auto; display: block;}
div.annotation {border-radius: 50%; font-size: 12px; position: absolute; background-color: #08f; color: #fff; padding: 5px; font-weight: bold; border: 1px #adf solid; text-align: center; width: 21px; height: 21px;}
div.annotationContainer {position: relative; width: 800px; display: block; margin-left: auto; margin-right: auto;}

BIN
manual/title.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
manual/title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

22
manual/toc.js Normal file
View File

@ -0,0 +1,22 @@
$(document).ready(function() {
var toc = $('#toc');
var i = 1;
$('h3,h4').each(function(i, e) {
var link = 'link' + i;
var a = $('<a>').attr('href', '#' + link).append(e.innerText);
$(e).before($('<a>').attr('name', link));
if (e.tagName == 'H3')
{
toc.append("&blacksquare; <a href='#" + link + "'>" + e.innerText + "</a><br />");
}
if (e.tagName == 'H4')
{
toc.append("<span style='text-indent: 2em; display: inline-block'>&#9643 <a href='#" + link + "'>" + e.innerText + "</a></span><br />");
}
});
});

BIN
music/Sadness.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -26,37 +26,37 @@ int hasLineOfSight(Entity *src, Entity *dest)
float sx, sy, tx, ty, dx, dy;
Entity **candidates, *e;
SDL_Rect losBounds;
sx = src->x + (src->w / 2);
sy = src->y + (src->h / 2);
tx = dest->x + (dest->w / 2);
ty = dest->y + (dest->h / 2);
losBounds.x = (int) MIN(src->x, dest->x);
losBounds.y = (int) MIN(src->y, dest->y);
losBounds.w = (int) (MAX(src->x, dest->x) - losBounds.x);
losBounds.h = (int) (MAX(src->y, dest->y) - losBounds.y);
candidates = getAllEntsWithin(losBounds.x, losBounds.y, losBounds.w, losBounds.h, NULL);
getSlope(sx, sy, tx, ty, &dx, &dy);
dx *= 8;
dy *= 8;
while (1)
{
sx -= dx;
sy -= dy;
mx = sx / MAP_TILE_SIZE;
my = sy / MAP_TILE_SIZE;
if (isSolid(mx, my))
{
return 0;
}
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e != src && collision(sx, sy, 8, 8, e->x, e->y, e->w, e->h))
@ -65,7 +65,7 @@ int hasLineOfSight(Entity *src, Entity *dest)
{
return 0;
}
if (e == dest)
{
return 1;
@ -73,7 +73,7 @@ int hasLineOfSight(Entity *src, Entity *dest)
}
}
}
return 0;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,9 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h"
extern int isSolid(int x, int y);
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
extern int isSolid(int x, int y);
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,8 +29,8 @@ void addExplosion(float x, float y, int radius, Entity *owner)
Entity **candidates, *e;
float power;
int i;
playSound(SND_EXPLOSION, CH_EXPLODE);
playBattleSound(SND_EXPLOSION, 0, x, y);
/* assuming x and y were from the top left of the entity */
x += radius / 2;
@ -42,7 +42,7 @@ void addExplosion(float x, float y, int radius, Entity *owner)
radiusRect.y = (int) (y - radius);
radiusRect.w = radius * 2;
radiusRect.h = radius * 2;
if (killTimer < SDL_GetTicks())
{
numKilled = 0;
@ -77,17 +77,17 @@ void addExplosion(float x, float y, int radius, Entity *owner)
{
stunBob();
}
if (owner->type == ET_ENEMY && e->health <= 0 && e->type == ET_ENEMY && strstr(((Unit*)owner)->unitType, "EyeDroid"))
{
game.stats[STAT_EYE_DROID_EXPLOSION_KILLS]++;
}
if (e->health <= 0)
{
e->dx = rrnd(-radius / 8, radius / 8);
e->dy = rrnd(-5, 0);
if (owner->type == ET_BOB)
{
numKilled++;
@ -98,9 +98,16 @@ void addExplosion(float x, float y, int radius, Entity *owner)
}
}
}
if (numKilled >= 12)
if (numKilled >= 2)
{
awardTrophy("GRENADE_COMBO");
setGameplayMessage(MSG_STANDARD, "%d hit grenade combo!", numKilled);
game.stats[STAT_GRENADE_COMBO] = MAX(game.stats[STAT_GRENADE_COMBO], numKilled);
if (numKilled >= 12)
{
awardTrophy("GRENADE_COMBO");
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,13 +20,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h"
extern int rrnd(int low, int high);
extern void stunBob(void);
extern void addExplosionParticles(float x, float y, float radius, int amount);
extern void playSound(int snd, int ch);
extern void awardTrophy(char *id);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void playBattleSound(int snd, int ch, int x, int y);
extern int rrnd(int low, int high);
extern void setGameplayMessage(int newMessageType, const char *format, ...);
extern void stunBob(void);
extern void swapSelf(Entity *e);
extern void awardTrophy(char *id);
extern Game game;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -56,7 +56,7 @@ void initWeapons(void)
missileSprite[0] = getSprite("MissileRight");
missileSprite[1] = getSprite("MissileLeft");
weaponName[WPN_PISTOL] = _("Pistol");
weaponName[WPN_PLASMA] = _("Plasma Rifle");
weaponName[WPN_SPREAD] = _("Spread Gun");
@ -68,16 +68,19 @@ void initWeapons(void)
void firePistol(void)
{
Bullet *bullet;
bullet = createBaseBullet((Unit*)world.bob);
bullet->weaponType = WPN_PISTOL;
bullet->facing = world.bob->facing;
bullet->sprite[0] = bulletSprite[0];
bullet->sprite[1] = bulletSprite[1];
world.bob->reload = 20;
if (world.bob->facing != FACING_DIE)
{
bullet = createBaseBullet((Unit*)world.bob, bulletSprite[0]->frames[0]->rect.w);
bullet->weaponType = WPN_PISTOL;
bullet->facing = world.bob->facing;
bullet->sprite[0] = bulletSprite[0];
bullet->sprite[1] = bulletSprite[1];
playSound(SND_PISTOL, CH_BOB);
world.bob->reload = 20;
playSound(SND_PISTOL, world.bob->uniqueId % MAX_SND_CHANNELS);
}
}
void fireAimedShot(Unit *owner)
@ -85,50 +88,59 @@ void fireAimedShot(Unit *owner)
int x, y;
float dx, dy;
Bullet *bullet;
x = (int) (world.bob->x + rrnd(-8, 24));
y = (int) (world.bob->y + rrnd(-8, 24));
getSlope(x, y, owner->x, owner->y, &dx, &dy);
if (owner->facing != FACING_DIE)
{
x = (int) (world.bob->x + rrnd(-8, 24));
y = (int) (world.bob->y + rrnd(-8, 24));
bullet = createBaseBullet(owner);
bullet->weaponType = WPN_AIMED_PISTOL;
bullet->dx = dx * 6;
bullet->dy = dy * 6;
bullet->sprite[0] = bullet->sprite[1] = aimedSprite;
bullet->health *= 2;
getSlope(x, y, owner->x, owner->y, &dx, &dy);
owner->reload = 15;
bullet = createBaseBullet(owner, aimedSprite->w);
bullet->weaponType = WPN_AIMED_PISTOL;
bullet->dx = dx * 6;
bullet->dy = dy * 6;
bullet->sprite[0] = bullet->sprite[1] = aimedSprite;
bullet->health *= 2;
playSound(SND_PISTOL, CH_WEAPON);
owner->reload = 15;
playBattleSound(SND_PISTOL, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
void fireMachineGun(Unit *owner)
{
Bullet *bullet;
bullet = createBaseBullet(owner);
bullet->weaponType = WPN_MACHINE_GUN;
bullet->sprite[0] = bulletSprite[0];
bullet->sprite[1] = bulletSprite[1];
owner->reload = 8;
playSound(SND_MACHINE_GUN, CH_WEAPON);
if (owner->facing != FACING_DIE)
{
bullet = createBaseBullet(owner, bulletSprite[0]->w);
bullet->weaponType = WPN_MACHINE_GUN;
bullet->sprite[0] = bulletSprite[0];
bullet->sprite[1] = bulletSprite[1];
owner->reload = 8;
playBattleSound(SND_MACHINE_GUN, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
void firePlasma(Unit *owner)
{
Bullet *bullet;
bullet = createBaseBullet(owner);
bullet->weaponType = WPN_PLASMA;
bullet->sprite[0] = plasmaSprite[0];
bullet->sprite[1] = plasmaSprite[1];
bullet->damage = 2;
owner->reload = owner->type == ET_BOB ? 4 : 8;
if (owner->facing != FACING_DIE)
{
bullet = createBaseBullet(owner, plasmaSprite[0]->w);
bullet->weaponType = WPN_PLASMA;
bullet->sprite[0] = plasmaSprite[0];
bullet->sprite[1] = plasmaSprite[1];
bullet->damage = 2;
playSound(SND_PLASMA, owner->type == ET_BOB ? CH_BOB : CH_WEAPON);
owner->reload = owner->type == ET_BOB ? 4 : 8;
playBattleSound(SND_PLASMA, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
void fireSpread(Unit *owner, int numberOfShots)
@ -137,61 +149,67 @@ void fireSpread(Unit *owner, int numberOfShots)
int i;
float dy;
dy = -(numberOfShots / 2) * 3;
for (i = 0 ; i < numberOfShots ; i++)
if (owner->facing != FACING_DIE)
{
bullet = createBaseBullet(owner);
bullet->weaponType = WPN_SPREAD;
bullet->sprite[0] = bullet->sprite[1] = owner->type == ET_BOB ? spreadShotSprite : alienSpreadShotSprite;
bullet->dx = owner->facing == FACING_RIGHT ? 15 : -15;
bullet->dy = dy;
dy = -(numberOfShots / 2) * 3;
dy += 3;
for (i = 0 ; i < numberOfShots ; i++)
{
bullet = createBaseBullet(owner, spreadShotSprite->w);
bullet->weaponType = WPN_SPREAD;
bullet->sprite[0] = bullet->sprite[1] = owner->type == ET_BOB ? spreadShotSprite : alienSpreadShotSprite;
bullet->dx = owner->facing == FACING_RIGHT ? 15 : -15;
bullet->dy = dy;
owner->reload = 16;
dy += 3;
owner->reload = 16;
}
playBattleSound(SND_SPREAD, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
playSound(SND_SPREAD, owner->type == ET_BOB ? CH_BOB : CH_WEAPON);
}
void fireLaser(Unit *owner)
{
Bullet *laser;
laser = createBaseBullet(owner);
laser->x = owner->x + owner->w / 2;
laser->y = owner->y + owner->h / 2;
laser->facing = owner->facing;
laser->dx = owner->facing == FACING_RIGHT ? 20 : -20;
laser->health = FPS * 3;
laser->sprite[0] = laser->sprite[1] = (owner->type == ET_BOB) ? laserSprite[0] : laserSprite[1];
initLaser(laser);
if (owner->facing != FACING_DIE)
{
laser = createBaseBullet(owner, laserSprite[0]->w);
laser->facing = owner->facing;
laser->dx = owner->facing == FACING_RIGHT ? 20 : -20;
laser->health = FPS * 3;
laser->sprite[0] = laser->sprite[1] = (owner->type == ET_BOB) ? laserSprite[0] : laserSprite[1];
owner->reload = owner->type == ET_BOB ? FPS / 2 : FPS;
initLaser(laser);
playSound(SND_LASER, owner->type == ET_BOB ? CH_BOB : CH_WEAPON);
owner->reload = owner->type == ET_BOB ? FPS / 2 : FPS;
playBattleSound(SND_LASER, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
void fireGrenade(Unit *owner)
{
Bullet *grenade;
grenade = createBaseBullet(owner);
grenade->x = owner->x + owner->w / 2;
grenade->y = owner->y;
grenade->facing = owner->facing;
grenade->health = FPS * 3;
grenade->dx = owner->facing == FACING_RIGHT ? 8 : -8;
grenade->sprite[0] = grenade->sprite[1] = (owner->type == ET_BOB) ? grenadeSprite : alienGrenadeSprite;
grenade->dy = -6;
initGrenade(grenade);
if (owner->facing != FACING_DIE)
{
grenade = createBaseBullet(owner, grenadeSprite->w);
grenade->y = owner->y;
grenade->facing = owner->facing;
grenade->health = FPS * 3;
grenade->dx = owner->facing == FACING_RIGHT ? 8 : -8;
grenade->sprite[0] = grenade->sprite[1] = (owner->type == ET_BOB) ? grenadeSprite : alienGrenadeSprite;
grenade->dy = -6;
owner->reload = FPS / 2;
initGrenade(grenade);
playSound(SND_THROW, owner->type == ET_BOB ? CH_BOB : CH_WEAPON);
owner->reload = FPS / 2;
playBattleSound(SND_THROW, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
void fireShotgun(Unit *owner)
@ -199,44 +217,49 @@ void fireShotgun(Unit *owner)
int i;
float dx, dy;
Bullet *bullet;
for (i = 0 ; i < 8 ; i++)
if (owner->facing != FACING_DIE)
{
getSlope(world.bob->x + rrnd(0, 40), world.bob->y + rrnd(0, 40), owner->x, owner->y, &dx, &dy);
for (i = 0 ; i < 8 ; i++)
{
getSlope(world.bob->x + rrnd(0, 40), world.bob->y + rrnd(0, 40), owner->x, owner->y, &dx, &dy);
bullet = createBaseBullet(owner);
bullet->weaponType = WPN_SHOTGUN;
bullet->x = owner->x + (owner->w / 2) + rrnd(-8, 8);
bullet->y = owner->y + (owner->h / 2) + rrnd(-8, 8);
bullet->dx = dx * 12;
bullet->dy = dy * 12;
bullet->damage = 2;
bullet->sprite[0] = bullet->sprite[1] = shotgunPelletSprite;
bullet = createBaseBullet(owner, 0);
bullet->weaponType = WPN_SHOTGUN;
bullet->x = owner->x + (owner->w / 2) + rrnd(-8, 8);
bullet->y = owner->y + (owner->h / 2) + rrnd(-8, 8);
bullet->dx = dx * 12;
bullet->dy = dy * 12;
bullet->damage = 2;
bullet->sprite[0] = bullet->sprite[1] = shotgunPelletSprite;
owner->reload = 15;
owner->reload = 15;
}
playBattleSound(SND_SHOTGUN, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
playSound(SND_SHOTGUN, CH_WEAPON);
}
void fireMissile(Unit *owner)
{
Bullet *missile;
missile = createBaseBullet(owner);
missile->x = owner->x + owner->w / 2;
missile->y = owner->y + 10;
missile->facing = owner->facing;
missile->dx = owner->facing == FACING_RIGHT ? 10 : -10;
missile->health = FPS * 3;
missile->sprite[0] = missileSprite[0];
missile->sprite[1] = missileSprite[1];
initMissile(missile);
if (owner->facing != FACING_DIE)
{
missile = createBaseBullet(owner, missileSprite[0]->w);
missile->y = owner->y + 10;
missile->facing = owner->facing;
missile->dx = owner->facing == FACING_RIGHT ? 10 : -10;
missile->health = FPS * 3;
missile->sprite[0] = missileSprite[0];
missile->sprite[1] = missileSprite[1];
owner->reload = FPS / 2;
initMissile(missile);
playSound(SND_MISSILE, CH_WEAPON);
owner->reload = FPS / 2;
playBattleSound(SND_MISSILE, owner->uniqueId % MAX_SND_CHANNELS, owner->x, owner->y);
}
}
int getRandomPlayerWeapon(int excludeGrenades)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,13 +20,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h"
extern Bullet *createBaseBullet(Unit *owner, int bulletWidth);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern Sprite *getSprite(char *name);
extern void initGrenade(Bullet *b);
extern void initLaser(Bullet *b);
extern void initMissile(Bullet *b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void playSound(int snd, int ch);
extern int rrnd(int low, int high);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern void initLaser(Bullet *b);
extern void initGrenade(Bullet *b);
extern void initMissile(Bullet *b);
extern Bullet *createBaseBullet(Unit *owner);
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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) 2018 Parallel Realities
Copyright (C) 2018-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,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PI 3.14159265358979323846
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define CAROLINE(a,b) MIN(a,b)
#define STRNCPY(dest, src, n) strncpy(dest, src, n); dest[n - 1] = '\0'
#define TO_RAIDANS(angleDegrees) (angleDegrees * PI / 180.0)
#define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI)
@ -38,6 +39,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define SAVE_FILENAME "game.save"
#define CONFIG_FILENAME "config.json"
#define UI_WIDTH 1280
#define UI_HEIGHT 720
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
@ -49,9 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_FONTS 64
#define NUM_TEXT_BUCKETS 64
#define TEXT_TTL (1000 * 20)
#define MAX_WIDGETS 48
#define NUM_GLYPH_BUCKETS 128
#define MAX_NAME_LENGTH 32
#define MAX_DESCRIPTION_LENGTH 512
@ -64,9 +66,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAP_WIDTH 200
#define MAP_HEIGHT 200
#define MAP_RENDER_WIDTH ((SCREEN_WIDTH / MAP_TILE_SIZE) + 1)
#define MAP_RENDER_HEIGHT ((SCREEN_HEIGHT / MAP_TILE_SIZE) + 1)
#define MAP_TILE_SIZE 64
#define MAP_TILE_AIR 0
#define MAP_TILE_WATER 1
@ -80,6 +79,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAP_TILE_OUTSIDE 255
#define MAP_TILE_MAX 256
/* for mirroring */
#define MAP_PIXEL_WIDTH (MAP_WIDTH * MAP_TILE_SIZE)
#define JUMP_POWER -12
#define MAX_OXYGEN (FPS * 10)
#define MAX_KEY_TYPES 8
@ -89,6 +91,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_ENTS_TO_OBSERVE 12
#define MAX_SND_CHANNELS 64
#define MAX_SAVE_SLOTS 5
enum
{
ET_NONE,
@ -98,7 +104,8 @@ enum
ET_ENEMY,
ET_TEEKA,
ET_BOSS,
ET_HEART_CELL,
ET_HEART,
ET_CELL,
ET_KEY,
ET_ITEM,
ET_CONSUMABLE,
@ -137,6 +144,10 @@ enum
#define EF_KILL_OFFSCREEN (2 << 15)
#define EF_ALWAYS_PROCESS (2 << 16)
#define EF_NO_TELEPORT (2 << 17)
#define EF_NO_OBSERVE (2 << 18)
#define EF_BULLET_HIT (2 << 19)
#define EF_CRUSHABLE (2 << 20)
#define EF_MIRROR (2 << 21)
#define GRAVITY_POWER 0.5f
#define FRICTION 0.75f
@ -235,7 +246,8 @@ enum
WS_OBSERVING,
WS_COMPLETE,
WS_MISSION_COMPLETE,
WS_GAME_OVER
WS_GAME_OVER,
WS_QUIT
};
enum
@ -311,23 +323,13 @@ enum
SND_MISSION_COMPLETE,
SND_HEART_CELL,
SND_TROPHY,
SND_ELECTRIC_HIT,
SND_ITEM_PAD,
SND_POWER_POOL,
SND_POP,
SND_MAX
};
enum
{
CH_ANY = -1,
CH_BOB,
CH_EXPLODE,
CH_WEAPON,
CH_DEATH,
CH_ITEM,
CH_TOUCH,
CH_MECHANICAL,
CH_EFFECTS,
CH_MAX
};
enum
{
WT_BUTTON,
@ -348,6 +350,7 @@ enum
enum
{
STAT_MISSIONS_COMPLETE,
STAT_KEYS_FOUND,
STAT_CELLS_FOUND,
STAT_HEARTS_FOUND,
@ -356,7 +359,9 @@ enum
STAT_DEATHS,
STAT_SHOTS_FIRED,
STAT_SHOTS_HIT,
STAT_SHOT_ACCURACY,
STAT_EYE_DROID_EXPLOSION_KILLS,
STAT_GRENADE_COMBO,
STAT_FLY_TIME,
STAT_SWIM_TIME,
STAT_CHERRIES_PICKED_UP,
@ -364,6 +369,79 @@ enum
STAT_WEAPONS_PICKED_UP,
STAT_ENEMIES_KILLED,
STAT_MISSIONS_PLAYED,
STAT_PERCENT_COMPLETE,
STAT_TIME_PLAYED,
STAT_MAX
};
enum
{
ST_MISSION_COMPLETE,
ST_OBJECTIVES,
ST_INCOMPLETE,
ST_COMPLETE,
ST_PRESS_FIRE,
ST_OPTIONS,
ST_CONTROLS,
ST_TROPHIES,
ST_PAGE,
ST_HIDDEN,
ST_WEAPON,
ST_CELL,
ST_HEART,
ST_TELEPORTER,
ST_LASERS,
ST_POWER_POINT,
ST_LIFT,
ST_EXIT,
ST_LOCKED,
ST_OPENED,
ST_GOT_GRENADES,
ST_PICKED_UP,
ST_REMOVED,
ST_REQUIRED,
ST_CANNOT_CARRY_KEYS,
ST_CANNOT_CARRY_ITEMS,
ST_RESCUED,
ST_JETPACK_POWER,
ST_AQUALUNG_POWER,
ST_QUIT_HUB,
ST_QUIT_TUTORIAL,
ST_QUIT_SAVE,
ST_QUIT_FREE_PLAY,
ST_QUIT_LOSE,
ST_MIAS,
ST_ITEMS,
ST_TARGETS,
ST_OBJECTIVE_COMPLETE,
ST_CHERRY_BUNCH,
ST_CHERRY_PAIR,
ST_CHERRY_SMALL,
ST_BATTERY_FULL,
ST_BATTERY,
ST_USED_BATTERY,
ST_WEAK_BATTERY,
ST_CHOOSE_SAVE,
ST_LOAD,
ST_OVERWRITE_1,
ST_OVERWRITE_2,
ST_FREEPLAY,
ST_HEART_CELL,
ST_HUB_MISSIONS,
ST_HUB_MIAS,
ST_HUB_TARGETS,
ST_HUB_KEYS,
ST_HUB_HEARTS,
ST_HUB_CELLS,
ST_CORRUPT_SAVE,
ST_EMPTY_SAVE,
ST_MISSION_CONFIG,
ST_MAX
};
#define PLUS_NONE 0
#define PLUS_NO_DOORS (2 << 0)
#define PLUS_STRONGER (2 << 1)
#define PLUS_RANDOM (2 << 2)
#define PLUS_KILL_ALL (2 << 3)
#define PLUS_MIRROR (2 << 4)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,16 +49,17 @@ static Sprite *walkSprite[3];
static Sprite *swimSprite[3];
static Sprite *flySprite[3];
static int checkpointTimer;
static int oldFacing;
Entity *initBob(void)
{
Bob *b;
b = malloc(sizeof(Bob));
memset(b, 0, sizeof(Bob));
initEntity((Entity*)b);
STRNCPY(b->name, "Bob", MAX_NAME_LENGTH);
b->type = ET_BOB;
@ -82,9 +83,9 @@ Entity *initBob(void)
b->reload = 0;
b->flags |= EF_SWIMS | EF_BOMB_SHIELD;
superAnimate = b->animate;
b->tick = tick;
b->init = init;
b->applyDamage = applyDamage;
@ -95,19 +96,21 @@ Entity *initBob(void)
b->die = die;
b->load = load;
b->save = save;
checkpointTimer = 0;
oldFacing = b->facing;
return (Entity*)b;
}
static void init(void)
{
changeSprite(walkSprite);
world.bob->checkpoints[0].x = world.bob->x;
world.bob->checkpoints[0].y = world.bob->y;
superAnimate();
}
@ -174,7 +177,7 @@ static void doAlive(void)
{
world.bob->outTimer = FPS * 3;
world.bob->stunTimer = 1;
if (world.bob->flags & EF_IMMUNE)
if (!(world.bob->flags & EF_IMMUNE))
{
world.bob->health--;
}
@ -186,7 +189,7 @@ static void doAlive(void)
{
world.bob->outTimer = FPS * 3;
world.bob->stunTimer = 1;
if (world.bob->flags & EF_IMMUNE)
if (!(world.bob->flags & EF_IMMUNE))
{
world.bob->health -= 2;
}
@ -201,8 +204,7 @@ static void handeImmunity(void)
if (world.bob->outTimer > 0)
{
world.bob->outTimer--;
if (world.bob->outTimer <= 0)
if (--world.bob->outTimer <= 0)
{
world.betweenTimer = FPS / 2;
resetAtCheckpoint();
@ -210,8 +212,7 @@ static void handeImmunity(void)
}
else if (world.bob->stunTimer > 0)
{
world.bob->stunTimer--;
if (world.bob->stunTimer <= 0)
if (--world.bob->stunTimer <= 0)
{
if (!world.bob->isOnGround && world.bob->environment != ENV_WATER)
{
@ -219,6 +220,7 @@ static void handeImmunity(void)
}
else
{
world.bob->facing = oldFacing;
world.bob->spriteFrame = 0;
world.bob->spriteTime = 0;
world.bob->dy = 0;
@ -229,8 +231,7 @@ static void handeImmunity(void)
}
else if (world.bob->immuneTimer > 0)
{
world.bob->immuneTimer--;
if (world.bob->immuneTimer <= 0)
if (--world.bob->immuneTimer <= 0)
{
world.bob->flags &= ~(EF_FLICKER | EF_IMMUNE);
}
@ -242,7 +243,7 @@ static void handeImmunity(void)
world.bob->checkpoints[i].x = world.bob->checkpoints[i - 1].x;
world.bob->checkpoints[i].y = world.bob->checkpoints[i - 1].y;
}
world.bob->checkpoints[0].x = world.bob->x;
world.bob->checkpoints[0].y = world.bob->y;
checkpointTimer = FPS;
@ -289,11 +290,11 @@ static void activate(int activate)
{
if (world.bob->environment == ENV_AIR)
{
setGameplayMessage(MSG_STANDARD, _("Not enough power for jetpack"));
setGameplayMessage(MSG_STANDARD, app.strings[ST_JETPACK_POWER]);
}
else
{
setGameplayMessage(MSG_STANDARD, _("Not enough power for aqualung"));
setGameplayMessage(MSG_STANDARD, app.strings[ST_AQUALUNG_POWER]);
}
}
}
@ -312,7 +313,7 @@ static void doBobInAir(void)
if (--world.bob->jpEffectTimer <= 0)
{
addFlameParticles(world.bob->x + (world.bob->facing * 25) + rrnd(-1, 1), world.bob->y + 25 + rrnd(-1, 1));
addFlameParticles(world.bob->x + (world.bob->facing * 25) + rrnd(-1, 1), world.bob->y + 25 + rrnd(-1, 1), 0);
world.bob->jpEffectTimer = 1;
}
@ -352,24 +353,42 @@ static void doBobInWater(void)
if (world.bob->oxygen == 0 && (world.frameCounter % 30) == 0)
{
world.bob->health--;
playSound(SND_DROWN, CH_BOB);
playSound(SND_DROWN, world.bob->uniqueId % MAX_SND_CHANNELS);
}
}
}
static void doDying(void)
{
world.bob->health--;
int mx, my;
if (world.bob->health <= -(FPS * 2))
if (--world.bob->health <= -(FPS * 2))
{
world.bob->flags |= EF_GONE;
throwFleshChunks(world.bob->x + world.bob->w / 2, world.bob->y + world.bob->h / 2, rrnd(3, 6));
if (app.config.blood)
{
throwFleshChunks(world.bob->x + world.bob->w / 2, world.bob->y + world.bob->h / 2, rrnd(3, 6));
}
else
{
addPopParticles(world.bob->x + world.bob->w / 2, world.bob->y + world.bob->h / 2);
}
world.state = WS_GAME_OVER;
playSound(SND_SPLAT, CH_BOB);
if (app.config.blood)
{
playSound(SND_SPLAT, world.bob->uniqueId % MAX_SND_CHANNELS);
}
else
{
playSound(SND_POP, world.bob->uniqueId % MAX_SND_CHANNELS);
}
mx = (int) ((world.bob->x + (world.bob->w / 2)) / MAP_TILE_SIZE);
my = (int) (world.bob->y / MAP_TILE_SIZE) + 1;
addBloodDecal(mx, my);
game.stats[STAT_DEATHS]++;
}
@ -453,7 +472,7 @@ static void bobWalk(void)
{
fireWeapon();
}
if (isControl(CONTROL_JETPACK))
{
activate(1);
@ -492,7 +511,7 @@ static void bobSwim(void)
{
firePistol();
}
if (isControl(CONTROL_JETPACK))
{
activate(1);
@ -530,7 +549,7 @@ static void bobFly(void)
{
fireWeapon();
}
if (isControl(CONTROL_JETPACK))
{
activate(1);
@ -600,6 +619,7 @@ void resetAtCheckpoint(void)
world.bob->x = world.bob->checkpoints[0].x;
world.bob->y = world.bob->checkpoints[0].y;
world.bob->facing = oldFacing;
world.bob->outTimer = 0;
world.bob->flags |= EF_FLICKER;
world.bob->flags &= ~EF_WEIGHTLESS;
@ -610,7 +630,7 @@ void resetAtCheckpoint(void)
addTeleportStars((Entity*)world.bob);
if (world.state == WS_IN_PROGRESS)
{
playSound(SND_APPEAR, CH_ANY);
playSound(SND_APPEAR, -1);
}
}
@ -630,32 +650,51 @@ static void die(void)
switch (rand() % 3)
{
case 0:
playSound(SND_DEATH_1, CH_DEATH);
playSound(SND_DEATH_1, world.bob->uniqueId % MAX_SND_CHANNELS);
break;
case 1:
playSound(SND_DEATH_2, CH_DEATH);
playSound(SND_DEATH_2, world.bob->uniqueId % MAX_SND_CHANNELS);
break;
case 2:
playSound(SND_DEATH_3, CH_DEATH);
playSound(SND_DEATH_3, world.bob->uniqueId % MAX_SND_CHANNELS);
break;
}
}
static SDL_Rect *getCurrentSprite(void)
{
if (world.bob->alive == ALIVE_ALIVE && world.bob->stunTimer <= 0)
Sprite *s;
s = (world.bob->alive == ALIVE_ALIVE && world.bob->stunTimer <= 0) ? world.bob->sprite[world.bob->facing] : world.bob->sprite[FACING_DIE];
{
return &world.bob->sprite[world.bob->facing]->frames[world.bob->spriteFrame]->rect;
}
return &world.bob->sprite[FACING_DIE]->frames[world.bob->spriteFrame]->rect;
if (world.bob->spriteFrame >= s->numFrames)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "WARNING: %s (%d) bad sprite frames - %d > %d\n", world.bob->name, world.bob->type, world.bob->spriteFrame, s->numFrames);
world.bob->spriteFrame = 0;
}
return &s->frames[world.bob->spriteFrame]->rect;
}
static void animate(void)
{
if (world.bob->dx != 0 || world.bob->stunTimer > 0 || world.bob->flags & EF_WEIGHTLESS || world.bob->health <= 0)
if (world.bob->stunTimer > 0 || world.bob->alive != ALIVE_ALIVE)
{
if (world.bob->facing != FACING_DIE)
{
oldFacing = world.bob->facing;
}
world.bob->facing = FACING_DIE;
superAnimate();
}
else if (world.bob->dx != 0 || world.bob->flags & EF_WEIGHTLESS)
{
superAnimate();
}
@ -666,10 +705,21 @@ static void load(cJSON *root)
world.bob->x = cJSON_GetObjectItem(root, "x")->valueint;
world.bob->y = cJSON_GetObjectItem(root, "y")->valueint;
world.bob->facing = lookup(cJSON_GetObjectItem(root, "facing")->valuestring);
if (game.plus & PLUS_MIRROR)
{
world.bob->x = MAP_PIXEL_WIDTH - world.bob->x;
}
}
static void save(cJSON *root)
{
/* in case Bob was put into stun state during save */
if (world.bob->facing == FACING_DIE)
{
world.bob->facing = oldFacing;
}
cJSON_AddStringToObject(root, "type", "Bob");
cJSON_AddNumberToObject(root, "x", world.bob->checkpoints[0].x);
cJSON_AddNumberToObject(root, "y", world.bob->checkpoints[0].y);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,32 +21,35 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
#include "../../json/cJSON.h"
#define WALK_SPEED 5
#define SWIM_SPEED 3
#define FLY_ACCEL 0.1
#define FLY_SPEED 8
#define SWIM_SPEED 3
#define WALK_SPEED 5
extern Sprite *getSprite(char *name);
extern char *getLookupName(const char *prefix, long num);
extern long lookup(const char *name);
extern double randF(void);
extern int rrnd(int low, int high);
extern float limit(float i, float a, float b);
extern int isSolid(int x, int y);
extern void setGameplayMessage(int type, char *format, ...);
extern void playSound(int snd, int ch);
extern void addFlameParticles(float x, float y);
extern void throwFleshChunks(float x, float y, int amount);
extern void firePistol(void);
extern void addBloodDecal(int x, int y);
extern void addFlameParticles(float x, float y, int rising);
extern void addPopParticles(float x, float y);
extern void addTeleportStars(Entity *e);
extern void clearControl(int type);
extern void fireGrenade(Entity *e);
extern void fireLaser(Entity *e);
extern void firePistol(void);
extern void firePlasma(Entity *e);
extern void fireSpread(Entity *e, int n);
extern void fireLaser(Entity *e);
extern void addTeleportStars(Entity *e);
extern char *getLookupName(const char *prefix, long num);
extern Sprite *getSprite(char *name);
extern void initEntity(Entity *e);
extern int isControl(int type);
extern void clearControl(int type);
extern int isSolid(int x, int y);
extern float limit(float i, float a, float b);
extern long lookup(const char *name);
extern void playSound(int snd, int ch);
extern double randF(void);
extern int rrnd(int low, int high);
extern void setGameplayMessage(int type, char *format, ...);
extern void throwFleshChunks(float x, float y, int amount);
extern App app;
extern Dev dev;
extern Game game;
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -32,14 +32,14 @@ static void save(cJSON *root);
Entity *initMIA(void)
{
MIA *m;
m = malloc(sizeof(MIA));
memset(m, 0, sizeof(MIA));
initEntity((Entity*)m);
m->type = ET_MIA;
m->tx = m->ty = -1;
m->sprite[FACING_LEFT] = getSprite("MIA");
@ -60,7 +60,7 @@ Entity *initMIA(void)
m->save = save;
m->isMissionTarget = 1;
return (Entity*)m;
}
@ -81,11 +81,10 @@ static void reset(void)
static void tick(void)
{
MIA *m;
m = (MIA*)self;
m->shudderTimer--;
if (m->shudderTimer <= 0)
if (--m->shudderTimer <= 0)
{
m->x = (m->tx + rand() % 4);
m->shudderTimer = 2;
@ -93,76 +92,82 @@ static void tick(void)
if (!m->isMissionTarget)
{
m->starTimer--;
if (m->starTimer <= 0)
if (--m->starTimer <= 0)
{
addMIATeleportStars(m->x + rand() % m->w, m->y + rand() % m->h);
m->starTimer = 1;
}
world.saveDelay = FPS;
}
}
static void touch(Entity *other)
{
MIA *m;
m = (MIA*)self;
if (m->isMissionTarget && other == (Entity*)world.bob)
{
m->action = preTeleport;
m->teleportTimer = FPS * 3;
setGameplayMessage(MSG_OBJECTIVE, _("Rescued %s"), m->name);
setGameplayMessage(MSG_OBJECTIVE, app.strings[ST_RESCUED], m->name);
m->isMissionTarget = 0;
m->flags |= EF_ALWAYS_PROCESS;
playSound(SND_MIA, CH_ANY);
m->plane = PLANE_FOREGROUND;
playSound(SND_MIA, m->uniqueId % MAX_SND_CHANNELS);
game.stats[STAT_MIAS_RESCUED]++;
updateObjective("MIA");
}
}
static void preTeleport(void)
{
MIA *m;
m = (MIA*)self;
if (--m->teleportTimer <= FPS)
{
m->action = teleport;
m->flags |= (EF_NO_CLIP | EF_WEIGHTLESS);
m->dy = -5;
}
world.saveDelay = FPS;
}
static void teleport(void)
{
MIA *m;
m = (MIA*)self;
if (--m->teleportTimer <= 0)
{
addTeleportStars(self);
game.stats[STAT_MIAS_RESCUED]++;
updateObjective("MIA");
m->alive = ALIVE_DEAD;
}
world.saveDelay = FPS;
}
static void load(cJSON *root)
{
MIA *m;
m = (MIA*)self;
m->active = cJSON_GetObjectItem(root, "isMissionTarget")->valueint;
}
static void save(cJSON *root)
{
MIA *m;
m = (MIA*)self;
cJSON_AddStringToObject(root, "type", "MIA");
cJSON_AddNumberToObject(root, "isMissionTarget", m->isMissionTarget);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,14 +21,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
#include "../../json/cJSON.h"
extern Sprite *getSprite(char *name);
extern void addMIATeleportStars(float x, float y);
extern void addTeleportStars(Entity *e);
extern void setGameplayMessage(int type, char *format, ...);
extern void playSound(int snd, int ch);
extern void updateObjective(char *targetName);
extern Sprite *getSprite(char *name);
extern void initEntity(Entity *e);
extern void playSound(int snd, int ch);
extern void setGameplayMessage(int type, char *format, ...);
extern void updateObjective(char *targetName);
extern App app;
extern Entity *self;
extern Game game;
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,11 +33,13 @@ static int exitMission;
Entity *initTeeka(void)
{
Unit *u;
u = createUnit();
u->unitType = "Teeka";
u->type = ET_TEEKA;
u->flags |= EF_IMMUNE;
u->action = lookForEnemies;
@ -49,13 +51,15 @@ Entity *initTeeka(void)
u->sprite[FACING_DIE] = getSprite("TeekaLeft");
u->health = u->healthMax = 9999;
superTick = u->tick;
u->tick = tick;
exitMission = 0;
aimedSprite = getSprite("AimedShot");
return (Entity*)u;
}
@ -83,13 +87,13 @@ static void lookForEnemies(void)
Entity *e;
float distance, range;
Unit *u;
u = (Unit*)self;
u->thinkTime = rrnd(FPS / 2, FPS);
target = NULL;
distance = 800;
for (e = world.entityHead.next ; e != NULL ; e = e->next)
@ -119,7 +123,7 @@ static void lookForEnemies(void)
{
addTeleportStars(self);
u->alive = ALIVE_DEAD;
playSound(SND_APPEAR, CH_ANY);
playBattleSound(SND_APPEAR, u->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
}
else
{
@ -130,9 +134,9 @@ static void lookForEnemies(void)
static void preFire(void)
{
Unit *u;
u = (Unit*)self;
if (u->reload > 0)
{
return;
@ -145,11 +149,10 @@ static void preFire(void)
attack();
u->shotsToFire--;
if (u->shotsToFire == 0)
if (--u->shotsToFire <= 0)
{
u->thinkTime = FPS;
u->action = lookForEnemies;
}
}
@ -157,12 +160,10 @@ static void attack(void)
{
Bullet *bullet;
float dx, dy;
getSlope(target->x, target->y, self->x, self->y, &dx, &dy);
bullet = createBaseBullet((Unit*)self);
bullet->x = self->x;
bullet->y = (self->y + self->h / 2) - 3;
bullet = createBaseBullet((Unit*)self, aimedSprite->w);
bullet->facing = self->facing;
bullet->damage = 1;
bullet->owner = self;
@ -175,7 +176,7 @@ static void attack(void)
((Unit*)self)->reload = 8;
playSound(SND_PISTOL, CH_WEAPON);
playBattleSound(SND_PISTOL, self->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
void teekaExitMission(void)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,15 +20,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern Unit *createUnit(void);
extern Sprite *getSprite(char *name);
extern int rrnd(int low, int high);
extern Bullet *createBaseBullet(Unit *owner);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern int getDistance(int x1, int y1, int x2, int y2);
extern int hasLineOfSight(Entity *src, Entity *dest);
extern void addTeleportStars(Entity *e);
extern void playSound(int snd, int ch);
extern Bullet *createBaseBullet(Unit *owner, int bulletWidth);
extern Unit *createUnit(void);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern Sprite *getSprite(char *name);
extern int hasLineOfSight(Entity *src, Entity *dest);
extern void playBattleSound(int snd, int ch, int x, int y);
extern int rrnd(int low, int high);
extern Entity *self;
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,19 +20,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "blaze.h"
void initBlaze(Entity *e)
Entity *initBlaze(void)
{
Boss *b;
b = (Boss*)e;
initBlobBoss(b);
b = initBlobBoss();
b->weakAgainst = ENV_WATER;
STRNCPY(b->name, "Blaze", MAX_NAME_LENGTH);
b->sprite[FACING_LEFT] = getSprite("BlazeLeft");
b->sprite[FACING_RIGHT] = getSprite("BlazeRight");
b->sprite[FACING_DIE] = getSprite("BlazeSpin");
return (Entity*)b;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,5 +20,5 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBlobBoss(Boss *b);
extern Sprite *getSprite(char *name);
extern Boss *initBlobBoss(void);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,23 +37,22 @@ static void (*superAnimate)(void);
static Sprite *aimedSprite;
void initBlobBoss(Entity *e)
Boss *initBlobBoss(void)
{
Boss *b;
initBoss(e);
b = (Boss*)e;
b = initBoss();
b->flags |= EF_HALT_AT_EDGE;
b->health = b->healthMax = 250;
b->teleportTimer = FPS * rrnd(4, 6);
superAnimate = b->animate;
b->activate = activate;
b->action = walk;
b->walk = walk;
b->tick = tick;
b->changeEnvironment = changeEnvironment;
@ -61,8 +60,10 @@ void initBlobBoss(Entity *e)
b->animate = animate;
b->applyDamage = applyDamage;
b->die = die1;
aimedSprite = getSprite("AimedShot");
return b;
}
static void activate(int activate)
@ -75,16 +76,16 @@ static void activate(int activate)
if (!isPlayingMusic())
{
playMusic("", 1);
playMusic(1);
}
}
static void tick(void)
{
Boss *b;
b = (Boss*)self;
if (b->health > 0)
{
b->stunTimer = MAX(b->stunTimer - 1, 0);
@ -94,6 +95,11 @@ static void tick(void)
b->health -= 2;
world.boss = b;
if (b->stunTimer == 0)
{
teleport();
}
}
if (b->stunTimer == 0)
@ -119,9 +125,9 @@ static void tick(void)
static void changeEnvironment()
{
Boss *b;
b = (Boss*)self;
if (b->environment == b->weakAgainst)
{
b->teleportTimer = 0;
@ -137,9 +143,9 @@ static void changeEnvironment()
static void die1(void)
{
Boss *b;
b = (Boss*)self;
b->flags |= EF_BOUNCES;
b->thinkTime = 0;
@ -159,42 +165,52 @@ static void die1(void)
switch (rand() % 3)
{
case 0:
playSound(SND_DEATH_1, CH_DEATH);
playBattleSound(SND_DEATH_1, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
break;
case 1:
playSound(SND_DEATH_2, CH_DEATH);
playBattleSound(SND_DEATH_2, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
break;
case 2:
playSound(SND_DEATH_3, CH_DEATH);
playBattleSound(SND_DEATH_3, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
break;
}
b->action = die2;
}
static SDL_Rect *getCurrentSprite(void)
{
Boss *b;
Sprite *s;
b = (Boss*)self;
if (b->stunTimer > 0 || b->health <= 0)
s = (b->stunTimer > 0 || b->health <= 0) ? b->sprite[FACING_DIE] : b->sprite[b->facing];
if (self->spriteFrame >= s->numFrames)
{
return &b->sprite[FACING_DIE]->frames[self->spriteFrame]->rect;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "WARNING: %s (%d) bad sprite frames - %d > %d\n", self->name, self->type, self->spriteFrame, s->numFrames);
self->spriteFrame = 0;
}
return &b->sprite[b->facing]->frames[self->spriteFrame]->rect;
return &s->frames[self->spriteFrame]->rect;
}
static void animate(void)
{
Boss *b;
b = (Boss*)self;
if (b->dx != 0 || b->health <= 0 || b->stunTimer > 0)
if (b->alive != ALIVE_ALIVE || b->stunTimer > 0)
{
b->facing = FACING_DIE;
superAnimate();
}
else if (b->dx != 0)
{
superAnimate();
}
@ -203,9 +219,9 @@ static void animate(void)
static void lookForPlayer(void)
{
Boss *b;
b = (Boss*)self;
b->thinkTime = rrnd(0, FPS / 2);
if (getDistance(world.bob->x, world.bob->y, b->x, b->y) > 650)
@ -232,9 +248,9 @@ static void lookForPlayer(void)
static void moveTowardsPlayer(void)
{
Boss *b;
b = (Boss*)self;
b->dx = 0;
if (rand() % 100 < 20)
@ -255,7 +271,7 @@ static void moveTowardsPlayer(void)
}
}
if (b->stunTimer == 0 && b->teleportTimer == 0)
if (rand() % 10 == 0 && b->stunTimer == 0 && b->teleportTimer == 0)
{
teleport();
@ -266,9 +282,9 @@ static void moveTowardsPlayer(void)
static void preFire(void)
{
Boss *b;
b = (Boss*)self;
if (b->reload > 0)
{
return;
@ -289,27 +305,28 @@ static void attack(void)
Bullet *bullet;
float dx, dy;
int bx, by;
bx = (int) (world.bob->x + rrnd(-8, 24));
by = (int) (world.bob->y + rrnd(-8, 24));
getSlope(bx, by, self->x, self->y, &dx, &dy);
if (self->facing != FACING_DIE)
{
bx = (int) (world.bob->x + rrnd(-8, 24));
by = (int) (world.bob->y + rrnd(-8, 24));
bullet = createBaseBullet((Unit*)self);
bullet->x = self->x;
bullet->y = (self->y + self->h / 2) - 3;
bullet->facing = self->facing;
bullet->damage = 1;
bullet->owner = self;
bullet->health = FPS * 3;
bullet->weaponType = WPN_AIMED_PISTOL;
bullet->dx = dx * 12;
bullet->dy = dy * 12;
bullet->sprite[0] = bullet->sprite[1] = aimedSprite;
getSlope(bx, by, self->x, self->y, &dx, &dy);
((Boss*)self)->reload = 4;
bullet = createBaseBullet((Unit*)self, aimedSprite->w);
bullet->facing = self->facing;
bullet->damage = 1;
bullet->owner = self;
bullet->health = FPS * 3;
bullet->weaponType = WPN_AIMED_PISTOL;
bullet->dx = dx * 12;
bullet->dy = dy * 12;
bullet->sprite[0] = bullet->sprite[1] = aimedSprite;
playSound(SND_MACHINE_GUN, CH_WEAPON);
((Boss*)self)->reload = 4;
playBattleSound(SND_MACHINE_GUN, self->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
}
static void walk(void)
@ -320,9 +337,9 @@ static void walk(void)
void reappear(void)
{
int valid, r;
valid = 0;
do
{
r = (int) (rand() % MAX_CHECKPOINTS);
@ -331,16 +348,16 @@ void reappear(void)
valid = (self->x != 0 && self->y != 0);
}
while (!valid);
self->y -= (self->h + 10);
walk();
self->flags &= ~EF_GONE;
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
playBattleSound(SND_APPEAR, -1, self->x, self->y);
}
static void applyDamage(int amount)
@ -359,28 +376,32 @@ static void applyDamage(int amount)
static void teleport(void)
{
self->action = reappear;
self->flags |= EF_GONE;
self->thinkTime = FPS * rrnd(3, 6);
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
if (self->health > 0)
{
self->action = reappear;
self->flags |= EF_GONE;
self->thinkTime = FPS * rrnd(3, 6);
addTeleportStars(self);
playBattleSound(SND_APPEAR, -1, self->x, self->y);
}
}
static void die2(void)
{
Boss *b;
b = (Boss*)self;
b->health--;
if (b->health <= -FPS)
{
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
playBattleSound(SND_APPEAR, -1, self->x, self->y);
b->alive = ALIVE_DEAD;
/* don't die! */
b->flags |= EF_GONE;
updateObjective(b->name);
@ -392,5 +413,7 @@ static void die2(void)
{
awardTrophy("BLAZE_FROST");
}
b->action = entityIdle;
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,21 +20,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBoss(Entity *e);
extern int rrnd(int low, int high);
extern void addTeleportStars(Entity *e);
extern void playMusic(char *filename, int loop);
extern int isPlayingMusic(void);
extern float limit(float i, float a, float b);
extern double randF(void);
extern void playSound(int snd, int ch);
extern Bullet *createBaseBullet(Unit *owner);
extern Sprite *getSprite(char *name);
extern void awardTrophy(char *id);
extern Bullet *createBaseBullet(Unit *owner, int bulletWidth);
extern int enemyCanSeePlayer(Entity *e);
extern void entityIdle(void);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern int enemyCanSeePlayer(Entity *e);
extern Sprite *getSprite(char *name);
extern Boss *initBoss(void);
extern int isPlayingMusic(void);
extern float limit(float i, float a, float b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void playMusic(int loop);
extern double randF(void);
extern int rrnd(int low, int high);
extern void updateObjective(char *targetName);
extern void awardTrophy(char *id);
extern Entity *self;
extern Game game;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,23 +20,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "boss.h"
static void lookForPlayer(void);
static void load(cJSON *root);
static void save(cJSON *root);
static void init(void);
void initBoss(Entity *e)
Boss *initBoss(void)
{
Boss *b;
initEntity(e);
b = (Boss*)e;
b->type = ET_BOSS;
b->sprite[FACING_LEFT] = b->sprite[FACING_RIGHT] = b->sprite[FACING_DIE] = getSprite("Boss");
b->isMissionTarget = 1;
b->action = lookForPlayer;
b = malloc(sizeof(Boss));
memset(b, 0, sizeof(Boss));
initEntity((Entity*)b);
b->type = ET_BOSS;
b->sprite[FACING_LEFT] = b->sprite[FACING_RIGHT] = b->sprite[FACING_DIE] = getSprite("Boss");
b->isMissionTarget = 1;
b->spriteFrame = 0;
b->spriteTime = 0;
@ -44,8 +45,22 @@ void initBoss(Entity *e)
world.boss = b;
b->flags |= EF_ALWAYS_PROCESS | EF_BOMB_SHIELD | EF_GONE;
b->init = init;
b->load = load;
b->save = save;
return b;
}
static void lookForPlayer(void)
static void init(void)
{
}
static void load(cJSON *root)
{
}
static void save(cJSON *root)
{
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initEntity(Entity *e);
extern Sprite *getSprite(char *name);
extern void initEntity(Entity *e);
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,8 +23,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void activate(int activate);
static void tick(void);
static void walk(void);
static void moveTowardsPlayer(void);
static void die1(void);
static void moveTowardsPlayer(int dir);
static void die(void);
static void die2(void);
static void selectWeapon(void);
static void attackPistol(void);
@ -40,39 +40,41 @@ static Sprite *aimedSprite;
static Sprite *missileSprite[2];
static Sprite *plasmaSprite[2];
void initEyeDroidCommander(Entity *e)
Entity *initEyeDroidCommander(void)
{
Boss *b;
initBoss(e);
b = (Boss*)e;
b = initBoss();
STRNCPY(b->name, "EyeDroid Commander", MAX_NAME_LENGTH);
b->sprite[FACING_LEFT] = getSprite("DroidCommanderLeft");
b->sprite[FACING_RIGHT] = getSprite("DroidCommanderRight");
b->sprite[FACING_DIE] = getSprite("DroidCommanderDie");
b->flags |= EF_WEIGHTLESS | EF_EXPLODES;
b->health = b->healthMax = 250;
b->action = walk;
b->walk = walk;
b->tick = tick;
b->activate = activate;
b->applyDamage = applyDamage;
b->die = die;
b->getCurrentSprite = getCurrentSprite;
brakingTimer = 0;
aimedSprite = getSprite("AimedShot");
missileSprite[0] = getSprite("MissileRight");
missileSprite[1] = getSprite("MissileLeft");
plasmaSprite[0] = getSprite("PlasmaRight");
plasmaSprite[1] = getSprite("PlasmaLeft");
return (Entity*)b;
}
static void activate(int activate)
@ -83,15 +85,15 @@ static void activate(int activate)
addTeleportStars(self);
playMusic("", 1);
playMusic(1);
}
static void tick(void)
{
Boss *b;
b = (Boss*)self;
if (b->health > 0)
{
b->facing = (world.bob->x < b->x) ? FACING_LEFT : FACING_RIGHT;
@ -108,12 +110,14 @@ static void tick(void)
}
else
{
addSmokeParticles(b->x + (b->w / 2), b->y);
addSmokeParticles(b->x + (b->w / 2), b->y, 0);
}
}
static void lookForPlayer(void)
{
float distance;
self->thinkTime = rrnd(0, FPS / 2);
if (rand() % 100 < 5)
@ -121,15 +125,17 @@ static void lookForPlayer(void)
brakingTimer = rrnd(60, 120);
}
if (getDistance(world.bob->x, world.bob->y, self->x, self->y) > 650)
distance = getDistance(world.bob->x, world.bob->y, self->x, self->y);
if (distance > app.config.winHeight)
{
moveTowardsPlayer();
moveTowardsPlayer(1);
return;
}
if (enemyCanSeePlayer(self))
if (!enemyCanSeePlayer(self))
{
moveTowardsPlayer();
moveTowardsPlayer(1);
return;
}
@ -138,16 +144,23 @@ static void lookForPlayer(void)
selectWeapon();
}
moveTowardsPlayer();
if (distance < app.config.winHeight / 4)
{
moveTowardsPlayer(-6);
}
else
{
moveTowardsPlayer(1);
}
}
static void selectWeapon(void)
{
Boss *b;
b = (Boss*)self;
if (world.bob->isOnGround || abs(self->y - world.bob->y) > 64)
if (world.bob->isOnGround || fabs(self->y - world.bob->y) > 64)
{
b->weaponType = WPN_AIMED_PISTOL;
b->shotsToFire = rrnd(1, 12);
@ -169,31 +182,35 @@ static void selectWeapon(void)
static void walk(void)
{
self->action = (self->health > 0) ? lookForPlayer : die1;
self->action = (self->health > 0) ? lookForPlayer : die;
}
static void moveTowardsPlayer(void)
static void moveTowardsPlayer(int dir)
{
float vel;
vel = 0.5 * dir;
if (brakingTimer == 0)
{
if (world.bob->x < self->x)
{
self->dx -= 0.5;
self->dx -= vel;
}
if (world.bob->x > self->x)
{
self->dx += 0.5;
self->dx += vel;
}
if (world.bob->y < self->y)
{
self->dy -= 0.5;
self->dy -= vel;
}
if (world.bob->y > self->y)
{
self->dy += 0.5;
self->dy += vel;
}
self->dx = limit(self->dx, -7.5, 7.5);
@ -204,9 +221,9 @@ static void moveTowardsPlayer(void)
static void preFire(void)
{
Boss *b;
b = (Boss*)self;
if (b->reload > 0)
{
return;
@ -225,22 +242,25 @@ static void preFire(void)
static void attack(void)
{
Boss *b;
b = (Boss*)self;
switch (b->weaponType)
if (self->facing != FACING_DIE)
{
case WPN_AIMED_PISTOL:
attackPistol();
break;
case WPN_MISSILE:
attackMissile();
break;
case WPN_PLASMA:
attackPlasma();
break;
default:
break;
b = (Boss*)self;
switch (b->weaponType)
{
case WPN_AIMED_PISTOL:
attackPistol();
break;
case WPN_MISSILE:
attackMissile();
break;
case WPN_PLASMA:
attackPlasma();
break;
default:
break;
}
}
}
@ -250,17 +270,15 @@ static void attackPistol(void)
float dx, dy;
Bullet *bullet;
Boss *b;
b = (Boss*)self;
bx = world.bob->x + rrnd(-8, 24);
by = world.bob->y + rrnd(-8, 24);
getSlope(bx, by, self->x, self->y, &dx, &dy);
bullet = createBaseBullet((Unit*)self);
bullet->x = (self->x + self->w / 2);
bullet->y = (self->y + self->h / 2) - 3;
bullet = createBaseBullet((Unit*)self, aimedSprite->w);
bullet->facing = self->facing;
bullet->damage = 1;
bullet->owner = self;
@ -272,19 +290,17 @@ static void attackPistol(void)
b->reload = 4;
playSound(SND_MACHINE_GUN, CH_WEAPON);
playBattleSound(SND_MACHINE_GUN, b->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
static void attackPlasma(void)
{
Boss *b;
Bullet *bullet;
b = (Boss*)self;
bullet = createBaseBullet((Unit*)self);
bullet->x = (self->x + self->w / 2);
bullet->y = (self->y + self->h / 2) - 3;
bullet = createBaseBullet((Unit*)self, plasmaSprite[0]->w);
bullet->facing = self->facing;
bullet->damage = 2;
bullet->owner = self;
@ -297,19 +313,17 @@ static void attackPlasma(void)
b->reload = 4;
playSound(SND_PLASMA, CH_WEAPON);
playBattleSound(SND_PLASMA, b->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
static void attackMissile(void)
{
Boss *b;
Bullet *missile;
b = (Boss*)self;
missile = createBaseBullet((Unit*)self);
missile->x = b->x + b->w / 2;
missile->y = b->y + b->h / 2;
missile = createBaseBullet((Unit*)self, missileSprite[0]->w);
missile->facing = b->facing;
missile->dx = b->facing == FACING_RIGHT ? 15 : -15;
missile->owner = self;
@ -317,9 +331,11 @@ static void attackMissile(void)
missile->sprite[0] = missileSprite[0];
missile->sprite[1] = missileSprite[1];
initMissile(missile);
b->reload = 15;
playSound(SND_MISSILE, CH_WEAPON);
playBattleSound(SND_MISSILE, b->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
static void applyDamage(int amount)
@ -333,12 +349,12 @@ static void applyDamage(int amount)
}
}
static void die1(void)
static void die(void)
{
Boss *b;
b = (Boss*)self;
b->dx = (randF() - randF()) * 3;
b->spriteTime = 0;
@ -352,27 +368,28 @@ static void die1(void)
if (rand() % 2)
{
playSound(SND_DROID_DIE_1, CH_DEATH);
playBattleSound(SND_DROID_DIE_1, b->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
else
{
playSound(SND_DROID_DIE_2, CH_DEATH);
playBattleSound(SND_DROID_DIE_2, b->uniqueId % MAX_SND_CHANNELS, self->x, self->y);
}
}
static void die2()
{
Boss *b;
b = (Boss*)self;
if (b->isOnGround)
{
addTeleportStars(self);
playSound(SND_APPEAR, CH_ANY);
playBattleSound(SND_APPEAR, -1, self->x, self->y);
b->alive = ALIVE_DEAD;
/* don't die! */
b->flags |= EF_GONE;
updateObjective(b->name);
@ -381,15 +398,22 @@ static void die2()
awardTrophy("EYEDROID_COMMANDER");
game.stats[STAT_ENEMIES_KILLED]++;
b->action = entityIdle;
}
}
static SDL_Rect *getCurrentSprite(void)
{
if (self->health <= 0)
Sprite *s;
s = (self->alive == ALIVE_ALIVE) ? self->sprite[self->facing] : self->sprite[FACING_DIE];
if (self->spriteFrame >= s->numFrames)
{
return &self->sprite[FACING_DIE]->frames[self->spriteFrame]->rect;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "WARNING: %s (%d) bad sprite frames - %d > %d\n", self->name, self->type, self->spriteFrame, s->numFrames);
self->spriteFrame = 0;
}
return &self->sprite[self->facing]->frames[self->spriteFrame]->rect;
return &s->frames[self->spriteFrame]->rect;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,23 +20,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBoss(Entity *e);
extern Sprite *getSprite(char *name);
extern void playMusic(char *filename, int loop);
extern void addTeleportStars(Entity *e);
extern float limit(float i, float a, float b);
extern void addSmokeParticles(float x, float y);
extern int rrnd(int low, int high);
extern int getDistance(int x1, int y1, int x2, int y2);
extern int enemyCanSeePlayer(Entity *e);
extern void updateObjective(char *targetName);
extern double randF(void);
extern void playSound(int snd, int ch);
extern Bullet *createBaseBullet(Unit *owner);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern void addExplosion(float x, float y, int radius, Entity *owner);
extern void addSmokeParticles(float x, float y, int rising);
extern void addTeleportStars(Entity *e);
extern void awardTrophy(char *id);
extern Bullet *createBaseBullet(Unit *owner, int bulletWidth);
extern int enemyCanSeePlayer(Entity *e);
extern void entityIdle(void);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern Sprite *getSprite(char *name);
extern Boss *initBoss(void);
extern void initMissile(Bullet *b);
extern float limit(float i, float a, float b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void playMusic(int loop);
extern double randF(void);
extern int rrnd(int low, int high);
extern void updateObjective(char *targetName);
extern App app;
extern Entity *self;
extern Game game;
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,19 +20,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "frost.h"
void initFrost(Entity *e)
Entity *initFrost(void)
{
Boss *b;
initBlobBoss(e);
b = (Boss*)e;
b = initBlobBoss();
b->weakAgainst = ENV_LAVA;
STRNCPY(b->name, "Frost", MAX_NAME_LENGTH);
b->sprite[FACING_LEFT] = getSprite("FrostLeft");
b->sprite[FACING_RIGHT] = getSprite("FrostRight");
b->sprite[FACING_DIE] = getSprite("FrostSpin");
return (Entity*)b;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,5 +20,5 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBlobBoss(Entity *e);
extern Sprite *getSprite(char *name);
extern Boss *initBlobBoss(void);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -32,21 +32,20 @@ static void applyDamage(int amount);
static void preFire(void);
static void selectWeapon(void);
static void moveTowardsPlayer(void);
static void getCollisionBounds(SDL_Rect *r);
static Entity *tankTrack;
static int brakingTimer;
static Sprite *missileSprite[2];
static Sprite *aimedSprite;
void initTankCommander(Entity *e)
Entity *initTankCommander(void)
{
Boss *b;
initBoss(e);
b = (Boss*)e;
STRNCPY(e->name, "Tank Commander", MAX_NAME_LENGTH);
b = initBoss();
STRNCPY(b->name, "Tank Commander", MAX_NAME_LENGTH);
b->sprite[FACING_LEFT] = getSprite("TankCommanderLeft");
b->sprite[FACING_RIGHT] = getSprite("TankCommanderRight");
@ -54,32 +53,36 @@ void initTankCommander(Entity *e)
b->flags |= EF_EXPLODES;
b->health = e->healthMax = 400;
b->health = b->healthMax = 400;
b->activate = activate;
b->action = walk;
b->walk = walk;
b->tick = tick;
b->die = die1;
b->applyDamage = applyDamage;
b->getCollisionBounds = getCollisionBounds;
brakingTimer = 0;
world.boss = b;
aimedSprite = getSprite("AimedShot");
missileSprite[0] = getSprite("MissileRight");
missileSprite[1] = getSprite("MissileLeft");
initTankTrack(tankTrack);
tankTrack = initTankTrack(b);
world.boss = b;
return (Entity*)b;
}
static void activate(int activate)
{
Boss *b;
b = (Boss*)self;
b->flags &= ~EF_GONE;
tankTrack->flags &= ~EF_GONE;
@ -88,15 +91,15 @@ static void activate(int activate)
addTeleportStars(self);
addTeleportStars(tankTrack);
playMusic("", 1);
playMusic(1);
}
static void tick(void)
{
Boss *b;
b = (Boss*)self;
if (b->health > 0)
{
b->facing = (world.bob->x < b->x) ? FACING_LEFT : FACING_RIGHT;
@ -116,9 +119,9 @@ static void tick(void)
static void lookForPlayer(void)
{
Boss *b;
b = (Boss*)self;
b->thinkTime = rrnd(0, FPS / 2);
if (rand() % 10 == 0)
@ -138,7 +141,7 @@ static void lookForPlayer(void)
return;
}
if (rand() % 100 <15)
if (rand() % 100 < 35)
{
selectWeapon();
}
@ -172,10 +175,10 @@ static void moveTowardsPlayer(void)
static void selectWeapon(void)
{
Boss *b;
b = (Boss*)self;
if (abs(b->y - world.bob->y) > 64)
if (fabs(b->y - world.bob->y) > 64)
{
b->weaponType = WPN_AIMED_PISTOL;
b->shotsToFire = rrnd(4, 12);
@ -192,9 +195,9 @@ static void selectWeapon(void)
static void preFire(void)
{
Boss *b;
b = (Boss*)self;
if (b->reload > 0)
{
moveTowardsPlayer();
@ -214,19 +217,22 @@ static void preFire(void)
static void attack(void)
{
Boss *b;
b = (Boss*)self;
switch (b->weaponType)
if (self->facing != FACING_DIE)
{
case WPN_AIMED_PISTOL:
attackPistol();
break;
case WPN_MISSILE:
attackMissile();
break;
default:
break;
b = (Boss*)self;
switch (b->weaponType)
{
case WPN_AIMED_PISTOL:
attackPistol();
break;
case WPN_MISSILE:
attackMissile();
break;
default:
break;
}
}
}
@ -236,15 +242,15 @@ static void attackPistol(void)
float dx, dy;
Bullet *bullet;
Boss *b;
b = (Boss*)self;
bx = world.bob->x + rrnd(-8, 24);
by = world.bob->y + rrnd(-8, 24);
getSlope(bx, by, b->x, b->y, &dx, &dy);
bullet = createBaseBullet((Unit*)self);
bullet = createBaseBullet((Unit*)self, aimedSprite->w);
bullet->x = (b->x + b->w / 2);
bullet->y = b->y + 30;
bullet->facing = b->facing;
@ -258,17 +264,17 @@ static void attackPistol(void)
b->reload = 4;
playSound(SND_MACHINE_GUN, CH_WEAPON);
playBattleSound(SND_MACHINE_GUN, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
static void attackMissile(void)
{
Bullet *missile;
Boss *b;
b = (Boss*)self;
missile = createBaseBullet((Unit*)self);
missile = createBaseBullet((Unit*)self, missileSprite[0]->w);
missile->x = b->x + b->w / 2;
missile->y = b->y + 30;
missile->facing = b->facing;
@ -282,15 +288,17 @@ static void attackMissile(void)
b->reload = 15;
playSound(SND_MISSILE, CH_WEAPON);
initMissile(missile);
playBattleSound(SND_MISSILE, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
static void die1(void)
{
Boss *b;
b = (Boss*)self;
b->flags |= EF_BOUNCES;
b->action = die2;
@ -304,7 +312,7 @@ static void die2(void)
{
int mx, my;
Boss *b;
b = (Boss*)self;
b->health--;
@ -313,7 +321,7 @@ static void die2(void)
{
mx = (int) ((b->x + (b->w / 2)) / MAP_TILE_SIZE);
my = (int) ((b->y + b->h) / MAP_TILE_SIZE);
addScorchDecal(mx, my);
addExplosion(b->x + rand() % b->w, b->y + rand() % b->h, 50, self);
@ -324,9 +332,11 @@ static void die2(void)
addTeleportStars(self);
addTeleportStars(tankTrack);
playSound(SND_APPEAR, CH_ANY);
playBattleSound(SND_APPEAR, -1, self->x, self->y);
b->alive = tankTrack->alive = ALIVE_DEAD;
/* don't die! */
b->flags |= EF_GONE;
tankTrack->alive |= EF_GONE;
updateObjective(b->name);
@ -335,6 +345,8 @@ static void die2(void)
awardTrophy("TANK_COMMANDER");
game.stats[STAT_ENEMIES_KILLED]++;
b->action = entityIdle;
}
}
@ -348,3 +360,11 @@ static void applyDamage(int amount)
addExplosion(self->x + self->w / 2, self->y + self->h / 2, 50, self);
}
}
static void getCollisionBounds(SDL_Rect *r)
{
r->x = self->facing == FACING_LEFT ? self->x + 98 : self->x;
r->y = self->y;
r->w = 140;
r->h = 66;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,22 +20,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBoss(Entity *e);
extern Sprite *getSprite(char *name);
extern void playMusic(char *filename, int loop);
extern void addTeleportStars(Entity *e);
extern float limit(float i, float a, float b);
extern int rrnd(int low, int high);
extern int getDistance(int x1, int y1, int x2, int y2);
extern int enemyCanSeePlayer(Entity *e);
extern void updateObjective(char *targetName);
extern void playSound(int snd, int ch);
extern Bullet *createBaseBullet(Unit *owner);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern void addExplosion(float x, float y, int radius, Entity *owner);
extern void addScorchDecal(int x, int y);
extern void initTankTrack(Entity *e);
extern void addTeleportStars(Entity *e);
extern void awardTrophy(char *id);
extern Bullet *createBaseBullet(Unit *owner, int bulletWidth);
extern int enemyCanSeePlayer(Entity *e);
extern void entityIdle(void);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy);
extern Sprite *getSprite(char *name);
extern Boss *initBoss(void);
extern void initMissile(Bullet *b);
extern Entity *initTankTrack(Boss *owner);
extern float limit(float i, float a, float b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void playMusic(int loop);
extern int rrnd(int low, int high);
extern void updateObjective(char *targetName);
extern Entity *self;
extern Game game;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,31 +20,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tankTrack.h"
static Entity *tankCommander;
static Boss *tankCommander;
static void tick(void);
static void touch(Entity *other);
static void animate(void);
static void (*superAnimate)(void);
static void applyDamage(int amount);
static void getCollisionBounds(SDL_Rect *r);
void initTankTrack(Entity *e, Entity *tank)
Entity *initTankTrack(Boss *owner)
{
initBoss(e);
Boss *b;
superAnimate = e->animate;
b = initBoss();
e->flags |= EF_EXPLODES | EF_NO_CLIP | EF_WEIGHTLESS | EF_IMMUNE;
superAnimate = b->animate;
e->isMissionTarget = 0;
b->flags |= EF_EXPLODES | EF_NO_CLIP | EF_WEIGHTLESS | EF_IMMUNE;
e->sprite[FACING_LEFT] = getSprite("TankTrackLeft");
e->sprite[FACING_RIGHT] = getSprite("TankTrackRight");
e->sprite[FACING_DIE] = getSprite("TankTrackLeft");
b->isMissionTarget = 0;
e->tick = tick;
e->touch = touch;
e->animate = animate;
b->sprite[FACING_LEFT] = getSprite("TankTrackLeft");
b->sprite[FACING_RIGHT] = getSprite("TankTrackRight");
b->sprite[FACING_DIE] = getSprite("TankTrackLeft");
tankCommander = tank;
b->tick = tick;
b->touch = touch;
b->animate = animate;
b->applyDamage = applyDamage;
b->getCollisionBounds = getCollisionBounds;
tankCommander = owner;
return (Entity*)b;
}
static void tick(void)
@ -72,7 +80,7 @@ static void touch(Entity *other)
{
if (other == (Entity*)world.bob && !world.bob->stunTimer && (world.bob->flags & EF_IMMUNE) == 0)
{
playSound(SND_FLESH_HIT, CH_ANY);
playSound(SND_FLESH_HIT, world.bob->uniqueId % MAX_SND_CHANNELS);
world.bob->dx = rrnd(-5, 5);
world.bob->dy = JUMP_POWER;
world.bob->applyDamage(3);
@ -86,6 +94,11 @@ static void touch(Entity *other)
}
}
static void applyDamage(int amount)
{
/* immune to all damage */
}
static void animate(void)
{
if (tankCommander->dx != 0)
@ -93,3 +106,11 @@ static void animate(void)
superAnimate();
}
}
static void getCollisionBounds(SDL_Rect *r)
{
r->x = self->x + 16;
r->y = self->y;
r->w = self->w - 32;
r->h = self->h;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,10 +20,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initBoss(Entity *e);
extern Sprite *getSprite(char *name);
extern int rrnd(int low, int high);
extern Boss *initBoss(void);
extern void playSound(int snd, int ch);
extern int rrnd(int low, int high);
extern Entity *self;
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,16 +23,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void tick(void);
static void touch(Entity *other);
Bullet *createBaseBullet(Unit *owner)
Bullet *createBaseBullet(Unit *owner, int bulletWidth)
{
Bullet *bullet;
bullet = malloc(sizeof(Bullet));
memset(bullet, 0, sizeof(Bullet));
initEntity((Entity*)bullet);
bullet->x = (owner->x + owner->w / 2);
bullet->x = owner->x + (owner->w / 2) - (bulletWidth / 2);
bullet->y = (owner->y + owner->h / 2) - 3;
bullet->dx = owner->facing == FACING_RIGHT ? 15 : -15;
bullet->facing = owner->facing;
@ -43,7 +43,7 @@ Bullet *createBaseBullet(Unit *owner)
bullet->tick = tick;
bullet->touch = touch;
bullet->spriteFrame = 0;
return bullet;
@ -65,7 +65,7 @@ static void tick(void)
/* don't allow the player to kill everything on the map by firing constantly */
if (b->owner->type == ET_BOB)
{
if (b->x < camera.x || b->y < camera.y || b->x > camera.x + SCREEN_WIDTH || b->y > camera.y + SCREEN_HEIGHT)
if (b->x < camera.x || b->y < camera.y || b->x > camera.x + app.config.winWidth || b->y > camera.y + app.config.winHeight)
{
b->alive = ALIVE_DEAD;
}
@ -75,6 +75,7 @@ static void tick(void)
static void touch(Entity *other)
{
Bullet *b;
int canHit;
b = (Bullet*)self;
@ -88,37 +89,47 @@ static void touch(Entity *other)
if (rand() % 2)
{
playSound(SND_RICO_1, CH_ANY);
playBattleSound(SND_RICO_1, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
else
{
playSound(SND_RICO_2, CH_ANY);
playBattleSound(SND_RICO_2, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
}
else if (other != b->owner && (!(other->flags & EF_IGNORE_BULLETS)) && b->owner->type != other->type)
else
{
swapSelf(other);
other->applyDamage(b->damage);
swapSelf(other);
canHit = (
other != b->owner &&
(!(other->flags & EF_IGNORE_BULLETS)) &&
b->owner->type != other->type &&
!((b->owner->type == ET_TEEKA && other->type == ET_BOB) || (b->owner->type == ET_BOB && other->type == ET_TEEKA))
);
if (other->flags & EF_EXPLODES)
if (canHit)
{
playSound(SND_METAL_HIT, CH_ANY);
swapSelf(other);
other->applyDamage(b->damage);
swapSelf(other);
addSparkParticles(b->x, b->y);
}
else
{
playSound(SND_FLESH_HIT, CH_ANY);
if (other->flags & EF_EXPLODES)
{
playBattleSound(SND_METAL_HIT, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
addSmallFleshChunk(b->x, b->y);
}
addSparkParticles(b->x, b->y);
}
else
{
playBattleSound(SND_FLESH_HIT, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
b->alive = ALIVE_DEAD;
addSmallFleshChunk(b->x, b->y);
}
if (b->owner->type == world.bob->type && (other->type == ET_ENEMY || other->type == ET_BOSS || other->type == ET_DESTRUCTABLE))
{
game.stats[STAT_SHOTS_HIT]++;
b->alive = ALIVE_DEAD;
if (b->owner->type == world.bob->type && (other->type == ET_ENEMY || other->type == ET_BOSS || other->type == ET_DESTRUCTABLE))
{
game.stats[STAT_SHOTS_HIT]++;
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,13 +20,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void playSound(int snd, int ch);
extern void initEntity(Entity *e);
extern void addSmallFleshChunk(float x, float y);
extern void addSparkParticles(float x, float y);
extern Bullet *createBaseBullet(Unit *owner);
extern void initEntity(Entity *e);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void swapSelf(Entity *e);
extern App app;
extern Camera camera;
extern Entity *self;
extern Game game;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -30,7 +30,7 @@ static void explode(void);
void initGrenade(Bullet *b)
{
b->flags = EF_BOUNCES | EF_IGNORE_BULLETS | EF_KILL_OFFSCREEN | EF_FRICTIONLESS | EF_NO_TELEPORT;
superBounce = b->bounce;
b->tick = tick;
@ -106,7 +106,7 @@ static float bounce(float x)
if (b->environment == ENV_AIR)
{
playSound(SND_GRENADE_BOUNCE, CH_EFFECTS);
playBattleSound(SND_GRENADE_BOUNCE, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
return superBounce(x);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,12 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void playSound(int snd, int ch);
extern void initGrenade(Bullet *b);
extern void addSmallFleshChunk(float x, float y);
extern void addSparkParticles(float x, float y);
extern void addExplosion(float x, float y, int radius, Entity *owner);
extern void addScorchDecal(int x, int y);
extern void addSmallFleshChunk(float x, float y);
extern void addSparkParticles(float x, float y);
extern void initGrenade(Bullet *b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern void swapSelf(Entity *e);
extern Entity *self;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,41 +48,48 @@ static void tick(void)
static void touch(Entity *other)
{
Bullet *b;
int canHit;
b = (Bullet*)self;
if (b->alive == ALIVE_ALIVE)
{
if (other != b->owner)
canHit = (
other != NULL &&
other != b->owner &&
(!(other->flags & EF_IGNORE_BULLETS)) &&
b->owner->type != other->type &&
!((b->owner->type == ET_TEEKA && other->type == ET_BOB) || (b->owner->type == ET_BOB && other->type == ET_TEEKA))
);
if (canHit)
{
if (other != NULL && (!(other->flags & EF_IGNORE_BULLETS)) && b->owner->type != other->type)
if (other->flags & EF_EXPLODES)
{
if (other->flags & EF_EXPLODES)
{
addSparkParticles(b->x, b->y);
playSound(SND_METAL_HIT, CH_ANY);
}
else
{
addSmallFleshChunk(b->x, b->y);
playSound(SND_FLESH_HIT, CH_ANY);
}
addSparkParticles(b->x, b->y);
playBattleSound(SND_METAL_HIT, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
else
{
addSmallFleshChunk(b->x, b->y);
playBattleSound(SND_FLESH_HIT, b->uniqueId % MAX_SND_CHANNELS, b->x, b->y);
}
swapSelf(other);
other->applyDamage(2);
swapSelf(other);
swapSelf(other);
other->applyDamage(2);
swapSelf(other);
if (b->owner->type == world.bob->type && (other->type == ET_ENEMY || other->type == ET_BOSS || other->type == ET_DESTRUCTABLE))
{
game.stats[STAT_SHOTS_HIT]++;
}
if (!(b->flags & EF_BULLET_HIT) && b->owner->type == world.bob->type && (other->type == ET_ENEMY || other->type == ET_BOSS || other->type == ET_DESTRUCTABLE))
{
b->flags |= EF_BULLET_HIT;
game.stats[STAT_SHOTS_HIT]++;
}
if (other->type == ET_BOB && world.bob->stunTimer == 0)
{
other->dx = rrnd(-8, 8);
other->dy = rrnd(-12, 0);
stunBob();
}
if (other->type == ET_BOB && world.bob->stunTimer == 0)
{
other->dx = rrnd(-8, 8);
other->dy = rrnd(-12, 0);
stunBob();
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,11 +20,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void playSound(int snd, int ch);
extern int rrnd(int low, int high);
extern void initLaser(Bullet *b);
extern void addSmallFleshChunk(float x, float y);
extern void addSparkParticles(float x, float y);
extern void initLaser(Bullet *b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern int rrnd(int low, int high);
extern void stunBob(void);
extern void swapSelf(Entity *e);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -46,7 +46,7 @@ static void tick(void)
if (b->health % 2)
{
addFlameParticles(b->x + (b->facing * b->w) + rrnd(-2, 2), b->y + (b->h / 2));
addFlameParticles(b->x + (b->facing * b->w) + rrnd(-2, 2), b->y + (b->h / 2), 0);
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,9 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern int rrnd(int low, int high);
extern void initMissile(Bullet *b);
extern void addExplosion(float x, float y, int radius, Entity *owner);
extern void addFlameParticles(float x, float y);
extern void addFlameParticles(float x, float y, int rising);
extern void initMissile(Bullet *b);
extern int rrnd(int low, int high);
extern Entity *self;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,15 +27,16 @@ static void die2(void);
static void animate(void);
static int canFire(Entity *target);
static void preFire(void);
static void getCollisionBounds(SDL_Rect *r);
Entity *initCannon(void)
{
Unit *u;
u = createUnit();
u->unitType = "Cannon";
u->type = ET_ENEMY;
u->sprite[FACING_LEFT] = getSprite("CannonLeft");
@ -60,7 +61,8 @@ Entity *initCannon(void)
u->walk = walk;
u->die = die;
u->canFire = canFire;
u->getCollisionBounds = getCollisionBounds;
return (Entity*)u;
}
@ -85,7 +87,7 @@ static void die(void)
u->flags |= EF_BOUNCES | EF_ALWAYS_PROCESS;
u->action = die2;
u->facing = FACING_DIE;
u->thinkTime = 0;
u->spriteTime = 0;
@ -105,7 +107,7 @@ static void die2(void)
{
Unit *u;
int mx, my;
u = (Unit*)self;
if (--u->health % 3 == 0)
@ -115,9 +117,11 @@ static void die2(void)
addScorchDecal(mx, my);
addExplosion(u->x, u->y, 50, self);
throwDebris(u->x + u->w / 2, u->y + u->h / 2, 1);
}
if (u->health <= -50)
if (u->alive == ALIVE_DYING && u->health <= -50)
{
updateObjective(u->name);
updateObjective("ENEMY");
@ -126,6 +130,8 @@ static void die2(void)
dropCarriedItem();
u->alive = ALIVE_DEAD;
addRandomWeapon(u->x, u->y);
}
}
@ -140,7 +146,7 @@ static void lookForPlayer(void)
{
Unit *u;
int r;
u = (Unit*)self;
u->thinkTime = rrnd(FPS / 2, FPS);
@ -186,9 +192,9 @@ static void lookForPlayer(void)
static void preFire(void)
{
Unit *u;
u = (Unit*)self;
u->facing = (world.bob->x < u->x) ? FACING_LEFT : FACING_RIGHT;
if (u->reload > 0)
@ -214,7 +220,15 @@ static void animate(void)
}
static void getCollisionBounds(SDL_Rect *r)
{
r->x = self->x + 36;
r->y = self->y;
r->w = 36;
r->h = self->h;
}
static int canFire(Entity *target)
{
return abs(target->y - self->y) <= MAP_TILE_SIZE;
return fabs(target->y - self->y) <= MAP_TILE_SIZE;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,16 +21,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void addExplosion(float x, float y, int radius, Entity *owner);
extern int rrnd(int low, int high);
extern Sprite *getSprite(char *name);
extern int getDistance(int x1, int y1, int x2, int y2);
extern int enemyCanSeePlayer(Entity *e);
extern void updateObjective(char *targetName);
extern void fireTriggers(char *targetName);
extern void dropCarriedItem(void);
extern void addRandomWeapon(int x, int y);
extern void addScorchDecal(int x, int y);
extern Unit *createUnit(void);
extern void dropCarriedItem(void);
extern int enemyCanSeePlayer(Entity *e);
extern void fireTriggers(char *targetName);
extern int getDistance(int x1, int y1, int x2, int y2);
extern Sprite *getSprite(char *name);
extern double randF(void);
extern int rrnd(int low, int high);
extern void throwDebris(float x, float y, int amount);
extern void updateObjective(char *targetName);
extern Dev dev;
extern Entity *self;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,22 +23,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void tick(void);
static void action(void);
static void touch(Entity *other);
static void changeEnvironment(void);
void initDebris(Decoration *d)
{
initEntity((Entity*)d);
d->type = ET_DECORATION;
d->effectType = rand() % 2;
d->spriteFrame = 0;
d->flags |= EF_BOUNCES | EF_IGNORE_BULLETS | EF_KILL_OFFSCREEN | EF_NO_TELEPORT;
d->flags |= EF_BOUNCES | EF_IGNORE_BULLETS | EF_KILL_OFFSCREEN | EF_NO_TELEPORT | EF_CRUSHABLE;
d->tick = tick;
d->action = action;
d->touch = touch;
d->changeEnvironment = changeEnvironment;
}
static void tick(void)
@ -49,16 +51,16 @@ static void tick(void)
static void action(void)
{
Decoration *d;
d = (Decoration*)self;
if (d->effectType == 0)
{
addFlameParticles(d->x + (rand() % d->w), d->y + (rand() % d->h));
addFlameParticles(d->x + (rand() % d->w), d->y + (rand() % d->h), d->isOnGround);
}
else
{
addSmokeParticles(d->x + (rand() % d->w), d->y + (rand() % d->h));
addSmokeParticles(d->x + (rand() % d->w), d->y + (rand() % d->h), d->isOnGround);
}
self->thinkTime = 1;
@ -67,11 +69,26 @@ static void action(void)
static void touch(Entity *other)
{
Decoration *d;
d = (Decoration*)self;
if (other == NULL)
{
d->dx *= 0.9;
}
}
static void changeEnvironment(void)
{
switch (self->environment)
{
case ENV_LAVA:
case ENV_SLIME:
case ENV_WATER:
self->alive = ALIVE_DEAD;
break;
default:
break;
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,8 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void addFlameParticles(float x, float y, int rising);
extern void addSmokeParticles(float x, float y, int rising);
extern void initEntity(Entity *e);
extern void addFlameParticles(float x, float y);
extern void addSmokeParticles(float x, float y);
extern Entity *self;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,12 +27,17 @@ static void touch(Entity *other);
void initFleshChunk(Decoration *d)
{
initEntity((Entity*)d);
d->type = ET_DECORATION;
d->flags |= EF_BOUNCES | EF_IGNORE_BULLETS | EF_KILL_OFFSCREEN | EF_NO_TELEPORT;
d->flags |= EF_BOUNCES | EF_IGNORE_BULLETS | EF_NO_TELEPORT | EF_CRUSHABLE;
d->bleedTime = FPS * 3;
if (app.config.blood != 2)
{
d->flags |= EF_KILL_OFFSCREEN;
}
d->bleedTime = (app.config.blood != 2) ? FPS * 3 : FPS * 15;
d->spriteFrame = 0;
@ -44,19 +49,20 @@ void initFleshChunk(Decoration *d)
static void tick(void)
{
Decoration *d;
d = (Decoration*)self;
d->health--;
d->bleedTime--;
}
static void action(void)
{
Decoration *d;
d = (Decoration*)self;
if (d->bleedTime > 0)
{
addBlood(d->x + (rand() % d->w), d->y + (rand() % d->h));
@ -67,8 +73,17 @@ static void action(void)
static void touch(Entity *other)
{
int mx, my;
if (other == NULL)
{
self->dx *= 0.9;
if (app.config.blood == 2)
{
mx = (int) ((self->x + (self->w / 2)) / MAP_TILE_SIZE);
my = (int) (self->y / MAP_TILE_SIZE) + 1;
addBloodDecal(mx, my);
}
}
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,7 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void initEntity(Entity *e);
extern void addBlood(float x, float y);
extern void addBloodDecal(int x, int y);
extern void initEntity(Entity *e);
extern App app;
extern Entity *self;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,14 +31,15 @@ static void activate(int active);
static void touch(Entity *other);
static void animate(void);
static void changeEnvironment(void);
static SDL_Rect *getCurrentSprite(void);
static void getCollisionBounds(SDL_Rect *r);
static void load(cJSON *root);
static void save(cJSON *root);
static SDL_Rect *getCurrentSprite(void);
void initEntity(Entity *e)
{
e->uniqueId = world.entityCounter++;
e->environment = ENV_AIR;
e->alive = ALIVE_ALIVE;
@ -54,10 +55,10 @@ void initEntity(Entity *e)
e->flags = 0;
e->thinkTime = 0;
e->spriteFrame = -1;
e->spriteTime = 0;
e->init = init;
e->reset = reset;
e->action = action;
@ -70,10 +71,11 @@ void initEntity(Entity *e)
e->getCurrentSprite = getCurrentSprite;
e->die = die;
e->changeEnvironment = changeEnvironment;
e->getCollisionBounds = getCollisionBounds;
e->load = load;
e->save = save;
world.entityTail->next = e;
world.entityTail = e;
}
@ -95,9 +97,9 @@ static void action(void)
static void animate(void)
{
Sprite *s;
s = self->sprite[self->facing];
if (self->spriteTime != -1)
{
if (--self->spriteTime <= 0)
@ -106,7 +108,7 @@ static void animate(void)
{
self->spriteFrame = 0;
}
self->spriteTime = self->sprite[self->facing]->times[self->spriteFrame];
}
}
@ -160,9 +162,31 @@ static void changeEnvironment(void)
{
}
void entityIdle(void)
{
}
static SDL_Rect *getCurrentSprite(void)
{
return &self->sprite[self->facing]->frames[self->spriteFrame]->rect;
Sprite *s;
s = self->sprite[self->facing];
if (self->spriteFrame >= s->numFrames)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "WARNING: %s (%d) bad sprite frames - %d > %d\n", self->name, self->type, self->spriteFrame, s->numFrames);
self->spriteFrame = 0;
}
return &s->frames[self->spriteFrame]->rect;
}
static void getCollisionBounds(SDL_Rect *r)
{
r->x = self->x;
r->y = self->y;
r->w = self->w;
r->h = self->h;
}
static void load(cJSON *root)

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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) 2018 Parallel Realities
Copyright (C) 2018-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 initEntityFactory(void)
{
memset(&head, 0, sizeof(EntityDef));
tail = &head;
addEntityDef("AquaBlob", initAquaBlob);
addEntityDef("PistolBlob", initPistolBlob);
addEntityDef("PistolEyeDroid", initPistolDroid);
@ -50,11 +50,15 @@ void initEntityFactory(void)
addEntityDef("PlasmaEyeDroid", initPlasmaDroid);
addEntityDef("PlasmaBlob", initPlasmaBlob);
addEntityDef("Cannon", initCannon);
addEntityDef("Blaze", initBlaze);
addEntityDef("Frost", initFrost);
addEntityDef("EyeDroidCommander", initEyeDroidCommander);
addEntityDef("TankCommander", initTankCommander);
addEntityDef("Bob", initBob);
addEntityDef("MIA", initMIA);
addEntityDef("Teeka", initTeeka);
addEntityDef("Item", initItem);
addEntityDef("BronzeKey", initBronzeKey);
addEntityDef("SilverKey", initSilverKey);
@ -64,10 +68,11 @@ void initEntityFactory(void)
addEntityDef("RedKeycard", initRedKeycard);
addEntityDef("YellowKeycard", initYellowKeycard);
addEntityDef("WhiteKeycard", initWhiteKeycard);
addEntityDef("WeaponPickup", initWeaponPickup);
addEntityDef("Cell", initCell);
addEntityDef("Heart", initHeart);
addEntityDef("Exit", initExit);
addEntityDef("PowerPool", initPowerPool);
addEntityDef("Teleporter", initTeleporter);
@ -92,7 +97,7 @@ void initEntityFactory(void)
Entity *createEntity(char *name)
{
EntityDef *def;
for (def = head.next ; def != NULL ; def = def->next)
{
if (strcmp(def->name, name) == 0)
@ -101,22 +106,22 @@ Entity *createEntity(char *name)
return def->initFunc();
}
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "No such entity definition '%s'", name);
exit(1);
return NULL;
}
static void addEntityDef(char *name, Entity *(*initFunc)(void))
{
EntityDef *def;
def = malloc(sizeof(EntityDef));
memset(def, 0, sizeof(EntityDef));
tail->next = def;
tail = def;
STRNCPY(def->name, name, MAX_NAME_LENGTH);
def->initFunc = initFunc;
}
@ -126,11 +131,11 @@ static Entity *initGenericEvilBlob(void)
int r;
char name[MAX_NAME_LENGTH];
strcpy(name, "");
r = rand() % world.numEnemyTypes;
sprintf(name, "%sBlob", world.enemyTypes[r]);
return createEntity(name);
}
@ -139,10 +144,10 @@ static Entity *initGenericEyeDroid(void)
int r;
char name[MAX_NAME_LENGTH];
strcpy(name, "");
r = rand() % world.numEnemyTypes;
sprintf(name, "%sEyeDroid", world.enemyTypes[r]);
return createEntity(name);
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,52 +21,57 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h"
extern Entity *initAquaBlob(void);
extern Entity *initBlaze(void);
extern Entity *initBlueKeycard(void);
extern Entity *initBob(void);
extern Entity *initBronzeDoor(void);
extern Entity *initBronzeKey(void);
extern Entity *initCannon(void);
extern Entity *initCardReader(void);
extern Entity *initCell(void);
extern Entity *initDestructable(void);
extern Entity *initDoor(void);
extern Entity *initExit(void);
extern Entity *initEyeDroidCommander(void);
extern Entity *initFrost(void);
extern Entity *initGoldDoor(void);
extern Entity *initGoldKey(void);
extern Entity *initGreenKeycard(void);
extern Entity *initGrenadeBlob(void);
extern Entity *initGrenadeDroid(void);
extern Entity *initHeart(void);
extern Entity *initHorizontalDoor(void);
extern Entity *initHorizontalLaserTrap(void);
extern Entity *initInfoPoint(void);
extern Entity *initItem(void);
extern Entity *initItemPad(void);
extern Entity *initLaserBlob(void);
extern Entity *initLaserDroid(void);
extern Entity *initLaserTrap(void);
extern Entity *initLift(void);
extern Entity *initMIA(void);
extern Entity *initMachineGunBlob(void);
extern Entity *initMachineGunDroid(void);
extern Entity *initPistolBlob(void);
extern Entity *initPistolDroid(void);
extern Entity *initGrenadeDroid(void);
extern Entity *initGrenadeBlob(void);
extern Entity *initShotgunDroid(void);
extern Entity *initShotgunBlob(void);
extern Entity *initBob(void);
extern Entity *initExit(void);
extern Entity *initPowerPool(void);
extern Entity *initTeleporter(void);
extern Entity *initPressurePlate(void);
extern Entity *initInfoPoint(void);
extern Entity *initPlasmaBlob(void);
extern Entity *initPlasmaDroid(void);
extern Entity *initPowerPoint(void);
extern Entity *initPowerPool(void);
extern Entity *initPressurePlate(void);
extern Entity *initPushBlock(void);
extern Entity *initLift(void);
extern Entity *initDoor(void);
extern Entity *initBronzeDoor(void);
extern Entity *initSilverDoor(void);
extern Entity *initGoldDoor(void);
extern Entity *initHorizontalDoor(void);
extern Entity *initMIA(void);
extern Entity *initItem(void);
extern Entity *initBronzeKey(void);
extern Entity *initSilverKey(void);
extern Entity *initGoldKey(void);
extern Entity *initCell(void);
extern Entity *initHeart(void);
extern Entity *initGreenKeycard(void);
extern Entity *initCardReader(void);
extern Entity *initBlueKeycard(void);
extern Entity *initRedKeycard(void);
extern Entity *initYellowKeycard(void);
extern Entity *initWhiteKeycard(void);
extern Entity *initLaserTrap(void);
extern Entity *initHorizontalLaserTrap(void);
extern Entity *initMachineGunDroid(void);
extern Entity *initLaserDroid(void);
extern Entity *initLaserBlob(void);
extern Entity *initShotgunBlob(void);
extern Entity *initShotgunDroid(void);
extern Entity *initSilverDoor(void);
extern Entity *initSilverKey(void);
extern Entity *initSpreadGunBlob(void);
extern Entity *initSpreadGunDroid(void);
extern Entity *initPlasmaDroid(void);
extern Entity *initPlasmaBlob(void);
extern Entity *initTankCommander(void);
extern Entity *initTeeka(void);
extern Entity *initDestructable(void);
extern Entity *initCannon(void);
extern Entity *initItemPad(void);
extern Entity *initTeleporter(void);
extern Entity *initWeaponPickup(void);
extern Entity *initWhiteKeycard(void);
extern Entity *initYellowKeycard(void);
extern World world;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,9 +25,9 @@ static int canFire(Entity *target);
Entity *initAquaBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "AquaBlob";
u->sprite[FACING_LEFT] = getSprite("AquaBlobLeft");
@ -41,7 +41,7 @@ Entity *initAquaBlob(void)
u->maxShotsToFire = 3;
u->canFire = canFire;
return (Entity*)u;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -22,4 +22,3 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern Unit *createEvilBlob(void);
extern Sprite *getSprite(char *name);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -30,7 +30,7 @@ static void animate(void);
Unit *createEvilBlob(void)
{
Unit *u;
u = createUnit();
u->reload = 0;
@ -38,7 +38,7 @@ Unit *createEvilBlob(void)
u->returnToStartTimer = 0;
u->flags |= EF_HALT_AT_EDGE;
superAnimate = u->animate;
u->action = lookForPlayer;
@ -64,15 +64,22 @@ static void die2(void)
u->health = -FPS;
}
if (u->health <= -FPS && (u->isOnGround || u->environment != ENV_AIR))
if (u->alive == ALIVE_DYING && u->health <= -FPS && (u->isOnGround || u->environment != ENV_AIR))
{
dropCarriedItem();
u->alive = ALIVE_DEAD;
throwFleshChunks(u->x + u->w / 2, u->y + u->h / 2, rrnd(3, 6));
if (app.config.blood)
{
throwFleshChunks(u->x + u->w / 2, u->y + u->h / 2, rrnd(3, 6));
}
else
{
addPopParticles(u->x + u->w / 2, u->y + u->h / 2);
}
if (rand() % 10 < 3)
if (rand() % 100 < 35)
{
addRandomWeapon(u->x, u->y);
}
@ -94,7 +101,14 @@ static void die2(void)
my = (int) (u->y / MAP_TILE_SIZE) + 1;
addBloodDecal(mx, my);
playSound(SND_SPLAT, CH_ANY);
if (app.config.blood)
{
playBattleSound(SND_SPLAT, world.bob->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
}
else
{
playBattleSound(SND_POP, world.bob->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
}
}
}
@ -197,7 +211,7 @@ static void returnToStart(void)
u->dy = u->startY < u->y ? -1 : -1;
}
if (abs(u->startX - u->x) <= MAP_TILE_SIZE)
if (fabs(u->startX - u->x) <= MAP_TILE_SIZE)
{
u->returnToStartTimer = 0;
}
@ -235,26 +249,26 @@ static void lookForPlayer(void)
patrol();
return;
}
r = randF();
if (world.missionType == MT_OUTPOST)
if (world.missionType == MT_OUTPOST || game.plus)
{
r = randF() * 0.65;
}
if (u->isMissionTarget)
{
r = randF() * 0.3;
}
if (r < 0.065)
if (r < 0.1)
{
moveTowardsPlayer();
u->shotsToFire = rrnd(1, u->maxShotsToFire);
u->action = u->preFire;
}
else if (r < 0.12)
else if (r < 0.2)
{
u->dx = 0;
u->shotsToFire = rrnd(1, u->maxShotsToFire);
@ -277,9 +291,10 @@ static void die(void)
u = (Unit*)self;
u->flags |= EF_BOUNCES | EF_ALWAYS_PROCESS;
u->flags &= ~(EF_HALT_AT_EDGE | EF_GONE);
u->action = die2;
u->facing = FACING_DIE;
u->thinkTime = 0;
u->spriteTime = 0;
@ -292,27 +307,34 @@ static void die(void)
u->dx = (randF() - randF()) * 5;
u->flags &= ~EF_HALT_AT_EDGE;
switch (rand() % 3)
if (app.config.blood)
{
case 0:
playSound(SND_DEATH_1, CH_DEATH);
break;
switch (rand() % 3)
{
case 0:
playBattleSound(SND_DEATH_1, u->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
break;
case 1:
playSound(SND_DEATH_2, CH_DEATH);
break;
case 1:
playBattleSound(SND_DEATH_2, u->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
break;
case 2:
playSound(SND_DEATH_3, CH_DEATH);
break;
case 2:
playBattleSound(SND_DEATH_3, u->uniqueId % MAX_SND_CHANNELS, u->x, u->y);
break;
}
}
}
static void animate(void)
{
if (self->dx != 0 || self->health <= 0)
if (self->alive != ALIVE_ALIVE)
{
self->facing = FACING_DIE;
superAnimate();
}
else if (self->dx != 0)
{
superAnimate();
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -20,21 +20,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern void dropCarriedItem(void);
extern int getDistance(int x1, int y1, int x2, int y2);
extern double randF(void);
extern void throwFleshChunks(float x, float y, int amount);
extern void addRandomWeapon(float x, float y);
extern float limit(float i, float a, float b);
extern void playSound(int snd, int ch);
extern void addBloodDecal(int x, int y);
extern void updateObjective(char *targetName);
extern void addPopParticles(float x, float y);
extern void addRandomItems(int x, int y);
extern void addRandomWeapon(int x, int y);
extern Unit *createUnit(void);
extern void dropCarriedItem(void);
extern int enemyCanSeePlayer(Entity *e);
extern void fireTriggers(char *name);
extern void addRandomItems(float x, float y);
extern int getDistance(int x1, int y1, int x2, int y2);
extern float limit(float i, float a, float b);
extern void playBattleSound(int snd, int ch, int x, int y);
extern double randF(void);
extern int rrnd(int low, int high);
extern Unit *createUnit(void);
extern void throwFleshChunks(float x, float y, int amount);
extern void updateObjective(char *targetName);
extern App app;
extern Dev dev;
extern Entity *self;
extern Game game;

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,18 +27,18 @@ static int canFire(Entity *target);
Entity *initGrenadeBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "GrenadeBlob";
u->sprite[FACING_LEFT] = getSprite("GrenadeBlobLeft");
u->sprite[FACING_RIGHT] = getSprite("GrenadeBlobRight");
u->sprite[FACING_DIE] = getSprite("GrenadeBlobSpin");
u->weaponType = WPN_GRENADES;
u->maxShotsToFire = 1;
superPreFire = u->preFire;
u->preFire = preFire;
@ -50,9 +50,9 @@ Entity *initGrenadeBlob(void)
static void preFire(void)
{
Unit *u;
u = (Unit*)self;
superPreFire();
if (u->shotsToFire == 0)
@ -72,5 +72,5 @@ static void preFire(void)
static int canFire(Entity *target)
{
return abs(target->y - self->y) <= MAP_TILE_SIZE * 2;
return fabs(target->y - self->y) <= MAP_TILE_SIZE * 2;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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) 2018 Parallel Realities
Copyright (C) 2018-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,11 +25,11 @@ static int canFire(Entity *target);
Entity *initLaserBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "LaserBlob";
u->sprite[FACING_LEFT] = getSprite("LaserBlobLeft");
u->sprite[FACING_RIGHT] = getSprite("LaserBlobRight");
u->sprite[FACING_DIE] = getSprite("LaserBlobSpin");
@ -39,11 +39,11 @@ Entity *initLaserBlob(void)
u->maxShotsToFire = 1;
u->canFire = canFire;
return (Entity*)u;
}
static int canFire(Entity *target)
{
return abs(target->y - self->y) <= MAP_TILE_SIZE * 2;
return fabs(target->y - self->y) <= MAP_TILE_SIZE * 2;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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) 2018 Parallel Realities
Copyright (C) 2018-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,11 +25,11 @@ static int canFire(Entity *target);
Entity *initMachineGunBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "MachineGunBlob";
u->sprite[FACING_LEFT] = getSprite("MachineGunBlobLeft");
u->sprite[FACING_RIGHT] = getSprite("MachineGunBlobRight");
u->sprite[FACING_DIE] = getSprite("MachineGunBlobSpin");
@ -39,11 +39,11 @@ Entity *initMachineGunBlob(void)
u->maxShotsToFire = 5;
u->canFire = canFire;
return (Entity*)u;
}
static int canFire(Entity *target)
{
return abs(target->y - self->y) <= MAP_TILE_SIZE * 2;
return fabs(target->y - self->y) <= MAP_TILE_SIZE * 2;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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) 2018 Parallel Realities
Copyright (C) 2018-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,11 +25,11 @@ static int canFire(Entity *target);
Entity *initPistolBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "PistolBlob";
u->sprite[FACING_LEFT] = getSprite("PistolBlobLeft");
u->sprite[FACING_RIGHT] = getSprite("PistolBlobRight");
u->sprite[FACING_DIE] = getSprite("PistolBlobSpin");
@ -39,7 +39,7 @@ Entity *initPistolBlob(void)
u->maxShotsToFire = 3;
u->canFire = canFire;
return (Entity*)u;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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
@ -22,4 +22,3 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern Unit *createEvilBlob(void);
extern Sprite *getSprite(char *name);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2018 Parallel Realities
Copyright (C) 2018-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,11 +25,11 @@ static int canFire(Entity *target);
Entity *initPlasmaBlob(void)
{
Unit *u;
u = createEvilBlob();
u->unitType = "PlasmaBlob";
u->sprite[FACING_LEFT] = getSprite("PlasmaBlobLeft");
u->sprite[FACING_RIGHT] = getSprite("PlasmaBlobRight");
u->sprite[FACING_DIE] = getSprite("PlasmaBlobSpin");
@ -39,11 +39,11 @@ Entity *initPlasmaBlob(void)
u->maxShotsToFire = 6;
u->canFire = canFire;
return (Entity*)u;
}
static int canFire(Entity *target)
{
return abs(target->y - self->y) <= MAP_TILE_SIZE * 2;
return fabs(target->y - self->y) <= MAP_TILE_SIZE * 2;
}

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