OSDN Git Service

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