1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 /* no header other than FlagInfo.h should be included here */
14
15 /* interface header */
16 #include "FlagInfo.h"
17
18 /* system headers */
19 #include <iostream>
20
21 // implementation-specific bzflag headers
22 #include "BZDBCache.h"
23
24 /* private */
25
26 /* protected */
27
28 /* public */
29
30 // flags list
31 FlagInfo *FlagInfo::flagList = NULL;
32 std::vector<FlagType*> FlagInfo::allowedFlags;
33 int FlagInfo::numExtraFlags = 0;
34 int FlagInfo::numFlags = 0;
35 int FlagInfo::numFlagsInAir;
36
FlagInfo()37 FlagInfo::FlagInfo(): numShots(0), flagIndex(0)
38 {
39 // prep flag
40 flag.type = Flags::Null;
41 flag.status = FlagNoExist;
42 flag.endurance = FlagNormal;
43 flag.owner = NoPlayer;
44 flag.position[0] = 0.0f;
45 flag.position[1] = 0.0f;
46 flag.position[2] = 0.0f;
47 flag.launchPosition[0] = 0.0f;
48 flag.launchPosition[1] = 0.0f;
49 flag.launchPosition[2] = 0.0f;
50 flag.landingPosition[0] = 0.0f;
51 flag.landingPosition[1] = 0.0f;
52 flag.landingPosition[2] = 0.0f;
53 flag.flightTime = 0.0f;
54 flag.flightEnd = 0.0f;
55 flag.initialVelocity = 0.0f;
56 player = -1;
57 grabs = 0;
58 required = false;
59 }
60
setSize(int _numFlags)61 void FlagInfo::setSize(int _numFlags)
62 {
63 // sanity check
64 if (_numFlags > 100000)
65 {
66 std::cerr << "WARNING: FlagInfo::setSize was given an insane flag count of " << _numFlags << std::endl;
67 std::cerr << "clamping to 100000 flags just for kicks" << std::endl;
68 _numFlags = 100000;
69 }
70
71 numFlags = _numFlags;
72 delete[] flagList;
73 flagList = NULL;
74 if (numFlags)
75 flagList = new FlagInfo[numFlags];
76 for (int i = 0; i < numFlags; i++)
77 flagList[i].flagIndex = i;
78 }
79
setAllowed(std::vector<FlagType * > allowed)80 void FlagInfo::setAllowed(std::vector<FlagType*> allowed)
81 {
82 allowedFlags = allowed;
83 }
84
setExtra(int extra)85 void FlagInfo::setExtra(int extra)
86 {
87 numExtraFlags = extra;
88 }
89
lookupFirstTeamFlag(int teamindex)90 int FlagInfo::lookupFirstTeamFlag(int teamindex)
91 {
92 for (int i = 0; i < numFlags; i++)
93 {
94 if (flagList[i].flag.type->flagTeam == teamindex)
95 return i;
96 }
97 return -1;
98 }
99
setRequiredFlag(FlagType * desc)100 void FlagInfo::setRequiredFlag(FlagType *desc)
101 {
102 required = true;
103 flag.type = desc;
104 }
105
addFlag()106 void FlagInfo::addFlag()
107 {
108 const float flagAltitude = BZDB.eval(StateDatabase::BZDB_FLAGALTITUDE);
109 const float gravity = BZDBCache::gravity;
110
111 // flag is now entering game
112 numFlagsInAir++;
113 flag.status = FlagComing;
114
115 // compute drop time
116 const float flightTime = 2.0f * sqrtf(-2.0f * flagAltitude / gravity);
117 flag.flightTime = 0.0f;
118 flag.flightEnd = flightTime;
119 flag.initialVelocity = -0.5f * gravity * flightTime;
120 dropDone = TimeKeeper::getCurrent();
121 dropDone += flightTime;
122
123 if (flag.type == Flags::Null)
124 // pick a random flag
125 flag.type = allowedFlags[(int)(allowedFlags.size() * (float)bzfrand())];
126
127 // decide how sticky the flag will be
128 if (flag.type->flagQuality == FlagBad)
129 flag.endurance = FlagSticky;
130 else
131 flag.endurance = FlagUnstable;
132
133 // how times will it stick around
134 if ((flag.endurance == FlagSticky) || (flag.type == Flags::Thief))
135 grabs = 1;
136 else
137 grabs = BZDB.evalInt(StateDatabase::BZDB_MAXFLAGGRABS);
138 }
139
pack(void * buf,bool hide)140 void *FlagInfo::pack(void *buf, bool hide)
141 {
142 if (FlagInfo::flagList[flagIndex].flag.type->flagTeam != ::NoTeam)
143 hide = false;
144 if (FlagInfo::flagList[flagIndex].player != -1)
145 hide = false;
146 buf = nboPackUShort(buf, flagIndex);
147 if (hide)
148 buf = FlagInfo::flagList[flagIndex].flag.fakePack(buf);
149 else
150 buf = FlagInfo::flagList[flagIndex].flag.pack(buf);
151 return buf;
152 }
153
dropFlag(float pos[3],float landingPos[3],bool vanish)154 void FlagInfo::dropFlag(float pos[3], float landingPos[3], bool vanish)
155 {
156 numFlagsInAir++;
157 flag.status = vanish ? FlagGoing : FlagInAir;
158
159 flag.landingPosition[0] = landingPos[0];
160 flag.landingPosition[1] = landingPos[1];
161 flag.landingPosition[2] = landingPos[2];
162
163 flag.position[0] = landingPos[0];
164 flag.position[1] = landingPos[1];
165 flag.position[2] = landingPos[2];
166 flag.launchPosition[0] = pos[0];
167 flag.launchPosition[1] = pos[1];
168 flag.launchPosition[2] = pos[2] + BZDBCache::tankHeight;
169
170 // compute flight info -- flight time depends depends on start and end
171 // altitudes and desired height above start altitude
172 const float gravity = BZDBCache::gravity;
173 const float flagAltitude = BZDB.eval(StateDatabase::BZDB_FLAGALTITUDE);
174 const float thrownAltitude = (flag.type == Flags::Shield) ?
175 BZDB.eval(StateDatabase::BZDB_SHIELDFLIGHT) * flagAltitude : flagAltitude;
176 const float maxAltitude = pos[2] + thrownAltitude;
177 const float upTime = sqrtf(-2.0f * thrownAltitude / gravity);
178 const float downTime = sqrtf(-2.0f * (maxAltitude - pos[2]) / gravity);
179 const float flightTime = upTime + downTime;
180
181 dropDone = TimeKeeper::getCurrent();
182 dropDone += flightTime;
183 flag.flightTime = 0.0f;
184 flag.flightEnd = flightTime;
185 flag.initialVelocity = -gravity * upTime;
186 }
187
resetFlag(float position[3],bool teamIsEmpty)188 void FlagInfo::resetFlag(float position[3], bool teamIsEmpty)
189 {
190 // reset a flag's info
191 player = -1;
192 // if it's a random flag, reset flag id
193 if (flagIndex >= numFlags - numExtraFlags)
194 flag.type = Flags::Null;
195
196 flag.position[0] = position[0];
197 flag.position[1] = position[1];
198 flag.position[2] = position[2];
199
200 // required flags mustn't just disappear
201 if (required)
202 {
203 if (flag.type->flagTeam == ::NoTeam)
204 // flag in now entering game
205 addFlag();
206 else if (teamIsEmpty)
207 flag.status = FlagNoExist;
208 else
209 flag.status = FlagOnGround;
210 }
211 else
212 flag.status = FlagNoExist;
213 }
214
grab(int playerIndex)215 void FlagInfo::grab(int playerIndex)
216 {
217 flag.status = FlagOnTank;
218 flag.owner = playerIndex;
219 player = playerIndex;
220 numShots = 0;
221 }
222
teamIndex() const223 TeamColor FlagInfo::teamIndex() const
224 {
225 return flag.type->flagTeam;
226 }
227
getIndex() const228 int FlagInfo::getIndex() const
229 {
230 return flagIndex;
231 }
232
getNextDrop(TimeKeeper & tm)233 float FlagInfo::getNextDrop(TimeKeeper &tm)
234 {
235 // find timeout when next flag would hit ground
236 float waitTime = 3.0f;
237 if (numFlagsInAir > 0)
238 {
239 for (int i = 0; i < numFlags; i++)
240 {
241 FlagInfo &flag = flagList[i];
242 if (flag.flag.status != FlagNoExist &&
243 flag.flag.status != FlagOnTank &&
244 flag.flag.status != FlagOnGround &&
245 flag.dropDone - tm < waitTime)
246 waitTime = float(flag.dropDone - tm);
247 }
248 }
249 return waitTime;
250 }
251
landing(const TimeKeeper & tm)252 bool FlagInfo::landing(const TimeKeeper &tm)
253 {
254 if (numFlagsInAir <= 0)
255 return false;
256
257 bool land = false;
258 if (flag.status == FlagInAir || flag.status == FlagComing)
259 {
260 if (dropDone - tm <= 0.0f)
261 {
262 flag.status = FlagOnGround;
263 numFlagsInAir--;
264 land = true;
265 }
266 }
267 else if (flag.status == FlagGoing)
268 {
269 if (dropDone - tm <= 0.0f)
270 {
271 flag.status = FlagNoExist;
272 numFlagsInAir--;
273 land = true;
274 }
275 }
276 return land;
277 }
278
setNoFlagInAir()279 void FlagInfo::setNoFlagInAir()
280 {
281 numFlagsInAir = 0;
282 }
283
getTextualInfo(char * message)284 void FlagInfo::getTextualInfo(char *message)
285 {
286 sprintf(message, "#%-3d i:%-3s p:%-3d r:%-2d g:%-2d s:%-2d "
287 "p:{%.1f, %.1f, %.1f}",
288 flagIndex, flag.type->flagAbbv.c_str(), player,
289 required ? 1 : 0, grabs, flag.status,
290 flag.position[0], flag.position[1], flag.position[2]);
291 }
292
exist()293 bool FlagInfo::exist()
294 {
295 return flag.status != FlagNoExist;
296 }
297
get(int index)298 FlagInfo *FlagInfo::get(int index)
299 {
300 if (index < 0)
301 return NULL;
302 if (index >= numFlags)
303 return NULL;
304 return &flagList[index];
305 }
306
307 // Local Variables: ***
308 // mode: C++ ***
309 // tab-width: 4 ***
310 // c-basic-offset: 4 ***
311 // indent-tabs-mode: nil ***
312 // End: ***
313 // ex: shiftwidth=4 tabstop=4
314