Advertisement
Guest User

eweapon.zh Fixed

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