Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Power.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: Power.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Power generation and usage classes
13 */
14 
15 #include "MemDebug.h"
16 #include "Power.h"
17 #include "Ship.h"
18 #include "NetUtil.h"
19 
20 #include "Game.h"
21 
22 // +----------------------------------------------------------------------+
23 
24 static char* source_type[] = {
25  "sys.power.battery", "sys.power.auxilliary", "sys.power.fusion"
26 };
27 
28 static int source_value[] = {
29  1, 2, 4
30 };
31 
32 PowerSource::PowerSource(SUBTYPE s, double max_out, double f_ratio)
33 : System(POWER_SOURCE, (int) s, "Power", source_value[s], 0),
34 max_output((float) max_out), fuel_ratio((float) f_ratio),
35 route_changed(false), requested_power_level(1.0f)
36 {
37  name = Game::GetText(source_type[s]);
38  abrv = Game::GetText(Text(source_type[s]) + ".abrv");
39 
40  if (fuel_ratio < 1) {
41  switch (subtype) { // enough to last for [n] hours at full power
42  case BATTERY: fuel_ratio = max_output * 5 * 3600 / 100; break;
43  case AUX: fuel_ratio = max_output * 50 * 3600 / 100; break;
44  case FUSION: fuel_ratio = max_output * 100 * 3600 / 100; break;
45  }
46  }
47 
48  capacity = 100.0f;
49 
50  if (subtype != BATTERY) {
51  emcon_power[0] = 10;
52  emcon_power[1] = 50;
53  emcon_power[2] = 100;
54  }
55 }
56 
58 : System(p),
59 max_output(p.max_output), fuel_ratio(p.fuel_ratio),
60 route_changed(false), requested_power_level(1.0f)
61 {
62  Mount(p);
64 }
65 
66 // +----------------------------------------------------------------------+
67 
68 void
70 {
71  if (client) {
72  int old_src_index = client->GetSourceIndex();
73 
74  client->SetSourceIndex(GetID());
75  clients.append(client);
76  route_changed = true;
77 
78  if (ship && old_src_index != GetID())
80  }
81 }
82 
83 void
85 {
86  if (client && clients.contains(client)) {
87  client->SetSourceIndex(-1);
88  clients.remove(client);
89  route_changed = true;
90  }
91 }
92 
93 // +----------------------------------------------------------------------+
94 
95 int
97 {
98  return (int) capacity;
99 }
100 
101 void
103 {
104  if (hours > 0)
105  fuel_ratio = (float) (max_output * hours * 3600 / 100);
106 }
107 
108 // +----------------------------------------------------------------------+
109 
110 void
111 PowerSource::ExecFrame(double seconds)
112 {
113  if (seconds < 0.001)
114  seconds = 0.001;
115 
116  if (capacity <= 0)
117  capacity = 0;
118 
119  System::ExecFrame(seconds);
120 
121  double energy_requested = 0;
122  double energy_avail = 0;
123  double total_distrib = 0;
124 
125  // fuel leak?
126  if (availability < 0.4 && capacity > 0)
127  capacity -= (float) (0.03 * seconds);
128 
129  if (IsPowerOn() && capacity > 0) {
130  energy_avail = max_output * seconds * power_level * availability;
131 
133  power_level += (float) (seconds * 0.03); // thirty seconds to charge up
134 
137  }
138  else if (power_level > requested_power_level) {
139  power_level -= (float) (seconds * 0.10); // ten seconds to power down
140 
143  }
144  }
145 
146  ListIter<System> iter = clients;
147  while (++iter) {
148  System* sink = iter.value();
149 
150  if (sink->IsPowerOn()) {
151  double joules = sink->GetRequest(seconds);
152 
153  if (joules > 0) {
154  if (sink->IsPowerCritical()) {
155 
156  if (joules > energy_avail)
157  joules = energy_avail;
158 
159  energy_avail -= joules;
160  total_distrib += joules;
161  sink->Distribute(joules, seconds);
162  }
163  else {
164  energy_requested += joules;
165  }
166  }
167  }
168  else {
169  sink->Distribute(-0.2 * sink->GetCapacity() * seconds, seconds);
170  }
171  }
172 
173  if (energy_avail > 0) {
174 
175  // enough to go around:
176  if (energy_requested <= energy_avail) {
177  iter.reset();
178 
179  while (++iter) {
180  System* sink = iter.value();
181 
182  if (sink->IsPowerOn() && !sink->IsPowerCritical()) {
183  double joules = sink->GetRequest(seconds);
184  total_distrib += joules;
185  sink->Distribute(joules, seconds);
186  }
187  }
188  }
189 
190  // load balancing:
191  else {
192  iter.reset();
193  while (++iter) {
194  System* sink = iter.value();
195 
196  if (sink->IsPowerOn() && !sink->IsPowerCritical()) {
197  double request = sink->GetRequest(seconds);
198  double delivery = 0;
199 
200  if (request > 0)
201  delivery = energy_avail * (request/energy_requested);
202 
203  if (delivery > 0) {
204  total_distrib += delivery;
205  sink->Distribute(delivery, seconds);
206  }
207  }
208  }
209  }
210  }
211 
212  if (IsPowerOn() && capacity > 0 && !Game::Paused()) {
213  // reactors always burn at least 10% of max (to maintain operating temp):
214  if (subtype != BATTERY) {
215  double baseline = 0.1 * max_output * seconds;
216 
217  if (total_distrib < baseline)
218  total_distrib = baseline;
219  }
220 
221  // expend fuel:
222  if (total_distrib > 0) {
223  double effective_fuel_ratio = fuel_ratio;
224 
225  switch (Ship::GetFlightModel()) {
226  default:
227  case Ship::FM_STANDARD:
228  effective_fuel_ratio = 1 * fuel_ratio * (0.25 + 0.75 * availability);
229  break;
230 
231  case Ship::FM_RELAXED:
232  effective_fuel_ratio = 3 * fuel_ratio * (0.25 + 0.75 * availability);
233  break;
234 
235  case Ship::FM_ARCADE:
236  effective_fuel_ratio = 4 * fuel_ratio * (0.25 + 0.75 * availability);
237  break;
238  }
239 
240  capacity -= (float) (total_distrib / effective_fuel_ratio);
241  }
242  }
243 
244  else if (capacity <= 0) {
245  capacity = 0.0f;
246  PowerOff();
247  }
248 }
249 
250 // +--------------------------------------------------------------------+
251 
252 void
254 {
255  if (level > 100)
256  level = 100;
257  else if (level < 0)
258  level = 0;
259 
260  level /= 100;
261 
262  if (requested_power_level != level) {
263  // if the system is on emergency override power,
264  // do not let the EMCON system use this method
265  // to drop it back to normal power:
266  if (requested_power_level > 1 && level == 1) {
267  requested_power_level = 1.2f;
268  }
269 
270  else {
271  requested_power_level = (float) level;
272  }
273  }
274 }
275 
276 void
278 {
279  bool changed = false;
280 
281  if (over && requested_power_level != 1.2f) {
282  requested_power_level = 1.2f;
283  changed = true;
284  }
285 
286  else if (!over && requested_power_level > 1) {
287  requested_power_level = 1.0f;
288  changed = true;
289  }
290 
291  if (changed)
293 }
294 
295 void
296 PowerSource::DrainPower(double to_level)
297 {
298  if (to_level >= 0 && to_level < power_level)
299  power_level = (float) to_level;
300 }