OSDN Git Service

- Correct parameter count to ACS_NamedExecuteWithResult in zspecial.acs.
[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         "PCD_PRINTMAPCHRANGE",          // [FDARI] output range\r
470         "PCD_PRINTWORLDCHRANGE",\r
471         "PCD_PRINTGLOBALCHRANGE",\r
472         "PCD_STRCPYTOMAPCHRANGE",       // [FDARI] input range\r
473         "PCD_STRCPYTOWORLDCHRANGE",\r
474         "PCD_STRCPYTOGLOBALCHRANGE",\r
475         "PCD_PUSHFUNCTION",                     // from Eternity\r
476         "PCD_CALLSTACK",                        // from Eternity\r
477         "PCD_SCRIPTWAITNAMED",\r
478         "PCD_TRANSLATIONRANGE3",\r
479 };\r
480 \r
481 // CODE --------------------------------------------------------------------\r
482 \r
483 //==========================================================================\r
484 //\r
485 // PC_OpenObject\r
486 //\r
487 //==========================================================================\r
488 \r
489 void PC_OpenObject(char *name, size_t size, int flags)\r
490 {\r
491         if(ObjectOpened == YES)\r
492         {\r
493                 PC_CloseObject();\r
494         }\r
495         if(strlen(name) >= MAX_FILE_NAME_LENGTH)\r
496         {\r
497                 ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name);\r
498         }\r
499         strcpy(ObjectName, name);\r
500         pc_Buffer = MS_Alloc(size, ERR_ALLOC_PCODE_BUFFER);\r
501         pc_BufferPtr = pc_Buffer;\r
502         pc_Address = 0;\r
503         ObjectFlags = flags;\r
504         BufferSize = size;\r
505         pc_ScriptCount = 0;\r
506         ObjectOpened = YES;\r
507         PC_AppendString("ACS");\r
508         PC_SkipInt(); // Script table offset\r
509 }\r
510 \r
511 //==========================================================================\r
512 //\r
513 // PC_CloseObject\r
514 //\r
515 //==========================================================================\r
516 \r
517 void PC_CloseObject(void)\r
518 {\r
519         MS_Message(MSG_DEBUG, "---- PC_CloseObject ----\n");\r
520         while (pc_Address & 3)\r
521         {\r
522                 PC_AppendByte (0);\r
523         }\r
524         if(!pc_NoShrink || (NumLanguages > 1) || (NumStringLists > 0) ||\r
525                 (pc_FunctionCount > 0) || MapVariablesInit || NumArrays != 0 ||\r
526                 pc_EncryptStrings || NumImports != 0 || HaveExtendedScripts)\r
527         {\r
528                 if(pc_EnforceHexen)\r
529                 {\r
530                         ERR_Exit(ERR_NOT_HEXEN, NO);\r
531                 }\r
532                 if(pc_WarnNotHexen)\r
533                 {\r
534                         fprintf(stderr, "\nThese scripts have been upgraded because they use new features.\n"\r
535                                                         "They will not be compatible with Hexen.\n");\r
536                 }\r
537                 CloseNew();\r
538         }\r
539         else\r
540         {\r
541                 CloseOld();\r
542         }\r
543         if(MS_SaveFile(ObjectName, pc_Buffer, pc_Address) == FALSE)\r
544         {\r
545                 ERR_Exit(ERR_SAVE_OBJECT_FAILED, NO);\r
546         }\r
547 }\r
548 \r
549 //==========================================================================\r
550 //\r
551 // CloseOld\r
552 //\r
553 //==========================================================================\r
554 \r
555 static void CloseOld(void)\r
556 {\r
557         int i;\r
558 \r
559         STR_WriteStrings();\r
560         PC_WriteInt((U_INT)pc_Address, 4);\r
561         PC_AppendInt((U_INT)pc_ScriptCount);\r
562         for(i = 0; i < pc_ScriptCount; ++i)\r
563         {\r
564                 scriptInfo_t *info = &ScriptInfo[i];\r
565                 MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",\r
566                         info->number, info->address, info->argCount);\r
567                 PC_AppendInt((U_INT)(info->number + info->type * 1000));\r
568                 PC_AppendInt((U_INT)info->address);\r
569                 PC_AppendInt((U_INT)info->argCount);\r
570         }\r
571         STR_WriteList();\r
572 }\r
573 \r
574 //==========================================================================\r
575 //\r
576 // CloseNew\r
577 //\r
578 // Creates a new-format ACS file. For programs that don't know any better,\r
579 // this will look just like an old ACS file with no scripts or strings but\r
580 // with some extra junk in the middle. Both WadAuthor and DeePsea will not\r
581 // accept ACS files that do not have the ACS\0 header. Worse, WadAuthor\r
582 // will hang if the file begins with ACS\0 but does not look like something\r
583 // that might have been created with Raven's ACC. Thus, the chunks live in\r
584 // the string block, and there are two 0 dwords at the end of the file.\r
585 //\r
586 //==========================================================================\r
587 \r
588 static void CloseNew(void)\r
589 {\r
590         int i, j, count;\r
591         int chunkStart;\r
592 \r
593         if(pc_WadAuthor)\r
594         {\r
595                 CreateDummyScripts();\r
596         }\r
597 \r
598         chunkStart = pc_Address;\r
599 \r
600         // Only write out those scripts that this acs file actually provides.\r
601         for(i = j = 0; i < pc_ScriptCount; ++i)\r
602         {\r
603                 if(!ScriptInfo[i].imported)\r
604                 {\r
605                         ++j;\r
606                 }\r
607         }\r
608         if(j > 0)\r
609         {\r
610                 PC_Append("SPTR", 4);\r
611                 PC_AppendInt(j * 8);\r
612                 for(i = 0; i < pc_ScriptCount; i++)\r
613                 {\r
614                         scriptInfo_t *info = &ScriptInfo[i];\r
615                         if(!info->imported)\r
616                         {\r
617                                 MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n",\r
618                                         info->number, info->address, info->argCount);\r
619                                 PC_AppendWord(info->number);\r
620                                 PC_AppendByte(info->type);\r
621                                 PC_AppendByte(info->argCount);\r
622                                 PC_AppendInt((U_INT)info->address);\r
623                         }\r
624                 }\r
625         }\r
626 \r
627         // If any scripts have more than the maximum number of arguments, output them.\r
628         for(i = j = 0; i < pc_ScriptCount; ++i)\r
629         {\r
630                 if(!ScriptInfo[i].imported && ScriptInfo[i].varCount > MAX_SCRIPT_VARIABLES)\r
631                 {\r
632                         ++j;\r
633                 }\r
634         }\r
635         if(j > 0)\r
636         {\r
637                 PC_Append("SVCT", 4);\r
638                 PC_AppendInt(j * 4);\r
639                 for(i = 0; i < pc_ScriptCount; ++i)\r
640                 {\r
641                         scriptInfo_t *info = &ScriptInfo[i];\r
642                         if(!info->imported && info->varCount > MAX_SCRIPT_VARIABLES)\r
643                         {\r
644                                 MS_Message(MSG_DEBUG, "Script %d, var count = %d\n",\r
645                                         info->number, info->varCount);\r
646                                 PC_AppendWord(info->number);\r
647                                 PC_AppendWord(info->varCount);\r
648                         }\r
649                 }\r
650         }\r
651 \r
652         // Write script flags in a separate chunk, so older ZDooms don't get confused\r
653         for(i = j = 0; i < pc_ScriptCount; ++i)\r
654         {\r
655                 if(!ScriptInfo[i].imported && ScriptInfo[i].flags != 0)\r
656                 {\r
657                         ++j;\r
658                 }\r
659         }\r
660         if (j > 0)\r
661         {\r
662                 PC_Append("SFLG", 4);\r
663                 PC_AppendInt(j * 4);\r
664                 for(i = 0; i < pc_ScriptCount; ++i)\r
665                 {\r
666                         scriptInfo_t *info = &ScriptInfo[i];\r
667                         if(!info->imported && info->flags != 0)\r
668                         {\r
669                                 PC_AppendWord(info->number);\r
670                                 PC_AppendWord(info->flags);\r
671                         }\r
672                 }\r
673         }\r
674 \r
675         // Write the string table for named scripts.\r
676         STR_WriteListChunk(STRLIST_NAMEDSCRIPTS, MAKE4CC('S','N','A','M'), NO);\r
677 \r
678         if(pc_FunctionCount > 0)\r
679         {\r
680                 PC_Append("FUNC", 4);\r
681                 PC_AppendInt(pc_FunctionCount * 8);\r
682                 for(i = 0; i < pc_FunctionCount; ++i)\r
683                 {\r
684                         functionInfo_t *info = &FunctionInfo[i];\r
685                         MS_Message(MSG_DEBUG, "Function %d:%s, address = %d, arg count = %d, var count = %d\n",\r
686                                 i, STR_GetString(STRLIST_FUNCTIONS, info->name),\r
687                                 info->address, info->argCount, info->localCount);\r
688                         PC_AppendByte(info->argCount);\r
689                         PC_AppendByte(info->localCount);\r
690                         PC_AppendByte((U_BYTE)(info->hasReturnValue?1:0));\r
691                         PC_AppendByte(0);\r
692                         PC_AppendInt((U_INT)info->address);\r
693                 }\r
694                 STR_WriteListChunk(STRLIST_FUNCTIONS, MAKE4CC('F','N','A','M'), NO);\r
695         }\r
696 \r
697         if(NumLanguages > 1)\r
698         {\r
699                 for(i = 0; i < NumLanguages; i++)\r
700                 {\r
701                         STR_WriteChunk(i, pc_EncryptStrings);\r
702                 }\r
703         }\r
704         else if(STR_ListSize(0) > 0)\r
705         {\r
706                 STR_WriteChunk(0, pc_EncryptStrings);\r
707         }\r
708 \r
709         STR_WriteListChunk(STRLIST_PICS, MAKE4CC('P','I','C','S'), NO);\r
710         if(MapVariablesInit)\r
711         {\r
712                 int j;\r
713 \r
714                 for(i = 0; i < pa_MapVarCount; ++i)\r
715                 {\r
716                         if(MapVariables[i].initializer != 0)\r
717                                 break;\r
718                 }\r
719                 for(j = pa_MapVarCount-1; j > i; --j)\r
720                 {\r
721                         if(MapVariables[j].initializer != 0)\r
722                                 break;\r
723                 }\r
724                 ++j;\r
725 \r
726                 if (i < j)\r
727                 {\r
728                         PC_Append("MINI", 4);\r
729                         PC_AppendInt((j-i)*4+4);\r
730                         PC_AppendInt(i);                                                // First map var defined\r
731                         for(; i < j; ++i)\r
732                         {\r
733                                 PC_AppendInt(MapVariables[i].initializer);\r
734                         }\r
735                 }\r
736         }\r
737 \r
738         // If this is a library, record which map variables are\r
739         // initialized with strings.\r
740         if(ImportMode == IMPORT_Exporting)\r
741         {\r
742                 count = 0;\r
743 \r
744                 for(i = 0; i < pa_MapVarCount; ++i)\r
745                 {\r
746                         if(MapVariables[i].isString)\r
747                         {\r
748                                 ++count;\r
749                         }\r
750                 }\r
751                 if(count > 0)\r
752                 {\r
753                         PC_Append("MSTR", 4);\r
754                         PC_AppendInt(count*4);\r
755                         for(i = 0; i < pa_MapVarCount; ++i)\r
756                         {\r
757                                 if(MapVariables[i].isString)\r
758                                 {\r
759                                         PC_AppendInt(i);\r
760                                 }\r
761                         }\r
762                 }\r
763 \r
764                 // Now do the same thing for arrays.\r
765                 for(count = 0, i = 0; i < pa_MapVarCount; ++i)\r
766                 {\r
767                         if(ArrayOfStrings[i])\r
768                         {\r
769                                 ++count;\r
770                         }\r
771                 }\r
772                 if(count > 0)\r
773                 {\r
774                         PC_Append("ASTR", 4);\r
775                         PC_AppendInt(count*4);\r
776                         for(i = 0; i < pa_MapVarCount; ++i)\r
777                         {\r
778                                 if(ArrayOfStrings[i])\r
779                                 {\r
780                                         PC_AppendInt(i);\r
781                                 }\r
782                         }\r
783                 }\r
784         }\r
785 \r
786         // Publicize the names of map variables in a library.\r
787         if(ImportMode == IMPORT_Exporting)\r
788         {\r
789                 for(i = 0; i < pa_MapVarCount; ++i)\r
790                 {\r
791                         if(!MapVariables[i].imported)\r
792                         {\r
793                                 STR_AppendToList(STRLIST_MAPVARS, MapVariables[i].name);\r
794                         }\r
795                         else\r
796                         {\r
797                                 STR_AppendToList(STRLIST_MAPVARS, NULL);\r
798                         }\r
799                 }\r
800                 STR_WriteListChunk(STRLIST_MAPVARS, MAKE4CC('M','E','X','P'), NO);\r
801         }\r
802 \r
803         // Record the names of imported map variables\r
804         count = 0;\r
805         for(i = 0; i < pa_MapVarCount; ++i)\r
806         {\r
807                 if(MapVariables[i].imported && !ArraySizes[i])\r
808                 {\r
809                         count += 5 + strlen(MapVariables[i].name);\r
810                 }\r
811         }\r
812         if(count > 0)\r
813         {\r
814                 PC_Append("MIMP", 4);\r
815                 PC_AppendInt(count);\r
816                 for(i = 0; i < pa_MapVarCount; ++i)\r
817                 {\r
818                         if(MapVariables[i].imported && !ArraySizes[i])\r
819                         {\r
820                                 PC_AppendInt(i);\r
821                                 PC_AppendString(MapVariables[i].name);\r
822                         }\r
823                 }\r
824         }\r
825 \r
826         if(NumArrays)\r
827         {\r
828                 int count;\r
829 \r
830                 // Arrays defined here\r
831                 for(count = 0, i = 0; i < pa_MapVarCount; ++i)\r
832                 {\r
833                         if(ArraySizes[i] && !MapVariables[i].imported)\r
834                         {\r
835                                 ++count;\r
836                         }\r
837                 }\r
838                 if(count)\r
839                 {\r
840                         PC_Append("ARAY", 4);\r
841                         PC_AppendInt(count*8);\r
842                         for(i = 0; i < pa_MapVarCount; ++i)\r
843                         {\r
844                                 if(ArraySizes[i] && !MapVariables[i].imported)\r
845                                 {\r
846                                         PC_AppendInt(i);\r
847                                         PC_AppendInt(ArraySizes[i]);\r
848                                 }\r
849                         }\r
850                         for(i = 0; i < pa_MapVarCount; ++i)\r
851                         {\r
852                                 if(ArrayInits[i])\r
853                                 {\r
854                                         int j;\r
855 \r
856                                         PC_Append("AINI", 4);\r
857                                         PC_AppendInt(ArraySizes[i]*4+4);\r
858                                         PC_AppendInt((U_INT)i);\r
859                                         MS_Message(MSG_DEBUG, "Writing array initializers for array %d (size %d)\n", i, ArraySizes[i]);\r
860                                         for(j = 0; j < ArraySizes[i]; ++j)\r
861                                         {\r
862                                                 PC_AppendInt((U_INT)ArrayInits[i][j]);\r
863                                         }\r
864                                 }\r
865                         }\r
866                 }\r
867 \r
868                 // Arrays imported from elsewhere\r
869                 for(count = 0, j = i = 0; i < pa_MapVarCount; ++i)\r
870                 {\r
871                         if(ArraySizes[i] && MapVariables[i].imported)\r
872                         {\r
873                                 count += 9 + strlen(MapVariables[i].name);\r
874                                 ++j;\r
875                         }\r
876                 }\r
877                 if(count)\r
878                 {\r
879                         PC_Append("AIMP", 4);\r
880                         PC_AppendInt(count+4);\r
881                         PC_AppendInt(j);\r
882                         for(i = 0; i < pa_MapVarCount; ++i)\r
883                         {\r
884                                 if(ArraySizes[i] && MapVariables[i].imported)\r
885                                 {\r
886                                         PC_AppendInt(i);\r
887                                         PC_AppendInt(ArraySizes[i]);\r
888                                         PC_AppendString(MapVariables[i].name);\r
889                                 }\r
890                         }\r
891                 }\r
892         }\r
893 \r
894         // Add a dummy chunk to indicate if this object is a library.\r
895         if(ImportMode == IMPORT_Exporting)\r
896         {\r
897                 PC_Append("ALIB", 4);\r
898                 PC_AppendInt(0);\r
899         }\r
900 \r
901         // Record libraries imported by this object.\r
902         if(NumImports > 0)\r
903         {\r
904                 count = 0;\r
905                 for(i = 0; i < NumImports; ++i)\r
906                 {\r
907                         count += strlen(Imports[i]) + 1;\r
908                 }\r
909                 if(count > 0)\r
910                 {\r
911                         PC_Append("LOAD", 4);\r
912                         PC_AppendInt(count);\r
913                         for(i = 0; i < NumImports; ++i)\r
914                         {\r
915                                 PC_AppendString(Imports[i]);\r
916                         }\r
917                 }\r
918         }\r
919 \r
920         PC_AppendInt((U_INT)chunkStart);\r
921         if(pc_NoShrink)\r
922         {\r
923                 PC_Append("ACSE", 4);\r
924         }\r
925         else\r
926         {\r
927                 PC_Append("ACSe", 4);\r
928         }\r
929         PC_WriteInt((U_INT)pc_Address, 4);\r
930 \r
931         // WadAuthor compatibility when creating a library is pointless, because\r
932         // that editor does not know anything about libraries and will never\r
933         // find their scripts ever.\r
934         if(pc_WadAuthor && ImportMode != IMPORT_Exporting)\r
935         {\r
936                 RecordDummyScripts();\r
937         }\r
938         else\r
939         {\r
940                 PC_AppendInt(0);\r
941         }\r
942         PC_AppendInt(0);\r
943 }\r
944 \r
945 //==========================================================================\r
946 //\r
947 // CreateDummyScripts\r
948 //\r
949 //==========================================================================\r
950 \r
951 static void CreateDummyScripts(void)\r
952 {\r
953         int i;\r
954 \r
955         MS_Message(MSG_DEBUG, "Creating dummy scripts to make WadAuthor happy.\n");\r
956         if(pc_Address%4 != 0)\r
957         { // Need to align\r
958                 U_INT pad = 0;\r
959                 PC_Append((void *)&pad, 4-(pc_Address%4));\r
960         }\r
961         pc_DummyAddress = pc_Address;\r
962         for(i = 0; i < pc_ScriptCount; ++i)\r
963         {\r
964                 // Only create dummies for scripts WadAuthor could care about.\r
965                 if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)\r
966                 {\r
967                         PC_AppendCmd(PCD_TERMINATE);\r
968                         if(!pc_NoShrink)\r
969                         {\r
970                                 PC_AppendCmd(PCD_NOP);\r
971                                 PC_AppendCmd(PCD_NOP);\r
972                                 PC_AppendCmd(PCD_NOP);\r
973                         }\r
974                 }\r
975         }\r
976 }\r
977 \r
978 //==========================================================================\r
979 //\r
980 // RecordDummyScripts\r
981 //\r
982 //==========================================================================\r
983 \r
984 static void RecordDummyScripts(void)\r
985 {\r
986         int i, j, count;\r
987 \r
988         for(i = count = 0; i < pc_ScriptCount; ++i)\r
989         {\r
990                 if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255)\r
991                 {\r
992                         ++count;\r
993                 }\r
994         }\r
995         PC_AppendInt((U_INT)count);\r
996         for(i = j = 0; i < pc_ScriptCount; ++i)\r
997         {\r
998                 scriptInfo_t *info = &ScriptInfo[i];\r
999                 if(!info->imported && info->number >= 0 && ScriptInfo[i].number <= 255)\r
1000                 {\r
1001                         MS_Message(MSG_DEBUG, "Dummy script %d, address = %d, arg count = %d\n",\r
1002                                 info->number, info->address, info->argCount);\r
1003                         PC_AppendInt((U_INT)info->number);\r
1004                         PC_AppendInt((U_INT)pc_DummyAddress + j*4);\r
1005                         PC_AppendInt((U_INT)info->argCount);\r
1006                         j++;\r
1007                 }\r
1008         }\r
1009 }\r
1010 \r
1011 //==========================================================================\r
1012 //\r
1013 // GrowBuffer\r
1014 //\r
1015 //==========================================================================\r
1016 \r
1017 void GrowBuffer(void)\r
1018 {\r
1019         ptrdiff_t buffpos = pc_BufferPtr - pc_Buffer;\r
1020 \r
1021         BufferSize *= 2;\r
1022         pc_Buffer = MS_Realloc(pc_Buffer, BufferSize, ERR_PCODE_BUFFER_OVERFLOW);\r
1023         pc_BufferPtr = pc_Buffer + buffpos;\r
1024 }\r
1025 \r
1026 //==========================================================================\r
1027 //\r
1028 // PC_Append functions\r
1029 //\r
1030 //==========================================================================\r
1031 \r
1032 static void Append(void *buffer, size_t size)\r
1033 {\r
1034         if (ImportMode != IMPORT_Importing)\r
1035         {\r
1036                 if(pc_Address+size > BufferSize)\r
1037                 {\r
1038                         GrowBuffer ();\r
1039                 }\r
1040                 memcpy(pc_BufferPtr, buffer, size);\r
1041                 pc_BufferPtr += size;\r
1042                 pc_Address += size;\r
1043         }\r
1044 }\r
1045 \r
1046 void PC_Append(void *buffer, size_t size)\r
1047 {\r
1048         if (ImportMode != IMPORT_Importing)\r
1049         {\r
1050                 MS_Message(MSG_DEBUG, "AD> %06d = (%d bytes)\n", pc_Address, size);\r
1051                 Append(buffer, size);\r
1052         }\r
1053 }\r
1054 \r
1055 void PC_AppendByte(U_BYTE val)\r
1056 {\r
1057         if (ImportMode != IMPORT_Importing)\r
1058         {\r
1059                 MS_Message(MSG_DEBUG, "AB> %06d = %d\n", pc_Address, val);\r
1060                 Append(&val, sizeof(U_BYTE));\r
1061         }\r
1062 }\r
1063 \r
1064 void PC_AppendWord(U_WORD val)\r
1065 {\r
1066         if (ImportMode != IMPORT_Importing)\r
1067         {\r
1068                 MS_Message(MSG_DEBUG, "AW> %06d = %d\n", pc_Address, val);\r
1069                 val = MS_LittleUWORD(val);\r
1070                 Append(&val, sizeof(U_WORD));\r
1071         }\r
1072 }\r
1073 \r
1074 void PC_AppendInt(U_INT val)\r
1075 {\r
1076         if (ImportMode != IMPORT_Importing)\r
1077         {\r
1078                 MS_Message(MSG_DEBUG, "AL> %06d = %d\n", pc_Address, val);\r
1079                 val = MS_LittleUINT(val);\r
1080                 Append(&val, sizeof(U_INT));\r
1081         }\r
1082 }\r
1083 \r
1084 void PC_AppendString(char *string)\r
1085 {\r
1086         if (ImportMode != IMPORT_Importing)\r
1087         {\r
1088                 int length;\r
1089 \r
1090                 length = strlen(string)+1;\r
1091                 MS_Message(MSG_DEBUG, "AS> %06d = \"%s\" (%d bytes)\n",\r
1092                         pc_Address, string, length);\r
1093                 Append(string, length);\r
1094         }\r
1095 }\r
1096 \r
1097 void PC_AppendCmd(pcd_t command)\r
1098 {\r
1099         boolean dupbyte = NO;\r
1100         if (ImportMode != IMPORT_Importing)\r
1101         {\r
1102                 pc_LastAppendedCommand = command;\r
1103                 if (pc_NoShrink)\r
1104                 {\r
1105                         MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,\r
1106                                 command, PCDNames[command]);\r
1107                         command = MS_LittleUINT(command);\r
1108                         Append(&command, sizeof(U_INT));\r
1109                 }\r
1110                 else\r
1111                 {\r
1112                         U_BYTE cmd;\r
1113                         if (command == PCD_DUP && PushByteAddr)\r
1114                         { // If the last instruction was PCD_PUSHBYTE, convert this PCD_DUP to a\r
1115                           // duplicate PCD_PUSHBYTE, so it can be merged into a single instruction below.\r
1116                                 command = PCD_PUSHBYTE;\r
1117                                 dupbyte = YES;\r
1118                                 MS_Message(MSG_DEBUG, "AC> PCD_DUP changed to PCD_PUSHBYTE\n");\r
1119                         }\r
1120                         else if (command != PCD_PUSHBYTE && PushByteAddr)\r
1121                         { // Maybe shrink a PCD_PUSHBYTE sequence into PCD_PUSHBYTES\r
1122                                 int runlen = (pc_Address - PushByteAddr) / 2;\r
1123                                 int i;\r
1124 \r
1125                                 if (runlen > 5)\r
1126                                 {\r
1127                                         pc_Buffer[PushByteAddr] = PCD_PUSHBYTES;\r
1128                                         for (i = 0; i < runlen; i++)\r
1129                                         {\r
1130                                                 pc_Buffer[PushByteAddr+i+2] = pc_Buffer[PushByteAddr+i*2+1];\r
1131                                         }\r
1132                                         pc_Buffer[PushByteAddr+1] = runlen;\r
1133                                         pc_Address = PushByteAddr + runlen + 2;\r
1134                                         pc_BufferPtr = pc_Buffer + pc_Address;\r
1135                                         MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSHBYTES\n",\r
1136                                                 runlen, PCD_PUSHBYTES);\r
1137                                 }\r
1138                                 else if (runlen > 1)\r
1139                                 {\r
1140                                         pc_Buffer[PushByteAddr] = PCD_PUSH2BYTES + runlen - 2;\r
1141                                         for (i = 1; i < runlen; i++)\r
1142                                         {\r
1143                                                 pc_Buffer[PushByteAddr+1+i] = pc_Buffer[PushByteAddr+1+i*2];\r
1144                                         }\r
1145                                         pc_Address = PushByteAddr + runlen + 1;\r
1146                                         pc_BufferPtr = pc_Buffer + pc_Address;\r
1147                                         MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSH%dBYTES\n",\r
1148                                                 runlen, PCD_PUSH2BYTES+runlen-2, runlen);\r
1149                                 }\r
1150                                 PushByteAddr = 0;\r
1151                         }\r
1152                         else if(command == PCD_PUSHBYTE && PushByteAddr == 0)\r
1153                         { // Remember the first PCD_PUSHBYTE, in case there are more\r
1154                                 PushByteAddr = pc_Address;\r
1155                         }\r
1156                         MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address,\r
1157                                 command, PCDNames[command]);\r
1158 \r
1159                         if (command < 256-16)\r
1160                         {\r
1161                                 cmd = command;\r
1162                                 Append(&cmd, sizeof(U_BYTE));\r
1163                         }\r
1164                         else\r
1165                         {\r
1166                                 // Room for expansion: The top 16 pcodes in the [0,255]\r
1167                                 // range select a set of pcodes, and the next byte is\r
1168                                 // the pcode in that set.\r
1169                                 cmd = ((command - (256-16)) >> 8) + (256-16);\r
1170                                 Append(&cmd, sizeof(U_BYTE));\r
1171                                 cmd = (command - (256-16)) & 255;\r
1172                                 Append(&cmd, sizeof(U_BYTE));\r
1173                         }\r
1174                         if (dupbyte)\r
1175                         {\r
1176                                 PC_AppendByte(pc_Buffer[pc_Address-2]);\r
1177                         }\r
1178                 }\r
1179         }\r
1180 }\r
1181 \r
1182 //==========================================================================\r
1183 //\r
1184 // PC_AppendShrink\r
1185 //\r
1186 //==========================================================================\r
1187 \r
1188 void PC_AppendShrink(U_BYTE val)\r
1189 {\r
1190         if(pc_NoShrink)\r
1191         {\r
1192                 PC_AppendInt(val);\r
1193         }\r
1194         else\r
1195         {\r
1196                 PC_AppendByte(val);\r
1197         }\r
1198 }\r
1199 \r
1200 //==========================================================================\r
1201 //\r
1202 // PC_AppendPushVal\r
1203 //\r
1204 //==========================================================================\r
1205 \r
1206 void PC_AppendPushVal(U_INT val)\r
1207 {\r
1208         if(pc_NoShrink || val > 255)\r
1209         {\r
1210                 PC_AppendCmd(PCD_PUSHNUMBER);\r
1211                 PC_AppendInt(val);\r
1212         }\r
1213         else\r
1214         {\r
1215                 PC_AppendCmd(PCD_PUSHBYTE);\r
1216                 PC_AppendByte((U_BYTE)val);\r
1217         }\r
1218 }\r
1219 \r
1220 //==========================================================================\r
1221 //\r
1222 // PC_Write functions\r
1223 //\r
1224 //==========================================================================\r
1225 \r
1226 static void Write(void *buffer, size_t size, int address)\r
1227 {\r
1228         if (ImportMode != IMPORT_Importing)\r
1229         {\r
1230                 if(address+size > BufferSize)\r
1231                 {\r
1232                         GrowBuffer();\r
1233                 }\r
1234                 memcpy(pc_Buffer+address, buffer, size);\r
1235         }\r
1236 }\r
1237 \r
1238 void PC_Write(void *buffer, size_t size, int address)\r
1239 {\r
1240         if (ImportMode != IMPORT_Importing)\r
1241         {\r
1242                 MS_Message(MSG_DEBUG, "WD> %06d = (%d bytes)\n", address, size);\r
1243                 Write(buffer, size, address);\r
1244         }\r
1245 }\r
1246 \r
1247 void PC_WriteByte(U_BYTE val, int address)\r
1248 {\r
1249         if (ImportMode != IMPORT_Importing)\r
1250         {\r
1251                 MS_Message(MSG_DEBUG, "WB> %06d = %d\n", address, val);\r
1252                 Write(&val, sizeof(U_BYTE), address);\r
1253         }\r
1254 }\r
1255 \r
1256 /*\r
1257 void PC_WriteWord(U_WORD val, int address)\r
1258 {\r
1259         MS_Message(MSG_DEBUG, "WW> %06d = %d\n", address, val);\r
1260         val = MS_LittleUWORD(val);\r
1261         Write(&val, sizeof(U_WORD), address);\r
1262 }\r
1263 */\r
1264 \r
1265 void PC_WriteInt(U_INT val, int address)\r
1266 {\r
1267         if (ImportMode != IMPORT_Importing)\r
1268         {\r
1269                 MS_Message(MSG_DEBUG, "WL> %06d = %d\n", address, val);\r
1270                 val = MS_LittleUINT(val);\r
1271                 Write(&val, sizeof(U_INT), address);\r
1272         }\r
1273         pc_LastAppendedCommand = PCD_NOP;\r
1274 }\r
1275 \r
1276 void PC_WriteString(char *string, int address)\r
1277 {\r
1278         if (ImportMode != IMPORT_Importing)\r
1279         {\r
1280                 int length;\r
1281 \r
1282                 length = strlen(string)+1;\r
1283                 MS_Message(MSG_DEBUG, "WS> %06d = \"%s\" (%d bytes)\n",\r
1284                         address, string, length);\r
1285                 Write(string, length, address);\r
1286         }\r
1287 }\r
1288 \r
1289 void PC_WriteCmd(pcd_t command, int address)\r
1290 {\r
1291         if (ImportMode != IMPORT_Importing)\r
1292         {\r
1293                 MS_Message(MSG_DEBUG, "WC> %06d = #%d:%s\n", address,\r
1294                         command, PCDNames[command]);\r
1295                 command = MS_LittleUINT(command);\r
1296                 Write(&command, sizeof(U_INT), address);\r
1297         }\r
1298 }\r
1299 \r
1300 //==========================================================================\r
1301 //\r
1302 // PC_Skip functions\r
1303 //\r
1304 //==========================================================================\r
1305 \r
1306 static void Skip(size_t size)\r
1307 {\r
1308         if (ImportMode != IMPORT_Importing)\r
1309         {\r
1310                 if(pc_Address+size > BufferSize)\r
1311                 {\r
1312                         GrowBuffer();\r
1313                 }\r
1314                 pc_BufferPtr += size;\r
1315                 pc_Address += size;\r
1316         }\r
1317 }\r
1318 \r
1319 void PC_Skip(size_t size)\r
1320 {\r
1321         if (ImportMode != IMPORT_Importing)\r
1322         {\r
1323                 MS_Message(MSG_DEBUG, "SD> %06d (skip %d bytes)\n", pc_Address, size);\r
1324                 Skip(size);\r
1325         }\r
1326 }\r
1327 \r
1328 /*\r
1329 void PC_SkipByte(void)\r
1330 {\r
1331         MS_Message(MSG_DEBUG, "SB> %06d (skip byte)\n", pc_Address);\r
1332         Skip(sizeof(U_BYTE));\r
1333 }\r
1334 */\r
1335 \r
1336 /*\r
1337 void PC_SkipWord(void)\r
1338 {\r
1339         MS_Message(MSG_DEBUG, "SW> %06d (skip word)\n", pc_Address);\r
1340         Skip(sizeof(U_WORD));\r
1341 }\r
1342 */\r
1343 \r
1344 void PC_SkipInt(void)\r
1345 {\r
1346         if (ImportMode != IMPORT_Importing)\r
1347         {\r
1348                 MS_Message(MSG_DEBUG, "SL> %06d (skip int)\n", pc_Address);\r
1349                 Skip(sizeof(U_INT));\r
1350         }\r
1351 }\r
1352 \r
1353 //==========================================================================\r
1354 //\r
1355 // PC_PutMapVariable\r
1356 //\r
1357 //==========================================================================\r
1358 \r
1359 void PC_PutMapVariable(int index, int value)\r
1360 {\r
1361         if(index < MAX_MAP_VARIABLES)\r
1362         {\r
1363                 MapVariables[index].isString = pa_ConstExprIsString;\r
1364                 MapVariables[index].initializer = value;\r
1365                 MapVariablesInit = YES;\r
1366                 if(pc_EnforceHexen)\r
1367                 {\r
1368                         ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1369                 }\r
1370         }\r
1371 }\r
1372 \r
1373 //==========================================================================\r
1374 //\r
1375 // PC_NameMapVariable\r
1376 //\r
1377 //==========================================================================\r
1378 \r
1379 void PC_NameMapVariable(int index, symbolNode_t *sym)\r
1380 {\r
1381         if(index < MAX_MAP_VARIABLES)\r
1382         {\r
1383                 MapVariables[index].name = sym->name;\r
1384                 MapVariables[index].imported = sym->imported;\r
1385         }\r
1386 }\r
1387 \r
1388 //==========================================================================\r
1389 //\r
1390 // PC_AddScript\r
1391 //\r
1392 //==========================================================================\r
1393 \r
1394 void PC_AddScript(int number, int type, int flags, int argCount)\r
1395 {\r
1396         scriptInfo_t *script;\r
1397         int i;\r
1398 \r
1399         if (flags != 0 || number < 0 || number >= 1000)\r
1400         {\r
1401                 HaveExtendedScripts = YES;\r
1402                 if(pc_EnforceHexen)\r
1403                 {\r
1404                         ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1405                 }\r
1406         }\r
1407 \r
1408         for (i = 0; i < pc_ScriptCount; i++)\r
1409         {\r
1410                 if (ScriptInfo[i].number == number)\r
1411                 {\r
1412                         ERR_Error(ERR_SCRIPT_ALREADY_DEFINED, YES);\r
1413                 }\r
1414         }\r
1415         if(pc_ScriptCount == MAX_SCRIPT_COUNT)\r
1416         {\r
1417                 ERR_Error(ERR_TOO_MANY_SCRIPTS, YES);\r
1418         }\r
1419         else\r
1420         {\r
1421                 script = &ScriptInfo[pc_ScriptCount];\r
1422                 script->number = number;\r
1423                 script->type = type;\r
1424                 script->address = (ImportMode == IMPORT_Importing) ? 0 : pc_Address;\r
1425                 script->argCount = argCount;\r
1426                 script->flags = flags;\r
1427                 script->srcLine = tk_Line;\r
1428                 script->imported = (ImportMode == IMPORT_Importing) ? YES : NO;\r
1429                 pc_ScriptCount++;\r
1430         }\r
1431 }\r
1432 \r
1433 //==========================================================================\r
1434 //\r
1435 // PC_SetScriptVarCount\r
1436 //\r
1437 // Sets the number of local variables used by a script, including\r
1438 // arguments.\r
1439 //\r
1440 //==========================================================================\r
1441 \r
1442 void PC_SetScriptVarCount(int number, int type, int varCount)\r
1443 {\r
1444         int i;\r
1445 \r
1446         for(i = 0; i < pc_ScriptCount; i++)\r
1447         {\r
1448                 if(ScriptInfo[i].number == number && ScriptInfo[i].type == type)\r
1449                 {\r
1450                         ScriptInfo[i].varCount = varCount;\r
1451                         break;\r
1452                 }\r
1453         }\r
1454 }\r
1455 \r
1456 //==========================================================================\r
1457 //\r
1458 // PC_AddFunction\r
1459 //\r
1460 //==========================================================================\r
1461 \r
1462 void PC_AddFunction(symbolNode_t *sym)\r
1463 {\r
1464         functionInfo_t *function;\r
1465 \r
1466         if(pc_FunctionCount == MAX_FUNCTION_COUNT)\r
1467         {\r
1468                 ERR_Error(ERR_TOO_MANY_FUNCTIONS, YES, NULL);\r
1469         }\r
1470         else if(pc_EnforceHexen)\r
1471         {\r
1472                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1473         }\r
1474 \r
1475         function = &FunctionInfo[pc_FunctionCount];\r
1476         function->hasReturnValue = (U_BYTE)sym->info.scriptFunc.hasReturnValue;\r
1477         function->argCount = (U_BYTE)sym->info.scriptFunc.argCount;\r
1478         function->localCount = (U_BYTE)sym->info.scriptFunc.varCount;\r
1479         function->name = STR_AppendToList (STRLIST_FUNCTIONS, sym->name);\r
1480         function->address = sym->info.scriptFunc.address;\r
1481         sym->info.scriptFunc.funcNumber = pc_FunctionCount;\r
1482         pc_FunctionCount++;\r
1483 }\r
1484 \r
1485 //==========================================================================\r
1486 //\r
1487 // PC_AddArray\r
1488 //\r
1489 //==========================================================================\r
1490 \r
1491 void PC_AddArray(int index, int size)\r
1492 {\r
1493         NumArrays++;\r
1494         ArraySizes[index] = size;\r
1495         if(pc_EnforceHexen)\r
1496         {\r
1497                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1498         }\r
1499 }\r
1500 \r
1501 //==========================================================================\r
1502 //\r
1503 // PC_InitArray\r
1504 //\r
1505 //==========================================================================\r
1506 \r
1507 void PC_InitArray(int index, int *entries, boolean hasStrings)\r
1508 {\r
1509         int i;\r
1510 \r
1511         // If the array is just initialized to zeros, then we don't need to\r
1512         // remember the initializer.\r
1513         for(i = 0; i < ArraySizes[index]; ++i)\r
1514         {\r
1515                 if(entries[i] != 0)\r
1516                 {\r
1517                         break;\r
1518                 }\r
1519         }\r
1520         if(i < ArraySizes[index])\r
1521         {\r
1522                 ArrayInits[index] = MS_Alloc(ArraySizes[index]*sizeof(int), ERR_OUT_OF_MEMORY);\r
1523                 memcpy(ArrayInits[index], entries, ArraySizes[index]*sizeof(int));\r
1524         }\r
1525         ArrayOfStrings[index] = hasStrings;\r
1526 }\r
1527 \r
1528 //==========================================================================\r
1529 //\r
1530 // PC_AddImport\r
1531 //\r
1532 //==========================================================================\r
1533 \r
1534 int PC_AddImport(char *name)\r
1535 {\r
1536         if (NumImports >= MAX_IMPORTS)\r
1537         {\r
1538                 ERR_Exit(ERR_TOO_MANY_IMPORTS, YES);\r
1539         }\r
1540         else if(pc_EnforceHexen)\r
1541         {\r
1542                 ERR_Error(ERR_HEXEN_COMPAT, YES);\r
1543         }\r
1544         strncpy(Imports[NumImports], name, 8);\r
1545         return NumImports++;\r
1546 }\r