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