/* * 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 -----------//