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 /* interface header */
14 #include "ShotStrategy.h"
15
16 /* common implementation headers */
17 #include "CollisionManager.h"
18 #include "Obstacle.h"
19 #include "ObstacleList.h"
20 #include "WallObstacle.h"
21 #include "ObstacleMgr.h"
22
ShotStrategy(ShotPath * _path)23 ShotStrategy::ShotStrategy(ShotPath* _path) :
24 path(_path)
25 {
26 // do nothing
27 }
28
~ShotStrategy()29 ShotStrategy::~ShotStrategy()
30 {
31 // do nothing
32 }
33
isStoppedByHit() const34 bool ShotStrategy::isStoppedByHit() const
35 {
36 return true;
37 }
38
sendUpdate(const FiringInfo &) const39 void ShotStrategy::sendUpdate(const FiringInfo&) const
40 {
41 // do nothing by default -- normal shots don't need updates
42 }
43
readUpdate(uint16_t,const void *)44 void ShotStrategy::readUpdate(uint16_t, const void*)
45 {
46 // do nothing by default -- normal shots don't need updates
47 }
48
expire()49 void ShotStrategy::expire()
50 {
51 // do nothing by default
52 }
53
setReloadTime(float t) const54 void ShotStrategy::setReloadTime(float t) const
55 {
56 path->setReloadTime(t);
57 }
58
setPosition(const float * p) const59 void ShotStrategy::setPosition(const float* p) const
60 {
61 path->setPosition(p);
62 }
63
setVelocity(const float * v) const64 void ShotStrategy::setVelocity(const float* v) const
65 {
66 path->setVelocity(v);
67 }
68
setExpiring() const69 void ShotStrategy::setExpiring() const
70 {
71 path->setExpiring();
72 }
73
setExpired() const74 void ShotStrategy::setExpired() const
75 {
76 path->setExpired();
77 }
78
getFiringInfo(ShotPath * p) const79 FiringInfo& ShotStrategy::getFiringInfo(ShotPath* p) const
80 {
81 return p->getFiringInfo();
82 }
83
getFirstBuilding(const Ray & ray,float min,float & t)84 const Obstacle* ShotStrategy::getFirstBuilding(const Ray& ray,
85 float min, float& t)
86 {
87 const Obstacle* closestObstacle = NULL;
88 unsigned int i = 0;
89
90 // check walls
91 const ObstacleList& walls = OBSTACLEMGR.getWalls();
92 for (i = 0; i < walls.size(); i++)
93 {
94 const WallObstacle* wall = (const WallObstacle*) walls[i];
95 if (!wall->isShootThrough())
96 {
97 const float wallt = wall->intersect(ray);
98 if (wallt > min && wallt < t)
99 {
100 t = wallt;
101 closestObstacle = wall;
102 }
103 }
104 }
105
106 //check everything else
107 const ObsList* olist = COLLISIONMGR.rayTest (&ray, t);
108
109 for (i = 0; i < (unsigned int)olist->count; i++)
110 {
111 const Obstacle* obs = olist->list[i];
112 if (!obs->isShootThrough())
113 {
114 const float timet = obs->intersect(ray);
115 if (obs->getType() == Teleporter::getClassName())
116 {
117 const Teleporter* tele = (const Teleporter*) obs;
118 int face;
119 if ((timet > min) && (timet < t) &&
120 (tele->isTeleported(ray, face) < 0.0f))
121 {
122 t = timet;
123 closestObstacle = obs;
124 }
125 }
126 else
127 {
128 if ((timet > min) && (timet < t))
129 {
130 t = timet;
131 closestObstacle = obs;
132 }
133 }
134 }
135 }
136
137 return closestObstacle;
138 }
139
reflect(float * v,const float * n)140 void ShotStrategy::reflect(float* v, const float* n) // const
141 {
142 // normal is assumed to be normalized, v needn't be
143 float d = -2.0f * ((n[0] * v[0]) + (n[1] * v[1]) + (n[2] * v[2]));
144
145 if (d >= 0.0f)
146 {
147 // normal reflection
148 v[0] += d * n[0];
149 v[1] += d * n[1];
150 v[2] += d * n[2];
151 }
152 else
153 {
154 // refraction due to inverted normal (still using the 2X factor)
155 float oldSpeed = sqrtf((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
156 d = -2.0f * d; // now using 4X refraction factor
157 v[0] += d * n[0];
158 v[1] += d * n[1];
159 v[2] += d * n[2];
160 // keep the same speed as the incoming vector
161 float newSpeed = sqrtf((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
162 const float scale = (oldSpeed / newSpeed);
163 v[0] *= scale;
164 v[1] *= scale;
165 v[2] *= scale;
166 }
167
168 return;
169 }
170
getFirstTeleporter(const Ray & ray,float min,float & t,int & f) const171 const Teleporter* ShotStrategy::getFirstTeleporter(const Ray& ray, float min,
172 float& t, int& f) const
173 {
174 const Teleporter* closestTeleporter = NULL;
175 int face;
176
177 const ObstacleList& teles = OBSTACLEMGR.getTeles();
178
179 for (unsigned int i = 0; i < teles.size(); i++)
180 {
181 const Teleporter& tele = *((const Teleporter*) teles[i]);
182 const float telet = tele.isTeleported(ray, face);
183 if (telet > min && telet < t)
184 {
185 t = telet;
186 f = face;
187 closestTeleporter = &tele;
188 }
189 }
190
191 return closestTeleporter;
192 }
193
getGround(const Ray & r,float min,float & t) const194 bool ShotStrategy::getGround(const Ray& r, float min, float &t) const
195 {
196 if (r.getDirection()[2] >= 0.0f)
197 return false;
198
199 float groundT = r.getOrigin()[2] / -r.getDirection()[2];
200 if ((groundT > min) && (groundT < t))
201 {
202 t = groundT;
203 return true;
204 }
205 return false;
206 }
207
208
209 // Local Variables: ***
210 // mode: C++ ***
211 // tab-width: 4 ***
212 // c-basic-offset: 4 ***
213 // indent-tabs-mode: nil ***
214 // End: ***
215 // ex: shiftwidth=4 tabstop=4
216