UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cl_battlescape.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "../client.h"
26 #include "cl_battlescape.h"
27 #include "cl_actor.h"
28 
30 
37 le_t* CL_BattlescapeSearchAtGridPos (const pos3_t pos, bool includingStunned, const le_t* actor)
38 {
39  le_t* le;
40  le_t* nonActor = nullptr;
41 
42  /* search for an actor on this field */
43  le = nullptr;
44  while ((le = LE_GetNextInUse(le))) {
45  if (actor != nullptr && le == actor->clientAction) {
46  /* if the actor has a client action assigned and we click onto the actor,
47  * we will trigger this client action */
48  if (VectorCompare(actor->pos, pos))
49  nonActor = le;
50  } else if (le != actor && LE_IsLivingAndVisibleActor(le) && (includingStunned || !LE_IsStunned(le)))
51  switch (le->fieldSize) {
52  case ACTOR_SIZE_NORMAL:
53  if (VectorCompare(le->pos, pos))
54  return le;
55  break;
56  case ACTOR_SIZE_2x2: {
57  pos3_t actor2x2[3];
58 
59  VectorSet(actor2x2[0], le->pos[0] + 1, le->pos[1], le->pos[2]);
60  VectorSet(actor2x2[1], le->pos[0], le->pos[1] + 1, le->pos[2]);
61  VectorSet(actor2x2[2], le->pos[0] + 1, le->pos[1] + 1, le->pos[2]);
62  if (VectorCompare(le->pos, pos)
63  || VectorCompare(actor2x2[0], pos)
64  || VectorCompare(actor2x2[1], pos)
65  || VectorCompare(actor2x2[2], pos))
66  return le;
67  break;
68  }
69  default:
70  Com_Error(ERR_DROP, "Grid_MoveCalc: unknown actor-size: %i!", le->fieldSize);
71  }
72  }
73 
74  return nonActor;
75 }
76 
83 {
84  return cl.spawned;
85 }
86 
95 bool CL_OnBattlescape (void)
96 {
97  /* server_state is set to zero (ss_dead) on every battlefield shutdown */
98  if (Com_ServerState())
99  return true; /* server */
100 
101  /* client */
102  if (cls.state >= ca_connected)
103  return true;
104 
105  return false;
106 }
107 
108 
109 #define LOOKUP_EPSILON 0.0001f
110 
115 static const float lookup[30]= {
116  0.0f, 0.1125f, 0.2227f, 0.3286f, 0.4284f, 0.5205f, 0.6039f,
117  0.6778f, 0.7421f, 0.7969f, 0.8427f, 0.8802f, 0.9103f, 0.9340f,
118  0.9523f, 0.9661f, 0.9763f, 0.9838f, 0.9891f, 0.9928f, 0.9953f,
119  0.9970f, 0.9981f, 0.9989f, 0.9993f, 0.9996f, 0.9998f, 0.9999f,
120  0.9999f, 1.0000f
121 };
122 
127 static const float lookupdiff[30]= {
128  1.1246f, 1.1024f, 1.0592f, 0.9977f, 0.9211f, 0.8336f, 0.7395f,
129  0.6430f, 0.5481f, 0.4579f, 0.3750f, 0.3011f, 0.2369f, 0.1828f,
130  0.1382f, 0.1024f, 0.0744f, 0.0530f, 0.0370f, 0.0253f, 0.0170f,
131  0.0112f, 0.0072f, 0.0045f, 0.0028f, 0.0017f, 0.0010f, 0.0006f,
132  0.0003f, 0.0002f
133 };
134 
144 static float CL_LookupErrorFunction (float z)
145 {
146  float ifloat;
147  int iint;
148 
149  /* erf(-z)=-erf(z), but erf of -ve number should never be used here
150  * so return 0 here */
151  if (z < LOOKUP_EPSILON)
152  return 0.0f;
153  if (z > 2.8f)
154  return 1.0f;
155  ifloat = floor(z * 10.0f);
156  iint = (int)ifloat;
157  assert(iint < 30);
158  return lookup[iint] + (z - ifloat / 10.0f) * lookupdiff[iint];
159 }
160 
161 static inline bool CL_TestLine (const vec3_t start, const vec3_t stop, const int levelmask)
162 {
163  return TR_TestLine(cl.mapTiles, start, stop, levelmask);
164 }
165 
176 int CL_GetHitProbability (const le_t* actor)
177 {
178  assert(actor);
179  assert(actor->fd);
180 
181  pos3_t toPos;
182  if (IS_MODE_FIRE_PENDING(actor->actorMode))
183  VectorCopy(actor->mousePendPos, toPos);
184  else
185  VectorCopy(mousePos, toPos);
186 
188  const le_t* le = LE_GetFromPos(toPos);
189  if (!le)
190  return 0;
191 
192  /* Target is not visible */
193  if (LE_IsInvisible(le))
194  return 0;
195 
196  /* or suicide attempted */
197  if (LE_IsSelected(le) && !FIRESH_IsMedikit(le->fd))
198  return 0;
199 
200  vec3_t shooter;
201  VectorCopy(actor->origin, shooter);
202  vec3_t target;
203  VectorCopy(le->origin, target);
204 
205  /* Calculate HitZone: */
206  const int distx = fabs(shooter[0] - target[0]);
207  const int disty = fabs(shooter[1] - target[1]);
208  const float distance = sqrtf(distx * distx + disty * disty);
209  float pseudosin;
210  if (distx > disty)
211  pseudosin = distance / distx;
212  else
213  pseudosin = distance / disty;
214  float width = 2 * PLAYER_WIDTH * pseudosin;
216 
217  const character_t* chr = CL_ActorGetChr(actor);
218  if (!chr)
219  Com_Error(ERR_DROP, "No character given for local entity");
220 
221  const float acc = GET_ACC(chr->score.skills[ABILITY_ACCURACY],
222  actor->fd->weaponSkill ? chr->score.skills[actor->fd->weaponSkill] : 0.0, CL_ActorInjuryModifier(actor, MODIFIER_ACCURACY));
223 
224  const float crouch = (LE_IsCrouched(actor) && actor->fd->crouch) ? actor->fd->crouch : 1.0;
225 
226  const float commonfactor = crouch * torad * distance;
227  const float stdevupdown = (actor->fd->spread[0] * (WEAPON_BALANCE + SKILL_BALANCE * acc)) * commonfactor;
228  const float stdevleftright = (actor->fd->spread[1] * (WEAPON_BALANCE + SKILL_BALANCE * acc)) * commonfactor;
229  const float hitchance = (stdevupdown > LOOKUP_EPSILON ? CL_LookupErrorFunction(height * 0.3536f / stdevupdown) : 1.0f)
230  * (stdevleftright > LOOKUP_EPSILON ? CL_LookupErrorFunction(width * 0.3536f / stdevleftright) : 1.0f);
231  /* 0.3536=sqrt(2)/4 */
232 
233  /* Calculate cover: */
234  int n = 0;
235  height = height / 18;
236  width = width / 18;
237  target[2] -= UNIT_HEIGHT / 2;
238  target[2] += height * 9;
239  float perpX = disty / distance * width;
240  float perpY = 0 - distx / distance * width;
241 
242  target[0] += perpX;
243  perpX *= 2;
244  target[1] += perpY;
245  perpY *= 2;
246  target[2] += 6 * height;
247  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
248  n++;
249  target[0] += perpX;
250  target[1] += perpY;
251  target[2] -= 6 * height;
252  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
253  n++;
254  target[0] += perpX;
255  target[1] += perpY;
256  target[2] += 4 * height;
257  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
258  n++;
259  target[2] += 4 * height;
260  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
261  n++;
262  target[0] -= perpX * 3;
263  target[1] -= perpY * 3;
264  target[2] -= 12 * height;
265  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
266  n++;
267  target[0] -= perpX;
268  target[1] -= perpY;
269  target[2] += 6 * height;
270  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
271  n++;
272  target[0] -= perpX;
273  target[1] -= perpY;
274  target[2] -= 4 * height;
275  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
276  n++;
277  target[0] -= perpX;
278  target[1] -= perpY;
279  target[2] += 10 * height;
280  if (!CL_TestLine(shooter, target, TL_FLAG_NONE))
281  n++;
282 
283  return 100 * (hitchance * (0.125) * n);
284 }
285 
286 static const float mapZBorder = -(UNIT_HEIGHT * 5);
296 bool CL_OutsideMap (const vec3_t position, const float delta)
297 {
298  if (position[0] < cl.mapData->mapBox.getMinX() - delta || position[0] > cl.mapData->mapBox.getMaxX() + delta)
299  return true;
300 
301  if (position[1] < cl.mapData->mapBox.getMinY() - delta || position[1] > cl.mapData->mapBox.getMaxY() + delta)
302  return true;
303 
304  /* if a le is deeper than 5 levels below the latest walkable level (0) then
305  * we can assume that it is outside the world
306  * This is needed because some maps (e.g. the dam map) has unwalkable levels
307  * that just exists for detail reasons */
308  if (position[2] < mapZBorder)
309  return true;
310 
311  /* still inside the map borders */
312  return false;
313 }
314 
320 {
321  le_t* le;
322  int count;
323 
324  count = 0;
325  le = nullptr;
326  while ((le = LE_GetNextInUse(le))) {
327  if (LE_IsLivingAndVisibleActor(le) && le->team != cls.team && le->team != TEAM_CIVILIAN)
328  count++;
329  }
330 
331  return count;
332 }
333 
334 #ifdef DEBUG
335 
336 #include "../../common/routing.h"
337 
342 void Grid_DumpWholeClientMap_f (void)
343 {
344  RT_DumpWholeMap(cl.mapTiles, cl.mapData->routing);
345 }
346 
351 void Grid_DumpClientRoutes_f (void)
352 {
354  VecToPos(cl.mapData->mapBox.mins, wpMins);
355  VecToPos(cl.mapData->mapBox.maxs, wpMaxs);
356  RT_WriteCSVFiles(cl.mapData->routing, "ufoaiclient", GridBox(wpMins, wpMaxs));
357 }
358 #endif
359 
361 {
362  if (!Com_CheckConfigStringIndex(index))
363  Com_Error(ERR_DROP, "invalid access to configstring array with index: %i", index);
364 
365  return cl.configstrings[index];
366 }
367 
369 {
370  return atoi(CL_GetConfigString(index));
371 }
372 
374 {
375  if (!Com_CheckConfigStringIndex(index))
376  Com_Error(ERR_DROP, "invalid access to configstring array with index: %i", index);
377 
378  /* change the string in cl
379  * there may be overflows in i==CS_TILES - but thats ok
380  * see definition of configstrings and MAX_TILESTRINGS */
381  if (index == CS_TILES || index == CS_POSITIONS)
383  else
384  NET_ReadString(msg, cl.configstrings[index], sizeof(cl.configstrings[index]));
385 
386  return cl.configstrings[index];
387 }
#define LE_IsStunned(le)
#define LOOKUP_EPSILON
float getMaxX() const
Definition: aabb.h:131
#define PLAYER_WIDTH
Definition: q_sizes.h:10
#define VectorCopy(src, dest)
Definition: vector.h:51
le_t * CL_BattlescapeSearchAtGridPos(const pos3_t pos, bool includingStunned, const le_t *actor)
Searches a local entity at the given position.
#define ACTOR_SIZE_2x2
Definition: defines.h:303
#define VectorSet(v, x, y, z)
Definition: vector.h:59
#define LE_IsCrouched(le)
chrScoreGlobal_t score
Definition: chr_shared.h:387
static const float mapZBorder
This is the structure that should be used for data that is needed for tactical missions only...
static ipos3_t wpMaxs
Definition: routing.cpp:35
bool CL_OnBattlescape(void)
Check whether we are in a tactical mission as server or as client. But this only means that we are ab...
void RT_WriteCSVFiles(const Routing &routing, const char *baseFilename, const GridBox &box)
Definition: routing.cpp:1330
pos3_t pos
vec2_t spread
Definition: inv_shared.h:146
char * CL_GetConfigString(int index)
char configstrings[MAX_CONFIGSTRINGS][MAX_TOKEN_CHARS]
#define MAX_TILESTRINGS
Definition: q_shared.h:298
#define LE_IsInvisible(le)
#define UNIT_HEIGHT
Definition: defines.h:122
struct le_s * clientAction
bool CL_OutsideMap(const vec3_t position, const float delta)
Checks whether give position is still inside the map borders.
character_t * CL_ActorGetChr(const le_t *le)
Returns the character information for an actor in the teamlist.
Definition: cl_actor.cpp:155
static const float lookupdiff[30]
table for lookup_erf lookup[]= {10*(erf(0.1)-erf(0.0)), 10*(erf(0.2)-erf(0.1)), ...}
float CL_ActorInjuryModifier(const le_t *le, const modifier_types_t type)
Returns the actor injury modifier of the specified type.
Definition: cl_actor.cpp:299
#define TEAM_CIVILIAN
Definition: q_shared.h:61
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
vec3_t origin
int CL_GetConfigStringInteger(int index)
vec3_t maxs
Definition: aabb.h:258
actorModes_t actorMode
le_t * LE_GetFromPos(const pos3_t pos)
Searches a local entity on a given grid field.
static bool CL_TestLine(const vec3_t start, const vec3_t stop, const int levelmask)
#define CS_POSITIONS
Definition: q_shared.h:326
ipos_t ipos3_t[3]
Definition: ufotypes.h:70
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
actorSizeEnum_t fieldSize
mapTiles_t * mapTiles
client_static_t cls
Definition: cl_main.cpp:83
#define ERR_DROP
Definition: common.h:211
int NET_ReadString(dbuffer *buf, char *string, size_t length)
Definition: netpack.cpp:302
static const float lookup[30]
table for lookup_erf lookup[]= {erf(0), erf(0.1), ...}
#define LE_IsSelected(le)
pos3_t mousePendPos
#define GET_ACC(ab, sk, pn)
Definition: q_shared.h:289
#define VecToPos(v, p)
Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the possible max negative ...
Definition: mathlib.h:100
#define FIRESH_IsMedikit(firedef)
Definition: inv_shared.h:661
bool LE_IsLivingAndVisibleActor(const le_t *le)
Checks whether the given le is a living and visible actor.
#define IS_MODE_FIRE_PENDING(x)
clientBattleScape_t cl
#define TL_FLAG_NONE
Definition: defines.h:357
#define WEAPON_BALANCE
Definition: inv_shared.h:43
int CL_CountVisibleEnemies(void)
Counts visible enemies on the battlescape.
#define MAX_TOKEN_CHARS
Definition: defines.h:372
float getMaxY() const
Definition: aabb.h:134
pos_t pos3_t[3]
Definition: ufotypes.h:58
bool CL_BattlescapeRunning(void)
Check whether we already have actors spawned on the battlefield.
int CL_GetHitProbability(const le_t *actor)
Calculates chance to hit if the actor has a fire mode activated.
QGL_EXTERN GLuint index
Definition: r_gl.h:110
bool Com_CheckConfigStringIndex(int index)
Definition: common.cpp:860
QGL_EXTERN GLuint count
Definition: r_gl.h:99
#define VectorCompare(a, b)
Definition: vector.h:63
a local entity
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
const fireDef_t * fd
float getMinY() const
Definition: aabb.h:122
#define PLAYER_CROUCHING_HEIGHT
Definition: q_sizes.h:13
#define SKILL_BALANCE
Definition: inv_shared.h:44
#define CS_TILES
Definition: q_shared.h:325
bool TR_TestLine(mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const int levelmask)
Checks traces against the world.
Definition: tracing.cpp:310
float getMinX() const
Definition: aabb.h:119
static float CL_LookupErrorFunction(float z)
calculate approximate erf, the error function http://en.wikipedia.org/wiki/Error_function uses lookup...
int weaponSkill
Definition: inv_shared.h:162
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define torad
Definition: mathlib.h:50
vec3_t mins
Definition: aabb.h:257
AABB mapBox
Definition: typedefs.h:351
char * CL_SetConfigString(int index, dbuffer *msg)
pos3_t mousePos
Definition: cl_actor.cpp:51
connstate_t state
Definition: client.h:55
float crouch
Definition: inv_shared.h:151
int team
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
Routing routing
Definition: typedefs.h:341
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition: common.cpp:538
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
static ipos3_t wpMins
world min and max values converted from vec to pos
Definition: routing.cpp:35
#define PLAYER_STANDING_HEIGHT
Definition: q_sizes.h:12
Describes a character with all its attributes.
Definition: chr_shared.h:369