UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_battlescape.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, 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
37le_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) {
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
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
115static 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
127static 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
144static 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
161static 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
176int CL_GetHitProbability (const le_t* actor)
177{
178 assert(actor);
179 assert(actor->fd);
180
181 pos3_t toPos;
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
286static const float mapZBorder = -(UNIT_HEIGHT * 5);
296bool 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
336#include "../../common/routing.h"
337
342void Grid_DumpWholeClientMap_f (void)
343{
344 RT_DumpWholeMap(cl.mapTiles, cl.mapData->routing);
345}
346
351void 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{
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{
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)
382 NET_ReadString(msg, cl.configstrings[index], MAX_TOKEN_CHARS * MAX_TILESTRINGS);
383 else
384 NET_ReadString(msg, cl.configstrings[index], sizeof(cl.configstrings[index]));
385
386 return cl.configstrings[index];
387}
@ ABILITY_ACCURACY
Definition chr_shared.h:39
@ MODIFIER_ACCURACY
Definition chr_shared.h:256
pos3_t mousePos
Definition cl_actor.cpp:51
character_t * CL_ActorGetChr(const le_t *le)
Returns the character information for an actor in the teamlist.
Definition cl_actor.cpp:155
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
static bool CL_TestLine(const vec3_t start, const vec3_t stop, const int levelmask)
#define LOOKUP_EPSILON
static float CL_LookupErrorFunction(float z)
calculate approximate erf, the error function http://en.wikipedia.org/wiki/Error_function uses lookup...
bool CL_OutsideMap(const vec3_t position, const float delta)
Checks whether give position is still inside the map borders.
char * CL_GetConfigString(int index)
int CL_GetHitProbability(const le_t *actor)
Calculates chance to hit if the actor has a fire mode activated.
static const float lookupdiff[30]
table for lookup_erf lookup[]= {10*(erf(0.1)-erf(0.0)), 10*(erf(0.2)-erf(0.1)), .....
le_t * CL_BattlescapeSearchAtGridPos(const pos3_t pos, bool includingStunned, const le_t *actor)
Searches a local entity at the given position.
int CL_GetConfigStringInteger(int index)
clientBattleScape_t cl
static const float lookup[30]
table for lookup_erf lookup[]= {erf(0), erf(0.1), ...}
char * CL_SetConfigString(int index, dbuffer *msg)
int CL_CountVisibleEnemies(void)
Counts visible enemies on the battlescape.
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...
static const float mapZBorder
bool CL_BattlescapeRunning(void)
Check whether we already have actors spawned on the battlefield.
le_t * LE_GetNextInUse(le_t *lastLE)
Iterate through the entities that are in use.
bool LE_IsLivingAndVisibleActor(const le_t *le)
Checks whether the given le is a living and visible actor.
le_t * LE_GetFromPos(const pos3_t pos)
Searches a local entity on a given grid field.
#define LE_IsCrouched(le)
#define LE_IsInvisible(le)
#define LE_IsSelected(le)
#define IS_MODE_FIRE_PENDING(x)
#define LE_IsStunned(le)
client_static_t cls
Definition cl_main.cpp:83
@ ca_connected
Definition cl_shared.h:79
Primary header for client.
void RT_WriteCSVFiles(const Routing &routing, const char *baseFilename, const GridBox &box)
Definition routing.cpp:1330
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition common.cpp:578
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
bool Com_CheckConfigStringIndex(int index)
Definition common.cpp:877
#define ERR_DROP
Definition common.h:211
#define TL_FLAG_NONE
Definition defines.h:357
#define UNIT_HEIGHT
Definition defines.h:122
#define ACTOR_SIZE_2x2
Definition defines.h:303
#define ACTOR_SIZE_NORMAL
Definition defines.h:302
#define MAX_TOKEN_CHARS
Definition defines.h:372
#define WEAPON_BALANCE
Definition inv_shared.h:43
#define FIRESH_IsMedikit(firedef)
Definition inv_shared.h:661
#define SKILL_BALANCE
Definition inv_shared.h:44
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define torad
Definition mathlib.h:50
#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
int NET_ReadString(dbuffer *buf, char *string, size_t length)
Definition netpack.cpp:302
#define MAX_TILESTRINGS
Definition q_shared.h:298
#define CS_TILES
Definition q_shared.h:325
#define CS_POSITIONS
Definition q_shared.h:326
#define TEAM_CIVILIAN
Definition q_shared.h:61
#define GET_ACC(ab, sk, pn)
Definition q_shared.h:289
#define PLAYER_STANDING_HEIGHT
Definition q_sizes.h:12
#define PLAYER_WIDTH
Definition q_sizes.h:10
#define PLAYER_CROUCHING_HEIGHT
Definition q_sizes.h:13
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLuint index
Definition r_gl.h:110
grid pathfinding and routing
Describes a character with all its attributes.
Definition chr_shared.h:388
chrScoreGlobal_t score
Definition chr_shared.h:406
int skills[SKILL_NUM_TYPES]
Definition chr_shared.h:122
This is the structure that should be used for data that is needed for tactical missions only.
float crouch
Definition inv_shared.h:151
int weaponSkill
Definition inv_shared.h:162
vec2_t spread
Definition inv_shared.h:146
a local entity
actorModes_t actorMode
vec3_t origin
actorSizeEnum_t fieldSize
pos3_t pos
const fireDef_t * fd
pos3_t mousePendPos
struct le_s * clientAction
static ipos3_t wpMins
world min and max values converted from vec to pos
Definition routing.cpp:35
static ipos3_t wpMaxs
Definition routing.cpp:35
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
pos_t pos3_t[3]
Definition ufotypes.h:58
vec_t vec3_t[3]
Definition ufotypes.h:39
ipos_t ipos3_t[3]
Definition ufotypes.h:70
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorCompare(a, b)
Definition vector.h:63
#define VectorSet(v, x, y, z)
Definition vector.h:59