1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/cit/src/RCS/tools.c $
21 * $Revision: 1.94 $
22 * $Author: dc $
23 * $Date: 1994/11/25 16:58:28 $
24 */
25
26 // Source code from random useful tools and utilities
27
28 #define __TOOLS_SRC
29
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "criterr.h"
34 #include "gr2ss.h"
35 #include "tools.h"
36 #include "mainloop.h"
37 #include "gamescr.h"
38 #include "musicai.h"
39 #include "colors.h"
40 #include "gamestrn.h"
41 #include "invdims.h"
42 #include "fullscrn.h"
43 #include "hud.h"
44 #include "canvchek.h"
45 #include "player.h"
46 #include "faketime.h"
47 #include "cit2d.h"
48
49 #include <SDL.h>
50 #include "OpenGL.h"
51
52 #ifndef STORE_CLIP
53 #define STORE_CLIP(a, b, c, d) \
54 a = gr_get_clip_l(); \
55 b = gr_get_clip_t(); \
56 c = gr_get_clip_r(); \
57 d = gr_get_clip_b()
58 #endif // !STORE_CLIP
59
60 #ifndef RESTORE_CLIP
61 #define RESTORE_CLIP(a, b, c, d) gr_set_cliprect(a, b, c, d)
62 #endif // !RESTORE_CLIP
63
64 //------------
65 // PROTOTYPES
66 //------------
67 int str_to_hex(char val);
68 void text_button(char *text, int xc, int yc, int col, int shad, int w, int h);
69 void simple_text_button(char *text, int xc, int yc, int col);
70 void Rect_gr_rect(LGRect *r);
71 void Rect_gr_box(LGRect *r);
72 char *itoa_2_10(char *s, int val);
73 void zoom_rect(LGRect *start, LGRect *end);
74
str_to_hex(char val)75 int str_to_hex(char val) {
76 int retval = 0;
77 if ((val >= '0') && (val <= '9'))
78 retval = val - '0';
79 else if ((val >= 'A') && (val <= 'F'))
80 retval = 10 + val - 'A';
81 else if ((val >= 'a') && (val <= 'f'))
82 retval = 10 + val - 'a';
83 return (retval);
84 }
85
strtoupper(char * text)86 void strtoupper(char *text) {
87 for (; *text; text++) {
88 if (islower(*text))
89 (*text) += 'A' - 'a';
90 }
91 }
92
93 #ifdef SVGA_SUPPORT
94 uchar shadow_scale = TRUE;
95 #endif
draw_shadowed_string(char * s,short x,short y,uchar shadow)96 void draw_shadowed_string(char *s, short x, short y, uchar shadow) {
97 LGPoint npt;
98 ubyte color = gr_get_fcolor();
99 npt.x = x;
100 npt.y = y;
101 if (shadow && FONT_IS_MONO(gr_get_font())) // draw a black box
102 {
103 #ifdef SVGA_SUPPORT
104 extern char convert_use_mode;
105 extern uchar perform_svga_conversion(uchar mask);
106 extern void ss_scale_string(char *s, short x, short y);
107 if ((convert_use_mode > 0) && (perform_svga_conversion(OVERRIDE_FONT))) {
108 if (shadow_scale)
109 ss_point_convert(&(npt.x), &(npt.y), FALSE);
110 gr_set_fcolor(shadow);
111 ss_scale_string(s, npt.x - 1, npt.y - 1);
112 ss_scale_string(s, npt.x, npt.y - 1);
113 ss_scale_string(s, npt.x + 1, npt.y - 1);
114 ss_scale_string(s, npt.x, npt.y + 1);
115 ss_scale_string(s, npt.x - 1, npt.y + 1);
116 ss_scale_string(s, npt.x + 1, npt.y + 1);
117 ss_scale_string(s, npt.x - 1, npt.y);
118 ss_scale_string(s, npt.x + 1, npt.y);
119 gr_set_fcolor(color);
120 ss_scale_string(s, npt.x, npt.y);
121 } else
122 #endif
123 {
124 gr_set_fcolor(shadow);
125 gr_string(s, npt.x - 1, npt.y - 1);
126 gr_string(s, npt.x, npt.y - 1);
127 gr_string(s, npt.x + 1, npt.y - 1);
128 gr_string(s, npt.x, npt.y + 1);
129 gr_string(s, npt.x - 1, npt.y + 1);
130 gr_string(s, npt.x + 1, npt.y + 1);
131 gr_string(s, npt.x - 1, npt.y);
132 gr_string(s, npt.x + 1, npt.y);
133 gr_set_fcolor(color);
134 gr_string(s, npt.x, npt.y);
135 }
136 } else {
137 gr_set_fcolor(color);
138 // gr_string(s,npt.x,npt.y);
139 ss_string(s, npt.x, npt.y);
140 }
141 }
142
draw_hires_resource_bm(Ref id,int x,int y)143 void draw_hires_resource_bm(Ref id, int x, int y) {
144 FrameDesc *f = RefLock(id);
145 if (f == NULL)
146 critical_error(CRITERR_MEM | 9);
147 gr_bitmap(&f->bm, x, y);
148 RefUnlock(id);
149 }
150
draw_hires_halfsize_bm(Ref id,int x,int y)151 void draw_hires_halfsize_bm(Ref id, int x, int y) {
152 FrameDesc *f = RefLock(id);
153 if (f == NULL)
154 critical_error(CRITERR_MEM | 9);
155 gr_scale_bitmap(&f->bm, x, y, (f->bm.w >> 1), (f->bm.h >> 1));
156 RefUnlock(id);
157 }
158
draw_raw_res_bm_temp(Ref id,int x,int y)159 errtype draw_raw_res_bm_temp(Ref id, int x, int y) {
160 FrameDesc *f = RefLock(id);
161 if (f == NULL) {
162 return ERR_FREAD;
163 }
164 ss_bitmap(&f->bm, x, y);
165 RefUnlock(id);
166 return OK;
167 }
168
draw_raw_resource_bm(Ref id,int x,int y)169 errtype draw_raw_resource_bm(Ref id, int x, int y) {
170 FrameDesc *f;
171
172 f = RefLock(id);
173 if (f == NULL)
174 critical_error(CRITERR_MEM | 9);
175 ss_bitmap(&f->bm, x, y);
176 RefUnlock(id);
177 return (OK);
178 }
179
draw_res_bm_core(Ref id,int x,int y,uchar scale)180 errtype draw_res_bm_core(Ref id, int x, int y, uchar scale) {
181 FrameDesc *f;
182 LGRect mouse_rect;
183
184 f = RefLock(id);
185 if (f == NULL)
186 critical_error(CRITERR_MEM | 9);
187 mouse_rect.ul.x = x;
188 mouse_rect.ul.y = y;
189 mouse_rect.lr.x = x + f->bm.w;
190 mouse_rect.lr.y = y + f->bm.h;
191
192 // Set the palette right, if one is provided....
193 if (is_onscreen())
194 uiHideMouse(&mouse_rect);
195 if (scale)
196 ss_bitmap(&f->bm, x, y);
197 else
198 ss_noscale_bitmap(&f->bm, x, y);
199 if (is_onscreen())
200 uiShowMouse(&mouse_rect);
201 RefUnlock(id);
202 return (OK);
203 }
204
draw_res_bm(Ref id,int x,int y)205 errtype draw_res_bm(Ref id, int x, int y) { return (draw_res_bm_core(id, x, y, TRUE)); }
206
207 // Note, does no mouse code!
draw_full_res_bm(Ref id,int x,int y,uchar fade_in)208 errtype draw_full_res_bm(Ref id, int x, int y, uchar fade_in) {
209 FrameDesc *f;
210 short *temp_pall;
211 byte pal_id;
212 extern void finish_pal_effect(byte id);
213 extern byte palfx_start_fade_up(uchar * new_pal);
214
215 f = RefLock(id);
216 if (f == NULL)
217 critical_error(CRITERR_MEM | 9);
218
219 // Set the palette right, if one is provided....
220 if (f->pallOff) {
221 // FIXME nasty hack to get at the private palette; the private palette
222 // is an offset from the start of the raw on-disc resource, so it
223 // includes the (raw) reftable as well as any previous ref entries.
224 RefTable *prt = (RefTable *)ResGet(REFID(id));
225 // Raw reftable size
226 size_t tabsize = sizeof(RefIndex) + (prt->numRefs+1) * sizeof(uint32_t);
227 temp_pall = (short *)((uchar *)prt->raw_data - tabsize + f->pallOff);
228 gr_set_pal(*temp_pall, *(temp_pall + 1), (uchar *)(temp_pall + 2));
229 }
230
231 if (fade_in && temp_pall != NULL) {
232 pal_id = palfx_start_fade_up((uchar *)(temp_pall + 2));
233 }
234
235 f->bm.bits = (uchar *)(f + 1);
236 ss_bitmap(&f->bm, x, y); // KLC ss_bitmap(&f->bm, x, y);
237 RefUnlock(id);
238 if (fade_in)
239 finish_pal_effect(pal_id);
240 ResDrop(REFID(id));
241 return (OK);
242 }
243
res_bm_width(Ref id)244 int res_bm_width(Ref id) {
245 FrameDesc *f;
246 int n;
247
248 f = RefLock(id);
249 if (f == NULL)
250 critical_error(CRITERR_MEM | 9);
251 n = f->bm.w;
252 RefUnlock(id);
253 return (n);
254 }
255
res_bm_height(Ref id)256 int res_bm_height(Ref id) {
257 FrameDesc *f;
258 int n;
259
260 f = RefLock(id);
261 if (f == NULL)
262 critical_error(CRITERR_MEM | 9);
263 n = f->bm.h;
264 RefUnlock(id);
265 return (n);
266 }
267
res_draw_text_shadowed(Id id,char * text,int x,int y,uchar shadow)268 errtype res_draw_text_shadowed(Id id, char *text, int x, int y, uchar shadow) {
269 gr_set_font(ResLock(id));
270 draw_shadowed_string(text, x, y, shadow);
271 ResUnlock(id);
272 return (OK);
273 }
274
res_draw_string(Id font,int strid,int x,int y)275 errtype res_draw_string(Id font, int strid, int x, int y) { return res_draw_text(font, get_temp_string(strid), x, y); }
276
277 // have some god damn parameters
278 // xc,yc is position, usually text center
279 // w.h. is rectangle wid+hgt, note <0 means that the x|yc is the upper left, not the center
280 // shad is how much to shade down color (-1 is no shadow)
281 // col is color of rectangle and text
text_button(char * text,int xc,int yc,int col,int shad,int w,int h)282 void text_button(char *text, int xc, int yc, int col, int shad, int w, int h) {
283 int ux, uy;
284 short tw, th;
285
286 gr_string_size(text, &tw, &th);
287
288 // do wacked out conversionitis
289 if (w < 0) {
290 ux = xc;
291 w = -w;
292 xc = ux + (w >> 1);
293 } else
294 ux = xc - (w >> 1);
295 if (h < 0) {
296 uy = yc;
297 h = -h;
298 yc = uy + (h >> 1);
299 } else
300 uy = yc - (h >> 1);
301
302 // two rectangles...
303 gr_set_fcolor(col);
304 ss_rect(ux, uy, ux + w, uy + h);
305 if (shad >= 0) {
306 gr_set_fcolor(col + shad);
307 ss_rect(ux + 1, uy + 1, ux + w - 1, uy + h - 1);
308 gr_set_fcolor(col);
309 }
310 // some text, eh?
311 ss_string(text, xc - (tw >> 1), yc - (th >> 1));
312 }
313
314 // ok, the easy case...
315 // centered at xc,yc, color base, auto-shadowed, size out setting
simple_text_button(char * text,int xc,int yc,int col)316 void simple_text_button(char *text, int xc, int yc, int col) {
317 short w, h;
318 gr_string_size(text, &w, &h);
319 text_button(text, xc, yc, col, 4, w + 12, h + 8);
320 }
321
Rect_gr_rect(LGRect * r)322 void Rect_gr_rect(LGRect *r) { ss_rect(r->ul.x, r->ul.y, r->lr.x, r->lr.y); }
323
Rect_gr_box(LGRect * r)324 void Rect_gr_box(LGRect *r) { ss_box(r->ul.x, r->ul.y, r->lr.x, r->lr.y); }
325
itoa_2_10(char * s,int val)326 char *itoa_2_10(char *s, int val) {
327 s[0] = '0' + (val / 10);
328 s[1] = '0' + (val % 10);
329 s[2] = '\0';
330 return s;
331 }
332
333 // max 99 hours...
second_format(int sec_remain,char * s)334 void second_format(int sec_remain, char *s) {
335 int c_l;
336 if (sec_remain >= 3600) {
337 itoa_2_10(s, sec_remain / 3600);
338 sec_remain %= 3600;
339 c_l = 3;
340 s[2] = ':';
341 } else
342 c_l = 0;
343 itoa_2_10(s + c_l, sec_remain / 60);
344 s[c_l + 2] = ':';
345 sec_remain %= 60;
346 itoa_2_10(s + c_l + 3, sec_remain);
347 if (s[0] == '0')
348 s[0] = ' ';
349 }
350
351 #ifdef NOT_YET // later, dude
352
353 #define BIG_BUF
354
355 #pragma disable_message(202)
gifdump_func(short keycode,ulong context,void * data)356 uchar gifdump_func(short keycode, ulong context, void *data) {
357 unsigned char *temp_buf;
358 int giffp;
359 char harold[45];
360
361 strcpy(harold, "SHOCK000.GIF");
362 giffp = open_gen(harold, O_CREAT | O_BINARY | O_WRONLY | O_TRUNC, S_IWRITE);
363 if (giffp == -1) {
364 message_info("GIF dump failed!");
365 return (ERR_NOEFFECT);
366 }
367 {
368 temp_buf = big_buffer;
369 gd_dump_screen(giffp, temp_buf);
370 strcat(harold, " saved");
371 message_info(harold);
372 }
373 return (TRUE);
374 }
375 #pragma enable_message(202)
376
377 #endif // NOT_YET
378
379 #define FULLSCREEN_MESSAGE_X 125
380 #define FULLSCREEN_MESSAGE_Y 8
381
382 #define MESSAGE_BUFSZ 128
383
384 #ifdef SVGA_SUPPORT_HATE_HATE
mouse_unconstrain(void)385 void mouse_unconstrain(void) {
386 // Note we are not calling the UI here since we are looking
387 // at actual screen size
388 mouse_constrain_xy(0, 0, grd_cap->w - 1, grd_cap->h - 1);
389 }
390 #endif
391
string_message_info(int strnum)392 errtype string_message_info(int strnum) {
393 char buf[MESSAGE_BUFSZ];
394 get_string(strnum, buf, MESSAGE_BUFSZ);
395 return message_info(buf);
396 }
397
398 char last_message[128];
399 ulong message_clear_time;
400
401 #define MESSAGE_INTERVAL 1200
402 #define CHAR_SOFTCR 0x01 // soft carriage return (wrapped text)
403 #define CHAR_SOFTSP 0x02 // soft space (wrapped text)
404 #define MESSAGE_LEN 80
405
406 LGRect msg_rect[2] = {
407 {GAME_MESSAGE_X, GAME_MESSAGE_Y, GAME_MESSAGE_X + GAME_MESSAGE_W, GAME_MESSAGE_Y + GAME_MESSAGE_H},
408 {FULLSCREEN_MESSAGE_X, FULLSCREEN_MESSAGE_Y, FULLSCREEN_MESSAGE_X + GAME_MESSAGE_W,
409 FULLSCREEN_MESSAGE_Y + GAME_MESSAGE_H}};
410
411 uchar message_resend = FALSE;
412 extern uchar game_paused;
413 extern uchar view360_message_obscured;
414 void strip_newlines(char *buf);
415
416 // Use the string wrapper's secret characters to delete newlines and double spaces.
strip_newlines(char * buf)417 void strip_newlines(char *buf) {
418 char *s;
419 for (s = buf; *s != '\0'; s++) {
420 if (*s == '\n')
421 *s = CHAR_SOFTSP;
422 if (isspace(*s) && isspace(*(s + 1)))
423 *s = CHAR_SOFTSP;
424 }
425 }
426
message_info(const char * info_text)427 errtype message_info(const char *info_text) {
428 extern errtype inventory_draw_new_page(int pgnum);
429 int x, y;
430 char buf[MESSAGE_LEN];
431
432 if (info_text != NULL) {
433 strncpy(buf, info_text, MESSAGE_LEN);
434 strip_newlines(buf);
435 } else
436 buf[0] = '\0';
437 if (_current_loop <= FULLSCREEN_LOOP) {
438 short a, b, c, d;
439 LGRect *r = &msg_rect[(full_game_3d && !game_paused) ? 1 : 0];
440
441 x = r->ul.x;
442 y = r->ul.y;
443 if (is_onscreen())
444 uiHideMouse(r);
445 gr_push_canvas(grd_screen_canvas);
446 STORE_CLIP(a, b, c, d);
447
448 ss_safe_set_cliprect(r->ul.x, r->ul.y, r->lr.x, r->lr.y);
449 if (!full_game_3d) {
450 y += 1;
451 if (!view360_message_obscured || game_paused) {
452 draw_raw_resource_bm(REF_IMG_bmBlankMessageLine, x, y);
453 // draw_hires_resource_bm(REF_IMG_bmBlankMessageLine,
454 // SCONV_X(x),
455 //SCONV_Y(y));
456 }
457 x += 2;
458 } else if (game_paused) {
459 extern grs_canvas inv_view360_canvas;
460 ss_noscale_bitmap(&inv_view360_canvas.bm, x, y);
461 x += 2;
462 y += 1;
463 }
464 if (!message_resend && info_text != last_message && strcmp(last_message, info_text) == 0) {
465 message_resend = TRUE;
466 message_clear_time = *tmd_ticks + CIT_CYCLE / 10;
467 hud_unset(HUD_MSGLINE);
468 } else {
469 message_resend = FALSE;
470 if ((!full_game_3d && !view360_message_obscured) || game_paused) {
471 gr_set_fcolor(WHITE);
472 res_draw_text_shadowed(RES_tinyTechFont, buf, x, y, full_game_3d);
473 hud_unset(HUD_MSGLINE);
474 } else if (full_game_3d || view360_message_obscured) {
475 if (buf[0] != '\0') {
476 hud_set_time(HUD_MSGLINE, 5 << APPROX_CIT_CYCLE_SHFT);
477 }
478 }
479 }
480 RESTORE_CLIP(a, b, c, d);
481 gr_pop_canvas();
482 if (is_onscreen())
483 uiShowMouse(r);
484 }
485 if (!message_resend && info_text != last_message) {
486 message_clear_time = *tmd_ticks + MESSAGE_INTERVAL;
487 strcpy(last_message, info_text);
488 }
489 return (OK);
490 }
491
492 uchar message_clear_on = TRUE;
493
message_clear_check()494 errtype message_clear_check() {
495 // much as I like spews that print every frame.......
496 // Spew(DSRC_GAMESYS_Messages, ("%d >? %d\n",player_struct.game_time,message_clear_time));
497 if (*tmd_ticks < message_clear_time)
498 return OK;
499 if (message_resend) {
500 char buf[sizeof(last_message)];
501 strcpy(buf, last_message);
502 return message_info(buf);
503 }
504 if (message_clear_on && !full_game_3d && !view360_message_obscured) {
505 errtype retval = message_info("");
506 return retval;
507 }
508 return (OK);
509 }
510
message_box(char * box_text)511 errtype message_box(char *box_text) {
512 message_info(box_text);
513 return (OK);
514 }
515
516 #ifdef NOT_YET // later, dude
517
518 #pragma disable_message(202)
confirm_box(char * confirm_text)519 uchar confirm_box(char *confirm_text) { return (TRUE); }
520 #pragma enable_message(202)
521
fopen_gen(char * fname,char * t)522 FILE *fopen_gen(char *fname, char *t) {
523 Datapath gen_path;
524 FILE *retval;
525 char temp[64];
526
527 gen_path.numDatapaths = 0;
528 gen_path.noCurrent = 1;
529 DatapathAddDir(&gen_path, "gen");
530 DatapathAddEnv(&gen_path, "GEN_DIR");
531 strcpy(temp, getenv("CITHOME"));
532 strcat(temp, "\\gen");
533 DatapathAddDir(&gen_path, temp);
534 DatapathNoCurrent(&gen_path);
535 next_number_dpath_fname(&gen_path, fname);
536 retval = DatapathOpen(&gen_path, fname, t);
537 DatapathFree(&gen_path);
538 return retval;
539 }
540
open_gen(char * fname,int access1,int access2)541 int open_gen(char *fname, int access1, int access2) {
542 Datapath gen_path;
543 int retval;
544
545 gen_path.numDatapaths = 0;
546 gen_path.noCurrent = 1;
547 DatapathAddDir(&gen_path, "gen");
548 DatapathAddEnv(&gen_path, "GEN_DIR");
549 DatapathNoCurrent(&gen_path);
550 next_number_dpath_fname(&gen_path, fname);
551 retval = DatapathFDOpen(&gen_path, fname, access1, access2);
552 DatapathFree(&gen_path);
553 return retval;
554 }
555
next_number_dpath_fname(Datapath * dpath,char * fname)556 char *next_number_dpath_fname(Datapath *dpath, char *fname) {
557 char *subname = strrchr(fname, '0');
558 int fhnd, numlen = 1, i, num = 0;
559
560 if (subname != NULL) {
561 while ((strlen(subname) != strlen(fname)) && (subname[0] == subname[-1])) {
562 subname--;
563 numlen++;
564 }
565 // try them, lets go, rock and roll, so on
566 while ((fhnd = DatapathFDOpen(dpath, fname, O_BINARY | O_RDONLY)) != -1) { /* Check next slot */
567 close(fhnd); /* good idea to, like, close the opened file */
568 ++num;
569 for (i = 0; i < numlen; i++)
570 subname[numlen - (i + 1)] = '0' + ((num >> (3 * i)) & 7);
571 }
572 close(fhnd);
573 }
574 return fname;
575 }
576
next_number_fname(char * fname)577 char *next_number_fname(char *fname) {
578 char *subname = strrchr(fname, '0');
579 int fhnd, numlen = 1, i, num = 0;
580
581 while ((strlen(subname) != strlen(fname)) && (subname[0] == subname[-1])) {
582 subname--;
583 numlen++;
584 }
585 /* Look for files like uwpic000.gif */
586 while ((fhnd = open(fname, O_BINARY | O_RDONLY)) != -1) { /* Check next slot */
587 close(fhnd); /* good idea to, like, close the opened file */
588 ++num;
589 for (i = 0; i < numlen; i++)
590 subname[numlen - (i + 1)] = '0' + ((num >> (3 * i)) & 7);
591 }
592 close(fhnd);
593 return fname;
594 }
595
596 #endif // NOT_YET
597
tight_loop(uchar check_input)598 errtype tight_loop(uchar check_input) {
599 if (music_on)
600 mlimbs_do_ai();
601
602 // KLC - does nothing!
603 // if (music_on || sfx_on)
604 // synchronous_update();
605
606 if (check_input) {
607 uiPoll();
608 kb_flush_bios();
609 }
610 return (OK);
611 }
612
613 // --------------------------------------------------
614 // STRING WRAPPER
615
616 #define HYPHEN '-'
617
618 // FIXME This code duplicates gr_font_string_wrap()
hyphenated_wrap_text(char * ps,char * out,short width)619 int hyphenated_wrap_text(char *ps, char *out, short width) {
620 char *psbase;
621 char *p;
622 char *pmark;
623 short numLines;
624 short currWidth;
625
626 // Set up to do wrapping
627
628 psbase = ps; // psbase = string beginning
629 numLines = 0; // ps = base of current line
630
631 // Do wrapping for each line till hit end
632
633 while (*ps) {
634 pmark = NULL; // no SOFTCR insert LGPoint yet
635 currWidth = 0; // and zero width so far
636 p = ps;
637
638 // Loop thru each word
639
640 while (*p) {
641
642 // Skip through to next CR or space or '\0', keeping track of width
643
644 while ((*p != 0) && (*p != '\n') && (*p != ' ') && (*p != CHAR_SOFTSP)) {
645 currWidth += gr_char_width(*p);
646 p++;
647 }
648
649 // If bypassed width, break out of word loop
650
651 if (currWidth > width ||
652 (*p == CHAR_SOFTSP && (currWidth + gr_char_width(HYPHEN)) > width)) {
653 if ((pmark == NULL) && (*p != 0) && (*p != '\n'))
654 pmark = p;
655 break;
656 }
657
658 // Else set new mark LGPoint (unless eol or eos, then bust out)
659
660 else {
661 if ((*p == 0) || (*p == '\n')) // hit end of line, wipe marker
662 {
663 pmark = NULL;
664 break;
665 }
666 pmark = p; // else advance marker
667 currWidth += gr_char_width(*p); // and account for space
668 p++;
669 }
670 }
671
672 // Now insert soft cr if marked one
673
674 if (pmark) {
675 strncpy(out, ps, pmark - ps);
676 out += pmark - ps;
677 if (*pmark == CHAR_SOFTSP)
678 *out++ = HYPHEN;
679 *out++ = CHAR_SOFTCR;
680 ps = pmark + 1;
681 if (*ps == ' ') // if wrapped and following space,
682 ps++; // turn into (ignored) soft space
683 }
684
685 // Otherwise, bump past cr
686 else {
687 strncpy(out, ps, p - ps + 1);
688 out += p - ps + 1;
689
690 if (*p)
691 ++p;
692 ps = p;
693 }
694
695 // Bump line counter in any case
696
697 ++numLines;
698 }
699
700 // When hit end of string, return # lines encountered
701
702 return (numLines);
703 }
704
705 // --------------------------------------------------------------------
706 // WAIT CURSOR
707
708 char wait_count = 0;
709
begin_wait()710 errtype begin_wait() {
711 extern LGCursor wait_cursor;
712 errtype retval;
713 if (wait_count == 0) {
714 uiHideMouse(NULL);
715 retval = uiPushGlobalCursor(&wait_cursor);
716 uiShowMouse(NULL);
717
718 extern void SDLDraw(void);
719 SDLDraw();
720 }
721 wait_count++;
722
723 return (retval);
724 }
725
726 #ifdef NOT_YET //
spoof_mouse_event(void)727 errtype spoof_mouse_event(void) {
728 int i;
729 uiMouseEvent ev;
730
731 uiMakeMotionEvent(&ev);
732 if (ev.buttons == 0)
733 return OK;
734 for (i = 0; i < NUM_MOUSE_BTNS; i++) {
735 if (ev.buttons & (1 << i))
736 ev.action |= MOUSE_BTN2DOWN(i);
737 }
738 ev.type = UI_EVENT_MOUSE;
739 return uiQueueEvent((uiEvent *)&ev);
740 }
741 #endif // NOT_YET
742
end_wait()743 errtype end_wait() {
744 errtype retval;
745 wait_count--;
746 if (wait_count <= 0) {
747 uiHideMouse(NULL);
748 retval = uiPopGlobalCursor();
749 uiShowMouse(NULL);
750 wait_count = 0;
751 uiFlush();
752 // spoof_mouse_event();
753 }
754 return (retval);
755 }
756
757 // --------------------------------------------------------------------
758 // ZOOM BOXES
759
760 /*
761 * Original zoom timing was 8 * 10 ticks at a timer frequency of 280 Hz, i.e.
762 * around 286 milliseconds. Assuming a refresh rate of 60 Hz that's around 17
763 * frames.
764 */
765
766 #define ZOOM_MS 286
767
768 #define INTERP(s, f, i) (((f) * (i) + (s) * (ZOOM_MS - (i)-1)) / (ZOOM_MS - 1))
769
770 bool ZoomEnable;
771 LGRect ZoomStart, ZoomEnd;
772 Uint32 ZoomTicks, ZoomI;
773
zoom_rect(LGRect * start,LGRect * end)774 void zoom_rect(LGRect *start, LGRect *end)
775 {
776 //set global variables used by ZoomProc()
777 ZoomEnable = TRUE;
778 ZoomStart = *start;
779 ZoomEnd = *end;
780 ZoomTicks = SDL_GetTicks();
781 }
782
783 //called just before and after SDLDraw() in mainloop()
ZoomDrawProc(int erase)784 void ZoomDrawProc(int erase)
785 {
786 if (!ZoomEnable) return;
787
788 if (!erase)
789 {
790 ZoomI = SDL_GetTicks() - ZoomTicks;
791 if (ZoomI >= ZOOM_MS) {ZoomEnable = 0; return;}
792 }
793
794 int ft = gr_get_fill_type();
795 int c = gr_get_fcolor();
796 gr_set_fill_type(FILL_XOR);
797 gr_set_fcolor(WHITE);
798
799 // make the zoom rectanle visible in OpenGL as well
800 if(full_game_3d && use_opengl()) {
801 gr_set_fcolor(0x1);
802 }
803
804 short ulx = INTERP(ZoomStart.ul.x, ZoomEnd.ul.x, ZoomI);
805 short uly = INTERP(ZoomStart.ul.y, ZoomEnd.ul.y, ZoomI);
806 short lrx = INTERP(ZoomStart.lr.x, ZoomEnd.lr.x, ZoomI);
807 short lry = INTERP(ZoomStart.lr.y, ZoomEnd.lr.y, ZoomI);
808 ss_box(ulx, uly, lrx, lry);
809 ss_box(ulx - 1, uly - 1, lrx + 1, lry + 1);
810
811 gr_set_fill_type(ft);
812 gr_set_fcolor(c);
813 }
814
815 // Returns the angle of difference between look_facing and the true direction
816 // that looker would have to be facing in order to see target, and puts that
817 // true direction into real_dir.
818
819 // Wow, I really ought to someday make this not use icky trig
820 // but instead write some fast simple version
point_in_view_arc(fix target_x,fix target_y,fix looker_x,fix looker_y,fixang look_facing,fixang * real_dir)821 fixang point_in_view_arc(fix target_x, fix target_y, fix looker_x, fix looker_y, fixang look_facing, fixang *real_dir) {
822 fix x_diff, y_diff;
823 fixang retval;
824
825 x_diff = target_x - looker_x;
826 y_diff = target_y - looker_y;
827 *real_dir = fix_atan2(y_diff, x_diff);
828
829 // Compensate for difference between our coordinate system and fixpoint's
830
831 // Hmmm, how do fixangs deal with negatives?
832 // Better normalize to absolute difference, just to be sure
833 // After all, they do have *real_dir to figure it out themselves
834 // if they want to.
835 if (*real_dir > look_facing)
836 retval = (*real_dir - look_facing);
837 else
838 retval = (look_facing - *real_dir);
839 if (retval > 0x8000)
840 retval = 0x10000 - retval;
841 return (retval);
842 }
843
844 // convert occurances of the character "from" to the character "to"
845 // in the string "s"
string_replace_char(char * s,char from,char to)846 void string_replace_char(char *s, char from, char to) {
847 for (; *s; s++) {
848 if (*s == from)
849 *s = to;
850 };
851 }
852
853 //gamma param not used here; see SetSDLPalette() in Shock.c
gamma_dealfunc(ushort gamma_qvar)854 void gamma_dealfunc(ushort gamma_qvar) {
855 gr_set_gamma_pal(0, 256, 0);
856 }
857