diff --git a/common.mk b/common.mk index 9ba374c..b1cceb2 100644 --- a/common.mk +++ b/common.mk @@ -2,7 +2,7 @@ VERSION = 0.1 REVISION = $(shell git rev-list HEAD 2>/dev/null | wc -l) LOCALE_MO = $(patsubst %.po,%.mo,$(wildcard locale/*.po)) -SEARCHPATH += src src/combat src/game src/system src/util src/widgets src/world +SEARCHPATH += src src/combat src/game src/hub src/system src/util src/widgets src/world vpath %.c $(SEARCHPATH) vpath %.h $(SEARCHPATH) @@ -12,7 +12,7 @@ OBJS += camera.o combat.o OBJS += draw.o OBJS += effects.o entities.o explosions.o OBJS += game.o -OBJS += hud.o +OBJS += hub.o hud.o OBJS += init.o input.o io.o items.o OBJS += lookup.o OBJS += main.o map.o maths.o diff --git a/src/defs.h b/src/defs.h index ec73322..ea563dc 100644 --- a/src/defs.h +++ b/src/defs.h @@ -56,7 +56,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_LINE_LENGTH 1024 #define MAX_FILENAME_LENGTH 1024 -#define NUM_TEXTURE_BUCKETS 32 +#define NUM_TEXTURE_BUCKETS 32 #define MAP_WIDTH 200 #define MAP_HEIGHT 200 @@ -75,6 +75,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAP_TILE_MAX 256 #define JUMP_POWER 1 +#define MAX_KEY_TYPES 12 #define ET_ENEMY 0 #define ET_KEY 1 @@ -136,8 +137,10 @@ enum enum { - MS_PARTIAL, - MS_MISSING_HEART_CELL + MS_INCOMPLETE, + MS_PARTIAL, + MS_MISSING_HEART_CELL, + MS_COMPLETE }; enum diff --git a/src/game/game.c b/src/game/game.c index c888d61..9a9bc60 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -20,6 +20,59 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "game.h" +/* +public Map missionStatuses; + +public List mias; +public List targets; +public Map keys; +*/ + +void initGame(void) +{ + memset(&game, 0, sizeof(Game)); + + game.cells = 5; + game.hearts = 10; + + game.timePlayed = 0; +} + +/* +public void updateTimePlayedString() +{ + final int hours = (int) TimeUnit.MILLISECONDS.toHours(timePlayed); + final int minutes = (int) TimeUnit.MILLISECONDS.toMinutes(timePlayed) % 60; + + timePlayedString = String.format("%dh %02dm", hours, minutes); +} + +public int getShotPercentage(int i) +{ + return BMath.getPercentage(statShotsHit[i], statShotsFired[i]); +} + +public void addKey(String key) +{ + AtomicInteger i = keys.get(key); + if (i == null) + { + i = new AtomicInteger(); + keys.put(key, i); + } + i.incrementAndGet(); +} + +public void removeKey(String key) +{ + AtomicInteger i = keys.get(key); + if (i != null && i.decrementAndGet() == 0) + { + keys.remove(key); + } +} +*/ + void destroyGame(void) { } diff --git a/src/game/game.h b/src/game/game.h index 8ad0dc9..bcaab26 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -19,3 +19,5 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "../common.h" + +extern Game game; diff --git a/src/hub/hub.c b/src/hub/hub.c new file mode 100644 index 0000000..4762d6f --- /dev/null +++ b/src/hub/hub.c @@ -0,0 +1,256 @@ +/* +Copyright (C) 2018 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "hub.h" + +static void unlockAllLevels(void); +static void unlockMission(char *id); +static int getMissionStatus(char *id); +static void loadMissions(void); +static void unlockNeighbouringMission(HubMission *sourceMission); +static int missionComparator(const void *a, const void *b); + +static HubMission hubMissionHead; +static HubMission *hubMissionTail; + +void initHub(void) +{ + int unlockedMissions; + HubMission *prevMission, *mission; + Tuple *t; + + memset(&hubMissionHead, 0, sizeof(HubMission)); + + hubMissionTail = &hubMissionHead; + + loadMissions(); + + if (dev.cheatLevels) + { + unlockAllLevels(); + } + + unlockedMissions = 0; + + for (t = game.missionStatusHead.next ; t != NULL ; t = t->next) + { + if (t->value.i != MS_INCOMPLETE) + { + unlockedMissions++; + } + } + + prevMission = &hubMissionHead; + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + if (mission->unlockCount > unlockedMissions && !dev.cheatLevels) + { + if (mission == hubMissionTail) + { + hubMissionTail = prevMission; + } + + prevMission->next = mission->next; + free(mission); + mission = prevMission; + } + else + { + mission->status = getMissionStatus(mission->id); + + if (mission->unlockCount == 0 && mission->status == -1) + { + mission->status = MS_INCOMPLETE; + unlockMission(mission->id); + } + } + + prevMission = mission; + } + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + if (mission->status == MS_COMPLETE || mission->status == MS_MISSING_HEART_CELL || mission->status == MS_PARTIAL) + { + unlockNeighbouringMission(mission); + } + + if (mission->status == MS_MISSING_HEART_CELL) + { + STRNCPY(mission->description, "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.", MAX_DESCRIPTION_LENGTH); + } + } + + prevMission = &hubMissionHead; + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + if (mission->status == -1 || mission->status == MS_COMPLETE) + { + if (mission == hubMissionTail) + { + hubMissionTail = prevMission; + } + + prevMission->next = mission->next; + free(mission); + mission = prevMission; + } + + prevMission = mission; + } +} + +static int getMissionStatus(char *id) +{ + Tuple *t; + + for (t = game.missionStatusHead.next ; t != NULL ; t = t->next) + { + if (strcmp(t->key, id) == 0) + { + return t->value.i; + } + } + + return -1; +} + +static void unlockMission(char *id) +{ + Tuple *t; + + for (t = game.missionStatusHead.next ; t != NULL ; t = t->next) + { + if (strcmp(t->key, id) == 0) + { + if (t->value.i == -1) + { + t->value.i = MS_INCOMPLETE; + } + return; + } + } + + t = malloc(sizeof(Tuple)); + memset(t, 0, sizeof(Tuple)); + game.missionStatusTail->next = t; + game.missionStatusTail = t; + + STRNCPY(t->key, id, MAX_NAME_LENGTH); + t->value.i = MS_INCOMPLETE; +} + +static void unlockAllLevels(void) +{ + HubMission *mission; + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + if (mission->status == -1 || mission->status == MS_INCOMPLETE) + { + mission->status = MS_INCOMPLETE; + unlockMission(mission->id); + } + } +} + +static void loadMissions(void) +{ +} + +static void unlockNeighbouringMission(HubMission *sourceMission) +{ + HubMission *mission, *missions[32]; + int i; + + i = 0; + memset(missions, 0, sizeof(HubMission*) * 32); + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + mission->distance = 99999; + + if (mission->status == MS_COMPLETE || mission->status == MS_MISSING_HEART_CELL || mission->status == MS_PARTIAL) + { + continue; + } + + mission->distance = getDistance(mission->x, mission->y, sourceMission->x, sourceMission->y); + + missions[i++] = mission; + } + + qsort(missions, i, sizeof(HubMission*), missionComparator); + + mission = missions[0]; + + if (mission != NULL) + { + if (mission->status == -1 || mission->status == MS_INCOMPLETE) + { + mission->status = MS_INCOMPLETE; + unlockMission(mission->id); + } + + mission = missions[1]; + + if (mission != NULL) + { + if (mission->status == -1 || mission->status == MS_INCOMPLETE) + { + mission->status = MS_INCOMPLETE; + unlockMission(mission->id); + } + } + } +} + +HubMission *getMissionAt(float x, float y) +{ + HubMission *rtn; + HubMission *mission; + float distance, dist; + + rtn = NULL; + distance = 32; + + for (mission = hubMissionHead.next ; mission != NULL ; mission = mission->next) + { + dist = getDistance(x, y, mission->x, mission->y); + + if (dist < distance) + { + rtn = mission; + distance = dist; + } + } + + return rtn; +} + +static int missionComparator(const void *a, const void *b) +{ + HubMission *m1 = *((HubMission**)a); + HubMission *m2 = *((HubMission**)b); + + return m2->distance - m1->distance; +} diff --git a/src/hub/hub.h b/src/hub/hub.h new file mode 100644 index 0000000..156c06a --- /dev/null +++ b/src/hub/hub.h @@ -0,0 +1,27 @@ +/* +Copyright (C) 2018 Parallel Realities + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "../common.h" + +extern int getDistance(int x1, int y1, int x2, int y2); + +extern Dev dev; +extern Game game; +extern World world; diff --git a/src/structs.h b/src/structs.h index 6736ac1..a865ff6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -27,17 +27,21 @@ typedef struct Trigger Trigger; typedef struct Marker Marker; typedef struct Particle Particle; typedef struct Sprite Sprite; +typedef struct Tuple Tuple; +typedef struct HubMission HubMission; typedef struct { int debug; int takeScreenshots; char *screenshotFolder; - int noAIWeapons; int showFPS; - int playerImmortal; - int playerUnlimitedMissiles; - int noEntityActions; - int allImmortal; + int cheatHealth; + int cheatPower; + int cheatOxygen; + int cheatKeys; + int cheatLevels; + int cheatReload; + int cheatBlind; int fps; } Dev; @@ -131,6 +135,28 @@ struct Trigger { Trigger *next; }; +struct HubMission { + char id[MAX_NAME_LENGTH]; + char name[MAX_NAME_LENGTH]; + char description[MAX_DESCRIPTION_LENGTH]; + float x; + float y; + int status; + int unlockCount; + float distance; + HubMission *next; +}; + +struct Tuple { + char key[MAX_NAME_LENGTH]; + union { + char s[MAX_NAME_LENGTH]; + int i; + float f; + } value; + Tuple *next; +}; + typedef struct { SDL_Rect bounds; float shakeAmount; @@ -172,7 +198,33 @@ typedef struct { } App; typedef struct { + int sound; + int music; +} Config; + +typedef struct { + int cells; + int hearts; + int keysFound; + int totalMIAs; + int totalTargets; + int totalCells; + int totalHearts; + int totalKeys; + int deaths; + int statShotsFired[WPN_ANY]; + int statShotsHit[WPN_ANY]; + int enemiesKilled; + int missionsPlayed; long timePlayed; + char worldId[MAX_NAME_LENGTH]; + int isResumingMission; + int isComplete; + char **mias; + char **targets; + int keys[MAX_KEY_TYPES][MAX_NAME_LENGTH]; + Tuple missionStatusHead, *missionStatusTail; + Config config; } Game; struct Marker {