aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/hugo/hugo.h
blob: a1e2c29494b47531a9713cfbcfb6331d4be1bd06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef GLK_HUGO_HUGO
#define GLK_HUGO_HUGO

#include "common/scummsys.h"
#include "glk/glk_api.h"
#include "glk/hugo/htokens.h"
#include "glk/hugo/hugo_defines.h"
#include "glk/hugo/hugo_types.h"
#include "glk/hugo/stringfn.h"

namespace Glk {
namespace Hugo {

/**
 * Hugo game interpreter
 */
class Hugo : public GlkAPI, public HTokens, public StringFunctions {
private:
	winid_t mainwin, currentwin;
	winid_t secondwin, auxwin;
	bool runtime_warnings;
	int dbnest;

	/**
	 * address_scale refers to the factor by which addresses are multiplied to
	 * get the "real" address.  In this way, a 16-bit integer can reference
	 * 64K * 16 = 1024K of memory.
	 */
	int address_scale;

	// heexpr
	int eval[MAX_EVAL_ELEMENTS];		///< expression components
	int evalcount;						///< # of expr. components
	int var[MAXLOCALS + MAXGLOBALS];	///< variables
	int incdec;							///< value is being incremented/dec.
	char getaddress;					///< true when finding &routine
	char inexpr;						///< true when in expression
	char inobj;							///< true when in object compound

	int last_precedence;


	// hemisc
	char gamefile[255];
	int game_version;
	int object_size;
	//HUGO_FILE game;
	Common::SeekableReadStream *game;
	HUGO_FILE script;
	HUGO_FILE save;
	HUGO_FILE playback;
	HUGO_FILE record;
	HUGO_FILE io; char ioblock; char ioerror;

	char id[3];
	char serial[9];
	unsigned int codestart;
	unsigned int objtable;
	unsigned int eventtable;
	unsigned int proptable;
	unsigned int arraytable;
	unsigned int dicttable;
	unsigned int syntable;
	unsigned int initaddr;
	unsigned int mainaddr;
	unsigned int parseaddr;
	unsigned int parseerroraddr;
	unsigned int findobjectaddr;
	unsigned int endgameaddr;
	unsigned int speaktoaddr;
	unsigned int performaddr;
	int objects;
	int events;
	int dictcount;
	int syncount;
	char context_command[MAX_CONTEXT_COMMANDS][64];
	int context_commands;
	unsigned char *mem;
	int loaded_in_memory;
	unsigned int defseg;
	unsigned int gameseg;
	long codeptr;
	long codeend;
	char pbuffer[MAXBUFFER * 2 + 1];
	int currentpos;
	int currentline;
	int full;
	signed char def_fcolor, def_bgcolor, def_slfcolor, def_slbgcolor;
	signed char fcolor, bgcolor, icolor, default_bgcolor;
	int currentfont;
	char capital;
	unsigned int textto;
	int SCREENWIDTH, SCREENHEIGHT;
	int physical_windowwidth, physical_windowheight,
		physical_windowtop, physical_windowleft,
		physical_windowbottom, physical_windowright;
	int inwindow;
	int charwidth, lineheight, FIXEDCHARWIDTH, FIXEDLINEHEIGHT;
	int current_text_x, current_text_y;
	bool skipping_more;
	int undostack[MAXUNDO][5];
	int undoptr;
	int undoturn;
	char undoinvalid;
	char undorecord;

	bool in_valid_window;
	int glk_fcolor, glk_bgcolor;
	int mainwin_bgcolor;
	int glk_current_font;
	bool just_cleared_screen;
	int secondwin_bottom;

	// heobject
	int display_object;				///< i.e., non-existent (yet)
	char display_needs_repaint;		///< for display object
	int display_pointer_x, display_pointer_y;

	// heparse
	char buffer[MAXBUFFER + MAXWORDS];
	char errbuf[MAXBUFFER + 1];				///< last invalid input
	char line[1025];						///< line buffer

	int words;								///< parsed word count
	const char *word[MAXWORDS + 1];			///< breakdown into words
	unsigned int wd[MAXWORDS + 1];			///<     "      "   dict. entries
	unsigned int parsed_number;				///< needed for numbers in input

