UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_mission.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 Original file from Quake 2 v3.21: quake2-2.31/game/g_spawn.c
10 Copyright (C) 1997-2001 Id Software, Inc.
11 
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 See the GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 
27 */
28 
29 #include "g_mission.h"
30 #include "g_actor.h"
31 #include "g_client.h"
32 #include "g_edicts.h"
33 #include "g_inventory.h"
34 #include "g_match.h"
35 #include "g_spawn.h"
36 #include "g_utils.h"
37 
38 void G_MissionAddVictoryMessage (const char* message)
39 {
40  gi.ConfigString(CS_VICTORY_CONDITIONS, "%s\n", message);
41 }
42 
43 static inline const char* G_MissionGetTeamString (const int team) {
44  return (team == TEAM_PHALANX ? "PHALANX" : (team == TEAM_ALIEN ? "The alien" : va("Team %i's", team)));
45 }
46 
53 bool G_MissionTouch (Edict* self, Edict* activator)
54 {
55  if (!G_IsLivingActor(activator))
56  return false;
57 
58  Actor* actor = makeActor(activator);
59  const char* const actorTeam = G_MissionGetTeamString(actor->getTeam());
60  if (!G_IsCivilian(actor) && self->isOpponent(actor)) {
61  if (!self->item && self->count) {
62  if (self->targetname) {
63  gi.BroadcastPrintf(PRINT_HUD, _("%s forces are attacking the %s!"), actorTeam, self->targetname);
64  } else {
65  const char* const teamName = G_MissionGetTeamString(self->getTeam());
66  gi.BroadcastPrintf(PRINT_HUD, _("%s forces are attacking %s target zone!"),
67  actorTeam, teamName);
68  }
69 
70  /* reset king of the hill counter */
71  self->count = 0;
72  }
73  return false;
74  }
75  if (self->count)
76  return false;
77 
78  if (self->isSameTeamAs(actor)) {
79  if (!self->item) {
80  linkedList_t* touched = self->touchedList;
81  while (touched) {
82  const Edict* const ent = static_cast<Edict*>(touched->data);
83  if (!self->isSameTeamAs(ent) && !G_IsCivilian(ent) && !G_IsDead(ent)) {
84  return false;
85  }
86  touched = touched->next;
87  }
88  self->count = level.actualRound;
89  if (self->targetname) {
90  gi.BroadcastPrintf(PRINT_HUD, _("%s forces have occupied the %s!"), actorTeam, self->targetname);
91  } else {
92  gi.BroadcastPrintf(PRINT_HUD, _("%s forces have occupied their target zone!"), actorTeam);
93  }
94  return true;
95  }
96  }
97 
98  /* search the item in the activator's inventory */
99  /* ignore items linked from any temp container the actor must have this in his hands */
100  const Container* cont = nullptr;
101  while ((cont = actor->chr.inv.getNextCont(cont))) {
102  Item* item = nullptr;
103  while ((item = cont->getNextItem(item))) {
104  const objDef_t* od = item->def();
105  /* check whether we found the searched item in the actor's inventory */
106  if (!Q_streq(od->id, self->item))
107  continue;
108 
109  /* drop the weapon - even if out of TUs */
110  G_ActorInvMove(actor, cont->def(), item, INVDEF(CID_FLOOR), NONE, NONE, false);
111  if (self->targetname) {
112  gi.BroadcastPrintf(PRINT_HUD, _("The %s was placed at the %s."), item->def()->name, self->targetname);
113  } else {
114  gi.BroadcastPrintf(PRINT_HUD, _("The %s was placed."), item->def()->name);
115  }
116  self->count = level.actualRound;
117  return true;
118  }
119  }
120 
121  return false;
122 }
123 
124 void G_MissionReset (Edict* self, Edict* activator)
125 {
126  /* Don't reset the mission timer for 'bring item' missions G_MissionThink will handle that */
127  if (!self->time || self->item)
128  return;
129  linkedList_t* touched = self->touchedList;
130  while (touched) {
131  const Edict* const ent = static_cast<Edict*>(touched->data);
132  if (self->isSameTeamAs(ent) && !(G_IsDead(ent) || ent == activator)) {
133  return;
134  }
135  touched = touched->next;
136  }
137  if (activator->getTeam() == self->getTeam()) {
138  const char* const actTeam = G_MissionGetTeamString(activator->getTeam());
139  if (self->targetname)
140  gi.BroadcastPrintf(PRINT_HUD, _("%s forces have left the %s!"), actTeam, self->targetname);
141  else
142  gi.BroadcastPrintf(PRINT_HUD, _("%s forces have left their target zone!"), actTeam);
143  }
144  /* All team actors are gone, reset counter */
145  self->count = 0;
146 }
147 
151 bool G_MissionUse (Edict* self, Edict* activator)
152 {
153  Edict* target = G_EdictsFindTargetEntity(self->target);
154  if (!target) {
155  gi.DPrintf("Target '%s' wasn't found for misc_mission\n", self->target);
156  G_FreeEdict(self);
157  return false;
158  }
159 
160  if (target->destroy) {
161  /* set this to zero to determine that this is a triggered destroy call */
162  target->HP = 0;
163  target->destroy(target);
164  /* freed when the level changes */
165  self->target = nullptr;
166  self->use = nullptr;
167  } else if (target->use)
168  target->use(target, activator);
169 
170  return true;
171 }
172 
173 static bool G_MissionIsTouched (Edict* self) {
174  linkedList_t* touched = self->touchedList;
175  while (touched) {
176  const Edict* const ent = static_cast<Edict*>(touched->data);
177  if (self->isSameTeamAs(ent) && !G_IsDead(ent))
178  return true;
179  touched = touched->next;
180  }
181  return false;
182 }
183 
188 void G_MissionThink (Edict* self)
189 {
190  if (!G_MatchIsRunning())
191  return;
192 
193  /* when every player has joined the match - spawn the mission target
194  * particle (if given) to mark the trigger */
195  if (self->particle) {
196  self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle);
197 
198  /* This is automatically freed on map shutdown */
199  self->particle = nullptr;
200  }
201 
202  Edict* chain = self->groupMaster;
203  if (!chain)
204  chain = self;
205  while (chain) {
206  if (chain->type == ET_MISSION) {
207  if (chain->item) {
208  const Item* ic;
209  G_GetFloorItems(chain);
210  ic = chain->getFloor();
211  if (!ic) {
212  /* reset the counter if there is no item */
213  chain->count = 0;
214  return;
215  }
216  for (; ic; ic = ic->getNext()) {
217  const objDef_t* od = ic->def();
218  assert(od);
219  /* not the item we are looking for */
220  if (Q_streq(od->id, chain->item))
221  break;
222  }
223  if (!ic) {
224  /* reset the counter if it's not the searched item */
225  chain->count = 0;
226  return;
227  }
228  }
229  if (chain->time) {
230  /* Check that the target zone is still occupied (last defender might have died) */
231  if (!chain->item && !G_MissionIsTouched(chain)) {
232  chain->count = 0;
233  }
234  const int endTime = level.actualRound - chain->count;
235  const int spawnIndex = (chain->getTeam() + level.teamOfs) % MAX_TEAMS;
236  const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS;
237  /* not every edict in the group chain has
238  * been occupied long enough */
239  if (!chain->count || endTime < chain->time ||
240  (endTime == chain->time && spawnIndex < currentIndex))
241  return;
242  }
243  if (chain->target && !chain->time && !chain->item) {
244  if (!G_MissionIsTouched(chain))
245  return;
246  }
247  }
248  chain = chain->groupChain;
249  }
250 
251  const bool endMission = self->target == nullptr;
252 
253  /* store team before the edict is released */
254  const int team = self->getTeam();
255  chain = self->groupMaster;
256  if (!chain)
257  chain = self;
258  while (chain) {
259  if (chain->type == ET_MISSION) {
260  if (chain->item != nullptr) {
261  Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM);
262  if (item != nullptr) {
263  if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) {
264  Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum());
265  } else if (!item->getFloor()) {
266  G_EventPerish(*item);
267  G_FreeEdict(item);
268  }
269  }
270  }
271  if (chain->link != nullptr) {
272  Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE);
273  if (particle != nullptr) {
274  G_AppearPerishEvent(G_VisToPM(particle->visflags), false, *particle, nullptr);
275  G_FreeEdict(particle);
276  }
277  chain->link = nullptr;
278  }
279 
280  /* Display mission message */
281  if (G_ValidMessage(chain)) {
282  const char* msg = chain->message;
283  if (msg[0] == '_')
284  ++msg;
285  gi.BroadcastPrintf(PRINT_HUD, "%s", msg);
286  }
287  }
288 
289  Edict* ent = chain->groupChain;
290  /* free the group chain (G_MissionUse() will free the edict if it fails) */
291  if (G_UseEdict(chain, nullptr))
292  G_FreeEdict(chain);
293  chain = ent;
294  }
295 
296  if (endMission)
297  G_MatchEndTrigger(team, level.activeTeam == TEAM_ALIEN ? 10 : 3);
298 }
void G_MissionAddVictoryMessage(const char *message)
Definition: g_mission.cpp:38
int getIdNum() const
Definition: g_edict.h:231
Item * getFloor() const
Definition: g_edict.h:262
void G_MatchEndTrigger(int team, int timeGap)
Triggers the end of the game. Will be executed in the next server (or game) frame.
Definition: g_match.cpp:125
#define TEAM_PHALANX
Definition: q_shared.h:62
#define MAX_TEAMS
Definition: defines.h:98
#define TEAM_ALIEN
Definition: q_shared.h:63
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
Edict * G_GetEdictFromPos(const pos3_t pos, const entity_type_t type)
Searches an edict of the given type at the given grid location.
Definition: g_utils.cpp:59
#define _(String)
Definition: cl_shared.h:43
Misc utility functions for game module.
void * data
Definition: list.h:31
bool G_InventoryRemoveItemByID(const char *itemID, Edict *ent, containerIndex_t container)
Removes one particular item from a given container.
Definition: g_inventory.cpp:80
const char * message
Definition: g_edict.h:130
int activeTeam
Definition: g_local.h:101
character_t chr
Definition: g_edict.h:116
bool(* use)(Edict *self, Edict *activator)
Definition: g_edict.h:154
Mission related code - king of the hill and so on.
const objDef_t * def(void) const
Definition: inv_shared.h:469
bool G_MissionUse(Edict *self, Edict *activator)
Mission trigger use function.
Definition: g_mission.cpp:151
const char * target
Definition: g_edict.h:125
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
Item * getNext() const
Definition: inv_shared.h:451
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
void G_AppearPerishEvent(playermask_t playerMask, bool appear, Edict &check, const Edict *ent)
Send the appear or perish event to the affected clients.
Definition: g_client.cpp:245
int actualRound
Definition: g_local.h:104
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition: g_actor.cpp:43
Actor * makeActor(Edict *ent)
Convert an Edict pointer into an Actor pointer.
Definition: g_edicts.cpp:327
Edict * G_EdictsFindTargetEntity(const char *target)
Searches the edict that has the given target as targetname set.
Definition: g_edicts.cpp:290
int getTeam() const
Definition: g_edict.h:269
bool G_MatchIsRunning(void)
Checks whether the game is running (active team and no intermission time)
Definition: g_match.cpp:320
item instance data, with linked list capability
Definition: inv_shared.h:402
Match related functions.
game_import_t gi
Definition: g_main.cpp:39
#define G_IsCivilian(ent)
Definition: g_local.h:148
teammask_t visflags
Definition: g_edict.h:82
pos3_t pos
Definition: g_edict.h:55
Edict * groupMaster
Definition: g_edict.h:168
An Edict of type Actor.
Definition: g_edict.h:348
#define CID_FLOOR
Definition: inv_shared.h:55
Edict * G_SpawnParticle(const vec3_t origin, int spawnflags, const char *particle)
Definition: g_spawn.cpp:551
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
const invDef_t * def() const
Definition: inv_shared.cpp:667
#define INVDEF(containerID)
Definition: cl_shared.h:47
void G_MissionReset(Edict *self, Edict *activator)
Definition: g_mission.cpp:124
int time
Definition: g_edict.h:136
Item * getNextItem(const Item *prev) const
Definition: inv_shared.cpp:671
static const char * G_MissionGetTeamString(const int team)
Definition: g_mission.cpp:43
const char * name
Definition: inv_shared.h:267
bool G_ActorInvMove(Actor *actor, const invDef_t *fromContType, Item *fItem, const invDef_t *toContType, int tx, int ty, bool checkaction)
Moves an item inside an inventory. Floors are handled special.
Definition: g_actor.cpp:506
int count
Definition: g_edict.h:135
void G_MissionThink(Edict *self)
Definition: g_mission.cpp:188
#define G_IsDead(ent)
Definition: g_actor.h:34
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
Brings new objects into the world.
entity_type_t type
Definition: g_edict.h:81
#define CS_VICTORY_CONDITIONS
Definition: q_shared.h:323
void G_EventPerish(const Edict &ent)
Send an event to all clients that are seeing the given edict, that it just has disappeared.
Definition: g_events.cpp:158
functions to handle the storage and lifecycle of all edicts in the game module.
const Edict * link
Definition: g_edict.h:80
bool(* destroy)(Edict *self)
Definition: g_edict.h:155
bool G_UseEdict(Edict *ent, Edict *activator)
Call the 'use' function for the given edict and all its group members.
Definition: g_utils.cpp:117
static bool G_MissionIsTouched(Edict *self)
Definition: g_mission.cpp:173
linkedList_t * next
Definition: list.h:32
Inventory inv
Definition: chr_shared.h:392
const char * item
Definition: g_edict.h:127
Edict * G_GetFloorItems(Edict *ent)
Prepares a list of items on the floor at given entity position.
Definition: g_inventory.cpp:59
#define NONE
Definition: defines.h:68
#define Q_streq(a, b)
Definition: shared.h:136
Definition: g_edict.h:45
#define G_ValidMessage(ent)
Definition: g_spawn.h:33
void G_FreeEdict(Edict *ent)
Marks the edict as free.
Definition: g_utils.cpp:41
bool G_MissionTouch(Edict *self, Edict *activator)
Mission trigger.
Definition: g_mission.cpp:53
Edict * groupChain
Definition: g_edict.h:167
const char * id
Definition: inv_shared.h:268
Interface for g_client.cpp.
level_locals_t level
Definition: g_main.cpp:38
int HP
Definition: g_edict.h:89
#define PRINT_HUD
Definition: defines.h:107