/*****************************************************************************
Module : Travian.H
Notices: 2007.3.1 Written by Ling, Xiao-li. Mailto: ling.xiaoli.s@gmail.com
Description: This file encapsulates html parsing relating to most tasks of travian web game,
such as upgrade task, build task, etc.
HTML getting or posting uses CHttpClient class.
HTML parsing uses CRegex which is a Wrapper for ATL regular string class CAtlRegExp<>.
*****************************************************************************/
#pragma once
#include "stdafx.h"
#include "EventLog.h"
#include "HttpClient.h"
#include "Regex.h"
//extern System::EventLog::CEventLog g_TravianEvtLog;
//#define LOGERR(sErr) g_TravianEvtLog.AddEvt(EVENT_ERR, sErr)
//#define LOGWARNN(sWar) g_TravianEvtLog.AddEvt(EVENT_WARN, sWar)
//#define LOGINFO(sInf) g_TravianEvtLog.AddEvt(EVENT_INFOR, sInf)
using namespace std;
using namespace System::EventLog;
using namespace System::Internet;
using namespace System::String;
namespace Travian
{
// NOTE: character & maybe encoded as: &
#define TRAVIAN_URL_TASK_CHECK _T("build.php?id=%d")
#define TRAVIAN_URL_TASK_UPGRADE_RESOURCE _T("dorf1.php?a=%d&c=")
#define TRAVIAN_URL_TASK_UPGRADE_BUILDING _T("dorf2.php?a=%d&c=")
#define TRAVIAN_URL_TASK_BUILD _T("dorf2.php?a=%d&id=%d&c=")
#define TRAVIAN_URL_TASK_CHECK_VILLAGE _T("dorf1.php")
#define TRAVIAN_URL_TASK_SWITCH_VILLAGE _T("dorf1.php?newdid=%d")
#define TRAVIAN_URL_TASK_VILLAGEURL_MARK _T("?newdid=") //!!!
#define TRAVIAN_URL_TASK_DEVELOP _T("build.php?id=%d&a=%d")
#define TRAVIAN_URL_TASK_CHECK_DISPATCH_TROOP _T("a2b.php")
#define TRAVIAN_URL_LOGINPAGE _T("login.php")
#define TRAVIAN_LOGIN_CONFIRMSTART _T("dorf1.php?ok")
#define TRAVIAN_CAT_RESOURCE 1
#define TRAVIAN_CAT_BUILDING 2
#define TRAVIAN_CAT_MILITARY 3
// Wall/Rally location are fixed
#define TRAVIAN_LOC_MB 26
#define TRAVIAN_LOC_RALLY 39
#define TRAVIAN_LOC_WALL 40
#define TRAVIAN_LOC_LOWLIMIT 1
#define TRAVIAN_LOC_UPLIMIT 40
#define TRAVIAN_LOC_RES_UPLIMIT 18 // resource location id up limit:
#define TRAVIAN_LOC_BLD_LOWLIMIT 19 // building location id starts from:
#define TRAVIAN_GROUP_LOWLIMIT 1
#define TRAVIAN_GROUP_UPLIMIT 37
#define TRAVIAN_TROOPTYPEID_LOWLIMIT 1
#define TRAVIAN_TROOPTYPEID_UPLIMIT 11
#define TRAVIAN_TRAP_ID 99 //!!!
#define DATETIME_PART_COUNT 6 // Date time format has 6 parts: Y-M-D H:M:S
#define TRAVIAN_COMMAND_LEN 3 // Travian backend program automatically generates extra parameter (here called command)
// in uprade or build task's links. And the command length is 3 chars at present.
struct RESOURCE
{
vector<long> vecRes;
RESOURCE() {
vecRes.resize(4);
vecRes.at(0) = 0; // Wood
vecRes.at(1) = 0; // Clay
vecRes.at(2) = 0; // Iron
vecRes.at(3) = 0; // Grain
};
RESOURCE(const RESOURCE& rhs)
{
vecRes = rhs.vecRes;
};
RESOURCE& operator = (const RESOURCE& rhs) {
vecRes = rhs.vecRes;
return *this;
}
};
struct TROOP
{
int nTypeID; // Troop Type ID
int nQty; // Quantity
TROOP() {
nTypeID = -1;
nQty = 0;
};
TROOP(const TROOP& rhs) {
nTypeID = rhs.nTypeID;
nQty = rhs.nQty;
};
TROOP& operator = (const TROOP& rhs) {
nTypeID = rhs.nTypeID;
nQty = rhs.nQty;
return *this;
}
};
// Village coordinate
struct VILLAGE
{
// Just fill nX,nY, or just fill sName.
int nX;
int nY;
CString sName;
VILLAGE() {
nX = 0; nY = 0;
};
VILLAGE(const VILLAGE& rhs) {
nX = rhs.nX; nY = rhs.nY;
sName = rhs.sName;
};
VILLAGE& operator = (const VILLAGE& rhs) {
nX = rhs.nX; nY = rhs.nY;
sName = rhs.sName;
return *this;
}
};
enum eTaskExecState
{
E_EXEC_STATE_INITIAL = -1
, E_EXEC_STATE_FINISHED = 0
, E_EXEC_STATE_DELAYED = 1 // this task will delay to execute because of current condition not satisfied, but condition will change in future.
, E_EXEC_STATE_STOPPED = 2 // this task cancelled because of beyond condition, such as trainning troop that has not been developed, and resource tranfer failed.
};
enum eTroopDispatchType
{
E_TROOPDISPATCH_NONE = -1
, E_TROOPDISPATCH_REINFORCE = 2
, E_TROOPDISPATCH_ATTACK_NORMAL = 3
, E_TROOPDISPATCH_ATTACK_RAID = 4
};
class CTravianTask;
typedef vector< pair<int, CTravianTask*> > Tasks;
class CTravianTask: public CEventWrapper
{
public:
eTaskExecState m_eExecState; // task execution state
int m_nVillageIndex; // The order number indexed by village creation date for one player, starting from 1.
int m_nLoc; // Represent target location. In build task, used as "id" parameter, but in upgrade task, used as "a" parameter.
COleDateTime m_dtFire;
bool m_bCanParallelExec; // whether this task can executed parallel with other tasks.
protected:
long m_nVillageID; // Village ID. -1 indicates the current player has only one village, so don't need to store village id.
bool m_bFormPost; // This task needs to post form data
bool m_bFormConfirmPost; // This task needs to post form data, and also needs post confirm form data.
CString m_sTaskDescStr; // task description string
protected:
static map<CString, vector<long> > m_mapVillageIDs; // map key is the combination of server name and user name, while value is the village IDs vector for that combination. Here don't need to adopt synchronization mechanism, but user should only user one thread to execute one server/user tasks.
public:
CTravianTask(CEventLog* pEvtLog)
: m_eExecState(E_EXEC_STATE_INITIAL)
, m_bFormPost(false)
, m_bFormConfirmPost(false)
, m_bCanParallelExec (false) {
m_pEvtLog = pEvtLog;
m_nVillageIndex = 1;
m_nVillageID = 0;
m_nLoc = -1;
};
CTravianTask(const CTravianTask& rhs) {
m_eExecState = rhs.m_eExecState;
m_bFormPost = rhs.m_bFormPost;
m_bFormConfirmPost = rhs.m_bFormConfirmPost;
m_bCanParallelExec = rhs.m_bCanParallelExec;
m_pEvtLog = rhs.m_pEvtLog;
m_nVillageIndex = rhs.m_nVillageIndex;
m_nVillageID = rhs.m_nVillageID;
m_nLoc = rhs.m_nLoc;
m_dtFire = rhs.m_dtFire;
};
virtual ~CTravianTask() {};
public:
static bool GetFormAction(CString& sHTML, CString& sFormActionURL, CEventLog& EvtLog); // Get form action URL (the fist one form).
// NOTE: Form elements tags:
// <input ...
// <select ...
// <textarea ...
// Get the given input field name/value pairs vector.
static bool GetFormInputFields(CString& sHTML, vector< pair<CString, CString> > & vecNameVal, map<CString, CString>& mapNameVal, CEventLog& EvtLog);
static bool GetFormInputFieldByIdx(vector< pair<CString, CString> > & vecNameVal, int nIndex, CString& sName, CString& sVal, CEventLog& EvtLog);
static bool GetFormInputFieldByIdx(CString& sHTML, int nIndex, CString& sName, CString& sVal, CEventLog& EvtLog);
static bool GetFormInputFieldByName(map<CString, CString>& mapNameVal, LPCTSTR lpszName, CString& sVal, CEventLog& EvtLog);
static bool GetFormInputFieldByName(CString& sHTML, LPCTSTR lpszName, CString& sVal, CEventLog& EvtLog);
static CString GetURLLoginPage() { return CString(TRAVIAN_URL_LOGINPAGE);};
static CString GetURLLoginConfirmStart() { return CString(TRAVIAN_LOGIN_CONFIRMSTART);};
static bool IsNeedLogin(CString& sHTML);
static bool GetLoginPostData(LPCTSTR lpszUName, LPCTSTR lpszUPwd, CString& sHTML, CStringA& sPostData, CString& sPostURL, CEventLog& EvtLog);
static bool GetTasks(LPCTSTR lpszTaskFile, Tasks& ts, CEventLog& EvtLog);
static void ClearTasks(Tasks& ts) { for(int i=0; i<ts.size(); i++) delete ts.at(i).second; ts.clear();};
static Tasks CloneTasks(const Tasks& ts) { Tasks ts_new; for(int i=0; i<ts.size(); i++) ts_new.push_back( make_pair(i, ts.at(i).second->Clone()) ); return ts_new;};
public:
bool GetVillageIDs(CHttpClient& http, LPCTSTR lpszSvr, LPCTSTR lpszUser, LPCTSTR lpszPwd);
inline bool GetVillageSwitchURL(CHttpClient& http, LPCTSTR lpszSvr, LPCTSTR lpszUser, LPCTSTR lpszPwd, CString& sRetURL); // if not needed to switch village, then return true and sRetURL empty. If encounter error, return false;
inline bool Login(CString& sRefererHTML, CHttpClient& http, LPCTSTR lpszSvr, LPCTSTR lpszUser, LPCTSTR lpszPwd);
eTaskExecState ExecTask(CHttpClient& http, LPCTSTR lpszSvr, LPCTSTR lpszUser, LPCTSTR lpszPwd, bool bRecursive=false);
public:
virtual CTravianTask* Clone() { return new CTravianTask(*this); };
virtual CString GetTaskRefererURL();
virtual bool GetTaskURL(CString& sHTML, CString& sRetPatURL, bool& bStopTask); // Return true: found the task upgrade url; false: not found task upgrade url.
virtual bool GetFormPostData(CString& sHTML, CStringA& sRetPostData, bool& bStopTask, bool bConfirmForm=false) { bStopTask = false; return true;};
virtual const CString& GetTaskStr();
};
// Build new building
class CTravianTaskBuild: public CTravianTask
{
public:
int m_nGroup; // Represent target group. Only needed in building task.
// To resource, the group parameter not needed, and only location can identify itself.
public:
CTravianTaskBuild(CEventLog* pEvtLog): CTravianTask(pEvtLog) {
m_nGroup = -1;
};
CTravianTaskBuild(CTravianTaskBuild& rhs):CTravianTask(rhs) {
m_nGroup = rhs.m_nGroup;
};
public:
virtual CTravianTaskBuild* Clone() { return new CTravianTaskBuild(*this); };
virtual bool GetTaskURL(CString& sHTML, CString& sRetPatURL, bool& bStopTask); // Return true: found the task building url; false: not found task build url.
virtual const CString& GetTaskStr();
};
// Development applies to: Academy, Armoury, Blacksmith
class CTravianTaskDevelop: public CTravianTask
{
public:
int m_nTroopType;
public:
CTravianTaskDevelop(CEventLog* pEvtLog): CTravianTask(pEvtLog) {
m_nTroopType = -1;
m_bCanParallelExec = true;
};
CTravianTaskDevelop(CTravianTaskDevelop& rhs):CTravianTask(rhs) {
m_nTroopType = rhs.m_nTroopType;
};
public:
virtual CTravianTaskDevelop* Clone() { return new CTravianTaskDevelop(*this); };
virtual bool GetTaskURL(CString& sHTML, CString& sRetPatURL, bool& bStopTask);
virtual const CString& GetTaskStr();
};
// Training applies to: Barracks, Stable, Workshop. Need to post form data.
class CTravianTaskTrain: public CTravianTask
{
public:
vector<TROOP> m_vecTroops; // Includes all troops event that some troops have quantity 0.
public:
CTravianTaskTrain(CEventLog* pEvtLog): CTravianTask(pEvtLog) {
m_bFormPost = true;
m_bCanParallelExec = true;
};
CTravianTaskTrain(CTravianTaskTrain& rhs):CTravianTask(rhs) {
m_vecTroops = rhs.m_vecTroops;
};
public:
virtual CTravianTaskTrain* Clone() { return new CTravianTaskTrain(*this); };
virtual bool GetFormPostData(CString& sHTML, CStringA& sRetPostData, bool& bStopTask, bool bConfirmForm=false);
virtual const CString& GetTaskStr();
};
// Transporting resource applies to Marketplace. Need to post form data.
class CTravianTaskResourceTransport: public CTravianTask
{
public:
RESOURCE m_res;
VILLAGE m_DestVillage;
public:
CTravianTaskResourceTransport(CEventLog* pEvtLog): CTravianTask(pEvtLog) {
m_bFormPost = true;
m_bFormConfirmPost = true;
m_DestVillage.nX = 0;
m_DestVillage.nY = 0;
m_bCanParallelExec = true;
};
CTravianTaskResourceTransport(CTravianTaskResourceTransport& rhs):CTravianTask(rhs) {
m_res = rhs.m_res;
m_DestVillage = rhs.m_DestVillage;
};
public:
virtual CTravianTaskResourceTransport* Clone() { return new CTravianTaskResourceTransport(*this); };
virtual bool GetFormPostData(CString& sHTML, CStringA& sRetPostData, bool& bStopTask, bool bConfirmForm=false);
virtual const CString& GetTaskStr();
};
// Dispatch troop applies to rally. Need to post form data.
class CTravianTaskDispatchTroop: public CTravianTask
{
public:
vector<TROOP> m_vecTroops;
VILLAGE m_DestVillage;
eTroopDispatchType m_eDispatchType;
public:
CTravianTaskDispatchTroop(CEventLog* pEvtLog): CTravianTask(pEvtLog) {
m_bFormPost = true;
m_bFormConfirmPost = true;
m_DestVillage.nX = 0;
m_DestVillage.nY = 0;
m_eDispatchType = E_TROOPDISPATCH_NONE;
m_bCanParallelExec = true;
for(int i=0, nTroopTyeId = TRAVIAN_TROOPTYPEID_LOWLIMIT; nTroopTyeId<= TRAVIAN_TROOPTYPEID_UPLIMIT; i++, nTroopTyeId++)
{
TROOP troop;
troop.nTypeID = nTroopTyeId;
m_vecTroops.push_back(troop);
}
};
CTravianTaskDispatchTroop(CTravianTaskDispatchTroop& rhs):CTravianTask(rhs) {
m_vecTroops = rhs.m_vecTroops;
m_DestVillage = rhs.m_DestVillage;
m_eDispatchType = rhs.m_eDispatchType;
};
public:
virtual CTravianTaskDispatchTroop* Clone() { return new CTravianTaskDispatchTroop(*this); };
virtual CString GetTaskRefererURL();
virtual bool GetFormPostData(CString& sHTML, CStringA& sRetPostData, bool& bStopTask, bool bConfirmForm=false);
virtual const CString& GetTaskStr();
};
};