//--------- Begin of function BulletProgram::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 BulletProgram::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType) { Bullet::init(parentType, parentRecno, targetXLoc, targetYLoc, targetMobileType); cur_step = 0; BaseObj *baseObjPtr = base_obj_array[parent_base_obj_recno]; Unit *parentUnit; // for fixed total_step of bullet, set sprite.dbf's speed // // else total_step = distance to target / unitattk.dbf's bullet_speed // // start animation bullet_running die_animation // delay_step total_step // // bullet_delay in if sprite.dbf's no. of frame filled // sprite.dbf & speed > 0, take in sframe.dbf // unitattk.dbf it else use // distance to // calculate if (sprite_info->speed > 0) total_step = sprite_info->speed; if( (parentUnit = baseObjPtr->cast_to_Unit()) ) { // delay obtained from unitattk.dbf // AttackInfo* attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack; delay_step = attackInfo->bullet_delay; } else { // delay obtained from sprite.dbf if the attacker is not a unit // delay_step = sprite_info->bullet_delay; } }
BaseObj::BaseObj(BaseObj *parent, const char *name) { _name = STRDUP(name); _displayName = NULL; _details = NULL; _parent = parent; _init_children = false; _init_attributes = false; _children = NULL; _numChildren = 0; _numActions = 0; _numAttributes = 0; _actions = NULL; _attributes = NULL; _lastActionName = NULL; _lastActionOutput = NULL; _lastActionStatus = 0; AddToParent(); BaseObj *p = _parent; while (p) { p->NotifyCreate(this); p = p->_parent; } }
BaseObj::~BaseObj() { int i; DeleteChildren(); DeleteFromParent(); BaseObj *parent = _parent; while (parent) { parent->NotifyDelete(this); parent = parent->_parent; } for (i = 0; i < _numAttributes; i++) { delete _attributes[i]->ReferenceName; delete _attributes[i]->Value; delete _attributes[i]->DisplayName; delete _attributes[i]->DisplayValue; delete _attributes[i]->DefaultValue; delete _attributes[i]->DisplayDefaultValue; delete _attributes[i]->Help; delete _attributes[i]->ContextualHelp; delete _attributes[i]->Listing; delete _attributes[i]->Dependancies; delete _attributes[i]; } delete []_attributes; for (i = 0; i < _numActions; i++) { delete _actions[i]->ReferenceName; delete _actions[i]->DisplayName; delete _actions[i]->Nmemonic; delete _actions[i]->AcceleratorText; delete _actions[i]->Accelerator; delete _actions[i]->Help; delete _actions[i]->ContextualHelp; delete _actions[i]->Dependancies; delete _actions[i]; } delete []_actions; delete []_children; free(_lastActionName); delete [] _lastActionOutput; free(_details); free(_displayName); free(_name); }
void Swarm::updateSwarm(real dt, SwarmNode* next, BaseObj& collision, std::vector<Bullet*> bulletList) { if (next->data.m_bAlive) { XMVECTOR pos = XMLoadFloat3(&next->data.m_vPos); XMVECTOR playerTarget = XMLoadFloat3(&m_pLead->data.m_vTarget); XMVECTOR distance = XMVector3Length(pos - playerTarget); if (XMVectorGetX(distance) < 120.0f || XMVectorGetY(distance) < 120.0f || false == m_pLead->data.m_bAlive) next->data.m_vTarget = m_pLead->data.m_vTarget; else next->data.m_vTarget = next->parent->data.m_vPos; // check if we hit the player next->data.update(dt); next->data.checkCollision(collision); if (next->data.m_bHit) next->data.reduceHealth(collision.getDamage()); if (next->data.m_fLife < 0.0f) { dynamic_cast<Player&>(collision).increasePoints(5.0f); collision.reduceHealth(next->data.m_fDamage); next->data.m_bAlive = false; //collision.increasePoints(20.0f); } // check if a bullet hit the alien for (unsigned int i = 0; i < bulletList.size(); ++i) { next->data.checkCollision(*bulletList[i]); if (next->data.m_bHit && next->data.m_bAlive) { next->data.reduceHealth(bulletList[i]->getDamage()); bulletList[i]->setState(Bullet::BState_Hit); } if (next->data.m_fLife < 0.0f) { dynamic_cast<Player&>(collision).increasePoints(25.0f); next->data.m_bAlive = false; } } } if (next->ltChild) updateSwarm(dt, next->ltChild, collision, bulletList); if (next->rtChild) updateSwarm(dt, next->rtChild, collision, bulletList); }
//--------- Begin of function Sprite::process_die --------// // // return : <int> 1 - dying animation completes. // 0 - still dying // int Sprite::process_die() { //--------- next frame ---------// // if( sys.frame_count%2 == 0 ) // { if (cur_frame == 1) { BaseObj *baseObj = base_obj_array[base_obj_recno]; Unit* unitPtr = baseObj->cast_to_Unit(); if (unitPtr) unitPtr->add_die_effect(); } se_res.sound(cur_x_loc(), cur_y_loc(), cur_frame, 'S',sprite_id,"DIE"); if( ++cur_frame > sprite_info->die.frame_count ) return 1; // } return 0; }
//--------- Begin of function UnitOrder::set ---------// // void UnitOrder::set(int newMode, int newPara, int newXLoc, int newYLoc) { mode = newMode; para = newPara; loc_x = newXLoc; loc_y = newYLoc; ai_action_id = 0; name_id = 0; //--- set name_id to Unit::name_id if the order is attacking a unit. This is for verifying attack target ---// if( mode==UNIT_ATTACK ) { BaseObj* targetObj = base_obj_array[para]; if( targetObj->obj_type == OBJ_UNIT ) name_id = targetObj->cast_to_Unit()->name_id; } }
// --------- 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); }
void Swarm::updateSwarm(Fugui::real dt, BaseObj& collision, std::vector<Bullet*> bulletList) { if (m_pLead) { if (m_pLead->data.m_bAlive) { m_pLead->data.update(dt); m_pLead->data.checkCollision(collision); if (m_pLead->data.m_bHit) m_pLead->data.m_fLife -= collision.getDamage(); if (m_pLead->data.m_fLife < 0.0f) { dynamic_cast<Player&>(collision).increasePoints(5.0f); m_pLead->data.m_bAlive = false; //collision.increasePoints(20.0f); } } // check if a bullet hit the alien for (unsigned int i = 0; i < bulletList.size(); ++i) { m_pLead->data.checkCollision(*bulletList[i]); if (m_pLead->data.m_bHit && m_pLead->data.m_bAlive) { m_pLead->data.reduceHealth(bulletList[i]->getDamage()); bulletList[i]->setState(Bullet::BState_Hit); } if (m_pLead->data.m_fLife < 0.0f) { dynamic_cast<Player&>(collision).increasePoints(25.0f); m_pLead->data.m_bAlive = false; } } if (m_pLead->ltChild) updateSwarm(dt, m_pLead->ltChild, collision, bulletList); if (m_pLead->rtChild) updateSwarm(dt, m_pLead->rtChild, collision, bulletList); } }
// ----- begin of function ScenarioEditor::disp_monster_view ------// // void ScenarioEditor::disp_monster_view() { if( power.command_id ) return; int drawMarker = 0; int validAction = 0; int markerX1, markerY1, markerX2, markerY2; int xLoc, yLoc; char mobileType; if( mouse.in_area(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2) ) { // destruction marker if there is a human Location *locPtr = power.test_detect(mouse.cur_x, mouse.cur_y, &mobileType, &xLoc, &yLoc); if( locPtr && locPtr->base_obj_recno() ) { BaseObj *baseObj = base_obj_array[locPtr->base_obj_recno()]; drawMarker = 1; validAction = 1; markerX1 = baseObj->obj_loc_x1(); markerY1 = baseObj->obj_loc_y1(); markerX2 = baseObj->obj_loc_x2(); markerY2 = baseObj->obj_loc_y2(); } // construction marker else if( world.zoom_matrix->get_detect_location(mouse.cur_x, mouse.cur_y, &xLoc, &yLoc, NULL) ) { locPtr = world.get_loc( xLoc, yLoc ); if( unit_or_struct == 0 && !vbrowse_unit_id.none_record ) { // put unit monster_unit_id_array[monster_unit_id_browse_recno-1] // on (xLoc, yLoc) int unitId = monster_unit_id_array[monster_unit_id_browse_recno-1]; UnitInfo *unitInfo = unit_res[unitId]; SpriteInfo *spriteInfo = sprite_res[unitInfo->sprite_id]; if( world.check_unit_space(xLoc, yLoc, xLoc+spriteInfo->loc_width-1, yLoc+spriteInfo->loc_height-1, unitInfo->mobile_type) ) { validAction = 1; } markerX1 = xLoc; markerY1 = yLoc; markerX2 = xLoc + spriteInfo->loc_width -1; markerY2 = yLoc + spriteInfo->loc_height -1; drawMarker = markerX2 < MAX_WORLD_X_LOC && markerY2 < MAX_WORLD_Y_LOC; } else if( unit_or_struct == 1 && !vbrowse_firm_build.none_record ) { err_when( monster_firm_group_array[monster_firm_group_browse_recno-1] == 0 ); // put firm group monster_firm_group_array[monster_firm_group_browse_recno] // on (xLoc, yLoc) FirmGroup *firmGroup = firm_res.get_group(monster_firm_group_array[monster_firm_group_browse_recno-1]); if( world.can_build_firm( xLoc, yLoc, firmGroup->firm_id, 0) ) { validAction = 1; } markerX1 = xLoc; markerY1 = yLoc; markerX2 = xLoc + firm_res[firmGroup->firm_id]->loc_width - 1; markerY2 = yLoc + firm_res[firmGroup->firm_id]->loc_height - 1; drawMarker = markerX2 < MAX_WORLD_X_LOC && markerY2 < MAX_WORLD_Y_LOC; } } } // ------ draw marker -------// if( drawMarker ) { draw_marker( validAction, markerX1, markerY1, markerX2, markerY2 ); } }
//--------- Begin of function Unit::process_ai --------// // // [int] forceExecute - whether force execute all AI functions // without checking day interavals. // (default: 0) // void Unit::process_ai() { if( unit_mode ) // let functions in OUN_MODE.CPP process units in specific modes return; err_when( !nation_recno ); //------ the behavior_mode of AI units is aggressive ------// behavior_mode = UNIT_AGGRESSIVE; //------- handle Seek Path failures ------// if( ai_handle_seek_path_fail() ) return; //--- if it's a spy from other nation, don't control it ---// if( spy_recno && true_nation_recno() != nation_recno ) { //--- a random chance of the AI catching the spy and resign it ---// if( is_visible() && misc.random(365 * FRAMES_PER_DAY)==0 ) // if the unit stay outside for one year, it will get caught { resign(COMMAND_AI); return; } if( !spy_array[spy_recno]->notify_cloaked_nation_flag ) // if notify_cloaked_nation_flag is 1, the nation will take it as its own spies return; } //----- think about rewarding this unit -----// if( race_id && rank_id != RANK_KING && info.game_date%5 == sprite_recno%5 ) { think_reward(); } //-----------------------------------------// if( !is_visible() ) return; //----- think about using items -------// if( think_use_item() ) return; //---- King flees under attack or surrounded by enemy ---// if( race_id && rank_id==RANK_KING ) { if( think_king_flee() ) return; } //---- General flees under attack or surrounded by enemy ---// if( race_id && rank_id==RANK_GENERAL && info.game_date%7 == sprite_recno%7 ) { if( think_general_flee() ) return; } //---- stop attacking a town with zero resistance ----// if( cur_order.mode==UNIT_ATTACK && nation_recno) { if( !base_obj_array.is_deleted(cur_order.para) ) { BaseObj* baseObj = base_obj_array[cur_order.para]; if( baseObj->cast_to_Town() && baseObj->cast_to_Town()->nation_recno==0 && baseObj->cast_to_Town()->resistance(nation_recno) < 1 ) { stop_order(); return; } } } //------ if the unit is not stop right now ------// if( !is_all_stop() ) { think_stop_chase(); return; } //-----------------------------------------// if( mobile_type==UNIT_LAND ) { if( ai_escape_fire() ) return; } //---------- if this is your spy --------// if( spy_recno && true_nation_recno()==nation_recno ) think_spy_action(); //----- if this unit is on a attack mission ----// if( is_all_stop() && in_ai_attack_mission ) { if( ai_attack_next_target() ) return; } //------ if this unit is from a camp --------// if( home_camp_firm_recno ) { FirmCamp* firmCamp; FirmMonsterFortress* firmMonsterFortress; int rc = 0; if( firm_array.is_deleted(home_camp_firm_recno) ) { rc = 0; } if( (firmCamp = firm_array[home_camp_firm_recno]->cast_to_FirmCamp()) ) { if( rank_id == RANK_SOLDIER ) rc = firmCamp->soldier_count < MAX_SOLDIER; else rc = !firmCamp->overseer_recno; } else if( (firmMonsterFortress = firm_array[home_camp_firm_recno]->cast_to_FirmMonsterFortress()) ) { rc = (unit_id == firmMonsterFortress->support_unit_id && !firmMonsterFortress->is_extra_builder_full()) || !firmMonsterFortress->is_soldier_full(); } else { err_here(); } if( rc ) { if( return_camp() ) return; } home_camp_firm_recno = 0; // the camp is already occupied by somebody } //------- if the unit is idle ------------// if( is_all_stop() ) { if( race_id && rank_id==RANK_KING ) { if( is_human() ) think_king_action(); else think_normal_monster_action(); } else if( race_id && rank_id==RANK_GENERAL ) { think_general_action(); } else { int unitClass = unit_res[unit_id]->unit_class; //------ if this unit is a weapon ------// // ######### begin Gilbert 24/3 ########// // BUGHERE : monster weapon was UNIT_CLASS_MONSTER but now UNIT_CLASS_MONS_WEAPON if( unitClass == UNIT_CLASS_WEAPON || unitClass == UNIT_CLASS_MONS_WEAPON ) // ######### end Gilbert 24/3 ########// { if( info.game_date%15 == sprite_recno%15 ) // don't call too often as the action may fail and it takes a while to call the function each time { think_weapon_action(); //-- ships AI are called in UnitMarine --// } } //------ if this unit is a monster ------// else if( unitClass == UNIT_CLASS_MONSTER || unitClass == UNIT_CLASS_INSECT || unitClass == UNIT_CLASS_ANIMAL ) { //--- if previous attempts for new action failed, don't call think_normal_human_action() so frequently then ---// if( ai_no_suitable_action ) { if( info.game_date%15 != sprite_recno%15 ) // don't call too often as the action may fail and it takes a while to call the function each time return; } if( !think_normal_monster_action() ) { ai_no_suitable_action = true; // set this flag so think_normal_human_action() won't be called continously ai_move_to_nearby_firm(FIRM_LAIR); } } //------ if this unit is a human ------// else if( unitClass == UNIT_CLASS_HUMAN ) { //--- if previous attempts for new action failed, don't call think_normal_human_action() so frequently then ---// if( ai_no_suitable_action ) { if( info.game_date%15 != sprite_recno%15 ) // don't call too often as the action may fail and it takes a while to call the function each time return; } if( !think_normal_human_action() ) { ai_no_suitable_action = true; // set this flag so think_normal_human_action() won't be called continously // if( !leader_unit_recno ) // only when the unit is not led by a commander // resign(COMMAND_AI); // else ai_move_to_nearby_town(); } } //---- if this unit is a wagon -----// else if( unitClass == UNIT_CLASS_WAGON ) { think_assign_human_to_town(); } } } }
// --------- begin of function BulletHoming::process_move --------// void BulletHoming::process_move() { int actualStep = total_step; if( base_obj_array.is_deleted(target_base_obj_recno) ) { target_base_obj_recno = 0; } else { BaseObj *baseObj = base_obj_array[target_base_obj_recno]; Unit *unitPtr = baseObj->cast_to_Unit(); if( unitPtr && unitPtr->is_visible() ) { // ---- 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 + LOCATE_WIDTH / 2; go_y = unitPtr->cur_y + LOCATE_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) / LOCATE_WIDTH; target_x_loc = (cur_y + adjY) + (int)(go_y-(cur_y+adjY)) / (actualStep - total_step) / LOCATE_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 * LOCATE_WIDTH; next_y = cur_y = target_y_loc * LOCATE_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(); } }
void UnitGroup::exe_assign(int destXLoc, int destYLoc, int targetMobileType, int actionNationRecno) { //---------------------------------------// Unit* unitPtr; int locX, locY; int right = 0; int left = 0; int midX = 0; int top = 0; int bottom = 0; int midY = 0; if(size() == 1) { unitPtr = get_unit(1); unitPtr->set_no_longer_in_formation(); unitPtr->assign(destXLoc, destYLoc, actionNationRecno); return; } Location* locPtr; locPtr = world.get_loc(destXLoc, destYLoc); int baseObjRecno = locPtr->base_obj_recno(targetMobileType); // ###### begin Gilbert 6/5 #######// if( !baseObjRecno ) return; // ###### end Gilbert 6/5 #######// BaseObj* thePlace = base_obj_array[baseObjRecno]; int destWidth = thePlace->obj_loc_width(); int destHeight = thePlace->obj_loc_height(); for(int i = 1; i<=size(); i++) { unitPtr = get_unit(i); unitPtr->set_no_longer_in_formation(); locX = unitPtr->next_x_loc(); locY = unitPtr->next_y_loc(); if(locX < destXLoc) //left left++; else if(locX > destXLoc+destWidth-1) //right right++; else midX++; if(locY < destYLoc) //top top++; else if(locY > destYLoc+destHeight-1) //bottom bottom++; else midY++; } if(!left && !midX) //all at right side { run_action( destXLoc, destYLoc, UNIT_ASSIGN, baseObjRecno ); return; } if(!right && !midX) //all at left side { run_action( destXLoc, destYLoc, UNIT_ASSIGN, baseObjRecno ); return; } if(!top && !midY) //all at bottom side { run_action( destXLoc, destYLoc, UNIT_ASSIGN, baseObjRecno); return; } if(!bottom && !midY) //all at top side { run_action(destXLoc, destYLoc, UNIT_ASSIGN, baseObjRecno); return; } for(i=1; i<=size(); i++) { unitPtr = get_unit(i); unitPtr->assign(destXLoc, destYLoc, actionNationRecno); } }
void UnitGroup::exe_attack(int targetObjRecno) { BaseObj *targetObj = base_obj_array[targetObjRecno]; int targetWidth = targetObj->obj_loc_width(); int targetHeight = targetObj->obj_loc_height(); int targetLocX = targetObj->obj_loc_x1(); int targetLocY = targetObj->obj_loc_y1(); /* int testLocX, testLocY; int index, unitIndex; int maxWidth=0, maxHeight=0; Unit* unitPtr; int w, h; int rangeAttack=0, closeAttack=0; int minAttackRange = 0; int distance; Unit** arrayForRangeAttack=NULL, **arrayForCloseAttack=NULL; int numberAttacking = 0; */ //--looking for the maximum range, size of the units ---// //--and counting how many units will do range attack and close attack respectively---// /* for(int i=1; i<=size(); i++) { unitPtr = get_unit(i); if(!unitPtr->can_attack()) continue; //---------------------------------------------// if(unitPtr->cur_action == SPRITE_ATTACK && unitPtr->cur_order.para == targetObjRecno) { numberAttacking++; continue; } // ##### begin Gilbert 4/11 ######// // distance = unitPtr->cal_distance(targetLocX, targetLocY, targetWidth, targetHeight); distance = unitPtr->area_distance(targetObj); // ##### end Gilbert 4/11 ######// unitPtr->choose_best_attack_mode(distance, targetObj->obj_mobile_type()); if(unitPtr->obj_loc_width() > maxWidth) maxWidth = unitPtr->obj_loc_width(); if(unitPtr->obj_loc_height() > maxHeight) maxHeight = unitPtr->obj_loc_height(); if((unitPtr->attack_range() < minAttackRange) && (unitPtr->attack_range()>1)) minAttackRange = unitPtr->attack_range(); if(unitPtr->attack_range() > 1) rangeAttack++; else closeAttack++; } //---------------------------------------------------------// // err_when(!rangeAttack && !closeAttack); if(!rangeAttack && !closeAttack) return; if(rangeAttack) arrayForRangeAttack = (Unit**) mem_add(sizeof(Unit*)*rangeAttack); if(closeAttack) arrayForCloseAttack = (Unit**) mem_add(sizeof(Unit*)*closeAttack); int iRa = 0, iCa = 0; //---- separate the units into two arrays by means of their attacking mode ---// for(i=1; i<=size(); i++) { unitPtr = get_unit(i); if(!unitPtr->can_attack()) continue; if(unitPtr->cur_action == SPRITE_ATTACK && unitPtr->cur_order.para == targetObjRecno) continue; if(unitPtr->attack_range()>1) arrayForRangeAttack[iRa++] = unitPtr; else arrayForCloseAttack[iCa++] = unitPtr; } err_when(!maxWidth); err_when(!maxHeight); //----- assign a good location for the units to undergo range attack -----// if(rangeAttack) { int xLoc1 = max(targetLocX-minAttackRange, 0); int yLoc1 = max(targetLocY-minAttackRange, 0); int xLoc2 = min(targetLocX+targetWidth-1+minAttackRange, MAX_WORLD_X_LOC-1); int yLoc2 = min(targetLocY+targetHeight-1+minAttackRange, MAX_WORLD_Y_LOC-1); int checkXLoc, checkYLoc; unitIndex = 0; unitPtr = arrayForRangeAttack[unitIndex]; //-------- checking for surrounding location ----------// for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++) { if(unitPtr->can_move(checkXLoc, yLoc1)) { unitPtr->attack_loc_offset_x = checkXLoc-targetLocX; unitPtr->attack_loc_offset_y = yLoc1-targetLocY; if(unitPtr->obj_loc_width()>1) checkXLoc += (unitPtr->obj_loc_width()-1); if(unitIndex<rangeAttack-1) unitPtr = arrayForRangeAttack[++unitIndex]; else break; } } if(unitIndex < rangeAttack) { for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++) { if(unitPtr->can_move(xLoc1, checkYLoc)) { unitPtr->attack_loc_offset_x = xLoc1-targetLocX; unitPtr->attack_loc_offset_y = checkYLoc-targetLocY; if(unitPtr->obj_loc_height() > 1) checkYLoc += (unitPtr->obj_loc_height()-1); if(unitIndex < rangeAttack-1) unitPtr = arrayForRangeAttack[++unitIndex]; else break; } } } if(unitIndex < rangeAttack) { for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++) { if(unitPtr->can_move(checkXLoc, yLoc2)) { unitPtr->attack_loc_offset_x = checkXLoc-targetLocX; unitPtr->attack_loc_offset_y = yLoc2-targetLocY; if(unitPtr->obj_loc_width() > 1) checkXLoc+= (unitPtr->obj_loc_width()-1); if(unitIndex < rangeAttack-1) unitPtr= arrayForRangeAttack[++unitIndex]; else break; } } } if(unitIndex < rangeAttack) { for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++) { if(unitPtr->can_move(xLoc2, checkYLoc)) { unitPtr->attack_loc_offset_x = xLoc2-targetLocX; unitPtr->attack_loc_offset_y = checkYLoc-targetLocY; if(unitPtr->obj_loc_height() > 1) checkYLoc+=(unitPtr->obj_loc_height()-1); if(unitIndex < rangeAttack-1) unitPtr = arrayForRangeAttack[++unitIndex]; else break; } } } if(unitIndex < rangeAttack) { for(; unitIndex<rangeAttack; unitIndex++) { unitPtr = arrayForRangeAttack[unitIndex]; //--settting attack_loc_offset_? to 0 will make them cannot attack --// unitPtr->attack_loc_offset_x = 0; unitPtr->attack_loc_offset_y = 0; } } } //---- finding a good location for the units undergoing close attack -----// if(closeAttack) { unitIndex = 0; unitPtr = arrayForCloseAttack[unitIndex]; if((testLocY=targetLocY-maxHeight) >= 0) //has top edge { w = unitPtr->obj_loc_width(); while(w>=0) { if(targetLocX >= w) { index = -w; break; } w--; } err_when(index>0); for(; index<targetWidth; index++) { if(unitPtr->can_move(targetLocX+index, testLocY)) { unitPtr->attack_loc_offset_x = index; unitPtr->attack_loc_offset_y = -maxHeight; if(unitPtr->obj_loc_width() > 1) index += (unitPtr->obj_loc_width()-1); if(unitIndex < closeAttack-1) unitPtr = arrayForCloseAttack[++unitIndex]; //get_next_unit else break; } } } if((unitIndex < closeAttack) && ((testLocX = targetLocX + targetWidth) <= MAX_WORLD_X_LOC-maxWidth)) //has right edge { h = unitPtr->obj_loc_height(); while(h>=0) { if(targetLocY >= h) { index = -h; break; } h--; } err_when(index>0); for(; index<targetHeight; index++) { if(unitPtr->can_move(testLocX, targetLocY+index)) { unitPtr->attack_loc_offset_x = targetWidth; unitPtr->attack_loc_offset_y = index; if(unitPtr->obj_loc_height() > 1) index += (unitPtr->obj_loc_height()-1); if(unitIndex < closeAttack-1) unitPtr = arrayForCloseAttack[++unitIndex]; //get next unit else break; } } } if((unitIndex < closeAttack) && ((testLocY = targetLocY + targetHeight) <= MAX_WORLD_Y_LOC-maxHeight)) //has bottom edge { w = unitPtr->obj_loc_width(); while(w>=0) { if(targetLocX+targetWidth<=MAX_WORLD_X_LOC-w) { index = targetWidth-(unitPtr->obj_loc_width()-w); break; } w--; } for(; index>=0; index--) { if(unitPtr->can_move(targetLocX+index, testLocY)) { unitPtr->attack_loc_offset_x = index; unitPtr->attack_loc_offset_y = targetHeight; if(unitIndex < closeAttack-1) { unitPtr = arrayForCloseAttack[++unitIndex]; if(unitPtr->obj_loc_width() > 1) index -= (unitPtr->obj_loc_width()-1); } else break; } } } if(unitIndex < closeAttack && ((testLocX = targetLocX-maxWidth) >=0 )) //has left edge { h = unitPtr->obj_loc_height(); while(h>=0) { if(targetLocY+targetHeight<=MAX_WORLD_Y_LOC-h) { index = targetHeight-(unitPtr->obj_loc_height()-h); break; } h--; } for(; index>=0; index--) { if(unitPtr->can_move(testLocX, targetLocY+index)) { unitPtr->attack_loc_offset_x = -1; unitPtr->attack_loc_offset_y = index; if(unitIndex < closeAttack-1) { unitPtr = arrayForCloseAttack[++unitIndex]; if(unitPtr->obj_loc_height() > 1) index -= (unitPtr->obj_loc_height()-1); } else break; } } } //----for those who cannot find a good position, cannot attack //---- setting the attack_loc_offset_? to 0 means they cannot attack -----// if(unitIndex < closeAttack) { while(unitIndex < closeAttack-1) { unitPtr->attack_loc_offset_x = 0; unitPtr->attack_loc_offset_y = 0; unitPtr = arrayForCloseAttack[++unitIndex]; } unitPtr->attack_loc_offset_x = 0; unitPtr->attack_loc_offset_y = 0; } } */ cluster_units_for_attack(targetObjRecno, targetLocX, targetLocY, targetWidth, targetHeight); /* if(arrayForRangeAttack) mem_del(arrayForRangeAttack); if(arrayForCloseAttack) mem_del(arrayForCloseAttack); */ }
//----- Begin of function Nation::consider_military_aid -----// // int Nation::consider_military_aid(TalkMsg* talkMsg) { Nation* fromNation = nation_array[talkMsg->from_nation_recno]; NationRelation* fromRelation = get_relation(talkMsg->from_nation_recno); //----- don't aid too frequently ------// if( info.game_date < fromRelation->last_military_aid_date + 200 - pref_allying_tendency ) return 0; //------- only when the AI relation >= 60 --------// if( fromRelation->ai_relation_level < 60 ) return 0; //--- if the requesting nation is not at war now ----// if( !fromNation->is_at_war() ) return 0; //---- can't aid if we are at war ourselves -----// if( is_at_war() ) return 0; //--- if the nation is having a financial difficulty, it won't agree ---// if( cash < 2000 * pref_cash_reserve / 100 ) return 0; //----- can't aid if we are too weak ourselves ---// if( ai_general_count*10 + total_human_count + total_monster_count < 100-pref_military_courage/2 ) { return 0; } //----- see what units are attacking the nation -----// if( unit_array.is_deleted(fromNation->last_attacker_obj_recno) ) return 0; BaseObj* baseObj = base_obj_array[ fromNation->last_attacker_obj_recno ]; if( baseObj->nation_recno == nation_recno ) // if it's our own units return 0; if( baseObj->nation_recno == 0 ) return 0; if( !baseObj->is_visible() ) return 0; //------ only attack if it's a common enemy to us and our ally -----// if( get_relation(baseObj->nation_recno)->status != RELATION_HOSTILE ) return 0; //------- calculate the combat level of the target units there ------// int hasWar; int targetCombatLevel = mobile_defense_combat_level( baseObj->obj_loc_x1(), baseObj->obj_loc_y1(), baseObj->nation_recno, 0, hasWar ); if( ai_attack_target(baseObj->obj_loc_x1(), baseObj->obj_loc_y1(), targetCombatLevel, 0, 1 ) ) //0-not defense mode, 1-just move to flag { fromRelation->last_military_aid_date = info.game_date; return 1; } return 0; }