From b22adbfa022abcf272426521850d8cfddd3b7051 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Wed, 24 Mar 2010 21:26:17 +0000 Subject: [PATCH] bugfix for scripted scenarios and placing unit model not showing --- source/glest_game/ai/ai.cpp | 482 ++++++++ source/glest_game/ai/ai.h | 189 +++ source/glest_game/ai/ai_interface.cpp | 238 ++++ source/glest_game/ai/ai_interface.h | 93 ++ source/glest_game/ai/ai_rule.cpp | 1030 +++++++++++++++++ source/glest_game/facilities/game_util.cpp | 12 +- source/glest_game/game/chat_manager.cpp | 2 +- source/glest_game/game/game.cpp | 43 +- source/glest_game/game/script_manager.cpp | 3 - source/glest_game/game/script_manager.h | 4 +- source/glest_game/graphics/renderer.cpp | 2 +- source/glest_game/gui/selection.cpp | 32 +- source/glest_game/main/battle_end.cpp | 2 +- source/glest_game/main/main.cpp | 32 +- source/glest_game/main/program.cpp | 56 - source/glest_game/main/program.h | 12 +- .../glest_game/menu/menu_state_scenario.cpp | 2 +- .../graphics/gl/particle_renderer_gl.cpp | 294 +++++ 18 files changed, 2381 insertions(+), 147 deletions(-) create mode 100644 source/glest_game/ai/ai.cpp create mode 100644 source/glest_game/ai/ai.h create mode 100644 source/glest_game/ai/ai_interface.cpp create mode 100644 source/glest_game/ai/ai_interface.h create mode 100644 source/glest_game/ai/ai_rule.cpp create mode 100644 source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp diff --git a/source/glest_game/ai/ai.cpp b/source/glest_game/ai/ai.cpp new file mode 100644 index 000000000..3e572d799 --- /dev/null +++ b/source/glest_game/ai/ai.cpp @@ -0,0 +1,482 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiño Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#include "ai.h" + +#include + +#include "ai_interface.h" +#include "ai_rule.h" +#include "unit_type.h" +#include "unit.h" +#include "program.h" +#include "config.h" +#include "leak_dumper.h" + +using namespace Shared::Graphics; +using namespace Shared::Util; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class ProduceTask +// ===================================================== + +ProduceTask::ProduceTask(UnitClass unitClass){ + taskClass= tcProduce; + this->unitClass= unitClass; + unitType= NULL; + resourceType= NULL; +} + +ProduceTask::ProduceTask(const UnitType *unitType){ + taskClass= tcProduce; + this->unitType= unitType; + resourceType= NULL; +} + +ProduceTask::ProduceTask(const ResourceType *resourceType){ + taskClass= tcProduce; + unitType= NULL; + this->resourceType= resourceType; +} + +string ProduceTask::toString() const{ + string str= "Produce "; + if(unitType!=NULL){ + str+= unitType->getName(); + } + return str; +} + +// ===================================================== +// class BuildTask +// ===================================================== + +BuildTask::BuildTask(const UnitType *unitType){ + taskClass= tcBuild; + this->unitType= unitType; + resourceType= NULL; + forcePos= false; +} + +BuildTask::BuildTask(const ResourceType *resourceType){ + taskClass= tcBuild; + unitType= NULL; + this->resourceType= resourceType; + forcePos= false; +} + +BuildTask::BuildTask(const UnitType *unitType, const Vec2i &pos){ + taskClass= tcBuild; + this->unitType= unitType; + resourceType= NULL; + forcePos= true; + this->pos= pos; +} + +string BuildTask::toString() const{ + string str= "Build "; + if(unitType!=NULL){ + str+= unitType->getName(); + } + return str; +} + +// ===================================================== +// class UpgradeTask +// ===================================================== + +UpgradeTask::UpgradeTask(const UpgradeType *upgradeType){ + taskClass= tcUpgrade; + this->upgradeType= upgradeType; +} + +string UpgradeTask::toString() const{ + string str= "Build "; + if(upgradeType!=NULL){ + str+= upgradeType->getName(); + } + return str; +} + +// ===================================================== +// class Ai +// ===================================================== + +void Ai::init(AiInterface *aiInterface){ + this->aiInterface= aiInterface; + startLoc= random.randRange(0, aiInterface->getMapMaxPlayers()-1); + upgradeCount= 0; + minWarriors= minMinWarriors; + randomMinWarriorsReached= false; + //add ai rules + aiRules.resize(14); + aiRules[0]= new AiRuleWorkerHarvest(this); + aiRules[1]= new AiRuleRefreshHarvester(this); + aiRules[2]= new AiRuleScoutPatrol(this); + aiRules[3]= new AiRuleReturnBase(this); + aiRules[4]= new AiRuleMassiveAttack(this); + aiRules[5]= new AiRuleAddTasks(this); + aiRules[6]= new AiRuleProduceResourceProducer(this); + aiRules[7]= new AiRuleBuildOneFarm(this); + aiRules[8]= new AiRuleProduce(this); + aiRules[9]= new AiRuleBuild(this); + aiRules[10]= new AiRuleUpgrade(this); + aiRules[11]= new AiRuleExpand(this); + aiRules[12]= new AiRuleRepair(this); + aiRules[13]= new AiRuleRepair(this); +} + +Ai::~Ai(){ + deleteValues(tasks.begin(), tasks.end()); + deleteValues(aiRules.begin(), aiRules.end()); +} + +void Ai::update(){ + //process ai rules + for(AiRules::iterator it= aiRules.begin(); it!=aiRules.end(); ++it){ + if((aiInterface->getTimer() % ((*it)->getTestInterval()*GameConstants::updateFps/1000))==0){ + if((*it)->test()){ + aiInterface->printLog(3, intToStr(1000*aiInterface->getTimer()/GameConstants::updateFps) + ": Executing rule: " + (*it)->getName() + '\n'); + (*it)->execute(); + } + } + } +} + + +// ==================== state requests ==================== + +int Ai::getCountOfType(const UnitType *ut){ + int count= 0; + for(int i=0; igetMyUnitCount(); ++i){ + if(ut == aiInterface->getMyUnit(i)->getType()){ + count++; + } + } + return count; +} + +int Ai::getCountOfClass(UnitClass uc){ + int count= 0; + for(int i=0; igetMyUnitCount(); ++i){ + if(aiInterface->getMyUnit(i)->getType()->isOfClass(uc)){ + ++count; + } + } + return count; +} + +float Ai::getRatioOfClass(UnitClass uc){ + if(aiInterface->getMyUnitCount()==0){ + return 0; + } + else{ + return static_cast(getCountOfClass(uc))/aiInterface->getMyUnitCount(); + } +} + +const ResourceType *Ai::getNeededResource(){ + + int amount= -1; + const ResourceType *neededResource= NULL; + const TechTree *tt= aiInterface->getTechTree(); + + for(int i=0; igetResourceTypeCount(); ++i){ + const ResourceType *rt= tt->getResourceType(i); + const Resource *r= aiInterface->getResource(rt); + if(rt->getClass()!=rcStatic && rt->getClass()!=rcConsumable && (r->getAmount()getAmount(); + neededResource= rt; + } + } + + return neededResource; +} + +bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){ + int count= aiInterface->onSightUnitCount(); + const Unit *unit; + + for(int i=0; igetOnSightUnit(i); + if(!aiInterface->isAlly(unit) && unit->isAlive()){ + pos= unit->getPos(); + field= unit->getCurrField(); + if(pos.dist(aiInterface->getHomeLocation())printLog(2, "Being attacked at pos "+intToStr(pos.x)+","+intToStr(pos.y)+"\n"); + return true; + } + } + } + return false; +} + +bool Ai::isStableBase(){ + + if(getCountOfClass(ucWarrior)>minWarriors){ + aiInterface->printLog(4, "Base is stable\n"); + return true; + } + else{ + aiInterface->printLog(4, "Base is not stable\n"); + return false; + } +} + +bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, bool idleOnly){ + vector units; + + *unitIndex= -1; + for(int i=0; igetMyUnitCount(); ++i){ + const Unit *unit= aiInterface->getMyUnit(i); + if(unit->getType()->hasCommandClass(ability)){ + if(!idleOnly || !unit->anyCommand() || unit->getCurrCommand()->getCommandType()->getClass()==ccStop){ + units.push_back(i); + } + } + } + + if(units.empty()){ + return false; + } + else{ + *unitIndex= units[random.randRange(0, units.size()-1)]; + return true; + } +} + +bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, CommandClass currentCommand){ + vector units; + + *unitIndex= -1; + for(int i=0; igetMyUnitCount(); ++i){ + const Unit *unit= aiInterface->getMyUnit(i); + if(unit->getType()->hasCommandClass(ability)){ + if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass()==currentCommand){ + units.push_back(i); + } + } + } + + if(units.empty()){ + return false; + } + else{ + *unitIndex= units[random.randRange(0, units.size()-1)]; + return true; + } +} + +bool Ai::findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Vec2i &outPos){ + + const int spacing= 1; + + for(int currRadius=0; currRadiusisFreeCells(outPos-Vec2i(spacing), building->getSize()+spacing*2, fLand)){ + return true; + } + } + } + } + + return false; + +} + + +// ==================== tasks ==================== + +void Ai::addTask(const Task *task){ + tasks.push_back(task); + aiInterface->printLog(2, "Task added: " + task->toString()); +} + +void Ai::addPriorityTask(const Task *task){ + deleteValues(tasks.begin(), tasks.end()); + tasks.clear(); + + tasks.push_back(task); + aiInterface->printLog(2, "Priority Task added: " + task->toString()); +} + +bool Ai::anyTask(){ + return !tasks.empty(); +} + +const Task *Ai::getTask() const{ + if(tasks.empty()){ + return NULL; + } + else{ + return tasks.front(); + } +} + +void Ai::removeTask(const Task *task){ + aiInterface->printLog(2, "Task removed: " + task->toString()); + tasks.remove(task); + delete task; +} + +void Ai::retryTask(const Task *task){ + tasks.remove(task); + tasks.push_back(task); +} +// ==================== expansions ==================== + +void Ai::addExpansion(const Vec2i &pos){ + + //check if there is a nearby expansion + for(Positions::iterator it= expansionPositions.begin(); it!=expansionPositions.end(); ++it){ + if((*it).dist(pos)maxExpansions){ + expansionPositions.pop_back(); + } +} + +Vec2i Ai::getRandomHomePosition(){ + + if(expansionPositions.empty() || random.randRange(0, 1) == 0){ + return aiInterface->getHomeLocation(); + } + + return expansionPositions[random.randRange(0, expansionPositions.size()-1)]; +} + +// ==================== actions ==================== + +void Ai::sendScoutPatrol(){ + Vec2i pos; + int unit; + + startLoc= (startLoc+1) % aiInterface->getMapMaxPlayers(); + pos= aiInterface->getStartLocation(startLoc); + + if(aiInterface->getFactionIndex()!=startLoc){ + if(findAbleUnit(&unit, ccAttack, false)){ + aiInterface->giveCommand(unit, ccAttack, pos); + aiInterface->printLog(2, "Scout patrol sent to: " + intToStr(pos.x)+","+intToStr(pos.y)+"\n"); + } + } + +} + +void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){ + int producerWarriorCount=0; + int maxProducerWarriors=random.randRange(1,11); + for(int i=0; igetMyUnitCount(); ++i){ + bool isWarrior; + const Unit *unit= aiInterface->getMyUnit(i); + const AttackCommandType *act= unit->getType()->getFirstAttackCommand(field); + if(act!=NULL && unit->getType()->hasCommandClass(ccProduce)) + { + producerWarriorCount++; + } + + if(aiInterface->getControlType()==ctCpuMega) + { + if(producerWarriorCount>maxProducerWarriors) + { + if( + unit->getCommandSize()>0 && + unit->getCurrCommand()->getCommandType()!=NULL && ( + unit->getCurrCommand()->getCommandType()->getClass()==ccBuild || + unit->getCurrCommand()->getCommandType()->getClass()==ccMorph || + unit->getCurrCommand()->getCommandType()->getClass()==ccProduce + ) + ) + { + isWarrior=false; + } + else + { + isWarrior=!unit->getType()->hasCommandClass(ccHarvest); + } + } + else + { + isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce); + } + } + else + { + isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce); + } + + + bool alreadyAttacking= unit->getCurrSkill()->getClass()==scAttack; + if(!alreadyAttacking && act!=NULL && (ultraAttack || isWarrior)){ + aiInterface->giveCommand(i, act, pos); + } + } + + if(aiInterface->getControlType()==ctCpuEasy) + { + minWarriors+= 1; + } + else if(aiInterface->getControlType()==ctCpuMega) + { + minWarriors+= 3; + if(minWarriors>maxMinWarriors-1 || randomMinWarriorsReached) + { + randomMinWarriorsReached=true; + minWarriors=random.randRange(maxMinWarriors-10, maxMinWarriors*2); + } + } + else if(minWarriorsprintLog(2, "Massive attack to pos: "+ intToStr(pos.x)+", "+intToStr(pos.y)+"\n"); +} + +void Ai::returnBase(int unitIndex){ + Vec2i pos; + CommandResult r; + int fi; + + fi= aiInterface->getFactionIndex(); + pos= Vec2i( + random.randRange(-villageRadius, villageRadius), random.randRange(-villageRadius, villageRadius)) + + getRandomHomePosition(); + r= aiInterface->giveCommand(unitIndex, ccMove, pos); + + //aiInterface->printLog(1, "Order return to base pos:" + intToStr(pos.x)+", "+intToStr(pos.y)+": "+rrToStr(r)+"\n"); +} + +void Ai::harvest(int unitIndex){ + + const ResourceType *rt= getNeededResource(); + + if(rt!=NULL){ + const HarvestCommandType *hct= aiInterface->getMyUnit(unitIndex)->getType()->getFirstHarvestCommand(rt); + Vec2i resPos; + if(hct!=NULL && aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), resPos)){ + resPos= resPos+Vec2i(random.randRange(-2, 2), random.randRange(-2, 2)); + aiInterface->giveCommand(unitIndex, hct, resPos); + //aiInterface->printLog(4, "Order harvest pos:" + intToStr(resPos.x)+", "+intToStr(resPos.y)+": "+rrToStr(r)+"\n"); + } + } +} + +}}//end namespace diff --git a/source/glest_game/ai/ai.h b/source/glest_game/ai/ai.h new file mode 100644 index 000000000..d80d2a6fa --- /dev/null +++ b/source/glest_game/ai/ai.h @@ -0,0 +1,189 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiño Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef _GLEST_GAME_AI_H_ +#define _GLEST_GAME_AI_H_ + +#include +#include + +#include "world.h" +#include "commander.h" +#include "command.h" +#include "random.h" + +using std::deque; +using std::vector; +using std::list; +using Shared::Util::Random; + +namespace Glest{ namespace Game{ + +class AiInterface; +class AiRule; + +// ===================================================== +// class Task +// +/// An action that has to be performed by the IA +// ===================================================== + +enum TaskClass{ + tcProduce, + tcBuild, + tcUpgrade +}; + +class Task{ +protected: + TaskClass taskClass; + +public: + virtual ~Task(){} + TaskClass getClass() const {return taskClass;} + virtual string toString() const= 0; +}; + +// ==================== ProduceTask ==================== + +class ProduceTask: public Task{ +private: + UnitClass unitClass; + const UnitType *unitType; + const ResourceType *resourceType; + +public: + ProduceTask(UnitClass unitClass); + ProduceTask(const UnitType *unitType); + ProduceTask(const ResourceType *resourceType); + + UnitClass getUnitClass() const {return unitClass;} + const UnitType *getUnitType() const {return unitType;} + const ResourceType *getResourceType() const {return resourceType;} + virtual string toString() const; +}; + +// ==================== BuildTask ==================== + +class BuildTask: public Task{ +private: + const UnitType *unitType; + const ResourceType *resourceType; + bool forcePos; + Vec2i pos; + +public: + BuildTask(const UnitType *unitType= NULL); + BuildTask(const ResourceType *resourceType); + BuildTask(const UnitType *unitType, const Vec2i &pos); + + const UnitType *getUnitType() const {return unitType;} + const ResourceType *getResourceType() const {return resourceType;} + bool getForcePos() const {return forcePos;} + Vec2i getPos() const {return pos;} + virtual string toString() const; +}; + +// ==================== UpgradeTask ==================== + +class UpgradeTask: public Task{ +private: + const UpgradeType *upgradeType; + +public: + UpgradeTask(const UpgradeType *upgradeType= NULL); + const UpgradeType *getUpgradeType() const {return upgradeType;} + virtual string toString() const; +}; + +// =============================== +// class AI +// +/// Main AI class +// =============================== + +class Ai{ +private: + static const int harvesterPercent= 30; + static const int maxBuildRadius= 40; + static const int minMinWarriors= 7; + static const int maxMinWarriors= 20; + static const int minStaticResources= 10; + static const int minConsumableResources= 20; + static const int maxExpansions= 2; + static const int villageRadius= 15; + +public: + enum ResourceUsage{ + ruHarvester, + ruWarrior, + ruBuilding, + ruUpgrade + }; + +private: + typedef vector AiRules; + typedef list Tasks; + typedef deque Positions; + +private: + AiInterface *aiInterface; + AiRules aiRules; + int startLoc; + bool randomMinWarriorsReached; + int upgradeCount; + Tasks tasks; + Positions expansionPositions; + Random random; + +public: + int minWarriors; + ~Ai(); + void init(AiInterface *aiInterface); + void update(); + + //state requests + AiInterface *getAiInterface() const {return aiInterface;} + Random* getRandom() {return &random;} + int getCountOfType(const UnitType *ut); + + int getCountOfClass(UnitClass uc); + float getRatioOfClass(UnitClass uc); + + const ResourceType *getNeededResource(); + bool isStableBase(); + bool findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Vec2i &pos); + bool findAbleUnit(int *unitIndex, CommandClass ability, bool idleOnly); + bool findAbleUnit(int *unitIndex, CommandClass ability, CommandClass currentCommand); + bool beingAttacked(Vec2i &pos, Field &field, int radius); + + //tasks + void addTask(const Task *task); + void addPriorityTask(const Task *task); + bool anyTask(); + const Task *getTask() const; + void removeTask(const Task *task); + void retryTask(const Task *task); + + //expansions + void addExpansion(const Vec2i &pos); + Vec2i getRandomHomePosition(); + + //actions + void sendScoutPatrol(); + void massiveAttack(const Vec2i &pos, Field field, bool ultraAttack= false); + void returnBase(int unitIndex); + void harvest(int unitIndex); +}; + +}}//end namespace + +#endif diff --git a/source/glest_game/ai/ai_interface.cpp b/source/glest_game/ai/ai_interface.cpp new file mode 100644 index 000000000..9770c03c2 --- /dev/null +++ b/source/glest_game/ai/ai_interface.cpp @@ -0,0 +1,238 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiño Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#include "ai_interface.h" + +#include "ai.h" +#include "command_type.h" +#include "faction.h" +#include "unit.h" +#include "unit_type.h" +#include "object.h" +#include "game.h" +#include "config.h" +#include "leak_dumper.h" + +using namespace Shared::Util; +using namespace Shared::Graphics; + +// ===================================================== +// class AiInterface +// ===================================================== + +namespace Glest{ namespace Game{ + +AiInterface::AiInterface(Game &game, int factionIndex, int teamIndex){ + this->world= game.getWorld(); + this->commander= game.getCommander(); + this->console= game.getConsole(); + + this->factionIndex= factionIndex; + this->teamIndex= teamIndex; + timer= 0; + + //init ai + ai.init(this); + + //config + logLevel= Config::getInstance().getInt("AiLog"); + redir= Config::getInstance().getBool("AiRedir"); + + //clear log file + if(logLevel>0){ + FILE *f= fopen(getLogFilename().c_str(), "wt"); + if(f==NULL){ + throw runtime_error("Can't open file: "+getLogFilename()); + } + fprintf(f, "%s", "Glest AI log file\n\n"); + fclose(f); + } +} + +// ==================== main ==================== + +void AiInterface::update(){ + timer++; + ai.update(); +} + +// ==================== misc ==================== + +void AiInterface::printLog(int logLevel, const string &s){ + if(this->logLevel>=logLevel){ + string logString= "(" + intToStr(factionIndex) + ") " + s; + + //print log to file + FILE *f= fopen(getLogFilename().c_str(), "at"); + if(f==NULL){ + throw runtime_error("Can't open file: "+getLogFilename()); + } + fprintf(f, "%s\n", logString.c_str()); + fclose(f); + + //redirect to console + if(redir) { + console->addLine(logString); + } + } +} + +// ==================== interaction ==================== + +CommandResult AiInterface::giveCommand(int unitIndex, CommandClass commandClass, const Vec2i &pos){ + Command *c= new Command (world->getFaction(factionIndex)->getUnit(unitIndex)->getType()->getFirstCtOfClass(commandClass), pos); + return world->getFaction(factionIndex)->getUnit(unitIndex)->giveCommand(c); +} + +CommandResult AiInterface::giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos){ + return world->getFaction(factionIndex)->getUnit(unitIndex)->giveCommand(new Command(commandType, pos)); +} + +CommandResult AiInterface::giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos, const UnitType *ut){ + return world->getFaction(factionIndex)->getUnit(unitIndex)->giveCommand(new Command(commandType, pos, ut)); +} + +CommandResult AiInterface::giveCommand(int unitIndex, const CommandType *commandType, Unit *u){ + return world->getFaction(factionIndex)->getUnit(unitIndex)->giveCommand(new Command(commandType, u)); +} + +// ==================== get data ==================== + +int AiInterface::getMapMaxPlayers(){ + return world->getMaxPlayers(); +} + +Vec2i AiInterface::getHomeLocation(){ + return world->getMap()->getStartLocation(world->getFaction(factionIndex)->getStartLocationIndex()); +} + +Vec2i AiInterface::getStartLocation(int loactionIndex){ + return world->getMap()->getStartLocation(loactionIndex); +} + +int AiInterface::getFactionCount(){ + return world->getFactionCount(); +} + +int AiInterface::getMyUnitCount() const{ + return world->getFaction(factionIndex)->getUnitCount(); +} + +int AiInterface::getMyUpgradeCount() const{ + return world->getFaction(factionIndex)->getUpgradeManager()->getUpgradeCount(); +} + +int AiInterface::onSightUnitCount(){ + int count=0; + Map *map= world->getMap(); + for(int i=0; igetFactionCount(); ++i){ + for(int j=0; jgetFaction(i)->getUnitCount(); ++j){ + SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(world->getFaction(i)->getUnit(j)->getPos())); + if(sc->isVisible(teamIndex)){ + count++; + } + } + } + return count; +} + +const Resource *AiInterface::getResource(const ResourceType *rt){ + return world->getFaction(factionIndex)->getResource(rt); +} + +const Unit *AiInterface::getMyUnit(int unitIndex){ + return world->getFaction(factionIndex)->getUnit(unitIndex); +} + +const Unit *AiInterface::getOnSightUnit(int unitIndex){ + + int count=0; + Map *map= world->getMap(); + + for(int i=0; igetFactionCount(); ++i){ + for(int j=0; jgetFaction(i)->getUnitCount(); ++j){ + Unit *u= world->getFaction(i)->getUnit(j); + if(map->getSurfaceCell(Map::toSurfCoords(u->getPos()))->isVisible(teamIndex)){ + if(count==unitIndex){ + return u; + } + else{ + count ++; + } + } + } + } + return NULL; +} + +const FactionType * AiInterface::getMyFactionType(){ + return world->getFaction(factionIndex)->getType(); +} + +const ControlType AiInterface::getControlType(){ + return world->getFaction(factionIndex)->getControlType(); +} + +const TechTree *AiInterface::getTechTree(){ + return world->getTechTree(); +} + +bool AiInterface::getNearestSightedResource(const ResourceType *rt, const Vec2i &pos, Vec2i &resultPos){ + float tmpDist; + + float nearestDist= infinity; + bool anyResource= false; + + const Map *map= world->getMap(); + + for(int i=0; igetW(); ++i){ + for(int j=0; jgetH(); ++j){ + Vec2i surfPos= Map::toSurfCoords(Vec2i(i, j)); + + //if explored cell + if(map->getSurfaceCell(surfPos)->isExplored(teamIndex)){ + Resource *r= map->getSurfaceCell(surfPos)->getResource(); + + //if resource cell + if(r!=NULL && r->getType()==rt){ + tmpDist= pos.dist(Vec2i(i, j)); + if(tmpDistgetFaction(factionIndex)->isAlly(unit->getFaction()); +} +bool AiInterface::reqsOk(const RequirableType *rt){ + return world->getFaction(factionIndex)->reqsOk(rt); +} + +bool AiInterface::reqsOk(const CommandType *ct){ + return world->getFaction(factionIndex)->reqsOk(ct); +} + +bool AiInterface::checkCosts(const ProducibleType *pt){ + return world->getFaction(factionIndex)->checkCosts(pt); +} + +bool AiInterface::isFreeCells(const Vec2i &pos, int size, Field field){ + return world->getMap()->isFreeCells(pos, size, field); +} + +}}//end namespace diff --git a/source/glest_game/ai/ai_interface.h b/source/glest_game/ai/ai_interface.h new file mode 100644 index 000000000..c3f8b8426 --- /dev/null +++ b/source/glest_game/ai/ai_interface.h @@ -0,0 +1,93 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiño Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef _GLEST_GAME_AIINTERFACE_H_ +#define _GLEST_GAME_AIINTERFACE_H_ + +#include "world.h" +#include "commander.h" +#include "command.h" +#include "conversion.h" +#include "ai.h" + +using Shared::Util::intToStr; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class AiInterface +// +/// The AI will interact with the game through this interface +// ===================================================== + +class AiInterface{ +private: + World *world; + Commander *commander; + Console *console; + Ai ai; + + int timer; + int factionIndex; + int teamIndex; + + //config + bool redir; + int logLevel; + +public: + AiInterface(Game &game, int factionIndex, int teamIndex); + + //main + void update(); + + //get + int getTimer() const {return timer;} + int getFactionIndex() const {return factionIndex;} + + //misc + void printLog(int logLevel, const string &s); + + //interact + CommandResult giveCommand(int unitIndex, CommandClass commandClass, const Vec2i &pos=Vec2i(0)); + CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType); + CommandResult giveCommand(int unitIndex, const CommandType *commandType, const Vec2i &pos); + CommandResult giveCommand(int unitIndex, const CommandType *commandType, Unit *u= NULL); + + //get data + const ControlType getControlType(); + int getMapMaxPlayers(); + Vec2i getHomeLocation(); + Vec2i getStartLocation(int locationIndex); + int getFactionCount(); + int getMyUnitCount() const; + int getMyUpgradeCount() const; + int onSightUnitCount(); + const Resource *getResource(const ResourceType *rt); + const Unit *getMyUnit(int unitIndex); + const Unit *getOnSightUnit(int unitIndex); + const FactionType *getMyFactionType(); + const TechTree *getTechTree(); + bool getNearestSightedResource(const ResourceType *rt, const Vec2i &pos, Vec2i &resultPos); + bool isAlly(const Unit *unit) const; + bool isAlly(int factionIndex) const; + bool reqsOk(const RequirableType *rt); + bool reqsOk(const CommandType *ct); + bool checkCosts(const ProducibleType *pt); + bool isFreeCells(const Vec2i &pos, int size, Field field); + +private: + string getLogFilename() const {return "ai"+intToStr(factionIndex)+".log";} +}; + +}}//end namespace + +#endif diff --git a/source/glest_game/ai/ai_rule.cpp b/source/glest_game/ai/ai_rule.cpp new file mode 100644 index 000000000..3904822c5 --- /dev/null +++ b/source/glest_game/ai/ai_rule.cpp @@ -0,0 +1,1030 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiño Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== +#include "ai_rule.h" + +#include +#include + +#include "ai.h" +#include "ai_interface.h" +#include "unit.h" +#include "leak_dumper.h" + +using Shared::Graphics::Vec2i; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class AiRule +// ===================================================== + +AiRule::AiRule(Ai *ai){ + this->ai= ai; +} + +// ===================================================== +// class AiRuleWorkerHarvest +// ===================================================== + +AiRuleWorkerHarvest::AiRuleWorkerHarvest(Ai *ai): + AiRule(ai) +{ + stoppedWorkerIndex= -1; +} + +bool AiRuleWorkerHarvest::test(){ + return ai->findAbleUnit(&stoppedWorkerIndex, ccHarvest, true); +} + +void AiRuleWorkerHarvest::execute(){ + ai->harvest(stoppedWorkerIndex); +} + +// ===================================================== +// class AiRuleRefreshHarvester +// ===================================================== + +AiRuleRefreshHarvester::AiRuleRefreshHarvester(Ai *ai): + AiRule(ai) +{ + workerIndex= -1; +} + +bool AiRuleRefreshHarvester::test(){ + return ai->findAbleUnit(&workerIndex, ccHarvest, ccHarvest); +} + +void AiRuleRefreshHarvester::execute(){ + ai->harvest(workerIndex); +} + +// ===================================================== +// class AiRuleScoutPatrol +// ===================================================== + +AiRuleScoutPatrol::AiRuleScoutPatrol(Ai *ai): + AiRule(ai) +{ +} + +bool AiRuleScoutPatrol::test(){ + return ai->isStableBase(); +} + +void AiRuleScoutPatrol::execute(){ + ai->sendScoutPatrol(); +} +// ===================================================== +// class AiRuleRepair +// ===================================================== + +AiRuleRepair::AiRuleRepair(Ai *ai): + AiRule(ai) +{ +} + +bool AiRuleRepair::test(){ + AiInterface *aiInterface= ai->getAiInterface(); + + //look for a damaged unit + for(int i=0; igetMyUnitCount(); ++i){ + const Unit *u= aiInterface->getMyUnit(i); + if(u->getHpRatio()<1.f){ + damagedUnitIndex= i; + return true; + } + } + return false; +} + +void AiRuleRepair::execute(){ + AiInterface *aiInterface= ai->getAiInterface(); + const Unit *damagedUnit= aiInterface->getMyUnit(damagedUnitIndex); + + //find a repairer and issue command + for(int i=0; igetMyUnitCount(); ++i){ + const Unit *u= aiInterface->getMyUnit(i); + const RepairCommandType *rct= static_cast(u->getType()->getFirstCtOfClass(ccRepair)); + if(rct!=NULL && (u->getCurrSkill()->getClass()==scStop || u->getCurrSkill()->getClass()==scMove)){ + if(rct->isRepairableUnitType(damagedUnit->getType())){ + aiInterface->giveCommand(i, rct, damagedUnit->getPos()); + aiInterface->printLog(3, "Repairing order issued"); + return; + } + } + } +} + +// ===================================================== +// class AiRuleReturnBase +// ===================================================== + +AiRuleReturnBase::AiRuleReturnBase(Ai *ai): + AiRule(ai) +{ + stoppedUnitIndex= -1; +} + +bool AiRuleReturnBase::test(){ + return ai->findAbleUnit(&stoppedUnitIndex, ccMove, true); +} + +void AiRuleReturnBase::execute(){ + ai->returnBase(stoppedUnitIndex); +} + +// ===================================================== +// class AiRuleMassiveAttack +// ===================================================== + +AiRuleMassiveAttack::AiRuleMassiveAttack(Ai *ai): + AiRule(ai) +{ +} + +bool AiRuleMassiveAttack::test(){ + + if(ai->isStableBase()){ + ultraAttack= false; + return ai->beingAttacked(attackPos, field, INT_MAX); + } + else{ + ultraAttack= true; + return ai->beingAttacked(attackPos, field, baseRadius); + } +} + +void AiRuleMassiveAttack::execute(){ + ai->massiveAttack(attackPos, field, ultraAttack); +} +// ===================================================== +// class AiRuleAddTasks +// ===================================================== + +AiRuleAddTasks::AiRuleAddTasks(Ai *ai): + AiRule(ai) +{ +} + +bool AiRuleAddTasks::test(){ + return !ai->anyTask() || ai->getCountOfClass(ucWorker)<4; +} + +void AiRuleAddTasks::execute(){ + int buildingCount= ai->getCountOfClass(ucBuilding); + int warriorCount= ai->getCountOfClass(ucWarrior); + int workerCount= ai->getCountOfClass(ucWorker); + int upgradeCount= ai->getAiInterface()->getMyUpgradeCount(); + + float buildingRatio= ai->getRatioOfClass(ucBuilding); + float warriorRatio= ai->getRatioOfClass(ucWarrior); + float workerRatio= ai->getRatioOfClass(ucWorker); + + //standard tasks + + //emergency workers + if(workerCount<4){ + ai->addPriorityTask(new ProduceTask(ucWorker)); + } + else{ + if(ai->getAiInterface()->getControlType()==ctCpuMega) + { + //workers + if(workerCount<5) ai->addTask(new ProduceTask(ucWorker)); + if(workerCount<10) ai->addTask(new ProduceTask(ucWorker)); + if(workerRatio<0.20) ai->addTask(new ProduceTask(ucWorker)); + if(workerRatio<0.30) ai->addTask(new ProduceTask(ucWorker)); + + //warriors + if(warriorCount<10) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.20) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.30) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=10) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=15) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorCountminWarriors+2) + { + ai->addTask(new ProduceTask(ucWarrior)); + if( buildingCount>9 ) + { + ai->addTask(new ProduceTask(ucWarrior)); + ai->addTask(new ProduceTask(ucWarrior)); + } + if( buildingCount>12 ) + { + ai->addTask(new ProduceTask(ucWarrior)); + ai->addTask(new ProduceTask(ucWarrior)); + } + } + + //buildings + if(buildingCount<6 || buildingRatio<0.20) ai->addTask(new BuildTask()); + if(buildingCount<10 && workerCount>12) ai->addTask(new BuildTask()); + //upgrades + if(upgradeCount==0 && workerCount>5) ai->addTask(new UpgradeTask()); + if(upgradeCount==1 && workerCount>10) ai->addTask(new UpgradeTask()); + if(upgradeCount==2 && workerCount>15) ai->addTask(new UpgradeTask()); + if(ai->isStableBase()) ai->addTask(new UpgradeTask()); + } + else if(ai->getAiInterface()->getControlType()==ctCpuEasy) + {// Easy CPU + //workers + if(workerCountaddTask(new ProduceTask(ucWorker)); + if(workerCount>5 && workerRatio<0.20) ai->addTask(new ProduceTask(ucWorker)); + + //warriors + if(warriorCount<10) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.20) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.30) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=10) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=15) ai->addTask(new ProduceTask(ucWarrior)); + + //buildings + if(buildingCount<6 || buildingRatio<0.20) ai->addTask(new BuildTask()); + if(buildingCount<10 && ai->isStableBase()) ai->addTask(new BuildTask()); + + //upgrades + if(upgradeCount==0 && workerCount>6) ai->addTask(new UpgradeTask()); + if(upgradeCount==1 && workerCount>7) ai->addTask(new UpgradeTask()); + if(upgradeCount==2 && workerCount>9) ai->addTask(new UpgradeTask()); + //if(ai->isStableBase()) ai->addTask(new UpgradeTask()); + } + else + {// normal CPU / UltraCPU ... + //workers + if(workerCount<5) ai->addTask(new ProduceTask(ucWorker)); + if(workerCount<10) ai->addTask(new ProduceTask(ucWorker)); + if(workerRatio<0.20) ai->addTask(new ProduceTask(ucWorker)); + if(workerRatio<0.30) ai->addTask(new ProduceTask(ucWorker)); + + //warriors + if(warriorCount<10) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.20) ai->addTask(new ProduceTask(ucWarrior)); + if(warriorRatio<0.30) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=10) ai->addTask(new ProduceTask(ucWarrior)); + if(workerCount>=15) ai->addTask(new ProduceTask(ucWarrior)); + + //buildings + if(buildingCount<6 || buildingRatio<0.20) ai->addTask(new BuildTask()); + if(buildingCount<10 && workerCount>12) ai->addTask(new BuildTask()); + + //upgrades + if(upgradeCount==0 && workerCount>5) ai->addTask(new UpgradeTask()); + if(upgradeCount==1 && workerCount>10) ai->addTask(new UpgradeTask()); + if(upgradeCount==2 && workerCount>15) ai->addTask(new UpgradeTask()); + if(ai->isStableBase()) ai->addTask(new UpgradeTask()); + } + } +} + +// ===================================================== +// class AiRuleBuildOneFarm +// ===================================================== + +AiRuleBuildOneFarm::AiRuleBuildOneFarm(Ai *ai): + AiRule(ai) +{ +} + +bool AiRuleBuildOneFarm::test(){ + AiInterface *aiInterface= ai->getAiInterface(); + + //for all units + for(int i=0; igetMyFactionType()->getUnitTypeCount(); ++i){ + const UnitType *ut= aiInterface->getMyFactionType()->getUnitType(i); + + //for all production commands + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + if(ct->getClass()==ccProduce){ + const UnitType *producedType= static_cast(ct)->getProducedUnit(); + + //for all resources + for(int k=0; kgetCostCount(); ++k){ + const Resource *r= producedType->getCost(k); + + //find a food producer in the farm produced units + if(r->getAmount()<0 && r->getType()->getClass()==rcConsumable && ai->getCountOfType(ut)==0){ + farm= ut; + return true; + } + } + } + } + } + return false; +} + +void AiRuleBuildOneFarm::execute(){ + ai->addPriorityTask(new BuildTask(farm)); +} + +// ===================================================== +// class AiRuleProduceResourceProducer +// ===================================================== + +AiRuleProduceResourceProducer::AiRuleProduceResourceProducer(Ai *ai): + AiRule(ai) +{ + interval= shortInterval; +} + +bool AiRuleProduceResourceProducer::test(){ + //emergency tasks: resource buildings + AiInterface *aiInterface= ai->getAiInterface(); + + //consumables first + for(int i=0; igetTechTree()->getResourceTypeCount(); ++i){ + rt= aiInterface->getTechTree()->getResourceType(i); + const Resource *r= aiInterface->getResource(rt); + if(rt->getClass()==rcConsumable && r->getBalance()<0){ + interval= longInterval; + return true; + + } + } + + //statics second + for(int i=0; igetTechTree()->getResourceTypeCount(); ++i){ + rt= aiInterface->getTechTree()->getResourceType(i); + const Resource *r= aiInterface->getResource(rt); + if(rt->getClass()==rcStatic && r->getAmount()addPriorityTask(new ProduceTask(rt)); + ai->addTask(new BuildTask(rt)); +} + +// ===================================================== +// class AiRuleProduce +// ===================================================== + +AiRuleProduce::AiRuleProduce(Ai *ai): + AiRule(ai) +{ + produceTask= NULL; +} + +bool AiRuleProduce::test(){ + const Task *task= ai->getTask(); + + if(task==NULL || task->getClass()!=tcProduce){ + return false; + } + + produceTask= static_cast(task); + return true; +} + +void AiRuleProduce::execute(){ + if(produceTask!=NULL){ + + //generic produce task, produce random unit that has the skill or produces the resource + if(produceTask->getUnitType()==NULL){ + produceGeneric(produceTask); + } + + //specific produce task, produce if possible, retry if not enough resources + else{ + produceSpecific(produceTask); + } + + //remove the task + ai->removeTask(produceTask); + } +} + +void AiRuleProduce::produceGeneric(const ProduceTask *pt){ + typedef vector UnitTypes; + UnitTypes ableUnits; + AiInterface *aiInterface= ai->getAiInterface(); + + //for each unit, produce it if possible + for(int i=0; igetMyUnitCount(); ++i){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is produce + if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){ + + const UnitType *producedUnit= static_cast(ct->getProduced()); + bool produceIt= false; + + //if the unit produces the resource + if(pt->getResourceType()!=NULL){ + const Resource *r= producedUnit->getCost(pt->getResourceType()); + if(r!=NULL && r->getAmount()<0){ + produceIt= true; + } + } + + else{ + //if the unit is from the right class + if(producedUnit->isOfClass(pt->getUnitClass())){ + if(aiInterface->reqsOk(ct) && aiInterface->reqsOk(producedUnit)){ + produceIt= true; + } + } + } + + if(produceIt){ + //if the unit is not already on the list + if(find(ableUnits.begin(), ableUnits.end(), producedUnit)==ableUnits.end()){ + ableUnits.push_back(producedUnit); + } + } + } + } + } + + //add specific produce task + if(!ableUnits.empty()){ + + //priority for non produced units + for(unsigned int i=0; igetCountOfType(ableUnits[i])==0){ + if(ai->getRandom()->randRange(0, 1)==0){ + ai->addTask(new ProduceTask(ableUnits[i])); + return; + } + } + } + + //normal case + ai->addTask(new ProduceTask(ableUnits[ai->getRandom()->randRange(0, ableUnits.size()-1)])); + } +} + +void AiRuleProduce::produceSpecific(const ProduceTask *pt){ + + AiInterface *aiInterface= ai->getAiInterface(); + + //if unit meets requirements + if(aiInterface->reqsOk(pt->getUnitType())){ + + //if unit doesnt meet resources retry + if(!aiInterface->checkCosts(pt->getUnitType())){ + ai->retryTask(pt); + return; + } + + //produce specific unit + vector producers; + const CommandType *defCt= NULL; + + //for each unit + for(int i=0; igetMyUnitCount(); ++i){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is produce + if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){ + const UnitType *producedUnit= static_cast(ct->getProduced()); + + //if units match + if(producedUnit == pt->getUnitType()){ + if(aiInterface->reqsOk(ct)){ + defCt= ct; + producers.push_back(i); + } + } + } + } + } + + //produce from random producer + if(!producers.empty()){ + if(aiInterface->getControlType()==ctCpuMega) + {// mega cpu trys to balance the commands to the producers + int randomstart=ai->getRandom()->randRange(0, producers.size()-1); + int lowestCommandCount=1000000; + int currentProducerIndex=producers[randomstart]; + int bestIndex=-1; + int besti=0; + int currentCommandCount=0; + for(unsigned int i=randomstart; igetMyUnit(currentProducerIndex)->getCommandSize(); + if( currentCommandCount==1 && + aiInterface->getMyUnit(currentProducerIndex)->getCurrCommand()->getCommandType()->getClass()==ccStop) + {// special for non buildings + currentCommandCount=0; + } + if(lowestCommandCount>currentCommandCount) + { + lowestCommandCount=aiInterface->getMyUnit(currentProducerIndex)->getCommandSize(); + bestIndex=currentProducerIndex; + besti=i%(producers.size()); + } + } + if( aiInterface->getMyUnit(bestIndex)->getCommandSize()>2) + { + // maybe we need another producer of this kind if possible! + if(aiInterface->reqsOk(aiInterface->getMyUnit(bestIndex)->getType())) + { + if(ai->getCountOfClass(ucBuilding)>5) + ai->addTask(new BuildTask(aiInterface->getMyUnit(bestIndex)->getType())); + } + // need to calculte another producer, maybe its better to produce another warrior with another producer + vector backupProducers; + // find another producer unit which is free and produce any kind of warrior. + //for each unit + for(int i=0; igetMyUnitCount(); ++i){ + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + //for each command + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + //if the command is produce + if(ct->getClass()==ccProduce) + { + const UnitType *unitType= static_cast(ct->getProduced()); + if(unitType->hasSkillClass(scAttack) && !unitType->hasCommandClass(ccHarvest) && aiInterface->reqsOk(ct)) + {//this can produce a warrior + backupProducers.push_back(i); + } + } + } + } + if(!backupProducers.empty()) + { + vector productionCommandIndexes; + int randomstart=ai->getRandom()->randRange(0, backupProducers.size()-1); + int lowestCommandCount=1000000; + int currentProducerIndex=backupProducers[randomstart]; + int bestIndex=-1; + int currentCommandCount=0; + for(unsigned int i=randomstart; igetMyUnit(currentProducerIndex)->getCommandSize(); + if( currentCommandCount==1 && + aiInterface->getMyUnit(currentProducerIndex)->getCurrCommand()->getCommandType()->getClass()==ccStop) + {// special for non buildings + currentCommandCount=0; + } + if(lowestCommandCount>currentCommandCount) + { + lowestCommandCount=currentCommandCount; + bestIndex=currentProducerIndex; + if(lowestCommandCount==0) break; + } + } + // a good producer is found, lets choose a warrior production + const UnitType *ut=aiInterface->getMyUnit(bestIndex)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is produce + if(ct->getClass()==ccProduce) + { + const UnitType *unitType= static_cast(ct->getProduced()); + if(unitType->hasSkillClass(scAttack) && !unitType->hasCommandClass(ccHarvest) && aiInterface->reqsOk(ct)) + {//this can produce a warrior + productionCommandIndexes.push_back(j); + } + } + } + int commandIndex=productionCommandIndexes[ai->getRandom()->randRange(0, productionCommandIndexes.size()-1)]; + aiInterface->giveCommand(bestIndex, ut->getCommandType(commandIndex)); + } + else + {// do it like normal CPU + aiInterface->giveCommand(bestIndex, defCt); + } + } + else + { + if(currentCommandCount==0) + { + aiInterface->giveCommand(bestIndex, defCt); + } + aiInterface->giveCommand(bestIndex, defCt); + } + } + else + { + int producerIndex= producers[ai->getRandom()->randRange(0, producers.size()-1)]; + aiInterface->giveCommand(producerIndex, defCt); + } + } + } +} + +// ======================================== +// class AiRuleBuild +// ======================================== + +AiRuleBuild::AiRuleBuild(Ai *ai): + AiRule(ai) +{ + buildTask= NULL; +} + +bool AiRuleBuild::test(){ + const Task *task= ai->getTask(); + + if(task==NULL || task->getClass()!=tcBuild){ + return false; + } + + buildTask= static_cast(task); + return true; +} + + +void AiRuleBuild::execute(){ + + if(buildTask!=NULL){ + + //generic build task, build random building that can be built + if(buildTask->getUnitType()==NULL){ + buildGeneric(buildTask); + } + //specific building task, build if possible, retry if not enough resources or not position + else{ + buildSpecific(buildTask); + } + + //remove the task + ai->removeTask(buildTask); + } +} + +void AiRuleBuild::buildGeneric(const BuildTask *bt){ + + //find buildings that can be built + AiInterface *aiInterface= ai->getAiInterface(); + typedef vector UnitTypes; + UnitTypes buildings; + + //for each unit + for(int i=0; igetMyUnitCount(); ++i){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is build + if(ct->getClass()==ccBuild){ + const BuildCommandType *bct= static_cast(ct); + + //for each building + for(int k=0; kgetBuildingCount(); ++k){ + const UnitType *building= bct->getBuilding(k); + if(aiInterface->reqsOk(bct) && aiInterface->reqsOk(building)){ + + //if any building, or produces resource + const ResourceType *rt= bt->getResourceType(); + const Resource *cost= building->getCost(rt); + if(rt==NULL || (cost!=NULL && cost->getAmount()<0)){ + buildings.push_back(building); + } + } + } + } + } + } + + //add specific build task + buildBestBuilding(buildings); +} + +void AiRuleBuild::buildBestBuilding(const vector &buildings){ + + if(!buildings.empty()){ + + //build the least built building + bool buildingFound= false; + for(int i=0; i<10 && !buildingFound; ++i){ + + if(i>0){ + + //Defensive buildings have priority + for(int j=0; jgetCountOfType(building)<=i+1 && isDefensive(building)) + { + ai->addTask(new BuildTask(building)); + buildingFound= true; + } + } + + //Warrior producers next + for(unsigned int j=0; jgetCountOfType(building)<=i+1 && isWarriorProducer(building)) + { + ai->addTask(new BuildTask(building)); + buildingFound= true; + } + } + + //Resource producers next + for(unsigned int j=0; jgetCountOfType(building)<=i+1 && isResourceProducer(building)) + { + ai->addTask(new BuildTask(building)); + buildingFound= true; + } + } + } + + //Any building + for(unsigned int j=0; jgetCountOfType(building)<=i) + { + ai->addTask(new BuildTask(building)); + buildingFound= true; + } + } + } + } +} + +void AiRuleBuild::buildSpecific(const BuildTask *bt){ + AiInterface *aiInterface= ai->getAiInterface(); + //if reqs ok + if(aiInterface->reqsOk(bt->getUnitType())){ + + //retry if not enough resources + if(!aiInterface->checkCosts(bt->getUnitType())){ + ai->retryTask(bt); + return; + } + + vector builders; + const BuildCommandType *defBct= NULL; + + //for each unit + for(int i=0; igetMyUnitCount(); ++i){ + + //if the unit is not going to build + const Unit *u= aiInterface->getMyUnit(i); + if(!u->anyCommand() || u->getCurrCommand()->getCommandType()->getClass()!=ccBuild){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is build + if(ct->getClass()==ccBuild){ + const BuildCommandType *bct= static_cast(ct); + + //for each building + for(int k=0; kgetBuildingCount(); ++k){ + const UnitType *building= bct->getBuilding(k); + + //if building match + if(bt->getUnitType()==building){ + if(aiInterface->reqsOk(bct)){ + builders.push_back(i); + defBct= bct; + } + } + } + } + } + } + } + + //use random builder to build + if(!builders.empty()){ + int builderIndex= builders[ai->getRandom()->randRange(0, builders.size()-1)]; + Vec2i pos; + Vec2i searchPos= bt->getForcePos()? bt->getPos(): ai->getRandomHomePosition(); + + //if free pos give command, else retry + if(ai->findPosForBuilding(bt->getUnitType(), searchPos, pos)){ + aiInterface->giveCommand(builderIndex, defBct, pos, bt->getUnitType()); + } + else{ + ai->retryTask(bt); + return; + } + } + } +} + +bool AiRuleBuild::isDefensive(const UnitType *building){ + return building->hasSkillClass(scAttack); +} + +bool AiRuleBuild::isResourceProducer(const UnitType *building){ + for(int i= 0; igetCostCount(); i++){ + if(building->getCost(i)->getAmount()<0){ + return true; + } + } + return false; +} + +bool AiRuleBuild::isWarriorProducer(const UnitType *building){ + for(int i= 0; i < building->getCommandTypeCount(); i++){ + const CommandType *ct= building->getCommandType(i); + if(ct->getClass() == ccProduce){ + const UnitType *ut= static_cast(ct)->getProducedUnit(); + + if(ut->isOfClass(ucWarrior)){ + return true; + } + } + } + return false; +} + +// ======================================== +// class AiRuleUpgrade +// ======================================== + +AiRuleUpgrade::AiRuleUpgrade(Ai *ai): + AiRule(ai) +{ + upgradeTask= NULL; +} + +bool AiRuleUpgrade::test(){ + const Task *task= ai->getTask(); + + if(task==NULL || task->getClass()!=tcUpgrade){ + return false; + } + + upgradeTask= static_cast(task); + return true; +} + +void AiRuleUpgrade::execute(){ + + //upgrade any upgrade + if(upgradeTask->getUpgradeType()==NULL){ + upgradeGeneric(upgradeTask); + } + //upgrade specific upgrade + else{ + upgradeSpecific(upgradeTask); + } + + //remove the task + ai->removeTask(upgradeTask); +} + +void AiRuleUpgrade::upgradeGeneric(const UpgradeTask *upgt){ + + typedef vector UpgradeTypes; + AiInterface *aiInterface= ai->getAiInterface(); + + //find upgrades that can be upgraded + UpgradeTypes upgrades; + + //for each upgrade, upgrade it if possible + for(int i=0; igetMyUnitCount(); ++i){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is upgrade + if(ct->getClass()==ccUpgrade){ + const UpgradeCommandType *upgct= static_cast(ct); + const UpgradeType *upgrade= upgct->getProducedUpgrade(); + if(aiInterface->reqsOk(upgct)){ + upgrades.push_back(upgrade); + } + } + } + } + + //add specific upgrade task + if(!upgrades.empty()){ + ai->addTask(new UpgradeTask(upgrades[ai->getRandom()->randRange(0, upgrades.size()-1)])); + } +} + +void AiRuleUpgrade::upgradeSpecific(const UpgradeTask *upgt){ + + AiInterface *aiInterface= ai->getAiInterface(); + + //if reqs ok + if(aiInterface->reqsOk(upgt->getUpgradeType())){ + + //if resources dont meet retry + if(!aiInterface->checkCosts(upgt->getUpgradeType())){ + ai->retryTask(upgt); + return; + } + + //for each unit + for(int i=0; igetMyUnitCount(); ++i){ + + //for each command + const UnitType *ut= aiInterface->getMyUnit(i)->getType(); + for(int j=0; jgetCommandTypeCount(); ++j){ + const CommandType *ct= ut->getCommandType(j); + + //if the command is upgrade + if(ct->getClass()==ccUpgrade){ + const UpgradeCommandType *uct= static_cast(ct); + const UpgradeType *producedUpgrade= uct->getProducedUpgrade(); + + //if upgrades match + if(producedUpgrade == upgt->getUpgradeType()){ + if(aiInterface->reqsOk(uct)){ + aiInterface->giveCommand(i, uct); + } + } + } + } + } + + } +} + +// ======================================== +// class AiRuleExpand +// ======================================== + +AiRuleExpand::AiRuleExpand(Ai *ai): + AiRule(ai) +{ + storeType= NULL; +} + +bool AiRuleExpand::test(){ + AiInterface *aiInterface = ai->getAiInterface(); + + for(int i= 0; igetTechTree()->getResourceTypeCount(); ++i){ + const ResourceType *rt = aiInterface->getTechTree()->getResourceType(i); + + if(rt->getClass()==rcTech){ + + // If any resource sighted + if(aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), expandPos)){ + + int minDistance= INT_MAX; + storeType= NULL; + + //If there is no close store + for(int j=0; jgetMyUnitCount(); ++j){ + const Unit *u= aiInterface->getMyUnit(j); + const UnitType *ut= aiInterface->getMyUnit(j)->getType(); + + // If this building is a store + if(ut->getStore(rt)>0){ + storeType = ut; + int distance= static_cast (u->getPos().dist(expandPos)); + + if(distance < minDistance){ + minDistance = distance; + } + } + } + + if(minDistance>expandDistance) + { + return true; + } + } + else{ + // send patrol to look for resource + ai->sendScoutPatrol(); + } + } + } + + return false; +} + +void AiRuleExpand::execute(){ + ai->addExpansion(expandPos); + ai->addPriorityTask(new BuildTask(storeType, expandPos)); +} + +}}//end namespace diff --git a/source/glest_game/facilities/game_util.cpp b/source/glest_game/facilities/game_util.cpp index 49fb5f981..ef000f9d8 100644 --- a/source/glest_game/facilities/game_util.cpp +++ b/source/glest_game/facilities/game_util.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published @@ -55,11 +55,11 @@ string getAboutString2(int i){ string getTeammateName(int i){ switch(i){ - case 0: return "Marti�o Figueroa"; - case 1: return "Jos� Luis Gonz�lez"; - case 2: return "Tucho Fern�ndez"; - case 3: return "Jos� Zanni"; - case 4: return "F�lix Men�ndez"; + case 0: return "Martiño Figueroa"; + case 1: return "José Luis González"; + case 2: return "Tucho Fernández"; + case 3: return "José Zanni"; + case 4: return "Félix Menéndez"; case 5: return "Marcos Caruncho"; case 6: return "Matthias Braun"; case 7: return "Titus Tscharntke"; diff --git a/source/glest_game/game/chat_manager.cpp b/source/glest_game/game/chat_manager.cpp index e99e9c8f5..a1bb8676e 100644 --- a/source/glest_game/game/chat_manager.cpp +++ b/source/glest_game/game/chat_manager.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index e6ef4294e..e15cc10f0 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published @@ -415,19 +415,18 @@ void Game::mouseDoubleClickLeft(int x, int y){ } void Game::mouseMove(int x, int y, const MouseState *ms){ - const Metrics &metrics = Metrics::getInstance(); mouseX = x; mouseY = y; if (ms->get(mbCenter)) { - /*if (input.isCtrlDown()) { - float speed = input.isShiftDown() ? 1.f : 0.125f; - float response = input.isShiftDown() ? 0.1875f : 0.0625f; - gameCamera.moveForwardH((y - lastMousePos.y) * speed, response); - gameCamera.moveSideH((x - lastMousePos.x) * speed, response); - } else*/ + //if (input.isCtrlDown()) { + // float speed = input.isShiftDown() ? 1.f : 0.125f; + // float response = input.isShiftDown() ? 0.1875f : 0.0625f; + // gameCamera.moveForwardH((y - lastMousePos.y) * speed, response); + // gameCamera.moveSideH((x - lastMousePos.x) * speed, response); + //} else { //float ymult = Config::getInstance().getCameraInvertYAxis() ? -0.2f : 0.2f; //float xmult = Config::getInstance().getCameraInvertXAxis() ? -0.2f : 0.2f; @@ -441,30 +440,36 @@ void Game::mouseMove(int x, int y, const MouseState *ms){ //main window if (y < 10) { gameCamera.setMoveZ(-scrollSpeed); - } else if (y > metrics.getVirtualH() - 10) { + } + else if (y > metrics.getVirtualH() - 10) { gameCamera.setMoveZ(scrollSpeed); - } else { + } + else { gameCamera.setMoveZ(0); } if (x < 10) { gameCamera.setMoveX(-scrollSpeed); - } else if (x > metrics.getVirtualW() - 10) { + } + else if (x > metrics.getVirtualW() - 10) { gameCamera.setMoveX(scrollSpeed); - } else { + } + else { gameCamera.setMoveX(0); } if (mainMessageBox.getEnabled()) { mainMessageBox.mouseMove(x, y); - } else if (ScriptManager::getMessageBox()->getEnabled()) { - ScriptManager::getMessageBox()->mouseMove(x, y); - //} else if (saveBox) { - // saveBox->mouseMove(x, y); - } else { - //graphics - gui.mouseMoveGraphics(x, y); } + if (scriptManager.getMessageBox()->getEnabled()) { + scriptManager.getMessageBox()->mouseMove(x, y); + } + //else if (saveBox) { + // saveBox->mouseMove(x, y); + //} else { + // //graphics + gui.mouseMoveGraphics(x, y); + //} } //display diff --git a/source/glest_game/game/script_manager.cpp b/source/glest_game/game/script_manager.cpp index 7e05eb208..4d5a2a991 100644 --- a/source/glest_game/game/script_manager.cpp +++ b/source/glest_game/game/script_manager.cpp @@ -34,9 +34,6 @@ PlayerModifiers::PlayerModifiers(){ // ===================================================== // class ScriptManager // ===================================================== - -GraphicMessageBox ScriptManager::messageBox; - ScriptManager* ScriptManager::thisScriptManager= NULL; const int ScriptManager::messageWrapCount= 30; const int ScriptManager::displayTextWrapCount= 64; diff --git a/source/glest_game/game/script_manager.h b/source/glest_game/game/script_manager.h index 61de09468..ae896404f 100644 --- a/source/glest_game/game/script_manager.h +++ b/source/glest_game/game/script_manager.h @@ -83,7 +83,7 @@ private: //misc MessageQueue messageQueue; - static GraphicMessageBox messageBox; + GraphicMessageBox messageBox; string displayText; //last created unit @@ -110,7 +110,7 @@ public: //message box functions bool getMessageBoxEnabled() const {return !messageQueue.empty();} - static GraphicMessageBox* getMessageBox() {return &messageBox;} + GraphicMessageBox* getMessageBox() {return &messageBox;} string getDisplayText() const {return displayText;} bool getGameOver() const {return gameOver;} const PlayerModifiers *getPlayerModifiers(int factionIndex) const {return &playerModifiers[factionIndex];} diff --git a/source/glest_game/graphics/renderer.cpp b/source/glest_game/graphics/renderer.cpp index e962737ea..1d25a0c8e 100644 --- a/source/glest_game/graphics/renderer.cpp +++ b/source/glest_game/graphics/renderer.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published diff --git a/source/glest_game/gui/selection.cpp b/source/glest_game/gui/selection.cpp index c282cb46e..0da69fe76 100644 --- a/source/glest_game/gui/selection.cpp +++ b/source/glest_game/gui/selection.cpp @@ -1,11 +1,11 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== @@ -26,7 +26,7 @@ namespace Glest{ namespace Game{ // ===================================================== void Selection::init(Gui *gui, int factionIndex){ - this->factionIndex= factionIndex; + this->factionIndex= factionIndex; this->gui= gui; } @@ -41,7 +41,7 @@ void Selection::select(Unit *unit){ return; } - //check if already selected + //check if already selected for(int i=0; ionSelectionChanged(); } -void Selection::clear(){ +void Selection::clear(){ //clear list selectedUnits.clear(); } @@ -127,17 +127,17 @@ bool Selection::isUniform() const{ bool Selection::isEnemy() const{ return selectedUnits.size()==1 && selectedUnits.front()->getFactionIndex()!=factionIndex; } - + bool Selection::isComandable() const{ - return - !isEmpty() && - !isEnemy() && + return + !isEmpty() && + !isEnemy() && !(selectedUnits.size()==1 && !selectedUnits.front()->isOperative()); } bool Selection::isCancelable() const{ - return - selectedUnits.size()>1 || + return + selectedUnits.size()>1 || (selectedUnits.size()==1 && selectedUnits[0]->anyCommand()); } @@ -204,4 +204,4 @@ void Selection::unitEvent(UnitObserver::Event event, const Unit *unit){ } } -}}//end namespace +}}//end namespace diff --git a/source/glest_game/main/battle_end.cpp b/source/glest_game/main/battle_end.cpp index 901ad8a41..b23596182 100644 --- a/source/glest_game/main/battle_end.cpp +++ b/source/glest_game/main/battle_end.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2008 Marti�o Figueroa +// Copyright (C) 2001-2008 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index 299662932..b8452f8d3 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -125,19 +125,6 @@ void MainWindow::eventMouseDown(int x, int y, MouseButton mouseButton){ default: break; } - - /* - switch(mouseButton){ - case mbLeft: - program->mouseDownLeft(x, getH() - y); - break; - case mbRight: - program->mouseDownRight(x, getH() - y); - break; - default: - break; - } - */ } void MainWindow::eventMouseUp(int x, int y, MouseButton mouseButton){ @@ -161,12 +148,6 @@ void MainWindow::eventMouseUp(int x, int y, MouseButton mouseButton){ default: break; } - - /* - if(mouseButton==mbLeft){ - program->mouseUpLeft(x, getH() - y); - } - */ } void MainWindow::eventMouseDoubleClick(int x, int y, MouseButton mouseButton){ @@ -190,12 +171,6 @@ void MainWindow::eventMouseDoubleClick(int x, int y, MouseButton mouseButton){ default: break; } - -/* - if(mouseButton == mbLeft){ - program->mouseDoubleClickLeft(x, getH() - y); - } -*/ } void MainWindow::eventMouseMove(int x, int y, const MouseState *ms){ @@ -206,8 +181,6 @@ void MainWindow::eventMouseMove(int x, int y, const MouseState *ms){ ProgramState *programState = program->getState(); programState->mouseMove(vx, vy, ms); - - //program->mouseMove(x, getH() - y, ms); } void MainWindow::eventMouseWheel(int x, int y, int zDelta) { @@ -222,10 +195,6 @@ void MainWindow::eventMouseWheel(int x, int y, int zDelta) { programState->eventMouseWheel(vx, vy, zDelta); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - //program->eventMouseWheel(x, y, zDelta); - //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void MainWindow::eventKeyDown(char key){ @@ -285,6 +254,7 @@ int glestMain(int argc, char** argv){ NetworkInterface::setDisplayMessageFunction(ExceptionHandler::DisplayMessage); showCursor(config.getBool("Windowed")); + //showCursor(false); program= new Program(); mainWindow= new MainWindow(program); diff --git a/source/glest_game/main/program.cpp b/source/glest_game/main/program.cpp index da946f9ad..0ce69d9f8 100644 --- a/source/glest_game/main/program.cpp +++ b/source/glest_game/main/program.cpp @@ -155,62 +155,6 @@ Program::~Program(){ singleton = NULL; } -void Program::eventMouseDown(int x, int y, MouseButton mouseButton) { - const Metrics &metrics = Metrics::getInstance(); - int vx = metrics.toVirtualX(x); - int vy = metrics.toVirtualY(window->getH() - y); - - switch(mouseButton) { - case mbLeft: - programState->mouseDownLeft(vx, vy); - break; - case mbRight: - programState->mouseDownRight(vx, vy); - break; - case mbCenter: - programState->mouseDownCenter(vx, vy); - break; - default: - break; - } -} - -void Program::mouseDownLeft(int x, int y){ - const Metrics &metrics= Metrics::getInstance(); - programState->mouseDownLeft(metrics.toVirtualX(x), metrics.toVirtualY(y)); -} - -void Program::mouseUpLeft(int x, int y){ - const Metrics &metrics= Metrics::getInstance(); - programState->mouseUpLeft(metrics.toVirtualX(x), metrics.toVirtualY(y)); -} - -void Program::mouseDownRight(int x, int y){ - const Metrics &metrics= Metrics::getInstance(); - programState->mouseDownRight(metrics.toVirtualX(x), metrics.toVirtualY(y)); -} - -void Program::mouseDoubleClickLeft(int x, int y){ - const Metrics &metrics= Metrics::getInstance(); - programState->mouseDoubleClickLeft(metrics.toVirtualX(x), metrics.toVirtualY(y)); -} - -void Program::eventMouseWheel(int x, int y, int zDelta) { - SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - const Metrics &metrics= Metrics::getInstance(); - int vx = metrics.toVirtualX(x); - int vy = metrics.toVirtualY(window->getH() - y); - - programState->eventMouseWheel(vx, vy, zDelta); -} - - -void Program::mouseMove(int x, int y, const MouseState *ms){ - const Metrics &metrics= Metrics::getInstance(); - programState->mouseMove(metrics.toVirtualX(x), metrics.toVirtualY(y), ms); -} - void Program::keyDown(char key){ //delegate event programState->keyDown(key); diff --git a/source/glest_game/main/program.h b/source/glest_game/main/program.h index ac6caa1f3..5b1e370fd 100644 --- a/source/glest_game/main/program.h +++ b/source/glest_game/main/program.h @@ -119,18 +119,10 @@ public: void initClient(WindowGl *window, const Ip &serverIp); //main - void mouseDownLeft(int x, int y); - void mouseUpLeft(int x, int y); - void mouseDownRight(int x, int y); - void mouseDoubleClickLeft(int x, int y); - void eventMouseWheel(int x, int y, int zDelta); - - void eventMouseDown(int x, int y, MouseButton mouseButton); - - void mouseMove(int x, int y, const MouseState *mouseState); void keyDown(char key); void keyUp(char key); - void keyPress(char c); + void keyPress(char c); + void loop(); void resize(SizeState sizeState); void showMessage(const char *msg); diff --git a/source/glest_game/menu/menu_state_scenario.cpp b/source/glest_game/menu/menu_state_scenario.cpp index f144dd202..b897ca77d 100644 --- a/source/glest_game/menu/menu_state_scenario.cpp +++ b/source/glest_game/menu/menu_state_scenario.cpp @@ -1,7 +1,7 @@ // ============================================================== // This file is part of Glest (www.glest.org) // -// Copyright (C) 2001-2005 Marti�o Figueroa +// Copyright (C) 2001-2005 Martiño Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published diff --git a/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp b/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp new file mode 100644 index 000000000..3c2674d7f --- /dev/null +++ b/source/shared_lib/sources/graphics/gl/particle_renderer_gl.cpp @@ -0,0 +1,294 @@ +// ============================================================== +// This file is part of Glest Shared Library (www.glest.org) +// +// Copyright (C) 2001-2008 Marti�o Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#include "particle_renderer_gl.h" + +#include "opengl.h" +#include "texture_gl.h" +#include "model_renderer.h" +#include "math_util.h" +#include "leak_dumper.h" + +namespace Shared{ namespace Graphics{ namespace Gl{ + +// ===================================================== +// class ParticleRendererGl +// ===================================================== + +// ===================== PUBLIC ======================== + +ParticleRendererGl::ParticleRendererGl(){ + assert(bufferSize%4 == 0); + + rendering= false; + + // init texture coordinates for quads + for(int i= 0; irender(this, mr); + rendering= false; + + //pop state + glPopClientAttrib(); + glPopAttrib(); + + //assertions + assertGl(); +} + +void ParticleRendererGl::renderSystem(ParticleSystem *ps){ + assertGl(); + assert(rendering); + + Vec3f rightVector; + Vec3f upVector; + float modelview[16]; + + //render particles + setBlendMode(ps->getBlendMode()); + + // get the current modelview state + glGetFloatv(GL_MODELVIEW_MATRIX , modelview); + rightVector= Vec3f(modelview[0], modelview[4], modelview[8]); + upVector= Vec3f(modelview[1], modelview[5], modelview[9]); + + // set state + if(ps->getTexture()!=NULL){ + glBindTexture(GL_TEXTURE_2D, static_cast(ps->getTexture())->getHandle()); + } + else{ + glBindTexture(GL_TEXTURE_2D, 0); + } + glDisable(GL_ALPHA_TEST); + glDisable(GL_FOG); + glAlphaFunc(GL_GREATER, 0.0f); + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + //fill vertex buffer with billboards + int bufferIndex= 0; + + for(int i=0; igetAliveParticleCount(); ++i){ + const Particle *particle= ps->getParticle(i); + float size= particle->getSize()/2.0f; + Vec3f pos= particle->getPos(); + Vec4f color= particle->getColor(); + + vertexBuffer[bufferIndex] = pos - (rightVector - upVector) * size; + vertexBuffer[bufferIndex+1] = pos - (rightVector + upVector) * size; + vertexBuffer[bufferIndex+2] = pos + (rightVector - upVector) * size; + vertexBuffer[bufferIndex+3] = pos + (rightVector + upVector) * size; + + colorBuffer[bufferIndex]= color; + colorBuffer[bufferIndex+1]= color; + colorBuffer[bufferIndex+2]= color; + colorBuffer[bufferIndex+3]= color; + + bufferIndex+= 4; + + if(bufferIndex >= bufferSize){ + bufferIndex= 0; + renderBufferQuads(bufferSize); + } + } + renderBufferQuads(bufferIndex); + + assertGl(); +} + +void ParticleRendererGl::renderSystemLine(ParticleSystem *ps){ + + assertGl(); + assert(rendering); + + if(!ps->isEmpty()){ + const Particle *particle= ps->getParticle(0); + + setBlendMode(ps->getBlendMode()); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_ALPHA_TEST); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + //fill vertex buffer with lines + int bufferIndex= 0; + + glLineWidth(particle->getSize()); + + for(int i=0; igetAliveParticleCount(); ++i){ + particle= ps->getParticle(i); + Vec4f color= particle->getColor(); + + vertexBuffer[bufferIndex] = particle->getPos(); + vertexBuffer[bufferIndex+1] = particle->getLastPos(); + + colorBuffer[bufferIndex]= color; + colorBuffer[bufferIndex+1]= color; + + bufferIndex+= 2; + + if(bufferIndex >= bufferSize){ + bufferIndex= 0; + renderBufferLines(bufferSize); + } + } + renderBufferLines(bufferIndex); + } + + assertGl(); +} + +void ParticleRendererGl::renderSystemLineAlpha(ParticleSystem *ps){ + + assertGl(); + assert(rendering); + + if(!ps->isEmpty()){ + const Particle *particle= ps->getParticle(0); + + setBlendMode(ps->getBlendMode()); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_ALPHA_TEST); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + //fill vertex buffer with lines + int bufferIndex= 0; + + glLineWidth(particle->getSize()); + + for(int i=0; igetAliveParticleCount(); ++i){ + particle= ps->getParticle(i); + Vec4f color= particle->getColor(); + + vertexBuffer[bufferIndex] = particle->getPos(); + vertexBuffer[bufferIndex+1] = particle->getLastPos(); + + colorBuffer[bufferIndex]= color; + colorBuffer[bufferIndex+1]= color; + colorBuffer[bufferIndex+1].w= 0.0f; + + bufferIndex+= 2; + + if(bufferIndex >= bufferSize){ + bufferIndex= 0; + renderBufferLines(bufferSize); + } + } + renderBufferLines(bufferIndex); + } + + assertGl(); +} + +void ParticleRendererGl::renderSingleModel(AttackParticleSystem *ps, ModelRenderer *mr){ + //render model + if(ps->getModel()!=NULL){ + + //init + glEnable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + glColor3f(1.f, 1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + //translate + Vec3f pos= ps->getPos(); + glTranslatef(pos.x, pos.y, pos.z); + + //rotate + Vec3f direction= ps->getDirection(); + Vec3f flatDirection= Vec3f(direction.x, 0.f, direction.z); + Vec3f rotVector= Vec3f(0.f, 1.f, 0.f).cross(flatDirection); + + float angleV= radToDeg(atan2(flatDirection.length(), direction.y)) - 90.f; + glRotatef(angleV, rotVector.x, rotVector.y, rotVector.z); + float angleH= radToDeg(atan2(direction.x, direction.z)); + glRotatef(angleH, 0.f, 1.f, 0.f); + + //render + mr->begin(true, true, false); + mr->render(ps->getModel()); + mr->end(); + + //end + glPopMatrix(); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + } +} + + +// ============== PRIVATE ===================================== + +void ParticleRendererGl::renderBufferQuads(int quadCount){ + glVertexPointer(3, GL_FLOAT, 0, vertexBuffer); + glTexCoordPointer(2, GL_FLOAT, 0, texCoordBuffer); + glColorPointer(4, GL_FLOAT, 0, colorBuffer); + + glDrawArrays(GL_QUADS, 0, quadCount); +} + +void ParticleRendererGl::renderBufferLines(int lineCount){ + glVertexPointer(3, GL_FLOAT, 0, vertexBuffer); + glColorPointer(4, GL_FLOAT, 0, colorBuffer); + + glDrawArrays(GL_LINES, 0, lineCount); +} + +void ParticleRendererGl::setBlendMode(ParticleSystem::BlendMode blendMode){ + switch(blendMode){ + case ParticleSystem::bmOne: + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + case ParticleSystem::bmOneMinusAlpha: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + default: + assert(false); + } +} + +}}} //end namespace