1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4 
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 
24 
25 #include "3d_def.h"
26 
27 
28 void VH_UpdateScreen();
29 
30 void TakeDamage(
31     int16_t points,
32     objtype* attacker);
33 
34 void SetPlaneViewSize();
35 
36 void HealSelf(
37     int16_t points);
38 
39 void GiveWeapon(
40     int weapon);
41 
42 void DrawScore();
43 void SetPlaneViewSize();
44 
45 
46 /*
47 =============================================================================
48 
49  LOCAL CONSTANTS
50 
51 =============================================================================
52 */
53 
54 #define VIEWTILEX (viewwidth / 16)
55 #define VIEWTILEY (viewheight / 16)
56 
57 
58 /*
59 =============================================================================
60 
61  GLOBAL VARIABLES
62 
63 =============================================================================
64 */
65 
66 bool ForceLoadDefault = false;
67 
68 int16_t DebugKeys();
69 
70 
71 /*
72 =============================================================================
73 
74  LOCAL VARIABLES
75 
76 =============================================================================
77 */
78 
79 bool PP_step = false;
80 
81 int16_t maporgx;
82 int16_t maporgy;
83 
84 void ViewMap();
85 
86 
DebugMemory()87 void DebugMemory()
88 {
89     ::CenterWindow(22, 15);
90 
91     ::US_Print("k\nTics      :");
92     ::US_PrintUnsigned(tics);
93     ::US_Print("\nReal Tics :");
94     ::US_PrintUnsigned(realtics);
95 
96     if ((gamestate.flags & GS_DRAW_CEILING) != 0) {
97         ::US_Print("\n\nCeiling TEX: ");
98         ::US_PrintUnsigned(CeilingTile - START_TEXTURES);
99 
100         ::US_Print(" Floor TEX: ");
101         ::US_PrintUnsigned(FloorTile - START_TEXTURES);
102     } else {
103         ::US_Print("\n\nTop COL: ");
104         ::US_PrintUnsigned(TopColor & 0xFF);
105 
106         ::US_Print(" Bottom COL: ");
107         ::US_PrintUnsigned(BottomColor & 0xFF);
108     }
109 
110     if ((gamestate.flags & GS_LIGHTING) != 0) {
111         ::US_Print("\nShade div :");
112         ::US_PrintUnsigned(normalshade_div);
113 
114         ::US_Print("\nShade max :");
115         ::US_PrintUnsigned(shade_max);
116     }
117 
118     VW_UpdateScreen();
119     ::IN_Ack();
120 
121     ::WindowW = 253;
122     ::WindowH = 8;
123     ::fontnumber = 2;
124 
125     ::LatchDrawPic(0, 0, TOP_STATUSBARPIC);
126     ::ShadowPrintLocationText(sp_normal);
127 }
128 
CountObjects()129 void CountObjects()
130 {
131     int16_t i, total, count, active, inactive, doors;
132     objtype* obj;
133 
134     CenterWindow(16, 7);
135     active = inactive = count = doors = 0;
136 
137     US_Print("Total statics :");
138     total = static_cast<int16_t>(laststatobj - &statobjlist[0]);
139     US_PrintUnsigned(total);
140 
141     US_Print("\nIn use statics:");
142     for (i = 0; i < total; i++) {
143         if (statobjlist[i].shapenum != -1) {
144             count++;
145         } else {
146             doors++; // debug
147         }
148     }
149     US_PrintUnsigned(count);
150 
151     US_Print("\nDoors         :");
152     US_PrintUnsigned(doornum);
153 
154     for (obj = player->next; obj; obj = obj->next) {
155         if (obj->active) {
156             active++;
157         } else {
158             inactive++;
159         }
160     }
161 
162     US_Print("\nTotal actors  :");
163     US_PrintUnsigned(active + inactive);
164 
165     US_Print("\nActive actors :");
166     US_PrintUnsigned(active);
167 
168     VW_UpdateScreen();
169     IN_Ack();
170 }
171 
CountTotals()172 void CountTotals()
173 {
174     CenterWindow(20, 11);
175 
176     US_Print("  CURRENT MAP TOTALS\n");
177 
178     US_Print("\nTotal Enemy:\n");
179     US_PrintUnsigned(gamestuff.level[gamestate.mapon].stats.total_enemy);
180 
181     US_Print("\nTotal Points:\n");
182     US_PrintUnsigned(gamestuff.level[gamestate.mapon].stats.total_points);
183 
184     US_Print("\nTotal Informants:\n");
185     US_PrintUnsigned(gamestuff.level[gamestate.mapon].stats.total_inf);
186 
187     VW_UpdateScreen();
188     IN_Ack();
189 }
190 
ShowMap()191 void ShowMap()
192 {
193     objtype old_player;
194 
195     memcpy(&old_player, player, sizeof(objtype));
196     player->angle = 90;
197     player->x = player->y = ((int32_t)32 << TILESHIFT) + (TILEGLOBAL / 2);
198 
199     CenterWindow(20, 11);
200 
201     US_CPrint("CURRENT MAP\n\n ");
202 
203     auto old_flags = ::ExtraRadarFlags;
204     ::ExtraRadarFlags |= OV_ACTORS | OV_PUSHWALLS;
205 
206     ShowOverhead(160 - 32, py, 32, 0, OV_ACTORS | OV_SHOWALL | OV_KEYS | OV_PUSHWALLS);
207     VW_UpdateScreen();
208 
209     ::ExtraRadarFlags = old_flags;
210 
211     memcpy(player, &old_player, sizeof(objtype));
212     IN_Ack();
213 }
214 
215 
216 // ---------------------------------------------------------------------------
217 // IncRange - Incs a value to a MAX value (including max value)
218 //
219 // NOTE: Assumes that 0 is the lowest value
220 // ---------------------------------------------------------------------------
IncRange(uint16_t Value,uint16_t MaxValue)221 uint16_t IncRange(
222     uint16_t Value,
223     uint16_t MaxValue)
224 {
225     if (Value == MaxValue) {
226         Value = 0;
227     } else {
228         Value++;
229     }
230 
231     return Value;
232 }
233 
234 // ---------------------------------------------------------------------------
235 // DecRange - Decs a value to 0 and resets to MAX_VALUE
236 //
237 // NOTE: Assumes that 0 is the lowest value
238 // ---------------------------------------------------------------------------
DecRange(uint16_t Value,uint16_t MaxValue)239 uint16_t DecRange(
240     uint16_t Value,
241     uint16_t MaxValue)
242 {
243     if (Value == 0) {
244         Value = MaxValue;
245     } else {
246         Value--;
247     }
248 
249     return Value;
250 }
251 
252 
DebugKeys()253 int16_t DebugKeys()
254 {
255     char string[3];
256     bool esc;
257     int16_t level;
258 
259     if (Keyboard[ScanCode::sc_a]) {       // A = Show Actors on AutoMap
260         ExtraRadarFlags ^= OV_ACTORS;
261         CenterWindow(24, 3);
262         if (ExtraRadarFlags & OV_ACTORS) {
263             US_PrintCentered("AUTOMAP: Show Actors ON");
264         } else {
265             US_PrintCentered("AUTOMAP: Show Actors OFF");
266         }
267         VW_UpdateScreen();
268         IN_Ack();
269         return 1;
270     }
271 
272     if (Keyboard[ScanCode::sc_k]) { // K = Map Content totals
273         CountTotals();
274         return 1;
275     } else if (Keyboard[ScanCode::sc_c]) { // C = count objects
276         CountObjects();
277         return 1;
278     } else if (Keyboard[ScanCode::sc_r]) { // R = show full map
279         ShowMap();
280         return 1;
281     } else if (Keyboard[ScanCode::sc_d]) { // D = Dumb/Blind Objects (Player Invisable)
282         CenterWindow(19, 3);
283         ::PlayerInvisable = !::PlayerInvisable;
284         if (PlayerInvisable) {
285             US_PrintCentered("Player Invisible!");
286         } else {
287             US_PrintCentered("Player visible");
288         }
289 
290         VW_UpdateScreen();
291         IN_Ack();
292         return 1;
293     } else if (Keyboard[ScanCode::sc_e]) { // E = Win Mission
294         CenterWindow(19, 3);
295         US_PrintCentered("Instant Wiener!");
296         InstantWin = 1;
297         playstate = ex_victorious;
298         VW_UpdateScreen();
299         IN_Ack();
300         return 1;
301     } else if (Keyboard[ScanCode::sc_f]) { // F = facing spot
302         CenterWindow(18, 5);
303         US_Print("X:");
304         US_PrintUnsigned(player->x);
305         US_Print("  ");
306         US_PrintUnsigned(player->x >> TILESHIFT);
307         US_Print("\nY:");
308         US_PrintUnsigned(player->y);
309         US_Print("  ");
310         US_PrintUnsigned(player->y >> TILESHIFT);
311         US_Print("\nA:");
312         US_PrintUnsigned(player->angle);
313         US_Print("\nD:");
314         US_PrintUnsigned(player->dir);
315         VW_UpdateScreen();
316         IN_Ack();
317         return 1;
318     }
319 
320     if (Keyboard[ScanCode::sc_g]) { // G = god mode
321         CenterWindow(12, 2);
322         if (godmode) {
323             US_PrintCentered("God mode OFF");
324         } else {
325             US_PrintCentered("God mode ON");
326         }
327         VW_UpdateScreen();
328         IN_Ack();
329         ::godmode = !::godmode;
330         return 1;
331     }
332 
333 
334     if (Keyboard[ScanCode::sc_h]) { // H = hurt self
335         IN_ClearKeysDown();
336         TakeDamage(1, nullptr);
337     } else if (Keyboard[ScanCode::sc_i]) { // I = item cheat
338         CenterWindow(12, 3);
339         US_PrintCentered("Free items!");
340         VW_UpdateScreen();
341         HealSelf(99);
342         GiveToken(5);
343 
344         const auto n = static_cast<int16_t>(::is_ps() ? wp_bfg_cannon : wp_grenade);
345 
346         for (int i = wp_autocharge; i <= n; i++) {
347             if (!(gamestate.weapons & (1 << i))) {
348                 GiveWeapon(i);
349                 break;
350             }
351         }
352 
353         gamestate.ammo += 50;
354         if (gamestate.ammo > MAX_AMMO) {
355             gamestate.ammo = MAX_AMMO;
356         }
357         DrawAmmo(true);
358         DrawScore();
359         IN_Ack();
360         return 1;
361     } else if (Keyboard[ScanCode::sc_m]) { // M = memory info
362         DebugMemory();
363         return 1;
364     }
365     else if (Keyboard[ScanCode::sc_q]) { // Q = fast quit
366         Quit();
367     }
368     else if (Keyboard[ScanCode::sc_o]) { // O = Show Push Walls
369         ExtraRadarFlags ^= OV_PUSHWALLS;
370         CenterWindow(24, 3);
371         if (ExtraRadarFlags & OV_PUSHWALLS) {
372             US_PrintCentered("AUTOMAP: Show PWalls ON");
373         } else {
374             US_PrintCentered("AUTOMAP: Show PWalls OFF");
375         }
376         VW_UpdateScreen();
377         IN_Ack();
378         return 1;
379     } else if (Keyboard[ScanCode::sc_u]) { // Unlock All Floors
380         CenterWindow(24, 3);
381         US_PrintCentered("Unlock All Floors!");
382         VW_UpdateScreen();
383         IN_Ack();
384 
385         for (int i = 0; i < ::MAPS_WITH_STATS; ++i) {
386             gamestuff.level[i].locked = false;
387         }
388 
389         return 1;
390     } else if (Keyboard[ScanCode::sc_s]) { // S = slow motion
391         ::singlestep = !::singlestep;
392         CenterWindow(18, 3);
393         if (singlestep) {
394             US_PrintCentered("Slow motion ON");
395         } else {
396             US_PrintCentered("Slow motion OFF");
397         }
398         VW_UpdateScreen();
399         IN_Ack();
400         return 1;
401     } else if (Keyboard[ScanCode::sc_w]) { // W = warp to level
402         ForceLoadDefault = Keyboard[ScanCode::sc_left_shift] | Keyboard[ScanCode::sc_right_shift] | Keyboard[ScanCode::sc_caps_lock];
403 
404         CenterWindow(26, 5);
405         PrintY += 6;
406         if (ForceLoadDefault) {
407             US_Print("         --- LOAD DEFAULT ---\n");
408         }
409         US_Print("  Current map: ");
410         US_PrintUnsigned(gamestate.mapon);
411         US_Print("\n  Enter map number: ");
412         VW_UpdateScreen();
413         esc = !US_LineInput(px, py, string, nullptr, true, 2, 0);
414         if (!esc && string[0] != '\0') {
415             const int MAX_WARP_LEVEL = (::is_aog() ? 10 : 23);
416             level = static_cast<int16_t>(atoi(string));
417             if (level > -1 && level <= MAX_WARP_LEVEL) {
418                 gamestate.lastmapon = gamestate.mapon;
419                 playstate = ex_warped;
420                 if (ForceLoadDefault) {
421                     BONUS_QUEUE = 0;
422                     BONUS_SHOWN = 0;
423                 }
424                 gamestate.mapon = level - 1;
425             }
426         }
427         return 1;
428     } else if (Keyboard[ScanCode::sc_home]) { // Dec top color
429         if (gamestate.flags & GS_DRAW_CEILING) {
430             CeilingTile = DecRange(CeilingTile, static_cast<uint16_t>(NUM_TILES - 1));
431             SetPlaneViewSize(); // Init new textures
432             return 1;
433         } else {
434             TopColor = DecRange((TopColor & 0xff), 0xff);
435             TopColor |= (TopColor << 8);
436         }
437     } else if (Keyboard[ScanCode::sc_page_up]) { // Inc top color
438         if (gamestate.flags & GS_DRAW_CEILING) {
439             CeilingTile = IncRange(CeilingTile, static_cast<uint16_t>(NUM_TILES - 1));
440             SetPlaneViewSize(); // Init new textures
441             return 1;
442         } else {
443             TopColor = IncRange((TopColor & 0xff), 0xff);
444             TopColor |= (TopColor << 8);
445         }
446     } else if (Keyboard[ScanCode::sc_end]) { // Dec bottom color
447         if (gamestate.flags & GS_DRAW_FLOOR) {
448             FloorTile = DecRange(FloorTile, static_cast<uint16_t>(NUM_TILES - 1));
449             SetPlaneViewSize(); // Init new textures
450             return 1;
451         } else {
452             BottomColor = DecRange((BottomColor & 0xff), 0xff);
453             BottomColor |= (BottomColor << 8);
454         }
455     } else if (Keyboard[ScanCode::sc_page_down]) { // Inc bottom color
456         if (gamestate.flags & GS_DRAW_FLOOR) {
457             FloorTile = IncRange(FloorTile, static_cast<uint16_t>(NUM_TILES - 1));
458             SetPlaneViewSize(); // Init new textures
459             return 1;
460         } else {
461             BottomColor = IncRange((BottomColor & 0xff), 0xff);
462             BottomColor |= (BottomColor << 8);
463         }
464     }
465 
466     if (gamestate.flags & GS_LIGHTING) { // Shading adjustments
467         if (Keyboard[ScanCode::sc_equals] && normalshade_div < 12) {
468             normalshade_div++;
469         } else if (Keyboard[ScanCode::sc_minus] && normalshade_div > 1) {
470             normalshade_div--;
471         }
472 
473         normalshade = (3 * (maxscale >> 2)) / normalshade_div;
474 
475         if (Keyboard[ScanCode::sc_right_bracket] && shade_max < 63) {
476             shade_max++;
477         } else if (Keyboard[ScanCode::sc_left_bracket] && shade_max > 5) {
478             shade_max--;
479         }
480     }
481 
482     return 0;
483 }
484