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 // class-interface header
14 #include "WorldWeapons.h"
15 
16 #include "WorldInfo.h"
17 // system headers
18 #include <vector>
19 
20 // common-interface headers
21 #include "TimeKeeper.h"
22 #include "ShotUpdate.h"
23 #include "Protocol.h"
24 #include "Address.h"
25 #include "StateDatabase.h"
26 #include "bzfsAPI.h"
27 
28 // bzfs specific headers
29 #include "bzfs.h"
30 #include "ShotManager.h"
31 
fireShot(FlagType * type,const float origin[3],const float vector[3],int * shotID,TeamColor teamColor,PlayerId targetPlayerID)32 uint32_t WorldWeapons::fireShot(FlagType* type, const float origin[3], const float vector[3], int *shotID,
33                                 TeamColor teamColor, PlayerId targetPlayerID)
34 {
35     if (!BZDB.isTrue(StateDatabase::BZDB_WEAPONS))
36         return INVALID_SHOT_GUID;
37 
38     void *buf, *bufStart = getDirectMessageBuffer();
39 
40     FiringInfo firingInfo;
41     firingInfo.timeSent = (float)TimeKeeper::getCurrent().getSeconds();
42     firingInfo.flagType = type;
43     firingInfo.lifetime = BZDB.eval(StateDatabase::BZDB_RELOADTIME);
44     firingInfo.shot.player = ServerPlayer;
45     memmove(firingInfo.shot.pos, origin, 3 * sizeof(float));
46 
47     const float shotSpeed = BZDB.eval(StateDatabase::BZDB_SHOTSPEED);
48 
49     for (int i = 0; i < 3; i++)
50         firingInfo.shot.vel[i] = vector[i] * shotSpeed;
51 
52     firingInfo.shot.dt = 0;
53     firingInfo.shot.team = teamColor;
54 
55     if (shotID != nullptr && shotID == 0)
56     {
57         *shotID = getNewWorldShotID();
58         firingInfo.shot.id = *shotID;
59     }
60     else if (shotID == nullptr)
61         firingInfo.shot.id = getNewWorldShotID();
62     else
63         firingInfo.shot.id = *shotID;
64 
65     bz_AllowServerShotFiredEventData_V1 allowEvent;
66     allowEvent.flagType = type->flagAbbv;
67     allowEvent.speed = shotSpeed;
68     for (int i = 0; i < 3; i++)
69     {
70         allowEvent.pos[i] = origin[i];
71         allowEvent.velocity[i] = firingInfo.shot.vel[i];
72     }
73     allowEvent.team = convertTeam(teamColor);
74 
75     worldEventManager.callEvents(bz_eAllowServerShotFiredEvent, &allowEvent);
76 
77     if (!allowEvent.allow)
78         return INVALID_SHOT_GUID;
79 
80     if (allowEvent.changed)
81     {
82         FlagTypeMap &flagMap = FlagType::getFlagMap();
83 
84         if (flagMap.find(allowEvent.flagType) == flagMap.end())
85             return INVALID_SHOT_GUID;
86 
87         FlagType *flag = flagMap.find(allowEvent.flagType)->second;
88         firingInfo.flagType = flag;
89     }
90 
91     buf = firingInfo.pack(bufStart);
92 
93     broadcastMessage(MsgShotBegin, (char*)buf - (char*)bufStart, bufStart);
94 
95     uint32_t shotGUID = ShotManager.AddShot(firingInfo, ServerPlayer);
96 
97     // Target the gm, construct it, and send packet
98     if (type->flagAbbv == "GM")
99     {
100         ShotManager.SetShotTarget(shotGUID, targetPlayerID);
101 
102         char packet[ShotUpdatePLen + PlayerIdPLen];
103         buf = (void*)packet;
104         buf = firingInfo.shot.pack(buf);
105         buf = nboPackUByte(buf, targetPlayerID);
106 
107         broadcastMessage(MsgGMUpdate, sizeof(packet), packet);
108     }
109 
110     bz_ServerShotFiredEventData_V1 event;
111     event.guid = shotGUID;
112     event.flagType = allowEvent.flagType;
113     event.speed = shotSpeed;
114     for (int i = 0; i < 3; i++)
115     {
116         event.pos[i] = origin[i];
117         event.velocity[i] = firingInfo.shot.vel[i];
118     }
119     event.team = convertTeam(teamColor);
120 
121     worldEventManager.callEvents(bz_eServerShotFiredEvent, &event);
122 
123     return shotGUID;
124 }
125 
WorldWeapons()126 WorldWeapons::WorldWeapons()
127     : worldShotId(0)
128 {
129 }
130 
131 
~WorldWeapons()132 WorldWeapons::~WorldWeapons()
133 {
134     clear();
135 }
136 
137 
clear(void)138 void WorldWeapons::clear(void)
139 {
140     for (std::vector<Weapon*>::iterator it = weapons.begin();
141             it != weapons.end(); ++it)
142     {
143         Weapon *w = *it;
144         delete w;
145     }
146     weapons.clear();
147 }
148 
149 
nextTime()150 float WorldWeapons::nextTime ()
151 {
152     TimeKeeper nextShot = TimeKeeper::getSunExplodeTime();
153     for (std::vector<Weapon*>::iterator it = weapons.begin();
154             it != weapons.end(); ++it)
155     {
156         Weapon *w = *it;
157         if (w->nextTime <= nextShot)
158             nextShot = w->nextTime;
159     }
160     return (float)(nextShot - TimeKeeper::getCurrent());
161 }
162 
163 
fire()164 void WorldWeapons::fire()
165 {
166     TimeKeeper nowTime = TimeKeeper::getCurrent();
167 
168     for (std::vector<Weapon*>::iterator it = weapons.begin();
169             it != weapons.end(); ++it)
170     {
171         Weapon *w = *it;
172         if (w->nextTime <= nowTime)
173         {
174             FlagType type = *(w->type);   // non-const copy
175 
176             float vec[3] = { 0,0,0 };
177             bz_vectorFromRotations(w->tilt, w->direction, vec);
178             fireShot(&type, w->origin, vec, nullptr, w->teamColor);
179 
180             //Set up timer for next shot, and eat any shots that have been missed
181             while (w->nextTime <= nowTime)
182             {
183                 w->nextTime += w->delay[w->nextDelay];
184                 w->nextDelay++;
185                 if (w->nextDelay == (int)w->delay.size())
186                     w->nextDelay = 0;
187             }
188         }
189     }
190 }
191 
192 
add(const FlagType * type,const float * origin,float direction,float tilt,TeamColor teamColor,float initdelay,const std::vector<float> & delay,TimeKeeper & sync)193 void WorldWeapons::add(const FlagType *type, const float *origin,
194                        float direction, float tilt, TeamColor teamColor,
195                        float initdelay, const std::vector<float> &delay,
196                        TimeKeeper &sync)
197 {
198     Weapon *w = new Weapon();
199     w->type = type;
200     w->teamColor = teamColor;
201     memmove(&w->origin, origin, 3*sizeof(float));
202     w->direction = direction;
203     w->tilt = tilt;
204     w->nextTime = sync;
205     w->nextTime += initdelay;
206     w->initDelay = initdelay;
207     w->nextDelay = 0;
208     w->delay = delay;
209 
210     weapons.push_back(w);
211 }
212 
213 
count(void)214 unsigned int WorldWeapons::count(void)
215 {
216     return weapons.size();
217 }
218 
219 
pack(void * buf) const220 void * WorldWeapons::pack(void *buf) const
221 {
222     buf = nboPackUInt(buf, weapons.size());
223 
224     for (unsigned int i=0 ; i < weapons.size(); i++)
225     {
226         const Weapon *w = (const Weapon *) weapons[i];
227         buf = w->type->pack (buf);
228         buf = nboPackVector(buf, w->origin);
229         buf = nboPackFloat(buf, w->direction);
230         buf = nboPackFloat(buf, w->initDelay);
231         buf = nboPackUShort(buf, (uint16_t)w->delay.size());
232         for (unsigned int j = 0; j < w->delay.size(); j++)
233             buf = nboPackFloat(buf, w->delay[j]);
234     }
235     return buf;
236 }
237 
238 
packSize(void) const239 int WorldWeapons::packSize(void) const
240 {
241     int fullSize = 0;
242 
243     fullSize += sizeof(uint32_t);
244 
245     for (unsigned int i=0 ; i < weapons.size(); i++)
246     {
247         const Weapon *w = (const Weapon *) weapons[i];
248         fullSize += FlagType::packSize; // flag type
249         fullSize += sizeof(float[3]); // pos
250         fullSize += sizeof(float);    // direction
251         fullSize += sizeof(float);    // init delay
252         fullSize += sizeof(uint16_t); // delay count
253         for (unsigned int j = 0; j < w->delay.size(); j++)
254             fullSize += sizeof(float);
255     }
256 
257     return fullSize;
258 }
259 
260 
getNewWorldShotID(void)261 int WorldWeapons::getNewWorldShotID(void)
262 {
263     if (worldShotId > _MAX_WORLD_SHOTS)
264         worldShotId = 0;
265     return worldShotId++;
266 }
267 
shotUsedInList(int shotID,Shots::ShotList & list)268 bool shotUsedInList(int shotID, Shots::ShotList& list)
269 {
270     for (size_t s = 0; s < list.size(); s++)
271     {
272         if (list[s]->GetLocalShotID() == shotID)
273             return true;
274     }
275     return false;
276 }
277 
278 //----------WorldWeaponGlobalEventHandler---------------------
279 // where we do the world weapon handling for event based shots since they are not really done by the "world"
280 
WorldWeaponGlobalEventHandler(FlagType * _type,const float * _origin,float _direction,float _tilt,TeamColor teamColor)281 WorldWeaponGlobalEventHandler::WorldWeaponGlobalEventHandler(FlagType *_type,
282         const float *_origin,
283         float _direction,
284         float _tilt,
285         TeamColor teamColor )
286 {
287     type = _type;
288     if (_origin)
289         memcpy(origin,_origin,sizeof(float)*3);
290     else
291         origin[0] = origin[1] = origin[2] = 0.0f;
292 
293     direction = _direction;
294     tilt = _tilt;
295     team = convertTeam(teamColor);
296 }
297 
~WorldWeaponGlobalEventHandler()298 WorldWeaponGlobalEventHandler::~WorldWeaponGlobalEventHandler()
299 {
300 }
301 
process(bz_EventData * eventData)302 void WorldWeaponGlobalEventHandler::process (bz_EventData *eventData)
303 {
304     if (!eventData || eventData->eventType != bz_eCaptureEvent)
305         return;
306 
307     bz_CTFCaptureEventData_V1 *capEvent = (bz_CTFCaptureEventData_V1*)eventData;
308 
309     if (capEvent->teamCapped != team)
310         return;
311 
312     float vec[3] = { 0,0,0 };
313     bz_vectorFromRotations(tilt, direction, vec);
314 
315     world->getWorldWeapons().fireShot(type, origin, vec, NULL);
316 }
317 
318 // Local Variables: ***
319 // mode: C++ ***
320 // tab-width: 4 ***
321 // c-basic-offset: 4 ***
322 // indent-tabs-mode: nil ***
323 // End: ***
324 // ex: shiftwidth=4 tabstop=4
325