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