Files
2018-07-17 14:15:37 +02:00

1015 lines
32 KiB
ActionScript

import hooks;
import systems;
import influence;
import resources;
#section server
from influence_global import getRandomActiveInfluenceEffect, getSenateLeader, getTaggedEffectOwner;
#section all
interface AIDiplomacy {
Empire@ get_empire();
uint get_allyMask();
uint get_selfMask();
uint enemiesMask(int maxStanding = -20);
int getStanding(Empire@ against);
array<InfluenceCard>& get_cardList();
Object@ considerOwnedPlanets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerImportantPlanets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerOwnedSystems(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerDefendingSystems(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerDefendingPlanets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerEnemySystems(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerImportantSystems(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerFleets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerEnemyFleets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerEnemyPlanets(const CardAI& hook, Targets& targets, VoteState@ vote = null, const InfluenceCard@ card = null);
Object@ considerMatchingImportRequests(const CardAI& hook, Targets& targets, VoteState@ vote, const InfluenceCard@ card, const ResourceType@ type, bool considerExisting);
void markProtecting(Object@ obj);
};
interface VoteState {
InfluenceVote@ get_data();
bool get_side();
bool get_isRaceVote();
void set_isRaceVote(bool value);
double get_priority();
void set_priority(double value);
double get_weightOppose();
void set_weightOppose(double value);
double get_weightSupport();
void set_weightSupport(double value);
};
uint getTargeted(const InfluenceVote@ vote, const Argument@ targArg) {
auto@ targ = vote.targets[targArg.integer];
if(targ is null)
return 0;
uint emps = 0;
if(targ.emp !is null) {
emps = targ.emp.mask;
}
else if(targ.obj !is null) {
if(targ.obj.isRegion)
emps = cast<Region>(targ.obj).PlanetsMask;
else
emps = targ.obj.owner.mask;
}
return emps & ~vote.startedBy.mask;
}
class CardAI : Hook {
void considerBuy(AIDiplomacy& ai, const StackInfluenceCard@ card, double& weight) const {}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const {}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const { return true; }
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const {}
bool vote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs) const { return true; }
double consider(AIDiplomacy& ai, Targets& targets, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const { return 0.0; }
double consider(AIDiplomacy& ai, Targets& targets, VoteState@ vote, const InfluenceCard@ card, Object@ requestedAt, Object@ currentSupplier) const { return 0.0; }
};
class VoteAI : Hook {
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {}
};
class BuyWeight : CardAI {
Document doc("This card can always be bought, and has a particular weight.");
Argument amount(AT_Decimal, "1.0", doc="Buy weight modification.");
#section server
void considerBuy(AIDiplomacy& ai, const StackInfluenceCard@ card, double& weight) const override {
weight *= amount.decimal;
}
#section all
};
class BuyAgainstEnemies : CardAI {
Document doc("If this card is against a specific empire, value it more if that empire is an enemy.");
Argument targ(TT_Empire, doc="Target to check.");
Argument amount(AT_Decimal, "1.5", doc="Buy weight modification.");
Argument max_standing(AT_Integer, "-20", doc="Anything above this standing is considered not an enemy.");
#section server
void considerBuy(AIDiplomacy& ai, const StackInfluenceCard@ card, double& weight) const override {
auto@ consTarg = card.targets[targ.integer];
if(consTarg is null || consTarg.emp is null || !consTarg.filled)
return;
if(consTarg.emp.isHostile(ai.empire) || ai.getStanding(consTarg.emp) < max_standing.integer)
weight *= amount.decimal;
else
weight /= amount.decimal;
}
#section all
};
class VoteSupport : CardAI {
Document doc("This card is played as a simple vote support card into votes.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(card.type.sideTarget != -1)
targs.fill(card.type.sideTarget).side = state.side;
if(!state.data.canVote(ai.empire, state.side)) {
weight *= 0.0;
return;
}
weight *= this.weight.decimal;
}
bool vote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs) const override {
if(card.type.sideTarget != -1)
targs.fill(card.type.sideTarget).side = state.side;
return true;
}
#section all
}
class VoteAlwaysNegative : CardAI {
Document doc("This card should be played as a bad card into votes we don't like.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(!state.side)
weight *= this.weight.decimal;
else
weight *= 0.0;
}
#section all
};
class VoteAlwaysPositive : CardAI {
Document doc("This card should be played as a card into votes we like.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(state.side)
weight *= this.weight.decimal;
else
weight *= 0.0;
}
#section all
};
class VoteNotOurs : CardAI {
Document doc("This card should only be played if we aren't the one who started this vote.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(state.data.startedBy is ai.empire)
weight *= 0.0;
}
#section all
};
class VoteAgainstEmpire : CardAI {
Document doc("This card should be played against empires voting in the opposite direction to us.");
Argument targ(TT_Empire, doc="Empire target this is against.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument min_vote(AT_Integer, "1", doc="Minimum amount of votes they should have cast opposite to us.");
Argument most_only(AT_Boolean, "False", doc="Only use this card against empires that have the most opposition of everyone.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Empire@ emp;
auto@ consTarg = card.targets[targ.integer];
if(consTarg !is null && consTarg.filled && consTarg.emp !is null) {
@emp = consTarg.emp;
}
else if(most_only.boolean) {
int bestVote = 0;
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ check = getEmpire(i);
if(check is ai.empire)
continue;
if(!state.data.isPresent(check))
continue;
int votes = state.data.getVoteFrom(check);
if(state.side) {
if(votes < bestVote) {
bestVote = votes;
@emp = check;
}
}
else {
if(votes > bestVote) {
bestVote = votes;
@emp = check;
}
}
}
}
else {
@emp = getEmpire(randomi(0, getEmpireCount()-1));
}
if(emp is null || !state.data.isPresent(emp)) {
weight *= 0.0;
return;
}
if(state.side) {
if(state.data.getVoteFrom(emp) > -min_vote.integer) {
weight *= 0.0;
return;
}
}
else {
if(state.data.getVoteFrom(emp) < min_vote.integer) {
weight *= 0.0;
return;
}
}
data.store(@emp);
}
bool vote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Empire@ emp;
if(!data.retrieve(@emp))
return false;
@targs.fill(targ.integer).emp = emp;
if(card.type.sideTarget != -1)
targs.fill(card.type.sideTarget).side = state.side;
return true;
}
#section all
};
class NotInRace : CardAI {
Document doc("This card should not be used in a 'race' vote such as zeitgeists.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(state.isRaceVote)
weight *= 0.0;
}
#section all
}
class VoteOnAlly : CardAI {
Document doc("This card should be used on allies who are voting the same way as we are.");
Argument targ(TT_Empire, doc="Empire target this is against.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument min_vote(AT_Integer, "1", doc="Minimum amount of votes they should have cast supporting us.");
Argument allied_only(AT_Boolean, "True", doc="Only consider empires that are actually allied to us, instead of just voting our way.");
Argument most_only(AT_Boolean, "False", doc="Only use this card against empires that have the most support of everyone.");
#section server
void considerVote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Empire@ emp;
auto@ consTarg = card.targets[targ.integer];
if(consTarg !is null && consTarg.filled && consTarg.emp !is null) {
@emp = consTarg.emp;
}
else if(most_only.boolean) {
int bestVote = 0;
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
Empire@ check = getEmpire(i);
if(check is ai.empire)
continue;
if(!state.data.isPresent(check))
continue;
if(allied_only.boolean && ai.allyMask & check.mask == 0)
continue;
int votes = state.data.getVoteFrom(check);
if(state.side) {
if(votes > bestVote) {
bestVote = votes;
@emp = check;
}
}
else {
if(votes < bestVote) {
bestVote = votes;
@emp = check;
}
}
}
}
else {
@emp = getEmpire(randomi(0, getEmpireCount()-1));
}
if(emp is null || !state.data.isPresent(emp)) {
weight *= 0.0;
return;
}
if(state.side) {
if(state.data.getVoteFrom(emp) < min_vote.integer) {
weight *= 0.0;
return;
}
}
else {
if(state.data.getVoteFrom(emp) > -min_vote.integer) {
weight *= 0.0;
return;
}
}
data.store(@emp);
}
bool vote(AIDiplomacy& ai, VoteState& state, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Empire@ emp;
if(!data.retrieve(@emp))
return false;
@targs.fill(targ.integer).emp = emp;
if(card.type.sideTarget != -1)
targs.fill(card.type.sideTarget).side = state.side;
return true;
}
#section all
};
class PlayOnImportantPlanets : CardAI {
Document doc("This card should be played on important planets in the empire when possible.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument min_level(AT_Integer, "2", doc="Don't target planets of a lower level than this.");
#section server
double consider(AIDiplomacy& ai, Targets& targets, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
if(int(obj.level) < min_level.integer)
return 0.0;
@targets.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targets[targ.integer]))
return 0.0;
double w = 0.8;
if(obj.primaryResourceExported)
w *= 0.5;
return w;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ check = ai.considerImportantPlanets(this, targs, null, card);
if(check !is null) {
data.store(@check);
if(check.primaryResourceExported)
weight *= 0.5;
weight *= this.weight.decimal;
return;
}
weight *= 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};
class PlayOnImportantSystems : CardAI {
Document doc("This card should be played on important systems in the empire when possible.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ best = ai.considerImportantSystems(this, targs, null, card);
if(best !is null) {
data.store(@best);
weight *= this.weight.decimal;
return;
}
weight *= 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};
class PlayOnImportantFleets : CardAI {
Document doc("This card should be played on important fleets.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument min_size(AT_Integer, "128", doc="Minimum size to consider the flagship.");
Argument enemies(AT_Boolean, "False", doc="Whether to play on an enemy's visible fleet instead of our own.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
Ship@ ship = cast<Ship>(obj);
if(ship !is null) {
const Design@ dsg = ship.blueprint.design;
if(dsg is null)
return 0.0;
if(dsg.hasTag(ST_Mothership) || dsg.hasTag(ST_Slipstream) || dsg.hasTag(ST_Gate))
return 0.0;
}
return obj.getFleetStrength();
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
//Find our strongest combat fleet
Ship@ strongest;
if(!enemies.boolean)
@strongest = cast<Ship>(ai.considerFleets(this, targs, null, card));
else
@strongest = cast<Ship>(ai.considerEnemyFleets(this, targs, null, card));
if(strongest is null) {
weight *= 0.0;
return;
}
auto@ dsg = strongest.blueprint.design;
if(dsg is null || dsg.size < min_size.integer) {
weight *= 0.0;
return;
}
//Consider playing on that fleet
@targs.fill(targ.integer).obj = strongest;
if(!card.isValidTarget(targ.integer, targs[targ.integer])) {
weight *= 0.0;
return;
}
data.store(@strongest);
weight *= this.weight.decimal;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Ship@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};
class PlayOnValuableCard : CardAI {
Document doc("Play this card on another valuable card we have.");
Argument targ(TT_Card, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument min_value(AT_Integer, "2", doc="Minimum value of the card to play this on.");
#section server
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
double totalValue = 0.0;
InfluenceCard@ otherCard;
auto@ cards = ai.cardList;
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
auto@ check = cards[i];
if(check.id == card.id)
continue;
targs.fill(targ.integer).id = check.id;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
continue;
double val = check.getPurchaseCost(ai.empire, uses=1);
if(val < min_value.integer)
continue;
totalValue += val;
if(randomd() < val / totalValue)
@otherCard = check;
}
if(otherCard !is null) {
weight *= this.weight.decimal;
int playOn = otherCard.id;
data.store(playOn);
}
else {
weight *= 0.0;
}
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
int playOn = -1;
if(!data.retrieve(playOn))
return false;
targs.fill(targ.integer).id = playOn;
return true;
}
#section all
};
class PlayOnDefendingPlanet : CardAI {
Document doc("This card should be played on planets that are currently being defended and under contestion.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "5.0", doc="Weight of the card in relation to other cards.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
if(!obj.isContested)
return 0.0;
if(obj.isProtected(ai.empire))
return 0.0;
if(obj.capturePct <= 0.01)
return 0.0;
if(!obj.enemiesInOrbit)
return 0.0;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ best = ai.considerDefendingPlanets(this, targs, null, card);
if(best !is null) {
data.store(@best);
weight *= this.weight.decimal;
return;
}
weight *= 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
ai.markProtecting(playOn);
return true;
}
#section all
};
class PlayOnDefendingSystem : CardAI {
Document doc("This card should be played on systems that are currently being defended and under contestion.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "5.0", doc="Weight of the card in relation to other cards.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
Region@ reg = cast<Region>(obj);
if(reg is null)
return 0.0;
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
if(reg.ProtectedMask & ai.empire.mask != 0)
return 0.0;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ best = ai.considerDefendingSystems(this, targs, null, card);
if(best !is null) {
data.store(@best);
weight *= this.weight.decimal;
return;
}
weight *= 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
ai.markProtecting(playOn);
return true;
}
#section all
};
class PlayOnEnemyEffect : CardAI {
Document doc("Play this card on an influence effect of someone we don't like.");
Argument targ(TT_Effect, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
auto@ eff = getRandomActiveInfluenceEffect();
if(eff is null || eff.owner is null) {
weight *= 0.0;
return;
}
//Only cast on effects we dislike the owner of
if(!ai.empire.isHostile(eff.owner) && ai.getStanding(eff.owner) >= -10) {
weight *= 0.0;
return;
}
targs.fill(targ.integer).id = eff.id;
if(!card.isValidTarget(targ.integer, targs[targ.integer])) {
weight *= 0.0;
return;
}
int playOn = eff.id;
data.store(playOn);
weight *= this.weight.decimal;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
int playOn = -1;
if(!data.retrieve(playOn))
return false;
targs.fill(targ.integer).id = playOn;
return true;
}
#section all
};
class PlayWhenInfluenceStronk : CardAI {
Document doc("Play this card if we have strong influence compared to other empires.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(ai.empire.PoliticalStrength != +1)
weight *= 0.0;
else
weight *= this.weight.decimal;
}
#section all
};
class PlayOnEnemy : CardAI {
Document doc("Play this card on enemies we dislike.");
Argument targ(TT_Empire, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
Argument war_only(AT_Boolean, "False", doc="Only play against enemies we are at war with, instead of everyone we dislike.");
#section server
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Empire@ emp = getEmpire(randomi(0, getEmpireCount()-1));
auto@ curTarg = targs[targ.integer];
if(curTarg !is null && curTarg.filled)
@emp = curTarg.emp;
if(emp is null) {
weight *= 0.0;
return;
}
if(!ai.empire.isHostile(emp) && (war_only.boolean || ai.getStanding(emp) >= -20)) {
weight *= 0.0;
return;
}
@targs.fill(targ.integer).emp = emp;
if(!card.isValidTarget(targ.integer, targs[targ.integer])) {
weight *= 0.0;
return;
}
data.store(@emp);
weight *= this.weight.decimal;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Empire@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).emp = playOn;
return true;
}
#section all
};
class IgnoreIfSenateLeader : CardAI {
Document doc("Ignore this card if you are senate leader.");
#section server
void considerBuy(AIDiplomacy& ai, const StackInfluenceCard@ card, double& weight) const override {
if(getSenateLeader() is ai.empire)
weight *= 0.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(getSenateLeader() is ai.empire)
weight *= 0.0;
}
#section all
};
class IgnoreIfAttributeGTE : CardAI {
Document doc("Ignore this card if you have a particular attribute above a value.");
Argument attrib(AT_EmpAttribute, doc="Attribute to check.");
Argument value(AT_Decimal, doc="Value to check for.");
#section server
void considerBuy(AIDiplomacy& ai, const StackInfluenceCard@ card, double& weight) const override {
if(ai.empire.getAttribute(attrib.integer) >= value.decimal)
weight *= 0.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
if(ai.empire.getAttribute(attrib.integer) >= value.decimal)
weight *= 0.0;
}
#section all
};
class PlayOnNearbyEnemyPlanet : CardAI {
Document doc("This card should be played on enemy planets that are nearby our space.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ planet = ai.considerEnemyPlanets(this, targs, null, card);
data.store(@planet);
if(planet !is null)
weight *= this.weight.decimal;
else
weight = 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};
class PlayOnNearbyEnemySystem : CardAI {
Document doc("This card should be played on enemy systems that are nearby our space.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument weight(AT_Decimal, "1.0", doc="Weight of the card in relation to other cards.");
#section server
double consider(AIDiplomacy& ai, Targets& targs, VoteState@ vote, const InfluenceCard@ card, Object@ obj) const {
@targs.fill(targ.integer).obj = obj;
if(!card.isValidTarget(targ.integer, targs[targ.integer]))
return 0.0;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ system = ai.considerEnemySystems(this, targs, null, card);
data.store(@system);
if(system !is null)
weight *= this.weight.decimal;
else
weight = 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};
class Important : VoteAI {
Document doc("This vote is important.");
Argument importance(AT_Decimal, doc="Importance multiplier for the vote.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
state.priority *= importance.decimal;
}
#section all
};
class BadFor : VoteAI {
Document doc("This vote is bad for whoever is in the target.");
Argument targ(TT_Any);
Argument weight(AT_Decimal, "2.0", doc="Just how bad is this vote?");
Argument importance(AT_Decimal, "1.0", doc="Modifier to important for related empires.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
uint emps = getTargeted(vote, targ);
//If it's us, this is bad
if(ai.selfMask & emps != 0) {
state.weightOppose *= this.weight.decimal;
state.priority *= this.importance.decimal;
}
//Try to protect allies a little as well
else if(ai.allyMask & emps != 0) {
state.weightOppose *= sqrt(this.weight.decimal);
state.priority *= this.importance.decimal;
}
}
#section all
};
class GoodFor : VoteAI {
Document doc("This vote is good for whoever is in the target.");
Argument targ(TT_Any);
Argument weight(AT_Decimal, "2.0", doc="Just how good is this vote?");
Argument importance(AT_Decimal, "1.0", doc="Modifier to important for related empires.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
uint emps = getTargeted(vote, targ);
//If it's us, this is bad
if(ai.selfMask & emps != 0) {
state.weightSupport *= this.weight.decimal;
state.priority *= this.importance.decimal;
}
//Try to help allies a little as well
else if(ai.allyMask & emps != 0) {
state.weightSupport *= sqrt(this.weight.decimal);
state.priority *= this.importance.decimal;
}
}
#section all
};
class GoodForNot : VoteAI {
Document doc("This vote is good for whoever is not the target.");
Argument targ(TT_Any);
Argument weight(AT_Decimal, "2.0", doc="Just how good is this vote?");
Argument importance(AT_Decimal, "1.0", doc="Modifier to important for related empires.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
uint emps = getTargeted(vote, targ);
if((ai.selfMask | ai.allyMask) & emps == 0) {
state.weightSupport *= this.weight.decimal;
state.priority *= this.importance.decimal;
}
else if(ai.selfMask & emps == 0) {
state.weightSupport *= sqrt(this.weight.decimal);
state.priority *= this.importance.decimal;
}
}
#section all
};
class BadForSenateLeader : VoteAI {
Document doc("This vote is bad for the current senate leader.");
Argument weight(AT_Decimal, "2.0", doc="Just how bad is this vote?");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
Empire@ curLeader = getSenateLeader();
uint emps = 0;
if(curLeader !is null && curLeader !is vote.startedBy)
emps |= curLeader.mask;
//If it's us, this is bad
if(ai.selfMask & emps != 0)
state.weightOppose *= this.weight.decimal;
//Try to protect allies a little as well
else if(ai.allyMask & emps != 0)
state.weightOppose *= sqrt(this.weight.decimal);
}
#section all
};
class BenefitRace : VoteAI {
Document doc("This vote is a race where the highest contributor benefits.");
Argument weight(AT_Decimal, "2.0", doc="The weight of winning this vote.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
state.isRaceVote = true;
state.weightSupport *= weight.decimal;
}
#section all
};
class BadIfAttributeGTE : VoteAI {
Document doc("This vote is bad if an attribute is at least a particular value.");
Argument attrib(AT_EmpAttribute, doc="Attribute to check.");
Argument value(AT_Decimal, doc="Value to check for.");
Argument weight(AT_Decimal, "2.0", doc="Just how bad is this vote?");
Argument importance(AT_Decimal, "1.0", doc="Importance multiplier to the vote.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
if(ai.empire.getAttribute(attrib.integer) >= value.decimal) {
state.weightOppose *= this.weight.decimal;
state.priority *= this.importance.decimal;
}
}
#section all
};
class ZeitgeistVote : VoteAI {
Document doc("This vote is a zeitgeist vote.");
Argument tag(AT_Custom, "Zeitgeist", doc="Tag to determine for current zeitgeist effect.");
Argument weight(AT_Decimal, "10.0", doc="Weight modification.");
#section server
void consider(AIDiplomacy& ai, VoteState& state, const InfluenceVote@ vote) const {
state.isRaceVote = true;
Empire@ current = getTaggedEffectOwner(tag.str);
if(current !is null && current.mask & ai.selfMask != 0)
state.weightOppose *= weight.decimal;
else
state.weightSupport *= weight.decimal;
}
#section all
};
class PlayAsCreatedResource : CardAI {
Document doc("This card is used to create a resource somewhere it is useful.");
Argument targ(TT_Object, doc="Target to fill in.");
Argument resource(AT_PlanetResource, doc="Resource to match import requests to.");
Argument weight(AT_Decimal, "1.0", doc="Value for activating this.");
Argument replaces_existing(AT_Boolean, "True", doc="Whether this can be used to replace an existing import of that type or not.");
#section server
double consider(AIDiplomacy& ai, Targets& targets, VoteState@ vote, const InfluenceCard@ card, Object@ requestedAt, Object@ currentSupplier) const {
@targets.fill(targ.integer).obj = requestedAt;
if(!card.isValidTarget(targ.integer, targets[targ.integer]))
return 0.0;
if(currentSupplier !is null)
return 0.5;
return 1.0;
}
void considerAct(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs, double& weight) const override {
Object@ check = ai.considerMatchingImportRequests(this, targs, null, card, getResource(resource.integer), replaces_existing.boolean);
if(check !is null) {
data.store(@check);
weight *= this.weight.decimal;
return;
}
weight *= 0.0;
}
bool act(AIDiplomacy& ai, const InfluenceCard@ card, any@ data, Targets& targs) const override {
Object@ playOn;
if(!data.retrieve(@playOn))
return false;
@targs.fill(targ.integer).obj = playOn;
return true;
}
#section all
};