FS2_Open
Open source remastering of the Freespace 2 engine
objectshield.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  */
8 
9 
10 
11 #include "math/staticrand.h"
12 #include "network/multi.h"
13 #include "object/object.h"
14 #include "object/objectshield.h"
15 #include "ship/ship.h"
16 #include "ship/subsysdamage.h"
17 
18 #include <limits.h>
19 
20 
21 float shield_get_strength(object *objp)
22 {
23  // no shield system, no strength!
24  if (objp->flags & OF_NO_SHIELDS)
25  return 0.0f;
26 
27  int i;
28  float strength = 0.0f;
29 
30  for (i = 0; i < objp->n_quadrants; i++)
31  strength += shield_get_quad(objp, i);
32 
33  return strength;
34 }
35 
36 void shield_set_strength(object *objp, float strength)
37 {
38  int i;
39 
40  for (i = 0; i < objp->n_quadrants; i++)
41  shield_set_quad(objp, i, strength / objp->n_quadrants);
42 }
43 
44 // Recharge whole shield.
45 // Apply delta/n_quadrants to each shield section.
46 void shield_add_strength(object *objp, float delta)
47 {
48  // if we aren't going to change anything anyway then just bail
49  if (delta == 0.0f)
50  return;
51 
52  float shield_str = shield_get_strength(objp);
53  float shield_recharge_limit = Ships[objp->instance].ship_max_shield_strength * Ships[objp->instance].max_shield_recharge;
54 
55  if (shield_str >= shield_recharge_limit)
56  return;
57 
59  || delta <= 0.0f) //SUSHI: We don't want smart shield management for negative delta
60  {
61  // set the limit for the shield recharge
62  if ((delta > 0.0f) && ((shield_str + delta) > shield_recharge_limit))
63  delta = shield_recharge_limit - shield_str;
64 
65  for (int i = 0; i < objp->n_quadrants; i++)
66  shield_add_quad(objp, i, delta / objp->n_quadrants);
67  }
68  else
69  {
70  float section_max = shield_get_max_quad(objp);
71 
72  // smart shield repair
73  while (delta > 0.0f)
74  {
75  //WMC - Set to INT_MAX so that this is set to something
76  float weakest = i2fl(INT_MAX);
77  int weakest_idx = -1;
78 
79  // find weakest shield quadrant
80  for (int i = 0; i < objp->n_quadrants; i++)
81  {
82  float quad = shield_get_quad(objp, i);
83  if (weakest_idx < 0 || quad < weakest)
84  {
85  weakest = quad;
86  weakest_idx = i;
87  }
88  }
89 
90  // all quads are at full strength
91  if (weakest >= section_max)
92  break;
93 
94  // set the limit for the shield recharge
95  if ((delta > 0.0f) && ((shield_str + delta) > shield_recharge_limit))
96  delta = shield_recharge_limit - shield_str;
97 
98  // throw all possible shield power at this quadrant
99  // if there's any left over then apply it to the next weakest on the next pass
100  float xfer_amount;
101  if (weakest + delta > section_max)
102  xfer_amount = section_max - weakest;
103  else
104  xfer_amount = delta;
105 
106  shield_add_quad(objp, weakest_idx, xfer_amount);
107  delta -= xfer_amount;
108  }
109  }
110 }
111 
112 static double factor = 1.0 / (log(50.0) - log(1.0));
113 
114 // Goober5000
115 float scale_quad(float generator_fraction, float quad_strength)
116 {
117  // the following formula makes a nice logarithmic curve between 1 and 50,
118  // when x goes from 0 to 100:
119  //
120  // ln(x) * (100 - 0)
121  // -----------------
122  // ln(50) - ln(1)
123  //
124  float effective_strength = quad_strength * ((float)log(generator_fraction) * (float)factor);
125 
126  // ensure not negative, which may happen if the shield gets below 1 percent
127  // (since we're dealing with logs)
128  if (effective_strength < 0.0f)
129  return 0.0f;
130  else
131  return effective_strength;
132 }
133 
134 // Goober5000
135 float shield_get_quad(object *objp, int quadrant_num)
136 {
137  // no shield system, no strength!
138  if (objp->flags & OF_NO_SHIELDS)
139  return 0.0f;
140 
141  // check array bounds
142  Assert(quadrant_num >= 0 && quadrant_num < objp->n_quadrants);
143  if (quadrant_num < 0 || quadrant_num >= objp->n_quadrants)
144  return 0.0f;
145 
146  if (objp->type != OBJ_SHIP && objp->type != OBJ_START)
147  return 0.0f;
148 
149  //WMC - I removed SUBSYSTEM_SHIELD_GENERATOR to prevent pilot file
150  // corruption, so comment all this out...
151  /*
152  // yarr!
153  ship_subsys_info *ssip = &Ships[objp->instance].subsys_info[SUBSYSTEM_SHIELD_GENERATOR];
154 
155  // do we have a shield generator?
156  if (ssip->num > 0 && !Fred_running)
157  {
158  // rules for shield generator affecting coverage:
159  // 1. if generator above 50%, effective strength = actual strength
160  // 2. if generator below 50%, effective strength uses the scale_quad formula
161  // 3. if generator below 30%, shields only have a sqrt(generator strength)
162  // chance of working, in addition to #2
163  float generator_fraction = ssip->current_hits / ssip->total_hits;
164 
165  if (generator_fraction > MIN_SHIELDS_FOR_FULL_STRENGTH)
166  {
167  return objp->shield_quadrant[quadrant_num];
168  }
169  else if (generator_fraction > MIN_SHIELDS_FOR_FULL_COVERAGE)
170  {
171  return scale_quad(generator_fraction, objp->shield_quadrant[quadrant_num]);
172  }
173  else
174  {
175  // randomize according to this object and the current time
176  // (Missiontime >> 13 is eighths of a second)
177  float rand_num = static_randf(OBJ_INDEX(objp) ^ (Missiontime >> 13));
178 
179  // maybe flicker the shield
180  if (rand_num < sqrt(generator_fraction))
181  return scale_quad(generator_fraction, objp->shield_quadrant[quadrant_num]);
182  else
183  return 0.0f;
184  }
185  }
186  // no shield generator, so behave as normal
187  else
188  */
189  return objp->shield_quadrant[quadrant_num];
190 }
191 
192 // Goober5000
193 void shield_set_quad(object *objp, int quadrant_num, float strength)
194 {
195  // check array bounds
196  Assert(quadrant_num >= 0 && quadrant_num < objp->n_quadrants);
197  if (quadrant_num < 0 || quadrant_num >= objp->n_quadrants)
198  return;
199 
200  // check range
201  if (strength < 0.0f)
202  strength = 0.0f;
203  float max_quad = shield_get_max_quad(objp);
204  if (strength > max_quad)
205  strength = max_quad;
206 
207  objp->shield_quadrant[quadrant_num] = strength;
208 }
209 
210 // Goober5000
211 void shield_add_quad(object *objp, int quadrant_num, float delta)
212 {
213  // if we aren't going to change anything anyway then just bail
214  if (delta == 0.0f)
215  return;
216 
217  // check array bounds
218  Assert(quadrant_num >= 0 && quadrant_num < objp->n_quadrants);
219  if (quadrant_num < 0 || quadrant_num >= objp->n_quadrants)
220  return;
221 
222  // important: don't use shield_get_quad here
223  float strength = objp->shield_quadrant[quadrant_num] + delta;
224 
225  // check range
226  if (strength < 0.0f)
227  strength = 0.0f;
228  float max_quad = shield_get_max_quad(objp);
229  if (strength > max_quad)
230  strength = max_quad;
231 
232  objp->shield_quadrant[quadrant_num] = strength;
233 }
234 
235 // Goober5000
237 {
238  if (objp->type != OBJ_SHIP && objp->type != OBJ_START)
239  return 0.0f;
240 
242 }
243 
244 void shield_set_max_strength(object *objp, float newmax)
245 {
246  if(objp->type != OBJ_SHIP)
247  return;
248 
249  Ships[objp->instance].ship_max_shield_strength = newmax;
250 }
251 
252 // Goober5000
253 float shield_get_max_quad(object *objp)
254 {
255  return shield_get_max_strength(objp) / objp->n_quadrants;
256 }
257 
258 // ***** This is the version that works on a quadrant basis.
259 // Return absolute amount of damage not applied.
260 float shield_apply_damage(object *objp, int quadrant_num, float damage)
261 {
262  float remaining_damage;
263 
264  // multiplayer clients bail here if nodamage
265  // if(MULTIPLAYER_CLIENT && (Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
266  if (MULTIPLAYER_CLIENT)
267  return damage;
268 
269  // check array bounds
270  Assert(quadrant_num >= 0 && quadrant_num < objp->n_quadrants);
271  if ((quadrant_num < 0) || (quadrant_num >= objp->n_quadrants))
272  return damage;
273 
274  if (objp->type != OBJ_SHIP && objp->type != OBJ_START)
275  return damage;
276 
277  Ai_info[Ships[objp->instance].ai_index].last_hit_quadrant = quadrant_num;
278 
279  remaining_damage = damage - shield_get_quad(objp, quadrant_num);
280  if (remaining_damage > 0.0f)
281  {
282  shield_set_quad(objp, quadrant_num, 0.0f);
283  return remaining_damage;
284  }
285  else
286  {
287  shield_add_quad(objp, quadrant_num, -damage);
288  return 0.0f;
289  }
290 }
291 
292 // Returns true if the shield presents any opposition to something
293 // trying to force through it.
294 // If quadrant is -1, looks at entire shield, otherwise
295 // just one quadrant
296 int shield_is_up(object *objp, int quadrant_num)
297 {
298  if ((quadrant_num >= 0) && (quadrant_num < objp->n_quadrants))
299  {
300  // Just check one quadrant
301  float quad = shield_get_quad(objp, quadrant_num);
302 
303  if (quad > MAX(2.0f, 0.1f * shield_get_max_quad(objp)))
304  return 1;
305  }
306  else
307  {
308  // Check all quadrants
309  float strength = shield_get_strength(objp);
310 
311  if (strength > MAX(2.0f * objp->n_quadrants, 0.1f * shield_get_max_strength(objp)))
312  return 1;
313  }
314 
315  return 0; // no shield strength
316 }
317 
#define MULTIPLAYER_CLIENT
Definition: multi.h:132
int i
Definition: multi_pxo.cpp:466
float shield_get_strength(object *objp)
float ship_max_shield_strength
Definition: ship.h:596
Assert(pm!=NULL)
int ai_index
Definition: ship.h:538
GLclampf f
Definition: Glext.h:7097
#define OF_NO_SHIELDS
Definition: object.h:110
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
float factor
Definition: lua.cpp:440
int n_quadrants
Definition: object.h:158
object * objp
Definition: lua.cpp:3105
int ai_profile_flags
Definition: ai.h:463
int instance
Definition: object.h:150
#define OBJ_START
Definition: object.h:35
float shield_get_max_strength(object *objp)
#define delta
Definition: fvi.cpp:418
void shield_set_quad(object *objp, int quadrant_num, float strength)
void shield_add_strength(object *objp, float delta)
#define OBJ_SHIP
Definition: object.h:32
int shield_is_up(object *objp, int quadrant_num)
float shield_apply_damage(object *objp, int quadrant_num, float damage)
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void shield_add_quad(object *objp, int quadrant_num, float delta)
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
float shield_get_quad(object *objp, int quadrant_num)
SCP_vector< float > shield_quadrant
Definition: object.h:159
void shield_set_max_strength(object *objp, float newmax)
void shield_set_strength(object *objp, float strength)
#define i2fl(i)
Definition: floating.h:32
#define MAX(a, b)
Definition: pstypes.h:299
#define AIPF_SMART_SHIELD_MANAGEMENT
Definition: ai_profiles.h:21
uint flags
Definition: object.h:151
float shield_get_max_quad(object *objp)
char type
Definition: object.h:146
float scale_quad(float generator_fraction, float quad_strength)
float max_shield_recharge
Definition: ship.h:599
int last_hit_quadrant
Definition: ai.h:421