/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OBULLETA.CPP
//Description : Object Bullet Array
//Owner : Alex
#include
#include
#include
#include
#include
#include
#include
#include
//--------- Begin of function BulletArray::BulletArray ---------//
//
// initArraySize - the initial size of this array.
//
BulletArray::BulletArray(int initArraySize) : SpriteArray(initArraySize)
{
}
//----------- End of function BulletArray::BulletArray -----------//
//--------- Begin of function BulletArray::create_bullet ---------//
//
// return: the recno of the bullet created.
//
int BulletArray::create_bullet(short spriteId, Bullet** bpp)
{
Bullet* bulletPtr;
SpriteInfo *spriteInfo = sprite_res[spriteId];
err_when(!spriteInfo);
err_when(spriteInfo->sprite_type != 'B');
switch(spriteInfo->sprite_sub_type)
{
case 0:
case ' ':
bulletPtr = new Bullet;
break;
case 'P':
bulletPtr = new Projectile;
break;
case 'H':
bulletPtr = new BulletHoming;
break;
case 'F':
bulletPtr = new BulletFlame;
break;
default:
err_here(); // undefined bullet type
if( bpp )
*bpp = NULL;
return 0;
}
add(bulletPtr);
if( bpp )
*bpp = bulletPtr;
return recno();
}
//----------- End of function BulletArray::create_bullet -----------//
//--------- Begin of function BulletArray::bullet_class_size ---------//
int BulletArray::bullet_class_size(int spriteId)
{
SpriteInfo *spriteInfo = sprite_res[spriteId];
err_when(spriteInfo->sprite_type != 'B');
switch(spriteInfo->sprite_sub_type)
{
case 0:
case ' ':
return sizeof(Bullet);
case 'P':
return sizeof(Projectile);
case 'H':
return sizeof(BulletHoming);
case 'F':
return sizeof(BulletFlame);
default:
err_here(); // undefined bullet type
return 0;
}
}
//----------- End of function BulletArray::bullet_class_size -----------//
//--------- Begin of function BulletArray::bullet_path_possible ---------//
// For default bullet:
// if the bullet is not blocked by building in its path, this
// function return 1 for success, otherwise return 0.
// For projectile bullet:
// always return 1
//
int BulletArray::bullet_path_possible(short startXLoc, short startYLoc, char attackerMobileType,
short destXLoc, short destYLoc, char targetMobileType,
char bulletSpeed, short bulletSpriteId)
{
if(attackerMobileType==UNIT_AIR || targetMobileType==UNIT_AIR)
return 1;
//-------- skip the checking for projectile -----------//
SpriteInfo *spriteInfo = sprite_res[bulletSpriteId];
if(spriteInfo->sprite_sub_type == 'P')
return 1;
err_when(spriteInfo->sprite_sub_type == 'P');
//----------------------- define variables ---------------//
int originX = startXLoc*ZOOM_LOC_WIDTH;
int originY = startYLoc*ZOOM_LOC_HEIGHT;
int goX = destXLoc*ZOOM_LOC_WIDTH;
int goY = destYLoc*ZOOM_LOC_HEIGHT;
int xStep = (goX - originX)/bulletSpeed;
int yStep = (goY - originY)/bulletSpeed;
int totalStep = max(1, max(abs(xStep), abs(yStep)));
int curStep = 0;
//------------------------------------------------------//
// if the path of the bullet is blocked, return 0
//------------------------------------------------------//
int curX = originX + ZOOM_LOC_WIDTH/2;
int curY = originY + ZOOM_LOC_HEIGHT/2;
int curXLoc, curYLoc;
Location *locPtr;
while(curStep++ 200);
curX += xStep;
curY += yStep;
curXLoc = curX/ZOOM_LOC_WIDTH;
curYLoc = curY/ZOOM_LOC_HEIGHT;
if(curXLoc==startXLoc && curYLoc==startYLoc)
continue;
if(curXLoc==destXLoc && curYLoc==destYLoc)
break; // is destination
locPtr = world.get_loc(curXLoc, curYLoc);
//### begin alex 2/6 ###//
//if(!locPtr->walkable(3) || locPtr->has_unit(UNIT_LAND) || locPtr->has_unit(UNIT_SEA))
if(!locPtr->walkable(3))
//#### end alex 2/6 ####//
return 0;
}
return 1;
}
//----------- End of function BulletArray::bullet_path_possible -----------//
//--------- Begin of function BulletArray::add_bullet_possible ---------//
// call bullet_possible to check whether bullets emitted from this position
// can reach the target location with blocking
//
// return 1 if bullets are able to reach the target location
// return 0 if not
//
int BulletArray::add_bullet_possible(short startXLoc, short startYLoc, char attackerMobileType,
short targetXLoc, short targetYLoc, char targetMobileType,
short targetWidth, short targetHeight, short& resultXLoc, short& resultYLoc,
char bulletSpeed, short bulletSpriteId)
{
resultXLoc = resultYLoc = -1;
//----------------------------------------------------------------------//
// for target with size 1x1
//----------------------------------------------------------------------//
if(targetWidth==1 && targetHeight==1)
{
if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc, targetYLoc, targetMobileType, bulletSpeed, bulletSpriteId))
{
resultXLoc = targetXLoc;
resultYLoc = targetYLoc;
return 1;
}
else
return 0;
}
err_when(targetWidth==1 && targetHeight==1);
//----------------------------------------------------------------------//
// choose the closest corner to be the default attacking point of range attack
//
// generalized case for range-attack is coded below. Work for target with
// size > 1x1
//----------------------------------------------------------------------//
//-------------- define parameters --------------------//
short adjWidth = targetWidth-1; // adjusted width;
short adjHeight = targetHeight-1; // adjusted height
short xOffset=0, yOffset=0; // the 1st(default) location for range attack
short atEdge = 0; // i.e. the attacking point is at the corner or edge of the target
// 1 for at the edge, 0 for at corner
//----------------------------------------------------------------------//
// determine initial xOffset
//----------------------------------------------------------------------//
if(startXLoc <= targetXLoc)
xOffset = 0; // the left hand side of the target
else if(startXLoc >= targetXLoc+adjWidth)
xOffset = adjWidth; // the right hand side of the target
else
{
xOffset = startXLoc - targetXLoc; // in the middle(vertical) of the target
atEdge++;
}
//----------------------------------------------------------------------//
// determine initial yOffset
//----------------------------------------------------------------------//
if(startYLoc <= targetYLoc)
yOffset = 0; // the upper of the target
else if(startYLoc >= targetYLoc+adjHeight)
yOffset = adjHeight;
else
{
yOffset = startYLoc - targetYLoc; // in the middle(horizontal) of the target
atEdge++;
}
//----------------------------------------------------------------------//
// checking whether it is possible to add bullet
//----------------------------------------------------------------------//
if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc+xOffset, targetYLoc+yOffset, targetMobileType, bulletSpeed, bulletSpriteId))
{
resultXLoc = targetXLoc+xOffset;
resultYLoc = targetYLoc+yOffset;
return 1;
}
short leftXOffset, leftYOffset;
short rightXOffset, rightYOffset;
short leftX, leftY, rightX, rightY;
short found=0; // found a location to attack the target and the path is not blocked
short end=0;
if(atEdge) // only check one edge of the target
{
if(xOffset==0 || xOffset==adjWidth) // horizontal edge
{
leftYOffset = rightYOffset = 0;
leftXOffset = 1;
rightXOffset = -1;
}
else if(yOffset==0 || yOffset==adjHeight) // vertical edge
{
leftXOffset = rightXOffset = 0;
leftYOffset = 1;
rightYOffset = -1;
}
else
err_here(); // the sprite is within the target ???
}
else // at the corner, need to check two edges of the target
{
leftYOffset = rightXOffset = 0;
leftXOffset = (xOffset==0) ? 1 : -1;
rightYOffset = (yOffset==0) ? 1 : -1;
}
leftX = rightX = xOffset;
leftY = rightY = yOffset;
while(!found)
{
end = 0;
//-------------------------------------------//
// for the leftX, leftY
//-------------------------------------------//
leftX += leftXOffset;
leftY += leftYOffset;
if(leftX>=0 && leftX=0 && leftY=0 && rightX=0 && rightY parentUnit - pointer to the attacking target unit
// targetUnit - pointer to the target unit
//
// return 1 if bullet is added successfully otherwise return 0.
//
short BulletArray::add_bullet(Unit* parentUnit, Unit* targetUnit)
{
//------------------------------------------------------//
// define parameters
//------------------------------------------------------//
SpriteInfo *targetSpriteInfo = targetUnit->sprite_info;
AttackInfo *attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack;
short attackXLoc = parentUnit->range_attack_x_loc;
short attackYLoc = parentUnit->range_attack_y_loc;
short targetXLoc = targetUnit->next_x_loc();
short targetYLoc = targetUnit->next_y_loc();
if(attackXLoc >= targetXLoc && attackXLoc < targetXLoc+targetSpriteInfo->loc_width &&
attackYLoc >= targetYLoc && attackYLoc < targetYLoc+targetSpriteInfo->loc_height)
{
//-------------------------------------------------------//
// the previous used range attack destination can be reused,
// time is saved 'cos no need to check for bullet_path_possible()
//-------------------------------------------------------//
short bulletId = (parentUnit->attack_info_array+parentUnit->cur_attack)->bullet_sprite_id;
Bullet* bulletPtr;
create_bullet( bulletId, &bulletPtr);
bulletPtr->init(BULLET_BY_UNIT, parentUnit->sprite_recno, attackXLoc, attackYLoc, targetUnit->mobile_type);
err_when(parentUnit->cur_dir!=parentUnit->final_dir);
//parentUnit->get_dir(parentUnit->next_x_loc(), parentUnit->next_y_loc(), attackXLoc, attackYLoc);
return 1;
}
err_here();
return 0;
}
//----------- End of function BulletArray::add_bullet -----------//
//--------- Begin of function Bullet::add_bullet ---------//
// Overload of add_bullet(), unit attack firm/town/wall
//
// parentUnit - pointer to the attacking target unit
// xLoc - the target upper left corner x loc
// note: taregt can be firm, town or wall
// yLoc - the target upper left corner y loc
//
// return 1 if bullet is added successfully otherwise return 0.
//
// note: unit attacks firm or town by bullet will call this
// function. The location of the firm or town is
// specified by xLoc and yLoc.
//
short BulletArray::add_bullet(Unit* parentUnit, short xLoc, short yLoc)
{
//------------------------------------------------------//
// define parameters
//------------------------------------------------------//
AttackInfo *attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack;
short attackXLoc = parentUnit->range_attack_x_loc;
short attackYLoc = parentUnit->range_attack_y_loc;
short targetXLoc = xLoc;
short targetYLoc = yLoc;
short width, height;
Firm* targetFirm = NULL;
Town* targetTown = NULL;
FirmInfo* firmInfo = NULL;
Location* locPtr = world.get_loc(xLoc, yLoc);
if(locPtr->is_firm())
{
targetFirm = firm_array[locPtr->firm_recno()];
firmInfo = firm_res[targetFirm->firm_id];
width = firmInfo->loc_width;
height = firmInfo->loc_height;
}
else if(locPtr->is_town())
{
targetTown = town_array[locPtr->town_recno()];
width = targetTown->loc_width();
height = targetTown->loc_height();
}
else if(locPtr->is_wall())
width = height = 1;
else
err_here();
if(attackXLoc >= targetXLoc && attackXLoc < targetXLoc+width &&
attackYLoc >= targetYLoc && attackYLoc < targetYLoc+height)
{
//-------------------------------------------------------//
// the previous used range attack destination can be reused,
// time is saved 'cos no need to check for bullet_path_possible()
//-------------------------------------------------------//
short bulletId = (parentUnit->attack_info_array+parentUnit->cur_attack)->bullet_sprite_id;
Bullet* bulletPtr;
create_bullet( bulletId, &bulletPtr);
bulletPtr->init(BULLET_BY_UNIT, parentUnit->sprite_recno, attackXLoc, attackYLoc, UNIT_LAND);
err_when(parentUnit->cur_dir!=parentUnit->final_dir);
//parentUnit->get_dir(parentUnit->next_x_loc(), parentUnit->next_y_loc(), attackXLoc, attackYLoc);
return 1;
}
err_here();
return 0;
}
//----------- End of function BulletArray::add_bullet -----------//
//--------- Begin of function Bullet::add_bullet ---------//
// Overload of add_bullet()
//
// parentFirm - pointer to the attacking target Firm
// targetUnit - pointer to the target Unit
//
// return 1 if bullet is added successfully otherwise return 0.
short BulletArray::add_bullet(Firm* parentFirm, Unit* targetUnit)
{
return 0;
}
//----------- End of function BulletArray::add_bullet -----------//
//--------- Begin of function Bullet::add_bullet ---------//
// Overload of add_bullet()
//
// parentFirm - pointer to the attacking target Firm
// targetFirm - pointer to the target Firm
//
// return 1 if bullet is added successfully otherwise return 0.
short BulletArray::add_bullet(Firm* parentFirm, Firm* targetFirm)
{
return 0;
}
//----------- End of function BulletArray::add_bullet -----------//