-
Notifications
You must be signed in to change notification settings - Fork 3
/
WL.c
2340 lines (2125 loc) · 98.7 KB
/
WL.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************************\
* *
* WL.c *
* *
* Wilderland - A Hobbit Environment *
* *
* (c) 2012-2019 by CH, Contact: [email protected] *
* Copyright 2019-2025 Valerio Messina [email protected] *
* *
* Simple Direct media Layer library (SDL 2.0) from www.libsdl.org (LGPL) *
* Z80 emulator based on Marat Fayzullin's work from 2007 (fms.komkon.org) *
* z80emu based on Lin Ke-Fong work from 2017 (github.com/anotherlin/z80emu) *
* 8x8 character set from ZX Spectrum ROM (c) by Amstrad, PD for emulators *
* *
* Compiler: Pelles C for Windows 6.5.80 with 'Microsoft Extensions' enabled, *
* GCC, MinGW/Msys2, Clang/LLVM *
* *
* V 2.10 - 20250106 *
* *
* WL.c is part of Wilderland - A Hobbit Environment *
* Wilderland is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* Wilderland is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with Wilderland. If not, see <http://www.gnu.org/licenses/>. *
* *
\****************************************************************************/
/*** INCLUDES ***************************************************************/
#define _DEFAULT_SOURCE // realpath()
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> // PATH_MAX,NAME_MAX
#include <string.h>
#include <unistd.h> // getcwd(),chdir()
#include <errno.h> // errno
#include <sys/stat.h> // mkdir()
#include <SDL.h> // SDL2
#include <SDL_image.h> // png support
#include "WL.h"
#include "SDLTWE.h"
#include "Spectrum.h"
#include "MapCoordinates.h"
/*** GLOBAL VARIABLES *******************************************************/
#include "GlobalVars.h"
#ifdef _WIN32
#define realpath(N,R) _fullpath((R),(N),PATH_MAX)
#endif
#ifndef SDL_HINT_VIDEODRIVER // support for SDL < 2.0.22
#define SDL_HINT_VIDEODRIVER "SDL_VIDEO_DRIVER"
#endif
#define MAXNAMELEN 100
int NoScanLines;
int HV; //Hobbit version
struct CharSetStruct CharSet;
word DictionaryBaseAddress;
word ObjectsIndexAddress, ObjectsAddress;
bool dockMap=true; // when false the map is undocked
int SeedRND = 0; // when 1 use Z80 refresh register to generate random numbers
char* dlgMsgPtr; // keep the dialog box error message
char* urlLnkPtr; // keep the Hobbit game download url
char zipFileName[FILENAME_MAX]; // keep the Hobbit zip filename
char binPath[PATH_MAX]=""; // path of binary files
char cfgPath[PATH_MAX]=""; // path of config files
char savPath[PATH_MAX]=""; // path where save and unzip TAP/TZX
char wlsPath[PATH_MAX]=""; // path where save/load WLS
SDL_Window* winPtr;
SDL_Window* MapWinPtr;
SDL_Renderer* renPtr;
SDL_Renderer* MapRenPtr;
SDL_Surface* MapSfcPtr;
struct TextWindowStruct LogWin; // left frame
struct TextWindowStruct GameWin; // game frame
struct TextWindowStruct HelpWin; // center frame with commands
struct TextWindowStruct ObjWin; // right frame with attributes
struct TextWindowStruct MapWin; // lower frame with map
// select the CPU emulator, CPUEMUL must be: eZ80 or ez80emu
#if CPUEMUL == eZ80
Z80 z80; // my Z80 processor
#endif
#if CPUEMUL == ez80emu
Z80_STATE z80; // my Z80 processor
int context;
#endif
size_t SizeOfZ80 = sizeof(z80);
size_t FileOfZ80; // fixed size vars(bye,word,char,short,int), skip void/register pointers and 32/64 bit padding
byte ZXmem[SL_48K]; // Spectrum 64 kB memory
//unsigned char ZXmem[1 << 16]; // Spectrum 64 kB memory for z80emu
uint8_t bit = 8*sizeof(void*); // 32 or 64 bit
//SDL_Scancode CurrentPressedCod;
SDL_Keycode CurrentPressedKey; // used by InZ80()
uint16_t CurrentPressedMod; // used by InZ80()
char dp=0; // used to hack unknown property 04 and 06
byte fou[OBJECTS_NR_MAX+1]; // used to hack unknown property 04
byte fiv[OBJECTS_NR_MAX+1]; // used to hack unknown property 05
byte six[OBJECTS_NR_MAX+1]; // used to hack unknown property 06
/****************************************************************************\
* WL_Setpixel on map *
* *
\****************************************************************************/
void WL_SetPixel(struct TextWindowStruct* TW, int x, int y, color_t color) {
int maxw = TW->rect.w;
int maxh = TW->rect.h;
if (x>=maxw) return; // MAPWINWIDTH
if (y>=maxh) return; // MAPWINHEIGHT
TW->framePtr[y*maxw + x] = color;
} // WL_SetPixel()
/****************************************************************************\
* DrawLineRelative: x,y start; dx,dy offset to end; rx,ry thick; color *
* *
\****************************************************************************/
void DrawLineRelative(struct TextWindowStruct* TW, int x, int y, int dx, int dy, int rx, int ry, color_t color) {
int x1, y1, sx, sy;
if (rx == 0 || ry == 0)
return;
sx = (dx > 0) ? 1 : -1;
dx *= sx;
sy = (dy > 0) ? 1 : -1;
dy *= sy;
while (rx > 1 || ry > 1) {
if (rx > 1)
rx--;
if (ry > 1)
ry--;
if (dx > dy)
for (x1 = 0; x1 < dx; x1++)
WL_SetPixel(TW, x + sx * (x1 + (rx - 1)), sy * (y + ((int)(dy * x1 / dx)) + (ry - 1)), color);
else
for (y1 = 0; y1 < dy; y1++)
WL_SetPixel(TW, x + sx * (((int)(dx * y1 / dy)) + (rx - 1)), y + sy * (y1 + (ry - 1)), color);
}
} // DrawLineRelative()
/****************************************************************************\
* PrintChar on map *
* *
\****************************************************************************/
void PrintChar(struct TextWindowStruct* TW, struct CharSetStruct* cs, char a, int x, int y, color_t ink, color_t paper) {
int i, j;
int CharIndex;
byte mask;
int ymul;
uint32_t *pixm;
if (WL_DEBUG) {
if ((cs->Width != 8) || (cs->Height != 8)) {
fprintf(stderr, "WL: ERROR in PrintChar. Only 8x8 pixel charsets are supported.\n");
return;
}
}
//ymul = MAPWINWIDTH; // scr->pitch / BYTESPERPIXEL;
ymul = TW->rect.w;
for (i = 0; i <= 7; i++) {
mask = 0x80;
CharIndex = (a - cs->CharMin) * cs->Height;
for (j = 0; j <= 7; j++, mask >>= 1) {
pixm = (uint32_t*) TW->framePtr + (y + i) * ymul + x + j;
if (cs->Bitmap[CharIndex + i] & mask)
*pixm = ink;
else
*pixm = paper;
}
}
} // PrintChar()
/****************************************************************************\
* PrintString on map *
* *
\****************************************************************************/
void PrintString(struct TextWindowStruct* TW, struct CharSetStruct* cs, char* ps, int x, int y, color_t ink, color_t paper) {
while (*ps) {
PrintChar(TW, cs, *ps++, x, y, ink, paper);
x += cs->Width;
}
} // PrintString()
/****************************************************************************\
* SearchByteWordTable for map and ? *
* *
* Returns pointer value or 0 if not found. *
\****************************************************************************/
word SearchByteWordTable(byte a, word address) {
while (ZXmem[address] != 0xFF) {
if (ZXmem[address] == a)
return (ZXmem[address + 1] + 0x100 * ZXmem[address + 2]);
else
address += 3;
}
return 0;
} // SearchByteWordTable()
/****************************************************************************\
* GetObjectAttributePointer for map and ? *
* *
* Returns pointer value or 0 if not found. *
\****************************************************************************/
word GetObjectAttributePointer(byte a, byte attributeoffset) {
word OAP;
OAP = SearchByteWordTable(a, ObjectsIndexAddress);
if (OAP)
return (OAP + attributeoffset);
else
return 0;
} // GetObjectAttributePointer()
/****************************************************************************\
* DrawAnimalPositon on map *
* *
\****************************************************************************/
void DrawAnimalPosition(struct TextWindowStruct* TW, struct CharSetStruct* cs, byte animalNr, word x, word y, byte objectoffset) {
char initials[10];
DrawLineRelative(TW, x, y + objectoffset*15, 10, -30, 4, 1, SC_BRRED);
strcpy(initials, AnimalInitials[animalNr]);
if (ZXmem[GetObjectAttributePointer(animalNr, ATTRIBUTE_OFF)] & ATTR_BROKEN)
strcat(initials, "+");
if (animalNr == OBJNR_YOU || animalNr == OBJNR_GANDALF || animalNr == OBJNR_THORIN)
PrintString(TW, cs, initials, x + 13, y + objectoffset*15 - 33, SC_BRRED, 0x00000000ul);
else
PrintString(TW, cs, initials, x + 13, y + objectoffset*15 - 33, SC_BRGREEN, 0x00000000ul);
} // DrawAnimalPosition()
/****************************************************************************\
* PrepareOneAnimalPositon on map *
* *
\****************************************************************************/
void PrepareOneAnimalPosition(struct TextWindowStruct* TW, struct CharSetStruct* cs, byte animalNr, byte *objectsperroom) {
byte CurrentAnimalRoom;
int i;
int x, y;
CurrentAnimalRoom = ZXmem[GetObjectAttributePointer(animalNr, P10_OFF_ROOM)];
for(i = 0; i<ROOMS_NROF_MAX; i++) {
if (MapCoordinates[i].RoomNumber == CurrentAnimalRoom) {
if (dockMap==true) {
x = MapCoordinates[i].X;
y = MapCoordinates[i].Y;
} else {
x = (float)MAPWINWIDTHND/MAPWINWIDTH*MapCoordinates[i].X;
y = (float)MAPWINWIDTHND/MAPWINWIDTH*MapCoordinates[i].Y;
}
DrawAnimalPosition(TW, cs, animalNr, x - INDICATOROFFSET,
y + INDICATOROFFSET,
objectsperroom[CurrentAnimalRoom]);
objectsperroom[CurrentAnimalRoom]++;
}
}
} // PrepareOneAnimalPosition()
/****************************************************************************\
* PrepareAnimalPositions on map *
* *
\****************************************************************************/
void PrepareAnimalPositions(struct TextWindowStruct* TW, struct CharSetStruct* cs, byte* objectsperroom) {
byte AnimalNr;
PrepareOneAnimalPosition(TW, cs, OBJNR_YOU, objectsperroom);
for(AnimalNr = OBJNR_DRAGON; AnimalNr <= OBJNR_DISGUSTINGGOBLIN; AnimalNr++)
PrepareOneAnimalPosition(TW, cs, AnimalNr, objectsperroom);
} // PrepareAnimalPositions()
/****************************************************************************\
* ShowTextWindow *
* *
\****************************************************************************/
void ShowTextWindow(struct TextWindowStruct* TW) {
SDL_UpdateTexture(TW->texPtr, NULL, TW->framePtr, TW->pitch); // Frame to Texture
SDL_RenderCopy(renPtr, TW->texPtr, NULL, &TW->rect); // Texture to Renderer
SDL_RenderPresent(renPtr); // to screen
SDL_Delay(delay); // to avoid flickering
} // ShowTextWindow()
/****************************************************************************\
* printZ80struct *
* *
\****************************************************************************/
void printZ80struct() {
uintptr_t p;
uintptr_t z = (uintptr_t)&z80;
uintptr_t fo=98; // file offset, was 64 on filever1
printf("z80 size:%zu\n", SizeOfZ80);
printf("z80 file:%zu\n", FileOfZ80);
printf("z80 addr:0x%p\n", &z80);
#if CPUEMUL == eZ80
printf( "fil ind address_____________ reg_______ value_____________\n");
p=(uintptr_t)&z80.AF.B.l; printf("%03tu %03tu @:0x%16tX F :0x%02X\n", p-z+fo, p-z, p, z80.AF.B.l);
p=(uintptr_t)&z80.AF.B.h; printf("%03tu %03tu @:0x%16tX A :0x%02X\n", p-z+fo, p-z, p, z80.AF.B.h);
p=(uintptr_t)&z80.BC.B.l; printf("%03tu %03tu @:0x%16tX C :0x%02X\n", p-z+fo, p-z, p, z80.BC.B.l);
p=(uintptr_t)&z80.BC.B.h; printf("%03tu %03tu @:0x%16tX B :0x%02X\n", p-z+fo, p-z, p, z80.BC.B.h);
p=(uintptr_t)&z80.DE.B.l; printf("%03tu %03tu @:0x%16tX E :0x%02X\n", p-z+fo, p-z, p, z80.DE.B.l);
p=(uintptr_t)&z80.DE.B.h; printf("%03tu %03tu @:0x%16tX D :0x%02X\n", p-z+fo, p-z, p, z80.DE.B.h);
p=(uintptr_t)&z80.HL.B.l; printf("%03tu %03tu @:0x%16tX L :0x%02X\n", p-z+fo, p-z, p, z80.HL.B.l);
p=(uintptr_t)&z80.HL.B.h; printf("%03tu %03tu @:0x%16tX H :0x%02X\n", p-z+fo, p-z, p, z80.HL.B.h);
p=(uintptr_t)&z80.IX.B.l; printf("%03tu %03tu @:0x%16tX IXl :0x%02X\n", p-z+fo, p-z, p, z80.IX.B.l);
p=(uintptr_t)&z80.IX.B.h; printf("%03tu %03tu @:0x%16tX IXh :0x%02X\n", p-z+fo, p-z, p, z80.IX.B.h);
p=(uintptr_t)&z80.IY.B.l; printf("%03tu %03tu @:0x%16tX IYl :0x%02X\n", p-z+fo, p-z, p, z80.IY.B.l);
p=(uintptr_t)&z80.IY.B.h; printf("%03tu %03tu @:0x%16tX IYh :0x%02X\n", p-z+fo, p-z, p, z80.IY.B.h);
p=(uintptr_t)&z80.PC.B.l; printf("%03tu %03tu @:0x%16tX PCl :0x%02X\n", p-z+fo, p-z, p, z80.PC.B.l);
p=(uintptr_t)&z80.PC.B.h; printf("%03tu %03tu @:0x%16tX PCh :0x%02X\n", p-z+fo, p-z, p, z80.PC.B.h);
p=(uintptr_t)&z80.SP.B.l; printf("%03tu %03tu @:0x%16tX SPl :0x%02X\n", p-z+fo, p-z, p, z80.SP.B.l),
p=(uintptr_t)&z80.SP.B.h; printf("%03tu %03tu @:0x%16tX SPh :0x%02X\n", p-z+fo, p-z, p, z80.SP.B.h),
p=(uintptr_t)&z80.AF.W; printf("%03tu %03tu @:0x%16tX AF :0x%02X\n", p-z+fo, p-z, p, z80.AF.W);
p=(uintptr_t)&z80.BC.W; printf("%03tu %03tu @:0x%16tX BC :0x%02X\n", p-z+fo, p-z, p, z80.BC.W);
p=(uintptr_t)&z80.DE.W; printf("%03tu %03tu @:0x%16tX DE :0x%02X\n", p-z+fo, p-z, p, z80.DE.W);
p=(uintptr_t)&z80.HL.W; printf("%03tu %03tu @:0x%16tX HL :0x%02X\n", p-z+fo, p-z, p, z80.HL.W);
p=(uintptr_t)&z80.IX.W; printf("%03tu %03tu @:0x%16tX IX :0x%02X\n", p-z+fo, p-z, p, z80.IX.W);
p=(uintptr_t)&z80.IY.W; printf("%03tu %03tu @:0x%16tX IY :0x%02X\n", p-z+fo, p-z, p, z80.IY.W);
p=(uintptr_t)&z80.PC.W; printf("%03tu %03tu @:0x%16tX PC :0x%02X\n", p-z+fo, p-z, p, z80.PC.W);
p=(uintptr_t)&z80.SP.W; printf("%03tu %03tu @:0x%16tX SP :0x%02X\n", p-z+fo, p-z, p, z80.SP.W);
p=(uintptr_t)&z80.AF1.W; printf("%03tu %03tu @:0x%16tX AF' :0x%02X\n", p-z+fo, p-z, p, z80.AF1.W);
p=(uintptr_t)&z80.BC1.W; printf("%03tu %03tu @:0x%16tX BC' :0x%02X\n", p-z+fo, p-z, p, z80.BC1.W);
p=(uintptr_t)&z80.DE1.W; printf("%03tu %03tu @:0x%16tX DE' :0x%02X\n", p-z+fo, p-z, p, z80.DE1.W);
p=(uintptr_t)&z80.HL1.W; printf("%03tu %03tu @:0x%16tX HL' :0x%02X\n", p-z+fo, p-z, p, z80.HL1.W);
p=(uintptr_t)&z80.IFF; printf("%03tu %03tu @:0x%16tX IFF :0x%02X\n", p-z+fo, p-z, p, z80.IFF);
p=(uintptr_t)&z80.I; printf("%03tu %03tu @:0x%16tX I :0x%02X\n", p-z+fo, p-z, p, z80.I);
p=(uintptr_t)&z80.R; printf("%03tu %03tu @:0x%16tX R :0x%02X\n", p-z+fo, p-z, p, z80.R);
p=(uintptr_t)&z80.IPeriod; printf("%03tu %03tu @:0x%16tX IPeriod :0x%08X\n", p-z+fo, p-z, p, z80.IPeriod);
p=(uintptr_t)&z80.ICount; printf("%03tu %03tu @:0x%16tX ICount :0x%08X\n", p-z+fo, p-z, p, z80.ICount);
p=(uintptr_t)&z80.IBackup; printf("%03tu %03tu @:0x%16tX IBackup :0x%08X\n", p-z+fo, p-z, p, z80.IBackup);
p=(uintptr_t)&z80.IRequest; printf("%03tu %03tu @:0x%16tX IRequest :0x%02X\n", p-z+fo, p-z, p, z80.IRequest);
p=(uintptr_t)&z80.IAutoReset; printf("%03tu %03tu @:0x%16tX IAutoReset:0x%02X\n", p-z+fo, p-z, p, z80.IAutoReset);
p=(uintptr_t)&z80.TrapBadOps; printf("%03tu %03tu @:0x%16tX TrapBadOps:0x%02X\n", p-z+fo, p-z, p, z80.TrapBadOps);
p=(uintptr_t)&z80.Trap; printf("%03tu %03tu @:0x%16tX Trap :0x%02X\n", p-z+fo, p-z, p, z80.Trap);
p=(uintptr_t)&z80.Trace; printf("%03tu %03tu @:0x%16tX Trace :0x%02X\n", p-z+fo, p-z, p, z80.Trace);
p=(uintptr_t)&z80.User; printf("%03tu %03tu @:0x%16tX &User :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.User);
#endif
#if CPUEMUL == ez80emu
printf( "fil ind address_____________ reg_ value_____________\n");
p=(uintptr_t)&z80.status; printf("%03tu %03tu @:0x%16tX stat:0x%08X\n", p-z+fo, p-z, p, z80.status);
p=(uintptr_t)&z80.registers.byte[0]; printf("%03tu %03tu @:0x%16tX C :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[0]);
p=(uintptr_t)&z80.registers.byte[1]; printf("%03tu %03tu @:0x%16tX B :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[1]);
p=(uintptr_t)&z80.registers.byte[2]; printf("%03tu %03tu @:0x%16tX E :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[2]);
p=(uintptr_t)&z80.registers.byte[3]; printf("%03tu %03tu @:0x%16tX D :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[3]);
p=(uintptr_t)&z80.registers.byte[4]; printf("%03tu %03tu @:0x%16tX L :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[4]);
p=(uintptr_t)&z80.registers.byte[5]; printf("%03tu %03tu @:0x%16tX H :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[5]);
p=(uintptr_t)&z80.registers.byte[6]; printf("%03tu %03tu @:0x%16tX F :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[6]);
p=(uintptr_t)&z80.registers.byte[7]; printf("%03tu %03tu @:0x%16tX A :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[7]);
p=(uintptr_t)&z80.registers.byte[8]; printf("%03tu %03tu @:0x%16tX IXl :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[8]);
p=(uintptr_t)&z80.registers.byte[9]; printf("%03tu %03tu @:0x%16tX IXh :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[9]);
p=(uintptr_t)&z80.registers.byte[10]; printf("%03tu %03tu @:0x%16tX IYl :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[10]);
p=(uintptr_t)&z80.registers.byte[11]; printf("%03tu %03tu @:0x%16tX IYh :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[11]);
p=(uintptr_t)&z80.registers.byte[12]; printf("%03tu %03tu @:0x%16tX Pl :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[12]);
p=(uintptr_t)&z80.registers.byte[13]; printf("%03tu %03tu @:0x%16tX Sh :0x%02X\n", p-z+fo, p-z, p, z80.registers.byte[13]);
p=(uintptr_t)&z80.registers.word[0]; printf("%03tu %03tu @:0x%16tX BC :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[0]);
p=(uintptr_t)&z80.registers.word[1]; printf("%03tu %03tu @:0x%16tX DE :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[1]);
p=(uintptr_t)&z80.registers.word[2]; printf("%03tu %03tu @:0x%16tX HL :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[2]);
p=(uintptr_t)&z80.registers.word[3]; printf("%03tu %03tu @:0x%16tX AF :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[3]);
p=(uintptr_t)&z80.registers.word[4]; printf("%03tu %03tu @:0x%16tX IX :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[4]);
p=(uintptr_t)&z80.registers.word[5]; printf("%03tu %03tu @:0x%16tX IY :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[5]);
p=(uintptr_t)&z80.registers.word[6]; printf("%03tu %03tu @:0x%16tX SP :0x%04X\n", p-z+fo, p-z, p, z80.registers.word[6]);
p=(uintptr_t)&z80.alternates[0]; printf("%03tu %03tu @:0x%16tX BC' :0x%04X\n", p-z+fo, p-z, p, z80.alternates[0]);
p=(uintptr_t)&z80.alternates[1]; printf("%03tu %03tu @:0x%16tX DE' :0x%04X\n", p-z+fo, p-z, p, z80.alternates[1]);
p=(uintptr_t)&z80.alternates[2]; printf("%03tu %03tu @:0x%16tX HL' :0x%04X\n", p-z+fo, p-z, p, z80.alternates[2]);
p=(uintptr_t)&z80.alternates[3]; printf("%03tu %03tu @:0x%16tX AF' :0x%04X\n", p-z+fo, p-z, p, z80.alternates[3]);
p=(uintptr_t)&z80.i; printf("%03tu %03tu @:0x%16tX I :0x%08X\n", p-z+fo, p-z, p, z80.i);
p=(uintptr_t)&z80.r; printf("%03tu %03tu @:0x%16tX R :0x%08X\n", p-z+fo, p-z, p, z80.r);
p=(uintptr_t)&z80.pc; printf("%03tu %03tu @:0x%16tX PC :0x%08X\n", p-z+fo, p-z, p, z80.pc);
p=(uintptr_t)&z80.iff1; printf("%03tu %03tu @:0x%16tX IFF1:0x%08X\n", p-z+fo, p-z, p, z80.iff1);
p=(uintptr_t)&z80.iff2; printf("%03tu %03tu @:0x%16tX IFF2:0x%08X\n", p-z+fo, p-z, p, z80.iff2);
p=(uintptr_t)&z80.im; printf("%03tu %03tu @:0x%16tX IM :0x%08X\n", p-z+fo, p-z, p, z80.im);
p=(uintptr_t)&z80.register_table[0]; printf("%03tu %03tu @:0x%16tX &B :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[0]);
p=(uintptr_t)&z80.register_table[1]; printf("%03tu %03tu @:0x%16tX &C :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[1]);
p=(uintptr_t)&z80.register_table[2]; printf("%03tu %03tu @:0x%16tX &D :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[2]);
p=(uintptr_t)&z80.register_table[3]; printf("%03tu %03tu @:0x%16tX &E :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[3]);
p=(uintptr_t)&z80.register_table[4]; printf("%03tu %03tu @:0x%16tX &H :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[4]);
p=(uintptr_t)&z80.register_table[5]; printf("%03tu %03tu @:0x%16tX &L :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[5]);
p=(uintptr_t)&z80.register_table[6]; printf("%03tu %03tu @:0x%16tX &HL :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[6]);
p=(uintptr_t)&z80.register_table[7]; printf("%03tu %03tu @:0x%16tX &A :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[7]);
p=(uintptr_t)&z80.register_table[8]; printf("%03tu %03tu @:0x%16tX &BC :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[8]);
p=(uintptr_t)&z80.register_table[9]; printf("%03tu %03tu @:0x%16tX &DE :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[9]);
p=(uintptr_t)&z80.register_table[10]; printf("%03tu %03tu @:0x%16tX &HL :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[10]);
p=(uintptr_t)&z80.register_table[11]; printf("%03tu %03tu @:0x%16tX &SP :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[11]);
p=(uintptr_t)&z80.register_table[12]; printf("%03tu %03tu @:0x%16tX &BC :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[12]);
p=(uintptr_t)&z80.register_table[13]; printf("%03tu %03tu @:0x%16tX &DE :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[13]);
p=(uintptr_t)&z80.register_table[14]; printf("%03tu %03tu @:0x%16tX &HL :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[14]);
p=(uintptr_t)&z80.register_table[15]; printf("%03tu %03tu @:0x%16tX &AF :0x%16tX\n", p-z+fo, p-z, p, (uintptr_t)z80.register_table[15]);
#endif
} // printZ80struct()
/****************************************************************************\
* printZ80 *
* *
\****************************************************************************/
void printZ80() {
unsigned int i;
byte mem;
printf("z80 size:%zu\n", SizeOfZ80);
printf("z80 file:%zu\n", FileOfZ80);
printf("z80 addr:0x%p\n", &z80);
for (i=0; i<SizeOfZ80; i++) {
mem = *( ((byte*)&z80) + i);
//printf("z80[%03u]='%c'=0x%02X=%03u\n", i, mem, mem, mem );
printf("z80[%03u]=0x%02X\n", i, mem );
}
} // printZ80()
/****************************************************************************\
* GetFileName *
* *
\****************************************************************************/
void GetFileName(char* fnstr, struct TextWindowStruct* TW, struct CharSetStruct* CS, color_t ink, color_t paper) {
SDL_Keycode s;
uint16_t m;
char* f = fnstr;
SDL_Event event;
while (1) {
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
s = event.key.keysym.sym;
m = event.key.keysym.mod;
//printf("sym:'%c'=%d mod:'%c'=%d\n", s, s, m, m);
if ((s >= 'a' && s <= 'z') || (s >= '0' && s <= '9') ||
s == '.' || s == '-') {
if (s=='-' && (m==KMOD_LSHIFT||m==KMOD_RSHIFT)) s='_';
*fnstr = s;
fnstr++;
SDLTWE_PrintCharTextWindow(TW, s, CS, ink, paper);
ShowTextWindow(TW);
if (fnstr-f >= MAXNAMELEN) {
*fnstr = 0;
return;
}
break;
}
if (s == SDLK_BACKSPACE) {
//printf("backspace\n");
if (f!=fnstr) { // not on first editable
*fnstr = '\b'; // backspace
fnstr--;
SDLTWE_PrintCharTextWindow(TW, '\b', CS, ink, paper);
ShowTextWindow(TW);
}
break;
}
if (s == SDLK_RETURN) {
*fnstr = 0;
return;
}
case SDL_KEYUP:
s = 0;
break;
}
}
}
} // GetFileName()
/****************************************************************************\
* SaveGame *
* *
\****************************************************************************/
void SaveGame(struct TextWindowStruct* TW, struct CharSetStruct* CS, int hv, color_t ink, color_t paper) {
char fn[MAXNAMELEN+4];
FILE *f;
int i;
SDLTWE_PrintString(TW, "\n\nSave Filename: ", CS, ink, paper);
ShowTextWindow(TW);
firstEditable = 15; // "Save Filename: "
GetFileName(fn, TW, CS, ink, paper);
firstEditable = 0;
if (fn[0] != '\0') strcat(fn, ".wls");
chdir(wlsPath); // go to WLS path to let read/write screenshot files
f = fopen(fn, "wb");
if (!f) {
fprintf(stderr, "WL: ERROR - Can't open file '%s' for saving game.\n", fn);
SDLTWE_PrintString(TW, "Can't open file for saving\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
fprintf(f, "GAMEVERSION=%i\r\n", hv);
fprintf(f, "FILEVERSION=2\r\n");
fprintf(f, "Z80VERSION=%i\r\n", CPUEMUL); // new in fileversion 2
fprintf(f, "SIZE(Z80)=0x%03zX\r\n", SizeOfZ80);
fprintf(f, "FILE(Z80)=0x%02zX\r\n", FileOfZ80);
#if CPUEMUL == eZ80
fprintf(f, "PC=0x%04X\r\n", z80.PC.W);
#endif
#if CPUEMUL == ez80emu
fprintf(f, "PC=0x%04X\r\n", (word)z80.pc);
#endif
fprintf(f, "***Z80***\n");
for (i = 0; i < FileOfZ80; i++) { // filever 2 save z80 partially
byte b = *( ((byte*)&z80) + i);
fprintf(f, "%c", b);
}
fprintf(f, "\n");
fprintf(f, "***MEMORY***\n");
for (i = 0; i <= SL_RAMEND; i++)
fprintf(f, "%c", ZXmem[i]);
fclose(f);
SDLTWE_PrintString(TW, ".wls saved.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
} // SaveGame()
/****************************************************************************\
* LoadGame *
* *
\****************************************************************************/
void LoadGame(struct TextWindowStruct* TW, struct CharSetStruct* CS, int hv, color_t ink, color_t paper) {
char fn[MAXNAMELEN+4];
FILE *f;
int ret;
size_t num;
int i, gameversion;
int fileversion, z80version;
size_t sizeOfZ80, fileOfZ80;
SDLTWE_PrintString(TW, "\n\nLoad Filename: ", CS, ink, paper);
ShowTextWindow(TW);
firstEditable = 15; // "Load Filename: "
GetFileName(fn, TW, CS, ink, paper);
firstEditable = 0;
strcat(fn, ".wls");
chdir(wlsPath); // go to WLS path to let read/write screenshot files
f = fopen(fn, "rb");
if (!f) {
fprintf(stderr, "WL: ERROR - Can't open file '%s' for loading game.\n", fn);
SDLTWE_PrintString(TW, ".wls not found!\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
ret = fscanf(f, "GAMEVERSION=%i\r\n", &gameversion);
if (ret != 1) {
printf("ret:%d gamever:%d\n", ret, gameversion);
SDLTWE_PrintString(TW, "\nError: GAMEVERSION not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (gameversion != hv) {
SDLTWE_PrintString(TW, "\nError: Wrong game version.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
ret=fscanf(f, "FILEVERSION=%i\r\n", &fileversion);
if (ret != 1) {
printf("ERROR: FILEVERSION not found.\n");
SDLTWE_PrintString(TW, "\nError: FILEVERSION not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (fileversion < 1 || fileversion > 2) {
printf("ret:%d filever:%d\n", ret, fileversion);
SDLTWE_PrintString(TW, "\nError: Unsupported Fileversion.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (fileversion == 2) { // compare z80 emulator
if (fscanf(f, "Z80VERSION=%i\r\n", &z80version) != 1) {
printf("ERROR: Z80VERSION not found.\n");
SDLTWE_PrintString(TW, "\nError: Z80VERSION not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (z80version != CPUEMUL) {
SDLTWE_PrintString(TW, "\nError: Wrong z80 emulator version.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
}
if (fscanf(f, "SIZE(Z80)=%05zX\r\n", &sizeOfZ80) != 1) {
SDLTWE_PrintString(TW, "\nError: SIZE(Z80) not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (sizeOfZ80 != SizeOfZ80) {
printf("WARN: z80size file:%zu mem:%zu FileOfZ80:%zu '%s'\n", sizeOfZ80, SizeOfZ80, FileOfZ80, fn);
if (fileversion == 1) {
if (bit==32 && sizeOfZ80==56 && SizeOfZ80==52) { // 56 on 64bit and 52 on 32bit
goto bitDiffer;
}
if (bit==32 && sizeOfZ80==440 && SizeOfZ80==244) { // 440 on 64bit and 244 on 32bit
goto bitDiffer;
}
if (bit==64 && sizeOfZ80==52 && SizeOfZ80==56) { // 56 on 64bit and 52 on 32bit
goto bitDiffer;
}
if (bit==64 && sizeOfZ80==244 && SizeOfZ80==440) { // 440 on 64bit and 244 on 32bit
goto bitDiffer;
}
SDLTWE_PrintString(TW, "\nError: Z80-structure sizes do not match.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
} else // on filever=2 will use and check FileOfZ80
bitDiffer:
printf("CONTINUE: savefile generated on different 32/64 bit architecture\n");
}
if (fileversion == 2) { // new in filever 2: read FILE(Z80)
if (fscanf(f, "FILE(Z80)=%04zX\r\n", &fileOfZ80) != 1) {
SDLTWE_PrintString(TW, "\nError: FILE(Z80) not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
if (fileOfZ80 != FileOfZ80) {
printf("ERROR: z80file:%zu mem:%zu\n", fileOfZ80, FileOfZ80);
SDLTWE_PrintString(TW, "\nError: Z80-structure File sizes do not match.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
}
// from here overwrite Z80 structure
#if CPUEMUL == eZ80
if (fscanf(f, "PC=%06hX\r\n", &z80.PC.W) != 1) {
#endif
#if CPUEMUL == ez80emu
word pc;
ret=fscanf(f, "PC=%06hX\r\n", &pc);
z80.pc=pc;
if (ret != 1) {
#endif
SDLTWE_PrintString(TW, "\nError: PC address not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
ret = fscanf(f, "***Z80***\n"); // should be "***Z80***", so ret = 0 conversions
if (ret != 0) { // so is EOF=-1
SDLTWE_PrintString(TW, "\nError: ***Z80*** not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
// SizeOfZ80: Z80:56 on 64bit, 52 on 32bit, z80emu:440 on 64bit, 244 on 32bit
// FileOfZ80: Z80:47 on 64/32bit, z80emu:52 on 64/32bit
for (i = 0; i < FileOfZ80; i++) { // read z80 partially
if (fscanf(f, "%c", ( ((byte*)&z80) + i) ) != 1) {
SDLTWE_PrintString(TW, "\nError: Z80struct:%%c does not match format.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
}
if (fileversion == 1) { // on filever=1 there are pointer bytes to skip
num = sizeOfZ80-FileOfZ80; // bytes to discard
// 56/52 - 47
printf("skipping num:%zu bytes of pointers+padding\n", num);
for (int i=1; i<=num; i++) { // Z80: 56 on 64bit,52 on 32bit, skip bytes
ret=fscanf(f, "%*c");
}
}
ret = fscanf(f, "\n");
ret = fscanf(f, "***MEMORY***\n"); // should be "***MEMORY***", so ret = 0 conversions
if (ret != 0) { // so is EOF=-1
SDLTWE_PrintString(TW, "\nError: ***MEMORY*** not found.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
for (i = 0; i <= SL_RAMEND; i++)
if (fscanf(f, "%c", ZXmem + i) != 1) {
SDLTWE_PrintString(TW, "\nError: MEMORY:%%c does not match format.\n\n", CS, ink, paper);
ShowTextWindow(TW);
chdir(cfgPath); // back to config path to let find assets files
return;
}
fclose(f);
SDLTWE_PrintString(TW, ".wls loaded.\n\n", CS, ink, paper);
ShowTextWindow(TW);
for (i = SL_SCREENSTART; i <= SL_ATTRIBUTEEND; i++) // display buffer
WrZ80(i, ZXmem[i]); // force call to WriteScreenByte+WriteAttributeByte
#if CPUEMUL == ez80emu
Z80ResetTable (&z80); // regenerate the register pointers to new address
#endif
chdir(cfgPath); // back to config path to let find assets files
} // LoadGame()
/****************************************************************************\
* GetHexByte *
* *
\****************************************************************************/
void GetHexByte(byte* b, struct TextWindowStruct* TW, struct CharSetStruct* CS, color_t ink, color_t paper) {
SDL_Keycode s;
SDL_Event event;
int nibble_count = 0;
*b = 0; // returned value
while (1) {
if (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
s = event.key.keysym.sym;
if (s >= '0' && s <= '9') {
if (nibble_count >= 2) break;
*b <<= 4;
*b += (s - '0');
nibble_count++;
SDLTWE_PrintCharTextWindow(TW, s, CS, ink, paper);
ShowTextWindow(TW);
break;
}
if ((s >= 'a' && s <= 'f') || (s >= 'A' && s <= 'F')) {
if (nibble_count >= 2) break;
s |= 0x20;
*b <<= 4;
*b += (s - 'a' + 0x0a);
s += 'A' - 'a'; // to upper case
nibble_count++;
SDLTWE_PrintCharTextWindow(TW, s, CS, ink, paper);
ShowTextWindow(TW);
break;
}
if (s == SDLK_BACKSPACE) {
//printf("backspace\n");
if (nibble_count>0) {
*b >>= 4;
nibble_count--;
SDLTWE_PrintCharTextWindow(TW, '\b', CS, ink, paper);
ShowTextWindow(TW);
}
break;
}
if (s == SDLK_RETURN) {
return;
}
case SDL_KEYUP:
s = 0;
break;
}
}
}
} // GetHexByte()
/****************************************************************************\
* Go *
* *
\****************************************************************************/
void Go(struct TextWindowStruct* TW, struct CharSetStruct* CS, int hv, color_t ink, color_t paper) {
byte rn;
SDLTWE_PrintString(TW, "\n\nEnter room number 0x", CS, ink, paper);
ShowTextWindow(TW);
firstEditable=20;
GetHexByte(&rn, TW, CS, ink, paper);
firstEditable=0;
if (rn < 1 || rn > ROOMS_NR_MAX) {
SDLTWE_PrintString(TW, ". ERROR, invalid room number.\n", CS, ink, paper);
ShowTextWindow(TW);
return;
}
switch (hv) {
case OWN:
ZXmem[L_YOU_OBJ_POSITION_OWN] = rn;
break;
case V10:
ZXmem[L_YOU_OBJ_POSITION_V10] = rn;
break;
case V12:
ZXmem[L_YOU_OBJ_POSITION_V12] = rn;
break;
default:
fprintf(stderr, "ERROR in WL/Go: unknown game version.\n");
return;
}
// move carried object too
word ai, oa;
for (ai=ObjectsIndexAddress+1; ZXmem[ai-1] != 0xFF; ai+=3) {
oa = ZXmem[ai] + 0x100 * ZXmem[ai + 1];
if (ZXmem[oa + P1_OFF_MO] == OBJNR_YOU) { // by Bilbo
ZXmem[oa + P10_OFF_ROOM] = rn;
}
}
SDLTWE_PrintString(TW, ". OK, you are now in room: 0x", CS, ink, paper);
char rnStr[4];
sprintf(rnStr, "%02X\n", rn);
SDLTWE_PrintString(TW, rnStr, CS, ink, paper);
ShowTextWindow(TW);
} // Go()
/****************************************************************************\
* Help *
* *
\****************************************************************************/
void Help(struct TextWindowStruct* TW, struct CharSetStruct* CS) {
char bitStr[20];
char str[65]=" WILDERLAND - A Hobbit Environment v"WLVER" "; // 45+WLVER(5)=50
sprintf(bitStr, "%u bit ", bit); // 14
if (strlen(str)+strlen(bitStr) <= 64) strcat(str, bitStr); // 64
// "0000000001111111111222222222233333333334444444444555555555566666"
// "1234567890123456789012345678901234567890123456789012345678901234"
//SDLTWE_PrintString(TW, " WILDERLAND - A Hobbit Environment v"WLVER" ", CS, SC_BRWHITE, SC_BRBLACK);
SDLTWE_PrintString(TW, str, CS, SC_BRWHITE, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " (c) 2012-2019 by CH, Copyright 2019-"WLYEAR" V.Messina ", CS, SC_WHITE, SC_BLACK);
ShowTextWindow(TW);
#if CPUEMUL == eZ80
SDLTWE_PrintString(TW, " Using Z80 emulator: Z80 by Marat Fayzullin ", CS, SC_BRWHITE, SC_BRBLACK);
#endif
#if CPUEMUL == ez80emu
SDLTWE_PrintString(TW, " Using Z80 emulator: z80emu by Lin Ke-Fong ", CS, SC_BRWHITE, SC_BRBLACK);
#endif
ShowTextWindow(TW);
if (HV == OWN) SDLTWE_PrintString(TW, " Selected 'The Hobbit' binary VOWN \n", CS, SC_BRWHITE, SC_BRBLACK);
if (HV == V10) SDLTWE_PrintString(TW, " Selected 'The Hobbit' binary V1.0 \n", CS, SC_BRWHITE, SC_BRBLACK);
if (HV == V12) SDLTWE_PrintString(TW, " Selected 'The Hobbit' binary V1.2 \n", CS, SC_BRWHITE, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " INFO: ", CS, SC_BRMAGENTA, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "1L=place #=qty MO=parent Vo=volume Ma=mass St=strength \n", CS, SC_BRCYAN, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " a-z.,\"@0[BS] -> game ATTRIBUTES ", CS, SC_BRMAGENTA, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " S-ave H-elp G-o v_isible A_nimal o_pen *_light ", CS, SC_BRCYAN, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " L-oad I-nfo b_roken f_ull F_luid l_ocked ", CS, SC_BRCYAN, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " Q-uit \n", CS, SC_BRWHITE, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, " Press 'n' as first key to play without graphics (not game 1.0) \n", CS, SC_RED, SC_BLACK);
ShowTextWindow(TW);
} // Help()
/****************************************************************************\
* Info *
* *
\****************************************************************************/
void Info(struct TextWindowStruct* TW, struct CharSetStruct* CS) {
SDLTWE_PrintString(TW, "\nWILDERLAND - A Hobbit Environment (c) 2012-2019 by CH, "WLYEAR" VM\n\n", CS, SC_BRWHITE, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "\"The Hobbit\" (c) Melbourne House, 1982. Written by Philip\n", CS, SC_BRMAGENTA, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "Mitchell and Veronika Megler.\n\n", CS, SC_BRMAGENTA, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "Simple Direct media Layer library (SDL 2.0) from www.libsdl.org\n", CS, SC_WHITE, SC_BLACK);
ShowTextWindow(TW);
#if CPUEMUL == eZ80
SDLTWE_PrintString(TW, "Z80 emulator based on Marat Fayzullin's work (fms.komkon.org)\n", CS, SC_WHITE, SC_BLACK);
#endif
#if CPUEMUL == ez80emu
SDLTWE_PrintString(TW, "z80emu based on Lin Ke-Fong work (github.com/anotherlin/z80emu)\n", CS, SC_WHITE, SC_BLACK);
#endif
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "8x8 charset from ZX Spectrum ROM (c) by Amstrad,PD for emulators\n\n", CS, SC_WHITE, SC_BLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "You are not allowed to distribute 'WILDERLAND' with Hobbit\nbinaries included!\n\n", CS, SC_BRWHITE, SC_BRBLACK);
ShowTextWindow(TW);
SDLTWE_PrintString(TW, "Contact: [email protected], [email protected]\n", CS, SC_WHITE, SC_BLACK);
ShowTextWindow(TW);
} // Info()
/****************************************************************************\
* GetDictWord *
* *
\****************************************************************************/
void GetDictWord(word a, char* buf) {
word i = 1; // char count
a += DictionaryBaseAddress;
// the following line relies on evaluation from left to right
while (!(ZXmem[a] & 0x80) || (i == 2) || ((i == 3) && (ZXmem[a - 1] & 0x80))) {
if (ZXmem[a] & 0x1F) {
*buf++ = (ZXmem[a] & 0x1F) + 'A' - 1;
}
a++;
i++;
}
if (ZXmem[a] & 0x1F)
*buf++ = (ZXmem[a] & 0x1F) + 'A' - 1;
*buf = 0;
} // GetDictWord()
/****************************************************************************\
* GetObjectFullName *
* *
* +0A/0B: ADJECTIVE1, +0C/0D: ADJECTIVE2, +08/09: NOUN *
\****************************************************************************/
void GetObjectFullName(word oa, char* OFN) {
word wa;
char StringBuffer[25];
wa = ZXmem[oa + 0x0A] + 0x100 * ZXmem[oa + 0x0B]; // adjective 1
if (wa) {
GetDictWord(wa, StringBuffer);
strcat(OFN, StringBuffer);
strcat(OFN, " ");
}
wa = ZXmem[oa + 0x0C] + 0x100 * ZXmem[oa + 0x0D]; // adjective 2
if (wa) {
GetDictWord(wa, StringBuffer);
if (!strcmp(StringBuffer, "INSIGNIFICANT"))
strcpy(StringBuffer, "INSIGN.");
strcat(OFN, StringBuffer);
strcat(OFN, " ");
}
wa = ZXmem[oa + 0x08] + 0x100 * ZXmem[oa + 0x09]; // noun
if (wa & 0x0FFF) {
GetDictWord(wa & 0x0FFF, StringBuffer);
strcat(OFN, StringBuffer);
}
} // GetObjectFullName()
/****************************************************************************\
* sbinprintf *
* *
\****************************************************************************/