]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/resources.qc
Merge branch 'master' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / resources.qc
1 #include "resources.qh"
2
3 /// \file
4 /// \brief Source file that contains implementation of the resource system.
5 /// \author Lyberta
6 /// \copyright GNU GPLv2 or any later version.
7
8 #include "autocvars.qh"
9 #include "miscfunctions.qh"
10
11 float GetResourceLimit(entity e, int res_type)
12 {
13         if(!IS_PLAYER(e))
14                 return RES_LIMIT_NONE; // no limits on non-players
15
16         float limit;
17         switch (res_type)
18         {
19                 case RES_HEALTH:
20                 {
21                         limit = autocvar_g_balance_health_limit;
22                         break;
23                 }
24                 case RES_ARMOR:
25                 {
26                         limit = autocvar_g_balance_armor_limit;
27                         break;
28                 }
29                 case RES_SHELLS:
30                 {
31                         limit = g_pickup_shells_max;
32                         break;
33                 }
34                 case RES_BULLETS:
35                 {
36                         limit = g_pickup_nails_max;
37                         break;
38                 }
39                 case RES_ROCKETS:
40                 {
41                         limit = g_pickup_rockets_max;
42                         break;
43                 }
44                 case RES_CELLS:
45                 {
46                         limit = g_pickup_cells_max;
47                         break;
48                 }
49                 case RES_PLASMA:
50                 {
51                         limit = g_pickup_plasma_max;
52                         break;
53                 }
54                 case RES_FUEL:
55                 {
56                         limit = autocvar_g_balance_fuel_limit;
57                         break;
58                 }
59                 default:
60                 {
61                         error("GetResourceLimit: Invalid resource type.");
62                         return 0;
63                 }
64         }
65         MUTATOR_CALLHOOK(GetResourceLimit, e, res_type, limit);
66         limit = M_ARGV(2, float);
67         if (limit > RES_AMOUNT_HARD_LIMIT)
68         {
69                 limit = RES_AMOUNT_HARD_LIMIT;
70         }
71         return limit;
72 }
73
74 float GetResource(entity e, int res_type)
75 {
76         return e.(GetResourceField(res_type));
77 }
78
79 bool SetResourceExplicit(entity e, int res_type, float amount)
80 {
81         .float res_field = GetResourceField(res_type);
82         if (e.(res_field) != amount)
83         {
84                 e.(res_field) = amount;
85                 return true;
86         }
87         return false;
88 }
89
90 void SetResource(entity e, int res_type, float amount)
91 {
92         bool forbid = MUTATOR_CALLHOOK(SetResource, e, res_type, amount);
93         if (forbid)
94         {
95                 return;
96         }
97         res_type = M_ARGV(1, int);
98         amount = M_ARGV(2, float);
99         float max_amount = GetResourceLimit(e, res_type); // TODO: should allow overriding these limits if cheats are enabled!
100         float amount_wasted = 0;
101         if (amount > max_amount && max_amount != RES_LIMIT_NONE)
102         {
103                 amount_wasted = amount - max_amount;
104                 amount = max_amount;
105         }
106         bool changed = SetResourceExplicit(e, res_type, amount);
107         if (changed)
108         {
109                 MUTATOR_CALLHOOK(ResourceAmountChanged, e, res_type, amount);
110         }
111         if (amount_wasted == 0)
112         {
113                 return;
114         }
115         MUTATOR_CALLHOOK(ResourceWasted, e, res_type, amount_wasted);
116 }
117
118 void GiveResource(entity receiver, int res_type, float amount)
119 {
120         if (amount <= 0)
121         {
122                 return;
123         }
124         bool forbid = MUTATOR_CALLHOOK(GiveResource, receiver, res_type, amount);
125         if (forbid)
126         {
127                 return;
128         }
129         res_type = M_ARGV(1, int);
130         amount = M_ARGV(2, float);
131         if (amount <= 0)
132         {
133                 return;
134         }
135         SetResource(receiver, res_type, GetResource(receiver, res_type) + amount);
136         switch (res_type)
137         {
138                 case RES_HEALTH:
139                 {
140                         receiver.pauserothealth_finished =
141                                 max(receiver.pauserothealth_finished, time +
142                                 autocvar_g_balance_pause_health_rot);
143                         return;
144                 }
145                 case RES_ARMOR:
146                 {
147                         receiver.pauserotarmor_finished =
148                                 max(receiver.pauserotarmor_finished, time +
149                                 autocvar_g_balance_pause_armor_rot);
150                         return;
151                 }
152                 case RES_FUEL:
153                 {
154                         receiver.pauserotfuel_finished = max(receiver.pauserotfuel_finished,
155                                 time + autocvar_g_balance_pause_fuel_rot);
156                         return;
157                 }
158         }
159 }
160
161 void GiveResourceWithLimit(entity receiver, int res_type, float amount, float limit)
162 {
163         if (amount <= 0)
164         {
165                 return;
166         }
167         bool forbid = MUTATOR_CALLHOOK(GiveResourceWithLimit, receiver, res_type, amount, limit);
168         if (forbid)
169         {
170                 return;
171         }
172         res_type = M_ARGV(1, int);
173         amount = M_ARGV(2, float);
174         limit = M_ARGV(3, float);
175         if (amount <= 0)
176         {
177                 return;
178         }
179         float current_amount = GetResource(receiver, res_type);
180         if (current_amount + amount > limit && limit != RES_LIMIT_NONE)
181         {
182                 amount = limit - current_amount;
183         }
184         GiveResource(receiver, res_type, amount);
185 }
186
187 void TakeResource(entity receiver, int res_type, float amount)
188 {
189         if (amount <= 0)
190         {
191                 return;
192         }
193         bool forbid = MUTATOR_CALLHOOK(TakeResource, receiver, res_type, amount);
194         if (forbid)
195         {
196                 return;
197         }
198         res_type = M_ARGV(1, int);
199         amount = M_ARGV(2, float);
200         if (amount <= 0)
201         {
202                 return;
203         }
204         SetResource(receiver, res_type, GetResource(receiver, res_type) - amount);
205 }
206
207 void TakeResourceWithLimit(entity receiver, int res_type, float amount, float limit)
208 {
209         if (amount <= 0)
210         {
211                 return;
212         }
213         bool forbid = MUTATOR_CALLHOOK(TakeResourceWithLimit, receiver, res_type, amount, limit);
214         if (forbid)
215         {
216                 return;
217         }
218         res_type = M_ARGV(1, int);
219         amount = M_ARGV(2, float);
220         limit = M_ARGV(3, float);
221         if (amount <= 0)
222         {
223                 return;
224         }
225         float current_amount = GetResource(receiver, res_type);
226         if (current_amount - amount < -limit)
227         {
228                 amount = -limit + current_amount;
229         }
230         TakeResource(receiver, res_type, amount);
231 }
232
233 void GiveOrTakeResource(entity receiver, int res_type, float amount)
234 {
235         if(amount < 0)
236         {
237                 TakeResource(receiver, res_type, amount * -1);
238         }
239         else
240         {
241                 GiveResource(receiver, res_type, amount);
242         }
243 }
244
245 void GiveOrTakeResourceWithLimit(entity receiver, int res_type, float amount, float limit)
246 {
247         if(amount < 0)
248         {
249                 TakeResourceWithLimit(receiver, res_type, amount * -1, limit);
250         }
251         else
252         {
253                 GiveResourceWithLimit(receiver, res_type, amount, limit);
254         }
255 }
256
257 int GetResourceType(.float res_field)
258 {
259         switch (res_field)
260         {
261                 case health: { return RES_HEALTH; }
262                 case armorvalue: { return RES_ARMOR; }
263                 case ammo_shells: { return RES_SHELLS; }
264                 case ammo_nails: { return RES_BULLETS; }
265                 case ammo_rockets: { return RES_ROCKETS; }
266                 case ammo_cells: { return RES_CELLS; }
267                 case ammo_plasma: { return RES_PLASMA; }
268                 case ammo_fuel: { return RES_FUEL; }
269         }
270         error("GetResourceType: Invalid field.");
271         return 0;
272 }
273
274 .float GetResourceField(int res_type)
275 {
276         switch (res_type)
277         {
278                 case RES_HEALTH: { return health; }
279                 case RES_ARMOR: { return armorvalue; }
280                 case RES_SHELLS: { return ammo_shells; }
281                 case RES_BULLETS: { return ammo_nails; }
282                 case RES_ROCKETS: { return ammo_rockets; }
283                 case RES_CELLS: { return ammo_cells; }
284                 case RES_PLASMA: { return ammo_plasma; }
285                 case RES_FUEL: { return ammo_fuel; }
286         }
287         error("GetResourceField: Invalid resource type.");
288         return health;
289 }