	signed char remaining;					///< multiple commands in input
	char parseerr[MAXBUFFER + 1];			///< for passing to RunPrint, etc.
	char parsestr[MAXBUFFER + 1];			///< for passing quoted string
	char xverb;								///< flag; 0 = regular verb
	char starts_with_verb;					///< input line; 0 = no verb word
	unsigned int grammaraddr;				///< address in grammar
	char *obj_parselist;					///< objects with noun/adjective
	int domain, odomain;					///< of object(s)
	int objlist[MAXOBJLIST];				///< for objects of verb
	char objcount;							///< of objlist
	char parse_allflag;						///< for "all" in MatchObject
	pobject_structure pobjlist[MAXPOBJECTS];	///< for possible objects
	int pobjcount;							///< of pobjlist
	int pobj;								///< last remaining suspect
	int obj_match_state;					///< see MatchCommand() for details
	char objword_cache[MAXWORDS];			///< for MatchWord() xobject, etc.
	char object_is_number;					///< number used in player command
	unsigned int objgrammar;				///< for 2nd pass
	int objstart;							///<  "   "   "
	int objfinish;							///<  "   "   "
	char addflag;							///< true if adding to objlist[]
	int speaking;							///< if command is addressed to obj.

	char oops[MAXBUFFER + 1];				///< illegal word
	int oopscount;							///< # of corrections in a row

	char parse_called_twice;
	char reparse_everything;
	char punc_string[64];					///< punctuation string

	char full_buffer;
	/**
	 * to MatchObject()
	 * Necessary for proper disambiguation when addressing a character;
	 * i.e., when 'held' doesn't refer to held by the player, etc.
	 */
	char recursive_call;
	int parse_location;						///< usually var[location]

	// herun
	int passlocal[MAXLOCALS];		///< locals passed to routine
	int arguments_passed;			///< when calling routine
	int ret;						///< return value and returning flag
	char retflag;
	bool during_player_input;
	char override_full;
	bool game_reset;				///< for restore, undo, etc.

	CODE_BLOCK code_block[MAXSTACKDEPTH];
	int stack_depth;
	int tail_recursion;
	long tail_recursion_addr;

	// Used by RunWindow for setting current window dimensions:
	int last_window_top, last_window_bottom, last_window_left, last_window_right;
	int lowest_windowbottom,				///< in text lines
		physical_lowest_windowbottom;		///< in pixels or text lines
	bool just_left_window;

	// heset
	char game_title[MAX_GAME_TITLE];
	char arrexpr;							///< true when assigning array
	char multiprop;							///< true in multiple prop. assign.
	int set_value;

#if defined (DEBUGGER)
	char debug_line[MAX_DEBUG_LINE];
	bool debug_eval;
	bool debug_eval_error;
	bool debugger_step_over;
	bool debugger_finish;
	bool debugger_run;
	bool debugger_interrupt;
	bool debugger_skip;
	bool runtime_error;
	int currentroutine;
	bool complex_prop_breakpoint;
	bool trace_complex_prop_routine;
	char *objectname[MAX_OBJECT];
	char *propertyname[MAX_PROPERTY];
//	CODE code[999];
	CALL call[999];
	int routines;
	int properties;
	WINDOW window[99];
	int codeline[9][100];
	char localname[9][100];
	int current_locals;
	long this_codeptr;
#endif
private:
	/**
	 * \defgroup heglk
	 * @{
	 */

	 /**
	  * Does whatever has to be done to initially set up the display
	  */
	void hugo_init_screen();

	/**
	 * Does whatever has to be done to clean up the display pre-termination
	 */
	void hugo_cleanup_screen() {
		// No implementation
	}

	int hugo_getkey() const {
		// Not needed here--single-character events are handled solely by hugo_waitforkey(), below
		return 0;
	}

	/**
	 * Gets a line of input from the keyboard, storing it in <buffer>.
	 */
	void hugo_getline(const char *prmpt);

