widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #04860
[Merge] lp:~widelands-dev/widelands/bug-1523165 into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/bug-1523165 into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #1523165 in widelands: "ai malfunctions after introduction of difficulty levels"
https://bugs.launchpad.net/widelands/+bug/1523165
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1523165/+merge/280397
This is part of changes I made in ai_ship_fix - fixing upgrading of productionsites and management of trainingsites.
I will keep working on ai_ship_tweaks branch, but this can be approved and merged indepedently of ship-related stuff.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1523165 into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2015-12-06 19:57:49 +0000
+++ src/ai/defaultai.cc 2015-12-12 20:55:58 +0000
@@ -70,7 +70,7 @@
// this is intended for map developers, by default should be off
constexpr bool kPrintStats = false;
-constexpr int kPersistentData = 0; //int16_t
+constexpr int kPersistentData = 0; //int16_t & bools
constexpr int kMilitLoneliness = 1;
constexpr int kAttacker = 2;
constexpr int kAttackMargin = 0; //uint32_t
@@ -134,6 +134,7 @@
ts_advanced_count_(0),
ts_advanced_const_count_(0),
ts_without_trainers_(0),
+ highest_nonmil_prio_(0),
scheduler_delay_counter_(0),
ai_personality_military_loneliness_(0),
ai_personality_attack_margin_(0),
@@ -312,6 +313,7 @@
// Pool of tasks to be executed this run. In ideal situation it will consist of one task only.
std::vector<SchedulerTask> current_task_queue;
+ assert (current_task_queue.empty());
// Here we push SchedulerTask members into the temporary queue, providing that a task is due now and
// the limit (jobs_to_run_count) is not exceeded
for (uint8_t i = 0; i < jobs_to_run_count; i += 1) {
@@ -851,12 +853,12 @@
// Here the AI persistent data either exists - then they are read
// or does not exist, then they are created and saved
- int16_t persistent_data_exists_ = 0;
+ bool persistent_data_exists_;
player_->get_ai_data(&persistent_data_exists_, kPersistentData);
- // 0 implies no saved data exits yet
- if (persistent_data_exists_ == 0) {
- player_->set_ai_data(static_cast<int16_t>(1), kPersistentData);
+ // if false, generate new values
+ if (!persistent_data_exists_) {
+ player_->set_ai_data(true, kPersistentData);
// these random values to make some small differences between players
// they are immediately saved
@@ -1520,6 +1522,11 @@
} else {
needed_spots = 1300 + (productionsites.size() - 200) * 20;
}
+ const bool has_enough_space = (spots_ > needed_spots);
+
+ //This is a replacement for simple count of mines
+ const int32_t virtual_mines =
+ mines_.size() + mineable_fields.size() / 25;
// *_military_scores are used as minimal score for a new military building
// to be built. As AI does not traverse all building fields at once, these thresholds
@@ -1533,7 +1540,18 @@
// least_military_score_ is allowed to get bellow 100 only if there is no military site in construction
// right now in order to (try to) avoid expansion lockup
- // this is just helpers to improve readability of code
+ // Bools below are helpers to improve readability of code
+
+ // Military sites have generally higher scores so this is a helper to boost economy
+ bool needs_boost_economy = false;
+ if (highest_nonmil_prio_ > 10
+ && has_enough_space
+ && virtual_mines >= 5){
+ needs_boost_economy = true;
+ }
+ //resetting highest_nonmil_prio_ so it can be recalculated anew
+ highest_nonmil_prio_ = 0;
+
const bool too_many_ms_constructionsites =
(pow(msites_in_constr(), 2) > militarysites.size());
const bool too_many_vacant_mil =
@@ -1541,7 +1559,7 @@
const int32_t kUpperLimit = 275;
const int32_t kBottomLimit = 40; // to prevent too dense militarysites
// modifying least_military_score_, down if more military sites are needed and vice versa
- if (too_many_ms_constructionsites || too_many_vacant_mil) {
+ if (too_many_ms_constructionsites || too_many_vacant_mil || needs_boost_economy) {
if (least_military_score_ < kUpperLimit) { //no sense to let it grow too hight
least_military_score_ += 2;
}
@@ -1580,7 +1598,7 @@
new_buildings_stop_ = true;
}
// 2. to not exhaust all free spots
- if (spots_ < needed_spots) {
+ if (!has_enough_space) {
new_buildings_stop_ = true;
}
// 3. too keep some proportions production sites vs military sites
@@ -1616,8 +1634,7 @@
// set necessity for mines
// we use 'virtual mines', because also mine spots can be changed
// to mines when AI decides so
- const int32_t virtual_mines =
- mines_.size() + mineable_fields.size() / 25;
+
resource_necessity_mines_ = 100 * (15 - virtual_mines) / 15;
resource_necessity_mines_ = (resource_necessity_mines_ > 100) ? 100 : resource_necessity_mines_;
resource_necessity_mines_ = (resource_necessity_mines_ < 20) ? 10 : resource_necessity_mines_;
@@ -1674,9 +1691,15 @@
// checking we have enough critical material on stock
for (uint32_t m = 0; m < bo.critical_built_mat_.size(); ++m) {
DescriptionIndex wt(static_cast<size_t>(bo.critical_built_mat_.at(m)));
- // shortage = less then 3 items in warehouses
- if (get_warehoused_stock(wt) < 3) {
+ uint32_t treshold = 3;
+ //generally trainingsites are more important
+ if (bo.type == BuildingObserver::TRAININGSITE) {
+ treshold = 2;
+ }
+
+ if (get_warehoused_stock(wt) < treshold) {
bo.build_material_shortage_ = true;
+ break;
}
}
}
@@ -1763,10 +1786,18 @@
} else if (bo.type == BuildingObserver::MILITARYSITE) {
bo.new_building_ = check_building_necessity(bo.desc->get_size(), gametime);
- } else if (bo.type == BuildingObserver::TRAININGSITE
- && // if we dont have enough build material or are above target of current ai mode
- (bo.build_material_shortage_ || bo.aimode_limit_achieved())) {
- bo.new_building_ = BuildingNecessity::kNotNeeded;
+ } else if (bo.type == BuildingObserver::TRAININGSITE){
+ if (bo.forced_after_ < gametime && bo.total_count() == 0) {
+ bo.new_building_ = BuildingNecessity::kForced;
+ } else if (ts_without_trainers_ || (ts_basic_const_count_ + ts_advanced_const_count_) > 0) {
+ bo.new_building_ = BuildingNecessity::kNotNeeded;
+ } else if (bo.prohibited_till_ > gametime) {
+ bo.new_building_ = BuildingNecessity::kNotNeeded;
+ } else if (bo.build_material_shortage_ || bo.aimode_limit_achieved()) {
+ bo.new_building_ = BuildingNecessity::kNotNeeded;
+ } else {
+ bo.new_building_ = BuildingNecessity::kAllowed;
+ }
} else if (bo.aimode_limit_achieved()) {
bo.new_building_ = BuildingNecessity::kNotNeeded;
} else {
@@ -2280,53 +2311,45 @@
} else if (bo.type == BuildingObserver::TRAININGSITE) {
- assert(!bo.build_material_shortage_);
+ prio = 30;
+
+ if (bo.new_building_ == BuildingNecessity::kForced) {
+ prio += 30;
+ }
+
+ if (bo.trainingsite_type_ == TrainingSiteType::kBasic){
+ prio = static_cast<int32_t>(militarysites.size())
+ - 40 * static_cast<int32_t>(ts_basic_count_);
+ }
+
+ if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
+ prio = static_cast<int32_t>(militarysites.size())
+ - 50 * static_cast<int32_t>(ts_advanced_count_);
+ }
// exclude spots on border
if (bf->near_border_) {
- continue;
- }
-
- // it is a bit difficult to get a new trainer.....
- if (ts_without_trainers_) {
- continue;
- }
-
- // target is only one for both types
- if ((ts_basic_const_count_ + ts_advanced_const_count_) > 0) {
- continue;
- }
-
- // we build one basic training site for 50 militarysites
- if (bo.trainingsite_type_ == TrainingSiteType::kBasic &&
- militarysites.size() / 50 < static_cast<int32_t>(ts_basic_count_)) {
- continue;
- }
- // we build one advanced training site for 75 militarysites
- if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced &&
- militarysites.size() / 75 < static_cast<int32_t>(ts_advanced_count_)) {
- continue;
- }
+ prio -= 5;
+ }
+
// for type1 we need 15 productionsties
if (bo.trainingsite_type_ == TrainingSiteType::kBasic && productionsites.size() < 15) {
- continue;
+ prio -= 15;
}
// for type2 we need 4 mines
if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced && virtual_mines < 4) {
- continue;
+ prio -= 15;;
}
- prio = 10;
-
// take care about borders and enemies
if (bf->enemy_nearby_) {
- prio /= 2;
+ prio -= 10;
}
if (bf->unowned_land_nearby_) {
- prio -= bf->unowned_land_nearby_ / 10;
+ prio -= 5;
}
}
@@ -2369,6 +2392,10 @@
prio *= 2;
}
+ if (bo.type != BuildingObserver::MILITARYSITE && highest_nonmil_prio_ < prio) {
+ highest_nonmil_prio_ = prio;
+ }
+
if (prio > proposed_priority) {
best_building = &bo;
proposed_priority = prio;
@@ -2495,6 +2522,10 @@
proposed_coords = mf->coords;
mine = true;
}
+
+ if (prio > highest_nonmil_prio_) {
+ highest_nonmil_prio_ = prio;
+ }
} // end of evaluation of field
}
@@ -3156,26 +3187,26 @@
doing_upgrade = true;
}
- // if the decision was not made yet, consider normal upgrade
- if (!doing_upgrade) {
- // compare the performance %
- if (en_bo.current_stats_ - site.bo->current_stats_
- > static_cast<uint32_t>(20)) {
- doing_upgrade = true;
- }
-
- if ((static_cast<int32_t>(en_bo.current_stats_) > 85 &&
- en_bo.total_count() * 2 < site.bo->total_count()) ||
- (static_cast<int32_t>(en_bo.current_stats_) > 50 &&
- en_bo.total_count() * 4 < site.bo->total_count())) {
-
- doing_upgrade = true;
- }
-
- // Dont forget about limitation of number of buildings
- if (en_bo.cnt_limit_by_aimode_ <= en_bo.total_count() - en_bo.unconnected_count_) {
- doing_upgrade = false;
- }
+ if (en_bo.total_count() == 1) {
+ //if the upgrade itself can be upgradeed futher, we are more willing to upgrade 2nd building
+ if (en_bo.upgrade_extends_ || en_bo.upgrade_substitutes_) {
+ if (en_bo.current_stats_ > 30) {
+ doing_upgrade = true;
+ }
+ } else if (en_bo.current_stats_ > 50) {
+ doing_upgrade = true;
+ }
+ }
+
+ if (en_bo.total_count() > 1) {
+ if (en_bo.current_stats_ > 80) {
+ doing_upgrade = true;
+ }
+ }
+
+ // Dont forget about limitation of number of buildings
+ if (en_bo.cnt_limit_by_aimode_ <= en_bo.total_count() - en_bo.unconnected_count_) {
+ doing_upgrade = false;
}
}
}
@@ -4155,6 +4186,7 @@
vacant_mil_positions_ = 0;
for (TrainingSiteObserver tso : trainingsites) {
vacant_mil_positions_ += 10 * (tso.site->soldier_capacity() - tso.site->stationed_soldiers().size());
+ vacant_mil_positions_ += (tso.site->can_start_working()) ? 0 : 10;
}
for (MilitarySiteObserver mso : militarysites) {
vacant_mil_positions_ += mso.site->soldier_capacity() - mso.site->stationed_soldiers().size();
@@ -4164,9 +4196,7 @@
// this function only check with trainingsites
// manipulates input queues and soldier capacity
bool DefaultAI::check_trainingsites(uint32_t gametime) {
- if (get_taskpool_task_time(SchedulerTaskId::kCheckTrainingsites) > gametime) {
- return false;
- }
+
if (trainingsites.empty()) {
set_taskpool_task_time(
gametime + 2 * kTrainingSitesCheckInterval, SchedulerTaskId::kCheckTrainingsites);
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2015-12-06 12:37:51 +0000
+++ src/ai/defaultai.h 2015-12-12 20:55:58 +0000
@@ -335,6 +335,9 @@
uint8_t ts_advanced_const_count_;
uint8_t ts_without_trainers_;
+ // This stores highest priority for new buildings except for militarysites
+ int32_t highest_nonmil_prio_;
+
// this is helping counter to track how many scheduler tasks are too delayed
// the purpose is to print out a warning that the game is pacing too fast
int32_t scheduler_delay_counter_;
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2015-11-21 11:34:10 +0000
+++ src/logic/player.cc 2015-12-12 20:55:58 +0000
@@ -1324,6 +1324,15 @@
m_ai_data_int16[position] = value;
}
+void Player::set_ai_data(bool value, uint32_t position) {
+ assert(position < kAIDataSize);
+ if (value) {
+ m_ai_data_int16[position] = 1;
+ } else {
+ m_ai_data_int16[position] = 0;
+ }
+}
+
void Player::get_ai_data(int32_t * value, uint32_t position) {
assert(position < kAIDataSize);
*value = m_ai_data_int32[position];
@@ -1339,6 +1348,16 @@
*value = m_ai_data_int16[position];
}
+void Player::get_ai_data(bool * value, uint32_t position) {
+ assert(position < kAIDataSize);
+ assert(m_ai_data_int16[position] == 0 || m_ai_data_int16[position] == 1);
+ if (m_ai_data_int16[position] == 1) {
+ *value = true;
+ } else {
+ *value = false;
+ }
+}
+
/**
* Read statistics data from a file.
*
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2015-11-11 09:53:54 +0000
+++ src/logic/player.h 2015-12-12 20:55:58 +0000
@@ -518,9 +518,11 @@
void set_ai_data(int32_t value, uint32_t position);
void set_ai_data(uint32_t value, uint32_t position);
void set_ai_data(int16_t value, uint32_t position);
+ void set_ai_data(bool value, uint32_t position);
void get_ai_data(int32_t * value, uint32_t position);
void get_ai_data(uint32_t * value, uint32_t position);
void get_ai_data(int16_t * value, uint32_t position);
+ void get_ai_data(bool * value, uint32_t position);
private:
BuildingStatsVector* get_mutable_building_statistics(const DescriptionIndex& i);
=== modified file 'tribes/buildings/trainingsites/atlanteans/dungeon/init.lua'
--- tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2015-12-12 20:55:58 +0000
@@ -37,6 +37,7 @@
aihints = {
trainingsite_type = "advanced",
+ prohibited_till = 1500,
very_weak_ai_limit = 0,
weak_ai_limit = 1
},
=== modified file 'tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua'
--- tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2015-12-12 20:55:58 +0000
@@ -36,6 +36,7 @@
aihints = {
prohibited_till=900,
+ forced_after_=1500,
trainingsite_type = "basic",
very_weak_ai_limit = 1,
weak_ai_limit = 2
=== modified file 'tribes/buildings/trainingsites/barbarians/battlearena/init.lua'
--- tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2015-12-12 20:55:58 +0000
@@ -51,7 +51,8 @@
},
aihints = {
- prohibited_till = 2700,
+ prohibited_till = 900,
+ forced_after = 1500,
trainingsite_type = "basic",
very_weak_ai_limit = 1,
weak_ai_limit = 3
=== modified file 'tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua'
--- tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2015-12-12 20:55:58 +0000
@@ -44,7 +44,7 @@
},
aihints = {
- prohibited_till = 500,
+ prohibited_till = 1500,
trainingsite_type = "advanced",
very_weak_ai_limit = 0,
weak_ai_limit = 1
=== modified file 'tribes/buildings/trainingsites/empire/arena/init.lua'
--- tribes/buildings/trainingsites/empire/arena/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/arena/init.lua 2015-12-12 20:55:58 +0000
@@ -41,6 +41,7 @@
aihints = {
trainingsite_type = "basic",
+ prohibited_till = 900,
very_weak_ai_limit = 1,
weak_ai_limit = 2
},
=== modified file 'tribes/buildings/trainingsites/empire/colosseum/init.lua'
--- tribes/buildings/trainingsites/empire/colosseum/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/colosseum/init.lua 2015-12-12 20:55:58 +0000
@@ -35,6 +35,7 @@
aihints = {
trainingsite_type = "basic",
+ prohibited_till = 1200,
very_weak_ai_limit = 1,
weak_ai_limit = 2
},
=== modified file 'tribes/buildings/trainingsites/empire/trainingcamp/init.lua'
--- tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2015-12-12 20:55:58 +0000
@@ -35,7 +35,7 @@
},
aihints = {
- prohibited_till = 2700,
+ prohibited_till = 1500,
trainingsite_type = "advanced",
very_weak_ai_limit = 0,
weak_ai_limit = 1
Follow ups