1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 Created for non-duplication of code between mac and SDL ports.
21 (Loren Petrich and others)
22
23 Jan 25, 2002 (Br'fin (Jeremy Parsons)):
24 Disabled network_speaker_idle_proc under Carbon
25
26 Mar 08, 2002 (Woody Zenfell):
27 Enabled network_microphone_idle_proc (in global_idle_proc()) under SDL
28 */
29
30 bool CheatsActive = false;
31 bool chat_input_mode = false;
32
33 #include "cseries.h"
34
35 #include "XML_ParseTreeRoot.h"
36 #include "interface.h"
37 #include "world.h"
38 #include "screen.h"
39 #include "map.h"
40 #include "shell.h"
41 #include "preferences.h"
42 #include "vbl.h"
43 #include "player.h"
44 #include "Music.h"
45 #include "items.h"
46 #include "network_sound.h"
47 #include "TextStrings.h"
48 #include "InfoTree.h"
49
50 #include <ctype.h>
51
52
53 extern void process_new_item_for_reloading(short player_index, short item_type);
54 extern bool try_and_add_player_item(short player_index, short type);
55 extern void mark_shield_display_as_dirty();
56 extern void mark_oxygen_display_as_dirty();
57 extern void accelerate_monster(short monster_index, world_distance vertical_velocity,
58 angle direction, world_distance velocity);
59 extern void network_speaker_idle_proc(void);
60 extern void update_interface(short time_elapsed);
61
62
63 // Cheat-keyword definition: tag and associated text string
64
65 #define MAXIMUM_KEYWORD_LENGTH 20
66
67 struct keyword_data
68 {
69 short tag;
70 char keyword[MAXIMUM_KEYWORD_LENGTH+1]; /* in uppercase */
71 };
72
73
74 enum // cheat tags
75 {
76 _tag_health,
77 _tag_oxygen,
78 _tag_map,
79 _tag_fusion,
80 _tag_invincible,
81 _tag_invisible,
82 _tag_extravision,
83 _tag_infravision,
84 _tag_pistol,
85 _tag_rifle,
86 _tag_missile, // LP change: corrected spelling
87 _tag_toaster, // flame-thrower
88 _tag_pzbxay,
89 _tag_shotgun, // LP addition
90 _tag_smg, // LP addition
91 _tag_ammo,
92 _tag_pathways,
93 _tag_view,
94 _tag_jump,
95 _tag_aslag,
96 _tag_save
97 };
98
99 void AddItemsToPlayer(short ItemType, short MaxNumber);
100
101 // Here, only one is added, unless the number of items is at least as great as MaxNumber
102 void AddOneItemToPlayer(short ItemType, short MaxNumber);
103
104 // LP addition: XML support for controlling whether cheats are active
105 keyword_data *original_keywords = NULL;
106
107 static keyword_data keywords[]=
108 {
109 {_tag_health, "NRG"},
110 {_tag_oxygen, "OTWO"},
111 {_tag_map, "MAP"},
112 {_tag_invisible, "BYE"},
113 {_tag_invincible, "NUKE"},
114 {_tag_infravision, "SEE"},
115 {_tag_extravision, "WOW"},
116 {_tag_pistol, "MAG"},
117 {_tag_rifle, "RIF"},
118 {_tag_missile, "POW"},
119 {_tag_toaster, "TOAST"},
120 {_tag_fusion, "MELT"},
121 {_tag_shotgun, "PUFF"},
122 {_tag_smg, "ZIP"},
123 {_tag_pzbxay, "PZBXAY"}, // the alien shotgon, in the phfor's language
124 {_tag_ammo, "AMMO"},
125 {_tag_jump, "QWE"},
126 {_tag_aslag, "SHIT"},
127 {_tag_save, "YOURMOM"}
128 };
129
130
131
AddItemsToPlayer(short ItemType,short MaxNumber)132 void AddItemsToPlayer(short ItemType, short MaxNumber)
133 {
134 for (int i=0; i<MaxNumber; i++)
135 try_and_add_player_item(local_player_index,ItemType);
136 }
137
AddOneItemToPlayer(short ItemType,short MaxNumber)138 void AddOneItemToPlayer(short ItemType, short MaxNumber)
139 {
140 local_player->items[ItemType] = MAX(local_player->items[ItemType],0);
141 if (local_player->items[ItemType] < MaxNumber)
142 try_and_add_player_item(local_player_index,ItemType);
143 }
144
145
handle_keyword(int tag)146 void handle_keyword(int tag)
147 {
148
149 switch (tag)
150 {
151 case _tag_health:
152 if (local_player->suit_energy<PLAYER_MAXIMUM_SUIT_ENERGY)
153 {
154 local_player->suit_energy= PLAYER_MAXIMUM_SUIT_ENERGY;
155 }
156 else
157 {
158 if (local_player->suit_energy<2*PLAYER_MAXIMUM_SUIT_ENERGY)
159 {
160 local_player->suit_energy= 2*PLAYER_MAXIMUM_SUIT_ENERGY;
161 }
162 else
163 {
164 local_player->suit_energy= MAX(local_player->suit_energy, 3*PLAYER_MAXIMUM_SUIT_ENERGY);
165 }
166 }
167 mark_shield_display_as_dirty();
168 break;
169 case _tag_oxygen:
170 local_player->suit_oxygen= MAX(local_player->suit_oxygen,PLAYER_MAXIMUM_SUIT_OXYGEN);
171 mark_oxygen_display_as_dirty();
172 break;
173 case _tag_map:
174 dynamic_world->game_information.game_options^= (_overhead_map_shows_items|_overhead_map_shows_monsters|_overhead_map_shows_projectiles);
175 break;
176 case _tag_invincible:
177 process_player_powerup(local_player_index, _i_invincibility_powerup);
178 break;
179 case _tag_invisible:
180 process_player_powerup(local_player_index, _i_invisibility_powerup);
181 break;
182 case _tag_infravision:
183 process_player_powerup(local_player_index, _i_infravision_powerup);
184 break;
185 case _tag_extravision:
186 process_player_powerup(local_player_index, _i_extravision_powerup);
187 break;
188 case _tag_jump:
189 accelerate_monster(local_player->monster_index, WORLD_ONE/10, 0, 0);
190 break;
191 // LP: changed these cheats and added new ones:
192 case _tag_pistol:
193 AddOneItemToPlayer(_i_magnum,2);
194 AddItemsToPlayer(_i_magnum_magazine,10);
195 break;
196 case _tag_rifle:
197 AddItemsToPlayer(_i_assault_rifle,10);
198 AddItemsToPlayer(_i_assault_rifle_magazine,10);
199 AddItemsToPlayer(_i_assault_grenade_magazine,10);
200 break;
201 case _tag_missile:
202 AddItemsToPlayer(_i_missile_launcher,1);
203 AddItemsToPlayer(_i_missile_launcher_magazine,10);
204 break;
205 case _tag_toaster:
206 AddItemsToPlayer(_i_flamethrower,1);
207 AddItemsToPlayer(_i_flamethrower_canister,10);
208 break;
209 case _tag_fusion:
210 AddItemsToPlayer(_i_plasma_pistol,1);
211 AddItemsToPlayer(_i_plasma_magazine,10);
212 break;
213 case _tag_pzbxay:
214 AddItemsToPlayer(_i_alien_shotgun,1);
215 break;
216 case _tag_shotgun:
217 AddOneItemToPlayer(_i_shotgun,2);
218 AddItemsToPlayer(_i_shotgun_magazine,10);
219 break;
220 case _tag_smg:
221 AddOneItemToPlayer(_i_smg,2);
222 AddItemsToPlayer(_i_smg_ammo,10);
223 break;
224 case _tag_save:
225 save_game();
226 break;
227 // LP guess as to what might be good: ammo-only version of "aslag"
228 case _tag_ammo:
229 {
230 short items[]= { _i_assault_rifle, _i_magnum, _i_missile_launcher, _i_flamethrower,
231 _i_plasma_pistol, _i_alien_shotgun, _i_shotgun,
232 _i_assault_rifle_magazine, _i_assault_grenade_magazine,
233 _i_magnum_magazine, _i_missile_launcher_magazine, _i_flamethrower_canister,
234 _i_plasma_magazine, _i_shotgun_magazine, _i_shotgun, _i_smg, _i_smg_ammo};
235
236 for(unsigned index= 0; index<sizeof(items)/sizeof(short); ++index)
237 {
238 switch(get_item_kind(items[index]))
239 {
240 case _ammunition:
241 AddItemsToPlayer(items[index],10);
242 break;
243 }
244 }
245 }
246 break;
247 case _tag_aslag:
248 {
249 // LP change: added the SMG and its ammo
250 short items[]= { _i_assault_rifle, _i_magnum, _i_missile_launcher, _i_flamethrower,
251 _i_plasma_pistol, _i_alien_shotgun, _i_shotgun,
252 _i_assault_rifle_magazine, _i_assault_grenade_magazine,
253 _i_magnum_magazine, _i_missile_launcher_magazine, _i_flamethrower_canister,
254 _i_plasma_magazine, _i_shotgun_magazine, _i_shotgun, _i_smg, _i_smg_ammo};
255
256 for(unsigned index= 0; index<sizeof(items)/sizeof(short); ++index)
257 {
258 switch(get_item_kind(items[index]))
259 {
260 case _weapon:
261 if(items[index]==_i_shotgun || items[index]==_i_magnum)
262 {
263 AddOneItemToPlayer(items[index],2);
264 } else {
265 AddItemsToPlayer(items[index],1);
266 }
267 break;
268
269 case _ammunition:
270 AddItemsToPlayer(items[index],10);
271 break;
272
273 case _powerup:
274 case _weapon_powerup:
275 break;
276
277 default:
278 break;
279 }
280 process_new_item_for_reloading(local_player_index, items[index]);
281 }
282 }
283 local_player->suit_energy = MAX(local_player->suit_energy, 3*PLAYER_MAXIMUM_SUIT_ENERGY);
284 update_interface(NONE);
285 break;
286
287 default:
288 break;
289 }
290
291 return;
292
293 }
294
295 /*
296 * Called regularly during event loops
297 */
298
global_idle_proc(void)299 void global_idle_proc(void)
300 {
301 Music::instance()->Idle();
302 network_speaker_idle_proc();
303 network_microphone_idle_proc();
304 SoundManager::instance()->Idle();
305 }
306
307 /*
308 * Somebody wants to do something important; free as much temporary memory as possible
309 */
310
free_and_unlock_memory(void)311 void free_and_unlock_memory(void)
312 {
313 SoundManager::instance()->StopAllSounds();
314 }
315
316 /*
317 * Special version of malloc() used for level transitions, frees some
318 * memory if possible
319 */
320
level_transition_malloc(size_t size)321 void *level_transition_malloc(
322 size_t size)
323 {
324 void *ptr= malloc(size);
325 if (!ptr)
326 {
327 SoundManager::instance()->UnloadAllSounds();
328
329 ptr= malloc(size);
330 if (!ptr)
331 {
332 unload_all_collections();
333
334 ptr= malloc(size);
335 }
336 }
337
338 return ptr;
339 }
340
341 // LP change: implementing Benad's "cheats always on"
342 // Originally, cheats were not on in the "FINAL" version
343 //
344 #define NUMBER_OF_KEYWORDS (sizeof(keywords)/sizeof(keyword_data))
345
346 static char keyword_buffer[MAXIMUM_KEYWORD_LENGTH+1];
347
process_keyword_key(char key)348 int process_keyword_key(
349 char key)
350 {
351 short tag = NONE;
352
353 // copy the buffer down and insert the new character
354 for (unsigned i=0;i<MAXIMUM_KEYWORD_LENGTH-1;++i)
355 {
356 keyword_buffer[i]= keyword_buffer[i+1];
357 }
358 keyword_buffer[MAXIMUM_KEYWORD_LENGTH-1]= toupper(key);
359 keyword_buffer[MAXIMUM_KEYWORD_LENGTH]= 0;
360
361 // any matches?
362 for (unsigned i=0; i<NUMBER_OF_KEYWORDS; ++i)
363 {
364 if (!strcmp(keywords[i].keyword, keyword_buffer+MAXIMUM_KEYWORD_LENGTH-strlen(keywords[i].keyword)))
365 {
366 // wipe the buffer if we have a match
367 memset(keyword_buffer, 0, MAXIMUM_KEYWORD_LENGTH);
368 tag= keywords[i].tag;
369 break;
370 }
371 }
372
373 return tag;
374 }
375
reset_mml_cheats()376 void reset_mml_cheats()
377 {
378 CheatsActive = false;
379 if (original_keywords)
380 {
381 for (int i = 0; i < NUMBER_OF_KEYWORDS; i++)
382 keywords[i] = original_keywords[i];
383 }
384 }
385
parse_mml_cheats(const InfoTree & root)386 void parse_mml_cheats(const InfoTree& root)
387 {
388 // back up old values first
389 if (!original_keywords)
390 {
391 original_keywords = (keyword_data *) malloc(sizeof(keywords));
392 assert(original_keywords);
393 for (int i = 0; i < NUMBER_OF_KEYWORDS; i++)
394 original_keywords[i] = keywords[i];
395 }
396
397 root.read_attr("on", CheatsActive);
398
399 BOOST_FOREACH(InfoTree ktree, root.children_named("keyword"))
400 {
401 int16 index;
402 if (!ktree.read_indexed("index", index, NUMBER_OF_KEYWORDS))
403 continue;
404
405 std::string word = ktree.get_value(std::string(""));
406 char *dest = keywords[index].keyword;
407 size_t decoded_len = DeUTF8_C(word.c_str(), word.size(), dest, MAXIMUM_KEYWORD_LENGTH);
408 for (size_t c = 0; c < decoded_len; c++, dest++)
409 *dest = toupper(*dest);
410 }
411 }
412