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

  1. // particle.c
  2.  
  3. // Egoboo, Copyright (C) 2000 Aaron Bishop
  4.  
  5. #include "egoboo.h"
  6.  
  7. //--------------------------------------------------------------------------------------------
  8. void make_prtlist(void)
  9. {
  10.     // ZZ> This function figures out which particles are visible, and it sets up dynamic
  11.     //     lighting
  12.     int cnt, tnc, disx, disy, distance, slot;
  13.  
  14.  
  15.     // Don't really make a list, just set to visible or not
  16.     numdynalight = 0;
  17.     dynadistancetobeat = MAXDYNADIST;
  18.     cnt = 0;
  19.     while(cnt < MAXPRT)
  20.     {
  21.         prtinview[cnt] = FALSE;
  22.         if(prton[cnt])
  23.         {
  24.             prtinview[cnt] = meshinrenderlist[prtonwhichfan[cnt]];
  25.             // Set up the lights we need
  26.             if(prtdynalighton[cnt])
  27.             {
  28.                 disx = prtxpos[cnt]-camtrackx;
  29.                 disx = ABS(disx);
  30.                 disy = prtypos[cnt]-camtracky;
  31.                 disy = ABS(disy);
  32.                 distance = disx+disy;
  33.                 if(distance < dynadistancetobeat)
  34.                 {
  35.                     if(numdynalight < MAXDYNA)
  36.                     {
  37.                         // Just add the light
  38.                         slot = numdynalight;
  39.                         dynadistance[slot] = distance;
  40.                         numdynalight++;
  41.                     }
  42.                     else
  43.                     {
  44.                         // Overwrite the worst one
  45.                         slot = 0;
  46.                         tnc = 1;
  47.                         dynadistancetobeat = dynadistance[0];
  48.                         while(tnc < MAXDYNA)
  49.                         {
  50.                             if(dynadistance[tnc] > dynadistancetobeat)
  51.                             {
  52.                                 slot = tnc;
  53.                             }
  54.                             tnc++;
  55.                         }
  56.                         dynadistance[slot] = distance;
  57.  
  58.  
  59.                         // Find the new distance to beat
  60.                         tnc = 1;
  61.                         dynadistancetobeat = dynadistance[0];
  62.                         while(tnc < MAXDYNA)
  63.                         {
  64.                             if(dynadistance[tnc] > dynadistancetobeat)
  65.                             {
  66.                                 dynadistancetobeat = dynadistance[tnc];
  67.                             }
  68.                             tnc++;
  69.                         }
  70.                     }
  71.                     dynalightlistx[slot] = prtxpos[cnt];
  72.                     dynalightlisty[slot] = prtypos[cnt];
  73.                     dynalightlevel[slot] = prtdynalightlevel[cnt];
  74.                     dynalightfalloff[slot] = prtdynalightfalloff[cnt];
  75.                 }
  76.             }
  77.         }
  78.         cnt++;
  79.     }
  80. }
  81.  
  82. //--------------------------------------------------------------------------------------------
  83. void free_one_particle_no_sound(int particle)
  84. {
  85.     // ZZ> This function sticks a particle back on the free particle stack
  86.     freeprtlist[numfreeprt]=particle;
  87.     numfreeprt++;
  88.     prton[particle]=FALSE;
  89. }
  90.  
  91. //--------------------------------------------------------------------------------------------
  92. void play_particle_sound(int particle, signed char sound)
  93. {
  94.     // ZZ> This function plays a sound effect for a particle
  95.     int distance, volume, frequency;
  96.  
  97.     frequency = FRQRANDOM;
  98.     if(sound!=-1)
  99.     {
  100.         distance = ABS(camtrackx-prtxpos[particle])+ABS(camtracky-prtypos[particle]);
  101.         volume = -distance;
  102.         volume = volume<<VOLSHIFT;
  103.         if(volume > VOLMIN)
  104.         {
  105.             if(prtmodel[particle]!=MAXMODEL)
  106.             {
  107.                 // Local sound
  108.  
  109.                 play_sound_pvf(capwaveindex[prtmodel[particle]][sound], PANMID, volume, frequency);
  110.  
  111.             }
  112.             else
  113.             {
  114.                 // Global sound ( for coins )
  115.  
  116.                 play_sound_pvf(sound, PANMID, volume, frequency);
  117.             }
  118.         }
  119.     }
  120. }
  121.  
  122. //--------------------------------------------------------------------------------------------
  123. void free_one_particle(int particle)
  124. {
  125.     // ZZ> This function sticks a particle back on the free particle stack and
  126.     //     plays the sound associated with the particle
  127.     int child;
  128.     if(prtspawncharacterstate[particle] != SPAWNNOCHARACTER)
  129.     {
  130.         child = spawn_one_character(prtxpos[particle], prtypos[particle], prtzpos[particle],
  131.                                     prtmodel[particle], prtteam[particle], 0, prtfacing[particle],
  132.                                     NULL, MAXCHR);
  133.         if(child != MAXCHR)
  134.         {
  135.             chraistate[child] = prtspawncharacterstate[particle];
  136.             chraiowner[child] = prtchr[particle];
  137.         }
  138.     }
  139.     play_particle_sound(particle, pipsoundend[prtpip[particle]]);
  140.     freeprtlist[numfreeprt]=particle;
  141.     numfreeprt++;
  142.     prton[particle]=FALSE;
  143. }
  144.  
  145. //--------------------------------------------------------------------------------------------
  146. int get_free_particle(int force)
  147. {
  148.     // ZZ> This function gets an unused particle.  If all particles are in use
  149.     //     and force is set, it grabs the first unimportant one.  The particle
  150.     //     index is the return value
  151.     int particle;
  152.  
  153.  
  154.     // Return MAXPRT if we can't find one
  155.     particle = MAXPRT;
  156.     if(numfreeprt==0)
  157.     {
  158.         if(force)
  159.         {
  160.             // Gotta find one, so go through the list
  161.             particle = 0;
  162.             while(particle<MAXPRT)
  163.             {
  164.                 if(prtbumpsize[particle]==0)
  165.                 {
  166.                     // Found one
  167.                     return particle;
  168.                 }
  169.                 particle++;
  170.             }
  171.         }
  172.     }
  173.     else
  174.     {
  175.         if(force || numfreeprt > (MAXPRT/4))
  176.         {
  177.             // Just grab the next one
  178.             numfreeprt--;
  179.             particle=freeprtlist[numfreeprt];
  180.         }
  181.     }
  182.     return particle;
  183. }
  184.  
  185. //--------------------------------------------------------------------------------------------
  186. unsigned short spawn_one_particle(float x, float y, float z,
  187.   unsigned short facing, unsigned short model, unsigned short pip, 
  188.   unsigned short characterattach, unsigned short grip, unsigned char team,
  189.   unsigned short characterorigin, unsigned short multispawn, unsigned short oldtarget)
  190. {
  191.     // ZZ> This function spawns a new particle, and returns the number of that particle
  192.     int cnt, velocity;
  193.     float xvel, yvel, zvel, tvel;
  194.     int offsetfacing, newrand;
  195.  
  196.  
  197.     // Convert from local pip to global pip
  198.     if(model<MAXMODEL)
  199.         pip = madprtpip[model][pip];
  200.  
  201.  
  202.     cnt = get_free_particle(pipforce[pip]);
  203.     if(cnt != MAXPRT)
  204.     {
  205.         // Necessary data for any part
  206.         prton[cnt] = TRUE;
  207.         prtpip[cnt] = pip;
  208.         prtmodel[cnt] = model;
  209.         prtinview[cnt] = FALSE;
  210.         prtlevel[cnt] = 0;
  211.         prtteam[cnt] = team;
  212.         prtchr[cnt] = characterorigin;
  213.         prtdamagetype[cnt] = pipdamagetype[pip];
  214.         prtspawncharacterstate[cnt] = SPAWNNOCHARACTER;
  215.  
  216.  
  217.         // Lighting and sound
  218.         prtdynalighton[cnt] = FALSE;
  219.         if(multispawn == 0)
  220.         {
  221.             prtdynalighton[cnt] = pipdynalightmode[pip];
  222.             if(pipdynalightmode[pip]==DYNALOCAL)
  223.             {
  224.                 prtdynalighton[cnt] = FALSE;
  225.                 if(chrteam[characterorigin] == rtslocalteam)
  226.                 {
  227.                     prtdynalighton[cnt] = TRUE;
  228.                 }
  229.             }
  230.         }
  231.         prtdynalightlevel[cnt] = pipdynalevel[pip];
  232.         prtdynalightfalloff[cnt] = pipdynafalloff[pip];
  233.  
  234.  
  235.  
  236.         // Set character attachments ( characterattach==MAXCHR means none )
  237.         prtattachedtocharacter[cnt] = characterattach;
  238.         prtgrip[cnt] = grip;
  239.  
  240.  
  241.  
  242.         // Correct facing
  243.         facing += pipfacingbase[pip];
  244.  
  245.  
  246.         // Targeting...
  247.         zvel = 0;
  248.         newrand = RANDIE;
  249.         z = z+pipzspacingbase[pip]+(newrand&pipzspacingrand[pip])-(pipzspacingrand[pip]>>1);
  250.         newrand = RANDIE;
  251.         velocity = (pipxyvelbase[pip]+(newrand&pipxyvelrand[pip]));
  252.         prttarget[cnt] = oldtarget;
  253.         if(pipnewtargetonspawn[pip])
  254.         {
  255.             if(piptargetcaster[pip])
  256.             {
  257.                 // Set the target to the caster
  258.                 prttarget[cnt] = characterorigin;
  259.             }
  260.             else
  261.             {
  262.                 // Find a target
  263.                 prttarget[cnt] = find_target(x, y, facing, piptargetangle[pip], piponlydamagefriendly[pip], FALSE, team, characterorigin, oldtarget);
  264.                 if(prttarget[cnt] != MAXCHR && piphoming[pip] == FALSE)
  265.                 {
  266.                     facing = facing-glouseangle;
  267.                 }
  268.                 // Correct facing for dexterity...
  269.                 offsetfacing = 0;
  270.                 if(chrdexterity[characterorigin]<PERFECTSTAT)
  271.                 {
  272.                     // Correct facing for randomness
  273.                     offsetfacing = RANDIE;
  274.                     offsetfacing = offsetfacing & pipfacingrand[pip];
  275.                     offsetfacing -= (pipfacingrand[pip]>>1);
  276.                     offsetfacing = (offsetfacing*(PERFECTSTAT-chrdexterity[characterorigin]))>>13;  // Divided by PERFECTSTAT
  277.                 }
  278.                 if(prttarget[cnt] != MAXCHR && pipzaimspd[pip]!=0)
  279.                 {
  280.                     // These aren't velocities...  This is to do aiming on the Z axis
  281.                     if(velocity > 0)
  282.                     {
  283.                         xvel = chrxpos[prttarget[cnt]]-x;
  284.                         yvel = chrypos[prttarget[cnt]]-y;
  285.                         tvel = sqrt(xvel*xvel+yvel*yvel)/velocity;  // This is the number of steps...
  286.                         if(tvel > 0)
  287.                         {
  288.                             zvel = (chrzpos[prttarget[cnt]]+(chrbumpsize[prttarget[cnt]]>>1)-z)/tvel;  // This is the zvel alteration
  289.                             if(zvel < -(pipzaimspd[pip]>>1)) zvel = -(pipzaimspd[pip]>>1);
  290.                             if(zvel > pipzaimspd[pip]) zvel = pipzaimspd[pip];
  291.                         }
  292.                     }
  293.                 }
  294.             }
  295.             // Does it go away?
  296.             if(prttarget[cnt]==MAXCHR && pipneedtarget[pip])
  297.             {
  298.                 free_one_particle(cnt);
  299.                 return MAXPRT;
  300.             }
  301.             // Start on top of target
  302.             if(prttarget[cnt]!=MAXCHR && pipstartontarget[pip])
  303.             {
  304.                 x = chrxpos[prttarget[cnt]];
  305.                 y = chrypos[prttarget[cnt]];
  306.             }
  307.         }
  308.         else
  309.         {
  310.             // Correct facing for randomness
  311.             offsetfacing = RANDIE;
  312.             offsetfacing = offsetfacing & pipfacingrand[pip];
  313.             offsetfacing -= (pipfacingrand[pip]>>1);
  314.         }
  315.         facing+=offsetfacing;
  316.         prtfacing[cnt] = facing;
  317.         facing = facing>>2;
  318.  
  319.  
  320.         // Location data from arguments
  321.         newrand = RANDIE;
  322.         x = x+turntosin[(facing+12288)&16383]*(pipxyspacingbase[pip]+(newrand&pipxyspacingrand[pip]));
  323.         y = y+turntosin[(facing+8192)&16383]*(pipxyspacingbase[pip]+(newrand&pipxyspacingrand[pip]));
  324.         if(x < 0)  x = 0;
  325.         if(x > meshedgex-2)  x = meshedgex - 2;
  326.         if(y < 0)  y = 0;
  327.         if(y > meshedgey-2)  y = meshedgey - 2;
  328.         prtxpos[cnt] = x;
  329.         prtypos[cnt] = y;
  330.         prtzpos[cnt] = z;
  331.  
  332.  
  333.         // Velocity data
  334.         xvel = turntosin[(facing+12288)&16383]*velocity;
  335.         yvel = turntosin[(facing+8192)&16383]*velocity;
  336.         newrand = RANDIE;
  337.         zvel += pipzvelbase[pip]+(newrand&pipzvelrand[pip])-(pipzvelrand[pip]>>1);
  338.         prtxvel[cnt] = xvel;
  339.         prtyvel[cnt] = yvel;
  340.         prtzvel[cnt] = zvel;
  341.  
  342.  
  343.         // Template values
  344.         prtbumpsize[cnt] = pipbumpsize[pip];
  345.         prtbumpsizebig[cnt] = prtbumpsize[cnt]+(prtbumpsize[cnt]>>1);
  346.         prtbumpheight[cnt] = pipbumpheight[pip];
  347.         prttype[cnt] = piptype[pip];
  348.  
  349.  
  350.         // Image data
  351.         newrand = RANDIE;
  352.         prtrotate[cnt] = (newrand&piprotaterand[pip])+piprotatebase[pip];
  353.         prtrotateadd[cnt] = piprotateadd[pip];
  354.         prtsize[cnt] = pipsizebase[pip];
  355.         prtsizeadd[cnt] = pipsizeadd[pip];
  356.         prtimage[cnt] = 0;
  357.         newrand = RANDIE;
  358.         prtimageadd[cnt] = pipimageadd[pip]+(newrand&pipimageaddrand[pip]);
  359.         prtimagestt[cnt] = pipimagebase[pip]<<8;
  360.         prtimagemax[cnt] = pipnumframes[pip]<<8;
  361.         prttime[cnt] = piptime[pip];
  362.         if(pipendlastframe[pip] && prtimageadd[cnt]!=0)
  363.         {
  364.             if(prttime[cnt]==0)
  365.             {
  366.                 // Part time is set to 1 cycle
  367.                 prttime[cnt] = (prtimagemax[cnt]/prtimageadd[cnt])-1;
  368.             }
  369.             else
  370.             {
  371.                 // Part time is used to give number of cycles
  372.                 prttime[cnt] = prttime[cnt]*((prtimagemax[cnt]/prtimageadd[cnt])-1);
  373.             }
  374.         }
  375.  
  376.  
  377.         // Set onwhichfan...
  378.         prtonwhichfan[cnt] = OFFEDGE;
  379.         if(prtxpos[cnt] > 0 && prtxpos[cnt] < meshedgex && prtypos[cnt] > 0 && prtypos[cnt] < meshedgey)
  380.         {
  381.             prtonwhichfan[cnt] = meshfanstart[((int)prtypos[cnt])>>7] + (((int)prtxpos[cnt])>>7);
  382.         }
  383.  
  384.  
  385.         // Damage stuff
  386.         prtdamagebase[cnt] = pipdamagebase[pip];
  387.         prtdamagerand[cnt] = pipdamagerand[pip];
  388.  
  389.  
  390.  
  391.         // Spawning data
  392.         prtspawntime[cnt] = pipcontspawntime[pip];
  393.         if(prtspawntime[cnt]!=0)
  394.         {
  395.             prtspawntime[cnt] = 1;
  396.             if(prtattachedtocharacter[cnt] != MAXCHR)
  397.             {
  398.                 prtspawntime[cnt]++; // Because attachment takes an update before it happens
  399.             }
  400.         }
  401.  
  402.  
  403.         // Sound effect
  404.         play_particle_sound(cnt, pipsoundspawn[pip]);
  405.     }
  406.     return cnt;
  407. }
  408.  
  409. //--------------------------------------------------------------------------------------------
  410. unsigned char __prthitawall(int particle)
  411. {
  412.     // ZZ> This function returns nonzero if the particle hit a wall
  413.     int x, y;
  414.  
  415.     y = prtypos[particle];  x = prtxpos[particle];
  416.     // !!!BAD!!! Should really do bound checking...
  417.     if(pipbumpmoney[prtpip[particle]])
  418.     {
  419.         return ((meshfx[meshfanstart[y>>7]+(x>>7)])&(MESHFXIMPASS|MESHFXWALL));
  420.     }
  421.     else
  422.     {
  423.         return ((meshfx[meshfanstart[y>>7]+(x>>7)])&(MESHFXIMPASS));
  424.     }
  425. }
  426.  
  427. //--------------------------------------------------------------------------------------------
  428. void disaffirm_attached_particles(unsigned short character)
  429. {
  430.     // ZZ> This function makes sure a character has no attached particles
  431.     unsigned short particle;
  432.  
  433.     particle = 0;
  434.     while(particle < MAXPRT)
  435.     {
  436.         if(prton[particle] && prtattachedtocharacter[particle]==character)
  437.         {
  438.             free_one_particle(particle);
  439.         }
  440.         particle++;
  441.     }
  442.  
  443.     // Set the alert for disaffirmation ( wet torch )
  444.     chralert[character]|=ALERTIFDISAFFIRMED;
  445. }
  446.  
  447. //--------------------------------------------------------------------------------------------
  448. unsigned short number_of_attached_particles(unsigned short character)
  449. {
  450.     // ZZ> This function returns the number of particles attached to the given character
  451.     unsigned short cnt, particle;
  452.  
  453.     cnt = 0;
  454.     particle = 0;
  455.     while(particle < MAXPRT)
  456.     {
  457.         if(prton[particle] && prtattachedtocharacter[particle]==character)
  458.         {
  459.             cnt++;
  460.         }
  461.         particle++;
  462.     }
  463.  
  464.     return cnt;
  465. }
  466.  
  467. //--------------------------------------------------------------------------------------------
  468. void reaffirm_attached_particles(unsigned short character)
  469. {
  470.     // ZZ> This function makes sure a character has all of it's particles
  471.     unsigned short numberattached;
  472.     unsigned short particle;
  473.  
  474.     numberattached = number_of_attached_particles(character);
  475.     while(numberattached < capattachedprtamount[chrmodel[character]])
  476.     {
  477.         particle = spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], 0, chrmodel[character], capattachedprttype[chrmodel[character]], character, SPAWNLAST+numberattached, chrteam[character], character, numberattached, MAXCHR);
  478.         if(particle != MAXPRT)
  479.         {
  480.             attach_particle_to_character(particle, character, prtgrip[particle]);
  481.         }
  482.         numberattached++;
  483.     }
  484.  
  485.     // Set the alert for reaffirmation ( for exploding barrels with fire )
  486.     chralert[character] = chralert[character]|ALERTIFREAFFIRMED;
  487. }
  488.  
  489.  
  490. //--------------------------------------------------------------------------------------------
  491. void move_particles(void)
  492. {
  493.     // ZZ> This is the particle physics function
  494.     int cnt, tnc, x, y, fan;
  495.     unsigned short facing, pip, particle;
  496.     float level;
  497.  
  498.     cnt = 0;
  499.     while(cnt < MAXPRT)
  500.     {
  501.         if(prton[cnt])
  502.         {
  503.             prtonwhichfan[cnt] = OFFEDGE;
  504.             prtlevel[cnt] = 0;
  505.             if(prtxpos[cnt] > 0 && prtxpos[cnt] < meshedgex && prtypos[cnt] > 0 && prtypos[cnt] < meshedgey)
  506.             {
  507.                 x = prtxpos[cnt];
  508.                 y = prtypos[cnt];
  509.                 x = x>>7;
  510.                 y = y>>7;
  511.                 fan = meshfanstart[y]+x;
  512.                 prtonwhichfan[cnt] = fan;
  513.                 prtlevel[cnt] = get_level(prtxpos[cnt], prtypos[cnt], fan, FALSE);
  514.             }
  515.  
  516.  
  517.             // To make it easier
  518.             pip = prtpip[cnt];
  519.  
  520.             // Animate particle
  521.             prtimage[cnt] = (prtimage[cnt]+prtimageadd[cnt]);
  522.             if(prtimage[cnt] >= prtimagemax[cnt])
  523.                 prtimage[cnt]=0;
  524.             prtrotate[cnt]+=prtrotateadd[cnt];
  525.             prtsize[cnt]+=prtsizeadd[cnt];
  526.  
  527.  
  528.             // Change dyna light values
  529.             prtdynalightlevel[cnt] += pipdynalightleveladd[pip];
  530.             prtdynalightfalloff[cnt] += pipdynalightfalloffadd[pip];
  531.  
  532.  
  533.             // Make it sit on the floor...  Shift is there to correct for sprite size
  534.             level = prtlevel[cnt]+(prtsize[cnt]>>9);
  535.  
  536.  
  537.             // Check floor collision and do iterative physics
  538.             if((prtzpos[cnt] < level && prtzvel[cnt] < 0.1) || (prtzpos[cnt] < level - PRTLEVELFIX))
  539.             {
  540.                 prtzpos[cnt] = level;
  541.                 prtxvel[cnt] = prtxvel[cnt]*noslipfriction;
  542.                 prtyvel[cnt] = prtyvel[cnt]*noslipfriction;
  543.                 if(pipendground[pip])  prttime[cnt] = 1;
  544.                 if(prtzvel[cnt] < 0)
  545.                 {
  546.                     if(prtzvel[cnt] > -STOPBOUNCINGPART)
  547.                     {
  548.                         // Make it not bounce
  549.                         prtzpos[cnt]-=.0001;
  550.                     }
  551.                     else
  552.                     {
  553.                         // Make it bounce
  554.                         prtzvel[cnt] = -prtzvel[cnt]*pipdampen[pip];
  555.                         // Play the sound for hitting the floor [FSND]
  556.                         play_particle_sound(cnt, pipsoundfloor[pip]);
  557.                     }
  558.                 }
  559.             }
  560.             else
  561.             {
  562.                 if(prtattachedtocharacter[cnt] == MAXCHR)
  563.                 {
  564.                     prtxpos[cnt]+=prtxvel[cnt];
  565.                     if(__prthitawall(cnt))
  566.                     {
  567.                         // Play the sound for hitting a wall [WSND]
  568.                         play_particle_sound(cnt, pipsoundwall[pip]);
  569.                         prtxpos[cnt]-=prtxvel[cnt];
  570.                         prtxvel[cnt]=(-prtxvel[cnt]*pipdampen[pip]);
  571.                         if(pipendwall[pip])
  572.                         {
  573.                             prttime[cnt] = 1;
  574.                         }
  575.                         else
  576.                         {
  577.                             // Change facing
  578.                             facing = prtfacing[cnt];
  579.                             if(facing < 32768)
  580.                             {
  581.                                 facing-=NORTH;
  582.                                 facing = ~facing;
  583.                                 facing+=NORTH;
  584.                             }
  585.                             else
  586.                             {
  587.                                 facing-=SOUTH;
  588.                                 facing = ~facing;
  589.                                 facing+=SOUTH;
  590.                             }
  591.                             prtfacing[cnt] = facing;
  592.                         }
  593.                     }
  594.                     prtypos[cnt]+=prtyvel[cnt];
  595.                     if(__prthitawall(cnt))
  596.                     {
  597.                         prtypos[cnt]-=prtyvel[cnt];
  598.                         prtyvel[cnt]=(-prtyvel[cnt]*pipdampen[pip]);
  599.                         if(pipendwall[pip])
  600.                         {
  601.                             prttime[cnt] = 1;
  602.                         }
  603.                         else
  604.                         {
  605.                             // Change facing
  606.                             facing = prtfacing[cnt];
  607.                             if(facing < 16384 || facing > 49152)
  608.                             {
  609.                                 facing = ~facing;
  610.                             }
  611.                             else
  612.                             {
  613.                                 facing-=EAST;
  614.                                 facing = ~facing;
  615.                                 facing+=EAST;
  616.                             }
  617.                             prtfacing[cnt] = facing;
  618.                         }
  619.                     }
  620.                     prtzpos[cnt]+=prtzvel[cnt];
  621.                     prtzvel[cnt]+=gravity;
  622.                 }
  623.             }
  624.             // Do homing
  625.             if(piphoming[pip] && prttarget[cnt]!=MAXCHR)
  626.             {
  627.                 if(chralive[prttarget[cnt]]==FALSE)
  628.                 {
  629.                     prttime[cnt] = 1;
  630.                 }
  631.                 else
  632.                 {
  633.                     if(prtattachedtocharacter[cnt]==MAXCHR)
  634.                     {
  635.                         prtxvel[cnt]=(prtxvel[cnt]+((chrxpos[prttarget[cnt]]-prtxpos[cnt])*piphomingaccel[pip]))*piphomingfriction[pip];
  636.                         prtyvel[cnt]=(prtyvel[cnt]+((chrypos[prttarget[cnt]]-prtypos[cnt])*piphomingaccel[pip]))*piphomingfriction[pip];
  637.                         prtzvel[cnt]=(prtzvel[cnt]+((chrzpos[prttarget[cnt]]+(chrbumpheight[prttarget[cnt]]>>1)-prtzpos[cnt])*piphomingaccel[pip]));
  638.  
  639.                     }
  640.                     if(piprotatetoface[pip])
  641.                     {
  642.                         // Turn to face target
  643.                         facing = atan2(chrypos[prttarget[cnt]]-prtypos[cnt], chrxpos[prttarget[cnt]]-prtxpos[cnt])*65535/(2*PI);
  644.                         facing+=32768;
  645.                         prtfacing[cnt] = facing;
  646.                     }
  647.                 }
  648.             }
  649.             // Do speed limit on Z
  650.             if(prtzvel[cnt] < -pipspdlimit[pip])  prtzvel[cnt]=-pipspdlimit[pip];
  651.  
  652.  
  653.  
  654.             // Spawn new particles if continually spawning
  655.             if(pipcontspawnamount[pip]>0)
  656.             {
  657.                 prtspawntime[cnt]--;
  658.                 if(prtspawntime[cnt] == 0)
  659.                 {
  660.                     prtspawntime[cnt] = pipcontspawntime[pip];
  661.                     facing = prtfacing[cnt];
  662.                     tnc = 0;
  663.                     while(tnc < pipcontspawnamount[pip])
  664.                     {
  665.                         particle = spawn_one_particle(prtxpos[cnt], prtypos[cnt], prtzpos[cnt],
  666.                                            facing, prtmodel[cnt], pipcontspawnpip[pip],
  667.                                            MAXCHR, SPAWNLAST, prtteam[cnt], prtchr[cnt], tnc, prttarget[cnt]);
  668.                         if(pipfacingadd[prtpip[cnt]]!=0 && particle < MAXPRT)
  669.                         {
  670.                             // Hack to fix velocity
  671.                             prtxvel[particle]+=prtxvel[cnt];
  672.                             prtyvel[particle]+=prtyvel[cnt];
  673.                         }
  674.                         facing+=pipcontspawnfacingadd[pip];
  675.                         tnc++;
  676.                     }
  677.                 }
  678.             }
  679.  
  680.  
  681.             // Check underwater
  682.             if(prtzpos[cnt] < waterdouselevel && (meshfx[prtonwhichfan[cnt]]&MESHFXWATER) && pipendwater[pip])
  683.             {
  684.                 // Splash for particles is just a ripple
  685.                 spawn_one_particle(prtxpos[cnt], prtypos[cnt], watersurfacelevel,
  686.                                    0, MAXMODEL, RIPPLE, MAXCHR, SPAWNLAST, NULLTEAM, MAXCHR, 0, MAXCHR);
  687.  
  688.  
  689.                 // Check for disaffirming character
  690.                 if(prtattachedtocharacter[cnt]!=MAXCHR && prtchr[cnt]==prtattachedtocharacter[cnt])
  691.                 {
  692.                     // Disaffirm the whole character
  693.                     disaffirm_attached_particles(prtattachedtocharacter[cnt]);
  694.                 }
  695.                 else
  696.                 {
  697.                     // Just destroy the particle
  698. //                    free_one_particle(cnt);
  699.                     prttime[cnt] = 1;
  700.                 }
  701.             }
  702. //            else
  703. //            {
  704.                 // Spawn new particles if time for old one is up
  705.                 if(prttime[cnt]!=0)
  706.                 {
  707.                     prttime[cnt]--;
  708.                     if(prttime[cnt] == 0)
  709.                     {
  710.                         facing = prtfacing[cnt];
  711.                         tnc = 0;
  712.                         while(tnc < pipendspawnamount[pip])
  713.                         {
  714.                             spawn_one_particle(prtxpos[cnt]-prtxvel[cnt], prtypos[cnt]-prtyvel[cnt], prtzpos[cnt],
  715.                                                facing, prtmodel[cnt], pipendspawnpip[pip],
  716.                                                MAXCHR, SPAWNLAST, prtteam[cnt], prtchr[cnt], tnc, prttarget[cnt]);
  717.                             facing+=pipendspawnfacingadd[pip];
  718.                             tnc++;
  719.                         }
  720.                         free_one_particle(cnt);
  721.                     }
  722.                 }
  723. //            }
  724.             prtfacing[cnt]+=pipfacingadd[pip];
  725.         }
  726.         cnt++;
  727.     }
  728. }
  729.  
  730. //--------------------------------------------------------------------------------------------
  731. void attach_particles()
  732. {
  733.     // ZZ> This function attaches particles to their characters so everything gets
  734.     //     drawn right
  735.     int cnt;
  736.  
  737.     cnt = 0;
  738.     while(cnt < MAXPRT)
  739.     {
  740.         if(prton[cnt] && prtattachedtocharacter[cnt]!=MAXCHR)
  741.         {
  742.             attach_particle_to_character(cnt, prtattachedtocharacter[cnt], prtgrip[cnt]);
  743.             // Correct facing so swords knock characters in the right direction...
  744.             if(pipdamfx[prtpip[cnt]]&DAMFXTURN)
  745.                 prtfacing[cnt] = chrturnleftright[prtattachedtocharacter[cnt]];
  746.         }
  747.         cnt++;
  748.     }
  749. }
  750.  
  751. //--------------------------------------------------------------------------------------------
  752. void free_all_particles()
  753. {
  754.     // ZZ> This function resets the particle allocation lists
  755.     numfreeprt = 0;
  756.     while(numfreeprt<MAXPRT)
  757.     {
  758.         prton[numfreeprt] = 0;
  759.         freeprtlist[numfreeprt] = numfreeprt;
  760.         numfreeprt++;
  761.     }
  762. }
  763.  
  764. //--------------------------------------------------------------------------------------------
  765. void setup_particles()
  766. {
  767.     // ZZ> This function sets up particle data
  768.     int cnt;
  769.     double x, y;
  770.  
  771.     particletexture = 0;
  772.  
  773.     // Image coordinates on the big particle bitmap
  774.     for (cnt = 0; cnt < MAXPARTICLEIMAGE; cnt++)
  775.     {
  776.         x = cnt&15;
  777.         y = cnt>>4;
  778.         particleimageu[cnt][0] = (float) ((.05+x)/16.0);
  779.         particleimageu[cnt][1] = (float) ((.95+x)/16.0);
  780.         particleimagev[cnt][0] = (float) ((.05+y)/16.0);
  781.         particleimagev[cnt][1] = (float) ((.95+y)/16.0);
  782.     }
  783.  
  784.     // Reset the allocation table
  785.     free_all_particles();
  786. }
  787.  
  788. //--------------------------------------------------------------------------------------------
  789. unsigned short terp_dir(unsigned short majordir, unsigned short minordir)
  790. {
  791.     // ZZ> This function returns a direction between the major and minor ones, closer
  792.     //     to the major.
  793.     unsigned short temp;
  794.  
  795.     // Align major direction with 0
  796.     minordir-=majordir;
  797.     if(minordir > 32768)
  798.     {
  799.         temp = 65535;
  800.         minordir = (minordir+(temp<<3)-temp)>>3;
  801.         minordir+=majordir;
  802.         return minordir;
  803.     }
  804.     temp = 0;
  805.     minordir = (minordir+(temp<<3)-temp)>>3;
  806.     minordir+=majordir;
  807.     return minordir;
  808. }
  809.  
  810. //--------------------------------------------------------------------------------------------
  811. unsigned short terp_dir_fast(unsigned short majordir, unsigned short minordir)
  812. {
  813.     // ZZ> This function returns a direction between the major and minor ones, closer
  814.     //     to the major, but not by much.  Makes turning faster.
  815.     unsigned short temp;
  816.  
  817.     // Align major direction with 0
  818.     minordir-=majordir;
  819.     if(minordir > 32768)
  820.     {
  821.         temp = 65535;
  822.         minordir = (minordir+(temp<<1)-temp)>>1;
  823.         minordir+=majordir;
  824.         return minordir;
  825.     }
  826.     temp = 0;
  827.     minordir = (minordir+(temp<<1)-temp)>>1;
  828.     minordir+=majordir;
  829.     return minordir;
  830. }
  831.  
  832. //--------------------------------------------------------------------------------------------
  833. void spawn_bump_particles(unsigned short character, unsigned short particle)
  834. {
  835.     // ZZ> This function is for catching characters on fire and such
  836.     int cnt;
  837.     signed short x, y, z;
  838.     int distance, bestdistance;
  839.     unsigned short frame;
  840.     unsigned short facing, bestvertex;
  841.     unsigned short amount;
  842.     unsigned short pip;
  843.     unsigned short vertices;
  844.     unsigned short direction, left, right, model;
  845.     float fsin, fcos;
  846.  
  847.  
  848.     pip = prtpip[particle];
  849.     amount = pipbumpspawnamount[pip];
  850.  
  851.  
  852.     if(amount != 0 || pipspawnenchant[pip])
  853.     {
  854.         // Only damage if hitting from proper direction
  855.         model = chrmodel[character];
  856.         vertices = madvertices[model];
  857.         direction = (atan2(prtyvel[particle], prtxvel[particle])+PI)*65535/(2*PI);
  858.         direction = chrturnleftright[character]-direction+32768;
  859.         if(madframefx[chrframe[character]]&MADFXINVICTUS)
  860.         {
  861.             // I Frame
  862.             if(pipdamfx[pip]&DAMFXBLOC)
  863.             {
  864.                 left = 65535;
  865.                 right = 0;
  866.             }
  867.             else
  868.             {
  869.                 direction -= capiframefacing[model];
  870.                 left = (~capiframeangle[model]);
  871.                 right = capiframeangle[model];
  872.             }
  873.         }
  874.         else
  875.         {
  876.             // N Frame
  877.             direction -= capnframefacing[model];
  878.             left = (~capnframeangle[model]);
  879.             right = capnframeangle[model];
  880.         }
  881.         // Check that direction
  882.         if(direction <= left && direction >= right)
  883.         {
  884.             // Spawn new enchantments
  885.             if(pipspawnenchant[pip])
  886.             {
  887.                 spawn_enchant(prtchr[particle], character, MAXCHR, MAXENCHANT, prtmodel[particle]);
  888.             }
  889.             // Spawn particles
  890.             if(amount != 0 && capresistbumpspawn[chrmodel[character]]==FALSE && chrinvictus[character]==FALSE && vertices != 0 && (chrdamagemodifier[character][prtdamagetype[particle]]&DAMAGESHIFT)<3)
  891.             {
  892.                 if(amount == 1)
  893.                 {
  894.                     // A single particle ( arrow? ) has been stuck in the character...
  895.                     // Find best vertex to attach to
  896.                     bestvertex = 0;
  897.                     bestdistance = 9999999;
  898.                     z = -chrzpos[character] + prtzpos[particle] + RAISE;
  899.                     facing = prtfacing[particle]-chrturnleftright[character]-16384;
  900.                     facing = facing>>2;
  901.                     fsin = turntosin[facing];
  902.                     fcos = turntosin[(facing+4096)&16383];
  903.                     y = 8192;
  904.                     x = -y*fsin;
  905.                     y = y*fcos;
  906.                     z = z<<10;///chrscale[character];
  907.                     frame = madframestart[chrmodel[character]];
  908.                     cnt = 0;
  909.                     while(cnt < vertices)
  910.                     {
  911.                         distance = ABS(x-madvrtx[frame][vertices-cnt-1])+ABS(y-madvrty[frame][vertices-cnt-1])+(ABS(z-madvrtz[frame][vertices-cnt-1]));
  912.                         if(distance < bestdistance)
  913.                         {
  914.                             bestdistance = distance;
  915.                             bestvertex = cnt;
  916.                         }
  917.                         cnt++;
  918.                     }
  919.                     spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], 0, prtmodel[particle], pipbumpspawnpip[pip],
  920.                                        character, bestvertex+1, prtteam[particle], prtchr[particle], cnt, character);
  921.                 }
  922.                 else
  923.                 {
  924.                     amount = (amount*vertices)>>5;  // Correct amount for size of character
  925.                     cnt = 0;
  926.                     while(cnt < amount)
  927.                     {
  928.                         spawn_one_particle(chrxpos[character], chrypos[character], chrzpos[character], 0, prtmodel[particle], pipbumpspawnpip[pip],
  929.                                            character, rand()%vertices, prtteam[particle], prtchr[particle], cnt, character);
  930.                         cnt++;
  931.                     }
  932.                 }
  933.             }
  934.         }
  935.     }
  936. }
  937.  
  938. //--------------------------------------------------------------------------------------------
  939. int prt_is_over_water(int cnt)
  940. {
  941.     // This function returns TRUE if the particle is over a water tile
  942.     int x, y, fan;
  943.  
  944.  
  945.     if(cnt < MAXPRT)
  946.     {
  947.         if(prtxpos[cnt] > 0 && prtxpos[cnt] < meshedgex && prtypos[cnt] > 0 && prtypos[cnt] < meshedgey)
  948.         {
  949.             x = prtxpos[cnt];
  950.             y = prtypos[cnt];
  951.             x = x>>7;
  952.             y = y>>7;
  953.             fan = meshfanstart[y]+x;
  954.             if(meshfx[fan]&MESHFXWATER)  return TRUE;
  955.         }
  956.     }
  957.     return FALSE;
  958. }
  959.  
  960. //--------------------------------------------------------------------------------------------
  961. void do_weather_spawn()
  962. {
  963.     // ZZ> This function drops snowflakes or rain or whatever, also swings the camera
  964.     int particle, cnt;
  965.     float x, y, z;
  966.     unsigned char foundone;
  967.  
  968.  
  969.     if(weathertime>0)
  970.     {
  971.         weathertime--;
  972.         if(weathertime==0)
  973.         {
  974.             weathertime=weathertimereset;
  975.  
  976.  
  977.             // Find a valid player
  978.             foundone = FALSE;
  979.             cnt = 0;
  980.             while(cnt < MAXPLAYER)
  981.             {
  982.                 weatherplayer = (weatherplayer+1)&(MAXPLAYER-1);
  983.                 if(plavalid[weatherplayer])
  984.                 {
  985.                     foundone = TRUE;
  986.                     cnt = MAXPLAYER;
  987.                 }
  988.                 cnt++;
  989.             }
  990.  
  991.  
  992.             // Did we find one?
  993.             if(foundone)
  994.             {
  995.                 // Yes, but is the character valid?
  996.                 cnt = plaindex[weatherplayer];
  997.                 if(chron[cnt] && chrinpack[cnt]==FALSE)
  998.                 {
  999.                     // Yes, so spawn over that character
  1000.                     x = chrxpos[cnt];
  1001.                     y = chrypos[cnt];
  1002.                     z = chrzpos[cnt];
  1003.                     particle = spawn_one_particle(x, y, z, 0, MAXMODEL, WEATHER4, MAXCHR, SPAWNLAST, NULLTEAM, MAXCHR, 0, MAXCHR);
  1004.                     if(weatheroverwater && particle != MAXPRT)
  1005.                     {
  1006.                         if(!prt_is_over_water(particle))
  1007.                         {
  1008.                             free_one_particle_no_sound(particle);
  1009.                         }
  1010.                     }
  1011.  
  1012.                 }
  1013.             }
  1014.         }
  1015.     }
  1016.     camswing = (camswing + camswingrate) & 16383;
  1017. }
  1018.  
  1019. //--------------------------------------------------------------------------------------------
  1020. int load_one_particle(char *szLoadName, int object, int pip)
  1021. {
  1022.     // ZZ> This function loads a particle template, returning FALSE if the file wasn't
  1023.     //     found
  1024.     FILE* fileread;
  1025.     int test, idsz;
  1026.     int iTmp;
  1027.     float fTmp;
  1028.     char cTmp;
  1029.  
  1030.  
  1031.     fileread = fopen(FILENAME(szLoadName), "r");
  1032.     if(fileread)
  1033.     {
  1034.         // General data
  1035.         globalname = szLoadName;
  1036.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1037.           pipforce[numpip] = FALSE;
  1038.           if(cTmp=='T' || cTmp=='t')  pipforce[numpip] = TRUE;
  1039.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1040.           if(cTmp=='L' || cTmp=='l')  piptype[numpip] = PRTLIGHTSPRITE;
  1041.           if(cTmp=='S' || cTmp=='s')  piptype[numpip] = PRTSOLIDSPRITE;
  1042.           if(cTmp=='T' || cTmp=='t')  piptype[numpip] = PRTALPHASPRITE;
  1043.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipimagebase[numpip]=iTmp;
  1044.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipnumframes[numpip] = iTmp;
  1045.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipimageadd[numpip] = iTmp;
  1046.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipimageaddrand[numpip] = iTmp;
  1047.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); piprotatebase[numpip] = iTmp;
  1048.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); piprotaterand[numpip] = iTmp;
  1049.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); piprotateadd[numpip] = iTmp;
  1050.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipsizebase[numpip] = iTmp;
  1051.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipsizeadd[numpip] = iTmp;
  1052.         goto_colon(fileread);  fscanf(fileread, "%f", &fTmp); pipspdlimit[numpip] = fTmp;
  1053.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipfacingadd[numpip] = iTmp;
  1054.  
  1055.  
  1056.         // Ending conditions
  1057.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1058.           pipendwater[numpip] = TRUE;
  1059.           if(cTmp=='F' || cTmp=='f')  pipendwater[numpip] = FALSE;
  1060.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1061.           pipendbump[numpip] = TRUE;
  1062.           if(cTmp=='F' || cTmp=='f')  pipendbump[numpip] = FALSE;
  1063.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1064.           pipendground[numpip] = TRUE;
  1065.           if(cTmp=='F' || cTmp=='f')  pipendground[numpip] = FALSE;
  1066.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1067.           pipendlastframe[numpip] = TRUE;
  1068.           if(cTmp=='F' || cTmp=='f')  pipendlastframe[numpip] = FALSE;
  1069.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); piptime[numpip] = iTmp;
  1070.  
  1071.  
  1072.         // Collision data
  1073.         goto_colon(fileread);  fscanf(fileread, "%f", &fTmp); pipdampen[numpip] = fTmp;
  1074.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipbumpmoney[numpip] = iTmp;
  1075.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipbumpsize[numpip] = iTmp;
  1076.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipbumpheight[numpip] = iTmp;
  1077.         goto_colon(fileread);  read_pair(fileread);
  1078.             pipdamagebase[numpip] = pairbase;
  1079.             pipdamagerand[numpip] = pairrand;
  1080.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1081.             if(cTmp=='S' || cTmp=='s') pipdamagetype[numpip] = DAMAGESLASH;
  1082.             if(cTmp=='C' || cTmp=='c') pipdamagetype[numpip] = DAMAGECRUSH;
  1083.             if(cTmp=='P' || cTmp=='p') pipdamagetype[numpip] = DAMAGEPOKE;
  1084.             if(cTmp=='H' || cTmp=='h') pipdamagetype[numpip] = DAMAGEHOLY;
  1085.             if(cTmp=='E' || cTmp=='e') pipdamagetype[numpip] = DAMAGEEVIL;
  1086.             if(cTmp=='F' || cTmp=='f') pipdamagetype[numpip] = DAMAGEFIRE;
  1087.             if(cTmp=='I' || cTmp=='i') pipdamagetype[numpip] = DAMAGEICE;
  1088.             if(cTmp=='Z' || cTmp=='z') pipdamagetype[numpip] = DAMAGEZAP;
  1089.  
  1090.  
  1091.         // Lighting data
  1092.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1093.             pipdynalightmode[numpip] = DYNAOFF;
  1094.             if(cTmp=='T' || cTmp=='t') pipdynalightmode[numpip] = DYNAON;
  1095.             if(cTmp=='L' || cTmp=='l') pipdynalightmode[numpip] = DYNALOCAL;
  1096.         goto_colon(fileread);  fscanf(fileread, "%f", &fTmp); pipdynalevel[numpip] = fTmp;
  1097.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipdynafalloff[numpip] = iTmp;
  1098.         if(pipdynafalloff[numpip] > MAXFALLOFF && rtscontrol)  pipdynafalloff[numpip] = MAXFALLOFF;
  1099.  
  1100.  
  1101.  
  1102.         // Initial spawning of this particle
  1103.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipfacingbase[numpip] = iTmp;
  1104.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipfacingrand[numpip] = iTmp;
  1105.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipxyspacingbase[numpip] = iTmp;
  1106.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipxyspacingrand[numpip] = iTmp;
  1107.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipzspacingbase[numpip] = iTmp;
  1108.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipzspacingrand[numpip] = iTmp;
  1109.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipxyvelbase[numpip] = iTmp;
  1110.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipxyvelrand[numpip] = iTmp;
  1111.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipzvelbase[numpip] = iTmp;
  1112.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipzvelrand[numpip] = iTmp;
  1113.  
  1114.  
  1115.         // Continuous spawning of other particles
  1116.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipcontspawntime[numpip] = iTmp;
  1117.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipcontspawnamount[numpip] = iTmp;
  1118.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipcontspawnfacingadd[numpip] = iTmp;
  1119.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipcontspawnpip[numpip] = iTmp;
  1120.  
  1121.  
  1122.         // End spawning of other particles
  1123.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipendspawnamount[numpip] = iTmp;
  1124.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipendspawnfacingadd[numpip] = iTmp;
  1125.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipendspawnpip[numpip] = iTmp;
  1126.  
  1127.  
  1128.         // Bump spawning of attached particles
  1129.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipbumpspawnamount[numpip] = iTmp;
  1130.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipbumpspawnpip[numpip] = iTmp;
  1131.  
  1132.  
  1133.         // Random stuff  !!!BAD!!! Not complete
  1134.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipdazetime[numpip] = iTmp;
  1135.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); pipgrogtime[numpip] = iTmp;
  1136.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1137.             pipspawnenchant[numpip] = FALSE;
  1138.             if(cTmp=='T' || cTmp=='t') pipspawnenchant[numpip] = TRUE;
  1139.         goto_colon(fileread);  // !!Cause roll
  1140.         goto_colon(fileread);  // !!Cause pancake
  1141.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1142.             pipneedtarget[numpip] = FALSE;
  1143.             if(cTmp=='T' || cTmp=='t') pipneedtarget[numpip] = TRUE;
  1144.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1145.             piptargetcaster[numpip] = FALSE;
  1146.             if(cTmp=='T' || cTmp=='t') piptargetcaster[numpip] = TRUE;
  1147.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1148.             pipstartontarget[numpip] = FALSE;
  1149.             if(cTmp=='T' || cTmp=='t') pipstartontarget[numpip] = TRUE;
  1150.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1151.             piponlydamagefriendly[numpip] = FALSE;
  1152.             if(cTmp=='T' || cTmp=='t') piponlydamagefriendly[numpip] = TRUE;
  1153.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp);
  1154.             if(iTmp < -1) iTmp = -1;
  1155.             if(iTmp > MAXWAVE-1) iTmp = MAXWAVE-1;
  1156.             pipsoundspawn[numpip] = iTmp;
  1157.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp);
  1158.             if(iTmp < -1) iTmp = -1;
  1159.             if(iTmp > MAXWAVE-1) iTmp = MAXWAVE-1;
  1160.             pipsoundend[numpip] = iTmp;
  1161.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1162.             pipfriendlyfire[numpip] = FALSE;
  1163.             if(cTmp=='T' || cTmp=='t') pipfriendlyfire[numpip] = TRUE;
  1164.         goto_colon(fileread);  // !!Hate group only
  1165.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1166.             pipnewtargetonspawn[numpip] = FALSE;
  1167.             if(cTmp=='T' || cTmp=='t') pipnewtargetonspawn[numpip] = TRUE;
  1168.         goto_colon(fileread);  fscanf(fileread, "%d", &iTmp); piptargetangle[numpip] = iTmp>>1;
  1169.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1170.             piphoming[numpip] = FALSE;
  1171.             if(cTmp=='T' || cTmp=='t') piphoming[numpip] = TRUE;
  1172.         goto_colon(fileread);  fscanf(fileread, "%f", &fTmp); piphomingfriction[numpip] = fTmp;
  1173.         goto_colon(fileread);  fscanf(fileread, "%f", &fTmp); piphomingaccel[numpip] = fTmp;
  1174.         goto_colon(fileread);  cTmp = get_first_letter(fileread);
  1175.             piprotatetoface[numpip] = FALSE;
  1176.             if(cTmp=='T' || cTmp=='t') piprotatetoface[numpip] = TRUE;
  1177.  
  1178.         // Clear expansions...
  1179.         pipzaimspd[numpip] = 0;
  1180.         pipsoundfloor[numpip] = -1;
  1181.         pipsoundwall[numpip] = -1;
  1182.         pipendwall[numpip] = pipendground[numpip];
  1183.         pipdamfx[numpip] = DAMFXTURN;
  1184.         if(piphoming[numpip])  pipdamfx[numpip] = DAMFXNONE;
  1185.         pipallowpush[numpip] = TRUE;
  1186.         pipdynalightfalloffadd[numpip] = 0;
  1187.         pipdynalightleveladd[numpip] = 0;
  1188.         // Read expansions
  1189.         while(goto_colon_yesno(fileread))
  1190.         {
  1191.             idsz = get_idsz(fileread);
  1192.             fscanf(fileread, "%c%d", &cTmp, &iTmp);
  1193.             test = ('T'-'A'<<15)|('U'-'A'<<10)|('R'-'A'<<5)|('N'-'A');  // [TURN]
  1194.             if(idsz == test)  pipdamfx[numpip] = DAMFXNONE;
  1195.             test = ('Z'-'A'<<15)|('S'-'A'<<10)|('P'-'A'<<5)|('D'-'A');  // [ZSPD]
  1196.             if(idsz == test)  pipzaimspd[numpip] = iTmp;
  1197.             test = ('F'-'A'<<15)|('S'-'A'<<10)|('N'-'A'<<5)|('D'-'A');  // [FSND]
  1198.             if(idsz == test)  pipsoundfloor[numpip] = iTmp;
  1199.             test = ('W'-'A'<<15)|('S'-'A'<<10)|('N'-'A'<<5)|('D'-'A');  // [WSND]
  1200.             if(idsz == test)  pipsoundwall[numpip] = iTmp;
  1201.             test = ('W'-'A'<<15)|('E'-'A'<<10)|('N'-'A'<<5)|('D'-'A');  // [WEND]
  1202.             if(idsz == test)  pipendwall[numpip] = iTmp;
  1203.             test = ('A'-'A'<<15)|('R'-'A'<<10)|('M'-'A'<<5)|('O'-'A');  // [ARMO]
  1204.             if(idsz == test)  pipdamfx[numpip] |= DAMFXARMO;
  1205.             test = ('B'-'A'<<15)|('L'-'A'<<10)|('O'-'A'<<5)|('C'-'A');  // [BLOC]
  1206.             if(idsz == test)  pipdamfx[numpip] |= DAMFXBLOC;
  1207.             test = ('A'-'A'<<15)|('R'-'A'<<10)|('R'-'A'<<5)|('O'-'A');  // [ARRO]
  1208.             if(idsz == test)  pipdamfx[numpip] |= DAMFXARRO;
  1209.             test = ('T'-'A'<<15)|('I'-'A'<<10)|('M'-'A'<<5)|('E'-'A');  // [TIME]
  1210.             if(idsz == test)  pipdamfx[numpip] |= DAMFXTIME;
  1211.             test = ('P'-'A'<<15)|('U'-'A'<<10)|('S'-'A'<<5)|('H'-'A');  // [PUSH]
  1212.             if(idsz == test)  pipallowpush[numpip] = iTmp;
  1213.             test = ('D'-'A'<<15)|('L'-'A'<<10)|('E'-'A'<<5)|('V'-'A');  // [DLEV]
  1214.             if(idsz == test)  pipdynalightleveladd[numpip] = iTmp/1000.0;
  1215.             test = ('D'-'A'<<15)|('R'-'A'<<10)|('A'-'A'<<5)|('D'-'A');  // [DRAD]
  1216.             if(idsz == test)  pipdynalightfalloffadd[numpip] = iTmp/1000.0;
  1217.         }
  1218.  
  1219.  
  1220.         // Make sure it's referenced properly
  1221.         madprtpip[object][pip]=numpip;
  1222.         numpip++;
  1223.  
  1224.  
  1225.         fclose(fileread);
  1226.         return TRUE;
  1227.     }
  1228.     return FALSE;
  1229. }
  1230.  
  1231. //--------------------------------------------------------------------------------------------
  1232. void reset_particles(char* modname)
  1233. {
  1234.     // ZZ> This resets all particle data and reads in the coin and water particles
  1235.     int cnt, object;
  1236.     char newloadname[256];
  1237.  
  1238.     // PORT: make_newloadname should work
  1239.     // PORT: load_one_particle should work too
  1240.  
  1241.     // Load in the standard particles ( the coins )
  1242.     numpip = 0;
  1243.     make_newloadname(modname, "gamedat/1money.txt", newloadname);
  1244.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1245.     {
  1246.         general_error(0, 0, "1MONEY.TXT NOT FOUND");
  1247.     }
  1248.     make_newloadname(modname, "gamedat/5money.txt", newloadname);
  1249.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1250.     {
  1251.         general_error(0, 0, "5MONEY.TXT NOT FOUND");
  1252.     }
  1253.     make_newloadname(modname, "gamedat/25money.txt", newloadname);
  1254.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1255.     {
  1256.         general_error(0, 0, "25MONEY.TXT NOT FOUND");
  1257.     }
  1258.     make_newloadname(modname, "gamedat/100money.txt", newloadname);
  1259.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1260.     {
  1261.         general_error(0, 0, "100MONEY.TXT NOT FOUND");
  1262.     }
  1263.     make_newloadname(modname, "gamedat/weather4.txt", newloadname);
  1264.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1265.     {
  1266.         general_error(0, 0, "WEATHER4.TXT NOT FOUND");
  1267.     }
  1268.     make_newloadname(modname, "gamedat/weather5.txt", newloadname);
  1269.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1270.     {
  1271.         general_error(0, 0, "WEATHER5.TXT NOT FOUND");
  1272.     }
  1273.     make_newloadname(modname, "gamedat/splash.txt", newloadname);
  1274.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1275.     {
  1276.         general_error(0, 0, "SPLASH.TXT NOT FOUND");
  1277.     }
  1278.     make_newloadname(modname, "gamedat/ripple.txt", newloadname);
  1279.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1280.     {
  1281.         general_error(0, 0, "RIPPLE.TXT NOT FOUND");
  1282.     }
  1283.     make_newloadname(modname, "gamedat/defend.txt", newloadname);
  1284.     if(load_one_particle(newloadname, 0, 0)==FALSE)
  1285.     {
  1286.         general_error(0, 0, "DEFEND.TXT NOT FOUND");
  1287.     }
  1288.  
  1289.     // Now clear out the local pips
  1290.     object = 0;
  1291.     while(object < MAXMODEL)
  1292.     {
  1293.         cnt = 0;
  1294.         while(cnt < MAXPRTPIPPEROBJECT)
  1295.         {
  1296.             madprtpip[object][cnt] = 0;
  1297.             cnt++;
  1298.         }
  1299.         object++;
  1300.     }
  1301. }
  1302.  
  1303.