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