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 #include "EntryZones.h"
14 #include "CustomZone.h"
15
16 #include <string>
17 #include <vector>
18
19 #include "global.h"
20 #include "Protocol.h"
21 #include "Flag.h"
22 #include "Team.h"
23
24 #include "WorldInfo.h"
25
26
EntryZones()27 EntryZones::EntryZones()
28 {
29 }
30
31
getZoneList() const32 const ZoneList& EntryZones::getZoneList() const
33 {
34 return zones;
35 }
36
37
addZone(const CustomZone * zone)38 void EntryZones::addZone(const CustomZone *zone)
39 {
40 zones.push_back(*zone);
41 }
42
43
addZoneFlag(int zone,int flagId)44 void EntryZones::addZoneFlag(int zone, int flagId)
45 {
46 if (zone >= (int)zones.size())
47 {
48 printf ("Internal error: EntryZones::addZoneFlag() unknown zone\n");
49 exit(1);
50 }
51 const std::string& qualifier = CustomZone::getFlagIdQualifier(flagId);
52 QPairList &qPairList = qmap[qualifier];
53 if (!qPairList.empty())
54 {
55 printf ("Internal error: EntryZones::addZoneFlag() duplicate\n");
56 exit(1);
57 }
58 qPairList.push_back(std::pair<int,float>(zone, 1.0f));
59 return;
60 }
61
62
calculateQualifierLists()63 void EntryZones::calculateQualifierLists()
64 {
65 // generate the qualifier lists
66 for (unsigned int i = 0; i < zones.size(); i++)
67 {
68 QualifierList qualifiers = zones[i].getQualifiers();
69 for (QualifierList::iterator it = qualifiers.begin(); it != qualifiers.end(); ++it)
70 {
71 std::string qualifier = *it;
72 QPairList &qPairList = qmap[qualifier];
73 qPairList.push_back(std::pair<int,float>(i, 0.0f));
74 }
75 }
76
77 // calculate the qualifier weights
78 for (QualifierMap::iterator mit = qmap.begin(); mit != qmap.end(); ++mit)
79 {
80 QPairList &qPairList = mit->second;
81 float total = 0.0f;
82 QPairList::iterator vit;
83 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
84 {
85 std::pair<int,float> &p = *vit;
86 int zoneIndex = p.first;
87 p.second = zones[zoneIndex].getArea();
88 total += p.second;
89 }
90 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
91 {
92 std::pair<int,float> &p = *vit;
93 p.second /= total;
94 }
95 }
96 }
97
98
getRandomPoint(const std::string & qual,float * pt) const99 bool EntryZones::getRandomPoint(const std::string &qual, float *pt) const
100 {
101 QualifierMap::const_iterator mit = qmap.find(qual);
102 if (mit == qmap.end())
103 return false;
104
105 const QPairList &qPairList = mit->second;
106
107 float rnd = (float)bzfrand();
108 float total = 0.0f;
109 QPairList::const_iterator vit;
110 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
111 {
112 total += vit->second;
113 if (total > rnd)
114 break;
115 }
116
117 if (vit == qPairList.end())
118 {
119 return false; // ??
120 }
121
122 zones[vit->first].getRandomPoint(pt);
123
124 return true;
125 }
126
127
getClosePoint(const std::string & qual,const float pos[3],float * pt) const128 bool EntryZones::getClosePoint(const std::string &qual, const float pos[3],
129 float *pt) const
130 {
131 QualifierMap::const_iterator mit = qmap.find(qual);
132 if (mit == qmap.end())
133 return false;
134
135 const QPairList &qPairList = mit->second;
136
137 int closest = -1;
138 float minDist = +Infinity;
139 QPairList::const_iterator vit;
140 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
141 {
142 const int index = vit->first;
143 float dist = zones[index].getDistToPoint(pos);
144 if (dist < minDist)
145 {
146 closest = index;
147 minDist = dist;
148 }
149 }
150
151 if (closest == -1)
152 return false;
153
154 zones[closest].getRandomPoint(pt);
155
156 return true;
157 }
158
159
getZonePoint(const std::string & qualifier,float * pt) const160 bool EntryZones::getZonePoint(const std::string &qualifier, float *pt) const
161 {
162 QualifierMap::const_iterator mit = qmap.find(qualifier);
163 if (mit == qmap.end())
164 return false;
165
166 const QPairList &qPairList = mit->second;
167
168 float rnd = (float)bzfrand();
169 float total = 0.0f;
170 QPairList::const_iterator vit;
171 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
172 {
173 total += vit->second;
174 if (total > rnd)
175 break;
176 }
177
178 if (vit == qPairList.end())
179 {
180 return false; // ??
181 }
182
183 zones[vit->first].getRandomPoint(pt);
184
185 return true;
186 }
187
188
getSafetyPoint(const std::string & qualifier,const float * pos,float * pt) const189 bool EntryZones::getSafetyPoint( const std::string &qualifier,
190 const float *pos, float *pt ) const
191 {
192 std::string safetyString = /*EntryZones::getSafetyPrefix() + */ qualifier;
193
194 QualifierMap::const_iterator mit = qmap.find(safetyString);
195 if (mit == qmap.end())
196 return false;
197
198 const QPairList &qPairList = mit->second;
199
200 int closest = -1;
201 float minDist = +Infinity;
202 QPairList::const_iterator vit;
203 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
204 {
205 const int index = vit->first;
206 float dist = zones[index].getDistToPoint(pos);
207 if (dist < minDist)
208 {
209 closest = index;
210 minDist = dist;
211 }
212 }
213
214 if (closest == -1)
215 return false;
216
217 const CustomZone *zone = &zones[closest];
218 zone->getRandomPoint(pt);
219
220 return true;
221 }
222
223
makeSplitLists(int zone,std::vector<FlagType * > & flags,std::vector<TeamColor> & teams,std::vector<TeamColor> & safety) const224 void EntryZones::makeSplitLists (int zone,
225 std::vector<FlagType*> &flags,
226 std::vector<TeamColor> &teams,
227 std::vector<TeamColor> &safety) const
228 {
229 flags.clear();
230 teams.clear();
231 safety.clear();
232
233 QualifierMap::const_iterator mit;
234 for (mit = qmap.begin(); mit != qmap.end(); ++mit)
235 {
236 const QPairList &qPairList = mit->second;
237 QPairList::const_iterator vit;
238 for (vit = qPairList.begin(); vit != qPairList.end(); ++vit)
239 {
240 const std::pair<int,float> &p = *vit;
241 int zoneIndex = p.first;
242 if (zoneIndex == zone)
243 {
244 const std::string& qual = mit->first;
245 int team;
246 FlagType *type;
247 if ((type = CustomZone::getFlagTypeFromQualifier(qual)) != Flags::Null)
248 flags.push_back(type);
249 else if ((team = CustomZone::getPlayerTeamFromQualifier(qual)) >= 0)
250 teams.push_back((TeamColor)team);
251 else if ((team = CustomZone::getFlagSafetyFromQualifier(qual)) >= 0)
252 safety.push_back((TeamColor)team);
253 else
254 printf ("EntryZones::makeSplitLists() ERROR on (%s)\n", mit->first.c_str());
255 }
256 }
257 }
258
259 return;
260 }
261
262
pack(void * buf) const263 void * EntryZones::pack(void *buf) const
264 {
265 buf = nboPackUInt(buf, zones.size());
266
267 for (unsigned int i = 0; i < zones.size(); i++)
268 {
269 const WorldFileLocation& z = (const WorldFileLocation) zones[i];
270 std::vector<FlagType*> flags;
271 std::vector<TeamColor> teams;
272 std::vector<TeamColor> safety;
273 makeSplitLists (i, flags, teams, safety);
274 buf = z.pack (buf);
275 buf = nboPackUShort(buf, (uint16_t)flags.size());
276 buf = nboPackUShort(buf, (uint16_t)teams.size());
277 buf = nboPackUShort(buf, (uint16_t)safety.size());
278 unsigned int j;
279 for (j = 0; j < flags.size(); j++)
280 buf = flags[j]->pack(buf);
281 for (j = 0; j < teams.size(); j++)
282 buf = nboPackUShort(buf, teams[j]);
283 for (j = 0; j < safety.size(); j++)
284 buf = nboPackUShort(buf, safety[j]);
285 }
286 return buf;
287 }
288
289
packSize() const290 int EntryZones::packSize() const
291 {
292 int fullSize = 0;
293
294 fullSize += sizeof(uint32_t); // zone count
295
296 for (unsigned int i = 0; i < zones.size(); i++)
297 {
298 std::vector<FlagType*> flags;
299 std::vector<TeamColor> teams;
300 std::vector<TeamColor> safety;
301 makeSplitLists (i, flags, teams, safety);
302 fullSize += sizeof(float[3]); // pos
303 fullSize += sizeof(float[3]); // size
304 fullSize += sizeof(float); // angle
305 fullSize += sizeof(uint16_t); // flag count
306 fullSize += sizeof(uint16_t); // team count
307 fullSize += sizeof(uint16_t); // safety count
308 unsigned int j;
309 for (j = 0; j < flags.size(); j++)
310 fullSize += FlagType::packSize;
311 for (j = 0; j < teams.size(); j++)
312 fullSize += sizeof(uint16_t);
313 for (j = 0; j < safety.size(); j++)
314 fullSize += sizeof(uint16_t);
315 }
316
317 return fullSize;
318 }
319
320
321 // Local Variables: ***
322 // mode: C++ ***
323 // tab-width: 4 ***
324 // c-basic-offset: 4 ***
325 // indent-tabs-mode: nil ***
326 // End: ***
327 // ex: shiftwidth=4 tabstop=4
328