OSDN Git Service

- added new AProps to ACC headers.
[zandronum/zandronum-acc.git] / pcode.c
1 \r
2 //**************************************************************************\r
3 //**\r
4 //** pcode.c\r
5 //**\r
6 //**************************************************************************\r
7 \r
8 // HEADER FILES ------------------------------------------------------------\r
9 \r
10 #include <string.h>\r
11 #include <stddef.h>\r
12 #include <stdio.h>\r
13 #include "pcode.h"\r
14 #include "common.h"\r
15 #include "error.h"\r
16 #include "misc.h"\r
17 #include "strlist.h"\r
18 #include "token.h"\r
19 #include "symbol.h"\r
20 #include "parse.h"\r
21 \r
22 // MACROS ------------------------------------------------------------------\r
23 \r
24 // TYPES -------------------------------------------------------------------\r
25 \r
26 typedef struct scriptInfo_s\r
27 {\r
28         S_WORD number;\r
29         U_BYTE type;\r
30         U_BYTE argCount;\r
31         U_WORD varCount;\r
32         U_WORD flags;\r
33         int address;\r
34         int srcLine;\r
35         boolean imported;\r
36 } scriptInfo_t;\r
37 \r
38 typedef struct functionInfo_s\r
39 {\r
40         U_BYTE hasReturnValue;\r
41         U_BYTE argCount;\r
42         U_BYTE localCount;\r
43         int address;\r
44         int name;\r
45 } functionInfo_t;\r
46 \r
47 typedef struct mapVarInfo_s\r
48 {\r
49         int initializer;\r
50         boolean isString;\r
51         char *name;\r
52         boolean imported;\r
53 } mapVarInfo_t;\r
54 \r
55 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------\r
56 \r
57 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------\r
58 \r
59 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------\r
60 \r
61 static void GrowBuffer(void);\r
62 static void Append(void *buffer, size_t size);\r
63 static void Write(void *buffer, size_t size, int address);\r
64 static void Skip(size_t size);\r
65 static void CloseOld(void);\r
66 static void CloseNew(void);\r
67 static void CreateDummyScripts(void);\r
68 static void RecordDummyScripts(void);\r
69 \r
70 // EXTERNAL DATA DECLARATIONS ----------------------------------------------\r
71 \r
72 // PUBLIC DATA DEFINITIONS -------------------------------------------------\r
73 \r
74 int pc_Address;\r
75 byte *pc_Buffer;\r
76 byte *pc_BufferPtr;\r
77 int pc_ScriptCount;\r
78 int pc_FunctionCount;\r
79 boolean pc_NoShrink;\r
80 boolean pc_HexenCase;\r
81 boolean pc_EnforceHexen;\r
82 boolean pc_WarnNotHexen;\r
83 boolean pc_WadAuthor = TRUE;\r
84 boolean pc_EncryptStrings;\r
85 int pc_LastAppendedCommand;\r
86 int pc_DummyAddress;\r
87 \r
88 // PRIVATE DATA DEFINITIONS ------------------------------------------------\r
89 \r
90 static size_t BufferSize;\r
91 static boolean ObjectOpened = NO;\r
92 static scriptInfo_t ScriptInfo[MAX_SCRIPT_COUNT];\r
93 static functionInfo_t FunctionInfo[MAX_FUNCTION_COUNT];\r
94 static int ArraySizes[MAX_MAP_VARIABLES];\r
95 static int *ArrayInits[MAX_MAP_VARIABLES];\r
96 static boolean ArrayOfStrings[MAX_MAP_VARIABLES];\r
97 static int NumArrays;\r
98 static mapVarInfo_t MapVariables[MAX_MAP_VARIABLES];\r
99 static boolean MapVariablesInit = NO;\r
100 static char ObjectName[MAX_FILE_NAME_LENGTH];\r
101 static int ObjectFlags;\r
102 static int PushByteAddr;\r
103 static char Imports[MAX_IMPORTS][9];\r
104 static int NumImports;\r
105 static boolean HaveExtendedScripts;\r
106 \r
107 static char *PCDNames[PCODE_COMMAND_COUNT] =\r
108 {\r
109         "PCD_NOP",\r
110         "PCD_TERMINATE",\r
111         "PCD_SUSPEND",\r
112         "PCD_PUSHNUMBER",\r
113         "PCD_LSPEC1",\r
114         "PCD_LSPEC2",\r
115         "PCD_LSPEC3",\r
116         "PCD_LSPEC4",\r
117         "PCD_LSPEC5",\r
118         "PCD_LSPEC1DIRECT",\r
119         "PCD_LSPEC2DIRECT",\r
120         "PCD_LSPEC3DIRECT",\r
121         "PCD_LSPEC4DIRECT",\r
122         "PCD_LSPEC5DIRECT",\r
123         "PCD_ADD",\r
124         "PCD_SUBTRACT",\r
125         "PCD_MULTIPLY",\r
126         "PCD_DIVIDE",\r
127         "PCD_MODULUS",\r
128         "PCD_EQ",\r
129         "PCD_NE",\r
130         "PCD_LT",\r
131         "PCD_GT",\r
132         "PCD_LE",\r
133         "PCD_GE",\r
134         "PCD_ASSIGNSCRIPTVAR",\r
135         "PCD_ASSIGNMAPVAR",\r
136         "PCD_ASSIGNWORLDVAR",\r
137         "PCD_PUSHSCRIPTVAR",\r
138         "PCD_PUSHMAPVAR",\r
139         "PCD_PUSHWORLDVAR",\r
140         "PCD_ADDSCRIPTVAR",\r
141         "PCD_ADDMAPVAR",\r
142         "PCD_ADDWORLDVAR",\r
143         "PCD_SUBSCRIPTVAR",\r
144         "PCD_SUBMAPVAR",\r
145         "PCD_SUBWORLDVAR",\r
146         "PCD_MULSCRIPTVAR",\r
147         "PCD_MULMAPVAR",\r
148         "PCD_MULWORLDVAR",\r
149         "PCD_DIVSCRIPTVAR",\r
150         "PCD_DIVMAPVAR",\r
151         "PCD_DIVWORLDVAR",\r
152         "PCD_MODSCRIPTVAR",\r
153         "PCD_MODMAPVAR",\r
154         "PCD_MODWORLDVAR",\r
155         "PCD_INCSCRIPTVAR",\r
156         "PCD_INCMAPVAR",\r
157         "PCD_INCWORLDVAR",\r
158         "PCD_DECSCRIPTVAR",\r
159         "PCD_DECMAPVAR",\r
160         "PCD_DECWORLDVAR",\r
161         "PCD_GOTO",\r
162         "PCD_IFGOTO",\r
163         "PCD_DROP",\r
164         "PCD_DELAY",\r
165         "PCD_DELAYDIRECT",\r
166         "PCD_RANDOM",\r
167         "PCD_RANDOMDIRECT",\r
168         "PCD_THINGCOUNT",\r
169         "PCD_THINGCOUNTDIRECT",\r
170         "PCD_TAGWAIT",\r
171         "PCD_TAGWAITDIRECT",\r
172         "PCD_POLYWAIT",\r
173         "PCD_POLYWAITDIRECT",\r
174         "PCD_CHANGEFLOOR",\r
175         "PCD_CHANGEFLOORDIRECT",\r
176         "PCD_CHANGECEILING",\r
177         "PCD_CHANGECEILINGDIRECT",\r
178         "PCD_RESTART",\r
179         "PCD_ANDLOGICAL",\r
180         "PCD_ORLOGICAL",\r
181         "PCD_ANDBITWISE",\r
182         "PCD_ORBITWISE",\r
183         "PCD_EORBITWISE",\r
184         "PCD_NEGATELOGICAL",\r
185         "PCD_LSHIFT",\r
186         "PCD_RSHIFT",\r
187         "PCD_UNARYMINUS",\r
188         "PCD_IFNOTGOTO",\r
189         "PCD_LINESIDE",\r
190         "PCD_SCRIPTWAIT",\r
191         "PCD_SCRIPTWAITDIRECT",\r
192         "PCD_CLEARLINESPECIAL",\r
193         "PCD_CASEGOTO",\r
194         "PCD_BEGINPRINT",\r
195         "PCD_ENDPRINT",\r
196         "PCD_PRINTSTRING",\r
197         "PCD_PRINTNUMBER",\r
198         "PCD_PRINTCHARACTER",\r
199         "PCD_PLAYERCOUNT",\r
200         "PCD_GAMETYPE",\r
201         "PCD_GAMESKILL",\r
202         "PCD_TIMER",\r
203         "PCD_SECTORSOUND",\r
204         "PCD_AMBIENTSOUND",\r
205         "PCD_SOUNDSEQUENCE",\r
206         "PCD_SETLINETEXTURE",\r
207         "PCD_SETLINEBLOCKING",\r
208         "PCD_SETLINESPECIAL",\r
209         "PCD_THINGSOUND",\r
210         "PCD_ENDPRINTBOLD",\r
211 // [RH] End of Hexen p-codes\r
212         "PCD_ACTIVATORSOUND",\r
213         "PCD_LOCALAMBIENTSOUND",\r
214         "PCD_SETLINEMONSTERBLOCKING",\r
215 // [BC] Start of new pcodes\r
216         "PCD_PLAYERBLUESKULL",\r
217         "PCD_PLAYERREDSKULL",\r
218         "PCD_PLAYERYELLOWSKULL",\r
219         "PCD_PLAYERMASTERSKULL",\r
220         "PCD_PLAYERBLUECARD",\r
221         "PCD_PLAYERREDCARD",\r
222         "PCD_PLAYERYELLOWCARD",\r
223         "PCD_PLAYERMASTERCARD",\r
224         "PCD_PLAYERBLACKSKULL",\r
225         "PCD_PLAYERSILVERSKULL",\r
226         "PCD_PLAYERGOLDSKULL",\r
227         "PCD_PLAYERBLACKCARD",\r
228         "PCD_PLAYERSILVERCARD",\r
229         "PCD_PLAYERONTEAM",\r
230         "PCD_PLAYERTEAM",\r
231         "PCD_PLAYERHEALTH",\r
232         "PCD_PLAYERARMORPOINTS",\r
233         "PCD_PLAYERFRAGS",\r
234         "PCD_PLAYEREXPERT",\r
235         "PCD_BLUETEAMCOUNT",\r
236         "PCD_REDTEAMCOUNT",\r
237         "PCD_BLUETEAMSCORE",\r
238         "PCD_REDTEAMSCORE",\r
239         "PCD_ISONEFLAGCTF",\r
240         "PCD_LSPEC6",\r
241         "PCD_LSPEC6DIRECT",\r
242         "PCD_PRINTNAME",\r
243         "PCD_MUSICCHANGE",\r
244         "PCD_CONSOLECOMMANDDIRECT",\r
245         "PCD_CONSOLECOMMAND",\r
246         "PCD_SINGLEPLAYER",\r
247 // [RH] End of Skull Tag p-codes\r
248         "PCD_FIXEDMUL",\r
249         "PCD_FIXEDDIV",\r
250         "PCD_SETGRAVITY",\r
251         "PCD_SETGRAVITYDIRECT",\r
252         "PCD_SETAIRCONTROL",\r
253         "PCD_SETAIRCONTROLDIRECT",\r
254         "PCD_CLEARINVENTORY",\r
255         "PCD_GIVEINVENTORY",\r
256         "PCD_GIVEINVENTORYDIRECT",\r
257         "PCD_TAKEINVENTORY",\r
258         "PCD_TAKEINVENTORYDIRECT",\r
259         "PCD_CHECKINVENTORY",\r
260         "PCD_CHECKINVENTORYDIRECT",\r
261         "PCD_SPAWN",\r
262         "PCD_SPAWNDIRECT",\r
263         "PCD_SPAWNSPOT",\r
264         "PCD_SPAWNSPOTDIRECT",\r
265         "PCD_SETMUSIC",\r
266         "PCD_SETMUSICDIRECT",\r
267         "PCD_LOCALSETMUSIC",\r
268         "PCD_LOCALSETMUSICDIRECT",\r
269         "PCD_PRINTFIXED",\r
270         "PCD_PRINTLOCALIZED",\r
271         "PCD_MOREHUDMESSAGE",\r
272         "PCD_OPTHUDMESSAGE",\r
273         "PCD_ENDHUDMESSAGE",\r
274         "PCD_ENDHUDMESSAGEBOLD",\r
275         "PCD_SETSTYLE",\r
276         "PCD_SETSTYLEDIRECT",\r
277         "PCD_SETFONT",\r
278         "PCD_SETFONTDIRECT",\r
279         "PCD_PUSHBYTE",\r
280         "PCD_LSPEC1DIRECTB",\r
281         "PCD_LSPEC2DIRECTB",\r
282         "PCD_LSPEC3DIRECTB",\r
283         "PCD_LSPEC4DIRECTB",\r
284         "PCD_LSPEC5DIRECTB",\r
285         "PCD_DELAYDIRECTB",\r
286         "PCD_RANDOMDIRECTB",\r
287         "PCD_PUSHBYTES",\r
288         "PCD_PUSH2BYTES",\r
289         "PCD_PUSH3BYTES",\r
290         "PCD_PUSH4BYTES",\r
291         "PCD_PUSH5BYTES",\r
292         "PCD_SETTHINGSPECIAL",\r
293         "PCD_ASSIGNGLOBALVAR",\r
294         "PCD_PUSHGLOBALVAR",\r
295         "PCD_ADDGLOBALVAR",\r
296         "PCD_SUBGLOBALVAR",\r
297         "PCD_MULGLOBALVAR",\r
298         "PCD_DIVGLOBALVAR",\r
299         "PCD_MODGLOBALVAR",\r
300         "PCD_INCGLOBALVAR",\r
301         "PCD_DECGLOBALVAR",\r
302         "PCD_FADETO",\r
303         "PCD_FADERANGE",\r
304         "PCD_CANCELFADE",\r
305         "PCD_PLAYMOVIE",\r
306         "PCD_SETFLOORTRIGGER",\r
307         "PCD_SETCEILINGTRIGGER",\r
308         "PCD_GETACTORX",\r
309         "PCD_GETACTORY",\r
310         "PCD_GETACTORZ",\r
311         "PCD_STARTTRANSLATION",\r
312         "PCD_TRANSLATIONRANGE1",\r
313         "PCD_TRANSLATIONRANGE2",\r
314         "PCD_ENDTRANSLATION",\r
315         "PCD_CALL",\r
316         "PCD_CALLDISCARD",\r
317         "PCD_RETURNVOID",\r
318         "PCD_RETURNVAL",\r
319         "PCD_PUSHMAPARRAY",\r
320         "PCD_ASSIGNMAPARRAY",\r
321         "PCD_ADDMAPARRAY",\r
322         "PCD_SUBMAPARRAY",\r
323         "PCD_MULMAPARRAY",\r
324         "PCD_DIVMAPARRAY",\r
325         "PCD_MODMAPARRAY",\r
326         "PCD_INCMAPARRAY",\r
327         "PCD_DECMAPARRAY",\r
328         "PCD_DUP",\r
329         "PCD_SWAP",\r
330         "PCD_WRITETOINI",\r
331         "PCD_GETFROMINI",\r
332         "PCD_SIN",\r
333         "PCD_COS",\r
334         "PCD_VECTORANGLE",\r
335         "PCD_CHECKWEAPON",\r
336         "PCD_SETWEAPON",\r
337         "PCD_TAGSTRING",\r
338         "PCD_PUSHWORLDARRAY",\r
339         "PCD_ASSIGNWORLDARRAY",\r
340         "PCD_ADDWORLDARRAY",\r
341         "PCD_SUBWORLDARRAY",\r
342         "PCD_MULWORLDARRAY",\r
343         "PCD_DIVWORLDARRAY",\r
344         "PCD_MODWORLDARRAY",\r
345         "PCD_INCWORLDARRAY",\r
346         "PCD_DECWORLDARRAY",\r
347         "PCD_PUSHGLOBALARRAY",\r
348         "PCD_ASSIGNGLOBALARRAY",\r
349         "PCD_ADDGLOBALARRAY",\r
350         "PCD_SUBGLOBALARRAY",\r
351         "PCD_MULGLOBALARRAY",\r
352         "PCD_DIVGLOBALARRAY",\r
353         "PCD_MODGLOBALARRAY",\r
354         "PCD_INCGLOBALARRAY",\r
355         "PCD_DECGLOBALARRAY",\r
356         "PCD_SETMARINEWEAPON",\r
357         "PCD_SETACTORPROPERTY",\r
358         "PCD_GETACTORPROPERTY",\r
359         "PCD_PLAYERNUMBER",\r
360         "PCD_ACTIVATORTID",\r
361         "PCD_SETMARINESPRITE",\r
362         "PCD_GETSCREENWIDTH",\r
363         "PCD_GETSCREENHEIGHT",\r
364         "PCD_THING_PROJECTILE2",\r
365         "PCD_STRLEN",\r
366         "PCD_SETHUDSIZE",\r
367         "PCD_GETCVAR",\r
368         "PCD_CASEGOTOSORTED",\r
369         "PCD_SETRESULTVALUE",\r
370         "PCD_GETLINEROWOFFSET",\r
371         "PCD_GETACTORFLOORZ",\r
372         "PCD_GETACTORANGLE",\r
373         "PCD_GETSECTORFLOORZ",\r
374         "PCD_GETSECTORCEILINGZ",\r
375         "PCD_LSPEC5RESULT",\r
376         "PCD_GETSIGILPIECES",\r
377         "PCD_GELEVELINFO",\r
378         "PCD_CHANGESKY",\r
379         "PCD_PLAYERINGAME",\r
380         "PCD_PLAYERISBOT",\r
381         "PCD_SETCAMERATOTEXTURE",\r
382         "PCD_ENDLOG",\r
383         "PCD_GETAMMOCAPACITY",\r
384         "PCD_SETAMMOCAPACITY",\r
385 // [JB] start of new pcodes\r
386         "PCD_PRINTMAPCHARARRAY",\r
387         "PCD_PRINTWORLDCHARARRAY",\r
388         "PCD_PRINTGLOBALCHARARRAY",\r
389 // [JB] end of new pcodes\r
390         "PCD_SETACTORANGLE",\r
391         "PCD_GRABINPUT",\r
392         "PCD_SETMOUSEPOINTER",\r
393         "PCD_MOVEMOUSEPOINTER",\r
394         "PCD_SPAWNPROJECTILE",\r
395         "PCD_GETSECTORLIGHTLEVEL",\r
396         "PCD_GETACTORCEILINGZ",\r
397         "PCD_SETACTORPOSITION",\r
398         "PCD_CLEARACTORINVENTORY",\r
399         "PCD_GIVEACTORINVENTORY",\r
400         "PCD_TAKEACTORINVENTORY",\r
401         "PCD_CHECKACTORINVENTORY",\r
402         "PCD_THINGCOUNTNAME",\r
403         "PCD_SPAWNSPOTFACING",\r
404         "PCD_PLAYERCLASS",\r
405         //[MW] start my p-codes\r
406         "PCD_ANDSCRIPTVAR",\r
407         "PCD_ANDMAPVAR", \r
408         "PCD_ANDWORLDVAR", \r
409         "PCD_ANDGLOBALVAR", \r
410         "PCD_ANDMAPARRAY", \r
411         "PCD_ANDWORLDARRAY", \r
412         "PCD_ANDGLOBALARRAY",\r
413         "PCD_EORSCRIPTVAR", \r
414         "PCD_EORMAPVAR", \r
415         "PCD_EORWORLDVAR", \r
416         "PCD_EORGLOBALVAR", \r
417         "PCD_EORMAPARRAY", \r
418         "PCD_EORWORLDARRAY", \r
419         "PCD_EORGLOBALARRAY",\r
420         "PCD_ORSCRIPTVAR", \r
421         "PCD_ORMAPVAR", \r
422         "PCD_ORWORLDVAR", \r
423         "PCD_ORGLOBALVAR", \r
424         "PCD_ORMAPARRAY", \r
425         "PCD_ORWORLDARRAY", \r
426         "PCD_ORGLOBALARRAY",\r
427         "PCD_LSSCRIPTVAR", \r
428         "PCD_LSMAPVAR", \r
429         "PCD_LSWORLDVAR", \r
430         "PCD_LSGLOBALVAR", \r
431         "PCD_LSMAPARRAY", \r
432         "PCD_LSWORLDARRAY", \r
433         "PCD_LSGLOBALARRAY",\r
434         "PCD_RSSCRIPTVAR", \r
435         "PCD_RSMAPVAR", \r
436         "PCD_RSWORLDVAR", \r
437         "PCD_RSGLOBALVAR", \r
438         "PCD_RSMAPARRAY", \r
439         "PCD_RSWORLDARRAY", \r
440         "PCD_RSGLOBALARRAY", \r
441         //[MW] end my p-codes\r
442         "PCD_GETPLAYERINFO",\r
443         "PCD_CHANGELEVEL",\r
444         "PCD_SECTORDAMAGE",\r
445         "PCD_REPLACETEXTURES",\r
446         "PCD_NEGATEBINARY",\r
447         "PCD_GETACTORPITCH",\r
448         "PCD_SETACTORPITCH",\r
449         "PCD_PRINTBIND",\r
450         "PCD_SETACTORSTATE",\r
451         "PCD_THINGDAMAGE2",\r
452         "PCD_USEINVENTORY",\r
453         "PCD_USEACTORINVENTORY",\r
454         "PCD_CHECKACTORCEILINGTEXTURE",\r
455         "PCD_CHECKACTORFLOORTEXTURE",\r
456         "PCD_GETACTORLIGHTLEVEL",\r
457         "PCD_SETMUGSHOTSTATE",\r
458         "PCD_THINGCOUNTSECTOR",\r
459         "PCD_THINGCOUNTNAMESECTOR",\r
460         "PCD_CHECKPLAYERCAMERA",\r
461         "PCD_MORPHACTOR",\r
462         "PCD_UNMORPHACTOR",\r
463         "PCD_GETPLAYERINPUT",\r
464         "PCD_CLASSIFYACTOR",\r
465         "PCD_PRINTBINARY",\r
466         "PCD_PRINTHEX",\r
467         "PCD_CALLFUNC",\r
468         "PCD_SAVESTRING",               // [FDARI]\r
469 };\r
470 \r
471 // CODE --------------------------------------------------------------------\r
472 \r
473 //==========================================================================\r
474 //\r
475 // PC_OpenObject\r
476 //\r
477 //==========================================================================\r
478 \r
479 void PC_OpenObject(char *name, size_t size, int flags)\r
480 {\r
481         if(ObjectOpened == YES)\r
482         {\r
483                 PC_CloseObject();\r
484         }\r
485         if(strlen(name) >= MAX_FILE_NAME_LENGTH)\r
486         {\r
487                 ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name);\r
488         }\r
489         strcpy(ObjectName, name);\r
490         pc_Buffer = MS_Alloc(size, ERR_ALLOC_PCODE_BUFFER);\r
491         pc_BufferPtr = pc_Buffer;\r
492         pc_Address = 0;\r
493         ObjectFlags = flags;\r
494         BufferSize = size;\r
495         pc_ScriptCount = 0;\r
496         ObjectOpened = YES;\r
497         PC_AppendString("ACS");\r
498         PC_SkipInt(); // Script table offset\r
499 }\r
500 \r
501 //==========================================================================\r
502 //\r
503 // PC_CloseObject\r
504 //\r
505 //==========================================================================\r
506 \r
507 void PC_CloseObject(void)\r
508 {\r
509         MS_Message(MSG_DEBUG, "---- PC_CloseObject ----\n");\r
510         while (pc_Address & 3)\r
511         {\r
512                 PC_AppendByte (0);\r
513         }\r
514         if(!pc_NoShrink || (NumLanguages > 1) || (NumStringLists > 0) ||\r
515                 (pc_FunctionCount > 0) || MapVariablesInit || NumArrays != 0 ||\r
516                 pc_EncryptStrings || NumImports != 0 || HaveExtendedScripts)\r
517         {\r
518                 if(pc_EnforceHexen)\r
519                 {\r
520                         ERR_Exit(ERR_NOT_HEXEN, NO);\r
521                 }\r
522                 if(pc_WarnNotHexen)\r
523                 {\r
524                         fprintf(stderr, "\nThese scripts have been upgraded because they use new features.\n"\r
525                                                         "They will not be compatible with Hexen.\n");\r
526                 }\r
527                 CloseNew();\r
528         }\r
529         else\r
530         {\r
531                 CloseOld();\r
532         }\r
533         if(MS_SaveFile(ObjectName, pc_Buffer, pc_Address) == FALSE)\r
534         {\r
535                 ERR_Exit(ERR_SAVE_OBJECT_FAILED, NO);\r
536         }\r
537 }\r
538 \r
539 //==========================================================================\r
540 //\r
541 // CloseOld\r
542 //\r
543 //==========================================================================\r
544 \r
545 static void CloseOld(void)\r
546 {\r
547         int i;\r
548 \r
549         STR_WriteStrings();\r
550         PC_WriteInt((U_INT)pc_Address, 4);\r
551         PC_AppendInt((U_INT)pc_ScriptCount);\r
552         for(i = 0; i < pc_ScriptCount; ++i)\r
553         {\r
554                 scriptInfo_t *info = &ScriptInfo[i];\r
555                 MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",\r
556                         info->number, info->address, info->argCount);\r
557                 PC_AppendInt((U_INT)(info->number + info->type * 1000));\r
558                 PC_AppendInt((U_INT)info->address);\r
559                 PC_AppendInt((U_INT)info->argCount);\r
560         }\r
561         STR_WriteList();\r
562 }\r
563 \r
564 //==========================================================================\r
565 //\r
566 // CloseNew\r
567 //\r
568 // Creates a new-format ACS file. For programs that don't know any better,\r
569 // this will look just like an old ACS file with no scripts or strings but\r
570 // with some extra junk in the middle. Both WadAuthor and DeePsea will not\r
571 // accept ACS files that do not have the ACS\0 header. Worse, WadAuthor\r
572 // will hang if the file begins with ACS\0 but does not look like something\r
573 // that might have been created with Raven's ACC. Thus, the chunks live in\r
574 // the string block, and there are two 0 dwords at the end of the file.\r
575 //\r
576 //==========================================================================\r
577 \r
578 static void CloseNew(void)\r
579 {\r
580         int i, j, count;\r
581         int chunkStart;\r
582 \r
583         if(pc_WadAuthor)\r
584         {\r
585                 CreateDummyScripts();\r
586         }\r
587 \r
588         chunkStart = pc_Address;\r
589 \r
590         // Only write out those scripts that this acs file actually provides.\r
591         for(i = j = 0; i < pc_ScriptCount; ++i)\r
592         {\r
593                 if(!ScriptInfo[i].imported)\r
594                 {\r
595                         ++j;\r
596                 }\r
597         }\r
598         if(j > 0)\r
599         {\r
600                 PC_Append("SPTR", 4);\r
601                 PC_AppendInt(j * 8);\r
602                 for(i = 0; i < pc_ScriptCount; i++)\r
603                 {\r
604                         scriptInfo_t *info = &ScriptInfo[i];\r
605                         if(!info->imported)\r
606                         {\r
607                                 MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",\r
608                                         info->number, info->address, info->argCount);\r
609                                 PC_AppendWord(info->number);\r
610                                 PC_AppendByte(info->type);\r
611                                 PC_AppendByte(info->argCount);\r
612                                 PC_AppendInt((U_INT)info->address);\r
613                         }\r
614                 }\r
615         }\r
616 \r
617         // If any scripts have more than the maximum number of arguments, output them.\r
618         for(i = j = 0; i < pc_ScriptCount; ++i)\r
619         {\r
620                 if(!ScriptInfo[i].imported && ScriptInfo[i].varCount > MAX_SCRIPT_VARIABLES)\r
621                 {\r
622                         ++j;\r
623                 }\r
624         }\r
625         if(j > 0)\r
626         {\r
627                 PC_Append("SVCT", 4);\r
628                 PC_AppendInt(j * 4);\r
629                 for(i = 0; i < pc_ScriptCount; ++i)\r
630                 {\r
631                         scriptInfo_t *info = &ScriptInfo[i];\r
632                         if(!info->imported && info->varCount > MAX_SCRIPT_VARIABLES)\r
633                         {\r
634                                 MS_Message(MSG_DEBUG, "Script %d, var count = %d\n",\r
635                                         info->number, info->varCount);\r
636                                 PC_AppendWord(info->number);\r
637                                 PC_AppendWord(info->varCount);\r
638                         }\r
639                 }\r
640         }\r
641 \r
642         // Write script flags in a separate chunk, so older ZDooms don't get confused\r
643         for(i = j = 0; i < pc_ScriptCount; ++i)\r
644         {\r
645                 if(!ScriptInfo[i].imported && ScriptInfo[i].flags != 0)\r
646                 {\r
647                         ++j;\r
648                 }\r
649         }\r
650         if (j > 0)\r
651         {\r
652                 PC_Append("SFLG", 4);\r
653                 PC_AppendInt(j * 4);\r
654                 for(i = 0; i < pc_ScriptCount; ++i)\r
655                 {\r
656                         scriptInfo_t *info = &ScriptInfo[i];\r
657                         if(!info->imported && info->flags != 0)\r
658                         {\r
659                                 PC_AppendWord(info->number);\r
660                                 PC_AppendWord(info->flags);\r
661                         }\r
662                 }\r
663         }\r
664 \r
665         // Write the string table for named scripts.\r
666         STR_WriteListChunk(STRLIST_NAMEDSCRIPTS, MAKE4CC('S','N','A','M'), NO);\r
667 \r
668         if(pc_FunctionCount > 0)\r
669         {\r
670                 PC_Append("FUNC", 4);\r
671                 PC_AppendInt(pc_FunctionCount * 8);\r
672                 for(i = 0; i < pc_FunctionCount; ++i)\r
673                 {\r
674                         functionInfo_t *info = &FunctionInfo[i];\r
675                         MS_Message(MSG_DEBUG, "Function %d:%s, address = %d, arg count = %d, var count = %d\n",\r
676                                 i, STR_GetString(STRLIST_FUNCTIONS, info->name),\r
677                                 info->address, info->argCount, info->localCount);\r
678                         PC_AppendByte(info->argCount);\r
679                         PC_AppendByte(info->localCount);\r
680                         PC_AppendByte((U_BYTE)(info->hasReturnValue?1:0));\r
681                         PC_AppendByte(0);\r
682                         PC_AppendInt((U_INT)info->address);\r
683                 }\r
684                 STR_WriteListChunk(STRLIST_FUNCTIONS, MAKE4CC('F','N','A','M'), NO);\r
685         }\r
686 \r
687         if(NumLanguages > 1)\r
688         {\r
689                 for(i = 0; i < NumLanguages; i++)\r
690                 {\r
691                         STR_WriteChunk(i, pc_EncryptStrings);\r
692                 }\r
693         }\r
694         else if(STR_ListSize(0) > 0)\r
695         {\r
696                 STR_WriteChunk(0, pc_EncryptStrings);\r
697         }\r
698 \r
699         STR_WriteListChunk(STRLIST_PICS, MAKE4CC('P','I','C','S'), NO);\r
700         if(MapVariablesInit)\r
701         {\r
702                 int j;\r
703 \r
704                 for(i = 0; i < pa_MapVarCount; ++i)\r
705                 {\r
706                         if(MapVariables[i].initializer != 0)\r
707                                 break;\r
708                 }\r
709                 for(j = pa_MapVarCount-1; j > i; --j)\r
710                 {\r
711                         if(MapVariables[j].initializer != 0)\r
712                                 break;\r
713                 }\r
714                 ++j;\r
715 \r
716                 if (i < j)\r
717                 {\r
718                         PC_Append("MINI", 4);\r
719                         PC_AppendInt((j-i)*4+4);\r
720                         PC_AppendInt(i);                                                // First map var defined\r
721                         for(; i < j; ++i)\r
722                         {\r
723                                 PC_AppendInt(MapVariables[i].initializer);\r
724                         }\r
725                 }\r
726         }\r
727 \r
728         // If this is a library, record which map variables are\r
729         // initialized with strings.\r
730         if(ImportMode == IMPORT_Exporting)\r
731         {\r
732                 count = 0;\r
733 \r
734                 for(i = 0; i < pa_MapVarCount; ++i)\r
735                 {\r
736                         if(MapVariables[i].isString)\r
737                         {\r
738                                 ++count;\r
739                         }\r
740                 }\r
741                 if(count > 0)\r
742                 {\r
743                         PC_Append("MSTR", 4);\r
744                         PC_AppendInt(count*4);\r
745                         for(i = 0; i < pa_MapVarCount; ++i)\r
746                         {\r
747                                 if(MapVariables[i].isString)\r
748                                 {\r
749                                         PC_AppendInt(i);\r
750                                 }\r
751                         }\r
752                 }\r
753 \r
754                 // Now do the same thing for arrays.\r
755                 for(count = 0, i = 0; i < pa_MapVarCount; ++i)\r
756                 {\r
757                         if(ArrayOfStrings[i])\r
758                         {\r
759                                 ++count;\r
760                         }\r
761                 }\r
762                 if(count > 0)\r
763                 {\r
764                         PC_Append("ASTR", 4);\r
765                         PC_AppendInt(count*4);\r
766                         for(i = 0; i < pa_MapVarCount; ++i)\r
767                         {\r
768                                 if(ArrayOfStrings[i])\r
769                                 {\r
770                                         PC_AppendInt(i);\r
771                                 }\r
772                         }\r
773                 }\r
774         }\r
775 \r
776         // Publicize the names of map variables in a library.\r
777         if(ImportMode == IMPORT_Exporting)\r
778         {\r
779                 for(i = 0; i < pa_MapVarCount; ++i)\r
780                 {\r
781                         if(!MapVariables[i].imported)\r
782                         {\r
783                                 STR_AppendToList(STRLIST_MAPVARS, MapVariables[i].name);\r
784                         }\r
785                         else\r
786                         {\r
787                                 STR_AppendToList(STRLIST_MAPVARS, NULL);\r
788                         }\r
789                 }\r
790                 STR_WriteListChunk(STRLIST_MAPVARS, MAKE4CC('M','E','X','P'), NO);\r
791         }\r
792 \r
793         // Record the names of imported map variables\r
794         count = 0;\r
795         for(i = 0; i < pa_MapVarCount; ++i)\r
796         {\r
797                 if(MapVariables[i].imported && !ArraySizes[i])\r
798                 {\r
799                         count += 5 + strlen(MapVariables[i].name);\r
800                 }\r
801         }\r
802         if(count > 0)\r
803         {\r
804                 PC_Append("MIMP", 4);\r
805                 PC_AppendInt(count);\r
806                 for(i = 0; i < pa_MapVarCount; ++i)\r
807                 {\r
808                         if(MapVariables[i].imported && !ArraySizes[i])\r
809                         {\r
810                                 PC_AppendInt(i);\r
811                                 PC_AppendString(MapVariables[i].name);\r
812                         }\r
813                 }\r
814         }\r
815 \r
816         if(NumArrays)\r
817         {\r
818                 int count;\r
819 \r
820                 // Arrays defined here\r
821                 for(count = 0, i = 0; i < pa_MapVarCount; ++i)\r
822                 {\r
823                         if(ArraySizes[i] && !MapVariables[i].imported)\r
824                         {\r
825                                 ++count;\r
826                         }\r
827                 }\r
828                 if(count)\r
829                 {\r
830                         PC_Append("ARAY", 4);\r
831                         PC_AppendInt(count*8);\r
832                         for(i = 0; i < pa_MapVarCount; ++i)\r
833                         {\r
834                                 if(ArraySizes[i] && !MapVariables[i].imported)\r
835                                 {\r
836                                         PC_AppendInt(i);\r
837                                         PC_AppendInt(ArraySizes[i]);\r
838                                 }\r
839                         }\r
840                         for(i = 0; i < pa_MapVarCount; ++i)\r
841                         {\r
842                                 if(ArrayInits[i])\r
843                                 {\r
844                                         int j;\r
845 \r
846                                         PC_Append("AINI", 4);\r
847                                         PC_AppendInt(ArraySizes[i]*4+4);\r
848                                         PC_AppendInt((U_INT)i);\r
849                                         MS_Message(MSG_DEBUG, "Writing array initializers for array %d (size %d)\n", i, ArraySizes[i]);\r
850                                         for(j = 0; j < ArraySizes[i]; ++j)\r
851                                         {\r
852                                                 PC_AppendInt((U_INT)ArrayInits[i][j]);\r
853                                         }\r
854                                 }\r
855                         }\r
856                 }\r
857 \r
858                 // Arrays imported from elsewhere\r
859                 for(count = 0, j = i = 0; i < pa_MapVarCount; ++i)\r
860                 {\r
861                         if(ArraySizes[i] && MapVariables[i].imported)\r
862                         {\r
863                                 count += 9 + strlen(MapVariables[i].name);\r
864                                 ++j;\r
865                         }\r
866                 }\r
867                 if(count)\r
868                 {\r
869                         PC_Append("AIMP", 4);\r
870                         PC_AppendInt(count+4);\r
871                         PC_AppendInt(j);\r
872                         for(i = 0; i < pa_MapVarCount; ++i)\r
873                         {\r
874                                 if(ArraySizes[i] && MapVariables[i].imported)\r
875                                 {\r
876                                         PC_AppendInt(i);\r
877                                         PC_AppendInt(ArraySizes[i]);\r
878                                         PC_AppendString(MapVariables[i].name);\r
879                                 }\r
880                         }\r
881                 }\r
882         }\r
883 \r
884         // Add a dummy chunk to indicate if this object is a library.\r
885         if(ImportMode == IMPORT_Exporting)\r
886         {\r
887                 PC_Append("ALIB", 4);\r
888                 PC_AppendInt(0);\r
889         }\r
890 \r
891         // Record libraries imported by this object.\r
892         if(NumImports > 0)\r
893         {\r
894                 count = 0;\r
895                 for(i = 0; i < NumImports; ++i)\r
896                 {\r
897                         count += strlen(Imports[i]) + 1;\r
898                 }\r
899                 if(count > 0)\r
900                 {\r
901                         PC_Append("LOAD", 4);\r
902                         PC_AppendInt(count);\r
903                         for(i = 0; i < NumImports; ++i)\r
904                         {\r
905                                 PC_AppendString(Imports[i]);\r
906                         }\r
907                 }\r
908         }\r
909 \r
910         PC_AppendInt((U_INT)chunkStart);\r
911         if(pc_NoShrink)\r
912         {\r
913                 PC_Append("ACSE", 4);\r
914         }\r
915         else\r
916         {\r
917                 PC_Append("ACSe", 4);\r
918         }\r
919         PC_WriteInt((U_INT)pc_Address, 4);\r
920 \r
921         // WadAuthor compatibility when creating a library is pointless, because\r
922         // that editor does not know anything about libraries and will never\r
923         // find their scripts ever.\r
924         if(pc_WadAuthor && ImportMode != IMPORT_Exporting)\r
925         {\r
926                 RecordDummyScripts();\r
927         }\r
928         else\r
929         {\r
930                 PC_AppendInt(0);\r
931         }\r
932         PC_AppendInt(0);\r
933 }\r
934 \r
935 //==========================================================================\r
936 //\r
937 // CreateDummyScripts\r
938 //\r
939 //==========================================================================\r
940 \r
941 static void CreateDummyScripts(void)\r
942 {\r
943         int i;\r
944 \r
945         MS_Message(MSG_DEBUG, "Creating dummy scripts to make WadAuthor happy.\n");\r
946         if(pc_Address%4 != 0)\r
947         { // Need to align\r
948                 U_INT pad = 0;\r
949                 PC_Append((void *)&pad, 4-(pc_Address%4));\r
950         }\r
951         pc_DummyAddress = pc_Address;\r
952         for(i = 0; i < pc_ScriptCount; ++i)\r
953         {\r
954                 // Only create dummies for scripts WadAuthor could care about.\r
955                 if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)\r
956                 {\r
957                         PC_AppendCmd(PCD_TERMINATE);\r
958                         if(!pc_NoShrink)\r
959                         {\r
960                                 PC_AppendCmd(PCD_NOP);\r
961                                 PC_AppendCmd(PCD_NOP);\r
962                                 PC_AppendCmd(PCD_NOP);\r
963                         }\r
964                 }\r
965         }\r
966 }\r
967 \r
968 //==========================================================================\r
969 //\r
970 // RecordDummyScripts\r
971 //\r
972 //==========================================================================\r
973 \r
974 static void RecordDummyScripts(void)\r
975 {\r
976         int i, j, count;\r
977 \r
978         for(i = count = 0; i < pc_ScriptCount; ++i)\r
979         {\r
980                 if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)\r
981                 {\r
982                         ++count;\r
983                 }\r
984         }\r
985         PC_AppendInt((U_INT)count);\r
986         for(i = j = 0; i < pc_ScriptCount; ++i)\r
987         {\r
988                 scriptInfo_t *info = &ScriptInfo[i];\r
989                 if(!info->imported && info->number >= 0 && ScriptInfo[i].number <= 255)\r
990                 {\r
991                         MS_Message(MSG_DEBUG, "Dummy script %d, address = %d, arg count = %d\n",\r
992                                 info->number, info->address, info->argCount);\r
993                         PC_AppendInt((U_INT)info->number);\r
994                         PC_AppendInt((U_INT)pc_DummyAddress + j*4);\r
995                         PC_AppendInt((U_INT)info->argCount);\r
996                         j++;\r
997                 }\r
998         }\r
999 }\r
1000 \r
1001 //==========================================================================\r
1002 //\r
1003 // GrowBuffer\r
1004 //\r
1005 //==========================================================================\r
1006 \r
1007 void GrowBuffer(void)\r
1008 {\r
1009         ptrdiff_t buffpos = pc_BufferPtr - pc_Buffer;\r
1010 \r
1011         BufferSize *= 2;\r
1012         pc_Buffer = MS_Realloc(pc_Buffer, BufferSize, ERR_PCODE_BUFFER_OVERFLOW);\r
1013         pc_BufferPtr = pc_Buffer + buffpos;\r
1014 }\r
1015 \r
1016 //==========================================================================\r
1017 //\r
1018 // PC_Append functions\r
1019 //\r
1020 //==========================================================================\r
1021 \r
1022 static void Append(void *buffer, size_t size)\r
1023 {\r
1024         if (ImportMode != IMPORT_Importing)\r
1025         {\r
1026                 if(pc_Address+size > BufferSize)\r
1027                 {\r
1028                         GrowBuffer ();\r
1029                 }\r
1030                 memcpy(pc_BufferPtr, buffer, size);\r
1031                 pc_BufferPtr += size;\r
1032                 pc_Address += size;\r
1033         }\r
1034 }\r
1035 \r
1036 void PC_Append(void *buffer, size_t size)\r
1037 {\r
1038         if (ImportMode != IMPORT_Importing)\r
1039         {\r
1040                 MS_Message(MSG_DEBUG, "AD> %06d = (%d bytes)\n", pc_Address, size);\r
1041                 Append(buffer, size);\r
1042         }\r
1043 }\r
1044 \r
1045 void PC_AppendByte(U_BYTE val)\r
1046 {\r
1047         if (ImportMode != IMPORT_Importing)\r
1048         {\r
1049                 MS_Message(MSG_DEBUG, "AB> %06d = %d\n", pc_Address, val);\r
1050                 Append(&val, sizeof(U_BYTE));\r
1051         }\r
1052 }\r
1053 \r
1054 void PC_AppendWord(U_WORD val)\r
1055 {\r
1056         if (ImportMode != IMPORT_Importing)\r
1057         {\r
1058                 MS_Message(MSG_DEBUG, "AW> %06d = %d\n", pc_Address, val);\r
1059                 val = MS_LittleUWORD(val);\r
1060                 Append(&val, sizeof(U_WORD));\r
1061         }\r
1062 }\r
1063 \r
1064 void PC_AppendInt(U_INT val)\r
1065 {\r
1066         if (ImportMode != IMPORT_Importing)\r
1067         {\r
1068                 MS_Message(MSG_DEBUG, "AL> %06d = %d\n", pc_Address, val);\r
1069                 val = MS_LittleUINT(val);\r
1070                 Append(&val, sizeof(U_INT));\r
1071         }\r
1072 }\r
1073 \r
1074 void PC_AppendString(char *string)\r
1075 {\r
1076         if (ImportMode != IMPORT_Importing)\r
1077         {\r
1078                 int length;\r
1079 \r
1080                 length = strlen(string)+1;\r
1081                 MS_Message(MSG_DEBUG, "AS> %06d = \"%s\" (%d bytes)\n",\r
1082                         pc_Address, string, length);\r
1083                 Append(string, length);\r
1084         }\r
1085 }\r
1086 \r
1087 void PC_AppendCmd(pcd_t command)\r
1088 {\r
1089         if (ImportMode != IMPORT_Importing)\r
1090         {\r
1091                 pc_LastAppendedCommand = command;\r
1092                 if (pc_NoShrink)\r
1093                 {\r
1094                         MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,\r
1095                                 command, PCDNames[command]);\r
1096                         command = MS_LittleUINT(command);\r
1097                         Append(&command, sizeof(U_INT));\r
1098                 }\r
1099                 else\r
1100                 {\r
1101                         U_BYTE cmd;\r
1102                         if (command != PCD_PUSHBYTE && PushByteAddr)\r
1103                         { // Maybe shrink a PCD_PUSHBYTE sequence into PCD_PUSHBYTES\r
1104                                 int runlen = (pc_Address - PushByteAddr) / 2;\r
1105                                 int i;\r
1106 \r
1107                                 if (runlen > 5)\r
1108                                 {\r
1109                                         pc_Buffer[PushByteAddr] = PCD_PUSHBYTES;\r
1110                                         for (i = 0; i < runlen; i++)\r
1111                                         {\r
1112                                                 pc_Buffer[PushByteAddr+i+2] = pc_Buffer[PushByteAddr+i*2+1];\r
1113                                         }\r
1114                                         pc_Buffer[PushByteAddr+1] = runlen;\r
1115                                         pc_Address = PushByteAddr + runlen + 2;\r
1116                                         pc_BufferPtr = pc_Buffer + pc_Address;\r
1117                                         MS_Message (MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSHBYTES\n",\r
1118                                                 runlen, PCD_PUSHBYTES);\r
1119                                 }\r
1120                                 else if (runlen > 1)\r
1121                                 {\r
1122                                         pc_Buffer[PushByteAddr] = PCD_PUSH2BYTES + runlen - 2;\r
1123                                         for (i = 1; i < runlen; i++)\r
1124                                         {\r
1125                                                 pc_Buffer[PushByteAddr+1+i] = pc_Buffer[PushByteAddr+1+i*2];\r
1126                                         }\r
1127                                         pc_Address = PushByteAddr + runlen + 1;\r
1128                                         pc_BufferPtr = pc_Buffer + pc_Address;\r
1129                                         MS_Message (MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSH%dBYTES\n",\r
1130                                                 runlen, PCD_PUSH2BYTES+runlen-2, runlen);\r
1131                                 }\r
1132                                 PushByteAddr = 0;\r
1133                         }\r
1134                         else if (command == PCD_PUSHBYTE && PushByteAddr == 0)\r
1135                         { // Remember the first PCD_PUSHBYTE, in case there are more\r
1136                                 PushByteAddr = pc_Address;\r
1137                         }\r
1138                         MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,\r
1139                                 command, PCDNames[command]);\r
1140 \r
1141                         if (command < 256-16)\r
1142                         {\r
1143                                 cmd = command;\r
1144                                 Append(&cmd, sizeof(U_BYTE));\r
1145                         }\r
1146                         else\r
1147                         {\r
1148                                 // Room for expansion: The top 16 pcodes in the [0,255]\r
1149                                 // range select a set of pcodes, and the next byte is\r
1150                                 // the pcode in that set.\r
1151                                 cmd = ((command - (256-16)) >> 8) + (256-16);\r
1152                                 Append(&cmd, sizeof(U_BYTE));\r
1153                                 cmd = (command - (256-16)) & 255;\r
1154                                 Append(&cmd, sizeof(U_BYTE));\r
1155                         }\r
1156                 }\r
1157         }\r
1158 }\r
1159 \r
1160 //==========================================================================\r
1161 //\r
1162 // PC_AppendShrink\r
1163 //\r
1164 //==========================================================================\r
1165 \r
1166 void PC_AppendShrink(U_BYTE val)\r
1167 {\r
1168         if(pc_NoShrink)\r
1169         {\r
1170                 PC_AppendInt(val);\r
1171         }\r
1172         else\r
1173         {\r
1174                 PC_AppendByte(val);\r
1175         }\r
1176 }\r
1177 \r
1178 //==========================================================================\r
1179 //\r
1180 // PC_AppendPushVal\r
1181 //\r
1182 //==========================================================================\r
1183 \r
1184 void PC_AppendPushVal(U_INT val)\r
1185 {\r
1186         if(pc_NoShrink || val > 255)\r
1187         {\r
1188                 PC_AppendCmd(PCD_PUSHNUMBER);\r
1189                 PC_AppendInt(val);\r
1190         }\r
1191         else\r
1192         {\r
1193                 PC_AppendCmd(PCD_PUSHBYTE);\r
1194                 PC_AppendByte((U_BYTE)val);\r
1195         }\r
1196 }\r
1197 \r
1198 //==========================================================================\r
1199 //\r
1200 // PC_Write functions\r
1201 //\r
1202 //==========================================================================\r
1203 \r
1204 static void Write(void *buffer, size_t size, int address)\r
1205 {\r
1206         if (ImportMode != IMPORT_Importing)\r
1207         {\r
1208                 if(address+size > BufferSize)\r
1209                 {\r
1210                         GrowBuffer();\r
1211                 }\r
1212                 memcpy(pc_Buffer+address, buffer, size);\r
1213         }\r
1214 }\r
1215 \r
1216 void PC_Write(void *buffer, size_t size, int address)\r
1217 {\r
1218         if (ImportMode != IMPORT_Importing)\r
1219         {\r
1220                 MS_Message(MSG_DEBUG, "WD> %06d = (%d bytes)\n", address, size);\r
1221                 Write(buffer, size, address);\r
1222         }\r
1223 }\r
1224 \r
1225 void PC_WriteByte(U_BYTE val, int address)\r
1226 {\r
1227         if (ImportMode != IMPORT_Importing)\r
1228         {\r
1229                 MS_Message(MSG_DEBUG, "WB> %06d = %d\n", address, val);\r
1230                 Write(&val, sizeof(U_BYTE), address);\r
1231         }\r
1232 }\r
1233 \r
1234 /*\r
1235 void PC_WriteWord(U_WORD val, int address)\r
1236 {\r
1237         MS_Message(MSG_DEBUG, "WW> %06d = %d\n", address, val);\r
1238         val = MS_LittleUWORD(val);\r
1239         Write(&val, sizeof(U_WORD), address);\r
1240 }\r
1241 */\r
1242 \r
1243 void PC_WriteInt(U_INT val, int address)\r
1244 {\r
1245         if (ImportMode != IMPORT_Importing)\r
1246         {\r
1247                 MS_Message(MSG_DEBUG, "WL> %06d = %d\n", address, val);\r
1248                 val = MS_LittleUINT(val);\r
1249                 Write(&val, sizeof(U_INT), address);\r
1250         }\r
1251         pc_LastAppendedCommand = PCD_NOP;\r
1252 }\r
1253 \r
1254 void PC_WriteString(char *string, int address)\r
1255 {\r
1256         if (ImportMode != IMPORT_Importing)\r
1257         {\r
1258                 int length;\r
1259 \r
1260                 length = strlen(string)+1;\r
1261                 MS_Message(MSG_DEBUG, "WS> %06d = \"%s\" (%d bytes)\n",\r
1262                         address, string, length);\r
1263                 Write(string, length, address);\r
1264         }\r
1265 }\r
1266 \r
1267 void PC_WriteCmd(pcd_t command, int address)\r
1268 {\r
1269         if (ImportMode != IMPORT_Importing)\r
1270         {\r
1271                 MS_Message(MSG_DEBUG, "WC> %06d = #%d:%s\n", address,\r
1272                         command, PCDNames[command]);\r
1273                 command = MS_LittleUINT(command);\r
1274                 Write(&command, sizeof(U_INT), address);\r
1275         }\r
1276 }\r
1277 \r
1278 //==========================================================================\r
1279 //\r
1280 // PC_Skip functions\r
1281 //\r
1282 //==========================================================================\r
1283 \r
1284 static void Skip(size_t size)\r
1285 {\r
1286         if (ImportMode != IMPORT_Importing)\r
1287         {\r
1288                 if(pc_Address+size > BufferSize)\r
1289                 {\r
1290                         GrowBuffer();\r
1291                 }\r
1292                 pc_BufferPtr += size;\r
1293                 pc_Address += size;\r
1294         }\r
1295 }\r
1296 \r
1297 void PC_Skip(size_t size)\r
1298 {\r
1299         if (ImportMode != IMPORT_Importing)\r
1300         {\r
1301                 MS_Message(MSG_DEBUG, "SD> %06d (skip %d bytes)\n", pc_Address, size);\r
1302                 Skip(size);\r
1303         }\r
1304 }\r
1305 \r
1306 /*\r
1307 void PC_SkipByte(void)\r
1308 {\r
1309         MS_Message(MSG_DEBUG, "SB> %06d (skip byte)\n", pc_Address);\r
1310         Skip(sizeof(U_BYTE));\r
1311 }\r
1312 */\r
1313 \r
1314 /*\r
1315 void PC_SkipWord(void)\r
1316 {\r
1317         MS_Message(MSG_DEBUG, "SW> %06d (skip word)\n", pc_Address);\r
1318         Skip(sizeof(U_WORD));\r
1319 }\r
1320 */\r
1321 \r
1322 void PC_SkipInt(void)\r
1323 {\r
1324         if (ImportMode != IMPORT_Importing)\r
1325         {\r
1326                 MS_Message(MSG_DEBUG, "SL> %06d (skip int)\n", pc_Address);\r
1327                 Skip(sizeof(U_INT));\r
1328         }\r
1329 }\r
1330 \r
1331 //==========================================================================\r
1332 //\r
1333 // PC_PutMapVariable\r
1334 //\r
1335 //==========================================================================\r
1336 \r
1337 void PC_PutMapVariable(int index, int value)\r
1338 {\r
1339         if(index < MAX_MAP_VARIABLES)\r
1340         {\r
1341                 MapVariables[index].isString = pa_ConstExprIsString;\r
1342                 MapVariables[index].initializer = value;\r
1343                 MapVariablesInit = YES;\r
1344                 if(pc_EnforceHexen)\r
1345                 {\r
1346                         ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1347                 }\r
1348         }\r
1349 }\r
1350 \r
1351 //==========================================================================\r
1352 //\r
1353 // PC_NameMapVariable\r
1354 //\r
1355 //==========================================================================\r
1356 \r
1357 void PC_NameMapVariable(int index, symbolNode_t *sym)\r
1358 {\r
1359         if(index < MAX_MAP_VARIABLES)\r
1360         {\r
1361                 MapVariables[index].name = sym->name;\r
1362                 MapVariables[index].imported = sym->imported;\r
1363         }\r
1364 }\r
1365 \r
1366 //==========================================================================\r
1367 //\r
1368 // PC_AddScript\r
1369 //\r
1370 //==========================================================================\r
1371 \r
1372 void PC_AddScript(int number, int type, int flags, int argCount)\r
1373 {\r
1374         scriptInfo_t *script;\r
1375         int i;\r
1376 \r
1377         if (flags != 0 || number < 0 || number >= 1000)\r
1378         {\r
1379                 HaveExtendedScripts = YES;\r
1380                 if(pc_EnforceHexen)\r
1381                 {\r
1382                         ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1383                 }\r
1384         }\r
1385 \r
1386         for (i = 0; i < pc_ScriptCount; i++)\r
1387         {\r
1388                 if (ScriptInfo[i].number == number)\r
1389                 {\r
1390                         ERR_Error(ERR_SCRIPT_ALREADY_DEFINED, YES);\r
1391                 }\r
1392         }\r
1393         if(pc_ScriptCount == MAX_SCRIPT_COUNT)\r
1394         {\r
1395                 ERR_Error(ERR_TOO_MANY_SCRIPTS, YES);\r
1396         }\r
1397         else\r
1398         {\r
1399                 script = &ScriptInfo[pc_ScriptCount];\r
1400                 script->number = number;\r
1401                 script->type = type;\r
1402                 script->address = (ImportMode == IMPORT_Importing) ? 0 : pc_Address;\r
1403                 script->argCount = argCount;\r
1404                 script->flags = flags;\r
1405                 script->srcLine = tk_Line;\r
1406                 script->imported = (ImportMode == IMPORT_Importing) ? YES : NO;\r
1407                 pc_ScriptCount++;\r
1408         }\r
1409 }\r
1410 \r
1411 //==========================================================================\r
1412 //\r
1413 // PC_SetScriptVarCount\r
1414 //\r
1415 // Sets the number of local variables used by a script, including\r
1416 // arguments.\r
1417 //\r
1418 //==========================================================================\r
1419 \r
1420 void PC_SetScriptVarCount(int number, int type, int varCount)\r
1421 {\r
1422         int i;\r
1423 \r
1424         for(i = 0; i < pc_ScriptCount; i++)\r
1425         {\r
1426                 if(ScriptInfo[i].number == number && ScriptInfo[i].type == type)\r
1427                 {\r
1428                         ScriptInfo[i].varCount = varCount;\r
1429                         break;\r
1430                 }\r
1431         }\r
1432 }\r
1433 \r
1434 //==========================================================================\r
1435 //\r
1436 // PC_AddFunction\r
1437 //\r
1438 //==========================================================================\r
1439 \r
1440 void PC_AddFunction(symbolNode_t *sym)\r
1441 {\r
1442         functionInfo_t *function;\r
1443 \r
1444         if(pc_FunctionCount == MAX_FUNCTION_COUNT)\r
1445         {\r
1446                 ERR_Error(ERR_TOO_MANY_FUNCTIONS, YES, NULL);\r
1447         }\r
1448         else if(pc_EnforceHexen)\r
1449         {\r
1450                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1451         }\r
1452 \r
1453         function = &FunctionInfo[pc_FunctionCount];\r
1454         function->hasReturnValue = (U_BYTE)sym->info.scriptFunc.hasReturnValue;\r
1455         function->argCount = (U_BYTE)sym->info.scriptFunc.argCount;\r
1456         function->localCount = (U_BYTE)sym->info.scriptFunc.varCount;\r
1457         function->name = STR_AppendToList (STRLIST_FUNCTIONS, sym->name);\r
1458         function->address = sym->info.scriptFunc.address;\r
1459         sym->info.scriptFunc.funcNumber = pc_FunctionCount;\r
1460         pc_FunctionCount++;\r
1461 }\r
1462 \r
1463 //==========================================================================\r
1464 //\r
1465 // PC_AddArray\r
1466 //\r
1467 //==========================================================================\r
1468 \r
1469 void PC_AddArray(int index, int size)\r
1470 {\r
1471         NumArrays++;\r
1472         ArraySizes[index] = size;\r
1473         if(pc_EnforceHexen)\r
1474         {\r
1475                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1476         }\r
1477 }\r
1478 \r
1479 //==========================================================================\r
1480 //\r
1481 // PC_InitArray\r
1482 //\r
1483 //==========================================================================\r
1484 \r
1485 void PC_InitArray(int index, int *entries, boolean hasStrings)\r
1486 {\r
1487         int i;\r
1488 \r
1489         // If the array is just initialized to zeros, then we don't need to\r
1490         // remember the initializer.\r
1491         for(i = 0; i < ArraySizes[index]; ++i)\r
1492         {\r
1493                 if(entries[i] != 0)\r
1494                 {\r
1495                         break;\r
1496                 }\r
1497         }\r
1498         if(i < ArraySizes[index])\r
1499         {\r
1500                 ArrayInits[index] = MS_Alloc(ArraySizes[index]*sizeof(int), ERR_OUT_OF_MEMORY);\r
1501                 memcpy(ArrayInits[index], entries, ArraySizes[index]*sizeof(int));\r
1502         }\r
1503         ArrayOfStrings[index] = hasStrings;\r
1504 }\r
1505 \r
1506 //==========================================================================\r
1507 //\r
1508 // PC_AddImport\r
1509 //\r
1510 //==========================================================================\r
1511 \r
1512 int PC_AddImport(char *name)\r
1513 {\r
1514         if (NumImports >= MAX_IMPORTS)\r
1515         {\r
1516                 ERR_Exit(ERR_TOO_MANY_IMPORTS, YES);\r
1517         }\r
1518         else if(pc_EnforceHexen)\r
1519         {\r
1520                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1521         }\r
1522         strncpy(Imports[NumImports], name, 8);\r
1523         return NumImports++;\r
1524 }\r