Advertisement
ZoriaRPG

GHost eweapons.zh replacement

Jan 23rd, 2017
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.34 KB | None | 0 0
  1. // ghost.zh
  2. // Version 2.8.0
  3.  
  4. // Arguments to SetEWeaponMovement()
  5. const int EWM_SINE_WAVE         = 1;
  6. const int EWM_HOMING            = 3;
  7. const int EWM_HOMING_REAIM      = 4;
  8. const int EWM_RANDOM            = 5;
  9. const int EWM_RANDOM_REAIM      = 6;
  10. const int EWM_VEER              = 7;
  11. const int EWM_THROW             = 15;
  12. const int EWM_FALL              = 19;
  13. const int EWM_DRIFT             = 20;
  14. const int EWM_DRIFT_WAIT        = 28;
  15.  
  16. // Flags used by certain EWeapon movement types
  17. const int EWMF_DIE = 01b;
  18. const int EWMF_BOUNCE = 10b;
  19.  
  20. // Arguments to SetEWeaponLifespan()
  21. const int EWL_TIMER        = 1;
  22. const int EWL_NEAR_LINK    = 2;
  23. const int EWL_SLOW_TO_HALT = 3;
  24.  
  25. // Arguments to SetEWeaponDeathEffect()
  26. const int EWD_VANISH             = 1;
  27. const int EWD_AIM_AT_LINK        = 2;
  28. const int EWD_EXPLODE            = 3;
  29. const int EWD_SBOMB_EXPLODE      = 4;
  30. const int EWD_4_FIREBALLS_HV     = 5;
  31. const int EWD_4_FIREBALLS_DIAG   = 6;
  32. const int EWD_4_FIREBALLS_RANDOM = 7;
  33. const int EWD_8_FIREBALLS        = 8;
  34. const int EWD_4_FIRES_HV         = 9;
  35. const int EWD_4_FIRES_DIAG       = 10;
  36. const int EWD_4_FIRES_RANDOM     = 11;
  37. const int EWD_8_FIRES            = 12;
  38. const int EWD_SPAWN_NPC          = 13;
  39. const int EWD_FIRE               = 14;
  40. const int EWD_RUN_SCRIPT         = 15;
  41.  
  42. // Prototype-based version
  43. const int EWD_EVEN   = 1;
  44. const int EWD_RANDOM = 2;
  45. const int EWD_AIMED  = 3;
  46.  
  47. // EWeapon flags
  48. const int EWF_UNBLOCKABLE          = 00000000001b;
  49. const int EWF_ROTATE               = 00000000010b;
  50. const int EWF_ROTATE_360           = 00000000100b;
  51. const int EWF_SHADOW               = 00000001000b;
  52. const int EWF_FLICKER              = 00000010000b;
  53. const int EWF_NO_COLLISION         = 00000100000b;
  54. const int EWF_FAKE_Z               = 00001000000b;
  55.  
  56. // Internal EWeapon flags
  57. const int __EWFI_DEAD              = 00010000000b;
  58. const int __EWFI_DUMMY             = 00100000000b;
  59. const int __EWFI_IS_GHZH_EWPN      = 01000000000b;
  60. const int __EWFI_DUMMY_CHECK       = 01100000000b;
  61. const int __EWFI_DEATH_EFFECT_DONE = 10000000000b;
  62. const int __EWFI_INTERNAL          = 11110000000b;
  63.  
  64.  
  65.  
  66. // Fire an eweapon
  67. eweapon FireEWeapon(int weaponID, int x, int y, float angle, int step, int damage, int sprite, int sound, int flags)
  68. {
  69.     if(sprite<0)
  70.         sprite=GetDefaultEWeaponSprite(weaponID);
  71.    
  72.     if(sound<0)
  73.         sound=GetDefaultEWeaponSound(weaponID);
  74.    
  75.     eweapon wpn=Screen->CreateEWeapon(weaponID);
  76.     wpn->X=x;
  77.     wpn->Y=y;
  78.     wpn->Step=step;
  79.     wpn->Damage=damage;
  80.     wpn->Angular=true;
  81.     wpn->Angle=angle;
  82.    
  83.     if(sprite>=0)
  84.         wpn->UseSprite(sprite);
  85.    
  86.     wpn->Misc[__EWI_FLAGS]=flags|__EWFI_IS_GHZH_EWPN;
  87.    
  88.     SetEWeaponDir(wpn); // After flags so unblockability is detected
  89.    
  90.     if((flags&EWF_NO_COLLISION)!=0)
  91.         wpn->CollDetection=false;
  92.    
  93.     if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE)!=0)
  94.         SetEWeaponRotation(wpn);
  95.    
  96.     Game->PlaySound(sound);
  97.    
  98.     return wpn;
  99. }
  100.  
  101.  
  102. // Fire an eweapon aimed based on Link's position
  103. eweapon FireAimedEWeapon(int weaponID, int x, int y, float angle, int step, int damage, int sprite, int sound, int flags)
  104. {
  105.     return FireEWeapon(weaponID, x, y, ArcTan(Link->X-x, Link->Y-y)+angle, step, damage, sprite, sound, flags);
  106. }
  107.  
  108.  
  109. // Fire a non-angular eweapon
  110. eweapon FireNonAngularEWeapon(int weaponID, int x, int y, int dir, int step, int damage, int sprite, int sound, int flags)
  111. {
  112.     if(sprite<0)
  113.         sprite=GetDefaultEWeaponSprite(weaponID);
  114.    
  115.     if(sound<0)
  116.         sound=GetDefaultEWeaponSound(weaponID);
  117.    
  118.     eweapon wpn=Screen->CreateEWeapon(weaponID);
  119.     wpn->X=x;
  120.     wpn->Y=y;
  121.     wpn->Step=step;
  122.     wpn->Damage=damage;
  123.     wpn->Angular=false;
  124.    
  125.     if((flags&EWF_UNBLOCKABLE)!=0)
  126.         wpn->Dir=__UnblockableDir(dir);
  127.     else
  128.         wpn->Dir=dir;
  129.        
  130.     if(sprite>=0)
  131.         wpn->UseSprite(sprite);
  132.  
  133.     if((flags&EWF_NO_COLLISION)!=0)
  134.         wpn->CollDetection=false;
  135.  
  136.     if((flags&EWF_ROTATE)!=0)
  137.         SetEWeaponRotation(wpn);
  138.    
  139.     wpn->Misc[__EWI_FLAGS]=flags|__EWFI_IS_GHZH_EWPN;
  140.    
  141.     Game->PlaySound(sound);
  142.     return wpn;
  143. }
  144.  
  145.  
  146. // Fire an eweapon larger than 1x1
  147. eweapon FireBigEWeapon(int weaponID, int x, int y, float angle, int step, int damage, int sprite, int sound, int flags, int width, int height)
  148. {
  149.     eweapon wpn=FireEWeapon(weaponID, x, y, angle, step, damage, sprite, sound, flags);
  150.     wpn->Extend=3;
  151.     wpn->TileWidth=width;
  152.     wpn->TileHeight=height;
  153.     wpn->HitWidth=16*width;
  154.     wpn->HitHeight=16*height;
  155.     return wpn;
  156. }
  157.  
  158.  
  159. // Fire an eweapon larger than 1x1 aimed based on Link's position
  160. eweapon FireBigAimedEWeapon(int weaponID, int x, int y, float angle, int step, int damage, int sprite, int sound, int flags, int width, int height)
  161. {
  162.     eweapon wpn=FireEWeapon(weaponID, x, y, ArcTan(Link->X-x, Link->Y-y)+angle, step, damage, sprite, sound, flags);
  163.     wpn->Extend=3;
  164.     wpn->TileWidth=width;
  165.     wpn->TileHeight=height;
  166.     wpn->HitWidth=16*width;
  167.     wpn->HitHeight=16*height;
  168.     return wpn;
  169. }
  170.  
  171.  
  172. // Fire a non-angular eweapon larger than 1x1
  173. eweapon FireBigNonAngularEWeapon(int weaponID, int x, int y, int dir, int step, int damage, int sprite, int sound, int flags, int width, int height)
  174. {
  175.     eweapon wpn=FireNonAngularEWeapon(weaponID, x, y, dir, step, damage, sprite, sound, flags);
  176.     wpn->Extend=3;
  177.     wpn->TileWidth=width;
  178.     wpn->TileHeight=height;
  179.     wpn->HitWidth=16*width;
  180.     wpn->HitHeight=16*height;
  181.     return wpn;
  182. }
  183.  
  184. // Create a dummy eweapon to use as a prototype
  185. eweapon CreateDummyEWeapon(int weaponID, int step, int damage, int sprite, int sound, int flags)
  186. {
  187.     eweapon wpn=Screen->CreateEWeapon(weaponID);
  188.     eweapon checkWpn;
  189.     int minID;
  190.     wpn->Step=0;
  191.     wpn->Damage=damage;
  192.     wpn->Misc[__EWI_DUMMY_STEP]=step;
  193.     wpn->Misc[__EWI_DUMMY_SOUND]=sound;
  194.     wpn->Misc[__EWI_DUMMY_SPRITE]=sprite;
  195.    
  196.     // Give the weapon a unique ID number so it can be found later
  197.     for(int i=Screen->NumEWeapons(); i>0; i--)
  198.     {
  199.         checkWpn=Screen->LoadEWeapon(i);
  200.         if((checkWpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY_CHECK)==__EWFI_DUMMY_CHECK)
  201.             continue;
  202.         minID=Min(minID, checkWpn->Misc[__EWI_ID]);
  203.     }
  204.     wpn->Misc[__EWI_ID]=minID-1;
  205.    
  206.     wpn->Misc[__EWI_FLAGS]=flags|__EWFI_IS_GHZH_EWPN|__EWFI_DUMMY;
  207.    
  208.     wpn->CollDetection=false;
  209.     wpn->DrawXOffset=32768;
  210.    
  211.     // Move it to make sure it's not deleted
  212.     wpn->X=32;
  213.     wpn->Y=32;
  214.    
  215.     return wpn;
  216. }
  217.  
  218.  
  219. // Create a dummy eweapon larger than 1x1
  220. eweapon CreateBigDummyEWeapon(int weaponID, int step, int damage, int sprite, int sound, int flags, int width, int height)
  221. {
  222.     eweapon wpn=CreateDummyEWeapon(weaponID, step, damage, sprite, sound, flags);
  223.     wpn->Extend=3;
  224.  
  225.     wpn->TileWidth=width;
  226.     wpn->TileHeight=height;
  227.     // No point setting the hitbox here
  228.     return wpn;
  229. }
  230.  
  231.  
  232. // Set an eweapon's movement type
  233. void SetEWeaponMovement(eweapon wpn, int type, int arg, int arg2)
  234. {
  235.     // Dummies normally use __EWI_XPOS and __EWI_YPOS for other purposes,
  236.     // so don't overwrite them
  237.     if((wpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY)==0)
  238.     {
  239.         wpn->Misc[__EWI_XPOS]=wpn->X;
  240.         wpn->Misc[__EWI_YPOS]=wpn->Y;
  241.     }
  242.     wpn->Misc[__EWI_WORK]=0;
  243.     wpn->Misc[__EWI_MOVEMENT]=type;
  244.     wpn->Misc[__EWI_MOVEMENT_ARG]=arg;
  245.     wpn->Misc[__EWI_MOVEMENT_ARG_2]=arg2;
  246.     wpn->Misc[__EWI_FLAGS]|=__EWFI_IS_GHZH_EWPN;
  247.  
  248.     if(type==EWM_HOMING_REAIM || type==EWM_RANDOM_REAIM)
  249.     {
  250.         // Dummy? Use its stored step instead of its real step
  251.         if((wpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY)!=0)
  252.             wpn->Misc[__EWI_WORK_2]=wpn->Misc[__EWI_DUMMY_STEP];
  253.         else
  254.             wpn->Misc[__EWI_WORK_2]=wpn->Step;
  255.     }
  256.     else if(type==EWM_THROW)
  257.     {
  258.         wpn->Misc[__EWI_WORK_2]=wpn->Z;
  259.  
  260.         // Necessary upward velocity to reach Link for thrown weapons
  261.         if(arg<=0)
  262.         {
  263.             // Special case for dummy weapons
  264.             if((wpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY)!=0)
  265.                 wpn->Misc[__EWI_MOVEMENT_ARG]=-1;
  266.  
  267.             // A rough approximation, but close enough
  268.             else
  269.             {
  270.                 float time=Distance(wpn->X, wpn->Y, Link->X, Link->Y)/(wpn->Step/100);
  271.                 wpn->Misc[__EWI_MOVEMENT_ARG]=GH_GRAVITY*time/2;
  272.             }
  273.         }
  274.     }
  275.     else if(type==EWM_FALL)
  276.     {
  277.         wpn->Z=arg;
  278.         wpn->Misc[__EWI_WORK_2]=arg;
  279.         wpn->Misc[__EWI_WORK]=GH_GRAVITY;
  280.     }
  281. }
  282.  
  283.  
  284. // Set an eweapon's lifespan
  285. void SetEWeaponLifespan(eweapon wpn, int type, int arg)
  286. {
  287.     wpn->Misc[__EWI_LIFESPAN]=type;
  288.     wpn->Misc[__EWI_LIFESPAN_ARG]=arg;
  289.     wpn->Misc[__EWI_FLAGS]|=__EWFI_IS_GHZH_EWPN;
  290. }
  291.  
  292.  
  293. // Set an eweapon to use a standard death effect
  294. void SetEWeaponDeathEffect(eweapon wpn, int type, int arg)
  295. {
  296.     // Make sure the script number is valid
  297.     if(type==EWD_RUN_SCRIPT)
  298.     {
  299.         if(arg<1 || arg>511)
  300.             type=EWD_VANISH;
  301.     }
  302.    
  303.     wpn->Misc[__EWI_ON_DEATH]=type;
  304.     wpn->Misc[__EWI_ON_DEATH_ARG]=arg;
  305.     wpn->Misc[__EWI_FLAGS]|=__EWFI_IS_GHZH_EWPN;
  306. }
  307.  
  308.  
  309. // Set an eweapon to spawn more eweapons on death
  310. void SetEWeaponDeathEffect(eweapon wpn, eweapon prototype, int numShots, int spreadType, float angle)
  311. {
  312.     // Combining four variables into two... Ugly, but doable
  313.     wpn->Misc[__EWI_ON_DEATH]=prototype->Misc[__EWI_ID]+(numShots%1000)/10000;
  314.     wpn->Misc[__EWI_ON_DEATH_ARG]=spreadType*100+(WrapAngle(angle)+6.2832);
  315.     wpn->Misc[__EWI_FLAGS]|=__EWFI_IS_GHZH_EWPN;
  316. }
  317.  
  318.  
  319. // Update a weapon's movement, lifespan, and death effects
  320. void UpdateEWeapon(eweapon wpn)
  321. {
  322.     if((__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_SUSPEND)!=0)
  323.         return;
  324.    
  325.     // Needed for EWF_ROTATE_360
  326.     int startX=wpn->X;
  327.     int startY=wpn->Y;
  328.     bool selfPropelled=true;
  329.  
  330.     // Is the weapon still active?
  331.     if((wpn->Misc[__EWI_FLAGS]&__EWFI_DEAD)==0)
  332.     {
  333.         // Start movement updates
  334.         if(wpn->Misc[__EWI_MOVEMENT]!=0)
  335.         {
  336.             // Split in half to reduce checks
  337.             if(wpn->Misc[__EWI_MOVEMENT]<=EWM_RANDOM_REAIM)
  338.             {
  339.                 if(wpn->Misc[__EWI_MOVEMENT]==EWM_SINE_WAVE)
  340.                     __UpdateEWMSineWave(wpn);
  341.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_HOMING)
  342.                     __UpdateEWMHoming(wpn);
  343.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_HOMING_REAIM)
  344.                     __UpdateEWMHomingReaim(wpn);
  345.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_RANDOM)
  346.                     __UpdateEWMRandom(wpn);
  347.                 else // EWM_RANDOM_REAIM
  348.                     __UpdateEWMRandomReaim(wpn);
  349.             }
  350.             else // wpn->Misc[__EWI_MOVEMENT]>EWM_RANDOM_REAIM
  351.             {
  352.                 if(wpn->Misc[__EWI_MOVEMENT]==EWM_VEER)
  353.                 {
  354.                     startX=wpn->Misc[__EWI_XPOS];
  355.                     startY=wpn->Misc[__EWI_YPOS];
  356.                     __UpdateEWMVeer(wpn);
  357.                     selfPropelled=false;
  358.                 }
  359.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_THROW)
  360.                     __UpdateEWMThrow(wpn);
  361.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_FALL)
  362.                     __UpdateEWMFall(wpn);
  363.                 else if(wpn->Misc[__EWI_MOVEMENT]==EWM_DRIFT)
  364.                 {
  365.                     startX=wpn->Misc[__EWI_XPOS];
  366.                     startY=wpn->Misc[__EWI_YPOS];
  367.                     __UpdateEWMDrift(wpn);
  368.                     selfPropelled=false;
  369.                 }
  370.                 else //EWM_DRIFT_WAIT
  371.                 {
  372.                     startX=wpn->Misc[__EWI_XPOS];
  373.                     startY=wpn->Misc[__EWI_YPOS];
  374.                     __UpdateEWMDriftWait(wpn);
  375.                     selfPropelled=false;
  376.                 }
  377.             }
  378.         } // End movement updates
  379.        
  380.        
  381.         // Start lifespan updates
  382.         if(wpn->Misc[__EWI_LIFESPAN]!=0)
  383.         {
  384.             if(wpn->Misc[__EWI_LIFESPAN]==EWL_TIMER)
  385.             {
  386.                 wpn->Misc[__EWI_LIFESPAN_ARG]-=1;
  387.                 if(wpn->Misc[__EWI_LIFESPAN_ARG]<=0)
  388.                     KillEWeapon(wpn);
  389.             }
  390.             else if(wpn->Misc[__EWI_LIFESPAN]==EWL_NEAR_LINK)
  391.             {
  392.                 if( ghostDistXY(wpn, wpn->Misc[__EWI_LIFESPAN_ARG]) )
  393.            
  394.         //Distance(wpn->X, wpn->Y, Link->X, Link->Y)<wpn->Misc[__EWI_LIFESPAN_ARG])
  395.                     KillEWeapon(wpn);
  396.             }
  397.             else if(wpn->Misc[__EWI_LIFESPAN]==EWL_SLOW_TO_HALT)
  398.             {
  399.                 wpn->Step=Max(0, wpn->Step-wpn->Misc[__EWI_LIFESPAN_ARG]);
  400.                 if(wpn->Step<=0)
  401.                     KillEWeapon(wpn);
  402.             }
  403.         } // End lifespan updates
  404.     }
  405.  
  406.     // Start death effects
  407.     else if(wpn->Misc[__EWI_ON_DEATH]!=0 && (wpn->Misc[__EWI_FLAGS]&__EWFI_DEATH_EFFECT_DONE)==0)
  408.     {
  409.         if(wpn->Misc[__EWI_ON_DEATH]<0)
  410.             __DoEWeaponDeathPrototype(wpn);
  411.  
  412.         // Split in half to reduce checks
  413.         else if(wpn->Misc[__EWI_ON_DEATH]<8)
  414.         {
  415.             if(wpn->Misc[__EWI_ON_DEATH]==EWD_VANISH)
  416.                 wpn->DeadState=0;
  417.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_AIM_AT_LINK)
  418.                 __DoEWeaponDeathAimAtLink(wpn);
  419.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_EXPLODE)
  420.                 __DoEWeaponDeathExplode(wpn);
  421.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_SBOMB_EXPLODE)
  422.                 __DoEWeaponDeathSBombExplode(wpn);
  423.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIREBALLS_HV)
  424.                 __DoEWeaponDeath4FireballsHV(wpn);
  425.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIREBALLS_DIAG)
  426.                 __DoEWeaponDeath4FireballsDiag(wpn);
  427.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIREBALLS_RANDOM)
  428.                 __DoEWeaponDeath4FireballsRand(wpn);
  429.         }
  430.         else // wpn->Misc[__EWI_ON_DEATH]>=8
  431.         {
  432.             if(wpn->Misc[__EWI_ON_DEATH]==EWD_8_FIREBALLS)
  433.                 __DoEWeaponDeath8Fireballs(wpn);
  434.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIRES_HV)
  435.                 __DoEWeaponDeath4FiresHV(wpn);
  436.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIRES_DIAG)
  437.                 __DoEWeaponDeath4FiresDiag(wpn);
  438.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_4_FIRES_RANDOM)
  439.                 __DoEWeaponDeath4FiresRand(wpn);
  440.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_8_FIRES)
  441.                 __DoEWeaponDeath8Fires(wpn);
  442.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_SPAWN_NPC)
  443.                 __DoEWeaponDeathSpawnNPC(wpn);
  444.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_FIRE)
  445.                 __DoEWeaponDeathSingleFire(wpn);
  446.             else if(wpn->Misc[__EWI_ON_DEATH]==EWD_RUN_SCRIPT)
  447.                 __DoEWeaponDeathRunScript(wpn);
  448.         }
  449.     } // End death effects
  450.    
  451.     // Start flags
  452.  
  453.     if((wpn->Misc[__EWI_FLAGS]&EWF_SHADOW)!=0)
  454.     {
  455.         if(wpn->Z>0)
  456.             DrawEWeaponShadow(wpn);
  457.     }
  458.    
  459.     if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE_360)!=0)
  460.     {
  461.         wpn->DrawXOffset=1000;
  462.        
  463.         // Don't draw if Link is dead
  464.         if(Link->HP<=0)
  465.             return;
  466.        
  467.         // Flickering? Nothing to do here.
  468.         if((wpn->Misc[__EWI_FLAGS]&EWF_FLICKER)!=0 &&
  469.            (__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_FLICKER)!=0)
  470.             return;
  471.        
  472.         float endX;
  473.         float endY;
  474.         float angle;
  475.        
  476.         // Get the angle first
  477.         if(wpn->Angular)
  478.             angle=RadtoDeg(wpn->Angle);
  479.         else
  480.         {
  481.             int dir=__NormalizeDir(wpn->Dir);
  482.            
  483.             if(dir==DIR_UP)
  484.                 angle=-90;
  485.             else if(dir==DIR_RIGHTUP)
  486.                 angle=-45;
  487.             else if(dir==DIR_RIGHT)
  488.                 angle=0;
  489.             else if(dir==DIR_RIGHTDOWN)
  490.                 angle=45;
  491.             else if(dir==DIR_DOWN)
  492.                 angle=90;
  493.             else if(dir==DIR_LEFTDOWN)
  494.                 angle=135;
  495.             else if(dir==DIR_LEFT)
  496.                 angle=180;
  497.             else // DIR_LEFTUP
  498.                 angle=-135;
  499.         }
  500.        
  501.         if(selfPropelled)
  502.         {
  503.             endX=wpn->X+wpn->Step/100*Cos(angle);
  504.             endY=wpn->Y+wpn->Step/100*Sin(angle);
  505.         }
  506.         else
  507.         {
  508.             endX=wpn->Misc[__EWI_XPOS];
  509.             endY=wpn->Misc[__EWI_YPOS];
  510.         }
  511.        
  512.         // If the weapon's moving, use that angle instead of
  513.         // wpn->Angle or wpn->Dir
  514.         if(!(startX==endX && startY==endY))
  515.             angle=Angle(startX, startY, endX, endY);
  516.        
  517.         int flip;
  518.         if(angle>=0 && angle<180)
  519.             flip=0;
  520.         else
  521.             flip=2;
  522.        
  523.         // Currently, these are always drawn on layer 4.
  524.         // That should probably be changed...
  525.         Screen->DrawTile(4, endX, endY-wpn->Z, wpn->Tile,
  526.           wpn->TileWidth, wpn->TileHeight, wpn->CSet, -1, -1,
  527.           endX, endY-wpn->Z, angle, flip, true, OP_OPAQUE);
  528.     }
  529.     else // EWF_ROTATE_360 isn't set
  530.     {
  531.         if((wpn->Misc[__EWI_FLAGS]&EWF_FLICKER)!=0)
  532.         {
  533.             // Weapons can't be made invisible; use DrawXOffset instead
  534.             if((__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_FLICKER)!=0)
  535.                 wpn->DrawXOffset=1000;
  536.             else
  537.                 wpn->DrawXOffset=0;
  538.         }
  539.        
  540.         if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE)!=0)
  541.             SetEWeaponRotation(wpn);
  542.     }
  543.    
  544.     if((wpn->Misc[__EWI_FLAGS]&EWF_FAKE_Z)!=0 || __GH_FAKE_EWEAPON_Z!=0)
  545.     {
  546.         // For some reason, DrawZOffset is also HitZOffset,
  547.         // so Y offsets also have to be used.
  548.         wpn->DrawZOffset=-wpn->Z;
  549.         wpn->HitYOffset=-wpn->Z;
  550.         wpn->DrawYOffset=-wpn->Z;
  551.     }
  552.    
  553.     // End flags
  554. }
  555.  
  556. // Used when Link is holding up an item. UpdateEWeapon() doesn't run, but
  557. // the appearance-related flags still need handled.
  558. void __UpdateEWeaponVisualFlags(eweapon wpn)
  559. {
  560.     if((wpn->Misc[__EWI_FLAGS]&EWF_SHADOW)!=0)
  561.     {
  562.         if(wpn->Z>0)
  563.             DrawEWeaponShadow(wpn);
  564.     }
  565.    
  566.     if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE_360)!=0)
  567.     {
  568.         wpn->DrawXOffset=1000;
  569.        
  570.         // Flickering? Nothing to do here.
  571.         if((wpn->Misc[__EWI_FLAGS]&EWF_FLICKER)!=0 &&
  572.            (__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_FLICKER)!=0)
  573.             return;
  574.        
  575.         // This works a little differently than in UpdateEWeapon(). Since
  576.         // movement isn't updating normally, the angle or direction are
  577.         // always used. It's not perfect, but it'll have to do.
  578.        
  579.         float angle;
  580.        
  581.         if(wpn->Angular)
  582.             angle=RadtoDeg(wpn->Angle);
  583.         else
  584.         {
  585.             int dir=__NormalizeDir(wpn->Dir);
  586.            
  587.             if(dir==DIR_UP)
  588.                 angle=-90;
  589.             else if(dir==DIR_RIGHTUP)
  590.                 angle=-45;
  591.             else if(dir==DIR_RIGHT)
  592.                 angle=0;
  593.             else if(dir==DIR_RIGHTDOWN)
  594.                 angle=45;
  595.             else if(dir==DIR_DOWN)
  596.                 angle=90;
  597.             else if(dir==DIR_LEFTDOWN)
  598.                 angle=135;
  599.             else if(dir==DIR_LEFT)
  600.                 angle=180;
  601.             else // DIR_LEFTUP
  602.                 angle=-135;
  603.         }
  604.        
  605.         int flip;
  606.         if(angle>=0 && angle<180)
  607.             flip=0;
  608.         else
  609.             flip=2;
  610.        
  611.         // Currently, these are always drawn on layer 4.
  612.         // That should probably be changed...
  613.         Screen->DrawTile(4, wpn->X, wpn->Y-wpn->Z, wpn->Tile, 1, 1, wpn->CSet,
  614.                          -1, -1, wpn->X, wpn->Y-wpn->Z, angle, flip, true, OP_OPAQUE);
  615.     }
  616.     else // EWF_ROTATE_360 isn't set
  617.     {
  618.         if((wpn->Misc[__EWI_FLAGS]&EWF_FLICKER)!=0)
  619.         {
  620.             // Weapons can't be made invisible; use DrawXOffset instead
  621.             if((__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_FLICKER)!=0)
  622.                 wpn->DrawXOffset=1000;
  623.             else
  624.                 wpn->DrawXOffset=0;
  625.         }
  626.        
  627.         if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE)!=0)
  628.             SetEWeaponRotation(wpn);
  629.     }
  630. }
  631.  
  632. // Set the weapon's direction based on its angle;
  633. // Can also makes weapons unblockable
  634. void SetEWeaponDir(eweapon wpn)
  635. {
  636.     float angle=wpn->Angle%6.2832;
  637.     int dir;
  638.    
  639.     if(angle<0)
  640.         angle+=6.2832;
  641.    
  642.     if(angle<0.3927 || angle>5.8905)
  643.         dir=DIR_RIGHT;
  644.     else if(angle<1.1781)
  645.         dir=DIR_RIGHTDOWN;
  646.     else if(angle<1.9635)
  647.         dir=DIR_DOWN;
  648.     else if(angle<2.7489)
  649.         dir=DIR_LEFTDOWN;
  650.     else if(angle<3.5343)
  651.         dir=DIR_LEFT;
  652.     else if(angle<4.3197)
  653.         dir=DIR_LEFTUP;
  654.     else if(angle<5.1051)
  655.         dir=DIR_UP;
  656.     else
  657.         dir=DIR_RIGHTUP;
  658.    
  659.     if((wpn->Misc[__EWI_FLAGS]&EWF_UNBLOCKABLE)!=0)
  660.         dir=__UnblockableDir(dir);
  661.    
  662.     wpn->Dir=dir;
  663. }
  664.  
  665.  
  666. // Flip the weapon's sprite to match its direction
  667. void SetEWeaponRotation(eweapon wpn)
  668. {
  669.     if(wpn->Angular)
  670.     {
  671.         float angle=wpn->Angle%6.2832;
  672.         if(angle<0)
  673.             angle+=6.2832;
  674.  
  675.         if(angle<0.7854 || angle>5.4978) // Right
  676.             wpn->Flip=4;
  677.         else if(angle<=2.3562) // Down
  678.             wpn->Flip=3;
  679.         else if(angle<3.927) // Left
  680.             wpn->Flip=7;
  681.         else // Up
  682.             wpn->Flip=0;
  683.     }
  684.     else
  685.     {
  686.         int dir=__NormalizeDir(wpn->Dir);
  687.         if(dir==DIR_UP || dir==DIR_RIGHTUP || dir==DIR_LEFTUP)
  688.             wpn->Flip=0;
  689.         else if(dir==DIR_DOWN || dir==DIR_RIGHTDOWN || dir==DIR_LEFTDOWN)
  690.             wpn->Flip=3;
  691.         else if(dir==DIR_LEFT)
  692.             wpn->Flip=7;
  693.         else // Right
  694.             wpn->Flip=4;
  695.     }
  696. }
  697.  
  698.  
  699. // Flip the weapon's sprite to match the given direction
  700. void SetEWeaponRotation(eweapon wpn, int dir)
  701. {
  702.     dir=__NormalizeDir(dir);
  703.     if(dir==DIR_UP || dir==DIR_RIGHTUP || dir==DIR_LEFTUP)
  704.         wpn->Flip=0;
  705.     else if(dir==DIR_DOWN || dir==DIR_RIGHTDOWN || dir==DIR_LEFTDOWN)
  706.         wpn->Flip=3;
  707.     else if(dir==DIR_LEFT)
  708.         wpn->Flip=7;
  709.     else // Right
  710.         wpn->Flip=4;
  711. }
  712.  
  713.  
  714. // Kill an eweapon, triggering any death effects
  715. void KillEWeapon(eweapon wpn)
  716. {
  717.     wpn->Misc[__EWI_FLAGS]|=__EWFI_DEAD;
  718. }
  719.  
  720.  
  721. // Draw a shadow under an eweapon
  722. void DrawEWeaponShadow(eweapon wpn)
  723. {
  724.     if(GH_SHADOW_FLICKER>0 && (__ghzhData[__GHI_GLOBAL_FLAGS]&__GHGF_FLICKER)!=0)
  725.         return;
  726.    
  727.     int x=CenterX(wpn)-8+wpn->DrawXOffset;
  728.     int y=wpn->Y+(wpn->TileHeight-1)*16+wpn->DrawYOffset-wpn->DrawZOffset;
  729.  
  730.     if(GH_SHADOW_TRANSLUCENT>0)
  731.         Screen->DrawTile(1, x, y, GH_SHADOW_TILE+__ghzhData[__GHI_SHADOW_FRAME],
  732.                          1, 1, GH_SHADOW_CSET, -1, -1, 0, 0, 0, 0, true, 64);
  733.     else
  734.         Screen->DrawTile(1, x, y, GH_SHADOW_TILE+__ghzhData[__GHI_SHADOW_FRAME],
  735.                          1, 1, GH_SHADOW_CSET, -1, -1, 0, 0, 0, 0, true, 128);
  736. }
  737.  
  738.  
  739. // Get the standard sprite for this weapon type
  740. int GetDefaultEWeaponSprite(int weaponID)
  741. {
  742.     if(weaponID==EW_FIREBALL || weaponID==EW_FIREBALL2)
  743.         return 17;
  744.     else if(weaponID==EW_ROCK)
  745.         return 18;
  746.     else if(weaponID==EW_ARROW)
  747.         return 19;
  748.     else if(weaponID==EW_FIRE)
  749.         return 35;
  750.     else if(weaponID==EW_FIRE2)
  751.         return 81;
  752.     else if(weaponID==EW_FIRETRAIL)
  753.         return 80;
  754.     else if(weaponID==EW_MAGIC)
  755.         return 21;
  756.     else if(weaponID==EW_BEAM)
  757.         return 20;
  758.     else if(weaponID==EW_WIND)
  759.         return 36;
  760.     else if(weaponID==EW_BOMB)
  761.         return 76;
  762.     else if(weaponID==EW_SBOMB)
  763.         return 77;
  764.     else if(weaponID==EW_BRANG)
  765.     {
  766.         // The sprite depends on what boomerang Link has, so check his inventory
  767.         int maxLevel=0;
  768.         itemdata id;
  769.  
  770.         for(int i=0; i<256; i++)
  771.         {
  772.             if(!Link->Item[i])
  773.                 continue;
  774.  
  775.             id=Game->LoadItemData(i);
  776.  
  777.             if(id->Family!=IC_BRANG)
  778.                 continue;
  779.  
  780.             if(id->Level>maxLevel)
  781.             {
  782.                 maxLevel=id->Level;
  783.                 if(maxLevel>=3) // Any higher won't matter
  784.                     break;
  785.             }
  786.  
  787.         }
  788.  
  789.         if(maxLevel<=1)
  790.             return 4;
  791.         else if(maxLevel==2)
  792.             return 5;
  793.         else
  794.             return 6;
  795.     }
  796.     else
  797.         return 0;
  798. }
  799.  
  800.  
  801. // Find the sound normally made by weapons of this type
  802. int GetDefaultEWeaponSound(int weaponID)
  803. {
  804.      if(weaponID==EW_FIREBALL || weaponID==EW_FIREBALL2)
  805.         return 40;
  806.     else if(weaponID==EW_MAGIC || weaponID==EW_WIND)
  807.         return 32;
  808.     else if(weaponID==EW_FIRE || weaponID==EW_FIRE2 || weaponID==EW_FIRETRAIL)
  809.         return 13;
  810.     else if(weaponID==EW_ROCK)
  811.         return 51;
  812.     else
  813.         return 0;
  814. }
  815.  
  816.  
  817. // Use this in a script started on eweapon death to find the weapon
  818. // that created it
  819. eweapon GetAssociatedEWeapon(int weaponID)
  820. {
  821.     eweapon wpn;
  822.    
  823.     for(int i=Screen->NumEWeapons(); i>0; i--)
  824.     {
  825.         wpn=Screen->LoadEWeapon(i);
  826.         if((wpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY_CHECK)!=__EWFI_IS_GHZH_EWPN) // Filter out dummies
  827.             continue;
  828.  
  829.         if(wpn->Misc[__EWI_ID]==weaponID)
  830.             return wpn;
  831.     }
  832.    
  833.     // Couldn't find it; return an uninitialized weapon
  834.     eweapon invalidWpn;
  835.     return invalidWpn;
  836. }
  837.  
  838.  
  839. // Is this a ghost.zh-controlled weapon?
  840. bool IsGhostZHEWeapon(eweapon wpn)
  841. {
  842.     return (wpn->Misc[__EWI_FLAGS]&__EWFI_IS_GHZH_EWPN)!=0;
  843. }
  844.  
  845.  
  846. // Is this a dummy weapon?
  847. bool IsDummyEWeapon(eweapon wpn)
  848. {
  849.     return (wpn->Misc[__EWI_FLAGS]&__EWFI_DUMMY_CHECK)==__EWFI_DUMMY_CHECK;
  850. }
  851.  
  852.  
  853. // Make a copy of the given eweapon, which should be a dummy
  854. void __CopyEWeapon(eweapon prototype, int centerX, int centerY, float angle)
  855. {
  856.     eweapon wpn=Screen->CreateEWeapon(prototype->ID);
  857.     if(prototype->Misc[__EWI_DUMMY_SPRITE]>0)
  858.         wpn->UseSprite(prototype->Misc[__EWI_DUMMY_SPRITE]);
  859.  
  860.     if(prototype->Extend==3)
  861.     {
  862.         wpn->Extend=3;
  863.         wpn->TileWidth=prototype->TileWidth;
  864.         wpn->TileHeight=prototype->TileHeight;
  865.         wpn->HitWidth=16*prototype->TileWidth;
  866.         wpn->HitHeight=16*prototype->TileHeight;
  867.         wpn->X=centerX-8*wpn->TileWidth;
  868.         wpn->Y=centerY-8*wpn->TileWidth;
  869.     }
  870.     else
  871.     {
  872.         wpn->X=centerX-8;
  873.         wpn->Y=centerY-8;
  874.     }
  875.  
  876.     wpn->Step=prototype->Misc[__EWI_DUMMY_STEP];
  877.     wpn->Damage=prototype->Damage;
  878.     wpn->Angular=true;
  879.     wpn->Angle=angle;
  880.     SetEWeaponDir(wpn);
  881.  
  882.     wpn->Misc[__EWI_XPOS]=wpn->X;
  883.     wpn->Misc[__EWI_YPOS]=wpn->Y;
  884.     wpn->Misc[__EWI_MOVEMENT]=prototype->Misc[__EWI_MOVEMENT];
  885.     wpn->Misc[__EWI_MOVEMENT_ARG_2]=prototype->Misc[__EWI_MOVEMENT_ARG_2];
  886.  
  887.     // Special case for thrown weapons with automatic velocity
  888.     if(prototype->Misc[__EWI_MOVEMENT]==EWM_THROW && prototype->Misc[__EWI_MOVEMENT_ARG]==-1)
  889.     {
  890.         float time=Distance(centerX, centerY, Link->X+8, Link->Y+8)/(wpn->Step/100);
  891.         wpn->Misc[__EWI_MOVEMENT_ARG]=GH_GRAVITY*time/2;
  892.     }
  893.     else
  894.         wpn->Misc[__EWI_MOVEMENT_ARG]=prototype->Misc[__EWI_MOVEMENT_ARG];
  895.  
  896.     wpn->Misc[__EWI_LIFESPAN]=prototype->Misc[__EWI_LIFESPAN];
  897.     wpn->Misc[__EWI_LIFESPAN_ARG]=prototype->Misc[__EWI_LIFESPAN_ARG];
  898.     wpn->Misc[__EWI_ON_DEATH]=prototype->Misc[__EWI_ON_DEATH];
  899.     wpn->Misc[__EWI_ON_DEATH_ARG]=prototype->Misc[__EWI_ON_DEATH_ARG];
  900.     wpn->Misc[__EWI_FLAGS]=(prototype->Misc[__EWI_FLAGS]&(~__EWFI_DUMMY));
  901.  
  902.     if((wpn->Misc[__EWI_FLAGS]&EWF_NO_COLLISION)!=0)
  903.         wpn->CollDetection=false;
  904.  
  905.     if((wpn->Misc[__EWI_FLAGS]&EWF_ROTATE)!=0)
  906.         SetEWeaponRotation(wpn);
  907. }
  908.  
  909.  
  910. // Get the unblockable version (8-15) of a direction
  911. int __UnblockableDir(int dir)
  912. {
  913.     if(dir==DIR_UP)
  914.         return 8;
  915.     if(dir==DIR_DOWN)
  916.         return 12;
  917.     if(dir==DIR_LEFT)
  918.         return 14;
  919.     if(dir==DIR_RIGHT)
  920.         return 10;
  921.     if(dir==DIR_LEFTUP)
  922.         return 15;
  923.     if(dir==DIR_RIGHTUP)
  924.         return 9;
  925.     if(dir==DIR_LEFTDOWN)
  926.         return 13;
  927.     if(dir==DIR_RIGHTDOWN)
  928.         return 11;
  929.    
  930.     // Should never get here
  931.     return dir;
  932. }
  933.  
  934.  
  935. bool ghostDistXY(eweapon b, int distance) {
  936.     int distx; int disty;
  937.     if ( Link->X > b->X ) distx = Link->X - b->X;
  938.     else distx = b->X - Link->X;
  939.    
  940.     if ( Link->Y > b->Y ) disty = Link->Y - b->Y;
  941.     else disty = b->Y - Link->Y;
  942.  
  943.     return ( distx <= distance && disty <= distance );
  944. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement