//--------- Begin of function Bullet::init ---------// // // <char> parentType - the type of object emits the bullet // <short> parentRecno - the recno of the object // <short> targetXLoc - the x loc of the target // <short> targetYLoc - the y loc of the target // <char> targetMobileType - target mobile type // void Bullet::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType) { parent_type = parentType; parent_recno = parentRecno; target_mobile_type = targetMobileType; //**** BUGHERE, using parentType and parentRecno to allow bullet by firm, town, etc. //**** BUGHERE, only allow bullet by unit for this version err_when(parent_type!=BULLET_BY_UNIT); Unit *parentUnit = unit_array[parentRecno]; //---------- copy attack info from the parent unit --------// AttackInfo* attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack; attack_damage = parentUnit->actual_damage(); damage_radius = attackInfo->bullet_radius; nation_recno = parentUnit->nation_recno; // ###### begin Gilbert 26/6 ########## // fire_radius = attackInfo->fire_radius; // ###### end Gilbert 26/6 ########## // //----- clone vars from sprite_res for fast access -----// sprite_id = attackInfo->bullet_sprite_id; sprite_info = sprite_res[sprite_id]; sprite_info->load_bitmap_res(); // the sprite bitmap will be freed by ~Sprite(), so we don't have to add ~Bullet() to free it. //--------- set the starting position of the bullet -------// cur_action = SPRITE_MOVE; cur_frame = 1; set_dir(parentUnit->attack_dir); SpriteFrame* spriteFrame = cur_sprite_frame(); origin_x = cur_x = parentUnit->cur_x; origin_y = cur_y = parentUnit->cur_y; //------ set the target position and bullet mobile_type -------// target_x_loc = targetXLoc; target_y_loc = targetYLoc; go_x = target_x_loc * ZOOM_LOC_WIDTH + ZOOM_LOC_WIDTH/2 - spriteFrame->offset_x - spriteFrame->width/2; // -spriteFrame->offset_x to make abs_x1 & abs_y1 = original x1 & y1. So the bullet will be centered on the target go_y = target_y_loc * ZOOM_LOC_HEIGHT + ZOOM_LOC_HEIGHT/2 - spriteFrame->offset_y - spriteFrame->height/2; mobile_type = parentUnit->mobile_type; //---------- set bullet movement steps -----------// int xStep = (go_x - cur_x)/attackInfo->bullet_speed; int yStep = (go_y - cur_y)/attackInfo->bullet_speed; total_step = MAX(1, MAX(abs(xStep), abs(yStep))); cur_step = 0; err_when( total_step < 0 ); // number overflow }
// --------- begin of function BulletHoming::init --------// void BulletHoming::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType) { Bullet::init(parentType, parentRecno, targetXLoc, targetYLoc, targetMobileType); // ------- find the maximum range --------// //**** BUGHERE, using parentType and parentRecno to allow bullet by firm, town, etc. //**** BUGHERE, only allow bullet by unit for this version err_when(parent_type!=BULLET_BY_UNIT); Unit *parentUnit = unit_array[parentRecno]; //---------- copy attack info from the parent unit --------// AttackInfo* attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack; speed = attackInfo->bullet_speed; max_step = char((attackInfo->attack_range * ZOOM_LOC_WIDTH + speed-1)/ speed); //--------- keep backup of centre of the bullet ---------// SpriteFrame *spriteFrame = cur_sprite_frame(); // origin_x/y and origin2_x/y are pointing at the centre of the bullet bitmap // origin_x += spriteFrame->offset_x + spriteFrame->width/2; origin_y += spriteFrame->offset_y + spriteFrame->height/2; origin2_x = origin_x; origin2_y = origin_y; go_x += spriteFrame->offset_x + spriteFrame->width/2; go_y += spriteFrame->offset_y + spriteFrame->height/2; // ------- find the target_type and target_recno ------// Location *locPtr = world.get_loc(targetXLoc, targetYLoc); //### begin alex 16/5 ###// //if( locPtr->has_unit(mobile_type) ) if(locPtr->has_unit(targetMobileType)) { target_type = BULLET_TARGET_UNIT; //target_recno = locPtr->unit_recno(mobile_type); target_recno = locPtr->unit_recno(targetMobileType); } //#### end alex 16/5 ####// else if( locPtr->is_town() ) { target_type = BULLET_TARGET_TOWN; target_recno = locPtr->town_recno(); } else if( locPtr->is_firm() ) { target_type = BULLET_TARGET_FIRM; target_recno = locPtr->firm_recno(); } else if( locPtr->is_wall() ) { target_type = BULLET_TARGET_WALL; } }
//--------- Begin of function Sprite::update_abs_pos ---------// // // Update the cur_width & cur_height vars of the sprite for later faster access. // // [SpriteFrame *] spriteFrame pointer to the current (default : NULL) void Sprite::update_abs_pos(SpriteFrame *spriteFrame) { if( !spriteFrame ) spriteFrame = cur_sprite_frame(); abs_x1 = cur_x + spriteFrame->offset_x; // absolute position abs_y1 = cur_y + spriteFrame->offset_y; abs_x2 = abs_x1 + spriteFrame->width - 1; abs_y2 = abs_y1 + spriteFrame->height - 1; }
// --------- begin of function BulletHoming::init --------// void BulletHoming::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType) { Bullet::init(parentType, parentRecno, targetXLoc, targetYLoc, targetMobileType); // ------- find the maximum range --------// BaseObj *baseObjPtr = base_obj_array[parent_base_obj_recno]; if( baseObjPtr->cast_to_Unit() ) { Unit *parentUnit = base_obj_array[parent_base_obj_recno]->cast_to_Unit(); AttackInfo* attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack; speed = attackInfo->bullet_speed; max_step = char((attackInfo->attack_range * LOCATE_WIDTH + speed-1)/ speed); } else if( baseObjPtr->cast_to_Firm() && baseObjPtr->cast_to_Firm()->cast_to_FirmFort() ) { FirmFort *firmFort = baseObjPtr->cast_to_Firm()->cast_to_FirmFort(); speed = firmFort->bullet_speed(); max_step = 100; // unlimited range } else { err_here(); } //--------- keep backup of centre of the bullet ---------// SpriteFrame *spriteFrame = cur_sprite_frame(); // origin_x/y and origin2_x/y are pointing at the centre of the bullet bitmap // origin_x += spriteFrame->offset_x + spriteFrame->width/2; origin_y += spriteFrame->offset_y + spriteFrame->height/2; origin2_x = origin_x; origin2_y = origin_y; go_x += spriteFrame->offset_x + spriteFrame->width/2; go_y += spriteFrame->offset_y + spriteFrame->height/2; // ------- find the target_type and target_recno ------// Location *locPtr = world.get_loc(targetXLoc, targetYLoc); target_base_obj_recno = locPtr->base_obj_recno(targetMobileType); }
// --------- Begin of function Projectile::init --------// //### begin alex 3/5 ###// void Projectile::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType) { Bullet::init(parentType, parentRecno, targetXLoc, targetYLoc, targetMobileType); //#### end alex 3/5 ####// short spriteId = sprite_info->get_sub_sprite_info(1)->sprite_id; act_bullet.init( spriteId, cur_x_loc(), cur_y_loc() ); short shadowSpriteId = sprite_info->get_sub_sprite_info(2)->sprite_id; bullet_shadow.init( shadowSpriteId, cur_x_loc(), cur_y_loc() ); // calculate z_coff; z_coff = (float)1.0; /* float dz = z_coff * total_step; if( dz >= 10.0) cur_dir = cur_dir & 7 | 8; // pointing up else if( dz <= -10.0) cur_dir = cur_dir & 7 | 16; // pointing down else cur_dir &= 7; */ // --------- recalcuate spriteFrame pointer ----------// SpriteFrame* spriteFrame = cur_sprite_frame(); }
// --------- begin of function BulletHoming::process_move --------// void BulletHoming::process_move() { int actualStep = total_step; if(target_type == BULLET_TARGET_UNIT) { Unit *unitPtr; if( unit_array.is_deleted(target_recno) || !(unitPtr = unit_array[target_recno]) || !unitPtr->is_visible() ) { // target lost/die, proceed to Bullet::process_move target_type = BULLET_TARGET_NONE; } else { // ---- calculate new target_x_loc, target_y_loc -----// target_x_loc = unitPtr->next_x_loc(); target_y_loc = unitPtr->next_y_loc(); // ---- re-calculate go_x, go_y ------// // go_x/y and origin2_x/y are pointing at the centre of the bullet bitmap // it is different from Bullet go_x = unitPtr->cur_x + ZOOM_LOC_WIDTH / 2; go_y = unitPtr->cur_y + ZOOM_LOC_HEIGHT /2; //---------- set bullet movement steps -----------// SpriteFrame *spriteFrame = cur_sprite_frame(); int adjX = spriteFrame->offset_x+spriteFrame->width/2; int adjY = spriteFrame->offset_y+spriteFrame->height/2; int xStep = abs(go_x - (cur_x+adjX))/speed; int yStep = abs(go_y - (cur_y+adjY))/speed; total_step = cur_step + MAX(xStep, yStep); // a homing bullet has a limited range, if the target go outside the // the limit, the bullet can't attack the target // in this case, actualStep is the number step from the source // to the target; total_step is the max_step // otherwise, actualStep is as same as total_step actualStep = total_step; if( total_step > max_step ) { total_step = max_step; // target_x_loc and target_y_loc is limited also target_x_loc = (cur_x + adjX) + (int)(go_x-(cur_x+adjX)) / (actualStep - total_step) / ZOOM_LOC_WIDTH; target_x_loc = (cur_y + adjY) + (int)(go_y-(cur_y+adjY)) / (actualStep - total_step) / ZOOM_LOC_HEIGHT; } } } // origin2_x = origin_x; // origin2_y = origin_y; // origin_x/y and origin2_x/y are pointing at the centre of the bullet bitmap // SpriteFrame *spriteFrame = cur_sprite_frame(); short adjX = spriteFrame->offset_x + spriteFrame->width/2; short adjY = spriteFrame->offset_y + spriteFrame->height/2; origin_x = cur_x + adjX; origin_y = cur_y + adjY; cur_x = origin_x + (int)(go_x-origin_x) / (actualStep + 1 - cur_step); cur_y = origin_y + (int)(go_y-origin_y) / (actualStep + 1 - cur_step); // cur_x, cur_y is temporary pointing at the centre of bullet bitmap // detect changing direction if( cur_step > 3 ) // not allow changing direction so fast set_dir(origin2_x, origin2_y, cur_x, cur_y); // change cur_x, cur_y to bitmap reference point spriteFrame= cur_sprite_frame(); adjX = spriteFrame->offset_x + spriteFrame->width/2; adjY = spriteFrame->offset_y + spriteFrame->height/2; cur_x -= adjX; cur_y -= adjY; cur_step++; //------- update frame id. --------// if( ++cur_frame > cur_sprite_move()->frame_count ) cur_frame = 1; //----- if the sprite has reach the destintion ----// if( cur_step > total_step ) { check_hit(); cur_action = SPRITE_DIE; // Explosion // ###### begin Gilbert 17/5 ########// // if it has die frame, adjust cur_x, cur_y to be align with the target_x_loc, target_y_loc if( sprite_info->die.first_frame_recno ) { next_x = cur_x = target_x_loc * ZOOM_LOC_WIDTH; next_y = cur_y = target_y_loc * ZOOM_LOC_HEIGHT; } // ###### end Gilbert 17/5 ########// cur_frame = 1; } // change of total_step may not call warn_target, so call more warn_target else if( total_step - cur_step <= 1 ) { warn_target(); } }
//--------- Begin of function Sprite::draw ---------// // void Sprite::draw() { //--------- draw sprite on the zoom window ---------// int needMirror; SpriteFrame* spriteFrame = cur_sprite_frame(&needMirror); update_abs_pos(spriteFrame); err_when( !sprite_info->res_bitmap.initialized() ); char* bitmapPtr = sprite_info->res_bitmap.read_imported(spriteFrame->bitmap_offset); //-------- check if the sprite is inside the view area --------// int x1 = abs_x1-World::view_top_x; // the sprite's position in the view window if( x1 <= -spriteFrame->width || x1 >= ZOOM_WIDTH ) // out of the view area, not even a slight part of it appears in the view area return; int y1 = abs_y1-World::view_top_y; if( y1 <= -spriteFrame->height || y1 >= ZOOM_HEIGHT ) return; //------- decide which approach to use for displaying -----// int x2 = abs_x2-World::view_top_x; int y2 = abs_y2-World::view_top_y; //---- only portion of the sprite is inside the view area ------// if( x1 < 0 || x2 >= ZOOM_WIDTH || y1 < 0 || y2 >= ZOOM_HEIGHT ) { if( needMirror ) // if this direction needed to be mirrored { if( !sprite_info->remap_bitmap_flag ) { vga_back.put_bitmap_area_trans_decompress_hmirror( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, MAX(0,x1)-x1, MAX(0,y1)-y1, MIN(ZOOM_WIDTH-1,x2)-x1, MIN(ZOOM_HEIGHT-1,y2)-y1 ); } else { vga_back.remap_bitmap_area_hmirror( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, vga.vga_color_table->get_table_array(), MAX(0,x1)-x1, MAX(0,y1)-y1, MIN(ZOOM_WIDTH-1,x2)-x1, MIN(ZOOM_HEIGHT-1,y2)-y1 ); } } else { if( !sprite_info->remap_bitmap_flag ) { vga_back.put_bitmap_area_trans_decompress( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, MAX(0,x1)-x1, MAX(0,y1)-y1, MIN(ZOOM_WIDTH-1,x2)-x1, MIN(ZOOM_HEIGHT-1,y2)-y1 ); } else { vga_back.remap_bitmap_area( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, vga.vga_color_table->get_table_array(), MAX(0,x1)-x1, MAX(0,y1)-y1, MIN(ZOOM_WIDTH-1,x2)-x1, MIN(ZOOM_HEIGHT-1,y2)-y1 ); } } } //---- the whole sprite is inside the view area ------// else { //------ mirror-bilting for certain directions ------// if( needMirror ) // if this direction needed to be mirrored { if( !sprite_info->remap_bitmap_flag ) { vga_back.put_bitmap_trans_decompress_hmirror( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr ); } else { vga_back.remap_bitmap_hmirror( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, vga.vga_color_table->get_table_array() ); } } else { if( !sprite_info->remap_bitmap_flag ) { vga_back.put_bitmap_trans_decompress( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr ); } else { vga_back.remap_bitmap( x1+ZOOM_X1, y1+ZOOM_Y1, bitmapPtr, vga.vga_color_table->get_table_array() ); } } } }