· 9 years ago · Oct 03, 2016, 08:12 PM
1//######################################################
2//
3// Kern des Skriptpakets "Ikarus"
4// Autor : Sektenspinner
5// Co-Autor : Gottfried
6// Version : 1.2.0
7//
8//######################################################
9
10//************************************************
11// Content:
12//************************************************
13/*
14 ## Preamble ##
15 -Versioncheck
16 -Logging Functions (preliminary)
17 -Parser Data Stack Hacking
18
19 ## Basic Read Write ##
20 -Read/Write of Integers, Strings, Arrays, Bytes
21
22 ## Basic zCParser related functions ##
23 -MEM_ReinitParser: Locate Parser data structures.
24 -Get and set instance offsets (e.g. MEM_PtrToInst)
25 -Jumps (via MEM_StackPos)
26 -MEM_GetFuncID and friends
27 -Address Operator _@ and friends
28 -Access static Arrays
29
30 ## Preliminary MEM_Alloc and MEM_Free ##
31 -(De-)Allocation with Strings
32
33 ## CALL Package ##
34 -ASM: Bytecode Streams and their execution
35 -CALL_Begin / End: The faster Mode of the package
36 -Parameter pushing
37 -Result poping
38 -calling conventions
39
40 ## UTILITY ##
41 -MEM_SetShowDebug
42 -MEM_Copy
43 -MEM_Swap
44 -MEM_Clear
45 -MEM_Realloc
46 -MEM_Compare
47
48 ## Windows Utilities ##
49 -LoadLibrary / GetProcAddress
50 -VirtualProtect / MemoryProtectionOverride
51 -MEM_MessageBox / MEM_InfoBox
52
53 ## Arrays ##
54 -Alloc / Clear / Free / Size / Read / Write
55 -Insert / Push / Pop / Top
56 -IndexOf / RemoveIndex / RemoveValue[Once]
57 -Sort / Unique
58 -ToString
59
60 ## String Tools ##
61 -GetCharAt / Length
62 -Substring / Prefix
63 -Compare
64 -STR_ToInt
65 -STR_IndexOf
66 -STR_Split
67 -STR_Upper
68
69 ## Elaborate zCParser related functions ##
70 -MEM_(Find/Get)ParserSymbol
71 -MEM_Call[, ByID, ByString]
72 -Find function by Stack Offset
73 -Locate current execution position on machine stack
74 * MEM_GetCallerStackPos
75 * MEM_SetCallerStackPos
76 -Label / goto / while / repeat
77 * Split function into tokens
78 * Trace calculation of parameter
79 * patch function
80 * Handle first while
81 * Handle first goto
82 * Handle first repeat
83
84 ## Access Menu Objects ##
85 -Find Menus and Menuitems by string
86
87 ## zCObjects ##
88 -Commonly used objects (MEM_InitGlobalInst)
89 -Validity checks (Hlp_Is_*)
90 -Find zCClassDef and class name for object
91 -Create and delete vobs
92 * MEM_InsertVob
93 * MEM_DeleteVob
94 -Locate Objects in the worlds Hash table
95 * Evaluate hash function
96 * Find Objects by name
97 * Properly change object name
98 -Send trigger and untrigger
99
100 ## Keyboard interaction ##
101 -MEM_KeyState
102 -MEM_InsertKeyEvent
103
104 ## Read and Write Ini Values ##
105 -Reading
106 * In Gothic's configuration
107 * In the mod's configuration
108 * Get command line
109 * Get key assignment
110 -Writing
111 * in Gothic's configuration
112 * Apply changes and write to disk
113
114 ## Benchmarking and time measurement ##
115 -Time Measurement
116 * Milliseconds
117 * Performance Counter
118 -Benchmark
119
120 ## Logging and Debug ##
121 -Send Info/Warning/Error to zSpy
122 -Print the Stacktrace
123 * Print Stacktrace line
124 * Print full Stack Trace
125 * Exception handler
126 * Installing the exeption handler
127
128 ## Revised functions ##
129 -Faster MEM_ReadInt / MEM_WriteInt
130 -Faster MEM_Alloc and MEM_Free
131
132 ## MEM_InitAll
133*/
134
135//#################################################
136//
137// Preamble
138//
139//#################################################
140
141//----------------------------------------------
142// Versioncheck
143// If your Code relies on fixes introduced in
144// a certain version of Ikarus,
145// and you want to give your code to users
146// that may have old versions, use this:
147//----------------------------------------------
148
149const int IKARUS_VERSION = 10200; //2 digits for Major and Minor Revision number.
150
151/* returns 1 if the version of Ikarus is the specified version or newer */
152func int MEM_CheckVersion(var int base, var int major, var int minor) {
153 if (major > 99 || minor > 99) {
154 return false;
155 };
156
157 return base*10000 + major * 100 + minor <= IKARUS_VERSION;
158};
159
160//--------------------------------------
161// Logging functions
162// MEM_SendToSpy will be revised
163// by MEM_InitAll to print neatly
164//--------------------------------------
165
166/* should the next message have an error box? */
167var int MEMINT_ForceErrorBox;
168
169func void MEM_SendToSpy(var int errorType, var string text) {
170 /* Implementierung wird von MEM_InitAll ersetzt! */
171 PrintDebug(ConcatStrings(text, "<<< (This is a preliminary printing variant, use MEM_InitAll to get neat 'Q:' prefixed messages.) >>>")); /* Q: is the Ikarus mark */
172};
173
174func void MEM_ErrorBox(var string text) {
175 MEMINT_ForceErrorBox = true;
176 MEM_SendToSpy(zERR_TYPE_FAULT, text);
177};
178
179func void MEM_PrintStackTrace() {
180 var string error; error = "MEM_PrintStackTrace: Cannot print the stacktrace before MEM_InitAll was called!";
181 MEM_SendToSpy(zERR_TYPE_FAULT, error);
182};
183
184func void MEMINT_HandleError(var int errorType, var string text) {
185 if (errorType >= zERR_PrintStackTrace) {
186 const int once = 0;
187 if (!once || !zERR_StackTraceOnlyForFirst) {
188 once = true;
189 MEM_PrintStackTrace();
190 };
191 };
192
193 if (errorType >= zERR_ReportToZSpy) {
194 const int errorBoxOnce = 0;
195 if (errorType >= zERR_ShowErrorBox)
196 && (!zERR_ErrorBoxOnlyForFirst || !errorBoxOnce) {
197 MEMINT_ForceErrorBox = true;
198 errorBoxOnce = true;
199 };
200
201 MEM_SendToSpy(errorType, text);
202 };
203};
204
205func void MEM_Error(var string error) {
206 MEMINT_HandleError(zERR_TYPE_FAULT, error);
207};
208
209func void MEM_Warn(var string warn) {
210 MEMINT_HandleError(zERR_TYPE_WARN, warn);
211};
212
213func void MEM_Info(var string info) {
214 if (zERR_ReportToZSpy > zERR_TYPE_INFO)
215 && (zERR_PrintStackTrace > zERR_TYPE_INFO) {
216 return; //dont waste time
217 };
218
219 MEMINT_HandleError(zERR_TYPE_INFO, info);
220};
221
222func void MEM_AssertFail (var string assertFailText) {
223 assertFailText = ConcatStrings ("Assertion failed. Report this: ", assertFailText);
224 MEM_Error (assertFailText);
225};
226
227/* custom channel */
228
229func void MEM_Debug(var string message) {
230 message = ConcatStrings(zERR_DEBUG_PREFIX, message);
231
232 if (zERR_DEBUG_TOSCREEN) {
233 Print(message);
234 };
235
236 if (zERR_DEBUG_ERRORBOX) {
237 MEMINT_ForceErrorBox = true;
238 };
239
240 if (zERR_DEBUG_ERRORBOX || zERR_DEBUG_TOSPY) {
241 MEM_SendToSpy(zERR_DEBUG_TYPE, message);
242 };
243};
244
245//--------------------------------------
246// Parser Data Stack Hacking
247//--------------------------------------
248
249class MEMINT_HelperClass {};
250var MEMINT_HelperClass MEMINT_INSTUNASSIGNED;
251var MEMINT_HelperClass MEMINT_PopDump;
252
253func int MEMINT_StackPushInt (var int val) {
254 return +val;
255};
256
257//Vorsicht: Referenz wird gepusht!
258func string MEMINT_StackPushString (var string val) {
259 return val;
260};
261
262func MEMINT_HelperClass MEMINT_StackPopInstSub () {};
263func void MEMINT_StackPopInst () {
264 MEMINT_PopDump = MEMINT_StackPopInstSub();
265};
266
267func void MEMINT_StackPushInst (var int val) {
268 MEMINT_StackPushInt (val);
269 MEMINT_StackPopInst();
270};
271
272func void MEMINT_StackPushVar (var int adr) {
273 MEMINT_StackPushInst (adr);
274 MEMINT_StackPushInst (zPAR_TOK_PUSHVAR);
275};
276
277//Alternative Formulierungen:
278func int MEMINT_PopInt() {};
279func string MEMINT_PopString() {};
280func int MEMINT_StackPopInt() {};
281func string MEMINT_StackPopString() {};
282func int MEMINT_StackPopInstAsInt() {
283 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
284};
285
286//--------------------------------------
287// MEM_Helper
288//--------------------------------------
289
290INSTANCE MEM_HELPER_INST (C_NPC)
291{
292 name = MEM_HELPER_NAME;
293 id = 42;
294
295 /* unsterblich: */
296 flags = 2;
297 attribute [ATR_HITPOINTS_MAX] = 2;
298 attribute [ATR_HITPOINTS] = 2;
299
300 /* irgendein Visual: */
301 Mdl_SetVisual (self, "Meatbug.mds");
302};
303
304var oCNpc MEM_Helper;
305
306func void MEMINT_GetMemHelper() {
307 MEM_Helper = Hlp_GetNpc (MEM_HELPER_INST);
308
309 if (!Hlp_IsValidNpc (MEM_Helper)) {
310 //self zwischenspeichern
311 var C_NPC selfBak;
312 selfBak = Hlp_GetNpc (self);
313 Wld_InsertNpc (MEM_HELPER_INST, MEM_FARFARAWAY);
314 MEM_Helper = Hlp_GetNpc (self);
315 self = Hlp_GetNpc (selfBak);
316 };
317};
318
319//GOTHIC_BASE_VERSION == 1 ? g1Val : g2Val
320func int MEMINT_SwitchG1G2(var int g1Val, var int g2Val) {
321 if (GOTHIC_BASE_VERSION == 1) {
322 return g1Val;
323 } else {
324 return g2Val;
325 };
326};
327
328//######################################################
329//
330// Basic Read Write Operations
331//
332//######################################################
333
334//--------------------------------------
335// Reading Parser-Data-Stack-Hacking
336//--------------------------------------
337
338func int MEM_ReadInt (var int address) {
339 /* note: there will not be error handling once Ikarus is
340 * fully set up by MEM_InitAll. This function will be replaced. */
341 if (address <= 0) {
342 MEM_Error (ConcatStrings ("MEM_ReadInt: Invalid address: ", IntToString (address)));
343 return 0;
344 };
345
346 MEMINT_StackPushVar (address);
347 MEMINT_StackPushInt (MEMINT_StackPopInt()); //als int nicht als var auf dem Stack
348};
349
350func string MEM_ReadString (var int address) {
351 if (address <= 0) {
352 MEM_Error (ConcatStrings ("MEM_ReadString: Invalid address: ", IntToString (address)));
353 return "";
354 };
355
356 MEMINT_StackPushVar (address);
357};
358
359//--------------------------------------
360// Assignments
361//--------------------------------------
362
363//Alte Lesemethode wird nur zum Bootstrap des neuen Systems gebraucht.
364func void MEMINT_OldWriteInt (var int address, var int val) {
365 /* other = address - MEM_NpcID_Offset */
366 MEM_Helper.enemy = address - MEM_NpcID_Offset;
367 /* res wird nicht gebraucht, müllt aber sonst den Stack zu! */
368 var int res; res = Npc_GetTarget (MEM_Helper);
369
370 /* *(other + oCNpc_idx_offset) = val */
371 other.id = val;
372};
373
374func void MEMINT_PrepareAssignments() {
375 /* sorgt dafür, dass MEMINT_Assign und MEMINT_StrAssign
376 * genau die Funktion von zPAR_OP_IS bzw. zPAR_TOK_ASSIGNSTR
377 * erfüllen.
378 * Diese Funktion wird nach Start von Gothic genau einmal aufgerufen. */
379
380 var int symTab; var int MEMINT_Assign_Sym; var int MEMINT_Assign_StackPos; var int stackStart;
381
382 //Navigation zum Code dieser Funktionen:
383 symTab = MEM_ReadInt (ContentParserAddress + zCParser_symtab_table_array_offset);
384 stackStart = MEM_ReadInt (ContentParserAddress + zCParser_stack_offset);
385 MEMINT_Assign_Sym = MEM_ReadInt (symTab + 4 * (MEMINT_AssignPredecessor + 1));
386 MEMINT_Assign_StackPos = MEM_ReadInt (MEMINT_Assign_Sym + zCParSymbol_content_offset);
387
388 //alte Lesemethode braucht Npc
389 MEMINT_GetMemHelper();
390 var C_NPC othBak;
391 othBak = Hlp_GetNpc (other);
392
393 //Code überschreiben. Vorsicht: Der erste Aufruf soll auch klappen!
394 MEMINT_OldWriteInt (stackStart + MEMINT_Assign_StackPos , (zPAR_OP_IS << 0) | (zPAR_TOK_RET << 8) | (zPAR_TOK_RET << 16) | (zPAR_TOK_RET << 24));
395 MEMINT_OldWriteInt (stackStart + MEMINT_Assign_StackPos + 4, (zPAR_TOK_RET << 0) | (zPAR_OP_IS << 8) | (zPAR_TOK_RET << 16) | (zPAR_TOK_RET << 24));
396 MEMINT_OldWriteInt (stackStart + MEMINT_Assign_StackPos + 8, (zPAR_TOK_ASSIGNSTR << 0) | (zPAR_TOK_RET << 8) | (zPAR_TOK_RET << 16) | (zPAR_TOK_RET << 24));
397 MEMINT_OldWriteInt (stackStart + MEMINT_Assign_StackPos + 12, (zPAR_TOK_RET << 0) | (zPAR_TOK_ASSIGNSTR << 8) | (zPAR_TOK_RET << 16) | (zPAR_TOK_RET << 24));
398
399 //alte Lesemethode muss aufräumen
400 MEM_Helper.enemy = 0;
401 other = Hlp_GetNpc (othBak);
402};
403
404var MEMINT_HelperClass MEMINT_AssignPredecessor;
405func void MEMINT_Assign() {
406 /* Hier soll stehen:
407 * zPAR_OP_IS
408 * zPAR_TOK_RET
409 *
410 * das schreibe ich da jetzt hin: */
411
412 MEMINT_PrepareAssignments (); //zPAR_TOK_CALL + 4 bytes
413 return; //zPAR_TOK_RET
414 return; //zPAR_TOK_RET
415 //zPAR_TOK_RET
416
417 //Summe: 8 Bytes
418};
419
420func void MEMINT_StrAssign() {
421 /* Hier soll stehen:
422 * zPAR_TOK_ASSIGNSTR
423 * zPAR_TOK_RET
424 *
425 * das schreibe ich da jetzt hin: */
426
427 MEMINT_PrepareAssignments (); //zPAR_TOK_CALL + 4 bytes
428 return; //zPAR_TOK_RET
429 return; //zPAR_TOK_RET
430 //zPAR_TOK_RET
431
432 //Summe: 8 Bytes
433};
434
435//--------------------------------------
436// Schreiboperationen
437//--------------------------------------
438
439func void MEM_WriteInt (var int address, var int val) {
440 /* note: there will not be error handling once Ikarus is
441 * fully set up by MEM_InitAll. This function will be replaced. */
442
443 if (address <= 0) {
444 MEM_Error (ConcatStrings ("MEM_WriteInt: Invalid address: ", IntToString (address)));
445 return;
446 };
447
448 MEMINT_StackPushInt (val);
449 MEMINT_StackPushVar (address);
450
451 MEMINT_Assign();
452};
453
454func void MEM_WriteString (var int address, var string val) {
455 if (address <= 0) {
456 MEM_Error (ConcatStrings ("MEM_WriteString: Invalid address: ", IntToString (address)));
457 return;
458 };
459
460 MEMINT_StackPushString (val);
461 MEMINT_StackPushVar (address);
462
463 MEMINT_StrAssign();
464};
465
466//------------------------------------------------
467// Byte-Zugriff
468//------------------------------------------------
469
470func int MEM_ReadByte (var int adr) {
471 return MEM_ReadInt (adr) & 255;
472};
473
474func void MEM_WriteByte (var int adr, var int val) {
475 if (val & ~ 255) {
476 MEM_Warn ("MEM_WriteByte: Val out of range! Truncating to 8 bits.");
477 val = val & 255;
478 };
479
480 MEM_WriteInt (adr, (MEM_ReadInt (adr) & ~ 255) | val);
481};
482
483//--------------------------------------
484// Arrayzugriff
485//--------------------------------------
486
487func int MEM_ReadIntArray (var int arrayAddress, var int offset) {
488 return MEM_ReadInt (arrayAddress + 4 * offset);
489};
490
491func void MEM_WriteIntArray (var int arrayAddress, var int offset, var int value) {
492 MEM_WriteInt (arrayAddress + 4 * offset, value);
493};
494
495func int MEM_ReadByteArray (var int arrayAddress, var int offset) {
496 return MEM_ReadByte (arrayAddress + offset);
497};
498
499func void MEM_WriteByteArray (var int arrayAddress, var int offset, var int value) {
500 MEM_WriteByte (arrayAddress + offset, value);
501};
502/* Zurzeit in LeGo drin.
503func string MEM_ReadStringArray (var int arrayAddress, var int offset) {
504 return MEM_ReadString (arrayAddress + offset * sizeof_zString);
505};*/
506
507func void MEM_WriteStringArray (var int arrayAddress, var int offset, var string value) {
508 MEM_WriteString (arrayAddress + sizeof_zString * offset, value);
509};
510
511//######################################################
512//
513// Basic zCParser related functions
514//
515//######################################################
516
517//Deprecated, use MEM_Parser instead!
518const int currParserAddress = 0; //const to keep it valid through loading
519const int currSymbolTableAddress = 0;
520const int currSymbolTableLength = 0;
521const int currSortedSymbolTableAddress = 0;
522const int currParserStackAddress = 0;
523const int contentSymbolTableAddress = 0;
524
525func void MEM_ReinitParser() {
526 currParserAddress = ContentParserAddress;
527
528 //Die Symboltabelle im Parser:
529 currSymbolTableAddress = MEM_ReadInt (currParserAddress + zCParser_symtab_table_array_offset);
530 currSymbolTableLength = MEM_ReadInt (currParserAddress + zCParser_symtab_table_array_offset + 8);
531 currSortedSymbolTableAddress = MEM_ReadInt (currParserAddress + zCParser_sorted_symtab_table_array_offset);
532 currParserStackAddress = MEM_ReadInt (currParserAddress + zCParser_stack_offset);
533
534 //Die Contentsymboltabelle braucht man immer mal wieder:
535 contentSymbolTableAddress = MEM_ReadInt (ContentParserAddress + zCParser_symtab_table_array_offset);
536};
537
538//removed, but keep stub
539func void MEM_SetParser(var int ID) {
540 if (!ID) {
541 MEM_Warn("MEM_SetParser was removed in Ikarus Version 1.2 and should not be used any more.");
542 } else {
543 MEM_Error("MEM_SetParser was removed in Ikarus Version 1.2 and cannot be used to change the current parser any more.");
544 };
545};
546
547//************************************************
548// Get and set instance offsets
549//************************************************
550
551//--------------------------------------
552// Instanz auf Pointer zeigen lassen
553//--------------------------------------
554
555var int MEM_AssignInstSuppressNullWarning;
556func void MEM_AssignInst (var int inst, var int ptr) {
557 if (inst <= 0) {
558 /* Anmerkung: inst == 0 kann auch nicht sein,
559 * da es keine Instance vor einer Klassendeklaration
560 * geben kann. */
561 MEM_Error (ConcatStrings ("MEM_AssignInst: Invalid instance: ", IntToString (inst)));
562 return;
563 };
564
565 if (ptr <= 0) {
566 if (ptr < 0) {
567 MEM_Error (ConcatStrings ("MEM_AssignInst: Invalid pointer: ", IntToString (ptr)));
568 return;
569 } else if (!MEM_AssignInstSuppressNullWarning) {
570 /* Instanzen die Null sind, will man eigentlich nicht, die machen nur Ärger. */
571 MEM_Warn ("MEM_AssignInst: ptr is NULL. Use MEM_AssignInstNull if that's what you want.");
572 };
573 };
574
575 var int sym;
576 sym = MEM_ReadIntArray (currSymbolTableAddress, inst);
577 MEM_WriteInt (sym + zCParSymbol_offset_offset, ptr);
578};
579
580func void MEM_AssignInstNull (var int inst) {
581 /* Normalerweise will man Instanzen nicht zurück auf 0 setzen.
582 * Oft wird es ein Fehler sein. Daher wird oben eine Warnung ausgegeben.
583 * Um die nicht zu bekommen gibt es hier die explizite Funktion */
584 MEM_AssignInstSuppressNullWarning = true;
585 MEM_AssignInst (inst, 0);
586 MEM_AssignInstSuppressNullWarning = false;
587};
588
589func MEMINT_HelperClass MEM_PtrToInst (var int ptr) {
590 var MEMINT_HelperClass hlp;
591 const int hlpOffsetPtr = 0;
592 if (!hlpOffsetPtr) {
593 hlpOffsetPtr = MEM_ReadIntArray (currSymbolTableAddress, hlp) + zCParSymbol_offset_offset;
594 };
595
596 if (ptr <= 0) {
597 if (ptr < 0) {
598 MEM_Error (ConcatStrings ("MEM_PtrToInst: Invalid pointer: ", IntToString (ptr)));
599 return;
600 } else if (!MEM_AssignInstSuppressNullWarning) {
601 /* Instanzen die Null sind, will man eigentlich nicht, die machen nur Ärger. */
602 MEM_Warn ("MEM_PtrToInst: ptr is NULL. Use MEM_NullToInst if that's what you want.");
603 };
604
605 MEM_WriteInt(hlpOffsetPtr, 0);
606 } else {
607 MEM_WriteInt(hlpOffsetPtr, ptr);
608 };
609 MEMINT_StackPushInst (hlp);
610};
611
612func MEMINT_HelperClass _^ (var int ptr) {
613 MEM_PtrToInst(ptr);
614};
615
616func MEMINT_HelperClass MEM_NullToInst () {
617 var MEMINT_HelperClass hlp;
618 MEMINT_StackPushInst (hlp);
619};
620
621func MEMINT_HelperClass MEM_CpyInst (var int inst) {
622 MEMINT_StackPushInst (inst);
623};
624
625//--------------------------------------
626// Deprecated relict from the time
627// when direct access to menu/pfx/vfx parsers
628// was possible
629//--------------------------------------
630
631func void MEM_AssignContentInst (var int inst, var int ptr) {
632 const int once = 0;
633 if (!once) { once = true;
634 MEM_Warn("MEM_AssignContentInst: This function was deprecated in Ikarus Version 1.2. Use the equivalent MEM_AssignInst instead.");
635 };
636
637 MEM_AssignInst(inst, ptr);
638};
639
640func void MEM_AssignContentInstNull (var int inst) {
641 const int once = 0;
642 if (!once) { once = true;
643 MEM_Warn("MEM_AssignContentInstNull: This function was deprecated in Ikarus Version 1.2. Use the equivalent MEM_AssignInstNull instead.");
644 };
645
646 MEM_AssignInstNull(inst);
647};
648
649//--------------------------------------
650// Get offset of an instance
651//--------------------------------------
652
653func int MEM_InstToPtr(var int inst) {
654 if (inst <= 0) {
655 /* Anmerkung: inst == 0 kann auch nicht sein,
656 * da es keine Instance vor eine Klassendeklaration
657 * geben kann. */
658 MEM_Error (ConcatStrings ("MEM_InstGetOffset: Invalid inst: ", IntToString (inst)));
659 return 0;
660 };
661
662 var int symb;
663 symb = MEM_ReadIntArray (currSymbolTableAddress, inst);
664 return MEM_ReadInt (symb + zCParSymbol_offset_offset);
665};
666
667//Abwärtskompatibilität
668func int MEM_InstGetOffset (var int inst) {
669 return MEM_InstToPtr(inst);
670};
671
672//--------------------------------------
673// Unsinnig. Nur zur Abwärtskompatibilität
674// überhaupt noch drin. Google sagt,
675// Lehona hat es mal irgendwo benutzt.
676//--------------------------------------
677
678//Lässt currParserSymb auf das Symbol mit Instanz inst zeigen.
679INSTANCE currParserSymb (zCPar_Symbol);
680func void MEM_SetCurrParserSymb (var int inst) {
681 if (inst <= 0) {
682 MEM_Error (ConcatStrings ("MEM_SetCurrParserSymb: Invalid inst: ", IntToString (inst)));
683 return;
684 };
685
686 var int symOffset; var int currParserSymOffset;
687 symOffset = MEM_ReadIntArray (currSymbolTableAddress, inst);
688 currParserSymOffset = MEM_ReadIntArray (contentSymbolTableAddress, currParserSymb);
689
690 MEM_WriteInt (currParserSymOffset + zCParSymbol_offset_offset, symOffset);
691};
692
693//************************************************
694// Sprünge
695//************************************************
696
697/* Es sieht einfach aus, gell? Aber das das funktioniert ist
698 * gar nicht so offensichtlich wie man glaubt.
699 * Das hier geht zum Beispiel:
700{
701 label = MEM_StackPos.position;
702
703 [...]
704
705 MEM_StackPos.position = label;
706};
707
708 * Das hier geht grandios schief:
709
710{
711 label = MEM_StackPos.position + 0;
712
713 [...]
714
715 MEM_StackPos.position = label;
716};
717
718 * Wer Experimente macht, wird wahrscheinlich auf die Nase fallen.
719 * Es ist Zufall, dass es so einfach funktioniert! */
720
721class MEMINT_StackPos {
722 var int position;
723};
724
725var MEMINT_StackPos MEM_StackPos;
726
727func void MEM_InitLabels() {
728 MEM_StackPos = _^(ContentParserAddress + zCParser_stack_stackPtr_offset);
729};
730
731func void MEM_CallByPtr(var int ptr) {
732 MEM_StackPos.position = ptr;
733};
734
735func void MEM_CallByOffset(var int offset) {
736 MEM_CallByPtr(offset + currParserStackAddress);
737};
738
739//************************************************
740// Idee von Gottfried: ID einer Funktion
741//************************************************
742
743func int MEM_GetFuncID(var func fnc) {
744 var zCPar_Symbol symb; /* dummy symbol with index indexOf(fnc)+1 */
745 symb = MEM_PtrToInst(MEM_ReadIntArray(contentSymbolTableAddress, symb - 1));
746
747 var int res;
748 var int loop; loop = MEM_StackPos.position;
749
750 if ((symb.bitfield & zCPar_Symbol_bitfield_type) != zPAR_TYPE_FUNC) {
751 MEM_Warn("MEM_GetFuncID: Unresolvable request (probably uninitialised function variable).");
752 return -1;
753 };
754
755 if (symb.bitfield & zPAR_FLAG_CONST) {
756 return +res;
757 } else {
758 res = symb.content;
759 symb = MEM_PtrToInst(MEM_ReadIntArray(contentSymbolTableAddress, res));
760 MEM_StackPos.position = loop;
761 };
762};
763
764func int MEM_GetFuncOffset(var func fnc) {
765 var int r;
766 r = MEM_GetFuncID(fnc); //ID(fnc)
767 r = MEM_ReadIntArray(contentSymbolTableAddress, r); //symbolTable[ID(fnc)]
768 r = MEM_ReadInt(r + zCParSymbol_content_offset); //symbolTable[ID(fnc)].content
769 return r + 0;
770};
771
772func int MEM_GetFuncPtr(var func fnc) {
773 return MEM_GetFuncOffset(fnc) + currParserStackAddress;
774};
775
776func void MEM_ReplaceFunc(var func f1, var func f2) {
777 var int ptr; ptr = MEM_GetFuncPtr(f1);
778 var int target; target = MEM_GetFuncOffset(f2);
779
780 /* jetzt bitte in einem Rutsch, nicht, dass da einer was ersetzen will, was ich brauche. */
781 MEM_WriteByte(ptr, zPAR_TOK_JUMP);
782 MEM_WriteInt (ptr + 1, target);
783};
784
785//************************************************
786// Functions that help me write Byte Code
787//************************************************
788
789var int MEMINT_OverrideFunc_Ptr;
790func void MEMINT_InitOverideFunc(var func f) {
791 MEMINT_OverrideFunc_Ptr = MEM_GetFuncPtr(f);
792};
793
794/* override function, token */
795func void MEMINT_OFTok(var int tok) {
796 MEM_WriteByte(MEMINT_OverrideFunc_Ptr, tok);
797 MEMINT_OverrideFunc_Ptr += 1;
798};
799
800/* override function, token + parameter */
801func void MEMINT_OFTokPar(var int tok, var int param) {
802 MEMINT_OFTok(tok);
803 MEM_WriteInt(MEMINT_OverrideFunc_Ptr, param);
804 MEMINT_OverrideFunc_Ptr += 4;
805};
806
807
808//************************************************
809// New Operators
810//************************************************
811
812//--------------------------------------
813// Address Operator
814//--------------------------------------
815
816//Dummies that are filled later:
817func int MEM_GetIntAddress(var int i) {
818 MEM_Error("MEM_GetIntAddress called before MEM_GetAddress_Init!");
819 return 0;
820};
821
822func int MEM_GetFloatAddress(var float f) {
823 MEM_Error("MEM_GetFloatAddress called before MEM_GetAddress_Init!");
824 return 0;
825};
826
827func int MEM_GetStringAddress(var string s) {
828 MEM_Error("MEM_GetStringAddress called before MEM_GetAddress_Init!");
829 return 0;
830};
831
832func int _@(var int i) {
833 MEM_Error("_@ called before MEM_GetAddress_Init!");
834 i = i; i = i; i = i; i = i; i = i; i = i; /* some space */
835 return 0;
836};
837
838func int _@s(var string s) {
839 MEM_Error("_@s called before MEM_GetAddress_Init!");
840 return 0;
841};
842
843func int _@f(var float f) {
844 MEM_Error("_@f called before MEM_GetAddress_Init!");
845 return 0;
846};
847
848func void MEMINT_GetAddress_Init(var func f) {
849 var MEMINT_HelperClass symb;
850
851 MEMINT_InitOverideFunc(f);
852 MEMINT_OFTokPar(zPAR_TOK_PUSHINST , symb );
853 MEMINT_OFTok (zPAR_TOK_ASSIGNINST );
854 MEMINT_OFTokPar(zPAR_TOK_PUSHINST , zPAR_TOK_PUSHINT);
855 MEMINT_OFTok (zPAR_TOK_RET );
856};
857
858func void MEM_GetAddress_Init() {
859 const int init_done = 0;
860 if (!init_done) {
861 MEMINT_GetAddress_Init(MEM_GetIntAddress);
862 MEMINT_GetAddress_Init(MEM_GetFloatAddress);
863 MEMINT_GetAddress_Init(MEM_GetStringAddress);
864 MEMINT_GetAddress_Init(STR_GetAddress);
865 MEMINT_GetAddress_Init(_@f);
866 MEMINT_GetAddress_Init(_@s);
867
868 /* something else for _@ */
869 MEMINT_InitOverideFunc(_@);
870 /* push zPAR_TOK_PUSHINT */ MEMINT_OFTokPar(zPAR_TOK_PUSHINST , zPAR_TOK_PUSHINT );
871 /* push int zPAR_TOK_PUSHINT */ MEMINT_OFTokPar(zPAR_TOK_PUSHINT , zPAR_TOK_PUSHINT );
872 /* equal? */ MEMINT_OFTok (zPAR_OP_EQUAL);
873 /* jumpF */ MEMINT_OFTokPar(zPAR_TOK_JUMPF , MEMINT_OverrideFunc_Ptr + 16 - currParserStackAddress);
874 /* push zPAR_TOK_PUSHINT */ MEMINT_OFTokPar(zPAR_TOK_PUSHINST , zPAR_TOK_PUSHINT );
875 /* call MEM_InstToPtr */ MEMINT_OFTokPar(zPAR_TOK_CALL , MEM_GetFuncOffset(MEM_InstToPtr) );
876 /* ret */ MEMINT_OFTok (zPAR_TOK_RET);
877 /* push zPAR_TOK_PUSHINT */ MEMINT_OFTokPar(zPAR_TOK_PUSHINST , zPAR_TOK_PUSHINT );
878 /* ret */ MEMINT_OFTok (zPAR_TOK_RET);
879 /* return var address as int */
880
881 init_done = true;
882 };
883};
884
885/**** downward compatiblity: ****/
886
887//alias for downward compatibility
888func void STR_GetAddressInit() {
889 MEM_GetAddress_Init();
890};
891
892/* for downward compatiblity there is a guarantee, that
893 * STR_GetAddress works ininitialised, but the first time
894 * may only return an address of a copy of the string */
895
896func int STR_GetAddress(var string str) {
897 str = str; //waste 11 bytes
898 MEM_GetAddress_Init(); //will override 12 bytes of THIS function
899
900 return STR_GetAddress(str);
901};
902
903//************************************************
904// Access static Arrays
905//************************************************
906
907//Workers
908func int MEMINT_ReadStatArr(var int offset) {
909 if (offset < 0) {
910 MEM_Error("MEM_ReadStatArr: Offset < 0!");
911 return 0;
912 };
913
914 MEMINT_StackPopInst();
915 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
916
917 var int adr;
918 adr = MEMINT_StackPopInt();
919
920 return MEM_ReadIntArray(adr, offset);
921};
922
923func void MEMINT_WriteStatArr(var int offset, var int value) {
924 if (offset < 0) {
925 MEM_Error("MEM_WriteStatArr: Offset < 0!");
926 return;
927 };
928
929 /* pop only the first two, the third differently: */
930 MEMINT_StackPopInst();
931 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
932
933 var int adr;
934 adr = MEMINT_StackPopInt();
935
936 MEM_WriteIntArray(adr, offset, value);
937};
938
939func void MEMINT_WriteStatStringArr(var int offset, var string value) {
940 if (offset < 0) {
941 MEM_Error("MEM_WriteStatStringArr: Offset < 0!");
942 return;
943 };
944
945 MEMINT_StackPopInst();
946 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
947
948 var int adr; adr = MEMINT_StackPopInt();
949 adr += sizeof_zString * offset;
950 MEM_WriteString(adr, value);
951};
952
953func string MEMINT_ReadStatStringArr(var int offset) {
954 if (offset < 0) {
955 MEM_Error("MEM_ReadStatStringArr: Offset < 0!");
956 return "";
957 };
958
959 MEMINT_StackPopInst();
960 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
961
962 var int adr; adr = MEMINT_StackPopInt();
963 adr += sizeof_zString * offset;
964 return MEM_ReadString(adr);
965};
966
967//Stubs
968func void MEM_WriteStatArr (var int array, var int offset, var int value) {
969 MEM_Error ("MEM_WriteStatArr was called before MEM_InitStatArrs!");
970};
971
972func int MEM_ReadStatArr (var int array, var int offset) {
973 MEM_Error ("MEM_ReadStatArr was called before MEM_InitStatArrs!");
974 return 0;
975};
976
977func void MEM_WriteStatStringArr(var string array, var int offset, var string value) {
978 MEM_Error ("MEM_WriteStatStringArr was called before MEM_InitStatArrs!");
979};
980
981func string MEM_ReadStatStringArr(var string array, var int offset) {
982 MEM_Error ("MEM_ReadStatStringArr was called before MEM_InitStatArrs!");
983};
984
985func void MEM_InitStatArrs() {
986 const int done = 0;
987
988 if (!done) {
989 MEM_ReplaceFunc(MEM_WriteStatArr, MEMINT_WriteStatArr);
990 MEM_ReplaceFunc(MEM_ReadStatArr, MEMINT_ReadStatArr);
991 MEM_ReplaceFunc(MEM_WriteStatStringArr, MEMINT_WriteStatStringArr);
992 MEM_ReplaceFunc(MEM_ReadStatStringArr, MEMINT_ReadStatStringArr);
993 done = true;
994 };
995};
996
997//######################################################
998//
999// Speicher allozieren
1000//
1001//######################################################
1002
1003func int MEM_Alloc (var int amount) {
1004 /* string mit AAAA holen */
1005 var int strPtr;
1006 var string str; str = "AAAA";
1007
1008 strPtr = _@s(str); //Adresse des zStrings im Symbol str.
1009
1010 var zString zstr;
1011 zstr = _^(strPtr); //zstr zeigt jetzt auf str
1012
1013 /* aus den As Nuller machen, weil ich genullten Speicher will */
1014 MEM_WriteInt (zstr.ptr, 0);
1015
1016 /* string mit sich selbst konkatenieren bis groß genug */
1017 var int size; size = 4;
1018
1019 //VORSICHT! mindestens einmal muss die Schleife durchlaufen werden.
1020 //sonst kommt (vermutlich, nicht genau überprüft) statisch die Adrese von der Parserkonstanten "AAAA" zurück!
1021 //Und das ist ein richtig mieser Fehler.
1022 var int loopStart; loopStart = MEM_StackPos.position;
1023 /* do */
1024 str = ConcatStrings (str, str);
1025 size *= 2;
1026 /* while */ if (size < amount) { MEM_StackPos.position = loopStart; };
1027
1028 /* Speicher ist jetzt reserviert. Dem String die Referenz wieder wegnehmen. */
1029 /* Vorsicht: ptr in Strings zeigt auf das Byte nach dem ersten Reservierten!
1030 * Strings haben Referenzzähler! */
1031 var int res; res = zstr.ptr - 1;
1032
1033 zstr.ptr = 0;
1034 zstr.len = 0;
1035 zstr.res = 0;
1036
1037 /* Der globale ConcatStrings-String darf keine Referenz mehr auf unseren String haben! */
1038
1039 //*(byte*)res == 1
1040 str = ConcatStrings("", "");
1041 //*(byte*)res == 0
1042
1043 return res;
1044};
1045
1046func void MEM_Free (var int ptr) {
1047 /* keine Nuller freigeben */
1048 if (!ptr) {
1049 MEM_Warn ("MEM_Free: ptr is 0. Ignoring request.");
1050 return;
1051 };
1052
1053 /* Vorsicht: ptr in Strings zeigt auf das Byte nach dem ersten Reservierten!
1054 * Strings haben Referenzzähler! Den Nullen! */
1055
1056 MEM_WriteByte(ptr, 0); ptr += 1;
1057
1058 /* Hilfsstring holen */
1059 var int strPtr;
1060 var string str; str = "";
1061
1062 strPtr = _@s(str);
1063
1064 var zString zstr;
1065 zstr = _^(strPtr);
1066
1067 /* dem String den Speicher geben und mit Zuweisung von "" an den String freigeben */
1068 zstr.ptr = ptr;
1069 zstr.len = 1;
1070 zstr.res = 1;
1071
1072 str = "";
1073};
1074
1075//#################################################
1076//
1077// CALL Package
1078//
1079//#################################################
1080
1081/* 1 Byte */
1082const int ASMINT_OP_movImToECX = 185; //0xB9
1083const int ASMINT_OP_movImToEDX = 186; //0xBA
1084const int ASMINT_OP_pushIm = 104; //0x68
1085const int ASMINT_OP_call = 232; //0xE8
1086const int ASMINT_OP_retn = 195; //0xC3
1087const int ASMINT_OP_nop = 144; //0x90
1088const int ASMINT_OP_jmp = 233; //0xE9
1089const int ASMINT_OP_PushEAX = 80; //0x50
1090const int ASMINT_OP_pusha = 96; //0x60 //aus LeGo geklaut
1091const int ASMINT_OP_popa = 97; //0x61 //aus LeGo geklaut
1092const int ASMINT_OP_movMemToEAX = 161; //0xA1 //aus LeGo geklaut
1093
1094/* 2 Bytes */
1095const int ASMINT_OP_movEAXToMem = 1417; //0x0589
1096const int ASMINT_OP_floatStoreToMem = 7641; //0x1DD9
1097const int ASMINT_OP_addImToESP = 50307; //0xC483
1098const int ASMINT_OP_movMemToECX = 3467; //0x0D8B
1099const int ASMINT_OP_movMemToEDX = 5515; //0x158B
1100const int ASMINT_OP_movECXtoEAX = 49547; //0xC18B aus LeGo geklaut
1101const int ASMINT_OP_movESPtoEAX = 50315; //0xC48B aus LeGo geklaut
1102const int ASMINT_OP_movEAXtoECX = 49545; //0xC189 aus LeGo geklaut
1103const int ASMINT_OP_movEBXtoEAX = 55433; //0xD889 aus LeGo geklaut
1104const int ASMINT_OP_movEBPtoEAX = 50571; //0xC58B aus LeGo geklaut
1105const int ASMINT_OP_movEDItoEAX = 51083; //0xC78B aus LeGo geklaut
1106const int ASMINT_OP_addImToEAX = 49283; //0xC083 aus LeGo geklaut
1107
1108/* Tuning:
1109 If not specified differently,
1110 there will be this much space available
1111 for an Assembler sequence. */
1112const int ASM_StandardStreamLength = 256;
1113
1114//************************************************
1115// ASM
1116//************************************************
1117
1118/* -----------------
1119/ INTERNAL STACK
1120/ ----------------- */
1121
1122/* ASM needs to save data at two points:
1123 * 1.) When calling an engine function it needs to store
1124 * the address of the current run because the Call
1125 * might use the ASM package again!
1126 * 2.) When nesting the use of the Call package there
1127 * needs to be a push and pop of the context.
1128 * 3.) Overflows are unlikely and cause a crash.
1129 */
1130
1131const int ASMINT_InternalStack = 0;
1132const int ASMINT_InternalStackWalker = 0;
1133const int ASMINT_InternalStackSize = 1024;
1134
1135func void ASMINT_Push(var int data) {
1136 if (ASMINT_InternalStackWalker >= ASMINT_InternalStackSize) {
1137 MEM_Error("ASMINT_Push: You seem to nest Engine Calls very extensively (or there is an Error in the ASM / CALL Package of Ikarus. Please contact Sekti with this problem!");
1138 };
1139
1140 MEM_WriteIntArray(ASMINT_InternalStack, ASMINT_InternalStackWalker, data);
1141 ASMINT_InternalStackWalker += 1;
1142};
1143
1144func int ASMINT_Pop() {
1145 if (ASMINT_InternalStackWalker <= 0) {
1146 MEM_Error("ASMINT_Pop: Underflow! This is probably connected to wrong use of the Call functions.");
1147 };
1148
1149 ASMINT_InternalStackWalker -= 1;
1150 return MEM_ReadIntArray(ASMINT_InternalStack, ASMINT_InternalStackWalker);
1151};
1152
1153/* -----------------
1154/ ASM Core
1155/ ----------------- */
1156
1157const int ASMINT_CallTarget = 0;
1158
1159func void ASMINT_MyExternal() {}; /* the Symbol belonging to this function will become an external symbol */
1160func void ASMINT_CallMyExternal() { /* calls some external */
1161 ExitGame(); /* will be changed so that it calls MyExternal */
1162};
1163
1164func void ASMINT_Init() {
1165 /* used later to set the pointer to the call-target. */
1166 if (!ASMINT_InternalStack) {
1167 /* create an array for later use */
1168 ASMINT_InternalStack = MEM_Alloc(4 * ASMINT_InternalStackSize);
1169
1170 /* find ASMINT_MyExternal */
1171 ASMINT_CallTarget = MEM_ReadIntArray (currSymbolTableAddress, MEM_GetFuncID(ASMINT_MYEXTERNAL));
1172 var zCPar_Symbol symb; symb = _^(ASMINT_CallTarget);
1173 ASMINT_CallTarget += zCParSymbol_content_offset; //this is where i will write what to call
1174
1175 /* turn ASMINT_MyExternal into an external */
1176 symb.bitfield = zPAR_TYPE_FUNC | zPAR_FLAG_EXTERNAL | zPAR_FLAG_CONST;
1177
1178 /* have ASM_CallMyExternal call MyExternal instead of ExitGame */
1179 MEM_WriteInt(MEM_GetFuncPtr(ASMINT_CallMyExternal) + 1, MEM_GetFuncID(ASMINT_MyExternal));
1180 };
1181};
1182
1183const int ASMINT_currRun = 0;
1184const int ASMINT_cursor = 0;
1185const int ASMINT_Length = 0;
1186
1187func void ASM_Open(var int space) {
1188 if (ASMINT_currRun) {
1189 MEM_Error ("ASM_Open: Only one stream of assembler code can be constructed at any given time (ASM_Open was called again before closing operation).");
1190 return;
1191 };
1192
1193 if (!space) {
1194 space = ASM_StandardStreamLength; //default size
1195 };
1196
1197 ASMINT_currRun = MEM_Alloc (space + 3); /* no byte fiddling at the end of the buffer */
1198 ASMINT_Length = space;
1199 ASMINT_cursor = ASMINT_currRun; /* pointing to the start */
1200};
1201
1202func void ASM (var int data, var int length) {
1203 if (!ASMINT_currRun) {
1204 ASM_Open (0);
1205 };
1206
1207 if (ASMINT_cursor - ASMINT_currRun + length > ASMINT_Length) {
1208 MEM_Error ("ASM: Reserved length is exceeded.");
1209 return;
1210 };
1211
1212 MEM_WriteInt (ASMINT_cursor, data);
1213 ASMINT_cursor += length;
1214};
1215
1216func void ASM_1 (var int data) { ASM (data, 1); };
1217func void ASM_2 (var int data) { ASM (data, 2); };
1218func void ASM_3 (var int data) { ASM (data, 3); };
1219func void ASM_4 (var int data) { ASM (data, 4); };
1220
1221func int ASM_Here() {
1222 if (!ASMINT_currRun) {
1223 ASM_Open (0);
1224 };
1225
1226 return ASMINT_cursor;
1227};
1228
1229func int ASM_Close() {
1230 ASM (ASMINT_OP_retn, 1);
1231 var int res; res = ASMINT_currRun;
1232 ASMINT_currRun = 0;
1233 return res;
1234};
1235
1236func void ASM_Run(var int ptr) {
1237 MEM_WriteInt(ASMINT_CallTarget, ptr);
1238 ASMINT_CallMyExternal();
1239};
1240
1241func void ASM_RunOnce() {
1242 if (!ASMINT_currRun) {
1243 MEM_Error ("ASM: ASM_Open has to be called before calling ASM_RunOnce.");
1244 };
1245
1246 ASM (ASMINT_OP_retn, 1);
1247
1248 /* Save this code in an array of codes.
1249 * Reason: On calling it another instance of this function may be
1250 * executing his own code */
1251
1252 ASMINT_Push(ASMINT_currRun);
1253
1254 MEM_WriteInt(ASMINT_CallTarget, ASMINT_currRun);
1255 ASMINT_currRun = 0; //more Code can be build while this one is running.
1256
1257 ASMINT_CallMyExternal();
1258
1259 /* Discard the code again */
1260 MEM_Free(ASMINT_Pop()); //free the run
1261};
1262
1263//************************************************
1264// Faster Calls
1265//************************************************
1266
1267const int CALLINT_CodeMode = 0;
1268 const int CALLINT_CodeMode_Disposable = 0;
1269 const int CALLINT_CodeMode_Recyclable = 1;
1270const int CALLINT_numParams = 0;
1271const int CALLINT_RetValStructSize = 0;
1272const int CALLINT_RetValIsFloat = 0;
1273const int CALLINT_PutRetValTo = 0;
1274
1275/* --------------------
1276/ Push and Pop Context
1277/ ----------------- */
1278
1279/* This will be used by the call package.
1280 * It became nessessary as many basic library functions
1281 * want to make use of CALL while the user might already need it. */
1282
1283func void ASMINT_PushContext() {
1284 ASMINT_Push(CALLINT_RetValStructSize);
1285 ASMINT_Push(CALLINT_RetValIsFloat);
1286 ASMINT_Push(CALLINT_PutRetValTo);
1287 ASMINT_Push(CALLINT_numParams);
1288 ASMINT_Push(CALLINT_CodeMode);
1289
1290 ASMINT_Push(ASMINT_currRun);
1291 ASMINT_Push(ASMINT_cursor);
1292 ASMINT_Push(ASMINT_Length);
1293
1294 ASMINT_currRun = 0;
1295 CALLINT_CodeMode = CALLINT_CodeMode_Disposable;
1296 CALLINT_numParams = 0;
1297 CALLINT_RetValIsFloat = 0;
1298 CALLINT_PutRetValTo = 0;
1299 CALLINT_RetValStructSize = 0;
1300};
1301
1302func void ASMINT_PopContext() {
1303 ASMINT_Length = ASMINT_Pop();
1304 ASMINT_cursor = ASMINT_Pop();
1305 ASMINT_currRun = ASMINT_Pop();
1306
1307 CALLINT_CodeMode = ASMINT_Pop();
1308 CALLINT_numParams = ASMINT_Pop();
1309 CALLINT_PutRetValTo = ASMINT_Pop();
1310 CALLINT_RetValIsFloat = ASMINT_Pop();
1311 CALLINT_RetValStructSize= ASMINT_Pop();
1312};
1313
1314/* There are two modes: The simple mode that produces a
1315 * disposable call that is used only once. All parameters
1316 * are hardcoded.
1317 * The second version produces code that can be used
1318 * more than once. Instead of the parameters the
1319 * user specifies the address where the parameters are
1320 * to be taken from. In addition to executing the code,
1321 * the user will receive an address that he can use
1322 * to repeat the call. This is much faster than
1323 * rebuilding the call from scratch. */
1324
1325/* Receives a pointer. In case the pointer is non-zero,
1326 * the code at this position is executed and 0 is returned.
1327 * In case pointer is zero, the current mode is changed
1328 * into recyclable mode, this means that the call functions
1329 * expect instructions to build a recyclable call. This
1330 * mode will continue until CALL_End(). This allows code like this:
1331
1332func int EngineFunc_Wrapper(var int this, var int param) {
1333 const int call = 0;
1334 if(CALL_Begin(call)) {
1335 CALL_IntParam(MEM_GetIntAddress(param));
1336 CALL_thiscall(MEM_GetIntAddress(this), EngineFunc_ptr);
1337 call = CALL_End();
1338 };
1339 return CALL_RetValAsInt();
1340}; */
1341
1342func void CALL_Open() {
1343 /* Push an empty context too, it is unclear how CALL_Close is
1344 * supposed to decide whether to pop or not.
1345 * Besides: This will only be executed the first time. */
1346 ASMINT_PushContext();
1347 CALLINT_CodeMode = CALLINT_CodeMode_Recyclable;
1348};
1349
1350func int CALL_Begin(var int ptr) {
1351 if (ptr) {
1352 ASM_Run(ptr);
1353 return 0;
1354 };
1355
1356 CALL_Open();
1357 return 1;
1358};
1359
1360func int CALL_Close() {
1361 if (CALLINT_CodeMode != CALLINT_CodeMode_Recyclable) {
1362 MEM_Error("CALL_Close: CALL_End or CALL_Close without matching CALL_Begin / CALL_Open? There is some serious problem with your code.");
1363 return 0;
1364 };
1365
1366 var int ptr;
1367 ptr = ASM_Close();
1368 ASMINT_PopContext(); /* restore previous context */
1369
1370 return ptr;
1371};
1372
1373func int CALL_End() {
1374 var int ptr;
1375 ptr = CALL_Close();
1376
1377 ASMINT_Push(ptr);
1378 ASM_Run(ptr); /* may use CALL_End */
1379 return ASMINT_Pop();
1380};
1381
1382//************************************************
1383// Build the code to lay parameters
1384// onto the machine stack.
1385//************************************************
1386
1387/* int */
1388func void CALL_IntParam(var int param) {
1389 if (CALLINT_CodeMode == CALLINT_CodeMode_Recyclable) {
1390 ASM_1(ASMINT_OP_movMemToEAX);
1391 ASM_4(param);
1392 ASM_1(ASMINT_OP_PushEAX);
1393 } else {
1394 ASM_1 (ASMINT_OP_pushIm);
1395 ASM_4 (param);
1396 };
1397
1398 CALLINT_numParams += 1;
1399};
1400
1401/* void */
1402func void CALL_PtrParam (var int param) {
1403 CALL_IntParam (param);
1404};
1405
1406/* float */
1407func void CALL_FloatParam (var int param) {
1408 CALL_IntParam (param);
1409};
1410
1411//string: Problem: The strings have to exist somewhere.
1412//To avoid ridiculously complicated code that needs to
1413//free the strings afterwards, I take 10 different static
1414//strings here. It is impropable that anyone ever wants
1415//to push more than ten strings on the machine stack at once.
1416func string CALLINT_PushString (var string str) {
1417 var int n; n += 1; if (n == 10) { n = 0; };
1418 if (n == 0) { var string s0; s0 = str; return s0; };
1419 if (n == 1) { var string s1; s1 = str; return s1; };
1420 if (n == 2) { var string s2; s2 = str; return s2; };
1421 if (n == 3) { var string s3; s3 = str; return s3; };
1422 if (n == 4) { var string s4; s4 = str; return s4; };
1423 if (n == 5) { var string s5; s5 = str; return s5; };
1424 if (n == 6) { var string s6; s6 = str; return s6; };
1425 if (n == 7) { var string s7; s7 = str; return s7; };
1426 if (n == 8) { var string s8; s8 = str; return s8; };
1427 if (n == 9) { var string s9; s9 = str; return s9; };
1428
1429 MEM_AssertFail ("Should be never here.");
1430};
1431
1432func int CALLINT_GetStringAddress (var string str) {
1433 return _@s(CALLINT_PushString (str));
1434};
1435
1436/* zString* */
1437func void CALL_zStringPtrParam (var string param) {
1438 if (CALLINT_CodeMode != CALLINT_CodeMode_Disposable) {
1439 MEM_Error("CALL_zStringPtrParam: This function only works when writing a disposable call!");
1440 return;
1441 };
1442
1443 /* simply push the address onto the stack */
1444 CALL_IntParam (CALLINT_GetStringAddress(param));
1445};
1446
1447/* cString* */
1448func void CALL_cStringPtrParam (var string param) {
1449 if (CALLINT_CodeMode != CALLINT_CodeMode_Disposable) {
1450 MEM_Error("CALL_cStringPtrParam: This function only works when writing a disposable call!");
1451 return;
1452 };
1453
1454 /* get the Pointer to the data and lay it on the stack */
1455 var zString str; str = _^(CALLINT_GetStringAddress(param));
1456 CALL_IntParam (str.ptr);
1457};
1458
1459/* struct (not a Pointer to a struct, but a struct as is) */
1460func void CALL_StructParam (var int ptr, var int words) {
1461 if (CALLINT_CodeMode == CALLINT_CodeMode_Recyclable) {
1462 CALL_IntParam (ptr + 4 * (words -1)); /* this is where i expect the last word */
1463 CALL_StructParam (ptr, words - 1);
1464 return;
1465 };
1466
1467 /* the struct as a whole has to be pushed onto the stack
1468 * it has to be pushed in reverse order to lie correctly */
1469 if (words > 0) {
1470 CALL_IntParam (MEM_ReadIntArray (ptr, words - 1));
1471 CALL_StructParam (ptr, words - 1);
1472 };
1473};
1474
1475/* switch: If the return value is a structure with a size
1476 * larget than 32 bit, the space for the return value has
1477 * to be allocated by the caller (this is us).
1478 * The address to the allocated memory is expected on the stack
1479 * as an additional parameter (pushed last)
1480 *
1481 * Warning: It is in the your responsibility to free
1482 * the memory, when the return value is not needed anymore.
1483 */
1484
1485func void CALL_RetValIsStruct (var int size) {
1486 if (CALLINT_CodeMode == CALLINT_CodeMode_Recyclable) {
1487 MEM_Error("CALL_RetValIsStruct: Only supported in disposable calls (not with CALL_Begin and CALL_End).");
1488 return;
1489 };
1490
1491 CALLINT_RetValStructSize = size;
1492};
1493
1494/* a special case of CALL_RetValIsStruct
1495 * a zString is a structure with the size of 20 bytes. */
1496func void CALL_RetValIszString() {
1497 CALL_RetValIsStruct (sizeof_zString);
1498};
1499
1500/* switch: If the return value is a float (and therefore
1501 * lies on the top of the FPU stack instead of lying in eax
1502 * I need to know that. */
1503func void CALL_RetValIsFloat() {
1504 CALLINT_RetValIsFloat = true;
1505};
1506
1507func void CALL_PutRetValTo(var int adr) {
1508 if (adr == 0) {
1509 CALLINT_PutRetValTo = -1;
1510 } else {
1511 CALLINT_PutRetValTo = adr;
1512 };
1513};
1514
1515//************************************************
1516// Getting the result after a call
1517//************************************************
1518
1519/* returns a value that is written to by the call */
1520var int CALLINT_Result;
1521
1522/* if the value some 32 bit constant, there is nothing to do */
1523func int CALL_RetValAsInt () { return +CALLINT_Result; };
1524func int CALL_RetValAsFloat() { return +CALLINT_Result; };
1525func int CALL_RetValAsPtr () { return +CALLINT_Result; };
1526
1527/* for those who are to lazy to use _^ themselves: */
1528func MEMINT_HelperClass CALL_RetValAsStructPtr() {
1529 _^(CALLINT_Result);
1530};
1531
1532/* parser data stack hacking does the trick for pointer to zStrings */
1533func string CALL_RetValAszStringPtr() {
1534 if (CALLINT_Result) {
1535 MEMINT_StackPushVar(CALLINT_Result);
1536 } else {
1537 return "";
1538 };
1539};
1540
1541/* A zString is merely a special case of a structure, with the difference,
1542 * that it is used as a primitive datatype. Nobody will be willing
1543 * to use it as a pointer to some memory or an instance in Daedalus.
1544 * This function copies the contents of the zString into a
1545 * daedalus string and frees the zString afterwards. */
1546func string CALL_RetValAszString() {
1547 var string ret;
1548 if (CALLINT_Result) {
1549 ret = CALL_RetValAszStringPtr();
1550
1551 MEMINT_StackPushString("");
1552 CALL_RetValAszStringPtr();
1553
1554 MEMINT_StrAssign();
1555
1556 MEM_Free (CALLINT_Result);
1557 CALLINT_Result = 0;
1558 };
1559
1560 return ret;
1561};
1562
1563//************************************************
1564// The calls
1565//************************************************
1566
1567func void CALLINT_makecall (var int adr, var int cleanStack) {
1568 if (CALLINT_RetValStructSize) {
1569 CALL_IntParam (MEM_Alloc (CALLINT_RetValStructSize));
1570 CALLINT_RetValStructSize = 0;
1571 };
1572
1573 /* make the call: */
1574 ASM_1 (ASMINT_OP_call);
1575 ASM_4 (adr - ASM_Here() - 4); /* -4, because the jump is relative to the _next_ instruction. */
1576
1577 /* copy the result into a daedalus variable */
1578 if (CALLINT_PutRetValTo != -1) {
1579 if (!CALLINT_RetValIsFloat) {
1580 ASM_2 (ASMINT_OP_movEAXToMem); /* mov CALLINT_Result eax */
1581 } else {
1582 ASM_2 (ASMINT_OP_floatStoreToMem); /* fstp CALLINT_Result */
1583 };
1584
1585 if (CALLINT_PutRetValTo) {
1586 ASM_4 (CALLINT_PutRetValTo);
1587 } else {
1588 ASM_4 (MEM_GetIntAddress(CALLINT_Result));
1589 };
1590 };
1591
1592 /* default: return value is not a float
1593 * and has default location */
1594 CALLINT_RetValIsFloat = false; //fürs nächste mal muss neugeschaltet werden.
1595 CALLINT_PutRetValTo = 0;
1596
1597 /* __cdecl has to clean the stack here: */
1598 if (cleanStack) {
1599 ASM_2 (ASMINT_OP_addImToESP);
1600 ASM_1 (CALLINT_numParams * 4);
1601 };
1602
1603 /* reset Param Counter */
1604 CALLINT_numParams = 0;
1605
1606 /* run the code that was build and discard it afterwards */
1607 if (CALLINT_CodeMode != CALLINT_CodeMode_Recyclable) {
1608 ASM_RunOnce();
1609 };
1610};
1611
1612/* all Parameters are passed on the stack (right to left)
1613 callee cleans the stack */
1614func void CALL__stdcall (var int adr) {
1615 CALLINT_makecall (adr, false);
1616};
1617
1618/* all Parameters are passed on the stack (right to left)
1619 caller cleans the stack */
1620func void CALL__cdecl (var int adr) {
1621 CALLINT_makecall (adr, true);
1622};
1623
1624/* __stdcall but with a this pointer in ecx. */
1625func void CALL__thiscall (var int this, var int adr) {
1626 /* this -> ecx */
1627 if (CALLINT_CodeMode == CALLINT_CodeMode_Recyclable) {
1628 ASM_2(ASMINT_OP_movMemToECX);
1629 } else {
1630 ASM_1(ASMINT_OP_movImToECX);
1631 };
1632
1633 ASM_4 (this);
1634 CALL__stdcall (adr);
1635};
1636
1637/* __stdcall but with the first two parameters passed in ecx and edx. */
1638func void CALL__fastcall (var int ecx, var int edx, var int adr) {
1639 if (CALLINT_CodeMode == CALLINT_CodeMode_Recyclable) {
1640 ASM_2(ASMINT_OP_movMemToEDX);
1641 } else {
1642 ASM_1 (ASMINT_OP_movImToEDX);
1643 };
1644
1645 ASM_4 (edx);
1646
1647 CALL__thiscall (ecx, adr);
1648};
1649
1650//#################################################
1651//
1652// UTILITY
1653//
1654//#################################################
1655
1656//--------------------------------------
1657// Debuginformationen anschalten
1658//--------------------------------------
1659
1660/* Empfehlung: Sofort in Startup_Global und Init_Global
1661 * die Debuginformationen anmachen.
1662 * Schadet bestimmt nicht.
1663 * Bei der Auslieferung der Mod wieder rausnehmen. */
1664
1665func void MEM_SetShowDebug (var int on) {
1666 MEM_WriteInt (showDebugAddress, on);
1667};
1668
1669//----------------------------------
1670// Bereichskopieren
1671//----------------------------------
1672
1673func void MEM_CopyBytes (var int src, var int dst, var int byteCount) {
1674 const int memcpy_G1 = 7846464; //0x77BA40
1675 const int memcpy_G2 = 8213280; //0x7D5320
1676
1677 const int call = 0;
1678 if (CALL_Begin(call)) {
1679 CALL_IntParam(_@(byteCount));
1680 CALL_IntParam(_@(src));
1681 CALL_IntParam(_@(dst));
1682
1683 CALL_PutRetValTo(0);
1684 CALL__cdecl(MEMINT_SwitchG1G2(memcpy_G1, memcpy_G2));
1685
1686 call = CALL_End();
1687 };
1688};
1689
1690func void MEM_CopyWords (var int src, var int dst, var int wordcount) {
1691 MEM_CopyBytes (src, dst, wordcount * 4);
1692};
1693
1694//alias, Abwärtskompatibilität
1695func void MEM_Copy (var int src, var int dst, var int wordcount) {
1696 MEM_CopyBytes (src, dst, wordcount * 4);
1697};
1698
1699//----------------------------------
1700// Swappen (was auch immer ich mir dabei gedacht habe)
1701//----------------------------------
1702
1703func void MEM_SwapBytes(var int src, var int dst, var int byteCount) {
1704 const int swap_G1 = 7829281; //0x777721
1705 const int swap_G2 = 8196369; //0x7D1111
1706
1707 const int call = 0;
1708 if (CALL_Begin(call)) {
1709 CALL_IntParam(_@(byteCount));
1710 CALL_PtrParam(_@(src));
1711 CALL_PtrParam(_@(dst));
1712
1713 CALL_PutRetValTo(0);
1714 CALL__cdecl(MEMINT_SwitchG1G2(swap_G1, swap_G2));
1715 call = CALL_End();
1716 };
1717};
1718
1719func void MEM_Swap(var int src, var int dst, var int wordCount) {
1720 MEM_SwapBytes(src, dst, wordCount*4);
1721};
1722
1723func void MEM_SwapWords(var int src, var int dst, var int wordCount) {
1724 MEM_SwapBytes(src, dst, wordCount*4);
1725};
1726
1727//----------------------------------
1728// memset
1729//----------------------------------
1730
1731func void MEM_Clear(var int ptr, var int size) {
1732 const int memset_G1 = 7877040; //0x7831B0
1733 const int memset_G2 = 8243856; //0x7DCA90
1734
1735 var int null;
1736 const int call = 0;
1737 if (CALL_Begin(call)) {
1738 CALL_IntParam(_@(size));
1739 CALL_IntParam(_@(null));
1740 CALL_PtrParam(_@(ptr));
1741
1742 CALL_PutRetValTo(0);
1743 CALL__cdecl(MEMINT_SwitchG1G2(memset_G1, memset_G2));
1744
1745 call = CALL_End();
1746 };
1747};
1748
1749//----------------------------------
1750// Realloc
1751//----------------------------------
1752
1753/* Speicher in ein neues Array kopieren */
1754func int MEM_Realloc (var int ptr, var int oldsize, var int newsize) {
1755 if (!ptr) {
1756 /* Meckern? */
1757 if (!oldsize) {
1758 MEM_Error ("MEM_Realloc: ptr is 0 but oldsize is not 0.");
1759 };
1760
1761 return MEM_Alloc (newsize);
1762 };
1763
1764 const int realloc_G1 = 7712186; //0x75ADBA
1765 const int realloc_G2 = 8078522; //0x7B44BA
1766
1767 const int call = 0;
1768 if (CALL_Begin(call)) {
1769 CALL_IntParam(_@(newsize));
1770 CALL_PtrParam(_@(ptr));
1771
1772 CALL_PutRetValTo(_@(ptr));
1773 CALL__cdecl(MEMINT_SwitchG1G2(realloc_G1, realloc_G2));
1774
1775 call = CALL_End();
1776 }; /* ptr is now filled */
1777
1778 if (oldsize < newsize) {
1779 MEM_Clear(ptr + oldsize, newsize - oldsize);
1780 };
1781
1782 return +ptr;
1783};
1784
1785//************************************************
1786// Compare Memory
1787//************************************************
1788
1789/* couldnt find memcmp at first glance...
1790 * left it as it is. */
1791
1792func int MEM_CompareBytes(var int ptr1, var int ptr2, var int byteCount) {
1793 if (byteCount < 0) {
1794 MEM_Error ("MEM_CompareBytes: Cannot compare less than 0 bytes!");
1795 return 0;
1796 };
1797
1798 if (byteCount == 0) {
1799 //in this case the addresses may be invalid.
1800 return 1;
1801 };
1802
1803 if (ptr1 <= 0)
1804 || (ptr2 <= 0) {
1805 MEM_Error ("MEM_CompareBytes: ptr1 or ptr2 is invalid (<= 0)");
1806 return 0;
1807 };
1808
1809 var int loopPos; loopPos = MEM_StackPos.position;
1810 if (byteCount >= 4) {
1811 if (MEM_ReadInt(ptr1) != MEM_ReadInt(ptr2)) {
1812 return 0;
1813 };
1814 ptr1 += 4; ptr2 += 4;
1815 byteCount -= 4;
1816 MEM_StackPos.position = loopPos;
1817 };
1818
1819 var int mask; mask = (1 << byteCount * 8) - 1;
1820 return (MEM_ReadInt(ptr1) & mask) == (MEM_ReadInt(ptr2) & mask);
1821};
1822
1823func int MEM_CompareWords(var int ptr0, var int ptr1, var int wordCount) {
1824 return MEM_CompareBytes(ptr0, ptr1, wordCount * 4);
1825};
1826
1827func int MEM_Compare(var int ptr0, var int ptr1, var int wordCount) {
1828 return MEM_CompareBytes(ptr0, ptr1, wordCount * 4);
1829};
1830
1831//#################################################
1832//
1833// Windows Utilities
1834//
1835//#################################################
1836
1837//--------------------------------------
1838// Funktionen aus anderen DLLs laden
1839//--------------------------------------
1840
1841/* http://msdn.microsoft.com/en-us/library/ms684175%28v=vs.85%29.aspx */
1842func int LoadLibrary (var string lpFileName) {
1843 const int call = 0;
1844 if (CALL_Begin(call)) {
1845 var int WinAPI__LoadLibrary;
1846 if (GOTHIC_BASE_VERSION == 2) {
1847 WinAPI__LoadLibrary = MEM_ReadInt (8577604); //0x82E244
1848 } else {
1849 WinAPI__LoadLibrary = MEM_ReadInt (8192588); //0x7D024C
1850 };
1851
1852 CALL_PtrParam(_@s(lpFileName) + 8 /* offset of ptr */);
1853
1854 CALL_PutRetValTo(_@(ret));
1855 CALL__stdcall(WinAPI__LoadLibrary);
1856
1857 call = CALL_End();
1858 };
1859
1860 var int ret;
1861 return +ret;
1862};
1863
1864/* http://msdn.microsoft.com/en-us/library/ms683212%28v=vs.85%29.aspx */
1865func int GetProcAddress (var int hModule, var string lpProcName) {
1866 const int call = 0;
1867
1868 if (CALL_Begin(call)) {
1869 var int WinAPI__GetProcAddress;
1870 if (GOTHIC_BASE_VERSION == 2) {
1871 WinAPI__GetProcAddress = MEM_ReadInt (8577688); //0x82E298
1872 } else {
1873 WinAPI__GetProcAddress = MEM_ReadInt (8192260); //0x7D0104
1874 };
1875
1876 CALL_PtrParam(_@s(lpProcName) + 8 /* offset of ptr */);
1877 CALL_PtrParam (_@(hModule));
1878
1879 CALL_PutRetValTo(_@(ret));
1880 CALL__stdcall (WinAPI__GetProcAddress);
1881
1882 call = CALL_End();
1883 };
1884
1885 var int ret;
1886 return +ret;
1887};
1888
1889//einfache Anwendung der obigen beiden Funktionen.
1890func int FindKernelDllFunction (var string name) {
1891 const int KERNEL32DLL = 0;
1892 if (!KERNEL32DLL) {
1893 KERNEL32DLL = LoadLibrary ("KERNEL32.DLL");
1894 };
1895
1896 return GetProcAddress(KERNEL32DLL, name);
1897};
1898
1899//--------------------------------------
1900// Schreibschutz umgehen
1901//--------------------------------------
1902
1903const int PAGE_EXECUTE = 16; //0x10
1904const int PAGE_EXECUTE_READ = 32; //0x20
1905const int PAGE_EXECUTE_READWRITE = 64; //0x40
1906const int PAGE_EXECUTE_WRITECOPY = 128; //0x80
1907
1908const int PAGE_NOACCESS = 1; //0x01
1909const int PAGE_READONLY = 2; //0x02
1910const int PAGE_READWRITE = 4; //0x04
1911const int PAGE_WRITECOPY = 8; //0x08
1912
1913/* http://msdn.microsoft.com/en-us/library/aa366898%28VS.85%29.aspx */
1914/* Note: I made lpflOldProtectPtr the return value and ignored
1915 * the return Value of VirtualProtect */
1916func int VirtualProtect (var int lpAddress, var int dwSize, var int flNewProtect) {
1917 const int adr = 0;
1918
1919 if (!adr) {
1920 adr = FindKernelDllFunction ("VirtualProtect");
1921 };
1922
1923 var int lpflOldProtect;
1924 var int lpflOldProtectPtr;
1925 lpflOldProtectPtr = _@(lpflOldProtect);
1926
1927 const int call = 0;
1928 if (CALL_Begin(call)) {
1929 CALL_PtrParam (_@(lpflOldProtectPtr));
1930 CALL_IntParam (_@(flNewProtect));
1931 CALL_IntParam (_@(dwSize));
1932 CALL_PtrParam (_@(lpAddress));
1933
1934 CALL_PutRetValTo(0);
1935 CALL__stdcall (adr);
1936
1937 call = CALL_End();
1938 };
1939
1940 return lpflOldProtect;
1941};
1942
1943func void MemoryProtectionOverride (var int address, var int size) {
1944 var int resDump;
1945 resDump = VirtualProtect (address, size, PAGE_EXECUTE_READWRITE);
1946};
1947
1948//--------------------------------------
1949// Message Boxen
1950//--------------------------------------
1951
1952const int MB_OK = 0;
1953const int MB_OKCANCEL = 1;
1954const int MB_ABORTRETRYIGNORE = 2;
1955const int MB_YESNOCANCEL = 3;
1956const int MB_YESNO = 4;
1957const int MB_RETRYCANCEL = 5;
1958const int MB_CANCELTRYCONTINUE = 6;
1959
1960const int MB_ICONERROR = 16; //0x10
1961const int MB_ICONQUESTION = 32; //0x20
1962const int MB_ICONWARNING = 48; //0x30
1963const int MB_ICONINFORMATION = 64; //0x40
1964
1965//alias:
1966 const int MB_ICONEXCLAMATION = MB_ICONWARNING;
1967 const int MB_ICONASTERISK = MB_ICONINFORMATION;
1968 const int MB_ICONSTOP = MB_ICONERROR;
1969 const int MB_ICONHAND = MB_ICONERROR;
1970
1971const int MB_DEFBUTTON1 = 0; //0x000
1972const int MB_DEFBUTTON2 = 256; //0x100
1973const int MB_DEFBUTTON3 = 512; //0x200
1974const int MB_DEFBUTTON4 = 768; //0x300
1975
1976const int IDOK = 1;
1977const int IDCANCEL = 2;
1978const int IDABORT = 3;
1979const int IDRETRY = 4;
1980const int IDIGNORE = 5;
1981const int IDYES = 6;
1982const int IDNO = 7;
1983const int IDTRYAGAIN = 10;
1984const int IDCONTINUE = 11;
1985
1986func int MEM_MessageBox (var string txt, var string caption, var int type) {
1987 /* Hier liegt die Funktion */
1988 const int WinAPI__MessageBox_G2 = 8079592; //0x7B48E8
1989 const int WinAPI__MessageBox_G1 = 7713298; //0x75B212
1990
1991 const int MB_TASKMODAL = 8192; //0x2000
1992
1993 /* Parameter in umgekehrter Reihenfolge */
1994 CALL_IntParam (type | MB_TASKMODAL); //soll in den Vordergrund
1995 CALL_cStringPtrParam (caption);
1996 CALL_cStringPtrParam (txt);
1997 CALL_IntParam (0);
1998
1999 CALL__stdcall (MEMINT_SwitchG1G2(WinAPI__MessageBox_G1, WinAPI__MessageBox_G2));
2000
2001 return CALL_RetValAsInt();
2002};
2003
2004func void MEM_InfoBox (var string txt) {
2005 var int res;
2006 res = MEM_MessageBox (txt, "Information:", MB_OK | MB_ICONINFORMATION);
2007};
2008
2009//#################################################################
2010//
2011// Arrays
2012//
2013//#################################################################
2014
2015//************************************************
2016// Alloc / Clear / Free / Size / Read / Write
2017//************************************************
2018
2019func int MEM_ArrayCreate () {
2020 return MEM_Alloc (sizeof_zCArray);
2021};
2022
2023func void MEM_ArrayFree(var int zCArray_ptr) {
2024 var int array; array = MEM_ReadInt (zCArray_ptr);
2025
2026 if (array) {
2027 MEM_Free (array);
2028 };
2029
2030 MEM_Free (zCArray_ptr);
2031};
2032
2033func void MEM_ArrayClear (var int zCArray_ptr) {
2034 var zCArray array;
2035 array = _^(zCArray_ptr);
2036
2037 if (array.array) {
2038 MEM_Free (array.array);
2039 array.array = 0;
2040 };
2041
2042 array.numAlloc = 0;
2043 array.numInArray = 0;
2044};
2045
2046func int MEM_ArraySize(var int zCArray_ptr) {
2047 return MEM_ReadInt(zCArray_ptr + 8);
2048};
2049
2050func void MEM_ArrayWrite(var int zCArray_ptr, var int pos, var int value) {
2051 var zCArray array;
2052 array = _^(zCArray_ptr);
2053
2054 if (pos < 0 || array.numInArray <= pos) {
2055 MEM_Error (ConcatStrings("MEM_ArrayWrite: pos out of bounds: ", IntToString(pos)));
2056 return;
2057 };
2058
2059 MEM_WriteIntArray(array.array, pos, value);
2060};
2061
2062func int MEM_ArrayRead(var int zCArray_ptr, var int pos) {
2063 var zCArray array; array = _^(zCArray_ptr);
2064
2065 if (pos < 0 || array.numInArray <= pos) {
2066 MEM_Error (ConcatStrings("MEM_ArrayRead: pos out of bounds: ", IntToString(pos)));
2067 return 0;
2068 };
2069
2070 return MEM_ReadIntArray(array.array, pos);
2071};
2072
2073//************************************************
2074// Insert / Push / Pop / Top
2075//************************************************
2076
2077func void MEM_ArrayInsert (var int zCArray_ptr, var int value) {
2078 var zCArray array;
2079 array = _^(zCArray_ptr);
2080
2081 if (!array.array) {
2082 //Noch gar kein Array angelegt. Erstmals anlegen
2083 array.numAlloc = 16; //Startwert
2084 array.array = MEM_Alloc (array.numAlloc * 4);
2085 } else if (array.numInArray >= array.numAlloc) {
2086 //kein Platz mehr
2087 //nehmen wir mal das doppelte (oder ist das zu gierig? sollte passen):
2088 array.numAlloc = 2 * array.numAlloc;
2089 array.array = MEM_Realloc (array.array, array.numInArray * 4, array.numAlloc * 4);
2090 };
2091
2092 //Jetzt muss Platz sein:
2093 MEM_WriteIntArray (array.array, array.numInArray, value);
2094 array.numInArray += 1;
2095};
2096
2097func void MEM_ArrayPush (var int zCArray_ptr, var int value) {
2098 MEM_ArrayInsert(zCArray_ptr, value);
2099};
2100
2101func int MEM_ArrayPop(var int zCArray_ptr) {
2102 if (!zCArray_ptr) {
2103 MEM_Error ("MEM_ArrayPop: Invalid address: zCArray_ptr may not be null!");
2104 return 0;
2105 };
2106
2107 var zCArray array;
2108 array = _^(zCArray_ptr);
2109
2110 if (!array.numInArray) {
2111 MEM_Error ("MEM_ArrayPop: Underflow! Cannot pop from empty array.");
2112 return 0;
2113 };
2114
2115 array.numInArray -= 1;
2116 return MEM_ReadIntArray(array.array, array.numInArray);
2117};
2118
2119func int MEM_ArrayTop(var int zCArray_ptr) {
2120 if (!zCArray_ptr) {
2121 MEM_Error ("MEM_ArrayTop: Invalid address: zCArray_ptr may not be null!");
2122 return 0;
2123 };
2124
2125 var zCArray array;
2126 array = _^(zCArray_ptr);
2127
2128 if (!array.numInArray) {
2129 MEM_Error ("MEM_ArrayTop: Underflow! Cannot pop from empty array.");
2130 return 0;
2131 };
2132
2133 return MEM_ReadIntArray(array.array, array.numInArray - 1);
2134};
2135
2136//************************************************
2137// IndexOf / RemoveIndex / RemoveValue[Once]
2138//************************************************
2139
2140func int MEM_ArrayIndexOf(var int zCArray_ptr, var int value) {
2141 if (!zCArray_ptr) {
2142 MEM_Error ("MEM_ArrayIndexOf: Invalid address: zCArray_ptr may not be null!");
2143 return -1;
2144 };
2145
2146 var zCArray array;
2147 array = _^(zCArray_ptr);
2148
2149 var int i; i = 0;
2150 var int loop; loop = MEM_StackPos.position;
2151
2152 if (i < array.numInArray) {
2153 if (MEM_ReadIntArray(array.array, i) == value) {
2154 return i;
2155 };
2156
2157 i += 1;
2158 MEM_StackPos.position = loop;
2159 };
2160
2161 return -1;
2162};
2163
2164func void MEM_ArrayRemoveIndex (var int zCArray_ptr, var int index) {
2165 if (!zCArray_ptr) {
2166 MEM_Error ("MEM_ArrayRemoveIndex: Invalid address: zCArray_ptr may not be null!");
2167 return;
2168 };
2169
2170 var zCArray array;
2171 array = _^(zCArray_ptr);
2172
2173 if (array.numInArray <= index) {
2174 MEM_Error ("MEM_ArrayRemoveIndex: index lies beyond the end of the array!");
2175 return;
2176 };
2177
2178 //letzten Wert in die Lücke schieben
2179 array.numInArray -= 1;
2180 MEM_WriteIntArray (array.array, index, MEM_ReadIntArray (array.array, array.numInArray));
2181};
2182
2183var int MEMINT_ArrayRemoveValue_OnlyOnce;
2184func void MEM_ArrayRemoveValue (var int zCArray_ptr, var int value) {
2185 if (!zCArray_ptr) {
2186 MEM_Error ("MEM_ArrayRemoveValue: Invalid address: zCArray_ptr may not be null!");
2187 return;
2188 };
2189
2190 var zCArray array;
2191 array = _^(zCArray_ptr);
2192
2193 var int i; i = 0;
2194 var int loop; loop = MEM_StackPos.position;
2195
2196 //schon durchgelaufen?
2197 /* while */ if (i < array.numInArray) {
2198 if (MEM_ReadIntArray (array.array, i) == value) {
2199 //dann element entfernen
2200 array.numInArray -= 1;
2201 MEM_WriteIntArray (array.array, i, MEM_ReadIntArray (array.array, array.numInArray));
2202
2203 //weitersuchen?
2204 if (MEMINT_ArrayRemoveValue_OnlyOnce) {
2205 MEMINT_ArrayRemoveValue_OnlyOnce = 2; //geschafft
2206 return;
2207 };
2208 } else {
2209 i += 1;
2210 };
2211
2212 MEM_StackPos.position = loop;
2213 };
2214};
2215
2216func void MEM_ArrayRemoveValueOnce (var int zCArray_ptr, var int value) {
2217 MEMINT_ArrayRemoveValue_OnlyOnce = true;
2218 MEM_ArrayRemoveValue (zCArray_ptr, value);
2219
2220 if (MEMINT_ArrayRemoveValue_OnlyOnce != 2) {
2221 MEM_Warn (ConcatStrings ("MEM_ArrayRemoveValueOnce: Could not find value: ", IntToString (value)));
2222 };
2223
2224 MEMINT_ArrayRemoveValue_OnlyOnce = false;
2225};
2226
2227//************************************************
2228// Sort / Unique
2229//************************************************
2230
2231func void MEMINT_QSort(var int base, var int num, var int size, var int comparator) {
2232 const int qsort_G1 = 7828863; //0x77757F
2233 const int qsort_G2 = 8195951; //0x7D0F6F
2234
2235 const int compare_G1 = 5502288; //0x53F550
2236 const int compare_G2 = 5586080; //0x553CA0
2237
2238 if (comparator == 0) {
2239 comparator = MEMINT_SwitchG1G2(compare_G1, compare_G2);
2240 };
2241
2242 var int qsort;
2243 qsort = MEMINT_SwitchG1G2(qsort_G1, qsort_G2 );
2244
2245 const int call = 0;
2246 if (CALL_Begin(call)) {
2247 CALL_PtrParam(_@(comparator));
2248 CALL_IntParam(_@(size));
2249 CALL_IntParam(_@(num));
2250 CALL_PtrParam(_@(base));
2251
2252 CALL_PutRetValTo(0);
2253 CALL__cdecl(qsort);
2254
2255 call = CALL_End();
2256 };
2257};
2258
2259func void MEM_ArraySort(var int zCArray_ptr) {
2260 if (!zCArray_ptr) {
2261 MEM_Error ("MEM_ArraySort: Invalid address: zCArray_ptr may not be null!");
2262 return;
2263 };
2264
2265 var zCArray array;
2266 array = _^(zCArray_ptr);
2267
2268 MEMINT_QSort(array.array, array.numInArray, 4, 0);
2269};
2270
2271func void MEM_ArrayUnique(var int zCArray_ptr) {
2272 if (!zCArray_ptr) {
2273 MEM_Error ("MEM_ArrayUnique: Invalid address: zCArray_ptr may not be null!");
2274 return;
2275 };
2276
2277 var zCArray array;
2278 array = _^(zCArray_ptr);
2279
2280 var int reader; var int writer; var int oldVal; var int newVal;
2281 reader = 0; writer = 0;
2282
2283 var int loop; loop = MEM_StackPos.position;
2284
2285 if (reader < array.numInArray) {
2286 newVal = MEM_ReadIntArray(array.array, reader);
2287
2288 if (!reader || newVal != oldVal) {
2289 MEM_WriteIntArray(array.array, writer, newVal);
2290 writer += 1;
2291 oldVal = newVal;
2292 };
2293
2294 reader += 1;
2295 MEM_StackPos.position = loop;
2296 };
2297
2298 array.numInArray = writer;
2299};
2300
2301//************************************************
2302// ToString
2303//************************************************
2304
2305func string MEM_ArrayToString (var int zCArray_ptr) {
2306 var string res; res = "";
2307
2308 if (!zCArray_ptr) {
2309 MEM_Error ("MEM_ArrayRemoveValue: Invalid address: zCArray_ptr may not be null!");
2310 return "";
2311 };
2312
2313 var zCArray array;
2314 array = _^(zCArray_ptr);
2315
2316 var int i; i = 0;
2317 var int loop; loop = MEM_StackPos.position;
2318 /* while */ if (i < array.numInArray) {
2319 res = ConcatStrings (res, IntToString (MEM_ReadIntArray (array.array, i)));
2320 if (i < array.numInArray - 1) {
2321 res = ConcatStrings (res, ",");
2322 };
2323 i += 1;
2324
2325 MEM_StackPos.position = loop;
2326 };
2327
2328 return res;
2329};
2330
2331//######################################################
2332//
2333// String Tools
2334//
2335//######################################################
2336func string MEMINT_PushString (var string str) {
2337 return str;
2338};
2339func int STRINT_GetStringAddress (var string str) {
2340 MEMINT_PushString (str);
2341 MEMINT_StackPopInst(); //zPAR_TOK_PUSHVAR oder so
2342 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
2343};
2344//--------------------------------------
2345// Zugriff auf einzelnes Zeichen
2346//--------------------------------------
2347
2348func int STR_GetCharAt (var string str, var int pos) {
2349 var zString zStr;
2350 zStr = _^(_@s(str));
2351
2352 if (pos < 0) || (pos >= zStr.len) {
2353 MEM_Warn ("STR_GetCharAt: Reading out of bounds! returning 0.");
2354 return 0;
2355 };
2356
2357 return MEM_ReadByte(zStr.ptr + pos);
2358};
2359
2360//--------------------------------------
2361// Länge eines Strings
2362//--------------------------------------
2363
2364func int STR_Search (var string str, var string pattern) {
2365 var zString zStr; var zString patt;
2366 var int patt1stChar;
2367 var int i; var int j;
2368 MEM_AssignInst (zStr, STRINT_GetStringAddress(str));
2369 MEM_AssignInst (patt, STRINT_GetStringAddress(pattern));
2370
2371 if (zStr.len < 1) || (patt.len > zStr.len) {
2372 MEM_Warn ("STR_Search: Reading out of bounds! returning -1.");
2373 return -1;
2374 };
2375
2376 patt1stChar = MEM_ReadInt (patt.ptr) & 255;
2377 i = 0;
2378
2379 var int loopStart; loopStart = MEM_StackPos.position;
2380
2381 if(MEM_ReadInt(zStr.ptr+i)&255 == patt1stChar)
2382 {
2383 var int subLoopStart;
2384 j = 1;
2385 subLoopStart = MEM_StackPos.position;
2386 if(MEM_ReadInt(zStr.ptr+i+j)&255 == MEM_ReadInt(patt.ptr+j)&255)
2387 {
2388 if(j==patt.len)
2389 {
2390 return i;//returns the begging pos of searched pattern in string
2391 };
2392 j+=1;
2393 MEM_StackPos.position=subLoopStart;
2394 };
2395 }
2396 else if(i<zStr.len-patt.len)//1st char don't match, but there is more characters to check...
2397 {
2398 i+=1;
2399 MEM_StackPos.position = loopStart;
2400 };
2401
2402 return -1;//pattern not found
2403};
2404
2405
2406func int STR_Len (var string str) {
2407 var zString zStr;
2408 zStr = _^(_@s(str));
2409 return +zStr.len;
2410};
2411
2412//--------------------------------------
2413// To and from char*
2414//--------------------------------------
2415
2416/* Be aware that strings may share their buffers!
2417 var string s1; var string s2;
2418 s1 = "Hello"; s2 = s1;
2419
2420 Now only one copy of "Hello" exists in memory!
2421 This is implemented by reference counting
2422 in ptr-1.
2423 */
2424
2425func int STR_toChar (var string str) {
2426 var zString zStr;
2427 zStr = _^(_@s(str));
2428 return +zStr.ptr;
2429};
2430
2431func int STRINT_toChar (var string str) {
2432 return STR_ToChar(str);
2433};
2434
2435func string STR_FromChar(var int char) {
2436 var string str;
2437 str = "";
2438 var int ptr; ptr = _@s(str);
2439
2440 const int call = 0;
2441 if (CALL_Begin(call)) {
2442 CALL_PtrParam(_@(char));
2443
2444 /* zString::zString(const char*) */
2445 CALL__thiscall(_@(ptr), MEMINT_SwitchG1G2(4199328 /* 0x4013A0 */,
2446 4198592 /* 0x4010C0 */));
2447 call = CALL_End();
2448 };
2449
2450 return str;
2451};
2452
2453//************************************************
2454// Substring / Prefix
2455//************************************************
2456
2457func string STR_SubStr (var string str, var int start, var int count) {
2458 if (start < 0) || (count < 0) {
2459 MEM_Error ("STR_SubStr: start and count may not be negative.");
2460 return "";
2461 };
2462
2463 /* Hole Adressen von zwei Strings, Source und Destination (für Kopieroperation) */
2464 var zString zStrSrc;
2465 var zString zStrDst; var string dstStr; dstStr = "";
2466
2467 zStrSrc = _^(_@s(str));
2468 zStrDst = _^(_@s(dstStr));
2469
2470 if (zStrSrc.len < start + count) {
2471 if (zStrSrc.len < start) {
2472 MEM_Warn ("STR_SubStr: The desired start of the substring lies beyond the end of the string.");
2473 return "";
2474
2475 } else {
2476 /* The start is in valid bounds. The End is shitty. */
2477 /* Careful! MEM_Warn will use STR_SubStr (but will never use it in a way that would produce a warning) */
2478 var string saveStr; var int saveStart; var int saveCount;
2479 saveStr = str; saveStart = start; saveCount = count;
2480 MEM_Warn ("STR_SubStr: The end of the desired substring exceeds the end of the string.");
2481 str = saveStr; start = saveStart; count = saveCount;
2482 count = zStrSrc.len - start;
2483 };
2484 };
2485
2486 zStrDst.ptr = MEM_Alloc (count+2)+1; /* +1 for reference counter byte, +1 for null byte */
2487 zStrDst.res = count;
2488
2489 MEM_CopyBytes (zStrSrc.ptr + start, zStrDst.ptr, count);
2490
2491 zStrDst.len = count;
2492
2493 return dstStr;
2494};
2495
2496//Von früher:
2497func string STR_Prefix (var string str, var int len) {
2498 return STR_SubStr(str, 0, len);
2499};
2500
2501//************************************************
2502// Compare Strings
2503//************************************************
2504
2505const int STR_GREATER = 1;
2506const int STR_EQUAL = 0;
2507const int STR_SMALLER = -1;
2508
2509func int STR_Compare(var string str1, var string str2) {
2510 const int strncmp_G1 = 7887344; //0x7859F0
2511 const int strncmp_G2 = 8254144; //0x7DF2C0
2512
2513 var int ptr1; ptr1 = _@s(str1);
2514 var int ptr2; ptr2 = _@s(str2);
2515
2516 var int len1; len1 = MEM_ReadInt(ptr1 + 12);
2517 var int len2; len2 = MEM_ReadInt(ptr2 + 12);
2518
2519 var int n; if (len1 > len2) { n = len2; } else { n = len1; };
2520
2521 /* access zString.ptr */
2522 ptr1 = MEM_ReadInt(ptr1 + 8);
2523 ptr2 = MEM_ReadInt(ptr2 + 8);
2524
2525 if (!ptr1 && !ptr2) {
2526 return STR_EQUAL;
2527 } else if (!ptr1) {
2528 return STR_SMALLER;
2529 } else if (!ptr2) {
2530 return STR_GREATER;
2531 };
2532
2533 const int call = 0;
2534 if (CALL_Begin(call)) {
2535 CALL_IntParam(_@(n));
2536
2537 CALL_PtrParam(_@(ptr2));
2538 CALL_PtrParam(_@(ptr1));
2539
2540 CALL_PutRetValTo(_@(ret));
2541 CALL__cdecl(MEMINT_SwitchG1G2(strncmp_G1, strncmp_G2));
2542
2543 call = CALL_End();
2544 };
2545
2546 /* Gothic's implementation returns -1, 0 or 1 */
2547 var int ret;
2548
2549 if (ret == 0) {
2550 if (len1 > len2) {
2551 return STR_GREATER;
2552 } else if (len1 < len2) {
2553 return STR_SMALLER;
2554 };
2555 };
2556
2557 return +ret;
2558};
2559
2560//************************************************
2561// STR_ToInt
2562//************************************************
2563
2564/* somewhat different from atol, therefore I will leave it as it is */
2565
2566func int STR_ToInt (var string str) {
2567 var int len;
2568 len = STR_Len (str);
2569
2570 var int buf; var int index;
2571 buf = STR_toChar(str);
2572 index = 0;
2573
2574 var int res; res = 0; var int minus; minus = FALSE;
2575
2576 var int loopStart; loopStart = MEM_StackPos.position;
2577 /* while */ if (index < len) {
2578 var int chr; chr = MEM_ReadInt (buf + index) & 255;
2579
2580 if (chr >= 48 /* 0 */) && (chr <= 57 /* 9 */) {
2581 res = res * 10 + (chr - 48);
2582 } else if (index == 0) {
2583 //am Anfang sind Vorzeichen erlaubt
2584 if (chr == 43 /*+*/) {
2585 /* ignore */
2586 } else if (chr == 45 /*-*/) {
2587 minus = true;
2588 } else {
2589 MEM_Warn (ConcatStrings ("STR_ToInt: cannot convert string: ", str));
2590 return 0;
2591 };
2592 } else {
2593 MEM_Warn (ConcatStrings ("STR_ToInt: cannot convert string: ", str));
2594 return 0;
2595 };
2596 index += 1;
2597 MEM_StackPos.position = loopStart;
2598 };
2599
2600 if (minus) {
2601 return -res;
2602 } else {
2603 return +res;
2604 };
2605};
2606
2607//************************************************
2608// STR_IndexOf
2609//************************************************
2610
2611func int STR_IndexOf(var string str, var string tok) {
2612 var zString zStr; zStr = _^(_@s(str));
2613 var zString zTok; zTok = _^(_@s(tok));
2614
2615 if(zTok.len == 0) {
2616 return 0;
2617 };
2618 if (zStr.len == 0) {
2619 return -1;
2620 };
2621
2622 var int startPos; startPos = zStr.ptr;
2623 var int startMax; startMax = zStr.ptr + zStr.len - zTok.len;
2624
2625 var int loopPos; loopPos = MEM_StackPos.position;
2626 if (startPos <= startMax) {
2627 if (MEM_CompareBytes(startPos, zTok.ptr, zTok.len)) {
2628 return startPos - zStr.ptr;
2629 };
2630 startPos += 1;
2631 MEM_StackPos.position = loopPos;
2632 };
2633 return -1;
2634};
2635
2636//************************************************
2637// STR_Split
2638//************************************************
2639
2640/* ursprünglicher Code von Gottfried */
2641
2642/* STRINT_SplitArray enthält folgendes:
2643 *
2644 * struct TStringInfo {
2645 * int length;
2646 * char* data;
2647 * };
2648 */
2649
2650const int STRINT_SplitArray = 0;
2651
2652func void STRINT_SplitReset() {
2653 if(!STRINT_SplitArray) {
2654 STRINT_SplitArray = MEM_ArrayCreate();
2655 return;
2656 };
2657
2658 var zCArray arr; arr = _^(STRINT_SplitArray);
2659
2660 var int i; i = 0;
2661 var int loopPos; loopPos = MEM_StackPos.position;
2662
2663 if /*while*/ (i < arr.numInArray) {
2664 MEM_Free(MEM_ReadIntArray(arr.array, i + 1));
2665 i += 2;
2666 MEM_StackPos.position = loopPos;
2667 };
2668
2669 MEM_ArrayClear(STRINT_SplitArray);
2670};
2671
2672func void STRINT_Split(var string Str, var string seperator) {
2673 STRINT_SplitReset();
2674
2675 var zString zStr; zStr = _^(_@s(Str));
2676
2677 if (STR_Len(seperator) != 1) {
2678 MEM_Error("STR_Split: Seperator must be a string of length 1!");
2679 return;
2680 };
2681
2682 if (zStr.len == 0) {
2683 //careful: cannot read from zStr.ptr if zStr.len == 0!
2684 //handling without lazy evaluation would be sucky.
2685 MEM_ArrayInsert(STRINT_SplitArray, 0);
2686 MEM_ArrayInsert(STRINT_SplitArray, MEM_Alloc(0));
2687 return;
2688 };
2689
2690 var int cSep; cSep = STR_GetCharAt(seperator, 0);
2691
2692 var int currTokStart; currTokStart = zStr.ptr;
2693 var int strEnd; strEnd = zStr.ptr + zStr.len;
2694 var int walker; walker = currTokStart;
2695 var int loopPos; loopPos = MEM_StackPos.position;
2696 if /* while*/ (walker <= strEnd) {
2697 if (walker == strEnd || MEM_ReadByte(walker) == cSep) {
2698 var int len; len = walker-currTokStart;
2699 var int subStr; subStr = MEM_Alloc(len);
2700 MEM_CopyBytes(currTokStart, subStr, len);
2701 MEM_ArrayInsert(STRINT_SplitArray, len);
2702 MEM_ArrayInsert(STRINT_SplitArray, subStr);
2703 currTokStart = walker + 1;
2704 };
2705
2706 walker += 1;
2707 MEM_StackPos.position = loopPos;
2708 };
2709};
2710
2711func string STRINT_SplitGet(var int offset) {
2712 var zCArray arr; arr = _^(STRINT_SplitArray);
2713
2714 if (arr.numInArray / 2 <= offset) {
2715 MEM_Error("STR_Split: The string does not decompose into that many substrings!");
2716 return "";
2717 };
2718
2719 var string str; str = "";
2720 var zString zstr; zstr = _^(_@s(str));
2721
2722 var int len; len = MEM_ReadIntArray(arr.array, 2*offset);
2723 zstr.ptr = MEM_Alloc(len+2)+1;
2724 zstr.len = len;
2725 zstr.res = len;
2726
2727 MEM_CopyBytes(MEM_ReadIntArray(arr.array, 2*offset + 1), zstr.ptr, len);
2728
2729 return str;
2730};
2731
2732var string STRINT_SplitCache;
2733var string STRINT_SplitSeperatorCache;
2734
2735func string STR_Split(var string str, var string separator, var int offset) {
2736 if (Hlp_StrCmp(STRINT_SplitCache, str)
2737 && !Hlp_StrCmp(STRINT_SplitCache, "")
2738 && Hlp_StrCmp(STRINT_SplitSeperatorCache, separator)) {
2739 return STRINT_SplitGet(offset);
2740 };
2741 STRINT_Split(str, separator);
2742 STRINT_SplitCache = str;
2743 STRINT_SplitSeperatorCache = separator;
2744
2745 return STRINT_SplitGet(offset);
2746};
2747
2748func int STR_SplitCount(var string str, var string seperator) {
2749 if (!Hlp_StrCmp(STRINT_SplitCache, str)
2750 || !Hlp_StrCmp(STRINT_SplitSeperatorCache, seperator)
2751 || Hlp_StrCmp(STRINT_SplitCache, "")) {
2752 STRINT_Split(str, seperator);
2753 STRINT_SplitCache = str;
2754 STRINT_SplitSeperatorCache = seperator;
2755 };
2756
2757 var zCArray arr; arr = _^(STRINT_SplitArray);
2758 return arr.numInArray / 2;
2759};
2760
2761//************************************************
2762// Upper Case (Gottfried)
2763//************************************************
2764
2765func string STR_Upper(var string str) {
2766 const int zSTRING__Upper_G1 = 4608912; //0x465390
2767 const int zSTRING__Upper_G2 = 4631296; //0x46AB00
2768
2769 var int ptr; ptr = _@s(str);
2770
2771 const int call = 0;
2772 if (CALL_Begin(call)) {
2773 CALL_PutRetValTo(0);
2774 CALL__thiscall(_@(ptr), MEMINT_SwitchG1G2(zSTRING__Upper_G1, zSTRING__Upper_G2));
2775
2776 call = CALL_End();
2777 };
2778
2779 return str;
2780};
2781
2782//######################################################
2783//
2784// More elaborate zCParser related functions
2785//
2786//######################################################
2787
2788//--------------------------------------
2789// Zeiger auf 8KB holen. Jeder darf drauf
2790// schreiben, niemand darf sich drauf
2791// verlassen, dass irgendjemand ihn
2792// unangetastet lässt.
2793//
2794// Zur Vermeidung temporärer kleiner
2795// MEM_Alloc anfragen.
2796//--------------------------------------
2797
2798/* Weiß nicht ob ich das mit hätte reinnehmen sollen...
2799 * Aber warum nicht? */
2800
2801func int MEMINT_GetBuf_8K_Sub() {
2802 var int buf[2048];
2803 return buf;
2804};
2805func int MEMINT_GetBuf_8K() {
2806 MEMINT_GetBuf_8K_Sub();
2807 MEMINT_StackPopInst();
2808 MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
2809};
2810
2811//************************************************
2812// Search Symbols
2813//************************************************
2814
2815func int MEM_FindParserSymbol (var string inst) {
2816 const int zCParser__GetIndex_G1 = 7250112; //0x6EA0C0
2817 const int zCParser__GetIndex_G2 = 7943280; //0x793470
2818
2819 var int ptr; ptr = _@s(inst);
2820
2821 const int call = 0;
2822 if (CALL_Begin(call)) {
2823 CALL_PtrParam(_@(ptr));
2824
2825 CALL_PutRetValTo(_@(ret));
2826 CALL__thiscall(_@(currParserAddress),
2827 MEMINT_SwitchG1G2(zCParser__GetIndex_G1, zCParser__GetIndex_G2));
2828
2829 call = CALL_End();
2830 };
2831
2832 var int ret;
2833 return +ret;
2834};
2835
2836func int MEM_GetSymbolIndex(var string inst) {
2837 return MEM_FindParserSymbol(inst);
2838};
2839
2840func int MEM_GetParserSymbol (var string inst) {
2841 var int symID;
2842 symID = MEM_FindParserSymbol (inst); //does ReinitParser
2843
2844 if (symID == -1) {
2845 return 0;
2846 } else {
2847 return MEM_ReadIntArray (currSymbolTableAddress, symID);
2848 };
2849};
2850
2851func int MEM_GetSymbol(var string inst) {
2852 return MEM_GetParserSymbol(inst);
2853};
2854
2855func int MEM_GetSymbolByIndex(var int id) {
2856 if (id < 0 || id >= currSymbolTableLength) {
2857 MEM_Error(ConcatStrings("MEM_GetSymbolByIndex: Index is not in valid bounds: ", IntToString(id)));
2858 return 0;
2859 };
2860
2861 return MEM_ReadIntArray (currSymbolTableAddress, id);
2862};
2863
2864//************************************************
2865// MEM_CallBy*
2866//************************************************
2867
2868//--------------------------------------
2869// Parameter übergeben,
2870// Rückgabewerte verwenden.
2871// Nochmal explizit
2872//--------------------------------------
2873
2874/* Kurze Hilfsfunktion, damit die Schnittstelle
2875 * von PushParam nicht verwirrt. */
2876func int MEMINT_PushIntParam(var int param) {
2877 return +param; //kein Var pushen sondern Konstante!
2878};
2879
2880/* Werte auf den Stack schieben */
2881func void MEM_PushIntParam (var int param) {
2882 MEMINT_PushIntParam (param);
2883};
2884
2885func void MEM_PushInstParam (var int inst) {
2886 MEMINT_StackPushInst(inst);
2887};
2888
2889/* wie MEMINT_PushString, aber eigene statische Strings
2890 * ging nämlich schief, weil STR_Compare oft string auf den Stack
2891 * schieben will! */
2892func string MEMINT_PushStringParamSub (var string str) {
2893 var int n; n += 1; if (n == 10) { n = 0; };
2894 if (n == 0) { var string s0; s0 = str; return s0; };
2895 if (n == 1) { var string s1; s1 = str; return s1; };
2896 if (n == 2) { var string s2; s2 = str; return s2; };
2897 if (n == 3) { var string s3; s3 = str; return s3; };
2898 if (n == 4) { var string s4; s4 = str; return s4; };
2899 if (n == 5) { var string s5; s5 = str; return s5; };
2900 if (n == 6) { var string s6; s6 = str; return s6; };
2901 if (n == 7) { var string s7; s7 = str; return s7; };
2902 if (n == 8) { var string s8; s8 = str; return s8; };
2903 if (n == 9) { var string s9; s9 = str; return s9; };
2904
2905 MEM_AssertFail ("Should be never here.");
2906};
2907
2908func void MEM_PushStringParam (var string str) {
2909 MEMINT_PushStringParamSub(str);
2910};
2911
2912/* Werte vom Stack herunterholen. */
2913func int MEM_PopIntResult () {};
2914func string MEM_PopStringResult() {};
2915func MEMINT_HelperClass MEM_PopInstResult() {};
2916
2917//--------------------------------------
2918// MEM_CallBy ID/String/
2919//--------------------------------------
2920
2921func void MEM_CallByID (var int symbID) {
2922 if (symbID < 0) {
2923 MEM_Error(ConcatStrings("MEM_CallByID: symbID may not be negative but is ", IntToString(symbID)));
2924 return;
2925 };
2926
2927 var zCPar_Symbol sym;
2928 sym = _^(MEM_ReadIntArray (contentSymbolTableAddress, symbID));
2929
2930 var int type;
2931 type = (sym.bitfield & zCPar_Symbol_bitfield_type);
2932
2933 if (type != zPAR_TYPE_FUNC) && (type != zPAR_TYPE_PROTOTYPE) && (type != zPAR_TYPE_INSTANCE) {
2934 MEM_Error (ConcatStrings ("MEM_CallByID: Provided symbol is not callable (not function, prototype or instance): ", sym.name));
2935 return;
2936 };
2937
2938 if (sym.bitfield & zPAR_FLAG_EXTERNAL) {
2939 CALL__stdcall(sym.content);
2940 } else {
2941 MEM_CallByPtr(sym.content + currParserStackAddress);
2942 };
2943};
2944
2945func void MEM_CallByString (var string fnc) {
2946 if (Hlp_StrCmp (fnc, "")) {
2947 MEM_Error ("MEM_CallByString: fnc may not be an empty string!");
2948 return;
2949 };
2950
2951 /* Mikrooptimierung: Wird zweimal hintereinander die selbe Funktion
2952 * mit CallByString aufgerufen, nicht nochmal neu suchen. */
2953 var int symbID;
2954 var string cacheFunc; var int cacheSymbID;
2955
2956 if (Hlp_StrCmp (cacheFunc, fnc)) {
2957 symbID = cacheSymbID;
2958 } else {
2959 symbID = MEM_FindParserSymbol (fnc);
2960
2961 if (symbID == -1) {
2962 MEM_Error (ConcatStrings ("MEM_CallByString: Undefined symbol: ", fnc));
2963 return;
2964 };
2965
2966 cacheFunc = fnc; cacheSymbID = symbID;
2967 };
2968
2969 MEM_CallByID (symbID);
2970};
2971
2972func void MEM_Call(var func fnc) {
2973 MEM_CallByID(MEM_GetFuncID(fnc));
2974};
2975
2976//************************************************
2977// Find function by Stack Offset
2978//************************************************
2979
2980func int MEMINT_BuildFuncStartsArray() {
2981 var int array; array = MEM_ArrayCreate();
2982
2983 var int lastOffset; lastOffset = 0;
2984 var int wasSorted; wasSorted = 1;
2985
2986 var int i; i = 0;
2987 var int loop; loop = MEM_StackPos.position;
2988
2989 if (i < MEM_Parser.symtab_table_numInArray) {
2990 var zCPar_Symbol symb;
2991 symb = _^(MEM_ReadIntArray(MEM_Parser.symtab_table_array, i));
2992
2993 if (symb.bitfield & zPAR_FLAG_CONST)
2994 && !(symb.bitfield & zPAR_FLAG_EXTERNAL)
2995 && ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_FUNC) {
2996 /* check integrity */
2997 if (wasSorted && lastOffset > symb.content) {
2998 wasSorted = 0;
2999 MEM_Info("The functions in the symbol table do not seem to be sorted by stack-offset.");
3000 };
3001
3002 lastOffset = symb.content;
3003 MEM_ArrayInsert(array, symb.content); //offset
3004 MEM_ArrayInsert(array, i); //id
3005 };
3006
3007 i += 1;
3008 MEM_StackPos.position = loop;
3009 };
3010
3011 if (!wasSorted) {
3012 var zCArray zcarr; zcarr = _^(array);
3013 MEMINT_QSort(zcarr.array, zcarr.numInArray / 2, 8, 0);
3014 };
3015
3016 return array;
3017};
3018
3019func int MEM_GetFuncIDByOffset(var int offset) {
3020 const int funcStartsArray = 0;
3021 if (!funcStartsArray) {
3022 funcStartsArray = MEMINT_BuildFuncStartsArray();
3023 };
3024
3025 if (offset < 0 || offset >= MEM_Parser.stack_stacksize) {
3026 MEM_Error("MEM_GetFuncIDByOffset: Offset is not in valid bounds (0 <= offset < ParserStackSize).");
3027 return -1;
3028 };
3029
3030 var zCArray array; array = _^(funcStartsArray);
3031
3032 /* binary search */
3033 var int res; res = -1;
3034 var int low; low = 0;
3035 var int high; high = array.numInArray / 2 - 1;
3036
3037 var int loop; loop = MEM_StackPos.position;
3038
3039 /* while (1) { */
3040 /* invariant: array[low] <= offset <= array[high]
3041 low < high */
3042
3043 var int med; med = (low + high) / 2; /* low <= med < high */
3044 var int medOffset; medOffset = MEM_ReadIntArray(array.array, 2*med);
3045
3046 if (medOffset >= offset) {
3047 high = med; /* progess because med < high */
3048 } else {
3049 if (low == med) {
3050 /* can only occur if low == high - 1 */
3051 if (MEM_ReadIntArray(array.array, 2*high) <= offset) {
3052 res = high;
3053 } else {
3054 res = low;
3055 };
3056 } else {
3057 low = med; /* progress because low < med */
3058 };
3059 };
3060
3061 if (low == high) {
3062 res = low;
3063 };
3064
3065 if (res != -1) {
3066 return MEM_ReadIntArray(array.array, 2*res + 1);
3067 };
3068
3069 MEM_StackPos.position = loop;
3070 /* } end while */
3071};
3072
3073//************************************************
3074// Den eigenene Stackframe finden
3075//************************************************
3076
3077//Get ESP that points (not too far) above the current DoStack Frame:
3078func int MEMINT_GetESP() {
3079 var int ESP;
3080
3081 const int call = 0;
3082 if (CALL_Begin(call)) {
3083 ASM_2(ASMINT_OP_movESPtoEAX);
3084 ASM_2(ASMINT_OP_movEAXToMem);
3085 ASM_4(_@(ESP));
3086 ASM_1(ASMINT_OP_retn);
3087
3088 call = CALL_End();
3089
3090 if (CALL_Begin(call)) {}; //result may be different on first time!
3091 };
3092 return ESP;
3093};
3094
3095//Check for and find zCParser::DoStack lying on itself on the Stack.
3096//returns the position one word above the return address (usually points to -1, part of the SEH)
3097func int MEMINT_IsFrameBoundary(var int ESP) {
3098 const int retAdr = 0;
3099 if (!retAdr) {
3100 /* Wenn DoStack sich selbst aufruft, steht diese Rücksprungaddresse auf dem Stack: */
3101 retAdr = MEMINT_SwitchG1G2(7246244 /* 0x6E91A4 */, 7939332 /*0x792504 */);
3102 };
3103
3104 return (MEM_ReadInt(ESP) == -1)
3105 && (MEM_ReadInt(ESP+4) == retAdr);
3106};
3107
3108func int MEMINT_FindFrameBoundary(var int ESP, var int searchWordsMAX) {
3109 var int loop; loop = MEM_StackPos.position;
3110
3111 /* didnt find anything */
3112 if (searchWordsMAX == 0) {
3113 return 0;
3114 };
3115
3116 /* while */
3117 if (!MEMINT_IsFrameBoundary(ESP)) {
3118 /* I am only interested in frame starts */
3119 ESP += 4;
3120 searchWordsMAX -= 1;
3121 MEM_StackPos.position = loop;
3122 };
3123 /* end while */
3124
3125 return ESP;
3126};
3127
3128//Now get not only some Stack Frame, but my own!
3129
3130/* offset of two frames when calling it self */
3131const int MEMINT_DoStackFrameSize = 88;
3132/* location of oldPopPos after having called itself */
3133const int MEMINT_DoStackPopPosOffset = MEMINT_DoStackFrameSize + MEMINT_DoStackFrameSize - 6 * 4;
3134
3135func int MEM_GetFrameBoundary() {
3136 const int offset = 0;
3137 var int ESP; ESP = MEMINT_GetESP();
3138
3139 if (!offset) {
3140 /* Offset depends on implementation of CALL but is, apart from that, constant.
3141 * Better calculate it from scratch at every start of gothic */
3142
3143 var int realESP;
3144 realESP = ESP;
3145 /* get into a safe area. When reading the ESP the following was in the way:
3146 * MEMINT_GetESP
3147 * CALL_Begin
3148 * ASM_Run
3149 * ASMINT_CallMyExternal */
3150
3151 realESP += 4*MEMINT_DoStackFrameSize;
3152
3153 /* MEMINT_FindFrameBoundary goes deep enough so that it reads on valid stack parts */
3154 realESP = MEMINT_FindFrameBoundary(realESP, MEMINT_DoStackFrameSize);
3155
3156 if (!realESP) {
3157 MEM_AssertFail("MEM_GetFrameBoundary: Could not locate start of stackframe.");
3158 return 0;
3159 };
3160
3161 var int myID; myID = MEM_GetFuncID(MEM_GetFrameBoundary);
3162
3163 var int loop; loop = MEM_StackPos.position;
3164
3165 var int popPos;
3166 popPos = MEM_ReadIntArray(realESP-MEMINT_DoStackPopPosOffset, 0); /* for safety, use a function that builds another stacklayer */
3167 realESP += MEMINT_DoStackFrameSize;
3168
3169 if (MEM_GetFuncIDByOffset(popPos) != myID) {
3170 MEM_StackPos.position = loop;
3171 };
3172
3173 offset = realESP - ESP;
3174 };
3175
3176 return ESP + offset;
3177};
3178
3179//--------------------------------------
3180// What this is all about:
3181//--------------------------------------
3182
3183func int MEM_GetCallerStackPos() {
3184 /* get my Frame Boundary, add 1 Frame (because this isnt about me)
3185 * and add another frame (because its not about my caller)
3186 * to get the PopPos of my caller's caller */
3187 return MEM_ReadInt(MEM_GetFrameBoundary() + 2*MEMINT_DoStackFrameSize - MEMINT_DoStackPopPosOffset);
3188};
3189
3190func void MEM_SetCallerStackPos(var int popPos) {
3191 MEM_WriteInt(MEM_GetFrameBoundary() + 2*MEMINT_DoStackFrameSize - MEMINT_DoStackPopPosOffset, popPos);
3192};
3193
3194//************************************************
3195// JUMP / GOTO / WHILE
3196//************************************************
3197
3198//--------------------------------------
3199// Split function into tokens
3200//--------------------------------------
3201
3202/* will append -1, -1, endOfFunc after the last token */
3203func void MEMINT_TokenizeFunction(var int funcID, var int tokenArray, var int paramArray, var int posArr) {
3204 var int pos;
3205 var zCPar_Symbol symb;
3206 symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, funcID));
3207 pos = symb.content;
3208 pos += currParserStackAddress;
3209
3210 var int loop; loop = MEM_StackPos.position;
3211
3212 MEM_ArrayInsert(posArr, pos);
3213 var int tok; tok = MEM_ReadByte(pos); pos += 1;
3214 var int param;
3215
3216 if (tok == zPAR_TOK_CALL || tok == zPAR_TOK_CALLEXTERN)
3217 || (tok == zPAR_TOK_PUSHINT || tok == zPAR_TOK_PUSHVAR)
3218 || (tok == zPAR_TOK_PUSHINST || tok == zPAR_TOK_SETINSTANCE)
3219 || (tok == zPAR_TOK_JUMP || tok == zPAR_TOK_JUMPF) {
3220 /* take one parameter */
3221 param = MEM_ReadInt(pos); pos += 4;
3222 } else if (tok == zPAR_TOK_PUSH_ARRAYVAR) {
3223 param = MEM_ReadInt(pos); pos += 4;
3224 pos += 1; //array index.
3225 } else if (tok > zPAR_TOK_SETINSTANCE) {
3226 var string err; err = ConcatStrings("MEMINT_TokenizeFunction: Invalid Token in function ", symb.name);
3227 err = ConcatStrings(err, ". Did you break it? This will probably cause more errors.");
3228 MEM_Error(err);
3229 return;
3230 } else {
3231 /* probably valid token without parameters */
3232 param = 0;
3233 };
3234
3235 MEM_ArrayInsert(tokenArray, tok);
3236 MEM_ArrayInsert(paramArray, param);
3237
3238 if (tok == zPAR_TOK_RET) {
3239 if (MEM_GetFuncIDByOffset(pos - currParserStackAddress) != funcID) {
3240 /* mark end of function */
3241 MEM_ArrayInsert(posArr, pos);
3242 MEM_ArrayInsert(tokenArray, -1);
3243 MEM_ArrayInsert(paramArray, -1);
3244 return;
3245 };
3246 };
3247
3248 MEM_StackPos.position = loop;
3249};
3250
3251//--------------------------------------
3252// Trace calculation of an argument
3253// back to its beginning
3254//--------------------------------------
3255
3256//Helperfunction: Trace the origin of one param:
3257func int MEMINT_TraceParameter(var int pos, var int tokenArr, var int paramArr) {
3258 /* assert: tokenArr is an array of parser tokens.
3259 * pos is an index into this array, pointing to the token
3260 * where a parameter is expected.
3261 * I will return the index of the token where the calculation
3262 * for this parameter starts. */
3263
3264 var int paramsNeeded; paramsNeeded = 1;
3265
3266 var int loop; loop = MEM_StackPos.position;
3267
3268 if (pos == 0) {
3269 MEM_Error("MEMINT_TraceParameter: The parameter was pushed outside the function.");
3270 return -1;
3271 };
3272 pos -= 1;
3273 var int tok; tok = MEM_ArrayRead(tokenArr, pos);
3274
3275 if (tok == zPAR_TOK_PUSHINT || tok == zPAR_TOK_PUSHVAR
3276 || tok == zPAR_TOK_PUSH_ARRAYVAR || tok == zPAR_TOK_PUSHINST) {
3277 paramsNeeded -= 1;
3278 } else if (tok >= zPAR_TOK_ASSIGNSTR && tok <= zPAR_TOK_ASSIGNINST)
3279 || (tok == zPAR_OP_IS) || (tok <= zPAR_OP_ISDIV && tok >= zPAR_OP_ISPLUS) {
3280 MEM_Error("MEMINT_TraceParameter: Assignment within expression that is expected to produce non-void result. This does not make sense.");
3281 paramsNeeded += 2;
3282 } else if (tok == zPAR_TOK_CALL || tok == zPAR_TOK_CALLEXTERN) {
3283 var zCPar_Symbol symb; var int symbID;
3284 if (tok == zPAR_TOK_CALL) {
3285 symbID = MEM_GetFuncIDByOffset(MEM_ArrayRead(paramArr, pos));
3286 } else {
3287 symbID = MEM_ArrayRead(paramArr, pos);
3288 };
3289
3290 symb = _^(MEM_GetSymbolByIndex(symbID));
3291 paramsNeeded += symb.bitfield & zCPar_Symbol_bitfield_ele; /* need to calculate the parameters */
3292 paramsNeeded -= symb.offset != 0; //!= 0 ==> return value!
3293 } else if (tok >= zPAR_OP_UNARY && tok <= zPAR_OP_MAX)
3294 || (tok == zPAR_TOK_SETINSTANCE) {
3295 /* nothing, unary operators have no effective parameter consumption
3296 * zPAR_TOK_SETINSTANCE does not either */
3297 } else if (tok <= zPAR_OP_HIGHER_EQ) {
3298 paramsNeeded += 1; //binary operations, two in, one out.
3299 } else {
3300 MEM_Error("MEMINT_TraceParameter: Invalid token!");
3301 };
3302
3303 if (paramsNeeded == 0) {
3304 if (pos > 0) {
3305 if (MEM_ArrayRead(tokenArr, pos-1) == zPAR_TOK_SETINSTANCE) {
3306 pos -= 1; //dont forget this token, it is important
3307 };
3308 };
3309 /* good, this is the point */
3310 return pos;
3311 };
3312
3313 MEM_StackPos.position = loop;
3314};
3315
3316//--------------------------------------
3317// Patch function:
3318// Scan function and replace calls to
3319// label, goto and while with
3320// appropriate tokens that handle
3321// the situation correctly
3322//--------------------------------------
3323
3324//For printing only
3325func string MEMINT_GetLabelName(var int labelValue) {
3326 /* alchemy: is the constant a symbol index or a plain constant? */
3327 if (1000 < labelValue && labelValue < MEM_Parser.symtab_table_numInArray) {
3328 var zCPar_Symbol symb;
3329 symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, labelValue));
3330 return symb.name;
3331 } else {
3332 return IntToString(labelValue);
3333 };
3334};
3335
3336func void MEMINT_PrepareLoopsAndJumps(var int stackPos) {
3337 var int tokenArr; tokenArr = MEM_ArrayCreate();
3338 var int paramArr; paramArr = MEM_ArrayCreate();
3339 var int posArr; posArr = MEM_ArrayCreate();
3340 var int size;
3341
3342 MEMINT_TokenizeFunction(MEM_GetFuncIDByOffset(stackPos), tokenArr, paramArr, posArr);
3343 size = MEM_ArraySize(posArr); /* all have the same size */
3344
3345 /* find all Labels and gotos */
3346 var int labelFunc; labelFunc = MEM_GetFuncOffset(MEM_Label);
3347 var int labelsArr; labelsArr = MEM_ArrayCreate();
3348 var int labelPosArr; labelPosArr = MEM_ArrayCreate(); /* position after the label */
3349
3350 var int gotoFunc; gotoFunc = MEM_GetFuncOffset(MEM_Goto);
3351 var int gotoArr; gotoArr = MEM_ArrayCreate();
3352 var int gotoPosArr; gotoPosArr = MEM_ArrayCreate(); /* position before the parameter push */
3353
3354 var int usedLabels; usedLabels = MEM_ArrayCreate();
3355
3356 var int i; i = 0;
3357 var int loop; loop = MEM_StackPos.position;
3358
3359 if (i < size) {
3360 var int type; const int goto = 1; const int label = 2;
3361
3362 if (MEM_ArrayRead(tokenArr, i) != zPAR_TOK_CALL) {
3363 type = 0;
3364 } else if (MEM_ArrayRead(paramArr, i) == gotoFunc) {
3365 type = goto;
3366 } else if (MEM_ArrayRead(paramArr, i) == labelFunc) {
3367 type = label;
3368 } else {
3369 type = 0;
3370 };
3371
3372 if (type) {
3373 /* assert: i > 0 */
3374 var int labelValue;
3375 var int pushingTok;
3376 pushingTok = MEM_ArrayRead(tokenArr, i - 1);
3377
3378 if (pushingTok == zPAR_TOK_PUSHINT) {
3379 labelValue = MEM_ArrayRead(paramArr, i - 1);
3380 } else if (pushingTok == zPAR_TOK_PUSHVAR) {
3381 /* the syntax check guarantees that an integer was pusht here */
3382 labelValue = MEM_ArrayRead(paramArr, i - 1); /* this is a symbol index */
3383 var zCPar_Symbol symb;
3384 symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, labelValue));
3385 labelValue = symb.content;
3386 } else {
3387 MEM_Error("MEMINT_PrepareLoopsAndJumps: Invalid label found. The parameters for MEM_Goto and MEM_Label must be a constant!");
3388 i += 1;
3389 MEM_StackPos.position = loop;
3390 };
3391
3392 if (type == label) {
3393 MEM_ArrayPush(labelsArr, labelValue);
3394 MEM_ArrayPush(labelPosArr, MEM_ArrayRead(posArr, i+1)); /* note: There is always a return after me */
3395 } else {
3396 MEM_ArrayPush(gotoArr, labelValue);
3397 MEM_ArrayPush(gotoPosArr, MEM_ArrayRead(posArr, i-1));
3398 };
3399 };
3400
3401 i += 1;
3402 MEM_StackPos.position = loop;
3403 };
3404
3405 /* make all gotos to jumps */
3406 i = 0;
3407 loop = MEM_StackPos.position;
3408
3409 if (i < MEM_ArraySize(gotoArr)) {
3410 labelValue = MEM_ArrayRead(gotoArr, i);
3411 var int gotoPos; gotoPos = MEM_ArrayRead(gotoPosArr, i);
3412
3413 var int labelIndex; labelIndex = MEM_ArrayIndexOf(labelsArr, labelValue);
3414
3415 var int labelPos;
3416 if (labelIndex == -1) {
3417 var string err; err = "MEMINT_PrepareLoopsAndJumps: Goto to non-existing label found: ";
3418 err = ConcatStrings(err, MEMINT_GetLabelName(labelValue));
3419 err = ConcatStrings(err, ".");
3420 MEM_Error(err);
3421
3422 labelPos = gotoPos + 10;
3423 } else {
3424 labelPos = MEM_ArrayRead(labelPosArr, labelIndex);
3425 };
3426
3427 labelPos -= currParserStackAddress; /* relative to stack start */
3428
3429 /* overwrite parameter push and call to MEM_Goto */
3430 MEM_WriteByte(gotoPos, zPAR_TOK_JUMP); gotoPos += 1;
3431 MEM_WriteInt (gotoPos, labelPos); gotoPos += 4;
3432 MEM_WriteByte(gotoPos, zPAR_TOK_JUMP); gotoPos += 1;
3433 MEM_WriteInt (gotoPos, labelPos); gotoPos += 4;
3434
3435 MEM_ArrayInsert(usedLabels, labelValue);
3436
3437 i += 1;
3438 MEM_StackPos.position = loop;
3439 };
3440
3441 /* consistency check: All Labels used? Labels declared multiple times? */
3442 loop = MEM_StackPos.position;
3443
3444 if (MEM_ArraySize(labelsArr)) {
3445 labelValue = MEM_ArrayRead(labelsArr, 0);
3446 MEM_ArrayRemoveIndex(labelsArr, 0); /* discard this entry */
3447
3448 if (MEM_ArrayIndexOf(labelsArr, labelValue) != -1) {
3449 /* still in there? */
3450 var string error; error = "MEMINT_PrepareLoopsAndJumps: Label declared more than once: ";
3451 error = ConcatStrings(error, MEMINT_GetLabelName(labelValue));
3452 error = ConcatStrings(error, ".");
3453 MEM_Error(error);
3454 } else if (MEM_ArrayIndexOf(usedLabels, labelValue) == -1) {
3455 error = "MEMINT_PrepareLoopsAndJumps: Unused Label: ";
3456 error = ConcatStrings(error, MEMINT_GetLabelName(labelValue));
3457 error = ConcatStrings(error, ".");
3458 MEM_Warn(error);
3459 };
3460
3461 MEM_StackPos.position = loop;
3462 };
3463
3464 MEM_ArrayFree(labelsArr );
3465 MEM_ArrayFree(labelPosArr );
3466 MEM_ArrayFree(gotoArr );
3467 MEM_ArrayFree(gotoPosArr );
3468 MEM_ArrayFree(usedLabels );
3469
3470 /* Handle while */
3471 var int whileOffset; whileOffset = MEM_GetFuncOffset(while);
3472 var int repeatOffset; repeatOffset = MEM_GetFuncOffset(repeat);
3473 var int endID; endID = MEM_FindParserSymbol("END");
3474 var int breakID; breakID = MEM_FindParserSymbol("BREAK");
3475 var int continueID; continueID = MEM_FindParserSymbol("CONTINUE");
3476
3477 var int loopType; loopType = -1; const int W = 0; const int R = 1;
3478 var int contTarget; contTarget = -1;
3479
3480 var int loopStack; loopStack = MEM_ArrayCreate(); /* contains saved data when nesting loops */
3481 var int jumpEndStack; jumpEndStack = MEM_ArrayCreate(); /* position of break statements and -1 as seperator for nesting */
3482
3483 i = 0;
3484 loop = MEM_StackPos.position;
3485
3486 if (i < size) {
3487 var int tok; tok = MEM_ArrayRead(tokenArr, i);
3488 var int param; param = MEM_ArrayRead(paramArr, i);
3489 var int pos; pos = MEM_ArrayRead(posArr, i);
3490 if (tok == zPAR_TOK_CALL && param == whileOffset) {
3491 MEM_ArrayPush(loopStack, loopType);
3492 MEM_ArrayPush(loopStack, contTarget);
3493
3494 MEM_WriteByte(pos, zPAR_TOK_JUMPF);
3495
3496 contTarget = MEM_ArrayRead(posArr, MEMINT_TraceParameter(i, tokenArr, paramArr));
3497 loopType = W;
3498
3499 MEM_ArrayPush(jumpEndStack, -1); /* seperator */
3500 MEM_ArrayPush(jumpEndStack, pos+1); /* insert the end-Pos of the loop here, as soon as I know it */
3501 } else if (tok == zPAR_TOK_CALL && param == repeatOffset) {
3502 /* for repeat I need a new code segment to jump into */
3503 MEM_ArrayPush(loopStack, loopType);
3504 MEM_ArrayPush(loopStack, contTarget);
3505
3506 loopType = R;
3507
3508 var int code; code = MEM_Alloc(30);
3509
3510 /* jump to the new code */
3511 MEM_WriteByte(pos , zPAR_TOK_JUMP);
3512 MEM_WriteInt (pos+1, code - currParserStackAddress);
3513
3514 /* create a MEMINT_RepeatData */
3515 var int dataPtr; dataPtr = MEM_Alloc(8);
3516 var int entryFiddler; entryFiddler = MEM_GetFuncOffset(MEMINT_RepeatEntryFiddle);
3517 var int redoChecker; redoChecker = MEM_GetFuncOffset(MEMINT_RepeatRedoCheck );
3518 /* let my entry handler fill the variable with 0 and remember the limit */
3519 MEM_WriteByte(code, zPAR_TOK_PUSHINT ); code += 1; MEM_WriteInt(code, dataPtr ); code += 4;
3520 MEM_WriteByte(code, zPAR_TOK_CALL ); code += 1; MEM_WriteInt(code, entryFiddler ); code += 4;
3521 /* directly after that check for valid bounds.
3522 * this is where a continue jumps to */
3523 contTarget = code;
3524 MEM_WriteByte(code, zPAR_TOK_PUSHINT ); code += 1; MEM_WriteInt(code, dataPtr ); code += 4;
3525 MEM_WriteByte(code, zPAR_TOK_CALL ); code += 1; MEM_WriteInt(code, redoChecker ); code += 4;
3526 /* jump to the end if the redochecker says so */
3527 MEM_WriteByte(code, zPAR_TOK_JUMPF ); code += 1;
3528 MEM_ArrayPush(jumpEndStack, -1); /* seperator */
3529 MEM_ArrayPush(jumpEndStack, code); /* insert the end-Pos of the loop here, as soon as I know it */
3530 code += 4;
3531 /* If i chose to continue, unconditional jump back to the code: */
3532 MEM_WriteByte(code, zPAR_TOK_JUMP ); code += 1; MEM_WriteInt(code, pos + 5 - currParserStackAddress); code += 4;
3533 } else if (tok == zPAR_TOK_PUSHVAR && param == endID) {
3534 if (loopType == -1) {
3535 MEM_Error("MEMINT_PrepareLoopsAndJumps: end found outside of loop!");
3536 i += 1;
3537 MEM_StackPos.position = loop;
3538 };
3539
3540 MEM_WriteByte(pos , zPAR_TOK_JUMP);
3541 MEM_WriteInt (pos+1, contTarget - currParserStackAddress);
3542
3543 /* handle all the breaks now: */
3544 var int brkLoop; brkLoop = MEM_StackPos.position;
3545 var int JmpEndPos; JmpEndPos = MEM_ArrayPop(jumpEndStack);
3546
3547 if (JmpEndPos != -1) { /* this is the guardian */
3548 MEM_WriteInt (JmpEndPos, pos + 5 - currParserStackAddress);
3549 MEM_StackPos.position = brkLoop;
3550 };
3551
3552 contTarget = MEM_ArrayPop(loopStack);
3553 loopType = MEM_ArrayPop(loopStack);
3554 } else if (tok == zPAR_TOK_PUSHVAR && param == breakID) {
3555 if (loopType == -1) {
3556 MEM_Error("MEMINT_PrepareLoopsAndJumps: break found outside of loop!");
3557 } else {
3558 MEM_WriteByte(pos, zPAR_TOK_JUMP);
3559 MEM_ArrayPush(jumpEndStack, pos+1); /* insert the end address here as soon as I know it */
3560 };
3561 } else if (tok == zPAR_TOK_PUSHVAR && param == continueID) {
3562 if (loopType == -1) {
3563 MEM_Error("MEMINT_PrepareLoopsAndJumps: continue found outside of loop!");
3564 } else {
3565 MEM_WriteByte(pos , zPAR_TOK_JUMP);
3566 MEM_WriteInt (pos+1, contTarget - currParserStackAddress);
3567 };
3568 };
3569
3570 i += 1;
3571 MEM_StackPos.position = loop;
3572 };
3573
3574 if (loopType != -1) {
3575 MEM_Error("MEMINT_PrepareLoopsAndJumps: Loop not closed with 'end;'.");
3576 };
3577
3578 MEM_ArrayFree(loopStack);
3579 MEM_ArrayFree(jumpEndStack);
3580
3581 /* cleanup */
3582
3583 MEM_ArrayFree(tokenArr);
3584 MEM_ArrayFree(paramArr);
3585 MEM_ArrayFree(posArr);
3586};
3587
3588//--------------------------------------
3589// while
3590//--------------------------------------
3591
3592class C_Label {}; /* so it is possible to declare var C_Label lbl */
3593
3594const int break = -42;
3595const int continue = -23;
3596const int end = -72;
3597func void while(var int b) {
3598 /* consistency check */
3599 var int calledFrom; calledFrom = MEM_GetCallerStackPos() - 5;
3600 if (MEM_ReadByte(calledFrom + currParserStackAddress) != zPAR_TOK_CALL)
3601 || (MEM_ReadInt (calledFrom + 1 + currParserStackAddress) != MEM_GetFuncOffset(while)) {
3602 MEM_Error("while: While was called in an unorthodox way! This cannot be handled.");
3603 return;
3604 };
3605
3606 MEMINT_PrepareLoopsAndJumps(calledFrom);
3607 b; /* repush b */
3608
3609 MEM_SetCallerStackPos(calledFrom); /* get before the call to while which is now a jumpf */
3610};
3611
3612//--------------------------------------
3613// label / goto
3614//--------------------------------------
3615
3616func void MEM_Label(var int lbl) {}; /* nothing to do */
3617func void MEM_Goto (var int lbl) {
3618 var int calledFrom; calledFrom = MEM_GetCallerStackPos() - 5;
3619 /* consistency check */
3620 if (MEM_ReadByte(calledFrom + currParserStackAddress) != zPAR_TOK_CALL)
3621 || (MEM_ReadInt (calledFrom + 1 + currParserStackAddress) != MEM_GetFuncOffset(MEM_Goto)) {
3622 MEM_Error("MEM_Goto: MEM_Goto was called in an unorthodox way! This cannot be handled.");
3623 return;
3624 };
3625
3626 MEMINT_PrepareLoopsAndJumps(calledFrom);
3627 MEM_SetCallerStackPos(calledFrom); /* get before the call to MEM_Goto which is now a jump */
3628};
3629
3630//--------------------------------------
3631// repeat
3632//--------------------------------------
3633
3634func void Repeat(var int variable, var int limit) {
3635 MEM_Error("MEM_Repat was called before MEM_InitRepeat / MEM_InitAll");
3636};
3637func void MEMINT_Repeat() {
3638 var int calledFrom; calledFrom = MEM_GetCallerStackPos() - 5;
3639
3640 /* consistency check */
3641 if (MEM_ReadByte(calledFrom + currParserStackAddress) != zPAR_TOK_CALL)
3642 || (MEM_ReadInt (calledFrom + 1 + currParserStackAddress) != MEM_GetFuncOffset(repeat)) {
3643 MEM_Error("repeat: repeat was called in an unorthodox way! This cannot be handled.");
3644 return;
3645 };
3646
3647 MEMINT_PrepareLoopsAndJumps(calledFrom);
3648
3649 /* I left the two parameters on the stack, we can start */
3650 MEM_SetCallerStackPos(calledFrom);
3651};
3652
3653func void MEM_InitRepeat() {
3654 const int done = 0;
3655 if (!done) {
3656 MEM_ReplaceFunc(Repeat, MEMINT_Repeat);
3657 done = true;
3658 };
3659};
3660
3661class MEMINT_RepeatData {
3662 var int varAdr;
3663 var int limit;
3664};
3665
3666func void MEMINT_RepeatEntryFiddle(/* var int VAR */ var int limit, var int loopData) {
3667 var int tok; tok = MEMINT_StackPopInstAsInt();
3668
3669 if (tok != zPAR_TOK_PUSHVAR) {
3670 MEM_Error("MEMINT_RepeatEntryFiddle: First Parameter given to MEM_Repeat is not an lValue (not modifiable).");
3671 return;
3672 };
3673
3674 var int varAdr; varAdr = MEMINT_StackPopInstAsInt();
3675 MEM_WriteInt(varAdr, -1); //starts with 0 (will be incremented immediately)
3676
3677 MEM_WriteInt(loopData , varAdr); /* the variable */
3678 MEM_WriteInt(loopData+4, limit);
3679};
3680
3681func int MEMINT_RepeatRedoCheck(var int loopData) {
3682 var MEMINT_RepeatData data;
3683 data = _^(loopData);
3684
3685 var int val; val = MEM_ReadInt(data.varAdr);
3686 val += 1;
3687
3688 MEM_WriteInt(data.varAdr, val);
3689
3690 return val < data.limit;
3691};
3692
3693//######################################################
3694//
3695// Access Menu Objects
3696//
3697//######################################################
3698
3699/*
3700 Leider werden manche Menüs jedesmal neu erzeugt (vom Script aus),
3701 andere dagegen werden beim ersten mal nach dem Spielstart erzeugt und dann behalten.
3702 Abhängig davon und von dem, was man eigentlich tun will, kann es nötig sein
3703 in den Menüscripten Änderungen einzubringen (indem man
3704 in den Variablen dort schreibt) oder es ist nötig sich das Menü
3705 als Objekt zu holen und in dem fertigen Objekt selbst herumzuschmieren.
3706*/
3707
3708func int MEM_GetMenuByString (var string menuName) {
3709 var zCArray menus;
3710 menus = _^(MEMINT_MenuArrayOffset);
3711
3712 var int pos; pos = 0;
3713
3714 var int loopStart; loopStart = MEM_StackPos.position;
3715
3716 if (pos >= menus.numInArray) {
3717 /* Liste durch und nichts gefunden? */
3718 /* Warnung nervt:
3719 MEM_Warn (ConcatStrings ("MEM_GetMenuByString: No Menu with the following name found: ", menuName));
3720 */
3721 return 0;
3722 };
3723
3724 var int menuAddr; menuAddr = MEM_ReadIntArray (menus.array, pos);
3725 var zCMenu menu; menu = _^(menuAddr);
3726
3727 if (Hlp_StrCmp (menu.name, menuName)) {
3728 return menuAddr;
3729 };
3730
3731 pos += 1;
3732 MEM_StackPos.position = loopStart;
3733};
3734
3735//--------------------------------------
3736// MenuItem Zugriff
3737//--------------------------------------
3738
3739/* Selbe Bemerkung wie zu Menüs */
3740
3741func int MEM_GetMenuItemByString (var string menuItemName) {
3742 var zCArray menuItems;
3743 menuItems = _^(MEMINT_MenuItemArrayAddres);
3744
3745 var int pos; pos = 0;
3746
3747 var int loopStart; loopStart = MEM_StackPos.position;
3748
3749 if (pos >= menuItems.numInArray) {
3750 /* Liste durch und nichts gefunden? */
3751 //Warnung rausgenommen: Die nervt extrem.
3752 //MEM_Warn (ConcatStrings ("MEM_GetMenuItemByString: No Menu with the following name found: ", menuItemName));
3753 return 0;
3754 };
3755
3756 var int menuItemAddr; menuItemAddr = MEM_ReadIntArray (menuItems.array, pos);
3757 var zCMenuItem menuItem; menuItem = _^(menuItemAddr);
3758
3759 if (Hlp_StrCmp (menuItem.id, menuItemName)) {
3760 return menuItemAddr;
3761 };
3762
3763 pos += 1;
3764 MEM_StackPos.position = loopStart;
3765};
3766
3767//######################################################
3768//
3769// zCObjects
3770//
3771//######################################################
3772
3773//************************************************
3774// Locate some commonly used objects
3775//************************************************
3776
3777instance MEM_Game (oCGame);
3778instance MEM_World(oWorld);
3779instance MEM_Timer(zCTimer);
3780instance MEM_WorldTimer(oCWorldTimer);
3781instance MEM_Vobtree(zCTree);
3782instance MEM_InfoMan(oCInfoManager);
3783instance MEM_InformationMan (oCInformationManager);
3784instance MEM_Waynet(zCWaynet);
3785instance MEM_Camera(zCCamera);
3786instance MEM_SkyController(zCSkyController_Outdoor);
3787instance MEM_SpawnManager (oCSpawnManager);
3788instance MEM_GameMananger (CGameManager);
3789instance MEM_GameManager (CGameManager);
3790instance MEM_Parser(zCParser);
3791
3792func void MEM_InitGlobalInst() {
3793 //Game:
3794 MEM_Game = _^(MEM_ReadInt (MEMINT_oGame_Pointer_Address));
3795
3796 //World:
3797 MEM_World = _^(MEM_Game._zCSession_world);
3798
3799 //Vobtree:
3800 MEM_Vobtree = _^(MEM_Game._zCSession_world + 36); //+ 0x0024
3801
3802 //InfoManager:
3803 MEM_InfoMan = _^(MEM_Game.infoman);
3804
3805 //InformationManager
3806 MEM_InformationMan = _^(MEMINT_oCInformationManager_Address);
3807
3808 //Waynet:
3809 MEM_Waynet = _^(MEM_World.wayNet);
3810
3811 //Camera
3812 MEM_Camera = _^(MEM_Game._zCSession_camera);
3813
3814 //SkyController:
3815 if (MEM_World.skyControlerOutdoor) {
3816 MEM_SkyController = _^(MEM_World.skyControlerOutdoor);
3817 } else {
3818 MEM_AssignInstNull (MEM_SkyController);
3819 };
3820
3821 //Spawnmanager
3822 MEM_SpawnManager = _^(MEM_Game.spawnman);
3823
3824 //zTimer:
3825 MEM_Timer = _^(MEMINT_zTimer_Address);
3826
3827 //WorldTimer:
3828 MEM_WorldTimer = _^(MEM_Game.wldTimer);
3829
3830 //GameManager
3831 MEM_GameMananger = _^(MEM_ReadInt(MEMINT_gameMan_Pointer_address)); /* shit: Typo! Keep it as to not break code */
3832 MEM_GameManager = _^(MEM_ReadInt(MEMINT_gameMan_Pointer_address));
3833
3834 //The Content Parser
3835 MEM_Parser = _^(contentParserAddress);
3836};
3837
3838//************************************************
3839// Validity checks
3840//************************************************
3841
3842func int Hlp_Is_oCMobFire (var int ptr) {
3843 if (!ptr) { return 0; };
3844 return (MEM_ReadInt (ptr) == oCMobFire_vtbl);
3845};
3846
3847func int Hlp_Is_zCMover(var int ptr) {
3848 if (!ptr) { return 0; };
3849 return (MEM_ReadInt (ptr) == zCMover_vtbl);
3850};
3851
3852func int Hlp_Is_oCMob(var int ptr) {
3853 if (!ptr) { return 0; };
3854
3855 var int vtbl;
3856 vtbl = MEM_ReadInt (ptr);
3857
3858 /* Schreibweise so bescheuert, weil Gothic Sourcer bei || meckert. */
3859 return (vtbl == oCMob_vtbl)
3860 | (vtbl == oCMobInter_vtbl)
3861 | (vtbl == oCMobContainer_vtbl)
3862 | (vtbl == oCMobDoor_vtbl);
3863};
3864
3865func int Hlp_Is_oCMobInter(var int ptr) {
3866 if (!ptr) { return 0; };
3867
3868 var int vtbl;
3869 vtbl = MEM_ReadInt (ptr);
3870
3871 return (vtbl == oCMobInter_vtbl)
3872 | (vtbl == oCMobContainer_vtbl)
3873 | (vtbl == oCMobDoor_vtbl);
3874};
3875
3876func int Hlp_Is_oCMobLockable(var int ptr) {
3877 if (!ptr) { return 0; };
3878
3879 /* Gibt es Lockables die weder Türen noch Truhe sind?
3880 * nutzt aber eh keiner => zu faul zum nachforschen. */
3881 var int vtbl;
3882 vtbl = MEM_ReadInt (ptr);
3883
3884 return (vtbl == oCMobContainer_vtbl)
3885 | (vtbl == oCMobDoor_vtbl);
3886};
3887
3888func int Hlp_Is_oCMobContainer(var int ptr) {
3889 if (!ptr) { return 0; };
3890 return (MEM_ReadInt (ptr) == oCMobContainer_vtbl);
3891};
3892
3893func int Hlp_Is_oCMobDoor(var int ptr) {
3894 if (!ptr) { return 0; };
3895 return (MEM_ReadInt (ptr) == oCMobDoor_vtbl);
3896};
3897
3898func int Hlp_Is_oCNpc (var int ptr) {
3899 if (!ptr) { return 0; };
3900 return (MEM_ReadInt (ptr) == oCNpc_vtbl);
3901};
3902
3903func int Hlp_Is_oCItem (var int ptr) {
3904 if (!ptr) { return 0; };
3905 return (MEM_ReadInt (ptr) == oCItem_vtbl);
3906};
3907
3908func int Hlp_Is_zCVobLight (var int ptr) {
3909 if (!ptr) { return 0; };
3910 return (MEM_ReadInt (ptr) == zCVobLight_vtbl);
3911};
3912
3913//************************************************
3914// Find zCClassDef
3915//************************************************
3916
3917func int MEM_GetClassDef (var int objPtr) {
3918 if (!objPtr) {
3919 MEM_Error ("MEMINT_GetClassDef: ObjPtr == 0.");
3920 return 0;
3921 };
3922
3923 //In obj._vtbl[0] steht die Adresse der Funktion, die ClassDef zurückgibt.
3924 //Diese Funktion besteht aus einem einfachen "mov eax" (1 byte), der Adresse (4 byte) und einem "retn" (1 byte).
3925
3926 //obj._vtbl[0] contains the address of a virtual function that returns
3927 //the classDef of the class of the object.
3928 //This function contains of a single "mov" command (1 byte) that is followed by the address that is of interest here.
3929
3930 return MEM_ReadInt (1 + MEM_ReadInt (MEM_ReadInt (objPtr)));
3931};
3932
3933func string MEM_GetClassName (var int objPtr) {
3934 var int classDef;
3935 classDef = MEM_GetClassDef (objPtr);
3936
3937 if (classDef) {
3938 return MEM_ReadString (classDef); //gleich die erste Eigenschaft / first property of zCClassDef.
3939 };
3940 return "";
3941};
3942
3943//************************************************
3944// Create and delete Vobs
3945//************************************************
3946
3947/* Danke an Gottfried für die Entdeckung von Wld_InsertObject! */
3948func int MEM_InsertVob(var string vis, var string wp) {
3949 /* oCMob von Gothic konstruieren lassen */
3950 const int oCNpc__player_G1 = 9288624; //0x8DBBB0
3951 const int oCNpc__player_G2 = 11216516; //0xAB2684
3952
3953 var int playerAdr;
3954 playerAdr = MEMINT_SwitchG1G2(oCNpc__player_G1, oCNpc__player_G2);
3955
3956 var int wasInvalid; wasInvalid = 0;
3957
3958 /* Wld_InsertObject crashed wenn es keinen Player gibt!
3959 * Das ist z.B. der Fall, wenn man dies hier aus der Startup aufruft. */
3960 if (!Hlp_Is_oCNpc(MEM_ReadInt(playerAdr))) {
3961 wasInvalid = 1;
3962 MEMINT_GetMemHelper();
3963 MEM_WriteInt(playerAdr, MEM_InstGetOffset(MEM_Helper));
3964 var int oldWorld; oldWorld = MEM_Helper._zCVob_homeWorld; //player braucht auch Homeworld.
3965 MEM_Helper._zCVob_HomeWorld = MEM_InstGetOffset(MEM_World);
3966 };
3967
3968 Wld_InsertObject(vis,wp);
3969
3970 /* wieder invalidieren */
3971 if (wasInvalid) {
3972 MEM_WriteInt(playerAdr, 0);
3973 MEM_Helper._zCVob_HomeWorld = oldWorld;
3974 };
3975
3976 /* Ein Pointer auf das neue Objekt findet sich im Vobtree
3977 * stets als erstes Kind des globalen Vobtrees */
3978 var zCTree newTreeNode;
3979 newTreeNode = _^ (MEM_World.globalVobTree_firstChild);
3980
3981 return newTreeNode.data;
3982};
3983
3984func void MEM_DeleteVob(var int vobPtr) {
3985 var int world; world = MEM_Game._zCSession_world;
3986
3987 const int call = 0;
3988 if (CALL_Begin(call)) {
3989 /* oCWorld.RemoveVob */
3990 CALL_IntParam(_@(vobPtr));
3991 CALL__thiscall(_@(world), MEMINT_SwitchG1G2(7171824, 7864512));
3992
3993 call = CALL_End();
3994 };
3995};
3996
3997//************************************************
3998// Hashing
3999//************************************************
4000
4001//--------------------------------------
4002// Evaluate hash function
4003//--------------------------------------
4004
4005func int MEM_GetBufferCRC32 (var int buf, var int buflen)
4006{
4007 const int GetBufferCRC32_G1 = 6088464; //0x5CE710
4008 const int GetBufferCRC32_G2 = 6265360; //0x5F9A10
4009
4010 var int null;
4011
4012 const int call = 0;
4013 if (CALL_Begin(call)) {
4014 CALL_IntParam(_@(null));
4015 CALL_IntParam(_@(buflen));
4016 CALL_PtrParam(_@(buf));
4017
4018 CALL_PutRetValTo(_@(ret));
4019 CALL__cdecl(MEMINT_SwitchG1G2(GetBufferCRC32_G1, GetBufferCRC32_G2));
4020
4021 call = CALL_End();
4022 };
4023
4024 var int ret;
4025 return +ret;
4026};
4027
4028func int MEM_GetStringHash (var string str) {
4029 return MEM_GetBufferCRC32 (STR_toChar(str), STR_Len (str));
4030};
4031
4032func int MEMINT_GetWorldHashBucket (var int hash) {
4033 var int bucketPtr;
4034 bucketPtr = _@(MEM_World);
4035 bucketPtr += zCWorld_VobHashTable_Offset + /* sizeof (zCArray) */ 12 * hash;
4036 return bucketPtr;
4037};
4038
4039//--------------------------------------
4040// Find Vob in hash function
4041//--------------------------------------
4042
4043func int MEM_SearchVobByName (var string str) {
4044 const int oCWorld__SearchVobByName_G1 = 7173120; //0x6D7400
4045 const int oCWorld__SearchVobByName_G2 = 7865872; //0x780610
4046
4047 var int ptr; ptr = _@s(str);
4048 var int world; world = _@(MEM_World);
4049
4050 const int call = 0;
4051 if (CALL_Begin(call)) {
4052 CALL_PtrParam(_@(ptr));
4053
4054 CALL_PutRetValTo(_@(ret));
4055 CALL__thiscall(_@(world),
4056 MEMINT_SwitchG1G2(oCWorld__SearchVobByName_G1, oCWorld__SearchVobByName_G2));
4057
4058 call = CALL_End();
4059 };
4060
4061 var int ret;
4062 return +ret;
4063};
4064
4065func int MEM_SearchAllVobsByName (var string str) {
4066 const int oCWorld__SearchVobListByName_G1 = 7173296; //0x6D74B0
4067 const int oCWorld__SearchVobListByName_G2 = 7866048; //0x7806C0
4068
4069 var int arr; arr = MEM_ArrayCreate();
4070 var int ptr; ptr = _@s(str);
4071 var int world; world = _@(MEM_World);
4072
4073 const int call = 0;
4074 if (CALL_Begin(call)) {
4075 CALL_PtrParam(_@(arr));
4076 CALL_PtrParam(_@(ptr));
4077
4078 CALL_PutRetValTo(0);
4079 CALL__thiscall(_@(world),
4080 MEMINT_SwitchG1G2(oCWorld__SearchVobListByName_G1, oCWorld__SearchVobListByName_G2));
4081
4082 call = CALL_End();
4083 };
4084
4085 MEM_ArraySort(arr);
4086 MEM_ArrayUnique(arr);
4087 return +arr;
4088};
4089
4090//--------------------------------------
4091// Vob umbenennen
4092//--------------------------------------
4093
4094func void MEM_RenameVob (var int vobPtr, var string newName) {
4095 const int zCVob_SetVobName_G1 = 6113648; //0x5D4970
4096 const int zCVob_SetVobName_G2 = 6290896; //0x5FFDD0
4097
4098 var int ptr; ptr = _@s(newName);
4099
4100 const int call = 0;
4101 if (CALL_Begin(call)) {
4102 CALL_PtrParam(_@(ptr));
4103 CALL_PutRetValTo(0);
4104 CALL__thiscall(_@(vobPtr),
4105 MEMINT_SwitchG1G2(zCVob_SetVobName_G1, zCVob_SetVobName_G2));
4106
4107 call = CALL_End();
4108 };
4109};
4110
4111//************************************************
4112// Trigger / Untrigger
4113//************************************************
4114
4115func int MEMINT_VobGetEM(var int vobPtr) {
4116 const int zCVob__GetEM_G1 = 6113712; //5D49B0
4117 const int zCVob__GetEM_G2 = 6290960; //5FFE10
4118
4119 const int null = 0;
4120 const int call = 0;
4121 if (CALL_Begin(call)) {
4122 CALL_PutRetValTo(_@(ret));
4123 CALL__fastcall(_@(vobPtr),
4124 _@(null),
4125 MEMINT_SwitchG1G2(zCVob__GetEM_G1, zCVob__GetEM_G2));
4126
4127 call = CALL_End();
4128 };
4129
4130 var int ret;
4131 return +ret;
4132};
4133
4134func void MEM_TriggerVob (var int vobPtr) {
4135 if (!vobPtr) {
4136 MEM_Error ("MEM_TriggerVob: VobPtr may not be null!");
4137 return;
4138 };
4139
4140 const int zCEventManager_OnTrigger_G1 = 7202656; //0x6DE760
4141 const int zCEventManager_OnTrigger_G2 = 7895536; //0x7879F0
4142
4143 var zCVob vob; vob = _^(vobPtr);
4144 var int eventMan; eventMan = MEMINT_VobGetEM(vobPtr);
4145
4146 const int call = 0;
4147 if (CALL_Begin(call)) {
4148 CALL_PtrParam(_@(vobPtr));
4149 CALL_PtrParam(_@(vobPtr));
4150 CALL_PutRetValTo(0);
4151 CALL__thiscall(_@(eventMan),
4152 MEMINT_SwitchG1G2(zCEventManager_OnTrigger_G1, zCEventManager_OnTrigger_G2));
4153
4154 call = CALL_End();
4155 };
4156};
4157
4158func void MEM_UntriggerVob (var int vobPtr) {
4159 if (!vobPtr) {
4160 MEM_Error ("MEM_UntriggerVob: VobPtr may not be null!");
4161 return;
4162 };
4163
4164 const int zCEventManager_OnUnTrigger_G1 = 7202848; //6DE820
4165 const int zCEventManager_OnUnTrigger_G2 = 7895728; //787AB0
4166
4167 var zCVob vob; vob = _^(vobPtr);
4168 var int eventMan; eventMan = MEMINT_VobGetEM(vobPtr);
4169
4170 const int call = 0;
4171 if (CALL_Begin(call)) {
4172 CALL_PtrParam(_@(vobPtr));
4173 CALL_PtrParam(_@(vobPtr));
4174 CALL_PutRetValTo(0);
4175 CALL__thiscall(_@(eventMan),
4176 MEMINT_SwitchG1G2(zCEventManager_OnUnTrigger_G1, zCEventManager_OnUnTrigger_G2));
4177
4178 call = CALL_End();
4179 };
4180};
4181
4182//######################################################
4183//
4184// Keyboard interaction
4185//
4186//######################################################
4187
4188//Rückgabewerte
4189const int KEY_UP = 0;
4190const int KEY_PRESSED = 1;
4191const int KEY_HOLD = 2;
4192const int KEY_RELEASED = 3;
4193
4194//--------------------------------------
4195// Grundlage: Ist die Taste gedrückt?
4196//--------------------------------------
4197
4198//etwas ungeschickt, dass die Methode, die auf KEY_HOLD prüft KeyPressed heißt... :-(
4199//aber jetzt ist es so und ich wills nicht ändern.
4200
4201func int MEM_KeyPressed(var int key) {
4202 return MEM_ReadInt (MEMINT_KeyEvent_Offset + key) & 255;
4203};
4204
4205//--------------------------------------
4206// Darauf aufbauend: Erkennung
4207// wann das erste mal gedrückt
4208// und wann gehalten
4209//--------------------------------------
4210
4211//Hier merke ich mir die Zustände seit der letzten Abfrage:
4212var int MEMINT_KeyState[1024]; //lieber mal etwas mehr, gibt noch JoystickButtons usw.
4213
4214func int MEM_KeyState(var int key) {
4215 var int pressed;
4216 pressed = MEM_KeyPressed (key);
4217
4218 //Adresse als Int runterholen:
4219 var int adr; adr = _@(MEMINT_KeyState);
4220 adr += 4 * key;
4221
4222 //State holen:
4223 var int keyState; keyState = MEM_ReadInt(adr);
4224
4225 //State bearbeiten:
4226 if (keyState == KEY_UP) {
4227 if (pressed) {
4228 keyState = KEY_PRESSED;
4229 };
4230 } else if (keyState == KEY_PRESSED) {
4231 if (pressed) {
4232 keyState = KEY_HOLD;
4233 } else {
4234 keyState = KEY_RELEASED;
4235 };
4236 } else if (keyState == KEY_HOLD) {
4237 if (!pressed) {
4238 keyState = KEY_RELEASED;
4239 };
4240 } else /* keyState == KEY_RELEASED */ {
4241 if (pressed) {
4242 keyState = KEY_PRESSED;
4243 } else {
4244 keyState = KEY_UP;
4245 };
4246 };
4247
4248 //Neuen State merken
4249 MEM_WriteInt (adr, keyState);
4250 return keyState; //zurückgeben.
4251};
4252
4253//--------------------------------------
4254// Key-Event einfügen
4255//--------------------------------------
4256
4257/* Problematisch, vielleicht gibt es irgendwann eine bessere Lösung.
4258 * Aber einiges kann man damit schon machen.
4259 * Beispiel:
4260 * -Inventar öffnen.
4261 * -Quicksave
4262 * -Charaktermenü öffnen
4263 * -Pause togglen (Marvin Modus)
4264 * -Log-Öffnen
4265 * -Hauptmenü öffnen (ESC)
4266 * ...
4267 *
4268 * An anderen Stellen will die Engine aber, dass der Key "getoggled"
4269 * wurde, das wird anderweitig verwaltet und ist hiervon nicht betroffen.
4270 * Daher kann man zum Beispiel das Inventar mit Hilfe dieser Funktion
4271 * nicht wieder schließen. */
4272
4273func void MEM_InsertKeyEvent(var int key) {
4274 MEM_ArrayInsert (MEMINT_KeyBuffer_offset, key);
4275};
4276
4277//#################################################################
4278//
4279// zCOptions Access:
4280//
4281//#################################################################
4282
4283var zCOption MEMINT_OPT_Set;
4284var zCOptionSection MEMINT_OPT_Section;
4285var zCOptionEntry MEMINT_OPT_Entry;
4286
4287//************************************************
4288// reading
4289//************************************************
4290
4291//--------------------------------------
4292// read in zCOptions
4293//--------------------------------------
4294
4295/* Search the current section for an entry */
4296func int MEMINT_OPT_FindEntry(var string optname) {
4297 //Anzahl Einträge == 0 ausschließen (weil nur do-while schleife möglich, keine while-do).
4298 if (!MEMINT_OPT_Section.entryList_numInArray) {
4299 return FALSE;
4300 };
4301
4302 var int i; i = 0;
4303 var int loopStart; loopStart = MEM_StackPos.position;
4304 /* while */ if (i < MEMINT_OPT_Section.entryList_numInArray) {
4305 var int ptr; ptr = MEM_ReadIntArray (MEMINT_OPT_Section.entryList_array, i);
4306 MEMINT_OPT_Entry = _^(ptr);
4307
4308 if (Hlp_StrCmp (MEMINT_OPT_Entry.varName, optname)) {
4309 return TRUE;
4310 };
4311
4312 i += 1;
4313
4314 MEM_StackPos.position = loopStart;
4315 }; /* end while */
4316
4317 return FALSE; //nichts gefunden.
4318};
4319
4320/* Search the current option set for a section */
4321func int MEMINT_OPT_FindSection (var string sectname) {
4322 //Anzahl Sektionen == 0 ausschließen (weil nur do-while schleife möglich, keine while-do).
4323 if (!MEMINT_OPT_Set.sectionList_numInArray) {
4324 return FALSE;
4325 };
4326
4327 var int i; i = 0;
4328 var int loopStart; loopStart = MEM_StackPos.position;
4329
4330 /* while */ if (i < MEMINT_OPT_Set.sectionList_numInArray) {
4331 var int ptr; ptr = MEM_ReadIntArray (MEMINT_OPT_Set.sectionList_array, i);
4332 MEMINT_OPT_Section = _^(ptr);
4333
4334 if (Hlp_StrCmp (MEMINT_OPT_Section.secName, sectname)) {
4335 return TRUE;
4336 };
4337
4338 i += 1;
4339
4340 MEM_StackPos.position = loopStart;
4341 }; /* end while */
4342
4343 return FALSE; //nichts gefunden.
4344};
4345
4346//--------------------------------------
4347// Search the Gothic.ini
4348//--------------------------------------
4349
4350func string MEM_GetGothOpt (var string sectionname, var string optionname) {
4351 MEMINT_OPT_Set = _^(MEM_ReadInt (zoptions_Pointer_Address));
4352
4353 if (!MEMINT_OPT_FindSection (sectionname)) {
4354 return "";
4355 };
4356
4357 if (!MEMINT_OPT_FindEntry (optionname)) {
4358 return "";
4359 };
4360
4361 return MEMINT_OPT_Entry.varValue;
4362};
4363
4364func int MEM_GothOptSectionExists (var string sectionname) {
4365 MEMINT_OPT_Set = _^(MEM_ReadInt (zoptions_Pointer_Address));
4366 return MEMINT_OPT_FindSection (sectionname);
4367};
4368
4369func int MEM_GothOptExists (var string sectionname, var string optionname) {
4370 if (!MEM_GothOptSectionExists (sectionname)) {
4371 return false;
4372 };
4373
4374 return MEMINT_OPT_FindEntry (optionname);
4375};
4376
4377//--------------------------------------
4378// Search the Mod.ini
4379//--------------------------------------
4380
4381func string MEM_GetModOpt (var string sectionname, var string optionname) {
4382 MEMINT_OPT_Set = _^(MEM_ReadInt (zgameoptions_Pointer_Address));
4383
4384 if (!MEMINT_OPT_FindSection (sectionname)) {
4385 return "";
4386 };
4387
4388 if (!MEMINT_OPT_FindEntry (optionname)) {
4389 return "";
4390 };
4391
4392 return MEMINT_OPT_Entry.varValue;
4393};
4394
4395func int MEM_ModOptSectionExists (var string sectionname) {
4396 MEMINT_OPT_Set = _^(MEM_ReadInt (zgameoptions_Pointer_Address));
4397 return MEMINT_OPT_FindSection (sectionname);
4398};
4399
4400func int MEM_ModOptExists (var string sectionname, var string optionname) {
4401 if (!MEM_ModOptSectionExists (sectionname)) {
4402 return false;
4403 };
4404
4405 return MEMINT_OPT_FindEntry (optionname);
4406};
4407
4408//--------------------------------------
4409// Get the command line
4410//--------------------------------------
4411
4412func string MEM_GetCommandLine () {
4413 MEMINT_OPT_Set = _^(MEM_ReadInt (zoptions_Pointer_Address));
4414 return MEMINT_OPT_Set.commandline;
4415};
4416
4417//#####################################################
4418// writing
4419//#####################################################
4420
4421/* Mod configuration is never saved to disk, therefore
4422 * there are no seperate functions for writing in it */
4423
4424func void MEM_SetGothOpt (var string section, var string option, var string value) {
4425 var int optSetPtr; optSetPtr = MEM_ReadInt (zoptions_Pointer_Address);
4426 MEMINT_OPT_Set = _^(optSetPtr);
4427
4428 if (!MEMINT_OPT_FindSection (section)) {
4429 MEM_Info (ConcatStrings ("MEM_SetGothOpt: Creating new Section: ", section));
4430 var int newSect_ptr;
4431 newSect_ptr = MEM_Alloc (sizeof_zCOptionSection);
4432 MEMINT_OPT_Section = _^(newSect_ptr);
4433 MEMINT_OPT_Section.secName = section;
4434
4435 MEM_ArrayInsert (optSetPtr + 8, newSect_ptr);
4436 };
4437
4438 if (!MEMINT_OPT_FindEntry (option)) {
4439 MEM_Info (ConcatStrings ("MEM_SetGothOpt: Creating new entry: ", option));
4440 var int newEntry_ptr;
4441 newEntry_ptr = MEM_Alloc (sizeof_zCOptionEntry);
4442 MEMINT_OPT_Entry = _^(newEntry_ptr);
4443 MEMINT_OPT_Entry.varName = option;
4444
4445 var int sectPtr;
4446 sectPtr = MEM_InstGetOffset (MEMINT_OPT_Section);
4447
4448 MEM_ArrayInsert (sectPtr + 20, newEntry_ptr);
4449 };
4450
4451 MEMINT_OPT_Entry.varValue = value;
4452 MEMINT_OPT_Entry.varValueTemp = value; /* dont forget temp value */
4453};
4454
4455//--------------------------------------
4456// Apply some changes
4457// and write ini to disk
4458//--------------------------------------
4459
4460func void MEM_ApplyGothOpt() {
4461 const int call = 0;
4462 if (CALL_Begin(call)) {
4463 /* CGameManager.ApplySomeSettings */
4464 CALL__thiscall(MEMINT_gameMan_Pointer_address, MEMINT_SwitchG1G2(4351936, 4355760));
4465 call = CALL_End();
4466 };
4467};
4468
4469//--------------------------------------
4470// Get a key
4471//--------------------------------------
4472
4473func int MEMINT_HexCharToInt(var int c) {
4474 const int ASCII_a = 97;
4475 const int ASCII_0 = 48;
4476 if (c >= ASCII_0 && c < ASCII_0 + 10) {
4477 return c - ASCII_0;
4478 } else if (c >= ASCII_a && c < ASCII_a + 6) {
4479 return 10 + c - ASCII_a;
4480 } else {
4481 MEM_Error(ConcatStrings("Invalid Hex Char: ", IntToString(c)));
4482 return 0;
4483 };
4484};
4485
4486func int MEMINT_KeyStringToKey(var string hex) {
4487 var zString str; str = _^(_@s(hex));
4488 var int res; res = 0;
4489
4490 res += MEMINT_HexCharToInt(MEM_ReadByte(str.ptr + 0)) << 4;
4491 res += MEMINT_HexCharToInt(MEM_ReadByte(str.ptr + 1)) << 0;
4492 res += MEMINT_HexCharToInt(MEM_ReadByte(str.ptr + 2)) << 12;
4493 res += MEMINT_HexCharToInt(MEM_ReadByte(str.ptr + 3)) << 8;
4494
4495 return res;
4496};
4497
4498func int MEM_GetKey(var string name) {
4499 var string raw;
4500 raw = MEM_GetGothOpt("KEYS", name);
4501
4502 if (STR_Len(raw) < 4) {
4503 MEM_Warn(ConcatStrings("Could not find key with name: ", name));
4504 return 0;
4505 };
4506
4507 return MEMINT_KeyStringToKey(raw);
4508};
4509
4510func int MEM_GetSecondaryKey(var string name) {
4511 var string raw;
4512 raw = MEM_GetGothOpt("KEYS", name);
4513
4514 /* Nur wenn auch zwei angegeben: */
4515 if (STR_Len(raw) < 8) {
4516 return 0; //no secondary key
4517 };
4518
4519 raw = STR_SubStr(raw, 4, 4);
4520
4521 return MEMINT_KeyStringToKey(raw);
4522};
4523
4524func string MEMINT_ByteToKeyHex(var int byte) {
4525 const int ASCII_0 = 48;
4526 byte = byte & 255;
4527
4528 const int mem = 0;
4529 if (!mem) { mem = MEM_Alloc(3); };
4530
4531 MEM_WriteByte(mem , (byte >> 4) + ASCII_0);
4532 MEM_WriteByte(mem + 1, (byte & 15) + ASCII_0);
4533 return STR_FromChar(mem);
4534};
4535
4536func void MEM_SetKeys(var string name, var int primary, var int secondary) {
4537 var string str; str = "";
4538 str = ConcatStrings(str, MEMINT_ByteToKeyHex( primary ));
4539 str = ConcatStrings(str, MEMINT_ByteToKeyHex((primary >> 8)));
4540 str = ConcatStrings(str, MEMINT_ByteToKeyHex( secondary ));
4541 str = ConcatStrings(str, MEMINT_ByteToKeyHex((secondary >> 8)));
4542
4543 MEM_SetGothOpt("KEYS", name, str);
4544
4545 /* Rebind the keys */
4546 const int call = 0;
4547 if (CALL_Begin(call)) {
4548 var int zInputPtr; zInputPtr = MEMINT_SwitchG1G2(8834208, 9246288);
4549 var int zCInput__BindKeys; zCInput__BindKeys = MEMINT_SwitchG1G2(5003568, 5045760);
4550
4551 var int null;
4552 CALL_IntParam(_@(null));
4553 CALL__thiscall(zInputPtr, zCInput__BindKeys);
4554 call = CALL_End();
4555 };
4556};
4557
4558func void MEM_SetKey(var string name, var int key) {
4559 MEM_SetKeys(name, key, MEM_GetSecondaryKey(name));
4560};
4561
4562func void MEM_SetSecondaryKey(var string name, var int key) {
4563 MEM_SetKeys(name, MEM_GetKey(name), key);
4564};
4565
4566//#################################################
4567//
4568// Zeitmessung / Benchmark / Speedup
4569//
4570//#################################################
4571
4572//************************************************
4573// Time Measurement
4574//************************************************
4575
4576func int MEM_GetSystemTime() {
4577 const int sysGetTimePtr_G1 = 5204320; //0x4F6960;
4578 const int sysGetTimePtr_G2 = 5264000; //0x505280;
4579
4580 const int call = 0;
4581 if (CALL_Begin(call)) {
4582 CALL_PutRetValTo(_@(ret));
4583 CALL__cdecl(MEMINT_SwitchG1G2(sysGetTimePtr_G1, sysGetTimePtr_G2));
4584 call = CALL_End();
4585 };
4586
4587 var int ret;
4588 return +ret;
4589};
4590
4591func int MEM_GetPerformanceCounter() {
4592 var int buf[2];
4593 var int space; space = _@(buf);
4594
4595 const int QueryPerformanceCounter_G1 = 7712432; //0x75AEB0
4596 const int QueryPerformanceCounter_G2 = 8079382; //0x7B4816
4597
4598 const int call = 0;
4599 if (CALL_Begin(call)) {
4600 CALL_IntParam(_@(space));
4601
4602 CALL_PutRetValTo(0);
4603 CALL__stdcall(MEMINT_SwitchG1G2(QueryPerformanceCounter_G1, QueryPerformanceCounter_G2));
4604 call = CALL_End();
4605 };
4606
4607 return buf[0];
4608};
4609
4610//************************************************
4611// Benchmark
4612//************************************************
4613
4614func void MEMINT_Benchmark_Helper() {
4615 MEMINT_Benchmark_Helper();
4616};
4617
4618 const int MEMINT_Benchmark_MS = 0;
4619 const int MEMINT_Benchmark_PC = 1;
4620 const int MEMINT_Benchmark_MMS = 2;
4621
4622func int MEMINT_Benchmark(var func f, var int times, var int unit) {
4623 MEM_WriteInt(MEM_GetFuncPtr(MEMINT_Benchmark_Helper) + 1, //the helper function should call...
4624 MEM_GetFuncOffset(f)); //... f
4625
4626 var int i; i = 0;
4627 var int startTime;
4628
4629 if (unit == MEMINT_Benchmark_MS) {
4630 startTime = MEM_GetSystemTime();
4631 } else {
4632 startTime = MEM_GetPerformanceCounter();
4633 };
4634
4635 var int loop; loop = MEM_StackPos.position;
4636 if (i < times) {
4637 MEMINT_Benchmark_Helper();
4638 i += 1;
4639 MEM_StackPos.position = loop;
4640 };
4641
4642 if (unit == MEMINT_Benchmark_MS) {
4643 return MEM_GetSystemTime() - startTime;
4644 } else {
4645 var int pc; pc = MEM_GetPerformanceCounter() - startTime;
4646
4647 if (unit == MEMINT_Benchmark_PC) {
4648 return pc;
4649 } else {
4650 if (pc > 2147483) {
4651 /* cannot multiply by 1000, but the number is large enough
4652 * I do not lose a lot if I divide first. */
4653 return (pc / MEM_ReadInt(PC_TicksPerMS_Address)) * 1000;
4654 } else {
4655 return (pc * 1000) / MEM_ReadInt(PC_TicksPerMS_Address);
4656 };
4657 };
4658 };
4659};
4660
4661func int MEM_BenchmarkMS(var func f) {
4662 return MEMINT_Benchmark(f, 1, MEMINT_Benchmark_MS);
4663};
4664
4665func int MEM_BenchmarkMS_N(var func f, var int n) {
4666 return MEMINT_Benchmark(f, n, MEMINT_Benchmark_MS);
4667};
4668
4669func int MEM_BenchmarkMMS(var func f) {
4670 return MEMINT_Benchmark(f, 1, MEMINT_Benchmark_MMS);
4671};
4672
4673func int MEM_BenchmarkMMS_N(var func f, var int n) {
4674 return MEMINT_Benchmark(f, n, MEMINT_Benchmark_MMS);
4675};
4676
4677func int MEM_BenchmarkPC(var func f) {
4678 return MEMINT_Benchmark(f, 1, MEMINT_Benchmark_PC);
4679};
4680
4681func int MEM_BenchmarkPC_N(var func f, var int n) {
4682 return MEMINT_Benchmark(f, n, MEMINT_Benchmark_PC);
4683};
4684
4685//#################################################
4686//
4687// Logging and Debug
4688//
4689//#################################################
4690
4691//************************************************
4692// SendToSpy
4693//************************************************
4694
4695func void MEMINT_SendToSpy_Implementation(var int errorType, var string text) {
4696 text = ConcatStrings("Q: ", text); //! = Ikarus
4697
4698 const int zerr_G1 = 8821208; //0x8699D8
4699 const int zerr_G2 = 9231568; //0x8CDCD0
4700 var int zerrPtr; zerrPtr = MEMINT_SwitchG1G2(zerr_G1, zerr_G2);
4701
4702 var zERROR zerr; zerr = _^(zerrPtr);
4703 var int old_ack_type; old_ack_type = zerr.ack_type;
4704 if (MEMINT_ForceErrorBox) {
4705 if (GOTHIC_BASE_VERSION == 1) {
4706 /* There is a warning "lost focus",
4707 * that will be printed constantly, unless
4708 * I reduce its priority here */
4709 MEM_WriteByte(5199298, 1);
4710 };
4711
4712 zerr.ack_type = zERR_TYPE_WARN;
4713
4714 /* Cannot enable Error Box for Infos, because
4715 * creating in Error Box creates Infos */
4716 if (errorType < zERR_TYPE_WARN) {
4717 errorType = zERR_TYPE_WARN;
4718 };
4719
4720 MEMINT_ForceErrorBox = 0;
4721 } else {
4722 zerr.ack_type = zERR_TYPE_FATAL;
4723 };
4724
4725 const int zERROR_Report_G1 = 4489808; //0x448250
4726 const int zERROR_Report_G2 = 4507856; //0x44C8D0
4727
4728 var int null;
4729
4730 var int ptr; ptr = _@s(text);
4731
4732 const int call = 0;
4733 if (CALL_Begin(call)) {
4734 CALL_PtrParam(_@(null)); //char * function
4735 CALL_PtrParam(_@(null)); //char * file
4736 CALL_IntParam(_@(null)); //int line
4737 CALL_IntParam(_@(null)); //uint flags
4738 CALL_IntParam(_@(null)); //uint level (useless?)
4739 CALL_PtrParam(_@(ptr)); //zString * message
4740 CALL_PtrParam(_@(null)); //int errorID (useless)
4741 CALL_PtrParam(_@(errorType)); //zERROR_TYPE errorType
4742
4743 CALL_PutRetValTo(0);
4744 CALL__thiscall(_@(zerrPtr),
4745 MEMINT_SwitchG1G2(zERROR_Report_G1, zERROR_Report_G2));
4746
4747 call = CALL_End();
4748 };
4749
4750 zerr.ack_type = old_ack_type;
4751};
4752
4753//************************************************
4754// Print Stacktrace
4755//************************************************
4756
4757//--------------------------------------
4758// Print one line of a stack trace
4759//--------------------------------------
4760
4761//Pretty Print
4762func void MEMINT_PrintStackTraceLine(var int popPos) {
4763 var int valid;
4764
4765 if (popPos < 0 || popPos >= MEM_Parser.stack_stacksize) {
4766 valid = false;
4767 } else {
4768 valid = true;
4769 var int funcID; var zCPar_Symbol symb;
4770 funcID = MEM_GetFuncIDByOffset(popPos);
4771 symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, funcID));
4772 };
4773
4774 const string spaces = " ";
4775 var string prt; prt = STR_Prefix(spaces, 8);
4776
4777 if (valid) {
4778 prt = ConcatStrings(prt, symb.name);
4779
4780 /* include parameters */
4781 prt = ConcatStrings(prt, "(");
4782
4783 var int loop;
4784 var int i; i = 1;
4785 loop = MEM_StackPos.position;
4786
4787 if (i <= (symb.bitfield & zCPar_Symbol_bitfield_ele)) {
4788 var zCPar_Symbol param;
4789 param = _^(MEM_ReadIntArray (currSymbolTableAddress, funcID + i));
4790
4791 if (i > 1) {
4792 prt = ConcatStrings(prt, ", ");
4793 };
4794
4795 if ((param.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INT) {
4796 prt = ConcatStrings(prt, IntToString(param.content));
4797 } else if ((param.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_STRING) {
4798 prt = ConcatStrings(prt, "'");
4799 prt = ConcatStrings(prt, MEM_ReadString(param.content));
4800 prt = ConcatStrings(prt, "'");
4801 } else if ((param.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_FUNC) {
4802 var zCPar_Symbol funcParm;
4803 funcParm = _^(MEM_ReadIntArray (currSymbolTableAddress, param.content));
4804 prt = ConcatStrings(prt, funcParm.name);
4805 /* too lazy to follow the chain back in case there is one */
4806 } else if ((param.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INSTANCE) {
4807 prt = ConcatStrings(prt, "(instance)");
4808 prt = ConcatStrings(prt, IntToString(param.offset));
4809 } else {
4810 prt = ConcatStrings(prt, "[Parameter of Unknown type]");
4811 };
4812
4813 i += 1;
4814 MEM_StackPos.position = loop;
4815 };
4816 prt = ConcatStrings(prt, ")");
4817 } else {
4818 prt = ConcatStrings(prt, "[UNKNOWN]");
4819 };
4820
4821 if (STR_Len(prt) < 70) {
4822 prt = ConcatStrings(prt, STR_Prefix(spaces, 70 - STR_Len(prt)));
4823 };
4824 prt = ConcatStrings(prt, " +");
4825
4826 var string bytes;
4827 if (valid) {
4828 bytes = IntToString(popPos - symb.content);
4829 } else {
4830 bytes = IntToString(popPos);
4831 };
4832
4833 if (STR_Len(bytes) < 5) {
4834 bytes = ConcatStrings(STR_Prefix(spaces, 5 - STR_Len(bytes)), bytes);
4835 };
4836 bytes = ConcatStrings(bytes, " bytes");
4837
4838 prt = ConcatStrings(prt, bytes);
4839
4840 MEM_SendToSpy(zERR_TYPE_FAULT, prt);
4841};
4842
4843//--------------------------------------
4844// Print Stack Trace when
4845// called from a daedalus function
4846//--------------------------------------
4847
4848func void MEMINT_PrintStackTrace_Implementation() {
4849 MEM_SendToSpy(zERR_TYPE_FAULT, "[start of stacktrace]");
4850
4851 var int ESP;
4852 ESP = MEMINT_FindFrameBoundary(MEMINT_GetESP(), -1);
4853 /* the first thing that looks like a frame boundary
4854 * for MEMINT_FindFrameBoundary WILL NOT look like that
4855 * from here, because I am further down in the stack: */
4856 ESP += MEMINT_DoStackFrameSize;
4857
4858 /* sehr ungünstig: Im Stackframe der Funktion steht gar nicht die
4859 * aktuelle PopPos, die steht nur im Stackframe desjenigen obendrüber
4860 * wo der sie eben grade pushen wollte: */
4861 var int passedMySelf; passedMySelf = 0;
4862 var int mySelf; mySelf = MEM_GetFuncID(MEMINT_PrintStackTrace_Implementation);
4863
4864 var int loop; loop = MEM_StackPos.position;
4865
4866 /* while */
4867 /* I am at the start of a DoStack Frame,
4868 * get the function that is called here: */
4869 var int popPos;
4870 popPos = MEM_ReadInt(ESP-MEMINT_DoStackPopPosOffset);
4871
4872 if (passedMySelf) {
4873 MEMINT_PrintStackTraceLine(popPos);
4874 } else if (popPos < MEM_Parser.stack_stacksize) {
4875 var int funcID;
4876 funcID = MEM_GetFuncIDByOffset(popPos);
4877 passedMySelf = (funcID == mySelf);
4878 };
4879
4880 /* Is there another DoStack directly und me? */
4881 if (MEMINT_IsFrameBoundary(ESP)) {
4882 /* go on searching! */
4883 ESP += MEMINT_DoStackFrameSize;
4884 MEM_StackPos.position = loop;
4885 };
4886 /* end while */
4887
4888 MEM_SendToSpy(zERR_TYPE_FAULT, "[end of stacktrace]");
4889};
4890
4891//--------------------------------------
4892// Print Stack Trace when the SEH
4893// of DoStack is called.
4894//--------------------------------------
4895
4896var int MEMINT_ExceptionHandlerESP; /* where start looking for stacktrace? */
4897var int MEMINT_TopPopPos; /* the PopPos of the (probably crashed) DoStack Instance. */
4898
4899func void MEMINT_ExceptionHandler() {
4900 const int invoked_once = 0;
4901
4902 if (!invoked_once) {
4903 invoked_once = true;
4904
4905 MEM_SendToSpy(zERR_TYPE_FAULT, "[start of stacktrace]");
4906
4907 MEMINT_PrintStackTraceLine(MEMINT_TopPopPos - MEM_Parser.stack_stack);
4908
4909 var int ESP; ESP = MEMINT_FindFrameBoundary(MEMINT_ExceptionHandlerESP, 500);
4910
4911 /* There may not be a frame boundary if there is a crash in the bottommost function */
4912 if (ESP) {
4913 /* note: the first has to be handled differently and was handled above */
4914 ESP += MEMINT_DoStackFrameSize;
4915
4916 var int loop; loop = MEM_StackPos.position;
4917
4918 MEMINT_PrintStackTraceLine(MEM_ReadInt(ESP - MEMINT_DoStackPopPosOffset));
4919
4920 if (MEMINT_IsFrameBoundary(ESP)) {
4921 ESP += MEMINT_DoStackFrameSize;
4922 MEM_StackPos.position = loop;
4923 };
4924 };
4925
4926 MEM_SendToSpy(zERR_TYPE_FAULT, "[end of stacktrace]");
4927 MEM_ErrorBox("Exception handler was invoked. Ikarus tried to print a Daedalus-Stacktrace to zSpy. Gothic will now crash and probably give you a stacktrace of its own.");
4928 };
4929};
4930
4931/* Try to catch exceptions: */
4932func void MEMINT_SetupExceptionHandler() {
4933 const int call = 0;
4934
4935 if (!call) {
4936 CALL_Open();
4937 var int handlerOffset;
4938 handlerOffset = MEM_GetFuncOffset(MEMINT_ExceptionHandler);
4939
4940 ASM_1(ASMINT_OP_movMemToEAX);
4941 ASM_4(_@(MEM_Parser.stack_stackptr));
4942 ASM_2(ASMINT_OP_movEAXToMem);
4943 ASM_4(_@(MEMINT_TopPopPos));
4944 ASM_2(ASMINT_OP_movESPtoEAX);
4945 ASM_2(ASMINT_OP_movEAXToMem);
4946 ASM_4(_@(MEMINT_ExceptionHandlerESP));
4947
4948 CALL_IntParam(_@(handlerOffset));
4949
4950 const int zCParser__DoStack_G1 = 7243264; //0x6E8600
4951 const int zCParser__DoStack_G2 = 7936352; //0x791960
4952
4953 CALL_PutRetValTo(0);
4954 CALL__thiscall(_@(contentParserAddress),
4955 MEMINT_SwitchG1G2(zCParser__DoStack_G1, zCParser__DoStack_G2));
4956
4957 /* now jump to the original handler (whatever that one is doing) */
4958 const int zCParser__DoStack_SEH_G1 = 8146176; //0x7C4D00
4959 const int zCParser__DoStack_SEH_G2 = 8562816; //0x82A880
4960
4961 var int SEH; SEH = MEMINT_SwitchG1G2(zCParser__DoStack_SEH_G1, zCParser__DoStack_SEH_G2);
4962
4963 ASM_1(ASMINT_OP_jmp);
4964 ASM_4(SEH - (ASM_Here() + 4));
4965
4966 call = CALL_Close();
4967
4968 /* install the exception handler: */
4969 const int zCParser__DoStack_SEH_Pusher_G1 = 7243266 + 1; //0x6E8602 + 1
4970 const int zCParser__DoStack_SEH_Pusher_G2 = 7936354 + 1; //0x791962 + 1
4971
4972 var int SEHPusher;
4973 SEHPusher = MEMINT_SwitchG1G2(zCParser__DoStack_SEH_Pusher_G1,
4974 zCParser__DoStack_SEH_Pusher_G2);
4975
4976 MemoryProtectionOverride(SEHPusher, 4);
4977
4978 MEM_WriteInt(SEHPusher, call);
4979 };
4980};
4981
4982//************************************************
4983// Setup Print Functions and SEH
4984//************************************************
4985
4986func void MEMINT_ReplaceLoggingFunctions() {
4987 const int init = 0;
4988 if (!init) {
4989 init = true;
4990
4991 MEM_Info("This will be the last Ikarus message printed with PrintDebug and prefix 'U: Skript:'. Subsequent messages will be printed with prefix 'Q:'.");
4992 MEM_ReplaceFunc(MEM_SendToSpy, MEMINT_SendToSpy_Implementation);
4993 MEM_Info("Ikarus log functions now print in colour with prefix 'Q:'.");
4994
4995 MEM_ReplaceFunc(MEM_PrintStackTrace, MEMINT_PrintStackTrace_Implementation);
4996
4997 MEMINT_SetupExceptionHandler();
4998 };
4999};
5000
5001//#################################################
5002//
5003// Revised functions
5004//
5005// With the more elaborate functions of Ikarus
5006// it is possible to speed up the basis of Ikarus.
5007//
5008// Keep names simular, so they don't confuse people
5009// when they see them on the callstack.
5010//
5011//#################################################
5012
5013//************************************************
5014// Faster Read / Write
5015//************************************************
5016
5017func void MEM_ReadInt_() {
5018 var int i;
5019 i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i;
5020};
5021
5022func void MEM_WriteInt_() {
5023 var int i;
5024 i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i; i = i;
5025};
5026
5027func void MEMINT_InitFasterReadWrite() {
5028 var MEMINT_HelperClass symb;
5029
5030 MEMINT_InitOverideFunc(MEM_ReadInt_);
5031
5032 /* The following is a fast rewrite of MEM_ReadInt */
5033
5034 //1. whatever is on the stack, make an RValue out of it:
5035 MEMINT_OfTok(zPAR_OP_UN_PLUS);
5036 //2. exchange PUSHINST with PUSHVAR
5037 MEMINT_OfTokPar(zPAR_TOK_PUSHINST, symb);
5038 MEMINT_OfTok (zPAR_TOK_ASSIGNINST);
5039 MEMINT_OfTokPar(zPAR_TOK_PUSHINST, zPAR_TOK_PUSHVAR);
5040 //3. Return as RValue:
5041 MEMINT_OfTok (zPAR_OP_UN_PLUS);
5042 MEMINT_OfTok (zPAR_TOK_RET);
5043
5044 MEM_ReplaceFunc(MEM_ReadInt, MEM_ReadInt_);
5045
5046 /* now a faster rewrite of MEM_WriteInt */
5047 var int id; id = MEM_GetFuncID(MEM_WriteInt);
5048
5049 MEMINT_InitOverideFunc(MEM_WriteInt_);
5050
5051 //1. save the second paremter in temporary location:
5052 MEMINT_OfTokPar(zPAR_TOK_PUSHVAR, id + 2 /* [val] */);
5053 MEMINT_OfTok (zPAR_OP_IS);
5054 //2. save the first parameter in temporary location:
5055 MEMINT_OfTokPar(zPAR_TOK_PUSHVAR, id + 1 /* [adr] */);
5056 MEMINT_OfTok (zPAR_OP_IS);
5057
5058 //3. Push them in reverse order:
5059 MEMINT_OfTokPar(zPAR_TOK_PUSHVAR, id + 2 /* [val] */);
5060 MEMINT_OfTokPar(zPAR_TOK_PUSHVAR, id + 1 /* [adr] */);
5061
5062 //4. make an RValue out of the address:
5063 MEMINT_OfTok (zPAR_OP_UN_PLUS);
5064 //5. exchange PUSHINST with PUSHVAR
5065 MEMINT_OfTokPar(zPAR_TOK_PUSHINST, symb);
5066 MEMINT_OfTok (zPAR_TOK_ASSIGNINST);
5067 MEMINT_OfTokPar(zPAR_TOK_PUSHINST, zPAR_TOK_PUSHVAR);
5068 //6. Assign and return:
5069 MEMINT_OfTok (zPAR_OP_IS);
5070 MEMINT_OfTok (zPAR_TOK_RET);
5071
5072 /* Vorsicht, MEM_ReplaceFunc(MEM_WriteInt, MEM_WriteInt_);
5073 * kann so nicht funktionieren, schließlich wird MEM_WriteInt dazu gebraucht */
5074 var int buf; buf = MEM_Alloc(5);
5075 MEM_WriteByte(buf , zPAR_TOK_JUMP);
5076 MEM_WriteInt (buf + 1, MEM_GetFuncOffset(MEM_WriteInt_));
5077 MEM_CopyBytes(buf, MEM_GetFuncPtr(MEM_WriteInt), 5);
5078};
5079
5080func void MEMINT_InitFasterPushInst() {
5081 var MEMINT_HelperClass symb;
5082
5083 MEMINT_InitOverideFunc(MEMINT_StackPushInst);
5084
5085 MEMINT_OfTok (zPAR_OP_UN_PLUS);
5086 MEMINT_OfTokPar(zPAR_TOK_PUSHINST, symb);
5087 MEMINT_OfTok (zPAR_TOK_ASSIGNINST);
5088 MEMINT_OfTok (zPAR_TOK_RET);
5089};
5090
5091//************************************************
5092// Faster MEM_Alloc, MEM_Free
5093//************************************************
5094
5095func int MEM_Alloc_(var int ele) {
5096 var int size; size = 1;
5097 const int call = 0;
5098
5099 if (CALL_Begin(call)) {
5100 var int cAlloc_ptr;
5101 cAlloc_ptr = MEMINT_SwitchG1G2(7712240 /*0x75ADF0*/, 8078576 /*0x7B44F0*/);
5102
5103 CALL_IntParam(_@(size));
5104 CALL_IntParam(_@(ele));
5105 CALL_PutRetValTo(_@(ret));
5106 CALL__cdecl(cAlloc_ptr);
5107 call = CALL_End();
5108 };
5109
5110 var int ret;
5111 return +ret;
5112};
5113
5114func void MEM_Free_(var int ptr) {
5115 /* keine Nuller freigeben */
5116 if (!ptr) {
5117 MEM_Warn ("MEM_Free: ptr is 0. Ignoring request.");
5118 return;
5119 };
5120
5121 const int call = 0;
5122
5123 if (CALL_Begin(call)) {
5124 var int free_ptr;
5125 free_ptr = MEMINT_SwitchG1G2(7712111 /*0x75AD6F*/, 8078540 /*0x7B44CC*/);
5126
5127 CALL_IntParam(_@(ptr));
5128
5129 CALL_PutRetValTo(0);
5130 CALL__cdecl(free_ptr);
5131 call = CALL_End();
5132 };
5133};
5134
5135//************************************************
5136// The actual replacement
5137//************************************************
5138
5139func void MEMINT_ReplaceSlowFunctions() {
5140 const int init = 0;
5141 if (!init) {
5142 init = true;
5143
5144 /* the following line is needed to set up the calls with the OLD
5145 * MEM_Alloc function. Call needs MEM_Alloc for setting up
5146 * the call, and since the NEW MEM_Alloc needs CALL
5147 * this would certainly not be a good idea. ;-)
5148 *
5149 * Wow this is confusing... */
5150
5151 MEM_Free_(MEM_Alloc_(1));
5152
5153 MEM_ReplaceFunc(MEM_Alloc, MEM_Alloc_);
5154 MEM_ReplaceFunc(MEM_Free, MEM_Free_);
5155
5156 MEMINT_InitFasterReadWrite();
5157 MEMINT_InitFasterPushInst();
5158
5159 MEM_ReplaceFunc(_^, MEM_PtrToInst); //forwarding so billiger
5160 };
5161};
5162
5163//#################################################################
5164//
5165// Initialise everything
5166//
5167//#################################################################
5168
5169func void MEMINT_VersionError() {
5170 const string G1 = "Gothic 1.08k";
5171 const string G2 = "der sogenannten 'Report-Version' von Gothic 2";
5172 const string G2EN = "the so-called 'Report-Version' of Gothic 2";
5173
5174 var string str;
5175 str = "Diese Mod funktioniert nur mit ";
5176 if (GOTHIC_BASE_VERSION == 1) {
5177 str = ConcatStrings(str, G1);
5178 } else {
5179 str = ConcatStrings(str, G2);
5180 };
5181 str = ConcatStrings(str, ", da sie Funktionalität aus dem Skriptpaket 'Ikarus' verwendet. Es ist wahrscheinlich, dass Gothic unmittelbar nach dieser Fehlermeldung abstürzt. Die genannte Version von Gothic steht zum Beispiel auf worldofgothic.de zum Download bereit. Der merkwürdige Charakter dieser Fehlermeldung ist leider nicht zu vermeiden. ### This mod only works with ");
5182 if (GOTHIC_BASE_VERSION == 1) {
5183 str = ConcatStrings(str, G1);
5184 } else {
5185 str = ConcatStrings(str, G2EN);
5186 };
5187 str = ConcatStrings(str, ", because it uses parts of the script package 'Ikarus'. Gothic will probably crash immediatly after displaying this error message. Said version of Gothic is available for download at worldofgothic.com. The weirdness of this error message is unavoidable. !README! ");
5188
5189 Wld_InsertObject(str, MEM_FARFARAWAY);
5190};
5191
5192func int MEMINT_ReportVersionCheck() {
5193 /* In both G1 and G2 the first Instruction at address
5194 * 0x401000 is some mov instruction moving some data
5195 * from some location within the data section.
5196 * This makes this check reliable */
5197
5198 var int val; val = MEMINT_SwitchG1G2(-521402937, 504628679);
5199 var int ptr; ptr = 4198400; //0x401000
5200
5201 if (MEM_ReadInt(ptr) != val) {
5202 /* Error-Message does not work for Gothic 1. I have no idea how to fix that. */
5203 MEMINT_VersionError();
5204 return false;
5205 };
5206
5207 return true;
5208};
5209
5210func void MEM_InitAll() {
5211 if (!MEMINT_ReportVersionCheck()) {
5212 return;
5213 };
5214
5215 MEM_ReinitParser(); /* depends on nothing */
5216 MEM_InitLabels(); /* depends in MEM_ReinitParser */
5217 MEM_InitGlobalInst(); /* depends on MEM_ReinitParser */
5218
5219 /* now I can use MEM_ReplaceFunc, MEM_GetFuncID */
5220 MEM_GetAddress_Init(); /* depends on MEM_ReinitParser and MEM_InitLabels */
5221 /* now the nicer operators are available */
5222
5223 MEM_InitStatArrs(); /* depends on MEM_ReinitParser and MEM_InitLabels */
5224 ASMINT_Init();
5225
5226 MEMINT_ReplaceLoggingFunctions();
5227 MEMINT_ReplaceSlowFunctions();
5228 MEM_InitRepeat();
5229
5230 /* takes a wail the first time it is called.
5231 call it to avoid delay later */
5232 var int dump; dump = MEM_GetFuncIDByOffset(0);
5233};
5234//Orc-Warrior Scripts
5235func void printdebug_s_i(var string a,var int b)
5236{
5237 var string pipe;
5238 pipe = concatstrings(a,inttostring(b));
5239 printdebug(pipe);
5240};
5241
5242func int oCNpc_GetPointer(var C_NPC slf)
5243{
5244 if (!Hlp_IsValidNpc(slf)) {
5245 MEM_Error (ConcatStrings ("oCNpc_GetPointer: Invalid c_npc: ", IntToString (slf.id)));
5246 return 0;
5247 };
5248 MEM_ReinitParser();
5249 var c_npc hlp; var int ptr;
5250 hlp = Hlp_GetNpc(MEM_HELPER_INST);
5251 MEM_Helper = Hlp_GetNpc (hlp);
5252 Npc_SetTarget(hlp,slf);//self,other
5253 ptr = MEM_Helper.enemy;
5254
5255 return ptr;
5256
5257};
5258/*Orc Warrior */
5259func int clamp (var int v, var int min, var int max) {
5260 if (v < min) { return min; };
5261 if (v > max) { return max; };
5262 return v;
5263};
5264func int RGBAToZColor (var int r, var int g, var int b, var int a) {
5265 //clamping for safety
5266 r = clamp (r, 0, 255) << zCOLOR_SHIFT_RED;
5267 g = clamp (g, 0, 255) << zCOLOR_SHIFT_GREEN;
5268 b = clamp (b, 0, 255) << zCOLOR_SHIFT_BLUE;
5269 a = clamp (a, 0, 255) << zCOLOR_SHIFT_ALPHA;
5270
5271 return r | g | b | a;
5272};
5273
5274
5275func int zColor_a (var int col) {
5276 var int ret; ret = (col & zCOLOR_ALPHA) >> zCOLOR_SHIFT_ALPHA ;
5277 printdebug(inttostring(ret));
5278 if(ret<0){ret = 256 + ret; };
5279 return ret;
5280
5281};
5282
5283
5284func int zColor_r (var int col) {
5285 var int ret; ret = (col & zCOLOR_RED) >> zCOLOR_SHIFT_RED ;
5286 printdebug(inttostring(ret));
5287 if(ret<0){ret = 256 + ret; };
5288 return ret;
5289
5290};
5291
5292func int zColor_g (var int col) {
5293 var int ret; ret = (col & zCOLOR_GREEn) >> zCOLOR_SHIFT_GREEN ;
5294 printdebug(inttostring(ret));
5295 if(ret<0){ret = 256 + ret; };
5296 return ret;
5297
5298};
5299
5300func int zColor_b (var int col) {
5301 var int ret; ret = (col & zCOLOR_BLUE) >> zCOLOR_SHIFT_BLUE ;
5302 printdebug(inttostring(ret));
5303 if(ret<0){ret = 256 + ret; };
5304 return ret;
5305
5306};