	/**
	 * Provided to be replaced by multitasking systems where cycling while waiting
	 * for a keystroke may not be such a hot idea.
	 */
	int hugo_waitforkey();

	/**
	 * Returns true if a keypress is waiting to be retrieved.
	 */
	int hugo_iskeywaiting();

	/**
	 * Waits for 1/n seconds.  Returns false if waiting is unsupported.
	 */
	int hugo_timewait(int n);

	/**
	 * Clears everything on the screen, moving the cursor to the top-left corner of the screen
	 */
	void hugo_clearfullscreen();

	/**
	 * Clears the currently defined window, moving the cursor to the top-left corner of the window
	 */
	void hugo_clearwindow();

	/**
	 * This function does whatever is necessary to set the system up for a standard text display
	 */
	void hugo_settextmode();

	void hugo_settextwindow(int left, int top, int right, int bottom);

	/**
	 * Specially accommodated in GetProp() While the engine thinks that the linelength is 0x7fff,
	this tells things like the display object the actual length.  (Defined as ACTUAL_LINELENGTH)
	*/
	int heglk_get_linelength();

	/**
	 * Similar to heglk_get_linelength().  (Defined as ACTUAL_SCREENHEIGHT)
	 */
	int heglk_get_screenheight();

	void hugo_settextpos(int x, int y);

	/**
	 * Essentially the same as printf() without formatting, since printf() generally doesn't take
	 * into account color setting, font changes, windowing, etc.
	 *
	 * The newline character '\n' must be explicitly included at the end of a line in order to
	 * produce a linefeed.  The new cursor position is set to the end of this printed text.
	 * Upon hitting the right edge of the screen, the printing position wraps to the start
	 * of the next line.
	 */
	void hugo_print(const char *a);

	/**
	 * Scroll the text window
	 */
	void hugo_scrollwindowup() {
		// No implementation. Glk takes care of it
	}

	/**
	 * Set the font
	 * @param f		The <f> argument is a mask containing any or none of:
	 *				BOLD_FONT, UNDERLINE_FONT, ITALIC_FONT, PROP_FONT.
	 */
	void hugo_font(int f);

	/**
	 * Set the foreground (print) color
	 */
	void hugo_settextcolor(int c);

	/**
	 * Set the background color
	 */
	void hugo_setbackcolor(int c);

	/**
	 * Color-setting functions should always pass the color through hugo_color()
	 * in order to properly set default fore/background colors
	 */
	int hugo_color(int c);

	/**
	 * Get the width of a character
	 * @remarks		As given here, this function works only for non-proportional printing.
	 * For proportional printing, hugo_charwidth() should return the width of the supplied
	 * character in the current font and style.
	*/
	int hugo_charwidth(char a) const;

	/**
	 * Return the width of a string
	 */
	int hugo_textwidth(const char *a) const;

	/**
	 * Return the length of a string
	 */
	int hugo_strlen(const char *a) const;

	void hugo_setgametitle(const char *t);

	int hugo_hasvideo() const;

	int hugo_playvideo(HUGO_FILE infile, long reslength, char loop_flag, char background, int volume);

	void hugo_stopvideo();

	/**@}*/

	/**
	 * \defgroup hemisc
	 * @{
	 */

	/**
	 * The all-purpose printing routine that takes care of word-wrapping.
	 */
	void AP(const char *a);

	/**
	 * Used whenever a routine is called, assumes the routine address and begins
	 * with the arguments (if any).
	 */
	int CallRoutine(unsigned int addr);

	/**
	 * Adds a command to the context command list.  A zero value (i.e., an empty string)
	 * resets the list.
	 */
	void ContextCommand();

	/**
	 * Dynamically creates a new dictionary entry.
	 */
	unsigned int Dict();

	/**
	 * Generates a fatal error
	 */
	void FatalError(int n);

	void FileIO();

	void Flushpbuffer();

	void GetCommand();

	/**
	 * From any address <addr>; the segment must be defined prior to calling the function.
	 */
	char *GetString(long addr);

