/* * 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 : OUNITA.CPP //Description : Object UnitArray #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NO_DEBUG_UNIT #undef err_when #undef err_here #undef err_if #undef err_else #undef err_now #define err_when(cond) #define err_here() #define err_if(cond) #define err_else #define err_now(msg) #undef DEBUG #endif //--------- Declare static functions ---------// static void put_profile(int y, char* dispDes, int dispValue); //--------- Begin of function UnitArray::UnitArray ---------// // // initArraySize - the initial size of this array. // UnitArray::UnitArray(int initArraySize) : SpriteArray(initArraySize) { } //----------- End of function UnitArray::UnitArray -----------// //--------- Begin of function UnitArray::init ---------// // void UnitArray::init() { //-------- initialize group selection parameter -------// cur_group_id = 1; cur_team_id = 1; selected_land_unit_count = 0; selected_sea_unit_count = 0; selected_air_unit_count = 0; idle_blocked_unit_reset_count = 0; selected_land_unit_array = NULL; selected_sea_unit_array = NULL; selected_air_unit_array = NULL; visible_unit_count = 0; mp_first_frame_to_select_caravan = 0; mp_first_frame_to_select_ship = 0; mp_pre_selected_caravan_recno = 0; mp_pre_selected_ship_recno = 0; //------------ init sprite_array ------------// SpriteArray::init(); } //----------- End of function UnitArray::init -----------// //--------- Begin of function UnitArray::add_unit ---------// // // unitId - the id. of the unit // nationRecno - the recno of the nation that the unit belongs to // [int] rankId - rank id. of the unit (none for non-human unit) // [int] unitLoyalty - loyalty of the unit (none for non-human unit) // [int] startXLoc, startYLoc - the starting location of the unit // (if startXLoc < 0, this is a unit for hire, and is not a unit of the game yet. init_sprite() won't be called for this unit) // (default: -1, -1) // [int] remoteAction - whether this is a remote action or not. // // return : - the recno of the unit added. // int UnitArray::add_unit(int unitId, int nationRecno, int rankId, int unitLoyalty, int startXLoc, int startYLoc) { //-------- create and initialize Unit -------// Unit* unitPtr = create_unit(unitId); //----------- add to SpriteArray ------------// unitPtr->init(unitId, nationRecno, rankId, unitLoyalty, startXLoc, startYLoc); //-------------------------------------------// return unitPtr->sprite_recno; } //----------- End of function UnitArray::add_unit -----------// //-------- Begin of function UnitArray::create_unit --------// // Unit* UnitArray::create_unit(int unitId) { Unit* unitPtr; UnitInfo* unitInfo = unit_res[unitId]; switch(unitId) { case UNIT_CARAVAN: unitPtr = new UnitCaravan; break; case UNIT_VESSEL: case UNIT_TRANSPORT: case UNIT_CARAVEL: case UNIT_GALLEON: unitPtr = new UnitMarine; break; case UNIT_EXPLOSIVE_CART: unitPtr = new UnitExpCart; break; default: if( unitInfo->is_monster ) unitPtr = new UnitMonster; else if( unitInfo->solider_id ) // if it is a vehicle unit unitPtr = new UnitVehicle; else if( god_res.is_god_unit(unitId) ) unitPtr = new UnitGod; else unitPtr = new Unit; } SpriteArray::add(unitPtr); // it set Sprite::sprite_recno return unitPtr; } //----------- End of function UnitArray::create_unit ---------// //-------- Begin of function UnitArray::unit_class_size --------// // // Return the size of the class. // int UnitArray::unit_class_size(int unitId) { UnitInfo* unitInfo = unit_res[unitId]; switch(unitId) { case UNIT_CARAVAN: return sizeof(UnitCaravan); case UNIT_VESSEL: case UNIT_TRANSPORT: case UNIT_CARAVEL: case UNIT_GALLEON: return sizeof(UnitMarine); case UNIT_EXPLOSIVE_CART: return sizeof(UnitExpCart); default: if( unitInfo->is_monster ) return sizeof(UnitMonster); else if( unitInfo->solider_id ) // if it is a vehicle unit return sizeof(UnitVehicle); else if( god_res.is_god_unit(unitId) ) return sizeof(UnitGod); else return sizeof(Unit); } } //----------- End of function UnitArray::unit_class_size ---------// //-------- Begin of function UnitArray::disappear_in_town --------// // // The unit disappear from the map because it has moved into a town. // void UnitArray::disappear_in_town(int unitRecno, int townRecno) { Unit* unitPtr = unit_array[unitRecno]; if( unitPtr->unit_mode == UNIT_MODE_REBEL ) rebel_array.settle_town(unitRecno, townRecno); del(unitRecno); // delete it from unit_array } //----------- End of function UnitArray::disappear_in_town ---------// //-------- Begin of function UnitArray::disappear_in_firm --------// // // The unit disappear from the map because it has moved into a town. // void UnitArray::disappear_in_firm(int unitRecno) { Unit* unitPtr = unit_array[unitRecno]; err_when( unitPtr->unit_mode == UNIT_MODE_REBEL ); // this shouldn't happen del(unitRecno); // delete it from unit_array } //----------- End of function UnitArray::disappear_in_firm ---------// //-------- Begin of function UnitArray::die --------// // void UnitArray::die(int unitRecno) { Unit* unitPtr = unit_array[unitRecno]; if( unitPtr->unit_mode == UNIT_MODE_REBEL ) rebel_array.drop_rebel_identity(unitRecno); unitPtr->die(); del(unitRecno); // delete it from unit_array } //----------- End of function UnitArray::die ---------// //--------- Begin of function UnitArray::draw_dot ---------// // // Draw 2x2 tiny squares on map window representing the location of the unit ---// // void UnitArray::draw_dot() { char* vgaBufPtr = vga_back.buf_ptr(); char* writePtr; int i, j, mapX, mapY; Unit* unitPtr; char* nationColorArray = nation_array.nation_color_array; char nationColor; int vgaBufPitch = vga_back.buf_pitch(); const unsigned int excitedColorCount = 4; char excitedColorArray[MAX_NATION+1][excitedColorCount]; short playerNationRecno = nation_array.player_recno; short lineFromX, lineFromY, lineToX, lineToY; int resultNodeRecno, resultNodeCount; ResultNode *resultNode1, *resultNode2; for( i = 0; i <= MAX_NATION; ++i ) { if( i == 0 || !nation_array.is_deleted(i) ) { char *remapTable = game.get_color_remap_table(i, 0); excitedColorArray[i][0] = remapTable[0xe0]; excitedColorArray[i][1] = remapTable[0xe1]; excitedColorArray[i][2] = remapTable[0xe2]; excitedColorArray[i][3] = remapTable[0xe3]; } else { excitedColorArray[i][0] = excitedColorArray[i][1] = excitedColorArray[i][2] = excitedColorArray[i][3] = (char) V_WHITE; } } int arraySize = size(); int lineColor; //### begin alex 27/10 ###// //------------- set boundary of anim_line to mini-map ------------// short animLineBoundX1 = anim_line.bound_x1; short animLineBoundY1 = anim_line.bound_y1; short animLineBoundX2 = anim_line.bound_x2; short animLineBoundY2 = anim_line.bound_y2; anim_line.bound_x1 = MAP_X1; anim_line.bound_y1 = MAP_Y1; anim_line.bound_x2 = MAP_X2; anim_line.bound_y2 = MAP_Y2; //#### end alex 27/10 ####// for(i=1; i<=arraySize; i++) { unitPtr = (Unit*)get_ptr(i); if( !unitPtr || !unitPtr->is_visible() || unitPtr->is_shealth()) continue; if( unitPtr->mobile_type == UNIT_SEA ) lineColor = V_WHITE; else lineColor = V_BLACK; //---------------- draw unit path in mini_map ------------// if(unitPtr->selected_flag && (config.show_unit_path & 2) ) { //#ifdef DEBUG //if(config.show_ai_info || unitPtr->nation_recno==playerNationRecno) //#else //if(unitPtr->nation_recno==playerNationRecno) //#endif if( config.show_ai_info || !playerNationRecno || unitPtr->is_nation(playerNationRecno) ) { resultNodeRecno = unitPtr->result_node_recno; resultNodeCount = unitPtr->result_node_count; if(resultNodeCount && resultNodeRecno<=resultNodeCount) { //-----------------------------------------------------------// if(unitPtr->cur_x_loc()!=unitPtr->go_x_loc() || unitPtr->cur_y_loc()!=unitPtr->go_y_loc()) { lineFromX = MAP_X1 + unitPtr->go_x_loc(); lineFromY = MAP_Y1 + unitPtr->go_y_loc(); lineToX = MAP_X1 + unitPtr->next_x_loc(); lineToY = MAP_Y1 + unitPtr->next_y_loc(); vga_back.line(lineFromX, lineFromY, lineToX, lineToY, lineColor); } //-----------------------------------------------------------// err_when(resultNodeRecno<1); resultNode1 = unitPtr->result_node_array + resultNodeRecno - 1; resultNode2 = resultNode1 + 1; for(j=resultNodeRecno+1; j<=resultNodeCount; j++, resultNode1++, resultNode2++) { lineFromX = MAP_X1 + resultNode2->node_x; lineFromY = MAP_Y1 + resultNode2->node_y; lineToX = MAP_X1 + resultNode1->node_x; lineToY = MAP_Y1 + resultNode1->node_y; vga_back.line(lineFromX, lineFromY, lineToX, lineToY, lineColor); } } //### begin alex 27/10 ###// //-------------- draw way_point on mini map ------------// if(unitPtr->way_point_count>1) { resultNode1 = unitPtr->way_point_array; resultNode2 = resultNode1+1; lineToX = MAP_X1 + resultNode1->node_x; lineToY = MAP_Y1 + resultNode1->node_y; for(j=unitPtr->way_point_count-1; j>0; j--, resultNode1++, resultNode2++) { lineFromX = MAP_X1 + resultNode2->node_x; lineFromY = MAP_Y1 + resultNode2->node_y; anim_line.draw_line(&vga_back, lineFromX, lineFromY, lineToX, lineToY, 0, 2); lineToX = lineFromX; lineToY = lineFromY; } } //#### end alex 27/10 ####// } } } //### begin alex 27/10 ###// //---------------- restore boundary setting of anim_line --------------// anim_line.bound_x1 = animLineBoundX1; anim_line.bound_y1 = animLineBoundY1; anim_line.bound_x2 = animLineBoundX2; anim_line.bound_y2 = animLineBoundY2; //#### end alex 27/10 ####// for(i=1; i<=arraySize; i++) { unitPtr = (Unit*)get_ptr(i); if( !unitPtr || !unitPtr->is_visible() || unitPtr->is_shealth()) continue; mapX = MAP_X1 + unitPtr->cur_x_loc(); mapY = MAP_Y1 + unitPtr->cur_y_loc(); if( mapX == MAP_WIDTH-1 ) mapX = MAP_WIDTH-2; if( mapY == MAP_HEIGHT-1 ) mapY = MAP_HEIGHT-2; writePtr = vgaBufPtr + mapY*vgaBufPitch + mapX; nationColor = unitPtr->cur_action != SPRITE_ATTACK ? nationColorArray[unitPtr->nation_recno] : excitedColorArray[unitPtr->nation_recno][sys.frame_count % excitedColorCount]; // ###### begin Gilbert 3/11 #######// int dotSize = unitPtr->mobile_type == UNIT_LAND ? 2 : 3; if( dotSize == 2 ) { if( writePtr[0] != UNEXPLORED_COLOR ) writePtr[0] = nationColor; if( writePtr[1] != UNEXPLORED_COLOR ) writePtr[1] = nationColor; if( writePtr[vgaBufPitch] != UNEXPLORED_COLOR ) writePtr[vgaBufPitch] = nationColor; if( writePtr[vgaBufPitch+1] != UNEXPLORED_COLOR ) writePtr[vgaBufPitch+1] = nationColor; } else if( dotSize == 3 ) { if( writePtr[-vgaBufPitch-1] != UNEXPLORED_COLOR ) writePtr[-vgaBufPitch-1] = nationColor; if( writePtr[-vgaBufPitch] != UNEXPLORED_COLOR ) writePtr[-vgaBufPitch] = nationColor; if( writePtr[-vgaBufPitch+1] != UNEXPLORED_COLOR ) writePtr[-vgaBufPitch+1] = nationColor; if( writePtr[-1] != UNEXPLORED_COLOR ) writePtr[-1] = nationColor; if( writePtr[0] != UNEXPLORED_COLOR ) writePtr[0] = nationColor; if( writePtr[1] != UNEXPLORED_COLOR ) writePtr[1] = nationColor; if( writePtr[vgaBufPitch-1] != UNEXPLORED_COLOR ) writePtr[vgaBufPitch-1] = nationColor; if( writePtr[vgaBufPitch] != UNEXPLORED_COLOR ) writePtr[vgaBufPitch] = nationColor; if( writePtr[vgaBufPitch+1] != UNEXPLORED_COLOR ) writePtr[vgaBufPitch+1] = nationColor; } // ###### end Gilbert 3/11 #######// } } //----------- End of function UnitArray::draw_dot -----------// //--------- Begin of function UnitArray::draw_profile ---------// void UnitArray::draw_profile() { #ifdef DEBUG static unsigned long lastDrawTime = m.get_time(); if(m.get_time() >= lastDrawTime + 1000) { //--------- update unit process profile ---------// last_unit_ai_profile_time = unit_ai_profile_time; unit_ai_profile_time = 0L; last_unit_profile_time = unit_profile_time; unit_profile_time = 0L; //--------- update seek path profile ---------// last_seek_path_profile_time = seek_path_profile_time; seek_path_profile_time = 0L; //--------- update sprite process profile --------// last_sprite_array_profile_time = sprite_array_profile_time; sprite_array_profile_time = 0L; //------- update sprite cur_action profile ---------// last_sprite_idle_profile_time = sprite_idle_profile_time; sprite_idle_profile_time = 0L; last_sprite_move_profile_time = sprite_move_profile_time; sprite_move_profile_time = 0L; last_sprite_wait_profile_time = sprite_wait_profile_time; sprite_wait_profile_time = 0L; last_sprite_attack_profile_time = sprite_attack_profile_time; sprite_attack_profile_time = 0L; last_unit_attack_profile_time = unit_attack_profile_time; unit_attack_profile_time = 0L; last_unit_assign_profile_time = unit_assign_profile_time; unit_assign_profile_time = 0L; lastDrawTime = m.get_time(); } //------------ draw unit process profile -------------// int y=ZOOM_Y1+120; put_profile(y , "Unit AI:" , last_unit_ai_profile_time ); put_profile(y+=20, "Unit:" , last_unit_profile_time ); put_profile(y+=20, "Sprite:" , last_sprite_array_profile_time ); put_profile(y+=20, "SeekPath:" , last_seek_path_profile_time ); put_profile(y+=20, "Sprite Idle:" , last_sprite_idle_profile_time ); put_profile(y+=20, "Sprite Move:" , last_sprite_move_profile_time ); put_profile(y+=20, "Sprite Wait:" , last_sprite_wait_profile_time ); put_profile(y+=20, "Sprite Attack:" , last_sprite_attack_profile_time ); put_profile(y+=20, "Unit Attack:" , last_unit_attack_profile_time ); put_profile(y+=20, "Unit Assign:" , last_unit_assign_profile_time ); #endif } //----------- End of function UnitArray::draw_profile -----------// //--------- Begin of static function put_profile ---------// // static void put_profile(int y, char* dispDes, int dispValue) { font_news.put( ZOOM_X1+10, y, dispDes ); font_news.put( ZOOM_X1+120, y, dispValue ); } //----------- End of static function put_profile -----------// //--------- Begin of function UnitArray::process ---------// // // This function is called every frame. // void UnitArray::process() { #define SYS_YIELD_INTERVAL 50 #define YEAR_FRAME_COUNT 365*FRAMES_PER_DAY // choose a value that is multiply of FRAMES_PER_DAY Unit* unitPtr; int i; int arraySize = size(); int sysFrameCount = int(sys.frame_count%FRAMES_PER_DAY); int yearFrameCount = int(sys.frame_count%YEAR_FRAME_COUNT); int compareI = arraySize%FRAMES_PER_DAY; if(compareI < sysFrameCount) compareI += FRAMES_PER_DAY; int sysYieldCount = arraySize - arraySize%SYS_YIELD_INTERVAL; for(i=arraySize; i; --i, compareI--) // for(i=arraySize; i>0; --i, compareI++) or //for(i=1; i<=arraySize; i++, compareI++) { //-------- system yield ---------// if(i==sysYieldCount) { sysYieldCount -= SYS_YIELD_INTERVAL; sys.yield(); } //-------------------------------// if(compareI == sysFrameCount) { compareI += FRAMES_PER_DAY; if( is_deleted(i) ) continue; unitPtr = (Unit*) get_ptr(i); //-------------- reset ignore_power_nation ------------// if(compareI==yearFrameCount && unitPtr->unit_id!=UNIT_CARAVAN) unitPtr->ignore_power_nation = 0; unitPtr->next_day(); // although this function is called every frame, next_day() & process_ai() is only called once per day if( is_deleted(i) ) continue; #ifdef DEBUG if(config.disable_ai_flag==0 && unitPtr->ai_unit) #else if( unitPtr->ai_unit ) #endif { #ifdef DEBUG unsigned long profileAiStartTime = m.get_time(); #endif unitPtr->process_ai(); #ifdef DEBUG unit_ai_profile_time += m.get_time() - profileAiStartTime; #endif } //----- if it's an independent unit -------// else if( !unitPtr->nation_recno && unitPtr->race_id && !unitPtr->spy_recno) unitPtr->think_independent_unit(); } } if(idle_blocked_unit_reset_count<50) idle_blocked_unit_reset_count++; // the ability to restart idle blocked attacking unit //------- process Sprite ---------// SpriteArray::process(); } //----------- End of function UnitArray::process -----------// //--------- Begin of function UnitArray::update_selected_trade_unit_info ---------// // update trade information of trading units if these units are selected // void UnitArray::update_selected_trade_unit_info() { short playerNationRecno = nation_array.player_recno; Unit *unitPtr; UnitMarine *marinePtr; if(remote.is_enable()) { for(int i=size(); i>0; --i) { if(is_deleted(i)) continue; unitPtr = (Unit*)get_ptr(i); if(!unitPtr->is_visible()) continue; switch(unitPtr->unit_id) { case UNIT_CARAVAN: if(mp_is_selected_caravan(i)) ((UnitCaravan*) unitPtr)->update_stop_and_goods_info(); break; case UNIT_VESSEL: case UNIT_CARAVEL: case UNIT_GALLEON: marinePtr = ((UnitMarine*) unitPtr); if(marinePtr->auto_mode && mp_is_selected_ship(i)) marinePtr->update_stop_and_goods_info(); break; default: break; } } } else if(selected_recno && !is_deleted(selected_recno)) { unitPtr = (Unit*)get_ptr(selected_recno); if(unitPtr->nation_recno==playerNationRecno || config.show_ai_info) { switch(unitPtr->unit_id) { case UNIT_CARAVAN: ((UnitCaravan*) unitPtr)->update_stop_and_goods_info(); break; case UNIT_VESSEL: case UNIT_CARAVEL: case UNIT_GALLEON: marinePtr = ((UnitMarine*) unitPtr); if(marinePtr->auto_mode) marinePtr->update_stop_and_goods_info(); break; default: break; } } } } //----------- End of function UnitArray::update_selected_trade_unit_info -----------// //----------- Begin of function UnitArray::return_camp -----------// // // Order all units that are currently selected to return to their // home camp. // void UnitArray::return_camp(int remoteAction, short *selectedUnitArray, int selectedCount) { Unit* unitPtr; if( !selectedUnitArray ) { if( !remoteAction && remote.is_enable() ) { selectedCount = 0; int i; for( i=unit_array.size() ; i>0 ; i-- ) { if( unit_array.is_deleted(i) ) continue; unitPtr = this->operator[](i); if( !unitPtr->selected_flag || !unitPtr->is_visible() ) continue; if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE) continue; if( !unitPtr->is_own() ) // only if the unit belongs to us (a spy is also okay if true_nation_recno is ours) continue; //---------------------------------// if( unitPtr->home_camp_firm_recno ) selectedCount++; } // packet structure : ... short *shortPtr = (short *) remote.new_send_queue_msg(MSG_UNITS_RETURN_CAMP, (1+selectedCount)*sizeof(short) ); *shortPtr = selectedCount; shortPtr++; int reCount = 0; for( i=unit_array.size() ; i>0 ; i-- ) { if( unit_array.is_deleted(i) ) continue; unitPtr = this->operator[](i); if( !unitPtr->selected_flag || !unitPtr->is_visible() ) continue; if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE) continue; if( !unitPtr->is_own() ) // only if the unit belongs to us (a spy is also okay if true_nation_recno is ours) continue; //---------------------------------// if( unitPtr->home_camp_firm_recno ) { err_when( reCount > selectedCount ); *shortPtr = i; shortPtr++; reCount++; } } err_when( reCount != selectedCount ); return; } else { for( int i=unit_array.size() ; i>0 ; i-- ) { if( unit_array.is_deleted(i) ) continue; unitPtr = this->operator[](i); if( !unitPtr->selected_flag || !unitPtr->is_visible() ) continue; if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE) continue; if( !unitPtr->is_own() ) // only if the unit belongs to us (a spy is also okay if true_nation_recno is ours) continue; //---------------------------------// if( unitPtr->home_camp_firm_recno ) unitPtr->return_camp(); } } } else { if( !remoteAction && remote.is_enable() ) { if( selectedCount > 0) { // packet structure : ... short *shortPtr = (short *) remote.new_send_queue_msg(MSG_UNITS_RETURN_CAMP, (1+selectedCount)*sizeof(short) ); *shortPtr = selectedCount; shortPtr++; memcpy(shortPtr, selectedUnitArray, sizeof(short)*selectedCount ); } return; } else { for( int j = selectedCount-1; j >= 0; j--) { // descending unit recno int i = selectedUnitArray[j]; if( unit_array.is_deleted(i) ) continue; unitPtr = this->operator[](i); if( !unitPtr->is_visible() ) continue; if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE) continue; //---------------------------------// if( unitPtr->home_camp_firm_recno ) unitPtr->return_camp(); } } } } //----------- End of function UnitArray::return_camp -----------// #ifdef DEBUG //------- Begin of function UnitArray::operator[] -----// Unit* UnitArray::operator[](int recNo) { Unit* unitPtr = (Unit*) get_ptr(recNo); if( !unitPtr ) err.run( "UnitArray[] is deleted" ); return unitPtr; } //--------- End of function UnitArray::operator[] ----// #endif //------- Begin of function UnitArray::is_deleted -----// int UnitArray::is_deleted(int recNo) { Unit *unitPtr = (Unit*) get_ptr(recNo); if( !unitPtr ) return 1; if( unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE ) return 1; return 0; } //--------- End of function UnitArray::is_deleted ----// //------- Begin of function UnitArray::is_truly_deleted -----// int UnitArray::is_truly_deleted(int recNo) { return get_ptr(recNo) == NULL; } //--------- End of function UnitArray::is_truly_deleted ----//