1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

How can I make random-playout agent on BattleServer

Discussion in 'Development General' started by 49sunmoon, Jul 2, 2017.

Tags:
  1. 49sunmoon

    49sunmoon New Member

    Joined:
    Jul 2, 2017
    Messages:
    1
    Likes Received:
    0
    # I am beginner at here. If here is not suitable for this kind of talk, please tell me where I go...

    I am thinking of developing pokemon AI.
    As a first step, I am trying to develop random-move agent by modifying source code of BattleServer.

    According to prior research, it will be done by following source code.
    But this article does not contain main.cpp and I wonder how to write it.

    # This is Japanese article, but I paste the code below and if you interested in, I will translate this to English.
    http://shingaryu.hatenablog.com/ent...%e3%82%a4%e3%83%96%e3%83%a9%e3%83%aa%e3%81%a8

    # In these codes, I added English comments

    #ifndef LOCALBATTLETEST_H
    #define LOCALBATTLETEST_H

    #include <QObject>
    #include "battle.h"

    class LocalBattleTest : public QObject
    {
    Q_OBJECT
    public:
    explicit LocalBattleTest(QObject *parent = 0);
    ~LocalBattleTest();
    QHash<int, BattleSituation *> battles;
    ContextSwitcher battleThread;
    BattleServerPluginManager *pluginManager;
    void testBattleExecute();
    void commandChoice(int battleID, BattleChoice choice);
    void ShowCurrentHPs();
    void databaseInit();
    int newBattle(BattlePlayer player1, BattlePlayer player2, ChallengeInfo challengeInfo, TeamBattle team1, TeamBattle team2);
    void ShowCurrentHPs(int battleID);
    signals:

    public slots:
    void notifyInfo(int battleID, int playerID, const QByteArray &info);
    void notifyFinished(int battleid, int result, int winner, int loser);
    };


    #endif // LOCALBATTLETEST_H



    //localbattletest.cpp
    #include "localbattletest.h"
    #include "battle.h"
    #include "pluginmanager.h"
    #include "moves.h"
    #include "abilities.h"
    #include "rbymoves.h"
    #include <PokemonInfo/movesetchecker.h>
    #include "../Shared/battlecommands.h"

    LocalBattleTest::LocalBattleTest(QObject *parent) : QObject(parent)
    {

    databaseInit();
    battleThread.start();
    pluginManager = new BattleServerPluginManager();
    }


    LocalBattleTest::~LocalBattleTest()
    {


    }

    //initialize databese
    void LocalBattleTest::databaseInit()
    {

    //copied from BattleServer::changeDbMod()

    PokemonInfoConfig::setFillMode(FillMode::Server);

    PokemonInfoConfig::changeMod("");

    /* Really useful for headless servers */
    GenInfo::init("db/gens/");
    PokemonInfo::init("db/pokes/");
    MoveSetChecker::init("db/pokes/");
    ItemInfo::init("db/items/");
    MoveInfo::init("db/moves/");
    TypeInfo::init("db/types/");
    NatureInfo::init("db/natures/");
    CategoryInfo::init("db/categories/");
    AbilityInfo::init("db/abilities/");
    HiddenPowerInfo::init("db/types/");
    StatInfo::init("db/status/");
    GenderInfo::init("db/genders/"); //needed by battlelogs plugin

    PokemonInfo::loadStadiumTradebacks();

    MoveEffect::init();
    RBYMoveEffect::init();
    ItemEffect::init();
    AbilityEffect::init();
    }


    void LocalBattleTest::testBattleExecute()
    {

    //set name and ID as you like
    BattlePlayer player1("Satoshi", 0);
    BattlePlayer player2("Shigeru", 1);

    Team team;
    // you can read files made by Generator
    team.loadFromFile("(***file path***)");
    auto team1 = TeamBattle(team);

    auto team2 = TeamBattle();
    team2.generateRandom(Pokemon::gen(Gen::ORAS)); //random party

    newBattle(player1, player2, ChallengeInfo(), team1, team2);
    }


    // create new instance
    int LocalBattleTest::newBattle(BattlePlayer player1, BattlePlayer player2, ChallengeInfo challengeInfo, TeamBattle team1, TeamBattle team2)
    {

    // definition of Qhash to obey the protocol of server

    int initialID = 10; //as you like

    int maxID = 0;
    foreach (auto item, battles.keys()) {
    if(item > maxID){
    maxID = item;
    }
    }
    auto id = battles.count() == 0 ? initialID : maxID + 1;

    // 6 on 6 single battle
    auto newBattle = new BattleSituation(player1, player2, challengeInfo, id, team1, team2, pluginManager);
    battles.insert(id, newBattle);

    //connection between BattleSituation and this object
    connect(newBattle, SIGNAL(battleInfo(int,int,QByteArray)), this, SLOT(notifyInfo(int,int,QByteArray)));
    connect(newBattle, SIGNAL(battleFinished(int,int,int,int)), this, SLOT(notifyFinished(int,int,int,int)));
    newBattle->start(battleThread);

    return id;
    }


    //reaction when receiving signal from BattleSituation
    void LocalBattleTest::notifyInfo(int battleID, int playerID, const QByteArray &info)
    {

    //Decoding information via QbyteArray and DataStream

    DataStream dataStream(info);
    uchar commandNumber;
    qint8 who;
    dataStream >> commandNumber >> who;

    using namespace BattleCommands;

    switch((int)commandNumber) //Only react to OfferChoice
    {
    case BattleCommand::OfferChoice: //OfferChoice means user must send something
    {
    if(who == 0) // showing HP when requirement choice to player1
    {
    ShowCurrentHPs(battleID);
    }

    // List all legal moves and select randomly

    BattleChoices choiceRegulation;
    dataStream >> choiceRegulation;
    QList<BattleChoice> validChoices;
    bool isMegaEvo = choiceRegulation.mega;

    for(int i = 0; i < 4; i++)
    {
    if(choiceRegulation.attackAllowed)
    {
    AttackChoice attack;
    attack.attackTarget = (who == 0) ? 1 : 0;
    attack.attackSlot = i;
    BattleChoice battleChoice(who, attack);
    battleChoice.setMegaEvo(isMegaEvo);

    validChoices << battleChoice;
    }
    }

    if(choiceRegulation.switchAllowed)
    {
    for(int i = 0; i < 6; i++)
    {
    if (!battles[battleID]->isOut(who, i) && !battles[battleID]->poke(who, i).ko())
    {
    SwitchChoice switchChoice;
    switchChoice.pokeSlot = i;
    validChoices << BattleChoice(who, switchChoice);
    }
    }
    }

    commandChoice(battleID, validChoices[rand() % validChoices.length()]);

    break;
    }
    }
    }


    //end of battle
    void LocalBattleTest::notifyFinished(int battleid, int result, int winner, int loser)
    {

    qDebug() << "finished";

    }


    //execute commands
    void LocalBattleTest::commandChoice(int battleID, BattleChoice choice)
    {


    //for debug
    switch(choice.type)
    {
    case ChoiceType::AttackType:
    {
    auto moveNumber = battles[battleID]->poke(choice.slot()).move(choice.attackSlot()).num();
    auto moveName = MoveInfo::Name(moveNumber);
    qDebug() << moveName << "is selected";
    break;
    }
    case ChoiceType::SwitchType:
    {
    auto pokeName = battles[battleID]->poke(choice.slot(), choice.pokeSlot()).nick();
    qDebug() << pokeName << "(change) is selected";
    break;
    }
    }
    qDebug();

    battles[battleID]->battleChoiceReceived(battles[battleID]->id(choice.slot()), choice);
    }


    //show HP for debug
    void LocalBattleTest::ShowCurrentHPs(int battleID)
    {

    auto b = battles[battleID];
    qDebug() << "Player0 HP:" << b->poke(0, 0).lifePoints() << b->poke(0, 1).lifePoints() << b->poke(0, 2).lifePoints() << b->poke(0, 3).lifePoints() << b->poke(0, 4).lifePoints() << b->poke(0, 5).lifePoints();
    qDebug() << "Player1 HP:" << b->poke(1, 0).lifePoints() << b->poke(1, 1).lifePoints() << b->poke(1, 2).lifePoints() << b->poke(1, 3).lifePoints() << b->poke(1, 4).lifePoints() << b->poke(1, 5).lifePoints();
    qDebug();
    }


    I modified main.cpp to

    int main(argc, argv){
    QtCoreApplication a(argc,argv);
    auto lbt = new LocalBattleTest();
    return a.exec();
    }

    I succeed compile. But when I start the binary ./BattleServer, it stops during battle.
    If you know how to fix it please teach me :)