Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * OpenTyrian: A modern cross-platform port of Tyrian
  3.  * Copyright (C) 2007-2013  The OpenTyrian Development Team
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18.  */
  19. #include "shots.h"
  20.  
  21. #include "player.h"
  22. #include "sprite.h"
  23. #include "video.h"
  24. #include "varz.h"
  25.  
  26. // I'm pretty sure the last extra entry is never used.
  27. PlayerShotDataType playerShotData[MAX_PWEAPON + 1]; /* [1..MaxPWeapon+1] */
  28. JE_byte shotAvail[MAX_PWEAPON]; /* [1..MaxPWeapon] */   /*0:Avail 1-255:Duration left*/
  29.  
  30. void simulate_player_shots( void )
  31. {
  32.         /* Player Shot Images */
  33.         for (int z = 0; z < MAX_PWEAPON; z++)
  34.         {
  35.                 if (shotAvail[z] != 0)
  36.                 {
  37.                         shotAvail[z]--;
  38.                         if (z != MAX_PWEAPON - 1)
  39.                         {
  40.                                 PlayerShotDataType* shot = &playerShotData[z];
  41.  
  42.                                 shot->shotXM += shot->shotXC;
  43.  
  44.                                 if (shot->shotXM <= 100)
  45.                                         shot->shotX += shot->shotXM;
  46.  
  47.                                 shot->shotYM += shot->shotYC;
  48.                                 shot->shotY += shot->shotYM;
  49.  
  50.                                 if (shot->shotYM > 100)
  51.                                 {
  52.                                         shot->shotY -= 120;
  53.                                         shot->shotY += player[0].delta_y_shot_move;
  54.                                 }
  55.  
  56.                                 if (shot->shotComplicated != 0)
  57.                                 {
  58.                                         shot->shotDevX += shot->shotDirX;
  59.                                         shot->shotX += shot->shotDevX;
  60.  
  61.                                         if (abs(shot->shotDevX) == shot->shotCirSizeX)
  62.                                                 shot->shotDirX = -shot->shotDirX;
  63.  
  64.                                         shot->shotDevY += shot->shotDirY;
  65.                                         shot->shotY += shot->shotDevY;
  66.  
  67.                                         if (abs(shot->shotDevY) == shot->shotCirSizeY)
  68.                                                 shot->shotDirY = -shot->shotDirY;
  69.                                         /*Double Speed Circle Shots - add a second copy of above loop*/
  70.                                 }
  71.  
  72.                                 int tempShotX = shot->shotX;
  73.                                 int tempShotY = shot->shotY;
  74.  
  75.                                 if (shot->shotX < 0 || shot->shotX > 140 ||
  76.                                     shot->shotY < 0 || shot->shotY > 170)
  77.                                 {
  78.                                         shotAvail[z] = 0;
  79.                                         goto draw_player_shot_loop_end;
  80.                                 }
  81.  
  82. /*                              if (shot->shotTrail != 255)
  83.                                 {
  84.                                         if (shot->shotTrail == 98)
  85.                                         {
  86.                                                 JE_setupExplosion(shot->shotX - shot->shotXM, shot->shotY - shot->shotYM, shot->shotTrail);
  87.                                         } else {
  88.                                                 JE_setupExplosion(shot->shotX, shot->shotY, shot->shotTrail);
  89.                                         }
  90.                                 }*/
  91.  
  92.                                 JE_word anim_frame = shot->shotGr + shot->shotAni;
  93.                                 if (++shot->shotAni == shot->shotAniMax)
  94.                                         shot->shotAni = 0;
  95.  
  96.                                 if (anim_frame < 6000)
  97.                                 {
  98.                                         if (anim_frame > 1000)
  99.                                                 anim_frame = anim_frame % 1000;
  100.                                         if (anim_frame > 500)
  101.                                                 blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesW2, anim_frame - 500);
  102.                                         else
  103.                                                 blit_sprite2(VGAScreen, tempShotX+1, tempShotY, shapesC1, anim_frame);
  104.                                 }
  105.                         }
  106.  
  107. draw_player_shot_loop_end:
  108.                         ;
  109.                 }
  110.         }
  111. }
  112.  
  113. static const JE_word linkMultiGr[17] /* [0..16] */ =
  114.         {77,221,183,301,1,282,164,202,58,201,163,281,39,300,182,220,77};
  115. static const JE_word linkSonicGr[17] /* [0..16] */ =
  116.         {85,242,131,303,47,284,150,223,66,224,149,283,9,302,130,243,85};
  117. static const JE_word linkMult2Gr[17] /* [0..16] */ =
  118.         {78,299,295,297,2,278,276,280,59,279,275,277,40,296,294,298,78};
  119.  
  120. void player_shot_set_direction( JE_integer shot_id, uint weapon_id, JE_real direction )
  121. {
  122.         PlayerShotDataType* shot = &playerShotData[shot_id];
  123.  
  124.         shot->shotXM = -roundf(sinf(direction) * shot->shotYM);
  125.         shot->shotYM = -roundf(cosf(direction) * shot->shotYM);
  126.  
  127.         // Some weapons have sprites for each direction, use those.
  128.         int rounded_dir;
  129.  
  130.         switch (weapon_id)
  131.         {
  132.         case 27:
  133.         case 32:
  134.         case 10:
  135.                 rounded_dir = roundf(direction * (16 / (2 * M_PI)));  /*16 directions*/
  136.                 shot->shotGr = linkMultiGr[rounded_dir];
  137.                 break;
  138.         case 28:
  139.         case 33:
  140.         case 11:
  141.                 rounded_dir = roundf(direction * (16 / (2 * M_PI)));  /*16 directions*/
  142.                 shot->shotGr = linkSonicGr[rounded_dir];
  143.                 break;
  144.         case 30:
  145.         case 35:
  146.         case 14:
  147.                 if (direction > M_PI_2 && direction < M_PI + M_PI_2)
  148.                 {
  149.                         shot->shotYC = 1;
  150.                 }
  151.                 break;
  152.         case 38:
  153.         case 22:
  154.                 rounded_dir = roundf(direction * (16 / (2 * M_PI)));  /*16 directions*/
  155.                 shot->shotGr = linkMult2Gr[rounded_dir];
  156.                 break;
  157.         }
  158. }
  159.  
  160. bool player_shot_move_and_draw(
  161.                 int shot_id, bool* out_is_special,
  162.                 int* out_shotx, int* out_shoty,
  163.                 JE_integer* out_shot_damage, JE_byte* out_blast_filter,
  164.                 JE_byte* out_chain, JE_byte* out_playerNum,
  165.                 JE_word* out_special_radiusw, JE_word* out_special_radiush )
  166. {
  167.         PlayerShotDataType* shot = &playerShotData[shot_id];
  168.  
  169.         shotAvail[shot_id]--;
  170.         if (shot_id != MAX_PWEAPON - 1)
  171.         {
  172.                 shot->shotXM += shot->shotXC;
  173.                 shot->shotX += shot->shotXM;
  174.                 JE_integer tmp_shotXM = shot->shotXM;
  175.  
  176.                 if (shot->shotXM > 100)
  177.                 {
  178.                         if (shot->shotXM == 101)
  179.                         {
  180.                                 shot->shotX -= 101;
  181.                                 shot->shotX += player[shot->playerNumber-1].delta_x_shot_move;
  182.                                 shot->shotY += player[shot->playerNumber-1].delta_y_shot_move;
  183.                         }
  184.                         else
  185.                         {
  186.                                 shot->shotX -= 120;
  187.                                 shot->shotX += player[shot->playerNumber-1].delta_x_shot_move;
  188.                         }
  189.                 }
  190.  
  191.                 shot->shotYM += shot->shotYC;
  192.                 shot->shotY += shot->shotYM;
  193.  
  194.                 if (shot->shotYM > 100)
  195.                 {
  196.                         shot->shotY -= 120;
  197.                         shot->shotY += player[shot->playerNumber-1].delta_y_shot_move;
  198.                 }
  199.  
  200.                 if (shot->shotComplicated != 0)
  201.                 {
  202.                         shot->shotDevX += shot->shotDirX;
  203.                         shot->shotX += shot->shotDevX;
  204.  
  205.                         if (abs(shot->shotDevX) == shot->shotCirSizeX)
  206.                                 shot->shotDirX = -shot->shotDirX;
  207.  
  208.                         shot->shotDevY += shot->shotDirY;
  209.                         shot->shotY += shot->shotDevY;
  210.  
  211.                         if (abs(shot->shotDevY) == shot->shotCirSizeY)
  212.                                 shot->shotDirY = -shot->shotDirY;
  213.  
  214.                         /*Double Speed Circle Shots - add a second copy of above loop*/
  215.                 }
  216.  
  217.                 *out_shotx = shot->shotX;
  218.                 *out_shoty = shot->shotY;
  219.  
  220.                 if (shot->shotX < -34 || shot->shotX > 290 ||
  221.                         shot->shotY < -15 || shot->shotY > 190)
  222.                 {
  223.                         shotAvail[shot_id] = 0;
  224.                         return false;
  225.                 }
  226.  
  227.                 if (shot->shotTrail != 255)
  228.                 {
  229.                         if (shot->shotTrail == 98)
  230.                                 JE_setupExplosion(shot->shotX - shot->shotXM, shot->shotY - shot->shotYM, 0, shot->shotTrail, false, false);
  231.                         else
  232.                                 JE_setupExplosion(shot->shotX, shot->shotY, 0, shot->shotTrail, false, false);
  233.                 }
  234.  
  235.                 if (shot->aimAtEnemy != 0)
  236.                 {
  237.                         if (--shot->aimDelay == 0)
  238.                         {
  239.                                 shot->aimDelay = shot->aimDelayMax;
  240.  
  241.                                 if (enemyAvail[shot->aimAtEnemy - 1] != 1)
  242.                                 {
  243.                                         if (shot->shotX < enemy[shot->aimAtEnemy - 1].ex)
  244.                                                 shot->shotXM++;
  245.                                         else
  246.                                                 shot->shotXM--;
  247.  
  248.                                         if (shot->shotY < enemy[shot->aimAtEnemy - 1].ey)
  249.                                                 shot->shotYM++;
  250.                                         else
  251.                                                 shot->shotYM--;
  252.                                 }
  253.                                 else
  254.                                 {
  255.                                         if (shot->shotXM > 0)
  256.                                                 shot->shotXM++;
  257.                                         else
  258.                                                 shot->shotXM--;
  259.                                 }
  260.                         }
  261.                 }
  262.  
  263.                 JE_word sprite_frame = shot->shotGr + shot->shotAni;
  264.                 if (++shot->shotAni == shot->shotAniMax)
  265.                         shot->shotAni = 0;
  266.  
  267.                 *out_shot_damage = shot->shotDmg;
  268.                 *out_blast_filter = shot->shotBlastFilter;
  269.                 *out_chain = shot->chainReaction;
  270.                 *out_playerNum = shot->playerNumber;
  271.  
  272.                 *out_is_special = sprite_frame > 60000;
  273.  
  274.                 if (*out_is_special)
  275.                 {
  276.                         blit_sprite_blend(VGAScreen, *out_shotx+1, *out_shoty, OPTION_SHAPES, sprite_frame - 60001);
  277.  
  278.                         *out_special_radiusw = sprite(OPTION_SHAPES, sprite_frame - 60001)->width / 2;
  279.                         *out_special_radiush = sprite(OPTION_SHAPES, sprite_frame - 60001)->height / 2;
  280.                 }
  281.                 else
  282.                 {
  283.                         if (sprite_frame > 1000)
  284.                         {
  285.                                 JE_doSP(*out_shotx+1 + 6, *out_shoty + 6, 5, 3, (sprite_frame / 1000) << 4);
  286.                                 sprite_frame = sprite_frame % 1000;
  287.                         }
  288.                         if (sprite_frame > 500)
  289.                         {
  290.                                 if (background2 && *out_shoty + shadowYDist < 190 && tmp_shotXM < 100)
  291.                                         blit_sprite2_darken(VGAScreen, *out_shotx+1, *out_shoty + shadowYDist, shapesW2, sprite_frame - 500);
  292.                                 blit_sprite2(VGAScreen, *out_shotx+1, *out_shoty, shapesW2, sprite_frame - 500);
  293.                         }
  294.                         else
  295.                         {
  296.                                 if (background2 && *out_shoty + shadowYDist < 190 && tmp_shotXM < 100)
  297.                                         blit_sprite2_darken(VGAScreen, *out_shotx+1, *out_shoty + shadowYDist, shapesC1, sprite_frame);
  298.                                 blit_sprite2(VGAScreen, *out_shotx+1, *out_shoty, shapesC1, sprite_frame);
  299.                         }
  300.                 }
  301.         }
  302.  
  303.         return true;
  304. }
  305.  
  306. JE_integer player_shot_create( JE_word portNum, uint bay_i, JE_word PX, JE_word PY, JE_word mouseX, JE_word mouseY, JE_word wpNum, JE_byte playerNum )
  307. {
  308.         static const JE_byte soundChannel[11] /* [1..11] */ = {0, 2, 4, 4, 2, 2, 5, 5, 1, 4, 1};
  309.  
  310.         // Bounds check
  311.         if (portNum > PORT_NUM || wpNum <= 0 || wpNum > WEAP_NUM)
  312.                 return MAX_PWEAPON;
  313.  
  314.         const JE_WeaponType* weapon = &weapons[wpNum];
  315.  
  316.         if (power < weaponPort[portNum].poweruse)
  317.                 return MAX_PWEAPON;
  318.         power -= weaponPort[portNum].poweruse;
  319.  
  320.         if (weapon->sound > 0)
  321.                 soundQueue[soundChannel[bay_i]] = weapon->sound;
  322.  
  323.         int shot_id = MAX_PWEAPON;
  324.         /*Rot*/
  325.         for (int multi_i = 1; multi_i <= weapon->multi; multi_i++)
  326.         {
  327.                 for (shot_id = 0; shot_id < MAX_PWEAPON; shot_id++)
  328.                         if (shotAvail[shot_id] == 0)
  329.                                 break;
  330.                 if (shot_id == MAX_PWEAPON)
  331.                         return MAX_PWEAPON;
  332.  
  333.                 if (shotMultiPos[bay_i] == weapon->max || shotMultiPos[bay_i] > 8)
  334.                         shotMultiPos[bay_i] = 1;
  335.                 else
  336.                         shotMultiPos[bay_i]++;
  337.  
  338.                 PlayerShotDataType* shot = &playerShotData[shot_id];
  339.                 shot->chainReaction = 0;
  340.  
  341.                 shot->playerNumber = playerNum;
  342.  
  343.                 shot->shotAni = 0;
  344.  
  345.                 shot->shotComplicated = weapon->circlesize != 0;
  346.  
  347.                 if (weapon->circlesize == 0)
  348.                 {
  349.                         shot->shotDevX = 0;
  350.                         shot->shotDirX = 0;
  351.                         shot->shotDevY = 0;
  352.                         shot->shotDirY = 0;
  353.                         shot->shotCirSizeX = 0;
  354.                         shot->shotCirSizeY = 0;
  355.                 }
  356.                 else
  357.                 {
  358.                         JE_byte circsize = weapon->circlesize;
  359.  
  360.                         if (circsize > 19)
  361.                         {
  362.                                 JE_byte circsize_mod20 = circsize % 20;
  363.                                 shot->shotCirSizeX = circsize_mod20;
  364.                                 shot->shotDevX = circsize_mod20 >> 1;
  365.  
  366.                                 circsize = circsize / 20;
  367.                                 shot->shotCirSizeY = circsize;
  368.                                 shot->shotDevY = circsize >> 1;
  369.                         }
  370.                         else
  371.                         {
  372.                                 shot->shotCirSizeX = circsize;
  373.                                 shot->shotCirSizeY = circsize;
  374.                                 shot->shotDevX = circsize >> 1;
  375.                                 shot->shotDevY = circsize >> 1;
  376.                         }
  377.                         shot->shotDirX = 1;
  378.                         shot->shotDirY = -1;
  379.                 }
  380.  
  381.                 shot->shotTrail = weapon->trail;
  382.  
  383.                 if (weapon->attack[shotMultiPos[bay_i]-1] > 99 && weapon->attack[shotMultiPos[bay_i]-1] < 250)
  384.                 {
  385.                         shot->chainReaction = weapon->attack[shotMultiPos[bay_i]-1] - 100;
  386.                         shot->shotDmg = 1;
  387.                 }
  388.                 else
  389.                 {
  390.                         shot->shotDmg = weapon->attack[shotMultiPos[bay_i]-1];
  391.                 }
  392.  
  393.                 shot->shotBlastFilter = weapon->shipblastfilter;
  394.  
  395.                 JE_integer tmp_by = weapon->by[shotMultiPos[bay_i]-1];
  396.  
  397.                 /*Note: Only front selection used for player shots...*/
  398.  
  399.                 shot->shotX = PX + weapon->bx[shotMultiPos[bay_i]-1];
  400.  
  401.                 shot->shotY = PY + tmp_by;
  402.                 shot->shotYC = -weapon->acceleration;
  403.                 shot->shotXC = weapon->accelerationx;
  404.  
  405.                 shot->shotXM = weapon->sx[shotMultiPos[bay_i]-1];
  406.  
  407.                 // Not sure what this field does exactly.
  408.                 JE_byte del = weapon->del[shotMultiPos[bay_i]-1];
  409.  
  410.                 if (del == 121)
  411.                 {
  412.                         shot->shotTrail = 0;
  413.                         del = 255;
  414.                 }
  415.  
  416.                 shot->shotGr = weapon->sg[shotMultiPos[bay_i]-1];
  417.                 if (shot->shotGr == 0)
  418.                         shotAvail[shot_id] = 0;
  419.                 else
  420.                         shotAvail[shot_id] = del;
  421.  
  422.                 if (del > 100 && del < 120)
  423.                         shot->shotAniMax = (del - 100 + 1);
  424.                 else
  425.                         shot->shotAniMax = weapon->weapani + 1;
  426.  
  427.                 if (del == 99 || del == 98)
  428.                 {
  429.                         tmp_by = PX - mouseX;
  430.                         if (tmp_by < -5)
  431.                                 tmp_by = -5;
  432.                         else if (tmp_by > 5)
  433.                                 tmp_by = 5;
  434.                         shot->shotXM += tmp_by;
  435.                 }
  436.  
  437.                 if (del == 99 || del == 100)
  438.                 {
  439.                         tmp_by = PY - mouseY - weapon->sy[shotMultiPos[bay_i]-1];
  440.                         if (tmp_by < -4)
  441.                                 tmp_by = -4;
  442.                         else if (tmp_by > 4)
  443.                                 tmp_by = 4;
  444.                         shot->shotYM = tmp_by;
  445.                 }
  446.                 else if (weapon->sy[shotMultiPos[bay_i]-1] == 98)
  447.                 {
  448.                         shot->shotYM = 0;
  449.                         shot->shotYC = -1;
  450.                 }
  451.                 else if (weapon->sy[shotMultiPos[bay_i]-1] > 100)
  452.                 {
  453.                         shot->shotYM = weapon->sy[shotMultiPos[bay_i]-1];
  454.                         shot->shotY -= player[shot->playerNumber-1].delta_y_shot_move;
  455.                 }
  456.                 else
  457.                 {
  458.                         shot->shotYM = -weapon->sy[shotMultiPos[bay_i]-1];
  459.                 }
  460.  
  461.                 if (weapon->sx[shotMultiPos[bay_i]-1] > 100)
  462.                 {
  463.                         shot->shotXM = weapon->sx[shotMultiPos[bay_i]-1];
  464.                         shot->shotX -= player[shot->playerNumber-1].delta_x_shot_move;
  465.                         if (shot->shotXM == 101)
  466.                                 shot->shotY -= player[shot->playerNumber-1].delta_y_shot_move;
  467.                 }
  468.  
  469.  
  470.                 if (weapon->aim > 5)  /*Guided Shot*/
  471.                 {
  472.                         uint best_dist = 65000;
  473.                         JE_byte closest_enemy = 0;
  474.                         /*Find Closest Enemy*/
  475.                         for (x = 0; x < 100; x++)
  476.                         {
  477.                                 if (enemyAvail[x] != 1 && !enemy[x].scoreitem)
  478.                                 {
  479.                                         y = abs(enemy[x].ex - shot->shotX) + abs(enemy[x].ey - shot->shotY);
  480.                                         if (y < best_dist)
  481.                                         {
  482.                                                 best_dist = y;
  483.                                                 closest_enemy = x + 1;
  484.                                         }
  485.                                 }
  486.                         }
  487.                         shot->aimAtEnemy = closest_enemy;
  488.                         shot->aimDelay = 5;
  489.                         shot->aimDelayMax = weapon->aim - 5;
  490.                 }
  491.                 else
  492.                 {
  493.                         shot->aimAtEnemy = 0;
  494.                 }
  495.  
  496.                 shotRepeat[bay_i] = weapon->shotrepeat;
  497.         }
  498.  
  499.         return shot_id;
  500. }
  501.