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