ed03d2f3ef
new ability lord...teach(whatever[whatever]) ability. teach is a targeted lord, it takes the cards current target and lords it the ability. im aware of a tiny memleak it contains, but the leak is happening on parser lvl, so i need more eyes to look at it. teach is ideally used for equipment, and was designed to fix issue 244 taught abilities are not given to the source cards. forced Ai to pay for sunburst correctly. it was choosing to pay with all of one type of mana. now it pays either max or 1 from max sunburst. added a tiny double check for Ai to try and find something to use if it suddenly has mana in its pool. it is only a single check in a turn, but i notice it actually does slightly improve the usages of dark ritual and foreach mana producers. ideally i wanted it to check EVERYTIME. but i could not achieve it without putting the game in danger of looping. so once is better then none :/ fixed a bug with affinity where it was not counting duel lands, this is becuase of not setting it up correctly for lands with multiple types SORRY!
173 lines
5.1 KiB
C++
173 lines
5.1 KiB
C++
#include "PrecompiledHeader.h"
|
|
|
|
#include "AIStats.h"
|
|
#include "GameObserver.h"
|
|
#include "Player.h"
|
|
#include "MTGCardInstance.h"
|
|
#include "WEvent.h"
|
|
#include "AllAbilities.h"
|
|
//TODO:better comments this is too cryptic to work on by anyone but original coder.
|
|
bool compare_aistats(AIStat * first, AIStat * second){
|
|
float damage1 = static_cast<float>(first->value / first->occurences);
|
|
float damage2 = static_cast<float>(second->value / second->occurences);
|
|
return (damage1 > damage2);
|
|
}
|
|
|
|
AIStats::AIStats(Player * _player, char * _filename){
|
|
filename = _filename;
|
|
load(_filename);
|
|
player = _player;
|
|
}
|
|
|
|
AIStats::~AIStats(){
|
|
list<AIStat *>::iterator it;
|
|
for ( it=stats.begin() ; it != stats.end(); it++ ){
|
|
AIStat * stat = *it;
|
|
delete stat;
|
|
}
|
|
}
|
|
|
|
void AIStats::updateStatsCard(MTGCardInstance * cardInstance, Damage * damage, float multiplier){
|
|
MTGCard * card = cardInstance->model;
|
|
AIStat * stat = find(card);
|
|
if (!stat){
|
|
stat = NEW AIStat(card->getMTGId(),0,1,0);
|
|
stats.push_back(stat);
|
|
}
|
|
if (damage->target == player){
|
|
stat->value+= multiplier * STATS_PLAYER_MULTIPLIER * damage->damage;
|
|
}else if (damage->target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE){
|
|
MTGCardInstance * target = (MTGCardInstance *)damage->target;
|
|
if (target->controller() == player && !target->isInPlay()){
|
|
//One of my creatures got lethal damage...
|
|
stat->value+= multiplier * STATS_CREATURE_MULTIPLIER * damage->damage;
|
|
}
|
|
}
|
|
}
|
|
|
|
int AIStats::receiveEvent(WEvent * event){
|
|
WEventDamage * e = dynamic_cast<WEventDamage *>(event);
|
|
if (!e) return 0; //we take only Damage events into accountright now
|
|
Damage * damage = e->damage;
|
|
MTGGameZone * opponentZone = player->opponent()->game->inPlay;
|
|
|
|
MTGCardInstance * card = damage->source;
|
|
updateStatsCard(card,damage);
|
|
|
|
//Auras on damage source can be the cause
|
|
for (int i = 0; i < opponentZone->nb_cards; ++i){
|
|
MTGCardInstance * aura = opponentZone->cards[i];
|
|
if (aura->target == card){
|
|
updateStatsCard(aura,damage, STATS_AURA_MULTIPLIER);
|
|
}
|
|
}
|
|
|
|
GameObserver * g = GameObserver::GetInstance();
|
|
//Lords
|
|
map<MTGCardInstance *, int> lords;
|
|
for (int i = 1; i < g->mLayers->actionLayer()->mCount; i++){ //0 is not a mtgability...hackish
|
|
MTGAbility * a = ((MTGAbility *)g->mLayers->actionLayer()->mObjects[i]);
|
|
if (ALord * al = dynamic_cast<ALord*>(a)) {
|
|
if (al->cards.find(card)!= al->cards.end() && opponentZone->hasCard(al->source)){
|
|
lords[al->source] = 1;
|
|
}
|
|
}
|
|
}
|
|
if (size_t nb = lords.size()){
|
|
for (map<MTGCardInstance *, int>::iterator it = lords.begin();it !=lords.end();++it){
|
|
updateStatsCard(it->first,damage, STATS_LORD_MULTIPLIER/nb);
|
|
}
|
|
}
|
|
|
|
stats.sort(compare_aistats); //this could be slow, if it is, let's run it only at the end of the turn
|
|
return 1; //is this meant to return 0 or 1?
|
|
}
|
|
//TODO:what does this do?
|
|
bool AIStats::isInTop(MTGCardInstance * card, unsigned int max, bool tooSmallCountsForTrue ){
|
|
if (stats.size()<max) return tooSmallCountsForTrue;
|
|
unsigned int n = 0;
|
|
MTGCard * source = card->model;
|
|
int id = source->getMTGId();
|
|
list<AIStat *>::iterator it;
|
|
for ( it=stats.begin() ; it != stats.end(); it++ ){
|
|
if (n >= max) return false;
|
|
AIStat * stat = *it;
|
|
if (stat->source == id){
|
|
if ((stat->value + card->DangerRanking()) >=3) return true;
|
|
return false;
|
|
}
|
|
n++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AIStat * AIStats::find(MTGCard * source){
|
|
int id = source->getMTGId();
|
|
list<AIStat *>::iterator it;
|
|
for ( it=stats.begin() ; it != stats.end(); it++ ){
|
|
AIStat * stat = *it;
|
|
if (stat->source == id) return stat;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void AIStats::load(char * filename){
|
|
std::ifstream file(filename);
|
|
std::string s;
|
|
|
|
if(file){
|
|
while(std::getline(file,s)){
|
|
int cardid = atoi(s.c_str());
|
|
std::getline(file,s);
|
|
int value = atoi(s.c_str());
|
|
std::getline(file,s);
|
|
int direct = atoi(s.c_str());
|
|
AIStat * stat = NEW AIStat(cardid,value,1,direct);
|
|
stats.push_back(stat);
|
|
}
|
|
file.close();
|
|
}else{
|
|
//TODO Error management
|
|
}
|
|
}
|
|
void AIStats::save(){
|
|
std::ofstream file(filename.c_str());
|
|
char writer[128];
|
|
if (file){
|
|
list<AIStat *>::iterator it;
|
|
for ( it=stats.begin() ; it != stats.end(); it++ ){
|
|
AIStat * stat = *it;
|
|
if (stat->value > 0){
|
|
sprintf(writer,"%i\n%i\n%i\n", stat->source,stat->value/2,stat->direct);
|
|
file<<writer;
|
|
}
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
}
|
|
|
|
void AIStats::Render(){
|
|
GameObserver * g = GameObserver::GetInstance();
|
|
float x0 = 10;
|
|
if (player == g->players[1]) x0 = 280;
|
|
JRenderer::GetInstance()->FillRoundRect(x0,10,200,180,5,ARGB(50,0,0,0));
|
|
|
|
WFont * f = resources.GetWFont(Fonts::MAIN_FONT);
|
|
int i = 0;
|
|
char buffer[512];
|
|
list<AIStat *>::iterator it;
|
|
for (it = stats.begin(); it !=stats.end(); ++it){
|
|
if (i>10) break;
|
|
AIStat * stat = *it;
|
|
if (stat->value > 0){
|
|
MTGCard * card = GameApp::collection->getCardById(stat->source);
|
|
if (card) {
|
|
sprintf(buffer, "%s %i", card->data->getName().c_str(), stat->value);
|
|
f->DrawString(buffer,x0+5,10 + 16 *(float)i);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|