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