	/**
	 * Get text block from position <textaddr> in the text bank.  If the game was not fully loaded
	 * in memory, i.e., if loaded_in_memory is not true, the block is read from disk.
	 */
	char *GetText(long textaddr);

	/**
	 * From the dictionary table.
	 */
	const char *GetWord(unsigned int w);

	void HandleTailRecursion(long addr);

	void InitGame();

	void LoadGame();

	/**
	 * Must be called before running every new routine, i.e. before calling RunRoutine().
	 * Unfortunately, the current locals must be saved in a temp array prior to calling.
	 * The argument n gives the number of arguments passed.
	 */
	void PassLocals(int n);

	inline unsigned char Peek(long a) {
		return MEM(defseg * 16L + a);
	}

	inline unsigned int PeekWord(long a) {
		return (unsigned char)MEM(defseg * 16L + a) + (unsigned char)MEM(defseg * 16L + a + 1) * 256;
	}

	inline void Poke(unsigned int a, unsigned char v) {
		SETMEM(defseg * 16L + a, v);
	}

	inline void PokeWord(unsigned int a, unsigned int v) {
		SETMEM(defseg * 16L + a, (char)(v % 256));
		SETMEM(defseg * 16L + a + 1, (char)(v / 256));
	}

	/**
	 * Returns <a> as a hex-number string in XXXXXX format.
	 */
	static const char *PrintHex(long a);

	/**
	 * Print to client display taking into account cursor relocation,
	 * font changes, color setting, and window scrolling.
	 */
	void Printout(char *a, int no_scrollback_linebreak);

	void PromptMore();

	int RecordCommands();

	/**
	 * Formats:
	 *
	 * end of turn:    (0, undoturn, 0, 0, 0)
	 * move obj.:      (MOVE_T, obj., parent, 0, 0)
	 * property:       (PROP_T, obj., prop., # or PROP_ROUTINE, val.)
	 * attribute:      (ATTR_T, obj., attr., 0 or 1, 0)
	 * variable:       (VAR_T, var., value, 0, 0)
	 * array:          (ARRAYDATA_T, array addr., element, val., 0)
	 * dict:           (DICT_T, entry length, 0, 0, 0)
	 * word setting:   (WORD_T, word number, new word, 0, 0)
	 */
	void SaveUndo(int a, int b, int c, int d, int e);

	/**
	 * Properly sets up the code_block structure for the current stack depth depending
	 * on if this is a called block (RUNROUTINE_BLOCK) or otherwise.
	 */
	void SetStackFrame(int depth, int type, long brk, long returnaddr);

	void SetupDisplay();

	/**
	 * The method is passed <a> as the string and <*i> as the position in the string.
	 * The character(s) at a[*i], a[*(i+1)], etc. are converted into a single Latin-1
	 * (i.e., greater than 127) character value.
	 *
	 * Assume that the AP() has already encountered a control character ('\'),
	 * and that a[*i]... is one of:
	 *
	 * `a	accent grave on following character (e.g., 'a')
	 * 'a	accent acute on following character (e.g., 'a')
	 * ~n	tilde on following (e.g., 'n' or 'N')
	 * :a	umlaut on following (e.g., 'a')
	 * ^a	circumflex on following (e.g., 'a')
	 * ,c	cedilla on following (e.g., 'c' or 'C')
	 * <	Spanish left quotation marks
	 * >	Spanish right quotation marks
	 * !	upside-down exclamation mark
	 * ?	upside-down question mark
	 * ae	ae ligature
	 * AE	AE ligature
	 * c	cents symbol
	 * L	British pound
	 * Y	Japanese Yen
	 * -	em (long) dash
	 * #nnn	character value given by nnn
	 *
	 * Note that the return value is a single character--which will be either unchanged
	 * or a Latin-1 character value.
	 */
	char SpecialChar(const char *a, int *i);

	int Undo();

	/**@}*/

	/**
	 * \defgroup heobject - Object/property/attribute management functions
	 * @{
	 */

#if defined (DEBUGGER)
	int CheckinRange(uint v1, uint v2, const char *v3) {
		// TODO: Where the heck is this actualy implemented in Gargoyle
		return 1;
	}

