home *** CD-ROM | disk | FTP | other *** search
/ Launch & Play / spustahrej2.iso / Egoboo / code / script.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-12-03  |  135.8 KB  |  3,514 lines

  1. // script.c
  2.  
  3. // Egoboo, Copyright (C) 2000 Aaron Bishop
  4.  
  5. #include "egoboo.h"
  6.  
  7. //------------------------------------------------------------------------------
  8. //AI Script Routines------------------------------------------------------------
  9. //------------------------------------------------------------------------------
  10. void insert_space(int position)
  11. {
  12.     // ZZ> This function adds a space into the load line if there isn't one
  13.     //     there already
  14.     unsigned char cTmp, cSwap;
  15.  
  16.     if(cLineBuffer[position]!=' ')
  17.     {
  18.         cTmp = cLineBuffer[position];
  19.         cLineBuffer[position]=' ';
  20.         position++;
  21.         iLineSize++;
  22.         while(position < iLineSize)
  23.         {
  24.             cSwap=cLineBuffer[position];
  25.             cLineBuffer[position]=cTmp;
  26.             cTmp=cSwap;
  27.             position++;
  28.         }
  29.     }
  30. }
  31.  
  32. //------------------------------------------------------------------------------
  33. void copy_one_line(int write)
  34. {
  35.     // ZZ> This function copies the line back to the load buffer
  36.     int read;
  37.     unsigned char cTmp;
  38.  
  39.  
  40.     read = 0;
  41.     cTmp=cLineBuffer[read];
  42.     while(cTmp != 0)
  43.     {
  44.         cTmp=cLineBuffer[read];  read++;
  45.         cLoadBuffer[write]=cTmp;  write++;
  46.     }
  47.  
  48.  
  49.  
  50.     iNumLine++;
  51. }
  52.  
  53. //------------------------------------------------------------------------------
  54. int load_one_line(int read)
  55. {
  56.     // ZZ> This function loads a line into the line buffer
  57.     int stillgoing, foundtext;
  58.     unsigned char cTmp;
  59.  
  60.  
  61.     // Parse to start to maintain indentation
  62.     iLineSize = 0;
  63.     stillgoing = TRUE;
  64.     while(stillgoing)
  65.     {
  66.         cTmp = cLoadBuffer[read];
  67.         stillgoing = FALSE;
  68.         if(cTmp==' ')
  69.         {
  70.             read++;
  71.             cLineBuffer[iLineSize]=cTmp; iLineSize++;
  72.             stillgoing = TRUE;
  73.         }
  74.     }
  75.  
  76.  
  77.     // Parse to comment or end of line
  78.     foundtext = FALSE;
  79.     stillgoing = TRUE;
  80.     while(stillgoing)
  81.     {
  82.         cTmp = cLoadBuffer[read];  read++;
  83.         if(cTmp=='\t')
  84.            cTmp = ' ';
  85.         if(cTmp != ' ' && cTmp != 0x0d && cTmp != 0x0a &&
  86.            (cTmp != '/' || cLoadBuffer[read]!='/'))
  87.             foundtext=TRUE;
  88.         cLineBuffer[iLineSize]=cTmp;
  89.         if(cTmp!=' ' || (cLoadBuffer[read]!=' ' && cLoadBuffer[read]!='\t'))
  90.           iLineSize++;
  91.         if(cTmp == 0x0d || cTmp == 0x0a)
  92.             stillgoing=FALSE;
  93.         if(cTmp == '/' && cLoadBuffer[read] == '/')
  94.             stillgoing=FALSE;
  95.     }
  96.     iLineSize--;  cLineBuffer[iLineSize]=0;
  97.     if(iLineSize>=1)
  98.     {
  99.         if(cLineBuffer[iLineSize-1]==' ')
  100.         {
  101.             iLineSize--;  cLineBuffer[iLineSize]=0;
  102.         }
  103.     }
  104.     iLineSize++;
  105.  
  106.  
  107.     // Parse to end of line
  108.     stillgoing=TRUE;
  109.     read--;
  110.     while(stillgoing)
  111.     {
  112.         cTmp = cLoadBuffer[read];  read++;
  113.         if(cTmp == 0x0a || cTmp==0x0d)
  114.             stillgoing=FALSE;
  115.     }
  116.  
  117.     if(foundtext==FALSE)
  118.     {
  119.         iLineSize=0;
  120.     }
  121.  
  122.  
  123.     return read;
  124. }
  125.  
  126. //------------------------------------------------------------------------------
  127. int load_parsed_line(int read)
  128. {
  129.     // ZZ> This function loads a line into the line buffer
  130.     unsigned char cTmp;
  131.  
  132.  
  133.     // Parse to start to maintain indentation
  134.     iLineSize = 0;
  135.     cTmp=cLoadBuffer[read];
  136.     while(cTmp!=0)
  137.     {
  138.         cLineBuffer[iLineSize]=cTmp;  iLineSize++;
  139.         read++;  cTmp = cLoadBuffer[read];
  140.     }
  141.     cLineBuffer[iLineSize]=0;  iLineSize++; read++;
  142.     return read;
  143. }
  144.  
  145. //------------------------------------------------------------------------------
  146. void surround_space(int position)
  147. {
  148.     insert_space(position+1);
  149.     if(position>0)
  150.     {
  151.         if(cLineBuffer[position-1]!=' ')
  152.         {
  153.             insert_space(position);
  154.         }
  155.     }
  156. }
  157.  
  158. //------------------------------------------------------------------------------
  159. void parse_null_terminate_comments()
  160. {
  161.     // ZZ> This function removes comments and endline codes, replacing
  162.     //     them with a 0
  163.     int read, write;
  164.  
  165.  
  166.     read = 0;
  167.     write = 0;
  168.     while(read < iLoadSize)
  169.     {
  170.         read=load_one_line(read);
  171.         if(iLineSize>2)
  172.         {
  173.             copy_one_line(write);
  174.             write+=iLineSize;
  175.         }
  176.     }
  177. }
  178.  
  179. //------------------------------------------------------------------------------
  180. int get_indentation()
  181. {
  182.     // ZZ> This function returns the number of starting spaces in a line
  183.     int cnt;
  184.     unsigned char cTmp;
  185.  
  186.     cnt = 0;
  187.     cTmp=cLineBuffer[cnt];
  188.     while(cTmp==' ')
  189.     {
  190.         cnt++;
  191.         cTmp=cLineBuffer[cnt];
  192.     }
  193.     cnt=cnt>>1;
  194.     if(cnt > 15)
  195.     {
  196.         if(globalparseerr)
  197.         {
  198.             fprintf(globalparseerr, "  %s - %d levels of indentation\n", globalparsename, cnt + 1);
  199.         }
  200.         parseerror = TRUE;
  201.         cnt = 15;
  202.     }
  203.     return cnt;
  204. }
  205.  
  206. //------------------------------------------------------------------------------
  207. void fix_operators()
  208. {
  209.     // ZZ> This function puts spaces around operators to seperate words
  210.     //     better
  211.     int cnt;
  212.     unsigned char cTmp;
  213.  
  214.     cnt = 0;
  215.     while(cnt < iLineSize)
  216.     {
  217.         cTmp=cLineBuffer[cnt];
  218.         if(cTmp=='+' || cTmp=='-' || cTmp=='/' || cTmp=='*' ||
  219.            cTmp=='%' || cTmp=='>' || cTmp=='<' || cTmp=='&' ||
  220.            cTmp=='=')
  221.         {
  222.             surround_space(cnt);
  223.             cnt++; 
  224.         }
  225.         cnt++;
  226.     }
  227. }
  228.  
  229. //------------------------------------------------------------------------------
  230. int starts_with_capital_letter()
  231. {
  232.     // ZZ> This function returns TRUE if the line starts with a capital
  233.     int cnt;
  234.     unsigned char cTmp;
  235.  
  236.     cnt = 0;
  237.     cTmp=cLineBuffer[cnt];
  238.     while(cTmp==' ')
  239.     {
  240.         cnt++;
  241.         cTmp=cLineBuffer[cnt];
  242.     }
  243.     if(cTmp>='A'&&cTmp<='Z')
  244.       return TRUE;
  245.     return FALSE;
  246. }
  247.  
  248. //------------------------------------------------------------------------------
  249. unsigned int get_high_bits()
  250. {
  251.     // ZZ> This function looks at the first word and generates the high
  252.     //     bit codes for it
  253.     unsigned int highbits;
  254.  
  255.     highbits = get_indentation();
  256.     if(starts_with_capital_letter())
  257.     {
  258.         highbits=highbits|16;
  259.     }
  260.     else
  261.     {
  262.     }
  263.     highbits=highbits<<27;
  264.     return highbits;
  265. }
  266.  
  267. //------------------------------------------------------------------------------
  268. int tell_code(int read)
  269. {
  270.     // ZZ> This function tells what code is being indexed by read, it
  271.     //     will return the next spot to read from and stick the code number
  272.     //     in iCodeIndex
  273.     int cnt, wordsize, codecorrect;
  274.     unsigned char cTmp;
  275.     int idsz, test;
  276.     char cWordBuffer[MAXCODENAMESIZE];
  277.  
  278.  
  279.     // Check bounds
  280.     iCodeIndex = MAXCODE;
  281.     if(read >= iLineSize)  return read;
  282.  
  283.  
  284.     // Skip spaces
  285.     cTmp=cLineBuffer[read];
  286.     while(cTmp==' ' || cTmp==0)
  287.     {
  288.         read++;
  289.         cTmp=cLineBuffer[read];
  290.     }
  291.     if(read >= iLineSize)  return read;
  292.  
  293.  
  294.     // Load the word into the other buffer
  295.     wordsize = 0;
  296.     while(cTmp!=' ' && cTmp!=0)
  297.     {
  298.         cWordBuffer[wordsize] = cTmp;  wordsize++;
  299.         read++;
  300.         cTmp=cLineBuffer[read];
  301.     }
  302.     cWordBuffer[wordsize] = 0;
  303.  
  304.  
  305.     // Check for numeric constant
  306.     if(cWordBuffer[0]>='0' && cWordBuffer[0]<='9')
  307.     {
  308.         sscanf(&cWordBuffer[0], "%d", &iCodeValueTmp);
  309.         iCodeIndex=-1;
  310.         return read;
  311.     }
  312.  
  313.  
  314.     // Check for IDSZ constant
  315.     if(cWordBuffer[0]=='[')
  316.     {
  317.         idsz = IDSZNONE;
  318.         cTmp = cWordBuffer[1]-'A';  idsz=idsz|(cTmp<<15);
  319.         cTmp = cWordBuffer[2]-'A';  idsz=idsz|(cTmp<<10);
  320.         cTmp = cWordBuffer[3]-'A';  idsz=idsz|(cTmp<<5);
  321.         cTmp = cWordBuffer[4]-'A';  idsz=idsz|(cTmp);
  322.         test = ('N'-'A'<<15)|('O'-'A'<<10)|('N'-'A'<<5)|('E'-'A');  // [NONE]
  323.         if(idsz == test)
  324.         {
  325.             idsz = IDSZNONE;
  326.         }
  327.         iCodeValueTmp = idsz;
  328.         iCodeIndex=-1;
  329.         return read;
  330.     }
  331.  
  332.  
  333.  
  334.     // Compare the word to all the codes
  335.     codecorrect = FALSE;
  336.     iCodeIndex = 0;
  337.     while(iCodeIndex < iNumCode && !codecorrect)
  338.     {
  339.         codecorrect = FALSE;
  340.         if(cWordBuffer[0] == cCodeName[iCodeIndex][0] && !codecorrect)
  341.         {
  342.             codecorrect = TRUE;
  343.             cnt = 1;
  344.             while(cnt < wordsize)
  345.             {
  346.                 if(cWordBuffer[cnt]!=cCodeName[iCodeIndex][cnt])
  347.                 {
  348.                     codecorrect=FALSE;
  349.                     cnt = wordsize;
  350.                 }
  351.                 cnt++;
  352.             }
  353.             if(cnt < MAXCODENAMESIZE)
  354.             {
  355.                 if(cCodeName[iCodeIndex][cnt]!=0)  codecorrect = FALSE;
  356.             }
  357.         }
  358.         iCodeIndex++;
  359.     }
  360.     if(codecorrect)
  361.     {
  362.         iCodeIndex--;
  363.         iCodeValueTmp=iCodeValue[iCodeIndex];
  364.         if(cCodeType[iCodeIndex]=='C')
  365.         {
  366.             // Check for constants
  367.             iCodeIndex = -1;
  368.         }
  369.     }
  370.     else
  371.     {
  372.         // Throw out an error code if we're loggin' 'em
  373.         if(cWordBuffer[0] != '=' || cWordBuffer[1] != 0)
  374.         {
  375.             if(globalparseerr)
  376.             {
  377.                 fprintf(globalparseerr, "  %s - %s undefined\n", globalparsename, cWordBuffer);
  378.             }
  379.             parseerror = TRUE;
  380.         }
  381.     }
  382.     return read;
  383. }
  384.  
  385. //------------------------------------------------------------------------------
  386. void add_code(unsigned int highbits)
  387. {
  388.     unsigned int value;
  389.  
  390.     if(iCodeIndex==-1)  highbits=highbits|0x80000000;
  391.     if(iCodeIndex != MAXCODE)
  392.     {
  393.         value = highbits|iCodeValueTmp;
  394.         iCompiledAis[iAisIndex]=value;
  395.         iAisIndex++;
  396.     }
  397. }
  398.  
  399. //------------------------------------------------------------------------------
  400. void parse_line_by_line()
  401. {
  402.     // ZZ> This function removes comments and endline codes, replacing
  403.     //     them with a 0
  404.     int read, line;
  405.     unsigned int highbits;
  406.     int parseposition;
  407.     int operands;
  408.  
  409.  
  410.     line = 0;
  411.     read = 0;
  412.     while(line < iNumLine)
  413.     {
  414.         read=load_parsed_line(read);
  415.         fix_operators();
  416.         highbits = get_high_bits();
  417.         parseposition = 0;
  418.         parseposition=tell_code(parseposition);  // VALUE
  419.         add_code(highbits);
  420.         iCodeValueTmp=0;  // SKIP FOR CONTROL CODES
  421.         add_code(0);
  422.         if((highbits&0x80000000)==0)
  423.         {
  424.             parseposition=tell_code(parseposition);  // EQUALS
  425.             parseposition=tell_code(parseposition);  // VALUE
  426.             add_code(0);
  427.             operands = 1;
  428.             while(parseposition<iLineSize)
  429.             {
  430.                 parseposition=tell_code(parseposition);  // OPERATOR
  431.                 if(iCodeIndex==-1) iCodeIndex=1;
  432.                 else iCodeIndex=0;
  433.                 highbits=((iCodeValueTmp&15)<<27)|(iCodeIndex<<31);
  434.                 parseposition=tell_code(parseposition);  // VALUE
  435.                 add_code(highbits);
  436.                 if(iCodeIndex!=MAXCODE)
  437.                   operands++;
  438.             }
  439.             iCompiledAis[iAisIndex-operands-1]=operands;  // Number of operands
  440.         }
  441.         line++;
  442.     }
  443. }
  444.  
  445. //------------------------------------------------------------------------------
  446. unsigned int jump_goto(int index)
  447. {
  448.     // ZZ> This function figures out where to jump to on a fail based on the
  449.     //     starting location and the following code.  The starting location
  450.     //     should always be a function code with indentation
  451.     unsigned int value;
  452.     int targetindent, indent;
  453.  
  454.  
  455.     value = iCompiledAis[index];  index+=2;
  456.     targetindent = (value>>27)&15;
  457.     indent = 100;
  458.     while(indent>targetindent)
  459.     {
  460.         value = iCompiledAis[index];
  461.         indent = (value>>27)&15;
  462.         if(indent>targetindent)
  463.         {
  464.             // Was it a function
  465.             if((value&0x80000000)!=0)
  466.             {
  467.                 // Each function needs a jump
  468.                 index++;
  469.                 index++;
  470.             }
  471.             else
  472.             {
  473.                 // Operations cover each operand
  474.                 index++;
  475.                 value = iCompiledAis[index];
  476.                 index++;
  477.                 index+=(value&255);
  478.             }
  479.         }
  480.     }
  481.     return index;
  482. }
  483.  
  484. //------------------------------------------------------------------------------
  485. void parse_jumps(int ainumber)
  486. {
  487.     // ZZ> This function sets up the fail jumps for the down and dirty code
  488.     int index;
  489.     unsigned int value, iTmp;
  490.  
  491.  
  492.     index = iAisStartPosition[ainumber];
  493.     value = iCompiledAis[index];
  494.     while(value != 0x80000035)  // End Function
  495.     {
  496.         value = iCompiledAis[index];
  497.         // Was it a function
  498.         if((value&0x80000000)!=0)
  499.         {
  500.             // Each function needs a jump
  501.             iTmp = jump_goto(index);
  502.             index++;
  503.             iCompiledAis[index]=iTmp;
  504.             index++;
  505.         }
  506.         else
  507.         {
  508.             // Operations cover each operand
  509.             index++;
  510.             iTmp = iCompiledAis[index];
  511.             index++;
  512.             index+=(iTmp&255);
  513.         }
  514.     }
  515. }
  516.  
  517. //------------------------------------------------------------------------------
  518. void log_code(int ainumber, char* savename)
  519. {
  520.     // ZZ> This function shows the actual code, saving it in a file
  521.     int index;
  522.     unsigned int value;
  523.     FILE* filewrite;
  524.  
  525.     filewrite = fopen(FILENAME(savename), "w");
  526.     if(filewrite)
  527.     {
  528.         index = iAisStartPosition[ainumber];
  529.         value = iCompiledAis[index];
  530.         while(value != 0x80000035)  // End Function
  531.         {
  532.             value = iCompiledAis[index];
  533.             fprintf(filewrite, "0x%08x--0x%08x\n", index, value);
  534.             index++;
  535.         }
  536.         fclose(filewrite);
  537.     }
  538.     SDL_Quit();
  539. }
  540.  
  541. //------------------------------------------------------------------------------
  542. int ai_goto_colon(int read)
  543. {
  544.     // ZZ> This function goes to spot after the next colon
  545.     unsigned char cTmp;
  546.  
  547.     cTmp = cLoadBuffer[read];
  548.     while(cTmp!=':' && read < iLoadSize)
  549.     {
  550.         read++;  cTmp=cLoadBuffer[read];
  551.     }
  552.     if(read < iLoadSize)  read++;
  553.     return read;
  554. }
  555.  
  556. //------------------------------------------------------------------------------
  557. void get_code(int read)
  558. {
  559.     // ZZ> This function gets code names and other goodies
  560.     unsigned char cTmp;
  561.     int iTmp;
  562.  
  563.     sscanf((char*) &cLoadBuffer[read], "%c%d%s", &cTmp, &iTmp, &cCodeName[iNumCode][0]);
  564.     cCodeType[iNumCode]=cTmp;
  565.     iCodeValue[iNumCode]=iTmp;
  566. }
  567.  
  568. //------------------------------------------------------------------------------
  569. void load_ai_codes(char* loadname)
  570. {
  571.     // ZZ> This function loads all of the function and variable names
  572.     FILE* fileread;
  573.     int read;
  574.  
  575.     iNumCode = 0;
  576.     fileread = fopen(FILENAME(loadname), "rb");
  577.     if(fileread)
  578.     {
  579.         iLoadSize = fread(&cLoadBuffer[0], 1, MD2MAXLOADSIZE, fileread);
  580.         read = 0;
  581.         read = ai_goto_colon(read);
  582.         while(read!=iLoadSize)
  583.         {
  584.             get_code(read);
  585.             iNumCode++;
  586.             read = ai_goto_colon(read);
  587.         }
  588.         fclose(fileread);
  589.     }
  590. }
  591.  
  592. //------------------------------------------------------------------------------
  593. int load_ai_script(char *loadname)
  594. {
  595.     // ZZ> This function loads a script to memory and
  596.     //     returns FALSE if it fails to do so
  597.     FILE* fileread;
  598.  
  599.     iNumLine = 0;
  600.     globalparsename = loadname;  // For error logging in ParseErr.TXT
  601.     fileread = fopen(FILENAME(loadname), "rb");
  602.     if(fileread && iNumAis < MAXAI)
  603.     {
  604.         // Make room for the code
  605.         iAisStartPosition[iNumAis]=iAisIndex;
  606.  
  607.         // Load into md2 load buffer
  608.         iLoadSize = fread(&cLoadBuffer[0], 1, MD2MAXLOADSIZE, fileread);
  609.         fclose(fileread);
  610.         parse_null_terminate_comments();
  611.         parse_line_by_line();
  612.         parse_jumps(iNumAis);
  613.         iNumAis++;
  614.         return TRUE;
  615.     }
  616.     return FALSE;
  617. }
  618.  
  619. //------------------------------------------------------------------------------
  620. void reset_ai_script()
  621. {
  622.     // ZZ> This function starts ai loading in the right spot
  623.     int cnt;
  624.  
  625.     iAisIndex=0;
  626.     for (cnt = 0; cnt < MAXMODEL; cnt++)
  627.         madai[cnt] = 0;
  628.  
  629.     iNumAis=0;
  630. }
  631.  
  632. //--------------------------------------------------------------------------------------------
  633. unsigned char run_function(unsigned int value, int character)
  634. {
  635.     // ZZ> This function runs a script function for the AI.
  636.     //     It returns FALSE if the script should jump over the
  637.     //     indented code that follows
  638.  
  639.     // Mask out the indentation
  640.     unsigned short valuecode = value;
  641.  
  642.     // Assume that the function will pass, as most do
  643.     unsigned char returncode = TRUE;
  644.  
  645.     unsigned short sTmp;
  646.     float fTmp;
  647.     int iTmp, tTmp;
  648.     int distance, volume;
  649.     unsigned int test;
  650.     char szDebug[256];
  651.  
  652.     // Figure out which function to run
  653.     switch(valuecode)
  654.     {
  655.         case FIFSPAWNED:
  656.             // Proceed only if it's a new character
  657.             returncode = ((chralert[character]&ALERTIFSPAWNED)!=0);
  658.             break;
  659.         case FIFTIMEOUT:
  660.             // Proceed only if time alert is set
  661.             returncode = (chraitime[character]==0);
  662.             break;
  663.         case FIFATWAYPOINT:
  664.             // Proceed only if the character reached a waypoint
  665.             returncode = ((chralert[character]&ALERTIFATWAYPOINT)!=0);
  666.             break;
  667.         case FIFATLASTWAYPOINT:
  668.             // Proceed only if the character reached its last waypoint
  669.             returncode = ((chralert[character]&ALERTIFATLASTWAYPOINT)!=0);
  670.             break;
  671.         case FIFATTACKED:
  672.             // Proceed only if the character was damaged
  673.             returncode = ((chralert[character]&ALERTIFATTACKED)!=0);
  674.             break;
  675.         case FIFBUMPED:
  676.             // Proceed only if the character was bumped
  677.             returncode = ((chralert[character]&ALERTIFBUMPED)!=0);
  678.             break;
  679.         case FIFORDERED:
  680.             // Proceed only if the character was ordered
  681.             returncode = ((chralert[character]&ALERTIFORDERED)!=0);
  682.             break;
  683.         case FIFCALLEDFORHELP:
  684.             // Proceed only if the character was called for help
  685.             returncode = ((chralert[character]&ALERTIFCALLEDFORHELP)!=0);
  686.             break;
  687.         case FSETCONTENT:
  688.             // Set the content
  689.             chraicontent[character] = valuetmpargument;
  690.             break;
  691.         case FIFKILLED:
  692.             // Proceed only if the character's been killed
  693.             returncode = ((chralert[character]&ALERTIFKILLED)!=0);
  694.             break;
  695.         case FIFTARGETKILLED:
  696.             // Proceed only if the character's target has just died
  697.             returncode = ((chralert[character]&ALERTIFTARGETKILLED)!=0);
  698.             break;
  699.         case FCLEARWAYPOINTS:
  700.             // Clear out all waypoints
  701.             chraigoto[character] = 0;
  702.             chraigotoadd[character] = 0;
  703.             chraigotox[character][0] = chrxpos[character];
  704.             chraigotoy[character][0] = chrypos[character];
  705.             break;
  706.         case FADDWAYPOINT:
  707.             // Add a waypoint to the waypoint list
  708.             chraigotox[character][chraigotoadd[character]]=valuetmpx;
  709.             chraigotoy[character][chraigotoadd[character]]=valuetmpy;
  710.             chraigotoadd[character]++;
  711.             if(chraigotoadd[character]>MAXWAY)  chraigotoadd[character]=MAXWAY-1;
  712.             break;
  713.         case FFINDPATH:
  714.             // This function adds enough waypoints to get from one point to another
  715.             // !!!BAD!!!
  716.             break;
  717.         case FCOMPASS:
  718.             // This function changes tmpx and tmpy in a circlular manner according
  719.             // to tmpturn and tmpdistance
  720.             sTmp = (valuetmpturn+16384);
  721.             valuetmpx = valuetmpx-turntosin[sTmp>>2]*valuetmpdistance;
  722.             valuetmpy = valuetmpy-turntosin[valuetmpturn>>2]*valuetmpdistance;
  723.             break;
  724.         case FGETTARGETARMORPRICE:
  725.             // This function gets the armor cost for the given skin
  726.             sTmp = valuetmpargument & 3;
  727.             valuetmpx = capskincost[chrmodel[chraitarget[character]]][sTmp];
  728.             break;
  729.         case FSETTIME:
  730.             // This function resets the time
  731.             chraitime[character]=valuetmpargument;
  732.             break;
  733.         case FGETCONTENT:
  734.             // Get the content
  735.             valuetmpargument = chraicontent[character];
  736.             break;
  737.         case FJOINTARGETTEAM:
  738.             // This function allows the character to leave its own team and join another
  739.             returncode = FALSE;
  740.             if(chron[chraitarget[character]])
  741.             {
  742.                 switch_team(character, chrteam[chraitarget[character]]);
  743.                 returncode = TRUE;
  744.             }
  745.         case FSETTARGETTONEARBYENEMY:
  746.             // This function finds a nearby enemy, and proceeds only if there is one
  747.             sTmp = get_nearby_target(character, FALSE, FALSE, TRUE, FALSE, IDSZNONE);
  748.             returncode = FALSE;
  749.             if(sTmp != MAXCHR)
  750.             {
  751.                 chraitarget[character] = sTmp;
  752.                 returncode = TRUE;
  753.             }
  754.             break;
  755.         case FSETTARGETTOTARGETLEFTHAND:
  756.             // This function sets the target to the target's left item
  757.             sTmp = chrholdingwhich[chraitarget[character]][0];
  758.             returncode = FALSE;
  759.             if(sTmp != MAXCHR)
  760.             {
  761.                 chraitarget[character] = sTmp;
  762.                 returncode = TRUE;
  763.             }
  764.             break;
  765.         case FSETTARGETTOTARGETRIGHTHAND:
  766.             // This function sets the target to the target's right item
  767.             sTmp = chrholdingwhich[chraitarget[character]][1];
  768.             returncode = FALSE;
  769.             if(sTmp != MAXCHR)
  770.             {
  771.                 chraitarget[character] = sTmp;
  772.                 returncode = TRUE;
  773.             }
  774.             break;
  775.         case FSETTARGETTOWHOEVERATTACKED:
  776.             // This function sets the target to whoever attacked the character last,
  777.             // failing for damage tiles
  778.             if(chrattacklast[character]!=MAXCHR)
  779.             {
  780.                 chraitarget[character]=chrattacklast[character];
  781.             }
  782.             else
  783.             {
  784.                 returncode = FALSE;
  785.             }
  786.             break;
  787.         case FSETTARGETTOWHOEVERBUMPED:
  788.             // This function sets the target to whoever bumped into the
  789.             // character last.  It never fails
  790.             chraitarget[character]=chrbumplast[character];
  791.             break;
  792.         case FSETTARGETTOWHOEVERCALLEDFORHELP:
  793.             // This function sets the target to whoever needs help
  794.             chraitarget[character]=teamsissy[chrteam[character]];
  795.             break;
  796.         case FSETTARGETTOOLDTARGET:
  797.             // This function reverts to the target with whom the script started
  798.             chraitarget[character]=valueoldtarget;
  799.             break;
  800.         case FSETTURNMODETOVELOCITY:
  801.             // This function sets the turn mode
  802.             chrturnmode[character] = TURNMODEVELOCITY;
  803.             break;
  804.         case FSETTURNMODETOWATCH:
  805.             // This function sets the turn mode
  806.             chrturnmode[character] = TURNMODEWATCH;
  807.             break;
  808.         case FSETTURNMODETOSPIN:
  809.             // This function sets the turn mode
  810.             chrturnmode[character] = TURNMODESPIN;
  811.             break;
  812.         case FSETBUMPHEIGHT:
  813.             // This function changes a character's bump height
  814.             chrbumpheight[character] = valuetmpargument*chrfat[character];
  815.             chrbumpheightsave[character] = valuetmpargument;
  816.             break;
  817.         case FIFTARGETHASID:
  818.             // This function proceeds if ID matches tmpargument
  819.             sTmp = chrmodel[chraitarget[character]];
  820.             returncode = capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument;
  821.             returncode = returncode | (capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument);
  822.             break;
  823.         case FIFTARGETHASITEMID:
  824.             // This function proceeds if the target has a matching item in his/her pack
  825.             returncode = FALSE;
  826.             // Check the pack
  827.             sTmp = chrnextinpack[chraitarget[character]];
  828.             while(sTmp != MAXCHR)
  829.             {
  830.                 if(capidsz[chrmodel[sTmp]][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[chrmodel[sTmp]][IDSZTYPE]==(unsigned int) valuetmpargument)
  831.                 {
  832.                     returncode = TRUE;
  833.                     sTmp = MAXCHR;
  834.                 }
  835.                 else
  836.                 {
  837.                     sTmp = chrnextinpack[sTmp];
  838.                 }
  839.             }
  840.             // Check left hand
  841.             sTmp = chrholdingwhich[chraitarget[character]][0];
  842.             if(sTmp != MAXCHR)
  843.             {
  844.                 sTmp = chrmodel[sTmp];
  845.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  846.                     returncode = TRUE;
  847.             }
  848.             // Check right hand
  849.             sTmp = chrholdingwhich[chraitarget[character]][1];
  850.             if(sTmp != MAXCHR)
  851.             {
  852.                 sTmp = chrmodel[sTmp];
  853.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  854.                     returncode = TRUE;
  855.             }
  856.             break;
  857.         case FIFTARGETHOLDINGITEMID:
  858.             // This function proceeds if ID matches tmpargument and returns the latch for the
  859.             // hand in tmpargument
  860.             returncode = FALSE;
  861.             // Check left hand
  862.             sTmp = chrholdingwhich[chraitarget[character]][0];
  863.             if(sTmp != MAXCHR)
  864.             {
  865.                 sTmp = chrmodel[sTmp];
  866.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  867.                 {
  868.                     valuetmpargument = LATCHBUTTONLEFT;
  869.                     returncode = TRUE;
  870.                 }
  871.             }
  872.             // Check right hand
  873.             sTmp = chrholdingwhich[chraitarget[character]][1];
  874.             if(sTmp != MAXCHR && returncode == FALSE)
  875.             {
  876.                 sTmp = chrmodel[sTmp];
  877.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  878.                 {
  879.                     valuetmpargument = LATCHBUTTONRIGHT;
  880.                     returncode = TRUE;
  881.                 }
  882.             }
  883.             break;
  884.         case FIFTARGETHASSKILLID:
  885.             // This function proceeds if ID matches tmpargument
  886.             returncode = (capidsz[chrmodel[chraitarget[character]]][IDSZSKILL]==(unsigned int) valuetmpargument);
  887.             break;
  888.         case FELSE:
  889.             // This function fails if the last one was more indented
  890.             if((valuelastindent&0x78000000)>(value&0x78000000))
  891.                 returncode = FALSE;
  892.             break;
  893.         case FRUN:
  894.             reset_character_accel(character);
  895.             break;
  896.         case FWALK:
  897.             reset_character_accel(character);
  898.             chrmaxaccel[character] *= .66;
  899.             break;
  900.         case FSNEAK:
  901.             reset_character_accel(character);
  902.             chrmaxaccel[character] *= .33;
  903.             break;
  904.         case FDOACTION:
  905.             // This function starts a new action, if it is valid for the model
  906.             // It will fail if the action is invalid or if the character is doing
  907.             // something else already
  908.             returncode = FALSE;
  909.             if(valuetmpargument < MAXACTION && chractionready[character])
  910.             {
  911.                 if(madactionvalid[chrmodel[character]][valuetmpargument])
  912.                 {
  913.                     chraction[character] = valuetmpargument;
  914.                     chrlip[character] = 0;
  915.                     chrlastframe[character] = chrframe[character];
  916.                     chrframe[character] = madactionstart[chrmodel[character]][valuetmpargument];
  917.                     chractionready[character] = FALSE;
  918.                     returncode = TRUE;
  919.                 }
  920.             }
  921.             break;
  922.         case FKEEPACTION:
  923.             // This function makes the current animation halt on the last frame
  924.             chrkeepaction[character] = TRUE;
  925.             break;
  926.         case FISSUEORDER:
  927.             // This function issues an order to all teammates
  928.             issue_order(character, valuetmpargument);
  929.             break;
  930.         case FDROPWEAPONS:
  931.             // This funtion drops the character's in hand items/riders
  932.             sTmp = chrholdingwhich[character][0];
  933.             if(sTmp != MAXCHR)
  934.             {
  935.                 detach_character_from_mount(sTmp, TRUE, TRUE);
  936.                 if(chrismount[character])
  937.                 {
  938.                     chrzvel[sTmp] = DISMOUNTZVEL;
  939.                     chrzpos[sTmp]+=DISMOUNTZVEL;
  940.                     chrjumptime[sTmp]=JUMPDELAY;
  941.                 }
  942.             }
  943.             sTmp = chrholdingwhich[character][1];
  944.             if(sTmp != MAXCHR)
  945.             {
  946.                 detach_character_from_mount(sTmp, TRUE, TRUE);
  947.                 if(chrismount[character])
  948.                 {
  949.                     chrzvel[sTmp] = DISMOUNTZVEL;
  950.                     chrzpos[sTmp]+=DISMOUNTZVEL;
  951.                     chrjumptime[sTmp]=JUMPDELAY;
  952.                 }
  953.             }
  954.             break;
  955.         case FTARGETDOACTION:
  956.             // This function starts a new action, if it is valid for the model
  957.             // It will fail if the action is invalid or if the target is doing
  958.             // something else already
  959.             returncode = FALSE;
  960.             if(chralive[chraitarget[character]])
  961.             {
  962.                 if(valuetmpargument < MAXACTION && chractionready[chraitarget[character]])
  963.                 {
  964.                     if(madactionvalid[chrmodel[chraitarget[character]]][valuetmpargument])
  965.                     {
  966.                         chraction[chraitarget[character]] = valuetmpargument;
  967.                         chrlip[chraitarget[character]] = 0;
  968.                         chrlastframe[chraitarget[character]] = chrframe[chraitarget[character]];
  969.                         chrframe[chraitarget[character]] = madactionstart[chrmodel[chraitarget[character]]][valuetmpargument];
  970.                         chractionready[chraitarget[character]] = FALSE;
  971.                         returncode = TRUE;
  972.                     }
  973.                 }
  974.             }
  975.             break;
  976.         case FOPENPASSAGE:
  977.             // This function opens the passage specified by tmpargument, failing if the
  978.             // passage was already open
  979.             returncode = open_passage(valuetmpargument);
  980.             break;
  981.         case FCLOSEPASSAGE:
  982.             // This function closes the passage specified by tmpargument, and proceeds
  983.             // only if the passage is clear of obstructions
  984.             returncode = close_passage(valuetmpargument);
  985.             break;
  986.         case FIFPASSAGEOPEN:
  987.             // This function proceeds only if the passage specified by tmpargument
  988.             // is both valid and open
  989.             returncode = FALSE;
  990.             if(valuetmpargument < numpassage && valuetmpargument >= 0)
  991.             {
  992.                 returncode = passopen[valuetmpargument];
  993.             }
  994.             break;
  995.         case FGOPOOF:
  996.             // This function flags the character to be removed from the game
  997.             returncode = FALSE;
  998.             if(chrisplayer[character]==FALSE)
  999.             {
  1000.                 returncode = TRUE;
  1001.                 valuegopoof = TRUE;
  1002.             }
  1003.             break;
  1004.         case FCOSTTARGETITEMID:
  1005.             // This function checks if the target has a matching item, and poofs it
  1006.             returncode = FALSE;
  1007.             // Check the pack
  1008.             iTmp = MAXCHR;
  1009.             tTmp = chraitarget[character];
  1010.             sTmp = chrnextinpack[tTmp];
  1011.             while(sTmp != MAXCHR)
  1012.             {
  1013.                 if(capidsz[chrmodel[sTmp]][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[chrmodel[sTmp]][IDSZTYPE]==(unsigned int) valuetmpargument)
  1014.                 {
  1015.                     returncode = TRUE;
  1016.                     iTmp = sTmp;
  1017.                     sTmp = MAXCHR;
  1018.                 }
  1019.                 else
  1020.                 {
  1021.                     tTmp = sTmp;
  1022.                     sTmp = chrnextinpack[sTmp];
  1023.                 }
  1024.             }
  1025.             // Check left hand
  1026.             sTmp = chrholdingwhich[chraitarget[character]][0];
  1027.             if(sTmp != MAXCHR)
  1028.             {
  1029.                 sTmp = chrmodel[sTmp];
  1030.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  1031.                 {
  1032.                     returncode = TRUE;
  1033.                     iTmp = chrholdingwhich[chraitarget[character]][0];
  1034.                 }
  1035.             }
  1036.             // Check right hand
  1037.             sTmp = chrholdingwhich[chraitarget[character]][1];
  1038.             if(sTmp != MAXCHR)
  1039.             {
  1040.                 sTmp = chrmodel[sTmp];
  1041.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  1042.                 {
  1043.                     returncode = TRUE;
  1044.                     iTmp = chrholdingwhich[chraitarget[character]][1];
  1045.                 }
  1046.             }
  1047.             if(returncode)
  1048.             {
  1049.                 if(chrammo[iTmp]<=1)
  1050.                 {
  1051.                     // Poof the item
  1052.                     if(chrinpack[iTmp])
  1053.                     {
  1054.                         // Remove from the pack
  1055.                         chrnextinpack[tTmp] = chrnextinpack[iTmp];
  1056.                         chrnuminpack[chraitarget[character]]--;
  1057.                         free_one_character(iTmp);
  1058.                     }
  1059.                     else
  1060.                     {
  1061.                         // Drop from hand
  1062.                         detach_character_from_mount(iTmp, TRUE, FALSE);
  1063.                         free_one_character(iTmp);
  1064.                     }
  1065.                 }
  1066.                 else
  1067.                 {
  1068.                     // Cost one ammo
  1069.                     chrammo[iTmp]--;
  1070.                 }
  1071.             }
  1072.             break;
  1073.         case FDOACTIONOVERRIDE:
  1074.             // This function starts a new action, if it is valid for the model
  1075.             // It will fail if the action is invalid
  1076.             returncode = FALSE;
  1077.             if(valuetmpargument < MAXACTION)
  1078.             {
  1079.                 if(madactionvalid[chrmodel[character]][valuetmpargument])
  1080.                 {
  1081.                     chraction[character] = valuetmpargument;
  1082.                     chrlip[character] = 0;
  1083.                     chrlastframe[character] = chrframe[character];
  1084.                     chrframe[character] = madactionstart[chrmodel[character]][valuetmpargument];
  1085.                     chractionready[character] = FALSE;
  1086.                     returncode = TRUE;
  1087.                 }
  1088.             }
  1089.             break;
  1090.         case FIFHEALED:
  1091.             // Proceed only if the character was healed
  1092.             returncode = ((chralert[character]&ALERTIFHEALED)!=0);
  1093.             break;
  1094.         case FSENDMESSAGE:
  1095.             // This function sends a message to the players
  1096.             display_message(madmsgstart[chrmodel[character]]+valuetmpargument, character);
  1097.             break;
  1098.         case FCALLFORHELP:
  1099.             // This function issues a call for help
  1100.             call_for_help(character);
  1101.             break;
  1102.         case FADDIDSZ:
  1103.             // This function adds an idsz to the module's menu.txt file
  1104.             add_module_idsz(pickedmodule, valuetmpargument);
  1105.             break;
  1106.         case FSETSTATE:
  1107.             // This function sets the character's state variable
  1108.             chraistate[character] = valuetmpargument;
  1109.             break;
  1110.         case FGETSTATE:
  1111.             // This function reads the character's state variable
  1112.             valuetmpargument = chraistate[character];
  1113.             break;
  1114.         case FIFSTATEIS:
  1115.             // This function fails if the character's state is inequal to tmpargument
  1116.             returncode = (valuetmpargument == chraistate[character]);
  1117.             break;
  1118.         case FIFTARGETCANOPENSTUFF:
  1119.             // This function fails if the target can't open stuff
  1120.             returncode = chropenstuff[chraitarget[character]];
  1121.             break;
  1122.         case FIFGRABBED:
  1123.             // Proceed only if the character was picked up
  1124.             returncode = ((chralert[character]&ALERTIFGRABBED)!=0);
  1125.             break;
  1126.         case FIFDROPPED:
  1127.             // Proceed only if the character was dropped
  1128.             returncode = ((chralert[character]&ALERTIFDROPPED)!=0);
  1129.             break;
  1130.         case FSETTARGETTOWHOEVERISHOLDING:
  1131.             // This function sets the target to the character's mount or holder,
  1132.             // failing if the character has no mount or holder
  1133.             returncode = FALSE;
  1134.             if(chrattachedto[character] < MAXCHR)
  1135.             {
  1136.                 chraitarget[character] = chrattachedto[character];
  1137.                 returncode = TRUE;
  1138.             }
  1139.             break;
  1140.         case FDAMAGETARGET:
  1141.             // This function applies little bit of love to the character's target.
  1142.             // The amount is set in tmpargument
  1143.             damage_character(chraitarget[character], 0, valuetmpargument, 1, chrdamagetargettype[character], chrteam[character], character, DAMFXBLOC);
  1144.             break;
  1145.         case FIFXISLESSTHANY:
  1146.             // Proceed only if tmpx is less than tmpy
  1147.             returncode = (valuetmpx < valuetmpy);
  1148.             break;
  1149.         case FSETWEATHERTIME:
  1150.             // Set the weather timer
  1151.             weathertimereset = valuetmpargument;
  1152.             weathertime = valuetmpargument;
  1153.             break;
  1154.         case FGETBUMPHEIGHT:
  1155.             // Get the characters bump height
  1156.             valuetmpargument = chrbumpheight[character];
  1157.             break;
  1158.         case FIFREAFFIRMED:
  1159.             // Proceed only if the character was reaffirmed
  1160.             returncode = ((chralert[character]&ALERTIFREAFFIRMED)!=0);
  1161.             break;
  1162.         case FUNKEEPACTION:
  1163.             // This function makes the current animation start again
  1164.             chrkeepaction[character] = FALSE;
  1165.             break;
  1166.         case FIFTARGETISONOTHERTEAM:
  1167.             // This function proceeds only if the target is on another team
  1168.             returncode = (chralive[chraitarget[character]] && chrteam[chraitarget[character]]!=chrteam[character]);
  1169.             break;
  1170.         case FIFTARGETISONHATEDTEAM:
  1171.             // This function proceeds only if the target is on an enemy team
  1172.             returncode = (chralive[chraitarget[character]] && teamhatesteam[chrteam[character]][chrteam[chraitarget[character]]] && chrinvictus[chraitarget[character]] == FALSE );
  1173.             break;
  1174.         case FPRESSLATCHBUTTON:
  1175.             // This function sets the latch buttons
  1176.             chrlatchbutton[character] = chrlatchbutton[character]|valuetmpargument;
  1177.             break;
  1178.         case FSETTARGETTOTARGETOFLEADER:
  1179.             // This function sets the character's target to the target of its leader,
  1180.             // or it fails with no change if the leader is dead
  1181.             returncode = FALSE;
  1182.             if(teamleader[chrteam[character]]!=NOLEADER)
  1183.             {
  1184.                 chraitarget[character] = chraitarget[teamleader[chrteam[character]]];
  1185.                 returncode = TRUE;
  1186.             }
  1187.             break;
  1188.         case FIFLEADERKILLED:
  1189.             // This function proceeds only if the character's leader has just died
  1190.             returncode = ((chralert[character]&ALERTIFLEADERKILLED)!=0);
  1191.             break;
  1192.         case FBECOMELEADER:
  1193.             // This function makes the character the team leader
  1194.             teamleader[chrteam[character]]=character;
  1195.             break;
  1196.         case FCHANGETARGETARMOR:
  1197.             // This function sets the target's armor type and returns the old type
  1198.             // as tmpargument and the new type as tmpx
  1199.             iTmp = chrtexture[chraitarget[character]]-madskinstart[chrmodel[chraitarget[character]]];
  1200.             valuetmpx = change_armor(chraitarget[character], valuetmpargument);
  1201.             valuetmpargument = iTmp;  // The character's old armor
  1202.             break;
  1203.         case FGIVEMONEYTOTARGET:
  1204.             // This function transfers money from the character to the target, and sets
  1205.             // tmpargument to the amount transferred
  1206.             iTmp = chrmoney[character];
  1207.             tTmp = chrmoney[chraitarget[character]];
  1208.             iTmp-=valuetmpargument;
  1209.             tTmp+=valuetmpargument;
  1210.             if(iTmp < 0) { tTmp+=iTmp;  valuetmpargument+=iTmp;  iTmp = 0; }
  1211.             if(tTmp < 0) { iTmp+=tTmp;  valuetmpargument+=tTmp;  tTmp = 0; }
  1212.             if(iTmp > MAXMONEY) { iTmp = MAXMONEY; }
  1213.             if(tTmp > MAXMONEY) { tTmp = MAXMONEY; }
  1214.             chrmoney[character] = iTmp;
  1215.             chrmoney[chraitarget[character]] = tTmp;
  1216.             break;
  1217.         case FDROPKEYS:
  1218.             drop_keys(character);
  1219.             break;
  1220.         case FIFLEADERISALIVE:
  1221.             // This function fails if there is no team leader
  1222.             returncode = (teamleader[chrteam[character]]!=NOLEADER);
  1223.             break;
  1224.         case FIFTARGETISOLDTARGET:
  1225.             // This function returns FALSE if the target has changed
  1226.             returncode = (chraitarget[character]==valueoldtarget);
  1227.             break;
  1228.         case FSETTARGETTOLEADER:
  1229.             // This function fails if there is no team leader
  1230.             if(teamleader[chrteam[character]]==NOLEADER)
  1231.             {
  1232.                 returncode = FALSE;
  1233.             }
  1234.             else
  1235.             {
  1236.                 chraitarget[character] = teamleader[chrteam[character]];
  1237.             }
  1238.             break;
  1239.         case FSPAWNCHARACTER:
  1240.             // This function spawns a character, failing if x,y is invalid
  1241.             sTmp = spawn_one_character(valuetmpx, valuetmpy, 0, chrmodel[character], chrteam[character], 0, valuetmpturn, NULL, MAXCHR);
  1242.             returncode = FALSE;
  1243.             if(sTmp < MAXCHR)
  1244.             {
  1245.                 if(__chrhitawall(sTmp))
  1246.                 {
  1247.                     free_one_character(sTmp);
  1248.                 }
  1249.                 else
  1250.                 {
  1251.                     tTmp = chrturnleftright[character]>>2;
  1252.                     chrxvel[sTmp]+=turntosin[(tTmp+12288)&16383]*valuetmpdistance;
  1253.                     chryvel[sTmp]+=turntosin[(tTmp+8192)&16383]*valuetmpdistance;
  1254.                     chrpassage[sTmp] = chrpassage[character];
  1255.                     chriskursed[sTmp] = FALSE;
  1256.                     chraichild[character] = sTmp;
  1257.                     chraiowner[sTmp] = chraiowner[character];
  1258.                     returncode = TRUE;
  1259.                 }
  1260.             }
  1261.             break;
  1262.         case FRESPAWNCHARACTER:
  1263.             // This function respawns the character at its starting location
  1264.             respawn_character(character);
  1265.             break;
  1266.         case FCHANGETILE:
  1267.             // This function changes the floor image under the character
  1268.             meshtile[chronwhichfan[character]]=valuetmpargument&(255);
  1269.             break;
  1270.         case FIFUSED:
  1271.             // This function proceeds only if the character has been used
  1272.             returncode = ((chralert[character]&ALERTIFUSED)!=0);
  1273.             break;
  1274.         case FDROPMONEY:
  1275.             // This function drops some of a character's money
  1276.             drop_money(character, valuetmpargument);
  1277.             break;
  1278.         case FSETOLDTARGET:
  1279.             // This function sets the old target to the current target
  1280.             valueoldtarget = chraitarget[character];
  1281.             break;
  1282.         case FDETACHFROMHOLDER:
  1283.             // This function drops the character, failing only if it was not held
  1284.             if(chrattachedto[character]!=MAXCHR)
  1285.             {
  1286.                 detach_character_from_mount(character, TRUE, TRUE);
  1287.             }
  1288.             else
  1289.             {
  1290.                 returncode = FALSE;
  1291.             }
  1292.             break;
  1293.         case FIFTARGETHASVULNERABILITYID:
  1294.             // This function proceeds if ID matches tmpargument
  1295.             returncode = (capidsz[chrmodel[chraitarget[character]]][IDSZVULNERABILITY]==(unsigned int) valuetmpargument);
  1296.             break;
  1297.         case FCLEANUP:
  1298.             // This function issues the clean up order to all teammates
  1299.             issue_clean(character);
  1300.             break;
  1301.         case FIFCLEANEDUP:
  1302.             // This function proceeds only if the character was told to clean up
  1303.             returncode = ((chralert[character]&ALERTIFCLEANEDUP)!=0);
  1304.             break;
  1305.         case FIFSITTING:
  1306.             // This function proceeds if the character is riding another
  1307.             returncode = (chrattachedto[character]!=MAXCHR);
  1308.             break;
  1309.         case FIFTARGETISHURT:
  1310.             // This function passes only if the target is hurt and alive
  1311.             if(chralive[chraitarget[character]]==FALSE || chrlife[chraitarget[character]] > chrlifemax[chraitarget[character]]-HURTDAMAGE)
  1312.                 returncode = FALSE;
  1313.             break;
  1314.         case FIFTARGETISAPLAYER:
  1315.             // This function proceeds only if the target is a player ( may not be local )
  1316.             returncode = chrisplayer[chraitarget[character]];
  1317.             break;
  1318.         case FPLAYSOUND:
  1319.             // This function plays a sound
  1320.             if(chroldz[character] > PITNOSOUND)
  1321.             {
  1322.                 distance = ABS(camtrackx-chroldx[character])+ABS(camtracky-chroldy[character]);
  1323.                 volume = -distance;
  1324.                 volume = volume<<VOLSHIFT;
  1325.                 if(volume > VOLMIN && moduleactive)
  1326.                 {
  1327.  
  1328.                     play_sound_pvf(capwaveindex[chrmodel[character]][valuetmpargument], PANMID, volume, valuetmpdistance);
  1329.  
  1330.                 }
  1331.             }
  1332.             break;
  1333.         case FSPAWNPARTICLE:
  1334.             // This function spawns a particle
  1335.             tTmp = character;
  1336.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  1337.             tTmp = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], chrturnleftright[character], chrmodel[character], valuetmpargument, character, valuetmpdistance, chrteam[character], tTmp, 0, MAXCHR);
  1338.             if(tTmp!=MAXPRT)
  1339.             {
  1340.                 // Detach the particle
  1341.                 attach_particle_to_character(tTmp, character, valuetmpdistance);
  1342.                 prtattachedtocharacter[tTmp]=MAXCHR;
  1343.                 // Correct X, Y, Z spacing
  1344.                 prtxpos[tTmp]+=valuetmpx;
  1345.                 prtypos[tTmp]+=valuetmpy;
  1346.                 prtzpos[tTmp]+=pipzspacingbase[prtpip[tTmp]];
  1347.                 // Don't spawn in walls
  1348.                 if(__prthitawall(tTmp))
  1349.                 {
  1350.                     prtxpos[tTmp] = chrxpos[character];
  1351.                     if(__prthitawall(tTmp))
  1352.                     {
  1353.                         prtypos[tTmp] = chrypos[character];
  1354.                     }
  1355.                 }
  1356.             }
  1357.             break;
  1358.         case FIFTARGETISALIVE:
  1359.             // This function proceeds only if the target is alive
  1360.             returncode = (chralive[chraitarget[character]]==TRUE);
  1361.             break;
  1362.         case FSTOP:
  1363.             chrmaxaccel[character] = 0;
  1364.             break;
  1365.         case FDISAFFIRMCHARACTER:
  1366.             disaffirm_attached_particles(character);
  1367.             break;
  1368.         case FREAFFIRMCHARACTER:
  1369.             reaffirm_attached_particles(character);
  1370.             break;
  1371.         case FIFTARGETISSELF:
  1372.             // This function proceeds only if the target is the character too
  1373.             returncode = (chraitarget[character]==character);
  1374.             break;
  1375.         case FIFTARGETISMALE:
  1376.             // This function proceeds only if the target is male
  1377.             returncode = (chrgender[character]==GENMALE);
  1378.             break;
  1379.         case FIFTARGETISFEMALE:
  1380.             // This function proceeds only if the target is female
  1381.             returncode = (chrgender[character]==GENFEMALE);
  1382.             break;
  1383.         case FSETTARGETTOSELF:
  1384.             // This function sets the target to the character
  1385.             chraitarget[character] = character;
  1386.             break;
  1387.         case FSETTARGETTORIDER:
  1388.             // This function sets the target to the character's left/only grip weapon,
  1389.             // failing if there is none
  1390.             if(chrholdingwhich[character][0]==MAXCHR)
  1391.             {
  1392.                 returncode = FALSE;
  1393.             }
  1394.             else
  1395.             {
  1396.                 chraitarget[character] = chrholdingwhich[character][0];
  1397.             }
  1398.             break;
  1399.         case FGETATTACKTURN:
  1400.             // This function sets tmpturn to the direction of the last attack
  1401.             valuetmpturn = chrdirectionlast[character];
  1402.             break;
  1403.         case FGETDAMAGETYPE:
  1404.             // This function gets the last type of damage
  1405.             valuetmpargument = chrdamagetypelast[character];
  1406.             break;
  1407.         case FBECOMESPELL:
  1408.             // This function turns the spellbook character into a spell based on its
  1409.             // content
  1410.             chrmoney[character] = (chrtexture[character]-madskinstart[chrmodel[character]])&3;
  1411.             change_character(character, chraicontent[character], 0, LEAVENONE);
  1412.             chraicontent[character] = 0;  // Reset so it doesn't mess up
  1413.             chraistate[character] = 0;  // Reset so it doesn't mess up
  1414.             changed = TRUE;
  1415.             break;
  1416.         case FBECOMESPELLBOOK:
  1417.             // This function turns the spell into a spellbook, and sets the content
  1418.             // accordingly
  1419.             chraicontent[character] = chrmodel[character];
  1420.             change_character(character, SPELLBOOK, chrmoney[character]&3, LEAVENONE);
  1421.             chraistate[character] = 0;  // Reset so it doesn't burn up
  1422.             changed = TRUE;
  1423.             break;
  1424.         case FIFSCOREDAHIT:
  1425.             // Proceed only if the character scored a hit
  1426.             returncode = ((chralert[character]&ALERTIFSCOREDAHIT)!=0);
  1427.             break;
  1428.         case FIFDISAFFIRMED:
  1429.             // Proceed only if the character was disaffirmed
  1430.             returncode = ((chralert[character]&ALERTIFDISAFFIRMED)!=0);
  1431.             break;
  1432.         case FTRANSLATEORDER:
  1433.             // This function gets the order and sets tmpx, tmpy, tmpargument and the 
  1434.             // target ( if valid )
  1435.             sTmp = chrorder[character]>>24;
  1436.             if(sTmp < MAXCHR)
  1437.             {
  1438.                 chraitarget[character] = sTmp;
  1439.             }
  1440.             valuetmpx = ((chrorder[character]>>14)&1023)<<6;
  1441.             valuetmpy = ((chrorder[character]>>4)&1023)<<6;
  1442.             valuetmpargument = chrorder[character]&15;
  1443.             break;
  1444.         case FSETTARGETTOWHOEVERWASHIT:
  1445.             // This function sets the target to whoever the character hit last,
  1446.             chraitarget[character]=chrhitlast[character];
  1447.             break;
  1448.         case FSETTARGETTOWIDEENEMY:
  1449.             // This function finds an enemy, and proceeds only if there is one
  1450.             sTmp = get_wide_target(character, FALSE, FALSE, TRUE, FALSE, IDSZNONE, FALSE);
  1451.             returncode = FALSE;
  1452.             if(sTmp != MAXCHR)
  1453.             {
  1454.                 chraitarget[character] = sTmp;
  1455.                 returncode = TRUE;
  1456.             }
  1457.             break;
  1458.         case FIFCHANGED:
  1459.             // Proceed only if the character was polymorphed
  1460.             returncode = ((chralert[character]&ALERTIFCHANGED)!=0);
  1461.             break;
  1462.         case FIFINWATER:
  1463.             // Proceed only if the character got wet
  1464.             returncode = ((chralert[character]&ALERTIFINWATER)!=0);
  1465.             break;
  1466.         case FIFBORED:
  1467.             // Proceed only if the character is bored
  1468.             returncode = ((chralert[character]&ALERTIFBORED)!=0);
  1469.             break;
  1470.         case FIFTOOMUCHBAGGAGE:
  1471.             // Proceed only if the character tried to grab too much
  1472.             returncode = ((chralert[character]&ALERTIFTOOMUCHBAGGAGE)!=0);
  1473.             break;
  1474.         case FIFGROGGED:
  1475.             // Proceed only if the character was grogged
  1476.             returncode = ((chralert[character]&ALERTIFGROGGED)!=0);
  1477.             break;
  1478.         case FIFDAZED:
  1479.             // Proceed only if the character was dazed
  1480.             returncode = ((chralert[character]&ALERTIFDAZED)!=0);
  1481.             break;
  1482.         case FIFTARGETHASSPECIALID:
  1483.             // This function proceeds if ID matches tmpargument
  1484.             returncode = (capidsz[chrmodel[chraitarget[character]]][IDSZSPECIAL]==(unsigned int) valuetmpargument);
  1485.             break;
  1486.         case FPRESSTARGETLATCHBUTTON:
  1487.             // This function sets the target's latch buttons
  1488.             chrlatchbutton[chraitarget[character]] = chrlatchbutton[chraitarget[character]]|valuetmpargument;
  1489.             break;
  1490.         case FIFINVISIBLE:
  1491.             // This function passes if the character is invisible
  1492.             returncode = (chralpha[character]<=INVISIBLE)||(chrlight[character]<=INVISIBLE);
  1493.             break;
  1494.         case FIFARMORIS:
  1495.             // This function passes if the character's skin is tmpargument
  1496.             tTmp = chrtexture[character]-madskinstart[chrmodel[character]];
  1497.             returncode = (tTmp==valuetmpargument);
  1498.             break;
  1499.         case FGETTARGETGROGTIME:
  1500.             // This function returns tmpargument as the grog time, and passes if it is not 0
  1501.             valuetmpargument = chrgrogtime[character];
  1502.             returncode = (valuetmpargument!=0);
  1503.             break;
  1504.         case FGETTARGETDAZETIME:
  1505.             // This function returns tmpargument as the daze time, and passes if it is not 0
  1506.             valuetmpargument = chrdazetime[character];
  1507.             returncode = (valuetmpargument!=0);
  1508.             break;
  1509.         case FSETDAMAGETYPE:
  1510.             // This function sets the bump damage type
  1511.             chrdamagetargettype[character] = valuetmpargument&(MAXDAMAGETYPE-1);
  1512.             break;
  1513.         case FSETWATERLEVEL:
  1514.             // This function raises and lowers the module's water
  1515.             fTmp = (valuetmpargument/10.0) - waterdouselevel;
  1516.             watersurfacelevel+=fTmp;
  1517.             waterdouselevel+=fTmp;
  1518.             for (iTmp = 0; iTmp < MAXWATERLAYER; iTmp++)
  1519.                 waterlayerz[iTmp]+=fTmp;
  1520.             break;
  1521.         case FENCHANTTARGET:
  1522.             // This function enchants the target
  1523.             sTmp = spawn_enchant(chraiowner[character], chraitarget[character], character, MAXENCHANT, MAXMODEL);
  1524.             returncode = (sTmp != MAXENCHANT);
  1525.             break;
  1526.         case FENCHANTCHILD:
  1527.             // This function can be used with SpawnCharacter to enchant the
  1528.             // newly spawned character
  1529.             sTmp = spawn_enchant(chraiowner[character], chraichild[character], character, MAXENCHANT, MAXMODEL);
  1530.             returncode = (sTmp != MAXENCHANT);
  1531.             break;
  1532.         case FTELEPORTTARGET:
  1533.             // This function teleports the target to the X, Y location, failing if the
  1534.             // location is off the map or blocked
  1535.             returncode = FALSE;
  1536.             if(valuetmpx > EDGE && valuetmpy > EDGE && valuetmpx < meshedgex-EDGE && valuetmpy < meshedgey-EDGE)
  1537.             {
  1538.                 // Yeah!  It worked!
  1539.                 sTmp = chraitarget[character];
  1540.                 detach_character_from_mount(sTmp, TRUE, FALSE);
  1541.                 chroldx[sTmp] = chrxpos[sTmp];
  1542.                 chroldy[sTmp]= chrypos[sTmp];
  1543.                 chrxpos[sTmp] = valuetmpx;
  1544.                 chrypos[sTmp] = valuetmpy;
  1545.                 if(__chrhitawall(sTmp))
  1546.                 {
  1547.                     // No it didn't...
  1548.                     chrxpos[sTmp] = chroldx[sTmp];
  1549.                     chrypos[sTmp] = chroldy[sTmp];
  1550.                     returncode = FALSE;
  1551.                 }
  1552.                 else
  1553.                 {
  1554.                     chroldx[sTmp] = chrxpos[sTmp];
  1555.                     chroldy[sTmp]= chrypos[sTmp];
  1556.                     returncode = TRUE;
  1557.                 }
  1558.             }
  1559.             break;
  1560.         case FGIVEEXPERIENCETOTARGET:
  1561.             // This function gives the target some experience, xptype from distance,
  1562.             // amount from argument...
  1563.             give_experience(chraitarget[character], valuetmpargument, valuetmpdistance);
  1564.             break;
  1565.         case FINCREASEAMMO:
  1566.             // This function increases the ammo by one
  1567.             if(chrammo[character] < chrammomax[character])
  1568.             {
  1569.                 chrammo[character]++;
  1570.             }
  1571.             break;
  1572.         case FUNKURSETARGET:
  1573.             // This function unkurses the target
  1574.             chriskursed[chraitarget[character]] = FALSE;
  1575.             break;
  1576.         case FGIVEEXPERIENCETOTARGETTEAM:
  1577.             // This function gives experience to everyone on the target's team
  1578.             give_team_experience(chrteam[chraitarget[character]], valuetmpargument, valuetmpdistance);
  1579.             break;
  1580.         case FIFUNARMED:
  1581.             // This function proceeds if the character has no item in hand
  1582.             returncode = (chrholdingwhich[character][0] == MAXCHR && chrholdingwhich[character][1] == MAXCHR);
  1583.             break;
  1584.         case FRESTOCKTARGETAMMOIDALL:
  1585.             // This function restocks the ammo of every item the character is holding,
  1586.             // if the item matches the ID given ( parent or child type )
  1587.             iTmp = 0;  // Amount of ammo given
  1588.             sTmp = chrholdingwhich[chraitarget[character]][0];
  1589.             iTmp += restock_ammo(sTmp, valuetmpargument);
  1590.             sTmp = chrholdingwhich[chraitarget[character]][1];
  1591.             iTmp += restock_ammo(sTmp, valuetmpargument);
  1592.             sTmp = chrnextinpack[chraitarget[character]];
  1593.             while(sTmp != MAXCHR)
  1594.             {
  1595.                 iTmp += restock_ammo(sTmp, valuetmpargument);
  1596.                 sTmp = chrnextinpack[sTmp];
  1597.             }
  1598.             valuetmpargument = iTmp;
  1599.             returncode = (iTmp != 0);
  1600.             break;
  1601.         case FRESTOCKTARGETAMMOIDFIRST:
  1602.             // This function restocks the ammo of the first item the character is holding,
  1603.             // if the item matches the ID given ( parent or child type )
  1604.             iTmp = 0;  // Amount of ammo given
  1605.             sTmp = chrholdingwhich[chraitarget[character]][0];
  1606.             iTmp += restock_ammo(sTmp, valuetmpargument);
  1607.             if(iTmp == 0)
  1608.             {
  1609.                 sTmp = chrholdingwhich[chraitarget[character]][1];
  1610.                 iTmp += restock_ammo(sTmp, valuetmpargument);
  1611.                 if(iTmp == 0)
  1612.                 {
  1613.                     sTmp = chrnextinpack[chraitarget[character]];
  1614.                     while(sTmp != MAXCHR && iTmp == 0)
  1615.                     {
  1616.                         iTmp += restock_ammo(sTmp, valuetmpargument);
  1617.                         sTmp = chrnextinpack[sTmp];
  1618.                     }
  1619.                 }
  1620.             }
  1621.             valuetmpargument = iTmp;
  1622.             returncode = (iTmp != 0);
  1623.             break;
  1624.         case FFLASHTARGET:
  1625.             // This function flashes the character
  1626.             flash_character(chraitarget[character], 255);
  1627.             break;
  1628.         case FSETREDSHIFT:
  1629.             // This function alters a character's coloration
  1630.             chrredshift[character] = valuetmpargument;
  1631.             break;
  1632.         case FSETGREENSHIFT:
  1633.             // This function alters a character's coloration
  1634.             chrgrnshift[character] = valuetmpargument;
  1635.             break;
  1636.         case FSETBLUESHIFT:
  1637.             // This function alters a character's coloration
  1638.             chrblushift[character] = valuetmpargument;
  1639.             break;
  1640.         case FSETLIGHT:
  1641.             // This function alters a character's transparency
  1642.             chrlight[character] = valuetmpargument;
  1643.             break;
  1644.         case FSETALPHA:
  1645.             // This function alters a character's transparency
  1646.             chralpha[character] = valuetmpargument;
  1647.             break;
  1648.         case FIFHITFROMBEHIND:
  1649.             // This function proceeds if the character was attacked from behind
  1650.             returncode = FALSE;
  1651.             if(chrdirectionlast[character] >= BEHIND-8192 && chrdirectionlast[character] < BEHIND+8192)
  1652.                 returncode = TRUE;
  1653.             break;
  1654.         case FIFHITFROMFRONT:
  1655.             // This function proceeds if the character was attacked from the front
  1656.             returncode = FALSE;
  1657.             if(chrdirectionlast[character] >= 49152+8192 || chrdirectionlast[character] < FRONT+8192)
  1658.                 returncode = TRUE;
  1659.             break;
  1660.         case FIFHITFROMLEFT:
  1661.             // This function proceeds if the character was attacked from the left
  1662.             returncode = FALSE;
  1663.             if(chrdirectionlast[character] >= LEFT-8192 && chrdirectionlast[character] < LEFT+8192)
  1664.                 returncode = TRUE;
  1665.             break;
  1666.         case FIFHITFROMRIGHT:
  1667.             // This function proceeds if the character was attacked from the right
  1668.             returncode = FALSE;
  1669.             if(chrdirectionlast[character] >= RIGHT-8192 && chrdirectionlast[character] < RIGHT+8192)
  1670.                 returncode = TRUE;
  1671.             break;
  1672.         case FIFTARGETISONSAMETEAM:
  1673.             // This function proceeds only if the target is on another team
  1674.             returncode = FALSE;
  1675.             if(chrteam[chraitarget[character]]==chrteam[character])
  1676.                 returncode = TRUE;
  1677.             break;
  1678.         case FKILLTARGET:
  1679.             // This function kills the target
  1680.             kill_character(chraitarget[character], character);
  1681.             break;
  1682.         case FUNDOENCHANT:
  1683.             // This function undoes the last enchant
  1684.             returncode = (chrundoenchant[character]!=MAXENCHANT);
  1685.             remove_enchant(chrundoenchant[character]);
  1686.             break;
  1687.         case FGETWATERLEVEL:
  1688.             // This function gets the douse level for the water, returning it in tmpargument
  1689.             valuetmpargument = waterdouselevel*10;
  1690.             break;
  1691.         case FCOSTTARGETMANA:
  1692.             // This function costs the target some mana
  1693.             returncode = cost_mana(chraitarget[character], valuetmpargument, character);
  1694.             break;
  1695.         case FIFTARGETHASANYID:
  1696.             // This function proceeds only if one of the target's IDSZ's matches tmpargument
  1697.             returncode = 0;
  1698.             tTmp = 0;
  1699.             while(tTmp < MAXIDSZ)
  1700.             {
  1701.                 returncode |= (capidsz[chrmodel[chraitarget[character]]][tTmp]==(unsigned int) valuetmpargument);
  1702.                 tTmp++;
  1703.             }
  1704.             break;
  1705.         case FSETBUMPSIZE:
  1706.             // This function sets the character's bump size
  1707.             fTmp = chrbumpsizebig[character];
  1708.             fTmp = fTmp/chrbumpsize[character];  // 1.5 or 2.0
  1709.             chrbumpsize[character] = valuetmpargument*chrfat[character];
  1710.             chrbumpsizebig[character] = fTmp*chrbumpsize[character];
  1711.             chrbumpsizesave[character] = valuetmpargument;
  1712.             chrbumpsizebigsave[character] = fTmp*chrbumpsizesave[character];
  1713.             break;
  1714.         case FIFNOTDROPPED:
  1715.             // This function passes if a kursed item could not be dropped
  1716.             returncode = ((chralert[character]&ALERTIFNOTDROPPED)!=0);
  1717.             break;
  1718.         case FIFYISLESSTHANX:
  1719.             // This function passes only if tmpy is less than tmpx
  1720.             returncode = (valuetmpy < valuetmpx);
  1721.             break;
  1722.         case FSETFLYHEIGHT:
  1723.             // This function sets a character's fly height
  1724.             chrflyheight[character] = valuetmpargument;
  1725.             break;
  1726.         case FIFBLOCKED:
  1727.             // This function passes if the character blocked an attack
  1728.             returncode = ((chralert[character]&ALERTIFBLOCKED)!=0);
  1729.             break;
  1730.         case FIFTARGETISDEFENDING:
  1731.             returncode = (chraction[chraitarget[character]] >= ACTIONPA && chraction[chraitarget[character]] <= ACTIONPD);
  1732.             break;
  1733.         case FIFTARGETISATTACKING:
  1734.             returncode = (chraction[chraitarget[character]] >= ACTIONUA && chraction[chraitarget[character]] <= ACTIONFD);
  1735.             break;
  1736.         case FIFSTATEIS0:
  1737.             returncode = (0 == chraistate[character]);
  1738.             break;
  1739.         case FIFSTATEIS1:
  1740.             returncode = (1 == chraistate[character]);
  1741.             break;
  1742.         case FIFSTATEIS2:
  1743.             returncode = (2 == chraistate[character]);
  1744.             break;
  1745.         case FIFSTATEIS3:
  1746.             returncode = (3 == chraistate[character]);
  1747.             break;
  1748.         case FIFSTATEIS4:
  1749.             returncode = (4 == chraistate[character]);
  1750.             break;
  1751.         case FIFSTATEIS5:
  1752.             returncode = (5 == chraistate[character]);
  1753.             break;
  1754.         case FIFSTATEIS6:
  1755.             returncode = (6 == chraistate[character]);
  1756.             break;
  1757.         case FIFSTATEIS7:
  1758.             returncode = (7 == chraistate[character]);
  1759.             break;
  1760.         case FIFCONTENTIS:
  1761.             returncode = (valuetmpargument == chraicontent[character]);
  1762.             break;
  1763.         case FSETTURNMODETOWATCHTARGET:
  1764.             // This function sets the turn mode
  1765.             chrturnmode[character] = TURNMODEWATCHTARGET;
  1766.             break;
  1767.         case FIFSTATEISNOT:
  1768.             returncode = (valuetmpargument != chraistate[character]);
  1769.             break;
  1770.         case FIFXISEQUALTOY:
  1771.             returncode = (valuetmpx == valuetmpy);
  1772.             break;
  1773.         case FDEBUGMESSAGE:
  1774.             // This function spits out a debug message
  1775.             sprintf(szDebug, "aistate %d, aicontent %d, target %d", chraistate[character], chraicontent[character], chraitarget[character]);
  1776.             debug_message(szDebug);
  1777.             sprintf(szDebug, "tmpx %d, tmpy %d", valuetmpx, valuetmpy);
  1778.             debug_message(szDebug);
  1779.             sprintf(szDebug, "tmpdistance %d, tmpturn %d", valuetmpdistance, valuetmpturn);
  1780.             debug_message(szDebug);
  1781.             sprintf(szDebug, "tmpargument %d, selfturn %d", valuetmpargument, chrturnleftright[character]);
  1782.             debug_message(szDebug);
  1783.             break;
  1784.         case FBLACKTARGET:
  1785.             // This function makes the target flash black
  1786.             flash_character(chraitarget[character], 0);
  1787.             break;
  1788.         case FSENDMESSAGENEAR:
  1789.             // This function sends a message if the camera is in the nearby area.
  1790.             iTmp = ABS(chroldx[character]-camtrackx) + ABS(chroldy[character]-camtracky);
  1791.             if(iTmp < MSGDISTANCE)
  1792.                 display_message(madmsgstart[chrmodel[character]]+valuetmpargument, character);
  1793.             break;
  1794.         case FIFHITGROUND:
  1795.             // This function passes if the character just hit the ground
  1796.             returncode = ((chralert[character]&ALERTIFHITGROUND)!=0);
  1797.             break;
  1798.         case FIFNAMEISKNOWN:
  1799.             // This function passes if the character's name is known
  1800.             returncode = chrnameknown[character];
  1801.             break;
  1802.         case FIFUSAGEISKNOWN:
  1803.             // This function passes if the character's usage is known
  1804.             returncode = capusageknown[chrmodel[character]];
  1805.             break;
  1806.         case FIFHOLDINGITEMID:
  1807.             // This function passes if the character is holding an item with the IDSZ given
  1808.             // in tmpargument, returning the latch to press to use it
  1809.             returncode = FALSE;
  1810.             // Check left hand
  1811.             sTmp = chrholdingwhich[character][0];
  1812.             if(sTmp != MAXCHR)
  1813.             {
  1814.                 sTmp = chrmodel[sTmp];
  1815.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  1816.                 {
  1817.                     valuetmpargument = LATCHBUTTONLEFT;
  1818.                     returncode = TRUE;
  1819.                 }
  1820.             }
  1821.             // Check right hand
  1822.             sTmp = chrholdingwhich[character][1];
  1823.             if(sTmp != MAXCHR)
  1824.             {
  1825.                 sTmp = chrmodel[sTmp];
  1826.                 if(capidsz[sTmp][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[sTmp][IDSZTYPE]==(unsigned int) valuetmpargument)
  1827.                 {
  1828.                     valuetmpargument = LATCHBUTTONRIGHT;
  1829.                     if(returncode == TRUE)  valuetmpargument = LATCHBUTTONLEFT+(rand()&1);
  1830.                     returncode = TRUE;
  1831.                 }
  1832.             }
  1833.             break;
  1834.         case FIFHOLDINGRANGEDWEAPON:
  1835.             // This function passes if the character is holding a ranged weapon, returning
  1836.             // the latch to press to use it.  This also checks ammo/ammoknown.
  1837.             returncode = FALSE;
  1838.             valuetmpargument = 0;
  1839.             // Check left hand
  1840.             tTmp = chrholdingwhich[character][0];
  1841.             if(tTmp != MAXCHR)
  1842.             {
  1843.                 sTmp = chrmodel[tTmp];
  1844.                 if(capisranged[sTmp] && (chrammomax[tTmp]==0 || (chrammo[tTmp]!=0 && chrammoknown[tTmp])))
  1845.                 {
  1846.                     valuetmpargument = LATCHBUTTONLEFT;
  1847.                     returncode = TRUE;
  1848.                 }
  1849.             }
  1850.             // Check right hand
  1851.             tTmp = chrholdingwhich[character][1];
  1852.             if(tTmp != MAXCHR)
  1853.             {
  1854.                 sTmp = chrmodel[tTmp];
  1855.                 if(capisranged[sTmp] && (chrammomax[tTmp]==0 || (chrammo[tTmp]!=0 && chrammoknown[tTmp])))
  1856.                 {
  1857.                     if(valuetmpargument == 0 || (allframe&1))
  1858.                     {
  1859.                         valuetmpargument = LATCHBUTTONRIGHT;
  1860.                         returncode = TRUE;
  1861.                     }
  1862.                 }
  1863.             }
  1864.             break;
  1865.         case FIFHOLDINGMELEEWEAPON:
  1866.             // This function passes if the character is holding a melee weapon, returning
  1867.             // the latch to press to use it
  1868.             returncode = FALSE;
  1869.             valuetmpargument = 0;
  1870.             // Check left hand
  1871.             sTmp = chrholdingwhich[character][0];
  1872.             if(sTmp != MAXCHR)
  1873.             {
  1874.                 sTmp = chrmodel[sTmp];
  1875.                 if(capisranged[sTmp]==FALSE && capweaponaction[sTmp]!=ACTIONPA)
  1876.                 {
  1877.                     valuetmpargument = LATCHBUTTONLEFT;
  1878.                     returncode = TRUE;
  1879.                 }
  1880.             }
  1881.             // Check right hand
  1882.             sTmp = chrholdingwhich[character][1];
  1883.             if(sTmp != MAXCHR)
  1884.             {
  1885.                 sTmp = chrmodel[sTmp];
  1886.                 if(capisranged[sTmp]==FALSE && capweaponaction[sTmp]!=ACTIONPA)
  1887.                 {
  1888.                     if(valuetmpargument == 0 || (allframe&1))
  1889.                     {
  1890.                         valuetmpargument = LATCHBUTTONRIGHT;
  1891.                         returncode = TRUE;
  1892.                     }
  1893.                 }
  1894.             }
  1895.             break;
  1896.         case FIFHOLDINGSHIELD:
  1897.             // This function passes if the character is holding a shield, returning the
  1898.             // latch to press to use it
  1899.             returncode = FALSE;
  1900.             valuetmpargument = 0;
  1901.             // Check left hand
  1902.             sTmp = chrholdingwhich[character][0];
  1903.             if(sTmp != MAXCHR)
  1904.             {
  1905.                 sTmp = chrmodel[sTmp];
  1906.                 if(capweaponaction[sTmp]==ACTIONPA)
  1907.                 {
  1908.                     valuetmpargument = LATCHBUTTONLEFT;
  1909.                     returncode = TRUE;
  1910.                 }
  1911.             }
  1912.             // Check right hand
  1913.             sTmp = chrholdingwhich[character][1];
  1914.             if(sTmp != MAXCHR)
  1915.             {
  1916.                 sTmp = chrmodel[sTmp];
  1917.                 if(capweaponaction[sTmp]==ACTIONPA)
  1918.                 {
  1919.                     valuetmpargument = LATCHBUTTONRIGHT;
  1920.                     returncode = TRUE;
  1921.                 }
  1922.             }
  1923.             break;
  1924.         case FIFKURSED:
  1925.             // This function passes if the character is kursed
  1926.             returncode = chriskursed[character];
  1927.             break;
  1928.         case FIFTARGETISKURSED:
  1929.             // This function passes if the target is kursed
  1930.             returncode = chriskursed[chraitarget[character]];
  1931.             break;
  1932.         case FIFTARGETISDRESSEDUP:
  1933.             // This function passes if the character's skin is dressy
  1934.             iTmp = chrtexture[character]-madskinstart[chrmodel[character]];
  1935.             iTmp = 1<<iTmp;
  1936.             returncode = ((capskindressy[chrmodel[character]]&iTmp)!=0);
  1937.             break;
  1938.         case FIFOVERWATER:
  1939.             // This function passes if the character is on a water tile
  1940.             returncode = ((meshfx[chronwhichfan[character]]&MESHFXWATER) != 0 && wateriswater);
  1941.             break;
  1942.         case FIFTHROWN:
  1943.             // This function passes if the character was thrown
  1944.             returncode = ((chralert[character]&ALERTIFTHROWN)!=0);
  1945.             break;
  1946.         case FMAKENAMEKNOWN:
  1947.             // This function makes the name of an item/character known.
  1948.             chrnameknown[character]=TRUE;
  1949. //            chricon[character] = TRUE;
  1950.             break;
  1951.         case FMAKEUSAGEKNOWN:
  1952.             // This function makes the usage of an item known...  For XP gains from
  1953.             // using an unknown potion or such
  1954.             capusageknown[chrmodel[character]] = TRUE;
  1955.             break;
  1956.         case FSTOPTARGETMOVEMENT:
  1957.             // This function makes the target stop moving temporarily
  1958.             chrxvel[chraitarget[character]] = 0;
  1959.             chryvel[chraitarget[character]] = 0;
  1960.             if(chrzvel[chraitarget[character]] > 0) chrzvel[chraitarget[character]] = gravity;
  1961.             break;
  1962.         case FSETXY:
  1963.             // This function stores tmpx and tmpy in the storage array
  1964.             chraix[character][valuetmpargument&STORAND] = valuetmpx;
  1965.             chraiy[character][valuetmpargument&STORAND] = valuetmpy;
  1966.             break;
  1967.         case FGETXY:
  1968.             // This function gets previously stored data, setting tmpx and tmpy
  1969.             valuetmpx = chraix[character][valuetmpargument&STORAND];
  1970.             valuetmpy = chraiy[character][valuetmpargument&STORAND];
  1971.             break;
  1972.         case FADDXY:
  1973.             // This function adds tmpx and tmpy to the storage array
  1974.             chraix[character][valuetmpargument&STORAND] += valuetmpx;
  1975.             chraiy[character][valuetmpargument&STORAND] += valuetmpy;
  1976.             break;
  1977.         case FMAKEAMMOKNOWN:
  1978.             // This function makes the ammo of an item/character known.
  1979.             chrammoknown[character]=TRUE;
  1980.             break;
  1981.         case FSPAWNATTACHEDPARTICLE:
  1982.             // This function spawns an attached particle
  1983.             tTmp = character;
  1984.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  1985.             tTmp = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], chrturnleftright[character], chrmodel[character], valuetmpargument, character, valuetmpdistance, chrteam[character], tTmp, 0, MAXCHR);
  1986.             break;
  1987.         case FSPAWNEXACTPARTICLE:
  1988.             // This function spawns an exactly placed particle
  1989.             tTmp = character;
  1990.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  1991.             spawn_one_particle(valuetmpx, valuetmpy, valuetmpdistance, chrturnleftright[character], chrmodel[character], valuetmpargument, MAXCHR, 0, chrteam[character], tTmp, 0, MAXCHR);
  1992.             break;
  1993.         case FACCELERATETARGET:
  1994.             // This function changes the target's speeds
  1995.             chrxvel[chraitarget[character]]+=valuetmpx;
  1996.             chryvel[chraitarget[character]]+=valuetmpy;
  1997.             break;
  1998.         case FIFDISTANCEISMORETHANTURN:
  1999.             // This function proceeds tmpdistance is greater than tmpturn
  2000.             returncode = (valuetmpdistance > (int) valuetmpturn);
  2001.             break;
  2002.         case FIFCRUSHED:
  2003.             // This function proceeds only if the character was crushed
  2004.             returncode = ((chralert[character]&ALERTIFCRUSHED)!=0);
  2005.             break;
  2006.         case FMAKECRUSHVALID:
  2007.             // This function makes doors able to close on this object
  2008.             chrcanbecrushed[character] = TRUE;
  2009.             break;
  2010.         case FSETTARGETTOLOWESTTARGET:
  2011.             // This sets the target to whatever the target is being held by,
  2012.             // The lowest in the set.  This function never fails
  2013.             while(chrattachedto[chraitarget[character]]!=MAXCHR)
  2014.             {
  2015.                 chraitarget[character] = chrattachedto[chraitarget[character]];
  2016.             }
  2017.             break;
  2018.         case FIFNOTPUTAWAY:
  2019.             // This function proceeds only if the character couln't be put in the pack
  2020.             returncode = ((chralert[character]&ALERTIFNOTPUTAWAY)!=0);
  2021.             break;
  2022.         case FIFTAKENOUT:
  2023.             // This function proceeds only if the character was taken out of the pack
  2024.             returncode = ((chralert[character]&ALERTIFTAKENOUT)!=0);
  2025.             break;
  2026.         case FIFAMMOOUT:
  2027.             // This function proceeds only if the character has no ammo
  2028.             returncode = (chrammo[character]==0);
  2029.             break;
  2030.         case FPLAYSOUNDLOOPED:
  2031.             // This function plays a looped sound
  2032.             if(moduleactive)
  2033.             {
  2034.  
  2035.                 volume = VOLMAX;
  2036.                 play_sound_pvf_looped(capwaveindex[chrmodel[character]][valuetmpargument], PANMID, volume, valuetmpdistance);
  2037.  
  2038.             }
  2039.             break;
  2040.         case FSTOPSOUND:
  2041.             // This function stops playing a sound
  2042.             stop_sound(capwaveindex[chrmodel[character]][valuetmpargument]);
  2043.             break;
  2044.         case FHEALSELF:
  2045.             // This function heals the character, without setting the alert or modifying
  2046.             // the amount
  2047.             if(chralive[character])
  2048.             {
  2049.                 iTmp = chrlife[character] + valuetmpargument;
  2050.                 if(iTmp > chrlifemax[character]) iTmp = chrlifemax[character];
  2051.                 if(iTmp < 1) iTmp = 1;
  2052.                 chrlife[character] = iTmp;
  2053.             }
  2054.             break;
  2055.         case FEQUIP:
  2056.             // This function flags the character as being equipped
  2057.             chrisequipped[character] = TRUE;
  2058.             break;
  2059.         case FIFTARGETHASITEMIDEQUIPPED:
  2060.             // This function proceeds if the target has a matching item equipped
  2061.             returncode = FALSE;
  2062.             sTmp = chrnextinpack[chraitarget[character]];
  2063.             while(sTmp != MAXCHR)
  2064.             {
  2065.                 if(sTmp != character && chrisequipped[sTmp] && (capidsz[chrmodel[sTmp]][IDSZPARENT]==(unsigned int) valuetmpargument || capidsz[chrmodel[sTmp]][IDSZTYPE]==(unsigned int) valuetmpargument))
  2066.                 {
  2067.                     returncode = TRUE;
  2068.                     sTmp = MAXCHR;
  2069.                 }
  2070.                 else
  2071.                 {
  2072.                     sTmp = chrnextinpack[sTmp];
  2073.                 }
  2074.             }
  2075.             break;
  2076.         case FSETOWNERTOTARGET:
  2077.             // This function sets the owner
  2078.             chraiowner[character] = chraitarget[character];
  2079.             break;
  2080.         case FSETTARGETTOOWNER:
  2081.             // This function sets the target to the owner
  2082.             chraitarget[character] = chraiowner[character];
  2083.             break;
  2084.         case FSETFRAME:
  2085.             // This function sets the character's current frame
  2086.             sTmp = valuetmpargument & 3;
  2087.             iTmp = valuetmpargument >> 2;
  2088.             set_frame(character, iTmp, sTmp);
  2089.             break;
  2090.         case FBREAKPASSAGE:
  2091.             // This function makes the tiles fall away ( turns into damage terrain )
  2092.             returncode = break_passage(valuetmpargument, valuetmpturn, valuetmpdistance, valuetmpx, valuetmpy);
  2093.             break;
  2094.         case FSETRELOADTIME:
  2095.             // This function makes weapons fire slower
  2096.             chrreloadtime[character] = valuetmpargument;
  2097.             break;
  2098.         case FSETTARGETTOWIDEBLAHID:
  2099.             // This function sets the target based on the settings of
  2100.             // tmpargument and tmpdistance
  2101.             sTmp = get_wide_target(character, ((valuetmpdistance>>3)&1),
  2102.                                               ((valuetmpdistance>>2)&1),
  2103.                                               ((valuetmpdistance>>1)&1),
  2104.                                               ((valuetmpdistance)&1),
  2105.                                               valuetmpargument, ((valuetmpdistance>>4)&1));
  2106.             returncode = FALSE;
  2107.             if(sTmp != MAXCHR)
  2108.             {
  2109.                 chraitarget[character] = sTmp;
  2110.                 returncode = TRUE;
  2111.             }
  2112.             break;
  2113.         case FPOOFTARGET:
  2114.             // This function makes the target go away
  2115.             returncode = FALSE;
  2116.             if(chrisplayer[chraitarget[character]]==FALSE)
  2117.             {
  2118.                 returncode = TRUE;
  2119.                 if(chraitarget[character] == character)
  2120.                 {
  2121.                     // Poof self later
  2122.                     valuegopoof = TRUE;
  2123.                 }
  2124.                 else
  2125.                 {
  2126.                     // Poof others now
  2127.                     if(chrattachedto[chraitarget[character]] != MAXCHR)
  2128.                         detach_character_from_mount(chraitarget[character], TRUE, FALSE);
  2129.                     if(chrholdingwhich[chraitarget[character]][0] != MAXCHR)
  2130.                         detach_character_from_mount(chrholdingwhich[chraitarget[character]][0], TRUE, FALSE);
  2131.                     if(chrholdingwhich[chraitarget[character]][1] != MAXCHR)
  2132.                         detach_character_from_mount(chrholdingwhich[chraitarget[character]][1], TRUE, FALSE);
  2133.                     free_inventory(chraitarget[character]);
  2134.                     free_one_character(chraitarget[character]);
  2135.                     chraitarget[character] = character;
  2136.                 }
  2137.             }
  2138.             break;
  2139.         case FCHILDDOACTIONOVERRIDE:
  2140.             // This function starts a new action, if it is valid for the model
  2141.             // It will fail if the action is invalid
  2142.             returncode = FALSE;
  2143.             if(valuetmpargument < MAXACTION)
  2144.             {
  2145.                 if(madactionvalid[chrmodel[chraichild[character]]][valuetmpargument])
  2146.                 {
  2147.                     chraction[chraichild[character]] = valuetmpargument;
  2148.                     chrlip[chraichild[character]] = 0;
  2149.                     chrframe[chraichild[character]] = madactionstart[chrmodel[chraichild[character]]][valuetmpargument];
  2150.                     chrlastframe[chraichild[character]] = chrframe[chraichild[character]];
  2151.                     chractionready[chraichild[character]] = FALSE;
  2152.                     returncode = TRUE;
  2153.                 }
  2154.             }
  2155.             break;
  2156.         case FSPAWNPOOF:
  2157.             // This function makes a lovely little poof at the character's location
  2158.             spawn_poof(character, chrmodel[character]);
  2159.             break;
  2160.         case FSETSPEEDPERCENT:
  2161.             reset_character_accel(character);
  2162.             chrmaxaccel[character] = chrmaxaccel[character] * valuetmpargument / 100.0;
  2163.             break;
  2164.         case FSETCHILDSTATE:
  2165.             // This function sets the child's state
  2166.             chraistate[chraichild[character]] = valuetmpargument;
  2167.             break;
  2168.         case FSPAWNATTACHEDSIZEDPARTICLE:
  2169.             // This function spawns an attached particle, then sets its size
  2170.             tTmp = character;
  2171.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  2172.             tTmp = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], chrturnleftright[character], chrmodel[character], valuetmpargument, character, valuetmpdistance, chrteam[character], tTmp, 0, MAXCHR);
  2173.             if(tTmp < MAXPRT)
  2174.             {
  2175.                 prtsize[tTmp] = valuetmpturn;
  2176.             }
  2177.             break;
  2178.         case FCHANGEARMOR:
  2179.             // This function sets the character's armor type and returns the old type
  2180.             // as tmpargument and the new type as tmpx
  2181.             valuetmpx = valuetmpargument;
  2182.             iTmp = chrtexture[character]-madskinstart[chrmodel[character]];
  2183.             valuetmpx = change_armor(character, valuetmpargument);
  2184.             valuetmpargument = iTmp;  // The character's old armor
  2185.             break;
  2186.         case FSHOWTIMER:
  2187.             // This function turns the timer on, using the value for tmpargument
  2188.             timeron = TRUE;
  2189.             timervalue = valuetmpargument;
  2190.             break;
  2191.         case FIFFACINGTARGET:
  2192.             // This function proceeds only if the character is facing the target
  2193.             sTmp = atan2(chrypos[chraitarget[character]]-chrypos[character], chrxpos[chraitarget[character]]-chrxpos[character])*65535/(2*PI);
  2194.             sTmp+=32768-chrturnleftright[character];
  2195.             returncode = (sTmp > 55535 || sTmp < 10000);
  2196.             break;
  2197.         case FSETVOLUME:
  2198.             // This function sets the volume of the given sound
  2199.             if(moduleactive && valuetmpdistance >= 0)
  2200.             {
  2201.                 distance = ABS(camtrackx-chroldx[character])+ABS(camtracky-chroldy[character])+valuetmpdistance;
  2202.                 volume = -distance;
  2203.                 volume = volume<<VOLSHIFT;
  2204.                 if(volume < VOLMIN) volume = VOLMIN;
  2205.                 iTmp = capwaveindex[chrmodel[character]][valuetmpargument];
  2206. /*PORT
  2207.                 if(iTmp < numsound && iTmp >= 0 && soundon)
  2208.                 {
  2209.                     lpDSBuffer[iTmp]->SetVolume(volume);
  2210.                 }
  2211. */
  2212.             }
  2213.             break;
  2214.         case FSPAWNATTACHEDFACEDPARTICLE:
  2215.             // This function spawns an attached particle with facing
  2216.             tTmp = character;
  2217.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  2218.             tTmp = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], valuetmpturn, chrmodel[character], valuetmpargument, character, valuetmpdistance, chrteam[character], tTmp, 0, MAXCHR);
  2219.             break;
  2220.         case FIFSTATEISODD:
  2221.             returncode = (chraistate[character]&1);
  2222.             break;
  2223.         case FSETTARGETTODISTANTENEMY:
  2224.             // This function finds an enemy, within a certain distance to the character, and
  2225.             // proceeds only if there is one
  2226.             sTmp = find_distant_target(character, valuetmpdistance);
  2227.             returncode = FALSE;
  2228.             if(sTmp != MAXCHR)
  2229.             {
  2230.                 chraitarget[character] = sTmp;
  2231.                 returncode = TRUE;
  2232.             }
  2233.             break;
  2234.         case FTELEPORT:
  2235.             // This function teleports the character to the X, Y location, failing if the
  2236.             // location is off the map or blocked
  2237.             returncode = FALSE;
  2238.             if(valuetmpx > EDGE && valuetmpy > EDGE && valuetmpx < meshedgex-EDGE && valuetmpy < meshedgey-EDGE)
  2239.             {
  2240.                 // Yeah!  It worked!
  2241.                 detach_character_from_mount(character, TRUE, FALSE);
  2242.                 chroldx[character] = chrxpos[character];
  2243.                 chroldy[character] = chrypos[character];
  2244.                 chrxpos[character] = valuetmpx;
  2245.                 chrypos[character] = valuetmpy;
  2246.                 if(__chrhitawall(character))
  2247.                 {
  2248.                     // No it didn't...
  2249.                     chrxpos[character] = chroldx[character];
  2250.                     chrypos[character] = chroldy[character];
  2251.                     returncode = FALSE;
  2252.                 }
  2253.                 else
  2254.                 {
  2255.                     chroldx[character] = chrxpos[character];
  2256.                     chroldy[character]= chrypos[character];
  2257.                     returncode = TRUE;
  2258.                 }
  2259.             }
  2260.             break;
  2261.         case FGIVESTRENGTHTOTARGET:
  2262.             // Permanently boost the target's strength
  2263.             if(chralive[chraitarget[character]])
  2264.             {
  2265.                 iTmp = valuetmpargument;
  2266.                 getadd(0, chrstrength[chraitarget[character]], PERFECTSTAT, &iTmp);
  2267.                 chrstrength[chraitarget[character]]+=iTmp;
  2268.             }
  2269.             break;
  2270.         case FGIVEWISDOMTOTARGET:
  2271.             // Permanently boost the target's wisdom
  2272.             if(chralive[chraitarget[character]])
  2273.             {
  2274.                 iTmp = valuetmpargument;
  2275.                 getadd(0, chrwisdom[chraitarget[character]], PERFECTSTAT, &iTmp);
  2276.                 chrwisdom[chraitarget[character]]+=iTmp;
  2277.             }
  2278.             break;
  2279.         case FGIVEINTELLIGENCETOTARGET:
  2280.             // Permanently boost the target's intelligence
  2281.             if(chralive[chraitarget[character]])
  2282.             {
  2283.                 iTmp = valuetmpargument;
  2284.                 getadd(0, chrintelligence[chraitarget[character]], PERFECTSTAT, &iTmp);
  2285.                 chrintelligence[chraitarget[character]]+=iTmp;
  2286.             }
  2287.             break;
  2288.         case FGIVEDEXTERITYTOTARGET:
  2289.             // Permanently boost the target's dexterity
  2290.             if(chralive[chraitarget[character]])
  2291.             {
  2292.                 iTmp = valuetmpargument;
  2293.                 getadd(0, chrdexterity[chraitarget[character]], PERFECTSTAT, &iTmp);
  2294.                 chrdexterity[chraitarget[character]]+=iTmp;
  2295.             }
  2296.             break;
  2297.         case FGIVELIFETOTARGET:
  2298.             // Permanently boost the target's life
  2299.             if(chralive[chraitarget[character]])
  2300.             {
  2301.                 iTmp = valuetmpargument;
  2302.                 getadd(LOWSTAT, chrlifemax[chraitarget[character]], PERFECTBIG, &iTmp);
  2303.                 chrlifemax[chraitarget[character]]+=iTmp;
  2304.                 if(iTmp < 0)
  2305.                 {
  2306.                     getadd(1, chrlife[chraitarget[character]], PERFECTBIG, &iTmp);
  2307.                 }
  2308.                 chrlife[chraitarget[character]]+=iTmp;
  2309.             }
  2310.             break;
  2311.         case FGIVEMANATOTARGET:
  2312.             // Permanently boost the target's mana
  2313.             if(chralive[chraitarget[character]])
  2314.             {
  2315.                 iTmp = valuetmpargument;
  2316.                 getadd(0, chrmanamax[chraitarget[character]], PERFECTBIG, &iTmp);
  2317.                 chrmanamax[chraitarget[character]]+=iTmp;
  2318.                 if(iTmp < 0)
  2319.                 {
  2320.                     getadd(0, chrmana[chraitarget[character]], PERFECTBIG, &iTmp);
  2321.                 }
  2322.                 chrmana[chraitarget[character]]+=iTmp;
  2323.             }
  2324.             break;
  2325.         case FSHOWMAP:
  2326.             // Show the map...  Fails if map already visible
  2327.             if(mapon)  returncode = FALSE;
  2328.             mapon = TRUE;
  2329.             break;
  2330.         case FSHOWYOUAREHERE:
  2331.             // Show the camera target location
  2332.             youarehereon = TRUE;
  2333.             break;
  2334.         case FSHOWBLIPXY:
  2335.             // Add a blip
  2336.             if(numblip < MAXBLIP)
  2337.             {
  2338.                 if(valuetmpx > 0 && valuetmpx < meshedgex && valuetmpy > 0 && valuetmpy < meshedgey)
  2339.                 {
  2340.                     if(valuetmpargument < NUMBAR && valuetmpargument >= 0)
  2341.                     {
  2342.                         blipx[numblip] = valuetmpx*MAPSIZE/meshedgex;
  2343.                         blipy[numblip] = valuetmpy*MAPSIZE/meshedgey;
  2344.                         blipc[numblip] = valuetmpargument;
  2345.                         numblip++;
  2346.                     }
  2347.                 }
  2348.             }
  2349.             break;
  2350.         case FHEALTARGET:
  2351.             // Give some life to the target
  2352.             if(chralive[chraitarget[character]])
  2353.             {
  2354.                 iTmp = valuetmpargument;
  2355.                 getadd(1, chrlife[chraitarget[character]], chrlifemax[chraitarget[character]], &iTmp);
  2356.                 chrlife[chraitarget[character]]+=iTmp;
  2357.                 // Check all enchants to see if they are removed
  2358.                 iTmp = chrfirstenchant[chraitarget[character]];
  2359.                 while(iTmp != MAXENCHANT)
  2360.                 {
  2361.                     test = ('H'-'A'<<15)|('E'-'A'<<10)|('A'-'A'<<5)|('L'-'A');  // [HEAL]
  2362.                     sTmp = encnextenchant[iTmp];
  2363.                     if(test == everemovedbyidsz[enceve[iTmp]])
  2364.                     {
  2365.                         remove_enchant(iTmp);
  2366.                     }
  2367.                     iTmp = sTmp;
  2368.                 }
  2369.             }
  2370.             break;
  2371.         case FPUMPTARGET:
  2372.             // Give some mana to the target
  2373.             if(chralive[chraitarget[character]])
  2374.             {
  2375.                 iTmp = valuetmpargument;
  2376.                 getadd(0, chrmana[chraitarget[character]], chrmanamax[chraitarget[character]], &iTmp);
  2377.                 chrmana[chraitarget[character]]+=iTmp;
  2378.             }
  2379.             break;
  2380.         case FCOSTAMMO:
  2381.             // Take away one ammo
  2382.             if(chrammo[character] > 0)
  2383.             {
  2384.                 chrammo[character]--;
  2385.             }
  2386.             break;
  2387.         case FMAKESIMILARNAMESKNOWN:
  2388.             // Make names of matching objects known
  2389.             iTmp = 0;
  2390.             while(iTmp < MAXCHR)
  2391.             {
  2392.                 sTmp = TRUE;
  2393.                 tTmp = 0;
  2394.                 while(tTmp < MAXIDSZ)
  2395.                 {
  2396.                     if(capidsz[chrmodel[character]][tTmp] != capidsz[chrmodel[iTmp]][tTmp])
  2397.                     {
  2398.                         sTmp = FALSE;
  2399.                     }
  2400.                     tTmp++;
  2401.                 }
  2402.                 if(sTmp)
  2403.                 {
  2404.                     chrnameknown[iTmp] = TRUE;
  2405.                 }
  2406.                 iTmp++;
  2407.             }
  2408.             break;
  2409.         case FSPAWNATTACHEDHOLDERPARTICLE:
  2410.             // This function spawns an attached particle, attached to the holder
  2411.             tTmp = character;
  2412.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  2413.             tTmp = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], chrturnleftright[character], chrmodel[character], valuetmpargument, tTmp, valuetmpdistance, chrteam[character], tTmp, 0, MAXCHR);
  2414.             break;
  2415.         case FSETTARGETRELOADTIME:
  2416.             // This function sets the target's reload time
  2417.             chrreloadtime[chraitarget[character]] = valuetmpargument;
  2418.             break;
  2419.         case FSETFOGLEVEL:
  2420.             // This function raises and lowers the module's fog
  2421.             fTmp = (valuetmpargument/10.0) - fogtop;
  2422.             fogtop+=fTmp;
  2423.             fogdistance+=fTmp;
  2424.             fogon = fogallowed;
  2425.             if(fogdistance < 1.0)  fogon = FALSE;
  2426.             break;
  2427.         case FGETFOGLEVEL:
  2428.             // This function gets the fog level
  2429.             valuetmpargument = fogtop*10;
  2430.             break;
  2431.         case FSETFOGTAD:
  2432.             // This function changes the fog color
  2433.             fogred = valuetmpturn;
  2434.             foggrn = valuetmpargument;
  2435.             fogblu = valuetmpdistance;
  2436.             break;
  2437.         case FSETFOGBOTTOMLEVEL:
  2438.             // This function sets the module's bottom fog level...
  2439.             fTmp = (valuetmpargument/10.0) - fogbottom;
  2440.             fogbottom+=fTmp;
  2441.             fogdistance-=fTmp;
  2442.             fogon = fogallowed;
  2443.             if(fogdistance < 1.0)  fogon = FALSE;
  2444.             break;
  2445.         case FGETFOGBOTTOMLEVEL:
  2446.             // This function gets the fog level
  2447.             valuetmpargument = fogbottom*10;
  2448.             break;
  2449.         case FCORRECTACTIONFORHAND:
  2450.             // This function turns ZA into ZA, ZB, ZC, or ZD...
  2451.             // tmpargument must be set to one of the A actions beforehand...
  2452.             if(chrattachedto[character]!= MAXCHR)
  2453.             {
  2454.                 if(chrinwhichhand[character]==GRIPLEFT)
  2455.                 {
  2456.                     // A or B
  2457.                     valuetmpargument = valuetmpargument + (rand()&1);
  2458.                 }
  2459.                 else
  2460.                 {
  2461.                     // C or D
  2462.                     valuetmpargument = valuetmpargument + 2 + (rand()&1);
  2463.                 }
  2464.             }
  2465.             break;
  2466.         case FIFTARGETISMOUNTED:
  2467.             // This function proceeds if the target is riding a mount
  2468.             returncode = FALSE;
  2469.             if(chrattachedto[chraitarget[character]]!=MAXCHR)
  2470.             {
  2471.                 returncode = chrismount[chrattachedto[chraitarget[character]]];
  2472.             }
  2473.             break;
  2474.         case FSPARKLEICON:
  2475.             // This function makes a blippie thing go around the icon
  2476.             if(valuetmpargument < NUMBAR && valuetmpargument > -1)
  2477.             {
  2478.                 chrsparkle[character] = valuetmpargument;
  2479.             }
  2480.             break;
  2481.         case FUNSPARKLEICON:
  2482.             // This function stops the blippie thing
  2483.             chrsparkle[character] = NOSPARKLE;
  2484.             break;
  2485.         case FGETTILEXY:
  2486.             // This function gets the tile at x,y
  2487.             if(valuetmpx >= 0 && valuetmpx < meshedgex)
  2488.             {
  2489.                 if(valuetmpy >= 0 && valuetmpy < meshedgey)
  2490.                 {
  2491.                     iTmp = meshfanstart[valuetmpy>>7] + (valuetmpx>>7);
  2492.                     valuetmpargument = meshtile[iTmp]&255;
  2493.                 }
  2494.             }
  2495.             break;
  2496.         case FSETTILEXY:
  2497.             // This function changes the tile at x,y
  2498.             if(valuetmpx >= 0 && valuetmpx < meshedgex)
  2499.             {
  2500.                 if(valuetmpy >= 0 && valuetmpy < meshedgey)
  2501.                 {
  2502.                     iTmp = meshfanstart[valuetmpy>>7] + (valuetmpx>>7);
  2503.                     meshtile[iTmp] = (valuetmpargument&255);
  2504.                 }
  2505.             }
  2506.             break;
  2507.         case FSETSHADOWSIZE:
  2508.             // This function changes a character's shadow size
  2509.             chrshadowsize[character] = valuetmpargument*chrfat[character];
  2510.             chrshadowsizesave[character] = valuetmpargument;
  2511.             break;
  2512.         case FORDERTARGET:
  2513.             // This function orders one specific character...  The target
  2514.             // Be careful in using this, always checking IDSZ first
  2515.             chrorder[chraitarget[character]] = valuetmpargument;
  2516.             chrcounter[chraitarget[character]] = 0;
  2517.             chralert[chraitarget[character]]|=ALERTIFORDERED;
  2518.             break;
  2519.         case FSETTARGETTOWHOEVERISINPASSAGE:
  2520.             // This function lets passage rectangles be used as event triggers
  2521.             sTmp = who_is_blocking_passage(valuetmpargument);
  2522.             returncode = FALSE;
  2523.             if(sTmp != MAXCHR)
  2524.             {
  2525.                 chraitarget[character] = sTmp;
  2526.                 returncode = TRUE;
  2527.             }
  2528.             break;
  2529.         case FIFCHARACTERWASABOOK:
  2530.             // This function proceeds if the base model is the same as the current
  2531.             // model or if the base model is SPELLBOOK
  2532.             returncode = (chrbasemodel[character] == SPELLBOOK ||
  2533.                           chrbasemodel[character] == chrmodel[character]);
  2534.             break;
  2535.         case FSETENCHANTBOOSTVALUES:
  2536.             // This function sets the boost values for the last enchantment
  2537.             iTmp = chrundoenchant[character];
  2538.             if(iTmp != MAXENCHANT)
  2539.             {
  2540.                 encownermana[iTmp] = valuetmpargument;
  2541.                 encownerlife[iTmp] = valuetmpdistance;
  2542.                 enctargetmana[iTmp] = valuetmpx;
  2543.                 enctargetlife[iTmp] = valuetmpy;
  2544.             }
  2545.             break;
  2546.         case FSPAWNCHARACTERXYZ:
  2547.             // This function spawns a character, failing if x,y,z is invalid
  2548.             sTmp = spawn_one_character(valuetmpx, valuetmpy, valuetmpdistance, chrmodel[character], chrteam[character], 0, valuetmpturn, NULL, MAXCHR);
  2549.             returncode = FALSE;
  2550.             if(sTmp < MAXCHR)
  2551.             {
  2552.                 if(__chrhitawall(sTmp))
  2553.                 {
  2554.                     free_one_character(sTmp);
  2555.                 }
  2556.                 else
  2557.                 {
  2558.                     chriskursed[sTmp] = FALSE;
  2559.                     chraichild[character] = sTmp;
  2560.                     chrpassage[sTmp] = chrpassage[character];
  2561.                     chraiowner[sTmp] = chraiowner[character];
  2562.                     returncode = TRUE;
  2563.                 }
  2564.             }
  2565.             break;
  2566.         case FSPAWNEXACTCHARACTERXYZ:
  2567.             // This function spawns a character ( specific model slot ),
  2568.             // failing if x,y,z is invalid
  2569.             sTmp = spawn_one_character(valuetmpx, valuetmpy, valuetmpdistance, valuetmpargument, chrteam[character], 0, valuetmpturn, NULL, MAXCHR);
  2570.             returncode = FALSE;
  2571.             if(sTmp < MAXCHR)
  2572.             {
  2573.                 if(__chrhitawall(sTmp))
  2574.                 {
  2575.                     free_one_character(sTmp);
  2576.                 }
  2577.                 else
  2578.                 {
  2579.                     chriskursed[sTmp] = FALSE;
  2580.                     chraichild[character] = sTmp;
  2581.                     chrpassage[sTmp] = chrpassage[character];
  2582.                     chraiowner[sTmp] = chraiowner[character];
  2583.                     returncode = TRUE;
  2584.                 }
  2585.             }
  2586.             break;
  2587.         case FCHANGETARGETCLASS:
  2588.             // This function changes a character's model ( specific model slot )
  2589.             change_character(chraitarget[character], valuetmpargument, 0, LEAVEALL);
  2590.             break;
  2591.         case FPLAYFULLSOUND:
  2592.             // This function plays a sound loud for everyone...  Victory music
  2593.             if(moduleactive)
  2594.             {
  2595.  
  2596.                 play_sound_pvf(capwaveindex[chrmodel[character]][valuetmpargument], PANMID, VOLMAX, valuetmpdistance);
  2597.  
  2598.             }
  2599.             break;
  2600.         case FSPAWNEXACTCHASEPARTICLE:
  2601.             // This function spawns an exactly placed particle that chases the target
  2602.             tTmp = character;
  2603.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  2604.             tTmp = spawn_one_particle(valuetmpx, valuetmpy, valuetmpdistance, chrturnleftright[character], chrmodel[character], valuetmpargument, MAXCHR, 0, chrteam[character], tTmp, 0, MAXCHR);
  2605.             if(tTmp < MAXPRT)
  2606.             {
  2607.                 prttarget[tTmp] = chraitarget[character];
  2608.             }
  2609.             break;
  2610.         case FCREATEORDER:
  2611.             // This function packs up an order, using tmpx, tmpy, tmpargument and the 
  2612.             // target ( if valid ) to create a new tmpargument
  2613.             sTmp = chraitarget[character]<<24;
  2614.             sTmp |= ((valuetmpx>>6)&1023)<<14;
  2615.             sTmp |= ((valuetmpy>>6)&1023)<<4;
  2616.             sTmp |= (valuetmpargument&15);
  2617.             valuetmpargument = sTmp;
  2618.             break;
  2619.         case FORDERSPECIALID:
  2620.             // This function issues an order to all with the given special IDSZ
  2621.             issue_special_order(valuetmpargument, valuetmpdistance);
  2622.             break;
  2623.         case FUNKURSETARGETINVENTORY:
  2624.             // This function unkurses every item a character is holding
  2625.             sTmp = chrholdingwhich[chraitarget[character]][0];
  2626.             chriskursed[sTmp] = FALSE;
  2627.             sTmp = chrholdingwhich[chraitarget[character]][1];
  2628.             chriskursed[sTmp] = FALSE;
  2629.             sTmp = chrnextinpack[chraitarget[character]];
  2630.             while(sTmp != MAXCHR)
  2631.             {
  2632.                 chriskursed[sTmp] = FALSE;
  2633.                 sTmp = chrnextinpack[sTmp];
  2634.             }
  2635.             break;
  2636.         case FIFTARGETISSNEAKING:
  2637.             // This function proceeds if the target is doing ACTIONDA or ACTIONWA
  2638.             returncode = (chraction[chraitarget[character]] == ACTIONDA || chraction[chraitarget[character]] == ACTIONWA);
  2639.             break;
  2640.         case FDROPITEMS:
  2641.             // This function drops all of the character's items
  2642.             drop_all_items(character);
  2643.             break;
  2644.         case FRESPAWNTARGET:
  2645.             // This function respawns the target at its current location
  2646.             sTmp = chraitarget[character];
  2647.             chroldx[sTmp] = chrxpos[sTmp];
  2648.             chroldy[sTmp] = chrypos[sTmp];
  2649.             chroldz[sTmp] = chrzpos[sTmp];
  2650.             respawn_character(sTmp);
  2651.             chrxpos[sTmp] = chroldx[sTmp];
  2652.             chrypos[sTmp] = chroldy[sTmp];
  2653.             chrzpos[sTmp] = chroldz[sTmp];
  2654.             break;
  2655.         case FTARGETDOACTIONSETFRAME:
  2656.             // This function starts a new action, if it is valid for the model and
  2657.             // sets the starting frame.  It will fail if the action is invalid
  2658.             returncode = FALSE;
  2659.             if(valuetmpargument < MAXACTION)
  2660.             {
  2661.                 if(madactionvalid[chrmodel[chraitarget[character]]][valuetmpargument])
  2662.                 {
  2663.                     chraction[chraitarget[character]] = valuetmpargument;
  2664.                     chrlip[chraitarget[character]] = 0;
  2665.                     chrframe[chraitarget[character]] = madactionstart[chrmodel[chraitarget[character]]][valuetmpargument];
  2666.                     chrlastframe[chraitarget[character]] = chrframe[chraitarget[character]];
  2667.                     chractionready[chraitarget[character]] = FALSE;
  2668.                     returncode = TRUE;
  2669.                 }
  2670.             }
  2671.             break;
  2672.         case FIFTARGETCANSEEINVISIBLE:
  2673.             // This function proceeds if the target can see invisible
  2674.             returncode = chrcanseeinvisible[chraitarget[character]];
  2675.             break;
  2676.         case FSETTARGETTONEARESTBLAHID:
  2677.             // This function finds the nearest target that meets the
  2678.             // requirements
  2679.             sTmp = get_nearest_target(character, ((valuetmpdistance>>3)&1),
  2680.                                                  ((valuetmpdistance>>2)&1),
  2681.                                                  ((valuetmpdistance>>1)&1),
  2682.                                                  ((valuetmpdistance)&1),
  2683.                                                  valuetmpargument);
  2684.             returncode = FALSE;
  2685.             if(sTmp != MAXCHR)
  2686.             {
  2687.                 chraitarget[character] = sTmp;
  2688.                 returncode = TRUE;
  2689.             }
  2690.             break;
  2691.         case FSETTARGETTONEARESTENEMY:
  2692.             // This function finds the nearest target that meets the
  2693.             // requirements
  2694.             sTmp = get_nearest_target(character, 0, 0, 1, 0, IDSZNONE);
  2695.             returncode = FALSE;
  2696.             if(sTmp != MAXCHR)
  2697.             {
  2698.                 chraitarget[character] = sTmp;
  2699.                 returncode = TRUE;
  2700.             }
  2701.             break;
  2702.         case FSETTARGETTONEARESTFRIEND:
  2703.             // This function finds the nearest target that meets the
  2704.             // requirements
  2705.             sTmp = get_nearest_target(character, 0, 1, 0, 0, IDSZNONE);
  2706.             returncode = FALSE;
  2707.             if(sTmp != MAXCHR)
  2708.             {
  2709.                 chraitarget[character] = sTmp;
  2710.                 returncode = TRUE;
  2711.             }
  2712.             break;
  2713.         case FSETTARGETTONEARESTLIFEFORM:
  2714.             // This function finds the nearest target that meets the
  2715.             // requirements
  2716.             sTmp = get_nearest_target(character, 0, 1, 1, 0, IDSZNONE);
  2717.             returncode = FALSE;
  2718.             if(sTmp != MAXCHR)
  2719.             {
  2720.                 chraitarget[character] = sTmp;
  2721.                 returncode = TRUE;
  2722.             }
  2723.             break;
  2724.         case FFLASHPASSAGE:
  2725.             // This function makes the passage light or dark...  For debug...
  2726.             flash_passage(valuetmpargument, valuetmpdistance);
  2727.             break;
  2728.         case FFINDTILEINPASSAGE:
  2729.             // This function finds the next tile in the passage, tmpx and tmpy are 
  2730.             // required and set on return
  2731.             returncode = find_tile_in_passage(valuetmpargument, valuetmpdistance);
  2732.             break;
  2733.         case FIFHELDINLEFTHAND:
  2734.             // This function proceeds if the character is in the left hand of another
  2735.             // character
  2736.             returncode = FALSE;
  2737.             sTmp = chrattachedto[character];
  2738.             if(sTmp != MAXCHR)
  2739.             {
  2740.                 returncode = (chrholdingwhich[sTmp][0] == character);
  2741.             }
  2742.             break;
  2743.         case FNOTANITEM:
  2744.             // This function makes the character a non-item character
  2745.             chrisitem[character] = FALSE;
  2746.             break;
  2747.         case FSETCHILDAMMO:
  2748.             // This function sets the child's ammo
  2749.             chrammo[chraichild[character]] = valuetmpargument;
  2750.             break;
  2751.         case FIFHITVULNERABLE:
  2752.             // This function proceeds if the character was hit by a weapon with the
  2753.             // correct vulnerability IDSZ...  [SILV] for Werewolves...
  2754.             returncode = ((chralert[character]&ALERTIFHITVULNERABLE)!=0);
  2755.             break;
  2756.         case FIFTARGETISFLYING:
  2757.             // This function proceeds if the character target is flying
  2758.             returncode = (chrflyheight[chraitarget[character]] > 0);
  2759.             break;
  2760.         case FIDENTIFYTARGET:
  2761.             // This function reveals the target's name, ammo, and usage
  2762.             // Proceeds if the target was unknown
  2763.             returncode = FALSE;
  2764.             sTmp = chraitarget[character];
  2765.             if(chrammomax[sTmp] != 0)  chrammoknown[sTmp]=TRUE;
  2766.             if(chrname[sTmp][0] != 'B' ||
  2767.                chrname[sTmp][1] != 'l' ||
  2768.                chrname[sTmp][2] != 'a' ||
  2769.                chrname[sTmp][3] != 'h' ||
  2770.                chrname[sTmp][4] != 0)
  2771.             {
  2772.                returncode = !chrnameknown[sTmp];
  2773.                chrnameknown[sTmp]=TRUE;
  2774.             }
  2775.             capusageknown[chrmodel[sTmp]] = TRUE;
  2776.             break;
  2777.         case FBEATMODULE:
  2778.             // This function displays the Module Ended message
  2779.             beatmodule = TRUE;
  2780.             break;
  2781.         case FENDMODULE:
  2782.             // This function presses the Escape key
  2783.             sdlkeybuffer[SDLK_ESCAPE]=1;
  2784.             break;
  2785.         case FDISABLEEXPORT:
  2786.             // This function turns export off
  2787.             exportvalid = FALSE;
  2788.             break;
  2789.         case FENABLEEXPORT:
  2790.             // This function turns export on
  2791.             exportvalid = TRUE;
  2792.             break;
  2793.         case FGETTARGETSTATE:
  2794.             // This function sets tmpargument to the state of the target
  2795.             valuetmpargument = chraistate[chraitarget[character]];
  2796.             break;
  2797.         case FSETSPEECH:
  2798.             // This function sets all of the RTS speech registers to tmpargument
  2799.             sTmp = 0;
  2800.             while(sTmp < MAXSPEECH)
  2801.             {
  2802.                 chrwavespeech[character][sTmp] = valuetmpargument;
  2803.                 sTmp++;
  2804.             }
  2805.             break;
  2806.         case FSETMOVESPEECH:
  2807.             // This function sets the RTS move speech register to tmpargument
  2808.             chrwavespeech[character][SPEECHMOVE] = valuetmpargument;
  2809.             break;
  2810.         case FSETSECONDMOVESPEECH:
  2811.             // This function sets the RTS movealt speech register to tmpargument
  2812.             chrwavespeech[character][SPEECHMOVEALT] = valuetmpargument;
  2813.             break;
  2814.         case FSETATTACKSPEECH:
  2815.             // This function sets the RTS attack speech register to tmpargument
  2816.             chrwavespeech[character][SPEECHATTACK] = valuetmpargument;
  2817.             break;
  2818.         case FSETASSISTSPEECH:
  2819.             // This function sets the RTS assist speech register to tmpargument
  2820.             chrwavespeech[character][SPEECHASSIST] = valuetmpargument;
  2821.             break;
  2822.         case FSETTERRAINSPEECH:
  2823.             // This function sets the RTS terrain speech register to tmpargument
  2824.             chrwavespeech[character][SPEECHTERRAIN] = valuetmpargument;
  2825.             break;
  2826.         case FSETSELECTSPEECH:
  2827.             // This function sets the RTS select speech register to tmpargument
  2828.             chrwavespeech[character][SPEECHSELECT] = valuetmpargument;
  2829.             break;
  2830.         case FCLEARENDMESSAGE:
  2831.             // This function empties the end-module text buffer
  2832.             endtext[0] = 0;
  2833.             endtextwrite = 0;
  2834.             break;
  2835.         case FADDENDMESSAGE:
  2836.             // This function appends a message to the end-module text buffer
  2837.             append_end_text(madmsgstart[chrmodel[character]]+valuetmpargument, character);
  2838.             break;
  2839.         case FSETMUSIC:
  2840.             // This function begins playing a new track of music
  2841.             if(valuetmpturn < IGTRACKS && valuetmpturn >= 0)
  2842.             {
  2843.                 ignexttrack = valuetmpturn;
  2844.                 igtrackcount = valuetmpdistance;
  2845.             }
  2846.             break;
  2847.         case FSETMUSICPASSAGE:
  2848.             // This function makes the given passage play music if a player enters it
  2849.             if(valuetmpargument < numpassage && valuetmpargument >= 0)
  2850.             {
  2851.                 if(valuetmpturn < IGTRACKS && valuetmpturn >= 0)
  2852.                 {
  2853.                     passtracktype[valuetmpargument] = valuetmpturn;
  2854.                     passtrackcount[valuetmpargument] = valuetmpdistance;
  2855.                 }
  2856.             }
  2857.             break;
  2858.         case FMAKECRUSHINVALID:
  2859.             // This function makes doors unable to close on this object
  2860.             chrcanbecrushed[character] = FALSE;
  2861.             break;
  2862.         case FSTOPMUSIC:
  2863.             // This function stops the interactive music
  2864.             igloaded = FALSE;
  2865.             break;
  2866.         case FFLASHVARIABLE:
  2867.             // This function makes the character flash according to tmpargument
  2868.             flash_character(character, valuetmpargument);
  2869.             break;
  2870.         case FACCELERATEUP:
  2871.             // This function changes the character's up down velocity
  2872.             chrzvel[character]+=valuetmpargument/100.0;
  2873.             break;
  2874.         case FFLASHVARIABLEHEIGHT:
  2875.             // This function makes the character flash, feet one color, head another...
  2876.             flash_character_height(character, valuetmpturn, valuetmpx,
  2877.                                               valuetmpdistance, valuetmpy);
  2878.             break;
  2879.         case FSETDAMAGETIME:
  2880.             // This function makes the character invincible for a little while
  2881.             chrdamagetime[character] = valuetmpargument;
  2882.             break;
  2883.         case FIFSTATEIS8:
  2884.             returncode = (8 == chraistate[character]);
  2885.             break;
  2886.         case FIFSTATEIS9:
  2887.             returncode = (9 == chraistate[character]);
  2888.             break;
  2889.         case FIFSTATEIS10:
  2890.             returncode = (10 == chraistate[character]);
  2891.             break;
  2892.         case FIFSTATEIS11:
  2893.             returncode = (11 == chraistate[character]);
  2894.             break;
  2895.         case FIFSTATEIS12:
  2896.             returncode = (12 == chraistate[character]);
  2897.             break;
  2898.         case FIFSTATEIS13:
  2899.             returncode = (13 == chraistate[character]);
  2900.             break;
  2901.         case FIFSTATEIS14:
  2902.             returncode = (14 == chraistate[character]);
  2903.             break;
  2904.         case FIFSTATEIS15:
  2905.             returncode = (15 == chraistate[character]);
  2906.             break;
  2907.         case FIFTARGETISAMOUNT:
  2908.             returncode = chrismount[chraitarget[character]];
  2909.             break;
  2910.         case FIFTARGETISAPLATFORM:
  2911.             returncode = chrplatform[chraitarget[character]];
  2912.             break;
  2913.         case FADDSTAT:
  2914.             if(chrstaton[character]==FALSE) add_stat(character);
  2915.             break;
  2916.         case FDISENCHANTTARGET:
  2917.             returncode = (chrfirstenchant[chraitarget[character]] != MAXENCHANT);
  2918.             disenchant_character(chraitarget[character]);
  2919.             break;
  2920.         case FDISENCHANTALL:
  2921.             iTmp = 0;
  2922.             while(iTmp < MAXENCHANT)
  2923.             {
  2924.                 remove_enchant(iTmp);
  2925.                 iTmp++;
  2926.             }
  2927.             break;
  2928.         case FSETVOLUMENEARESTTEAMMATE:
  2929. /*PORT
  2930.             if(moduleactive && valuetmpdistance >= 0)
  2931.             {
  2932.                 // Find the closest teammate
  2933.                 iTmp = 10000;
  2934.                 sTmp = 0;
  2935.                 while(sTmp < MAXCHR)
  2936.                 {
  2937.                     if(chron[sTmp] && chralive[sTmp] && chrteam[sTmp] == chrteam[character])
  2938.                     {
  2939.                         distance = ABS(camtrackx-chroldx[sTmp])+ABS(camtracky-chroldy[sTmp]);
  2940.                         if(distance < iTmp)  iTmp = distance;
  2941.                     }
  2942.                     sTmp++;
  2943.                 }
  2944.                 distance=iTmp+valuetmpdistance;
  2945.                 volume = -distance;
  2946.                 volume = volume<<VOLSHIFT;
  2947.                 if(volume < VOLMIN) volume = VOLMIN;
  2948.                 iTmp = capwaveindex[chrmodel[character]][valuetmpargument];
  2949.                 if(iTmp < numsound && iTmp >= 0 && soundon)
  2950.                 {
  2951.                     lpDSBuffer[iTmp]->SetVolume(volume);
  2952.                 }
  2953.             }
  2954. */
  2955.             break;
  2956.         case FADDSHOPPASSAGE:
  2957.             // This function defines a shop area
  2958.             add_shop_passage(character, valuetmpargument);
  2959.             break;
  2960.         case FTARGETPAYFORARMOR:
  2961.             // This function costs the target some money, or fails if 'e doesn't have
  2962.             // enough...
  2963.             // tmpx is amount needed
  2964.             // tmpy is cost of new skin
  2965.             sTmp = chraitarget[character];   // The target
  2966.             tTmp = chrmodel[sTmp];           // The target's model
  2967.             iTmp =  capskincost[tTmp][valuetmpargument&3];
  2968.             valuetmpy = iTmp;                // Cost of new skin
  2969.             iTmp -= capskincost[tTmp][(chrtexture[sTmp]-madskinstart[tTmp])&3];  // Refund
  2970.             if(iTmp > chrmoney[sTmp])
  2971.             {
  2972.                 // Not enough...
  2973.                 valuetmpx = iTmp - chrmoney[sTmp];  // Amount needed
  2974.                 returncode = FALSE;
  2975.             }
  2976.             else
  2977.             {
  2978.                 // Pay for it...  Cost may be negative after refund...
  2979.                 chrmoney[sTmp]-=iTmp;
  2980.                 if(chrmoney[sTmp] > MAXMONEY)  chrmoney[sTmp] = MAXMONEY;
  2981.                 valuetmpx = 0;
  2982.                 returncode = TRUE;
  2983.             }
  2984.             break;
  2985.         case FJOINEVILTEAM:
  2986.             // This function adds the character to the evil team...
  2987.             switch_team(character, EVILTEAM);
  2988.             break;
  2989.         case FJOINNULLTEAM:
  2990.             // This function adds the character to the null team...
  2991.             switch_team(character, NULLTEAM);
  2992.             break;
  2993.         case FJOINGOODTEAM:
  2994.             // This function adds the character to the good team...
  2995.             switch_team(character, GOODTEAM);
  2996.             break;
  2997.         case FPITSKILL:
  2998.             // This function activates pit deaths...
  2999.             pitskill=TRUE;
  3000.             break;
  3001.         case FSETTARGETTOPASSAGEID:
  3002.             // This function finds a character who is both in the passage and who has
  3003.             // an item with the given IDSZ
  3004.             sTmp = who_is_blocking_passage_ID(valuetmpargument, valuetmpdistance);
  3005.             returncode = FALSE;
  3006.             if(sTmp != MAXCHR)
  3007.             {
  3008.                 chraitarget[character] = sTmp;
  3009.                 returncode = TRUE;
  3010.             }
  3011.             break;
  3012.         case FMAKENAMEUNKNOWN:
  3013.             // This function makes the name of an item/character unknown.
  3014.             chrnameknown[character]=FALSE;
  3015.             break;
  3016.         case FSPAWNEXACTPARTICLEENDSPAWN:
  3017.             // This function spawns a particle that spawns a character...
  3018.             tTmp = character;
  3019.             if(chrattachedto[character]!=MAXCHR)  tTmp = chrattachedto[character];
  3020.             tTmp = spawn_one_particle(valuetmpx, valuetmpy, valuetmpdistance, chrturnleftright[character], chrmodel[character], valuetmpargument, MAXCHR, 0, chrteam[character], tTmp, 0, MAXCHR);
  3021.             if(tTmp != MAXPRT)
  3022.             {
  3023.                 prtspawncharacterstate[tTmp] = valuetmpturn;
  3024.             }
  3025.             break;
  3026.         case FSPAWNPOOFSPEEDSPACINGDAMAGE:
  3027.             // This function makes a lovely little poof at the character's location,
  3028.             // adjusting the xy speed and spacing and the base damage first
  3029.             // Temporarily adjust the values for the particle type
  3030.             sTmp = chrmodel[character];
  3031.             sTmp = madprtpip[sTmp][capgopoofprttype[sTmp]];
  3032.             iTmp = pipxyvelbase[sTmp];
  3033.             tTmp = pipxyspacingbase[sTmp];
  3034.             test = pipdamagebase[sTmp];
  3035.             pipxyvelbase[sTmp] = valuetmpx;
  3036.             pipxyspacingbase[sTmp] = valuetmpy;
  3037.             pipdamagebase[sTmp] = valuetmpargument;
  3038.             spawn_poof(character, chrmodel[character]);
  3039.             // Restore the saved values
  3040.             pipxyvelbase[sTmp] = iTmp;
  3041.             pipxyspacingbase[sTmp] = tTmp;
  3042.             pipdamagebase[sTmp] = test;
  3043.             break;
  3044.         case FGIVEEXPERIENCETOGOODTEAM:
  3045.             // This function gives experience to everyone on the G Team
  3046.             give_team_experience(GOODTEAM, valuetmpargument, valuetmpdistance);
  3047.             break;
  3048.     }
  3049.  
  3050.  
  3051.     return returncode;
  3052. }
  3053.  
  3054. //--------------------------------------------------------------------------------------------
  3055. void set_operand(unsigned char variable)
  3056. {
  3057.     // ZZ> This function sets one of the tmp* values for scripted AI    
  3058.     switch(variable)
  3059.     {
  3060.         case VARTMPX:
  3061.             valuetmpx=valueoperationsum;
  3062.             break;
  3063.         case VARTMPY:
  3064.             valuetmpy=valueoperationsum;
  3065.             break;
  3066.         case VARTMPDISTANCE:
  3067.             valuetmpdistance=valueoperationsum;
  3068.             break;
  3069.         case VARTMPTURN:
  3070.             valuetmpturn=valueoperationsum;
  3071.             break;
  3072.         case VARTMPARGUMENT:
  3073.             valuetmpargument=valueoperationsum;
  3074.             break;
  3075.     }
  3076. }
  3077.  
  3078. //--------------------------------------------------------------------------------------------
  3079. void run_operand(unsigned int value, int character)
  3080. {
  3081.     // ZZ> This function does the scripted arithmetic in operator,operand pairs
  3082.     unsigned char opcode;
  3083.     unsigned char variable;
  3084.     int iTmp;
  3085.  
  3086.  
  3087.     // Get the operation code
  3088.     opcode = (value>>27);
  3089.     if(opcode&16)
  3090.     {
  3091.         // Get the working value from a constant, constants are all but high 5 bits
  3092.         iTmp = value&0x07ffffff;
  3093.     }
  3094.     else
  3095.     {
  3096.         // Get the working value from a register
  3097.         variable = value;
  3098.         iTmp = 1;
  3099.         switch(variable)
  3100.         {
  3101.             case VARTMPX:
  3102.                 iTmp = valuetmpx;
  3103.                 break;
  3104.             case VARTMPY:
  3105.                 iTmp = valuetmpy;
  3106.                 break;
  3107.             case VARTMPDISTANCE:
  3108.                 iTmp = valuetmpdistance;
  3109.                 break;
  3110.             case VARTMPTURN:
  3111.                 iTmp = valuetmpturn;
  3112.                 break;
  3113.             case VARTMPARGUMENT:
  3114.                 iTmp = valuetmpargument;
  3115.                 break;
  3116.             case VARRAND:
  3117.                 iTmp = RANDIE;
  3118.                 break;
  3119.             case VARSELFX:
  3120.                 iTmp = chrxpos[character];
  3121.                 break;
  3122.             case VARSELFY:
  3123.                 iTmp = chrypos[character];
  3124.                 break;
  3125.             case VARSELFTURN:
  3126.                 iTmp = chrturnleftright[character];
  3127.                 break;
  3128.             case VARSELFCOUNTER:
  3129.                 iTmp = chrcounter[character];
  3130.                 break;
  3131.             case VARSELFORDER:
  3132.                 iTmp = chrorder[character];
  3133.                 break;
  3134.             case VARSELFMORALE:
  3135.                 iTmp = teammorale[chrbaseteam[character]];
  3136.                 break;
  3137.             case VARSELFLIFE:
  3138.                 iTmp = chrlife[character];
  3139.                 break;
  3140.             case VARTARGETX:
  3141.                 iTmp = chrxpos[chraitarget[character]];
  3142.                 break;
  3143.             case VARTARGETY:
  3144.                 iTmp = chrypos[chraitarget[character]];
  3145.                 break;
  3146.             case VARTARGETDISTANCE:
  3147.                 iTmp = ABS((int)(chrxpos[chraitarget[character]]-chrxpos[character]))+
  3148.                        ABS((int)(chrypos[chraitarget[character]]-chrypos[character]));
  3149.                 break;
  3150.             case VARTARGETTURN:
  3151.                 iTmp = chrturnleftright[chraitarget[character]];
  3152.                 break;
  3153.             case VARLEADERX:
  3154.                 iTmp = chrxpos[character];
  3155.                 if(teamleader[chrteam[character]]!=NOLEADER)
  3156.                     iTmp = chrxpos[teamleader[chrteam[character]]];
  3157.                 break;
  3158.             case VARLEADERY:
  3159.                 iTmp = chrypos[character];
  3160.                 if(teamleader[chrteam[character]]!=NOLEADER)
  3161.                     iTmp = chrypos[teamleader[chrteam[character]]];
  3162.                 break;
  3163.             case VARLEADERDISTANCE:
  3164.                 iTmp = 10000;
  3165.                 if(teamleader[chrteam[character]]!=NOLEADER)
  3166.                     iTmp = ABS((int)(chrxpos[teamleader[chrteam[character]]]-chrxpos[character]))+
  3167.                            ABS((int)(chrypos[teamleader[chrteam[character]]]-chrypos[character]));
  3168.                 break;
  3169.             case VARLEADERTURN:
  3170.                 iTmp = chrturnleftright[character];
  3171.                 if(teamleader[chrteam[character]]!=NOLEADER)
  3172.                     iTmp = chrturnleftright[teamleader[chrteam[character]]];
  3173.                 break;
  3174.             case VARGOTOX:
  3175.                 iTmp = chraigotox[character][chraigoto[character]];
  3176.                 break;
  3177.             case VARGOTOY:
  3178.                 iTmp = chraigotoy[character][chraigoto[character]];
  3179.                 break;
  3180.             case VARGOTODISTANCE:
  3181.                 iTmp = ABS((int)(chraigotox[character][chraigoto[character]]-chrxpos[character]))+
  3182.                        ABS((int)(chraigotoy[character][chraigoto[character]]-chrypos[character]));
  3183.                 break;
  3184.             case VARTARGETTURNTO:
  3185.                 iTmp = atan2(chrypos[chraitarget[character]]-chrypos[character], chrxpos[chraitarget[character]]-chrxpos[character])*65535/(2*PI);
  3186.                 iTmp+=32768;
  3187.                 iTmp = iTmp&65535;
  3188.                 break;
  3189.             case VARPASSAGE:
  3190.                 iTmp = chrpassage[character];
  3191.                 break;
  3192.             case VARWEIGHT:
  3193.                 iTmp = chrholdingweight[character];
  3194.                 break;
  3195.             case VARSELFALTITUDE:
  3196.                 iTmp = chrzpos[character]-chrlevel[character];
  3197.                 break;
  3198.             case VARSELFID:
  3199.                 iTmp = capidsz[chrmodel[character]][IDSZTYPE];
  3200.                 break;
  3201.             case VARSELFHATEID:
  3202.                 iTmp = capidsz[chrmodel[character]][IDSZHATE];
  3203.                 break;
  3204.             case VARSELFMANA:
  3205.                 iTmp = chrmana[character];
  3206.                 if(chrcanchannel[character])  iTmp += chrlife[character];
  3207.                 break;
  3208.             case VARTARGETSTR:
  3209.                 iTmp = chrstrength[chraitarget[character]];
  3210.                 break;
  3211.             case VARTARGETWIS:
  3212.                 iTmp = chrwisdom[chraitarget[character]];
  3213.                 break;
  3214.             case VARTARGETINT:
  3215.                 iTmp = chrintelligence[chraitarget[character]];
  3216.                 break;
  3217.             case VARTARGETDEX:
  3218.                 iTmp = chrdexterity[chraitarget[character]];
  3219.                 break;
  3220.             case VARTARGETLIFE:
  3221.                 iTmp = chrlife[chraitarget[character]];
  3222.                 break;
  3223.             case VARTARGETMANA:
  3224.                 iTmp = chrmana[chraitarget[character]];
  3225.                 if(chrcanchannel[chraitarget[character]])  iTmp += chrlife[chraitarget[character]];
  3226.                 break;
  3227.             case VARTARGETLEVEL:
  3228.                 iTmp = chrexperiencelevel[chraitarget[character]];
  3229.                 break;
  3230.             case VARTARGETSPEEDX:
  3231.                 iTmp = chrxvel[chraitarget[character]];
  3232.                 break;
  3233.             case VARTARGETSPEEDY:
  3234.                 iTmp = chryvel[chraitarget[character]];
  3235.                 break;
  3236.             case VARTARGETSPEEDZ:
  3237.                 iTmp = chrzvel[chraitarget[character]];
  3238.                 break;
  3239.             case VARSELFSPAWNX:
  3240.                 iTmp = chrxstt[character];
  3241.                 break;
  3242.             case VARSELFSPAWNY:
  3243.                 iTmp = chrystt[character];
  3244.                 break;
  3245.             case VARSELFSTATE:
  3246.                 iTmp = chraistate[character];
  3247.                 break;
  3248.             case VARSELFSTR:
  3249.                 iTmp = chrstrength[character];
  3250.                 break;
  3251.             case VARSELFWIS:
  3252.                 iTmp = chrwisdom[character];
  3253.                 break;
  3254.             case VARSELFINT:
  3255.                 iTmp = chrintelligence[character];
  3256.                 break;
  3257.             case VARSELFDEX:
  3258.                 iTmp = chrdexterity[character];
  3259.                 break;
  3260.             case VARSELFMANAFLOW:
  3261.                 iTmp = chrmanaflow[character];
  3262.                 break;
  3263.             case VARTARGETMANAFLOW:
  3264.                 iTmp = chrmanaflow[chraitarget[character]];
  3265.                 break;
  3266.             case VARSELFATTACHED:
  3267.                 iTmp = number_of_attached_particles(character);
  3268.                 break;
  3269.             case VARSWINGTURN:
  3270.                 iTmp = camswing<<2;
  3271.                 break;
  3272.             case VARXYDISTANCE:
  3273.                 iTmp = sqrt(valuetmpx*valuetmpx + valuetmpy*valuetmpy);
  3274.                 break;
  3275.             case VARSELFZ:
  3276.                 iTmp = chrzpos[character];
  3277.                 break;
  3278.             case VARTARGETALTITUDE:
  3279.                 iTmp = chrzpos[chraitarget[character]]-chrlevel[chraitarget[character]];
  3280.                 break;
  3281.             case VARTARGETZ:
  3282.                 iTmp = chrzpos[chraitarget[character]];
  3283.                 break;
  3284.             case VARSELFINDEX:
  3285.                 iTmp = character;
  3286.                 break;
  3287.             case VAROWNERX:
  3288.                 iTmp = chrxpos[chraiowner[character]];
  3289.                 break;
  3290.             case VAROWNERY:
  3291.                 iTmp = chrypos[chraiowner[character]];
  3292.                 break;
  3293.             case VAROWNERTURN:
  3294.                 iTmp = chrturnleftright[chraiowner[character]];
  3295.                 break;
  3296.             case VAROWNERDISTANCE:
  3297.                 iTmp = ABS((int)(chrxpos[chraiowner[character]]-chrxpos[character]))+
  3298.                        ABS((int)(chrypos[chraiowner[character]]-chrypos[character]));
  3299.                 break;
  3300.             case VAROWNERTURNTO:
  3301.                 iTmp = atan2(chrypos[chraiowner[character]]-chrypos[character], chrxpos[chraiowner[character]]-chrxpos[character])*65535/(2*PI);
  3302.                 iTmp+=32768;
  3303.                 iTmp = iTmp&65535;
  3304.                 break;
  3305.             case VARXYTURNTO:
  3306.                 iTmp = atan2(valuetmpy-chrypos[character], valuetmpx-chrxpos[character])*65535/(2*PI);
  3307.                 iTmp+=32768;
  3308.                 iTmp = iTmp&65535;
  3309.                 break;
  3310.             case VARSELFMONEY:
  3311.                 iTmp = chrmoney[character];
  3312.                 break;
  3313.             case VARSELFACCEL:
  3314.                 iTmp = (chrmaxaccel[character]*100.0);
  3315.                 break;
  3316.             case VARTARGETEXP:
  3317.                 iTmp = chrexperience[chraitarget[character]];
  3318.                 break;
  3319.             case VARSELFAMMO:
  3320.                 iTmp = chrammo[character];
  3321.                 break;
  3322.         }
  3323.     }
  3324.  
  3325.  
  3326.     // Now do the math
  3327.     switch(opcode&15)
  3328.     {
  3329.         case OPADD:
  3330.             valueoperationsum+=iTmp;
  3331.             break;
  3332.         case OPSUB:
  3333.             valueoperationsum-=iTmp;
  3334.             break;
  3335.         case OPAND:
  3336.             valueoperationsum=valueoperationsum&iTmp;
  3337.             break;
  3338.         case OPSHR:
  3339.             valueoperationsum=valueoperationsum>>iTmp;
  3340.             break;
  3341.         case OPSHL:
  3342.             valueoperationsum=valueoperationsum<<iTmp;
  3343.             break;
  3344.         case OPMUL:
  3345.             valueoperationsum=valueoperationsum*iTmp;
  3346.             break;
  3347.         case OPDIV:
  3348.             if(iTmp != 0)
  3349.             {
  3350.                 valueoperationsum=valueoperationsum/iTmp;
  3351.             }
  3352.             break;
  3353.         case OPMOD:
  3354.             if(iTmp != 0)
  3355.             {
  3356.                 valueoperationsum=valueoperationsum%iTmp;
  3357.             }
  3358.             break;
  3359.     }
  3360. }
  3361.  
  3362. //--------------------------------------------------------------------------------------------
  3363. void let_character_think(int character)
  3364. {
  3365.     // ZZ> This function lets one character do AI stuff
  3366.     unsigned short aicode;
  3367.     unsigned int index;
  3368.     unsigned int value;
  3369.     unsigned int iTmp;
  3370.     unsigned char functionreturn;
  3371.     int operands;
  3372.  
  3373.  
  3374.     // Make life easier
  3375.     valueoldtarget = chraitarget[character];
  3376.     aicode=chraitype[character];
  3377.  
  3378.  
  3379.     // Figure out alerts that weren't already set
  3380.     set_alerts(character);
  3381.     changed = FALSE;
  3382.  
  3383.  
  3384.     // Clear the button latches
  3385.     if(chrisplayer[character]==FALSE)
  3386.     {
  3387.         chrlatchbutton[character] = 0;
  3388.     }
  3389.  
  3390.  
  3391.     // Reset the target if it can't be seen
  3392.     if(!chrcanseeinvisible[character] && chralive[character])
  3393.     {
  3394.         if(chralpha[chraitarget[character]]<=INVISIBLE || chrlight[chraitarget[character]]<=INVISIBLE)
  3395.         {
  3396.             chraitarget[character] = character;
  3397.         }
  3398.     }
  3399.  
  3400.  
  3401.     // Run the AI Script
  3402.     index = iAisStartPosition[aicode];
  3403.     valuegopoof = FALSE;
  3404.  
  3405.  
  3406.     value = iCompiledAis[index];
  3407.     while((value&0x87ffffff) != 0x80000035)  // End Function
  3408.     {
  3409.         value = iCompiledAis[index];
  3410.         // Was it a function
  3411.         if((value&0x80000000)!=0)
  3412.         {
  3413.             // Run the function
  3414.             functionreturn = run_function(value, character);
  3415.             // Get the jump code
  3416.             index++;
  3417.             iTmp=iCompiledAis[index];
  3418.             if(functionreturn==TRUE)
  3419.             {
  3420.                 // Proceed to the next function
  3421.                 index++;
  3422.             }
  3423.             else
  3424.             {
  3425.                 // Jump to where the jump code says to go
  3426.                 index=iTmp;
  3427.             }
  3428.         }
  3429.         else
  3430.         {
  3431.             // Get the number of operands
  3432.             index++;
  3433.             operands = iCompiledAis[index];
  3434.             // Now run the operation
  3435.             valueoperationsum=0;
  3436.             index++;
  3437.             while(operands > 0)
  3438.             {
  3439.                 iTmp = iCompiledAis[index];
  3440.                 run_operand(iTmp,character);  // This sets valueoperationsum
  3441.                 operands--;
  3442.                 index++;
  3443.             }
  3444.             // Save the results in the register that called the arithmetic
  3445.             set_operand(value);
  3446.         }
  3447.         // This is used by the Else function
  3448.         valuelastindent = value;
  3449.     }
  3450.  
  3451.  
  3452.     // Set latches
  3453.     if(chrisplayer[character]==FALSE && aicode!=0)
  3454.     {
  3455.         if(chrismount[character]&&chrholdingwhich[character][0]!=MAXCHR)
  3456.         {
  3457.             // Mount
  3458.             chrlatchx[character] = chrlatchx[chrholdingwhich[character][0]];
  3459.             chrlatchy[character] = chrlatchy[chrholdingwhich[character][0]];
  3460.         }
  3461.         else
  3462.         {
  3463.             // Normal AI
  3464.             chrlatchx[character] = (chraigotox[character][chraigoto[character]]-chrxpos[character])/1000.0;
  3465.             chrlatchy[character] = (chraigotoy[character][chraigoto[character]]-chrypos[character])/1000.0;
  3466.         }
  3467.     }
  3468.  
  3469.  
  3470.     // Clear alerts for next time around
  3471.     chralert[character] = 0;
  3472.     if(changed)  chralert[character] = ALERTIFCHANGED;
  3473.  
  3474.  
  3475.     // Do poofing
  3476.     if(valuegopoof)
  3477.     {
  3478.         if(chrattachedto[character] != MAXCHR)
  3479.             detach_character_from_mount(character, TRUE, FALSE);
  3480.         if(chrholdingwhich[character][0] != MAXCHR)
  3481.             detach_character_from_mount(chrholdingwhich[character][0], TRUE, FALSE);
  3482.         if(chrholdingwhich[character][1] != MAXCHR)
  3483.             detach_character_from_mount(chrholdingwhich[character][1], TRUE, FALSE);
  3484.         free_inventory(character);
  3485.         free_one_character(character);
  3486.         // If this character was killed in another's script, we don't want the poof to
  3487.         // carry over...
  3488.         valuegopoof = FALSE;
  3489.     }
  3490. }
  3491.  
  3492. //--------------------------------------------------------------------------------------------
  3493. void let_ai_think()
  3494. {
  3495.     // ZZ> This function lets every computer controlled character do AI stuff
  3496.     int character;
  3497.  
  3498.  
  3499.     numblip = 0;
  3500.     character = 0;
  3501.     while(character < MAXCHR)
  3502.     {
  3503.         if(chron[character] && (!chrinpack[character]||capisequipment[chrmodel[character]]) && (chralive[character]||(chralert[character]&ALERTIFCLEANEDUP)||(chralert[character]&ALERTIFCRUSHED)))
  3504.         {
  3505.             // Cleaned up characters shouldn't be alert to anything else
  3506.             if(chralert[character]&ALERTIFCRUSHED)  chralert[character] = ALERTIFCRUSHED;
  3507.             if(chralert[character]&ALERTIFCLEANEDUP)  chralert[character] = ALERTIFCLEANEDUP;
  3508.             let_character_think(character);
  3509.         }
  3510.         character++;
  3511.     }
  3512. }
  3513.  
  3514.