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