	 /**
	  * Shorthand since many of these object functions may call CheckinRange() if the debugger
	  * is running and runtime_warnings is set.
	 */
	int CheckObjectRange(int obj);

	void DebugRunRoutine(long addr) {}

	void RuntimeWarning(const char *msg) {}

	void DebugMessageBox(const char *title, const char *msg) {}

	bool IsBreakpoint(long loc) const { return false; }

	const char *RoutineName(long loc) { return "Routine"; }

	void AddStringtoCodeWindow(const char *str) {}

	void SwitchtoDebugger() {}

	void DebuggerFatal(DEBUGGER_ERROR err) { error("Debugger error"); }

	void RecoverLastGood() {}
#endif

	int Child(int obj);

	int Children(int obj);

	int Elder(int obj);

	/**
	 * Returns one of four sets of 32 attributes.
	 */
	unsigned long GetAttributes(int obj, int attribute_set);

	/**
	 * Returns the value of '<obj>.<p> #<n>'  If <s> is true, the self global
	 * is not set to <obj> in order to facilitate <obj>..<p> calls.
	 */
	int GetProp(int obj, int p, int n, char s);

	/**
	 * Returns the value of the last object above <obj> in the tree before object 0.
	 */
	int GrandParent(int obj);

	void MoveObj(int obj, int p);

	const char *Name(int obj);

	int Parent(int obj);

	/**
	 * Returns address of <obj>.<p> (with <offset> provided for additive properties--
	 * i.e. subsequent calls with the same <obj> and <p>.
	 */
	unsigned int PropAddr(int obj, int p, unsigned int offset);

	/**
	 * Writes (puts) one of four sets of 32 attributes.
	 */
	void PutAttributes(int obj, unsigned long a, int attribute_set);

	/**
	 * Set an attribute
	 * c = 1 for set, 0 for clear
	 */
	void SetAttribute(int obj, int attr, int c);

	int Sibling(int obj);

	int TestAttribute(int obj, int attr, int nattr);

	int Youngest(int obj);

	/**@}*/

	/**
	* \defgroup Miscellaneous
	* @{
	*/

	int hugo_fseek(Common::SeekableReadStream *s, long int offset, int whence) {
		return s->seek(offset, whence);
	}

	int hugo_fgetc(Common::SeekableReadStream *s) {
		return s->readByte();
	}

	bool hugo_ferror(Common::SeekableReadStream *s) const {
		return s->err();
	}

	long hugo_ftell(Common::SeekableReadStream *s) {
		return s->pos();
	}

	int hugo_fclose(strid_t f) {
		delete f;
		return 0;
	}

	void hugo_exit(const char *msg) {
		error("%s", line);
	}

	size_t hugo_fread(void *ptr, size_t size, size_t count, Common::SeekableReadStream *s) {
		return s->read(ptr, size * count);
	}

	/**@}*/
private:
	/**
	 * Allocate memory block
	 */
	void *hugo_blockalloc(size_t num) { return malloc(num); }

	void hugo_blockfree(void *block) { free(block); }
public:
	/**
	 * Constructor
	 */
	Hugo(OSystem *syst, const GlkGameDescription &gameDesc);

	/**
	 * Run the game
	 */
	void runGame();

	/**
	 * Returns the running interpreter type
	 */
	virtual InterpreterType getInterpreterType() const override { return INTERPRETER_HUGO; }

	/**
	 * Load a savegame from the passed stream
	 */
	virtual Common::Error loadGameData(strid_t file) override;

	/**
	 * Save the game to the passed stream
	 */
	virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override;

	// TODO: Stubs to be Properly implemented
	int GetValue() { return 0; }
	void PlayGame() {}
	void hugo_closefiles() {}
	void RunRoutine(long v) {}
	unsigned int FindWord(const char *a) { return 0; }
	void hugo_stopsample() {}
	void hugo_stopmusic() {}
	int hugo_hasgraphics() { return 0; }
	int hugo_writetoscript(const char *s) { return 0; }
};

} // End of namespace Hugo
} // End of namespace Glk

#endif