Merge branch 'master' into terencehill/music_player
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator_new_toys.qc
1 /*
2
3 CORE    laser   vortex     lg      rl      cry     gl      elec    hagar   fireb   hook
4                                                                         vaporizer  porto
5                                                                         tuba
6
7 NEW             rifle   hlac    minel                           seeker
8 IDEAS                                   OPEN    flak    OPEN            FUN FUN FUN FUN
9
10
11
12 How this mutator works:
13  =======================
14
15 When a gun tries to spawn, this mutator is called. It will provide alternate
16 weaponreplace lists.
17
18 Entity:
19
20 {
21 "classname" "weapon_vortex"
22 "new_toys" "rifle"
23 }
24 -> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
25
26 {
27 "classname" "weapon_vortext"
28 "new_toys" "vortex rifle"
29 }
30 -> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
31
32 {
33 "classname" "weapon_vortex"
34 "new_toys" "vortex"
35 }
36 -> This is always a Vortex.
37
38 If the map specifies no "new_toys" argument
39
40 There will be two default replacements selectable: "replace all" and "replace random".
41 In "replace all" mode, e.g. Vortex will have the default replacement "rifle".
42 In "replace random" mode, Vortex will have the default replacement "vortex rifle".
43
44 This mutator's replacements run BEFORE regular weaponreplace!
45
46 The New Toys guns do NOT get a spawn function, so they can only ever be spawned
47 when this mutator is active.
48
49 Likewise, warmup, give all, give ALL and impulse 99 will not give them unless
50 this mutator is active.
51
52 Outside this mutator, they still can be spawned by:
53 - setting their start weapon cvar to 1
54 - give weaponname
55 - weaponreplace
56 - weaponarena (but all and most weapons arena again won't include them)
57
58 This mutator performs the default replacements on the DEFAULTS of the
59 start weapon selection.
60
61 These weapons appear in the menu's priority list, BUT get a suffix
62 "(Mutator weapon)".
63
64 Picking up a "new toys" weapon will not play standard weapon pickup sound, but
65 roflsound "New toys, new toys!" sound.
66
67 */
68
69 .string new_toys;
70
71 float autocvar_g_new_toys_autoreplace;
72 #define NT_AUTOREPLACE_NEVER 0
73 #define NT_AUTOREPLACE_ALWAYS 1
74 #define NT_AUTOREPLACE_RANDOM 2
75
76 MUTATOR_HOOKFUNCTION(nt_SetModname)
77 {
78         modname = "NewToys";
79         return 0;
80 }
81
82 float nt_IsNewToy(float w)
83 {
84         switch(w)
85         {
86                 case WEP_SEEKER:
87                 case WEP_MINE_LAYER:
88                 case WEP_HLAC:
89                 case WEP_RIFLE:
90                 case WEP_SHOCKWAVE:
91                         return TRUE;
92                 default:
93                         return FALSE;
94         }
95 }
96
97 string nt_GetFullReplacement(string w)
98 {
99         switch(w)
100         {
101                 case "hagar": return "seeker";
102                 case "devastator": return "minelayer";
103                 case "machinegun": return "hlac";
104                 case "vortex": return "rifle";
105                 case "shotgun": return "shockwave";
106                 default: return string_null;
107         }
108 }
109
110 string nt_GetReplacement(string w, float m)
111 {
112         if(m == NT_AUTOREPLACE_NEVER)
113                 return w;
114         string s = nt_GetFullReplacement(w);
115         if (!s)
116                 return w;
117         if(m == NT_AUTOREPLACE_RANDOM)
118                 s = strcat(w, " ", s);
119         return s;
120 }
121
122 MUTATOR_HOOKFUNCTION(nt_SetStartItems)
123 {
124         // rearrange start_weapon_default
125         // apply those bits that are set by start_weapon_defaultmask
126         // same for warmup
127
128         float i, j, k, n;
129
130         WepSet newdefault;
131         WepSet warmup_newdefault;
132
133         newdefault = '0 0 0';
134         warmup_newdefault = '0 0 0';
135
136         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
137         {
138                 entity e = get_weaponinfo(i);
139                 if(!e.weapon)
140                         continue;
141
142                 n = tokenize_console(nt_GetReplacement(e.netname, autocvar_g_new_toys_autoreplace));
143
144                 for(j = 0; j < n; ++j)
145                         for(k = WEP_FIRST; k <= WEP_LAST; ++k)
146                                 if(get_weaponinfo(k).netname == argv(j))
147                                 {
148                                         if(start_weapons & WepSet_FromWeapon(i))
149                                                 newdefault |= WepSet_FromWeapon(k);
150                                         if(warmup_start_weapons & WepSet_FromWeapon(i))
151                                                 warmup_newdefault |= WepSet_FromWeapon(k);
152                                 }
153         }
154
155         newdefault &= start_weapons_defaultmask;
156         start_weapons &= ~start_weapons_defaultmask;
157         start_weapons |= newdefault;
158
159         warmup_newdefault &= warmup_start_weapons_defaultmask;
160         warmup_start_weapons &= ~warmup_start_weapons_defaultmask;
161         warmup_start_weapons |= warmup_newdefault;
162
163         return 0;
164 }
165
166 MUTATOR_HOOKFUNCTION(nt_SetWeaponreplace)
167 {
168         // otherwise, we do replace
169         if(self.new_toys)
170         {
171                 // map defined replacement:
172                 ret_string = self.new_toys;
173         }
174         else
175         {
176                 // auto replacement:
177                 ret_string = nt_GetReplacement(other.netname, autocvar_g_new_toys_autoreplace);
178         }
179
180         // apply regular weaponreplace
181         ret_string = W_Apply_Weaponreplace(ret_string);
182
183         return 0;
184 }
185
186 MUTATOR_HOOKFUNCTION(nt_FilterItem)
187 {
188         if(nt_IsNewToy(self.weapon))
189                 self.item_pickupsound = "weapons/weaponpickup_new_toys.wav";
190         return 0;
191 }
192
193 MUTATOR_DEFINITION(mutator_new_toys)
194 {
195         MUTATOR_HOOK(SetModname, nt_SetModname, CBC_ORDER_ANY);
196         MUTATOR_HOOK(SetStartItems, nt_SetStartItems, CBC_ORDER_ANY);
197         MUTATOR_HOOK(SetWeaponreplace, nt_SetWeaponreplace, CBC_ORDER_LAST);
198         MUTATOR_HOOK(FilterItem, nt_FilterItem, CBC_ORDER_ANY);
199
200         MUTATOR_ONADD
201         {
202                 if(time > 1) // game loads at time 1
203                         error("This cannot be added at runtime\n");
204
205                 precache_sound("weapons/weaponpickup_new_toys.wav");
206
207                 // mark the guns as ok to use by e.g. impulse 99
208                 float i;
209                 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
210                         if(nt_IsNewToy(i))
211                                 get_weaponinfo(i).spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
212         }
213
214         MUTATOR_ONROLLBACK_OR_REMOVE
215         {
216                 float i;
217                 for(i = WEP_FIRST; i <= WEP_LAST; ++i)
218                         if(nt_IsNewToy(i))
219                                 get_weaponinfo(i).spawnflags |= WEP_FLAG_MUTATORBLOCKED;
220         }
221
222         MUTATOR_ONREMOVE
223         {
224                 print("This cannot be removed at runtime\n");
225                 return -1;
226         }
227
228         return 0;
229 }