Disabled in progress code related to unit rotation feature (will re-enabled after current release)
This commit is contained in:
parent
c166338e95
commit
e9847750c1
|
@ -0,0 +1,921 @@
|
||||||
|
// ==============================================================
|
||||||
|
// ==============================================================
|
||||||
|
// 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 "gui.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "world.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "upgrade.h"
|
||||||
|
#include "unit.h"
|
||||||
|
#include "metrics.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "platform_util.h"
|
||||||
|
#include "sound_renderer.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "faction.h"
|
||||||
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
|
using namespace Shared::Graphics;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
namespace Glest{ namespace Game{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Mouse3d
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
const float Mouse3d::fadeSpeed= 1.f/50.f;
|
||||||
|
|
||||||
|
Mouse3d::Mouse3d(){
|
||||||
|
enabled= false;
|
||||||
|
rot= 0;
|
||||||
|
fade= 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse3d::enable(){
|
||||||
|
enabled= true;
|
||||||
|
fade= 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse3d::update(){
|
||||||
|
if(enabled){
|
||||||
|
rot= (rot + 3) % 360;
|
||||||
|
fade+= fadeSpeed;
|
||||||
|
if(fade>1.f) fade= 1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// class SelectionQuad
|
||||||
|
// ===============================
|
||||||
|
|
||||||
|
SelectionQuad::SelectionQuad(){
|
||||||
|
enabled= false;
|
||||||
|
posDown= Vec2i(0);
|
||||||
|
posUp= Vec2i(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionQuad::setPosDown(const Vec2i &posDown){
|
||||||
|
enabled= true;
|
||||||
|
this->posDown= posDown;
|
||||||
|
this->posUp= posDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionQuad::setPosUp(const Vec2i &posUp){
|
||||||
|
this->posUp= posUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionQuad::disable(){
|
||||||
|
enabled= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class Gui
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
Gui::Gui(){
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
posObjWorld= Vec2i(54, 14);
|
||||||
|
computeSelection= false;
|
||||||
|
validPosObjWorld= false;
|
||||||
|
activeCommandType= NULL;
|
||||||
|
activeCommandClass= ccStop;
|
||||||
|
selectingBuilding= false;
|
||||||
|
selectingPos= false;
|
||||||
|
selectingMeetingPoint= false;
|
||||||
|
activePos= invalidPos;
|
||||||
|
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::init(Game *game){
|
||||||
|
this->commander= game->getCommander();
|
||||||
|
this->gameCamera= game->getGameCamera();
|
||||||
|
this->console= game->getConsole();
|
||||||
|
this->world= game->getWorld();
|
||||||
|
selection.init(this, world->getThisFactionIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::end(){
|
||||||
|
selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== get ====================
|
||||||
|
|
||||||
|
const UnitType *Gui::getBuilding() const{
|
||||||
|
assert(selectingBuilding);
|
||||||
|
return choosenBuildingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== is ====================
|
||||||
|
|
||||||
|
bool Gui::isPlacingBuilding() const{
|
||||||
|
return isSelectingPos() && activeCommandType!=NULL && activeCommandType->getClass()==ccBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== set ====================
|
||||||
|
|
||||||
|
void Gui::invalidatePosObjWorld(){
|
||||||
|
validPosObjWorld= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::setComputeSelectionFlag(){
|
||||||
|
computeSelection= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== reset state ====================
|
||||||
|
|
||||||
|
void Gui::resetState(){
|
||||||
|
selectingBuilding= false;
|
||||||
|
selectingPos= false;
|
||||||
|
selectingMeetingPoint= false;
|
||||||
|
activePos= invalidPos;
|
||||||
|
activeCommandClass= ccStop;
|
||||||
|
activeCommandType= NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== events ====================
|
||||||
|
|
||||||
|
void Gui::update(){
|
||||||
|
setComputeSelectionFlag();
|
||||||
|
mouse3d.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::tick(){
|
||||||
|
computeDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
//in display coords
|
||||||
|
bool Gui::mouseValid(int x, int y){
|
||||||
|
return computePosDisplay(x, y) != invalidPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDownLeftDisplay(int x, int y){
|
||||||
|
if(!selectingPos && !selectingMeetingPoint){
|
||||||
|
int posDisplay= computePosDisplay(x, y);
|
||||||
|
if(posDisplay!= invalidPos){
|
||||||
|
if(selection.isComandable()){
|
||||||
|
if(selectingBuilding){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selectingBuilding == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
mouseDownDisplayUnitBuild(posDisplay);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selectingBuilding == false\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
mouseDownDisplayUnitSkills(posDisplay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
computeDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseMoveDisplay(int x, int y){
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
computeInfoString(computePosDisplay(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDownLeftGraphics(int x, int y){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(selectingPos){
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selectingPos == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
//give standard orders
|
||||||
|
giveTwoClickOrders(x, y);
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
//set meeting point
|
||||||
|
else if(selectingMeetingPoint){
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selectingMeetingPoint == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(selection.isComandable()){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selection.isComandable() == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
Vec2i targetPos;
|
||||||
|
if(Renderer::getInstance().computePosition(Vec2i(x, y), targetPos)){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] computePosition() == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
commander->trySetMeetingPoint(selection.getFrontUnit(), targetPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] selectionQuad()\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
selectionQuad.setPosDown(Vec2i(x, y));
|
||||||
|
computeSelected(false);
|
||||||
|
}
|
||||||
|
computeDisplay();
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDownRightGraphics(int x, int y){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(selectingPos || selectingMeetingPoint){
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
else if(selection.isComandable()){
|
||||||
|
giveDefaultOrders(x, y);
|
||||||
|
}
|
||||||
|
computeDisplay();
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseUpLeftGraphics(int x, int y){
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] START\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
if(!selectingPos && !selectingMeetingPoint){
|
||||||
|
if(selectionQuad.isEnabled()){
|
||||||
|
selectionQuad.setPosUp(Vec2i(x, y));
|
||||||
|
if(selection.isComandable() && random.randRange(0, 1)==0){
|
||||||
|
SoundRenderer::getInstance().playFx(
|
||||||
|
selection.getFrontUnit()->getType()->getSelectionSound(),
|
||||||
|
selection.getFrontUnit()->getCurrVector(),
|
||||||
|
gameCamera->getPos());
|
||||||
|
}
|
||||||
|
selectionQuad.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseMoveGraphics(int x, int y){
|
||||||
|
|
||||||
|
//compute selection
|
||||||
|
if(selectionQuad.isEnabled()){
|
||||||
|
selectionQuad.setPosUp(Vec2i(x, y));
|
||||||
|
if(computeSelection){
|
||||||
|
computeSelection= false;
|
||||||
|
computeSelected(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute position for building
|
||||||
|
if(isPlacingBuilding()){
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] isPlacingBuilding() == true\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
validPosObjWorld= Renderer::getInstance().computePosition(Vec2i(x,y), posObjWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
display.setInfoText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDoubleClickLeftGraphics(int x, int y){
|
||||||
|
if(!selectingPos && !selectingMeetingPoint){
|
||||||
|
selectionQuad.setPosDown(Vec2i(x, y));
|
||||||
|
computeSelected(true);
|
||||||
|
computeDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::groupKey(int groupIndex){
|
||||||
|
if(isKeyDown(vkControl)){
|
||||||
|
selection.assignGroup(groupIndex);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
selection.recallGroup(groupIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float Gui::getUnitTypeBuildRotation(int unitId) const {
|
||||||
|
float rotationValue = -1;
|
||||||
|
|
||||||
|
if(unitTypeBuildRotation.find(unitId) != unitTypeBuildRotation.end()) {
|
||||||
|
rotationValue = unitTypeBuildRotation.find(unitId)->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rotationValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::hotKey(char key){
|
||||||
|
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] key = [%c]\n",__FILE__,__FUNCTION__,key);
|
||||||
|
|
||||||
|
if(key==' '){
|
||||||
|
centerCameraOnSelection();
|
||||||
|
}
|
||||||
|
else if(key=='I'){
|
||||||
|
selectInterestingUnit(iutIdleHarvester);
|
||||||
|
}
|
||||||
|
else if(key=='B'){
|
||||||
|
selectInterestingUnit(iutBuiltBuilding);
|
||||||
|
}
|
||||||
|
else if(key=='R'){
|
||||||
|
//!!!
|
||||||
|
if(0 && isPlacingBuilding()) {
|
||||||
|
const UnitType *unitType = getBuilding();
|
||||||
|
float unitTypeRotation = getUnitTypeBuildRotation(unitType->getId());
|
||||||
|
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] unitType->getId() = %d unitTypeRotation = %f\n",__FILE__,__FUNCTION__,unitType->getId(),unitTypeRotation);
|
||||||
|
|
||||||
|
if(unitTypeRotation < 0) {
|
||||||
|
unitTypeRotation = 0;
|
||||||
|
}
|
||||||
|
unitTypeRotation += 90;
|
||||||
|
if(unitTypeRotation >= 360) {
|
||||||
|
unitTypeRotation = 0;
|
||||||
|
}
|
||||||
|
unitTypeBuildRotation[unitType->getId()] = unitTypeRotation;
|
||||||
|
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] unitType->getId() = %d NEW unitTypeRotation = %f\n",__FILE__,__FUNCTION__,unitType->getId(),unitTypeRotation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectInterestingUnit(iutProducer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(key=='D'){
|
||||||
|
selectInterestingUnit(iutDamaged);
|
||||||
|
}
|
||||||
|
else if(key=='T'){
|
||||||
|
selectInterestingUnit(iutStore);
|
||||||
|
}
|
||||||
|
else if(key=='A'){
|
||||||
|
clickCommonCommand(ccAttack);
|
||||||
|
}
|
||||||
|
else if(key=='S'){
|
||||||
|
clickCommonCommand(ccStop);
|
||||||
|
}
|
||||||
|
else if(key=='M'){
|
||||||
|
clickCommonCommand(ccMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::onSelectionChanged(){
|
||||||
|
resetState();
|
||||||
|
computeDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= PRIVATE =================
|
||||||
|
|
||||||
|
void Gui::giveOneClickOrders(){
|
||||||
|
CommandResult result;
|
||||||
|
if(selection.isUniform()){
|
||||||
|
result= commander->tryGiveCommand(&selection, activeCommandType);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result= commander->tryGiveCommand(&selection, activeCommandClass);
|
||||||
|
}
|
||||||
|
addOrdersResultToConsole(activeCommandClass, result);
|
||||||
|
activeCommandType= NULL;
|
||||||
|
activeCommandClass= ccStop;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::giveDefaultOrders(int x, int y){
|
||||||
|
|
||||||
|
//compute target
|
||||||
|
const Unit *targetUnit= NULL;
|
||||||
|
Vec2i targetPos;
|
||||||
|
if(!computeTarget(Vec2i(x, y), targetPos, targetUnit)){
|
||||||
|
console->addStdMessage("InvalidPosition");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//give order
|
||||||
|
CommandResult result= commander->tryGiveCommand(&selection, targetPos, targetUnit);
|
||||||
|
|
||||||
|
//graphical result
|
||||||
|
addOrdersResultToConsole(activeCommandClass, result);
|
||||||
|
if(result == crSuccess || result == crSomeFailed){
|
||||||
|
mouse3d.enable();
|
||||||
|
|
||||||
|
if(random.randRange(0, 1)==0){
|
||||||
|
SoundRenderer::getInstance().playFx(
|
||||||
|
selection.getFrontUnit()->getType()->getCommandSound(),
|
||||||
|
selection.getFrontUnit()->getCurrVector(),
|
||||||
|
gameCamera->getPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::giveTwoClickOrders(int x, int y){
|
||||||
|
|
||||||
|
CommandResult result;
|
||||||
|
|
||||||
|
//compute target
|
||||||
|
const Unit *targetUnit= NULL;
|
||||||
|
Vec2i targetPos;
|
||||||
|
if(!computeTarget(Vec2i(x, y), targetPos, targetUnit)){
|
||||||
|
console->addStdMessage("InvalidPosition");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//give orders to the units of this faction
|
||||||
|
if(!selectingBuilding){
|
||||||
|
if(selection.isUniform()){
|
||||||
|
result= commander->tryGiveCommand(&selection, activeCommandType, targetPos, targetUnit);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result= commander->tryGiveCommand(&selection, activeCommandClass, targetPos, targetUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//selecting building
|
||||||
|
result= commander->tryGiveCommand( selection.getFrontUnit(), activeCommandType, posObjWorld, choosenBuildingType );
|
||||||
|
}
|
||||||
|
|
||||||
|
//graphical result
|
||||||
|
addOrdersResultToConsole(activeCommandClass, result);
|
||||||
|
if(result == crSuccess || result == crSomeFailed){
|
||||||
|
mouse3d.enable();
|
||||||
|
|
||||||
|
if(random.randRange(0, 1)==0){
|
||||||
|
SoundRenderer::getInstance().playFx(
|
||||||
|
selection.getFrontUnit()->getType()->getCommandSound(),
|
||||||
|
selection.getFrontUnit()->getCurrVector(),
|
||||||
|
gameCamera->getPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::centerCameraOnSelection(){
|
||||||
|
if(!selection.isEmpty()){
|
||||||
|
Vec3f refPos= selection.getRefPos();
|
||||||
|
gameCamera->centerXZ(refPos.x, refPos.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::selectInterestingUnit(InterestingUnitType iut){
|
||||||
|
const Faction* thisFaction= world->getThisFaction();
|
||||||
|
const Unit* previousUnit= NULL;
|
||||||
|
bool previousFound= true;
|
||||||
|
|
||||||
|
//start at the next harvester
|
||||||
|
if(selection.getCount()==1){
|
||||||
|
const Unit* refUnit= selection.getFrontUnit();
|
||||||
|
|
||||||
|
if(refUnit->isInteresting(iut)){
|
||||||
|
previousUnit= refUnit;
|
||||||
|
previousFound= false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear selection
|
||||||
|
selection.clear();
|
||||||
|
|
||||||
|
//search
|
||||||
|
for(int i= 0; i<thisFaction->getUnitCount(); ++i){
|
||||||
|
Unit* unit= thisFaction->getUnit(i);
|
||||||
|
|
||||||
|
if(previousFound){
|
||||||
|
if(unit->isInteresting(iut)){
|
||||||
|
selection.select(unit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(unit==previousUnit){
|
||||||
|
previousFound= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//search again if we have a previous
|
||||||
|
if(selection.isEmpty() && previousUnit!=NULL && previousFound==true){
|
||||||
|
for(int i= 0; i<thisFaction->getUnitCount(); ++i){
|
||||||
|
Unit* unit= thisFaction->getUnit(i);
|
||||||
|
|
||||||
|
if(unit->isInteresting(iut)){
|
||||||
|
selection.select(unit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::clickCommonCommand(CommandClass commandClass){
|
||||||
|
for(int i= 0; i<Display::downCellCount; ++i){
|
||||||
|
const CommandType* ct= display.getCommandType(i);
|
||||||
|
if((ct!=NULL && ct->getClass()==commandClass) || display.getCommandClass(i)==commandClass){
|
||||||
|
mouseDownDisplayUnitSkills(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDownDisplayUnitSkills(int posDisplay){
|
||||||
|
if(!selection.isEmpty()){
|
||||||
|
if(posDisplay != cancelPos){
|
||||||
|
if(posDisplay!=meetingPointPos){
|
||||||
|
const Unit *unit= selection.getFrontUnit();
|
||||||
|
|
||||||
|
//uniform selection
|
||||||
|
if(selection.isUniform()){
|
||||||
|
if(unit->getFaction()->reqsOk(display.getCommandType(posDisplay))){
|
||||||
|
activeCommandType= display.getCommandType(posDisplay);
|
||||||
|
activeCommandClass= activeCommandType->getClass();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
activeCommandType= NULL;
|
||||||
|
activeCommandClass= ccStop;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//non uniform selection
|
||||||
|
else{
|
||||||
|
activeCommandType= NULL;
|
||||||
|
activeCommandClass= display.getCommandClass(posDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
//give orders depending on command type
|
||||||
|
if(!selection.isEmpty()){
|
||||||
|
const CommandType *ct= selection.getUnit(0)->getType()->getFirstCtOfClass(activeCommandClass);
|
||||||
|
if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
|
||||||
|
assert(selection.isUniform());
|
||||||
|
selectingBuilding= true;
|
||||||
|
}
|
||||||
|
else if(ct->getClicks()==cOne){
|
||||||
|
invalidatePosObjWorld();
|
||||||
|
giveOneClickOrders();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
selectingPos= true;
|
||||||
|
activePos= posDisplay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
activePos= posDisplay;
|
||||||
|
selectingMeetingPoint= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
commander->tryCancelCommand(&selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::mouseDownDisplayUnitBuild(int posDisplay){
|
||||||
|
int factionIndex= world->getThisFactionIndex();
|
||||||
|
|
||||||
|
if(posDisplay==cancelPos){
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
|
||||||
|
const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
|
||||||
|
const UnitType *ut= bct->getBuilding(posDisplay);
|
||||||
|
if(world->getFaction(factionIndex)->reqsOk(ut)){
|
||||||
|
choosenBuildingType= ut;
|
||||||
|
assert(choosenBuildingType!=NULL);
|
||||||
|
selectingPos= true;;
|
||||||
|
activePos= posDisplay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::computeInfoString(int posDisplay){
|
||||||
|
|
||||||
|
Lang &lang= Lang::getInstance();
|
||||||
|
|
||||||
|
display.setInfoText("");
|
||||||
|
if(posDisplay!=invalidPos && selection.isComandable()){
|
||||||
|
if(!selectingBuilding){
|
||||||
|
if(posDisplay==cancelPos){
|
||||||
|
display.setInfoText(lang.get("Cancel"));
|
||||||
|
}
|
||||||
|
else if(posDisplay==meetingPointPos){
|
||||||
|
display.setInfoText(lang.get("MeetingPoint"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//uniform selection
|
||||||
|
if(selection.isUniform()){
|
||||||
|
const Unit *unit= selection.getFrontUnit();
|
||||||
|
const CommandType *ct= display.getCommandType(posDisplay);
|
||||||
|
if(ct!=NULL){
|
||||||
|
if(unit->getFaction()->reqsOk(ct)){
|
||||||
|
display.setInfoText(ct->getDesc(unit->getTotalUpgrade()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(ct->getClass()==ccUpgrade){
|
||||||
|
const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
|
||||||
|
if(unit->getFaction()->getUpgradeManager()->isUpgrading(uct->getProducedUpgrade())){
|
||||||
|
display.setInfoText(lang.get("Upgrading"));
|
||||||
|
}
|
||||||
|
else if(unit->getFaction()->getUpgradeManager()->isUpgraded(uct->getProducedUpgrade())){
|
||||||
|
display.setInfoText(lang.get("AlreadyUpgraded"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
display.setInfoText(ct->getReqDesc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
display.setInfoText(ct->getReqDesc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//non uniform selection
|
||||||
|
else{
|
||||||
|
const UnitType *ut= selection.getFrontUnit()->getType();
|
||||||
|
CommandClass cc= display.getCommandClass(posDisplay);
|
||||||
|
if(cc!=ccNull){
|
||||||
|
display.setInfoText(lang.get("CommonCommand") + ": " + ut->getFirstCtOfClass(cc)->toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(posDisplay==cancelPos){
|
||||||
|
display.setInfoText(lang.get("Return"));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
|
||||||
|
const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
|
||||||
|
display.setInfoText(bct->getBuilding(posDisplay)->getReqDesc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::computeDisplay(){
|
||||||
|
|
||||||
|
//init
|
||||||
|
display.clear();
|
||||||
|
|
||||||
|
// ================ PART 1 ================
|
||||||
|
|
||||||
|
//title, text and progress bar
|
||||||
|
if(selection.getCount()==1){
|
||||||
|
display.setTitle(selection.getFrontUnit()->getFullName());
|
||||||
|
display.setText(selection.getFrontUnit()->getDesc());
|
||||||
|
display.setProgressBar(selection.getFrontUnit()->getProductionPercent());
|
||||||
|
}
|
||||||
|
|
||||||
|
//portraits
|
||||||
|
for(int i=0; i<selection.getCount(); ++i){
|
||||||
|
display.setUpImage(i, selection.getUnit(i)->getType()->getImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================ PART 2 ================
|
||||||
|
|
||||||
|
if(selectingPos || selectingMeetingPoint){
|
||||||
|
display.setDownSelectedPos(activePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selection.isComandable()){
|
||||||
|
if(!selectingBuilding){
|
||||||
|
|
||||||
|
//cancel button
|
||||||
|
const Unit *u= selection.getFrontUnit();
|
||||||
|
const UnitType *ut= u->getType();
|
||||||
|
if(selection.isCancelable()){
|
||||||
|
display.setDownImage(cancelPos, ut->getCancelImage());
|
||||||
|
display.setDownLighted(cancelPos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//meeting point
|
||||||
|
if(selection.isMeetable()){
|
||||||
|
display.setDownImage(meetingPointPos, ut->getMeetingPointImage());
|
||||||
|
display.setDownLighted(meetingPointPos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selection.isUniform()){
|
||||||
|
//uniform selection
|
||||||
|
if(u->isBuilt()){
|
||||||
|
int morphPos= 8;
|
||||||
|
for(int i=0; i<ut->getCommandTypeCount(); ++i){
|
||||||
|
int displayPos= i;
|
||||||
|
const CommandType *ct= ut->getCommandType(i);
|
||||||
|
if(ct->getClass()==ccMorph){
|
||||||
|
displayPos= morphPos++;
|
||||||
|
}
|
||||||
|
display.setDownImage(displayPos, ct->getImage());
|
||||||
|
display.setCommandType(displayPos, ct);
|
||||||
|
display.setDownLighted(displayPos, u->getFaction()->reqsOk(ct));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else{
|
||||||
|
//non uniform selection
|
||||||
|
int lastCommand= 0;
|
||||||
|
for(int i=0; i<ccCount; ++i){
|
||||||
|
CommandClass cc= static_cast<CommandClass>(i);
|
||||||
|
if(isSharedCommandClass(cc) && cc!=ccBuild){
|
||||||
|
display.setDownLighted(lastCommand, true);
|
||||||
|
display.setDownImage(lastCommand, ut->getFirstCtOfClass(cc)->getImage());
|
||||||
|
display.setCommandClass(lastCommand, cc);
|
||||||
|
lastCommand++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
|
||||||
|
//selecting building
|
||||||
|
const Unit *unit= selection.getFrontUnit();
|
||||||
|
if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
|
||||||
|
const BuildCommandType* bct= static_cast<const BuildCommandType*>(activeCommandType);
|
||||||
|
for(int i=0; i<bct->getBuildingCount(); ++i){
|
||||||
|
display.setDownImage(i, bct->getBuilding(i)->getImage());
|
||||||
|
display.setDownLighted(i, unit->getFaction()->reqsOk(bct->getBuilding(i)));
|
||||||
|
}
|
||||||
|
display.setDownImage(cancelPos, selection.getFrontUnit()->getType()->getCancelImage());
|
||||||
|
display.setDownLighted(cancelPos, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Gui::computePosDisplay(int x, int y){
|
||||||
|
int posDisplay= display.computeDownIndex(x, y);
|
||||||
|
|
||||||
|
if(posDisplay<0 || posDisplay>=Display::downCellCount){
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
else if(selection.isComandable()){
|
||||||
|
if(posDisplay!=cancelPos){
|
||||||
|
if(posDisplay!=meetingPointPos){
|
||||||
|
if(!selectingBuilding){
|
||||||
|
//standard selection
|
||||||
|
if(display.getCommandClass(posDisplay)==ccNull && display.getCommandType(posDisplay)==NULL){
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//building selection
|
||||||
|
if(activeCommandType!=NULL && activeCommandType->getClass()==ccBuild){
|
||||||
|
const BuildCommandType *bct= static_cast<const BuildCommandType*>(activeCommandType);
|
||||||
|
if(posDisplay>=bct->getBuildingCount()){
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//check meeting point
|
||||||
|
if(!selection.isMeetable()){
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//check cancel button
|
||||||
|
if(!selection.isCancelable()){
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
posDisplay= invalidPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return posDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::addOrdersResultToConsole(CommandClass cc, CommandResult result){
|
||||||
|
|
||||||
|
switch(result){
|
||||||
|
case crSuccess:
|
||||||
|
break;
|
||||||
|
case crFailReqs:
|
||||||
|
switch(cc){
|
||||||
|
case ccBuild:
|
||||||
|
console->addStdMessage("BuildingNoReqs");
|
||||||
|
break;
|
||||||
|
case ccProduce:
|
||||||
|
console->addStdMessage("UnitNoReqs");
|
||||||
|
break;
|
||||||
|
case ccUpgrade:
|
||||||
|
console->addStdMessage("UpgradeNoReqs");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case crFailRes:
|
||||||
|
switch(cc){
|
||||||
|
case ccBuild:
|
||||||
|
console->addStdMessage("BuildingNoRes");
|
||||||
|
break;
|
||||||
|
case ccProduce:
|
||||||
|
console->addStdMessage("UnitNoRes");
|
||||||
|
break;
|
||||||
|
case ccUpgrade:
|
||||||
|
console->addStdMessage("UpgradeNoRes");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case crFailUndefined:
|
||||||
|
console->addStdMessage("InvalidOrder");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case crSomeFailed:
|
||||||
|
console->addStdMessage("SomeOrdersFailed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gui::isSharedCommandClass(CommandClass commandClass){
|
||||||
|
for(int i=0; i<selection.getCount(); ++i){
|
||||||
|
const Unit *unit= selection.getUnit(i);
|
||||||
|
const CommandType *ct= unit->getType()->getFirstCtOfClass(commandClass);
|
||||||
|
if(ct==NULL || !unit->getFaction()->reqsOk(ct))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui::computeSelected(bool doubleClick){
|
||||||
|
Selection::UnitContainer units;
|
||||||
|
Renderer::getInstance().computeSelected(units, selectionQuad.getPosDown(), selectionQuad.getPosUp());
|
||||||
|
selectingBuilding= false;
|
||||||
|
activeCommandType= NULL;
|
||||||
|
|
||||||
|
//select all units of the same type if double click
|
||||||
|
if(doubleClick && units.size()==1){
|
||||||
|
const Unit *refUnit= units.front();
|
||||||
|
int factionIndex= refUnit->getFactionIndex();
|
||||||
|
for(int i=0; i<world->getFaction(factionIndex)->getUnitCount(); ++i){
|
||||||
|
Unit *unit= world->getFaction(factionIndex)->getUnit(i);
|
||||||
|
if(unit->getPos().dist(refUnit->getPos())<doubleClickSelectionRadius &&
|
||||||
|
unit->getType()==refUnit->getType())
|
||||||
|
{
|
||||||
|
units.push_back(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shiftDown= isKeyDown(vkShift);
|
||||||
|
bool controlDown= isKeyDown(vkControl);
|
||||||
|
|
||||||
|
if(!shiftDown && !controlDown){
|
||||||
|
selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!controlDown){
|
||||||
|
selection.select(units);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
selection.unSelect(units);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gui::computeTarget(const Vec2i &screenPos, Vec2i &targetPos, const Unit *&targetUnit){
|
||||||
|
Selection::UnitContainer uc;
|
||||||
|
Renderer &renderer= Renderer::getInstance();
|
||||||
|
renderer.computeSelected(uc, screenPos, screenPos);
|
||||||
|
validPosObjWorld= false;
|
||||||
|
|
||||||
|
if(!uc.empty()){
|
||||||
|
targetUnit= uc.front();
|
||||||
|
targetPos= targetUnit->getPos();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
targetUnit= NULL;
|
||||||
|
if(renderer.computePosition(screenPos, targetPos)){
|
||||||
|
validPosObjWorld= true;
|
||||||
|
posObjWorld= targetPos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}//end namespace
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,546 @@
|
||||||
|
// ==============================================================
|
||||||
|
// This file is part of Glest (www.glest.org)
|
||||||
|
//
|
||||||
|
// Copyright (C) 2001-2008 Marti<74>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 "unit_type.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "upgrade_type.h"
|
||||||
|
#include "resource_type.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "xml_parser.h"
|
||||||
|
#include "tech_tree.h"
|
||||||
|
#include "resource.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "game_util.h"
|
||||||
|
#include "leak_dumper.h"
|
||||||
|
#include "unit_particle_type.h"
|
||||||
|
//#include "socket.h"
|
||||||
|
|
||||||
|
using namespace Shared::Xml;
|
||||||
|
using namespace Shared::Graphics;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
namespace Glest{ namespace Game{
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// class Level
|
||||||
|
// ===============================
|
||||||
|
|
||||||
|
void Level::init(string name, int kills){
|
||||||
|
this->name= name;
|
||||||
|
this->kills= kills;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class UnitType
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
// ===================== PUBLIC ========================
|
||||||
|
|
||||||
|
const char *UnitType::propertyNames[]= {"burnable", "rotated_climb"};
|
||||||
|
|
||||||
|
// ==================== creation and loading ====================
|
||||||
|
|
||||||
|
UnitType::UnitType(){
|
||||||
|
|
||||||
|
lightColor= Vec3f(0.f);
|
||||||
|
light= false;
|
||||||
|
multiSelect= false;
|
||||||
|
armorType= NULL;
|
||||||
|
|
||||||
|
for(int i=0; i<pCount; ++i){
|
||||||
|
properties[i]= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0; i<fieldCount; ++i){
|
||||||
|
fields[i]= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cellMap= NULL;
|
||||||
|
hpRegeneration= 0;
|
||||||
|
epRegeneration= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitType::~UnitType(){
|
||||||
|
deleteValues(commandTypes.begin(), commandTypes.end());
|
||||||
|
deleteValues(skillTypes.begin(), skillTypes.end());
|
||||||
|
deleteValues(selectionSounds.getSounds().begin(), selectionSounds.getSounds().end());
|
||||||
|
deleteValues(commandSounds.getSounds().begin(), commandSounds.getSounds().end());
|
||||||
|
delete [] cellMap;
|
||||||
|
//remove damageParticleSystemTypes
|
||||||
|
while(!damageParticleSystemTypes.empty()){
|
||||||
|
delete damageParticleSystemTypes.back();
|
||||||
|
damageParticleSystemTypes.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitType::preLoad(const string &dir){
|
||||||
|
name= lastDir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitType::load(int id,const string &dir, const TechTree *techTree, const FactionType *factionType, Checksum* checksum){
|
||||||
|
|
||||||
|
this->id= id;
|
||||||
|
string path;
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
Logger::getInstance().add("Unit type: " + formatString(name), true);
|
||||||
|
|
||||||
|
//file load
|
||||||
|
path= dir+"/"+name+".xml";
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
DWORD fileAttributes = GetFileAttributes(path.c_str());
|
||||||
|
if( (fileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
checksum->addFile(path);
|
||||||
|
|
||||||
|
XmlTree xmlTree;
|
||||||
|
xmlTree.load(path);
|
||||||
|
const XmlNode *unitNode= xmlTree.getRootNode();
|
||||||
|
|
||||||
|
const XmlNode *parametersNode= unitNode->getChild("parameters");
|
||||||
|
|
||||||
|
//size
|
||||||
|
size= parametersNode->getChild("size")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//height
|
||||||
|
height= parametersNode->getChild("height")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//maxHp
|
||||||
|
maxHp= parametersNode->getChild("max-hp")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//hpRegeneration
|
||||||
|
hpRegeneration= parametersNode->getChild("max-hp")->getAttribute("regeneration")->getIntValue();
|
||||||
|
|
||||||
|
//maxEp
|
||||||
|
maxEp= parametersNode->getChild("max-ep")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
if(maxEp!=0){
|
||||||
|
//wpRegeneration
|
||||||
|
epRegeneration= parametersNode->getChild("max-ep")->getAttribute("regeneration")->getIntValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
//armor
|
||||||
|
armor= parametersNode->getChild("armor")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//armor type string
|
||||||
|
string armorTypeName= parametersNode->getChild("armor-type")->getAttribute("value")->getRestrictedValue();
|
||||||
|
armorType= techTree->getArmorType(armorTypeName);
|
||||||
|
|
||||||
|
//sight
|
||||||
|
sight= parametersNode->getChild("sight")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//prod time
|
||||||
|
productionTime= parametersNode->getChild("time")->getAttribute("value")->getIntValue();
|
||||||
|
|
||||||
|
//multi selection
|
||||||
|
multiSelect= parametersNode->getChild("multi-selection")->getAttribute("value")->getBoolValue();
|
||||||
|
|
||||||
|
//cellmap
|
||||||
|
const XmlNode *cellMapNode= parametersNode->getChild("cellmap");
|
||||||
|
bool hasCellMap= cellMapNode->getAttribute("value")->getBoolValue();
|
||||||
|
if(hasCellMap){
|
||||||
|
cellMap= new bool[size*size];
|
||||||
|
for(int i=0; i<size; ++i){
|
||||||
|
const XmlNode *rowNode= cellMapNode->getChild("row", i);
|
||||||
|
string row= rowNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
if(row.size()!=size){
|
||||||
|
throw runtime_error("Cellmap row has not the same length as unit size");
|
||||||
|
}
|
||||||
|
for(int j=0; j<row.size(); ++j){
|
||||||
|
cellMap[i*size+j]= row[j]=='0'? false: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] Original Unit cellmap matrix below [%s] [%s]:\n",__FILE__,__FUNCTION__,getName().c_str(),path.c_str());
|
||||||
|
for(int iRow = 0; iRow < size; ++iRow) {
|
||||||
|
const XmlNode *rowNode= cellMapNode->getChild("row", iRow);
|
||||||
|
string row= rowNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] row = %s\n",__FILE__,__FUNCTION__,row.c_str());
|
||||||
|
|
||||||
|
for(int iCol = 0; iCol < size; ++iCol) {
|
||||||
|
bool getCellResult = getCellMapCell(iCol, iRow);
|
||||||
|
if(Socket::enableDebugText) printf("In [%s::%s] matrix [%d,%d] = %d\n",__FILE__,__FUNCTION__,iRow,iCol,getCellResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//levels
|
||||||
|
const XmlNode *levelsNode= parametersNode->getChild("levels");
|
||||||
|
levels.resize(levelsNode->getChildCount());
|
||||||
|
for(int i=0; i<levels.size(); ++i){
|
||||||
|
const XmlNode *levelNode= levelsNode->getChild("level", i);
|
||||||
|
levels[i].init(
|
||||||
|
levelNode->getAttribute("name")->getRestrictedValue(),
|
||||||
|
levelNode->getAttribute("kills")->getIntValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
//fields
|
||||||
|
const XmlNode *fieldsNode= parametersNode->getChild("fields");
|
||||||
|
for(int i=0; i<fieldsNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *fieldNode= fieldsNode->getChild("field", i);
|
||||||
|
string fieldName= fieldNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
if(fieldName=="land"){
|
||||||
|
fields[fLand]= true;
|
||||||
|
}
|
||||||
|
else if(fieldName=="air"){
|
||||||
|
fields[fAir]= true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw runtime_error("Not a valid field: "+fieldName+": "+ path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//properties
|
||||||
|
const XmlNode *propertiesNode= parametersNode->getChild("properties");
|
||||||
|
for(int i=0; i<propertiesNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *propertyNode= propertiesNode->getChild("property", i);
|
||||||
|
string propertyName= propertyNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
bool found= false;
|
||||||
|
for(int i=0; i<pCount; ++i){
|
||||||
|
if(propertyName==propertyNames[i]){
|
||||||
|
properties[i]= true;
|
||||||
|
found= true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found){
|
||||||
|
throw runtime_error("Unknown property: " + propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//damage-particles
|
||||||
|
if(parametersNode->hasChild("damage-particles")){
|
||||||
|
const XmlNode *particleNode= parametersNode->getChild("damage-particles");
|
||||||
|
bool particleEnabled= particleNode->getAttribute("value")->getBoolValue();
|
||||||
|
if(particleEnabled){
|
||||||
|
for(int i=0; i<particleNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *particleFileNode= particleNode->getChild("particle-file", i);
|
||||||
|
string path= particleFileNode->getAttribute("path")->getRestrictedValue();
|
||||||
|
UnitParticleSystemType *unitParticleSystemType= new UnitParticleSystemType();
|
||||||
|
unitParticleSystemType->load(dir, dir + "/" + path);
|
||||||
|
damageParticleSystemTypes.push_back(unitParticleSystemType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//light
|
||||||
|
const XmlNode *lightNode= parametersNode->getChild("light");
|
||||||
|
light= lightNode->getAttribute("enabled")->getBoolValue();
|
||||||
|
if(light){
|
||||||
|
lightColor.x= lightNode->getAttribute("red")->getFloatValue(0.f, 1.f);
|
||||||
|
lightColor.y= lightNode->getAttribute("green")->getFloatValue(0.f, 1.f);
|
||||||
|
lightColor.z= lightNode->getAttribute("blue")->getFloatValue(0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//unit requirements
|
||||||
|
const XmlNode *unitRequirementsNode= parametersNode->getChild("unit-requirements");
|
||||||
|
for(int i=0; i<unitRequirementsNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *unitNode= unitRequirementsNode->getChild("unit", i);
|
||||||
|
string name= unitNode->getAttribute("name")->getRestrictedValue();
|
||||||
|
unitReqs.push_back(factionType->getUnitType(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
//upgrade requirements
|
||||||
|
const XmlNode *upgradeRequirementsNode= parametersNode->getChild("upgrade-requirements");
|
||||||
|
for(int i=0; i<upgradeRequirementsNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *upgradeReqNode= upgradeRequirementsNode->getChild("upgrade", i);
|
||||||
|
string name= upgradeReqNode->getAttribute("name")->getRestrictedValue();
|
||||||
|
upgradeReqs.push_back(factionType->getUpgradeType(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
//resource requirements
|
||||||
|
const XmlNode *resourceRequirementsNode= parametersNode->getChild("resource-requirements");
|
||||||
|
costs.resize(resourceRequirementsNode->getChildCount());
|
||||||
|
for(int i=0; i<costs.size(); ++i){
|
||||||
|
const XmlNode *resourceNode= resourceRequirementsNode->getChild("resource", i);
|
||||||
|
string name= resourceNode->getAttribute("name")->getRestrictedValue();
|
||||||
|
int amount= resourceNode->getAttribute("amount")->getIntValue();
|
||||||
|
costs[i].init(techTree->getResourceType(name), amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//resources stored
|
||||||
|
const XmlNode *resourcesStoredNode= parametersNode->getChild("resources-stored");
|
||||||
|
storedResources.resize(resourcesStoredNode->getChildCount());
|
||||||
|
for(int i=0; i<storedResources.size(); ++i){
|
||||||
|
const XmlNode *resourceNode= resourcesStoredNode->getChild("resource", i);
|
||||||
|
string name= resourceNode->getAttribute("name")->getRestrictedValue();
|
||||||
|
int amount= resourceNode->getAttribute("amount")->getIntValue();
|
||||||
|
storedResources[i].init(techTree->getResourceType(name), amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//image
|
||||||
|
const XmlNode *imageNode= parametersNode->getChild("image");
|
||||||
|
image= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
|
image->load(dir+"/"+imageNode->getAttribute("path")->getRestrictedValue());
|
||||||
|
|
||||||
|
//image cancel
|
||||||
|
const XmlNode *imageCancelNode= parametersNode->getChild("image-cancel");
|
||||||
|
cancelImage= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
|
cancelImage->load(dir+"/"+imageCancelNode->getAttribute("path")->getRestrictedValue());
|
||||||
|
|
||||||
|
//meeting point
|
||||||
|
const XmlNode *meetingPointNode= parametersNode->getChild("meeting-point");
|
||||||
|
meetingPoint= meetingPointNode->getAttribute("value")->getBoolValue();
|
||||||
|
if(meetingPoint){
|
||||||
|
meetingPointImage= Renderer::getInstance().newTexture2D(rsGame);
|
||||||
|
meetingPointImage->load(dir+"/"+meetingPointNode->getAttribute("image-path")->getRestrictedValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
//selection sounds
|
||||||
|
const XmlNode *selectionSoundNode= parametersNode->getChild("selection-sounds");
|
||||||
|
if(selectionSoundNode->getAttribute("enabled")->getBoolValue()){
|
||||||
|
selectionSounds.resize(selectionSoundNode->getChildCount());
|
||||||
|
for(int i=0; i<selectionSounds.getSounds().size(); ++i){
|
||||||
|
const XmlNode *soundNode= selectionSoundNode->getChild("sound", i);
|
||||||
|
string path= soundNode->getAttribute("path")->getRestrictedValue();
|
||||||
|
StaticSound *sound= new StaticSound();
|
||||||
|
sound->load(dir + "/" + path);
|
||||||
|
selectionSounds[i]= sound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//command sounds
|
||||||
|
const XmlNode *commandSoundNode= parametersNode->getChild("command-sounds");
|
||||||
|
if(commandSoundNode->getAttribute("enabled")->getBoolValue()){
|
||||||
|
commandSounds.resize(commandSoundNode->getChildCount());
|
||||||
|
for(int i=0; i<commandSoundNode->getChildCount(); ++i){
|
||||||
|
const XmlNode *soundNode= commandSoundNode->getChild("sound", i);
|
||||||
|
string path= soundNode->getAttribute("path")->getRestrictedValue();
|
||||||
|
StaticSound *sound= new StaticSound();
|
||||||
|
sound->load(dir + "/" + path);
|
||||||
|
commandSounds[i]= sound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//skills
|
||||||
|
const XmlNode *skillsNode= unitNode->getChild("skills");
|
||||||
|
skillTypes.resize(skillsNode->getChildCount());
|
||||||
|
for(int i=0; i<skillTypes.size(); ++i){
|
||||||
|
const XmlNode *sn= skillsNode->getChild("skill", i);
|
||||||
|
const XmlNode *typeNode= sn->getChild("type");
|
||||||
|
string classId= typeNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
SkillType *skillType= SkillTypeFactory::getInstance().newInstance(classId);
|
||||||
|
skillType->load(sn, dir, techTree, factionType);
|
||||||
|
skillTypes[i]= skillType;
|
||||||
|
}
|
||||||
|
|
||||||
|
//commands
|
||||||
|
const XmlNode *commandsNode= unitNode->getChild("commands");
|
||||||
|
commandTypes.resize(commandsNode->getChildCount());
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
const XmlNode *commandNode= commandsNode->getChild("command", i);
|
||||||
|
const XmlNode *typeNode= commandNode->getChild("type");
|
||||||
|
string classId= typeNode->getAttribute("value")->getRestrictedValue();
|
||||||
|
CommandType *commandType= CommandTypeFactory::getInstance().newInstance(classId);
|
||||||
|
commandType->load(i, commandNode, dir, techTree, factionType, *this);
|
||||||
|
commandTypes[i]= commandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
computeFirstStOfClass();
|
||||||
|
computeFirstCtOfClass();
|
||||||
|
|
||||||
|
if(getFirstStOfClass(scStop)==NULL){
|
||||||
|
throw runtime_error("Every unit must have at least one stop skill: "+ path);
|
||||||
|
}
|
||||||
|
if(getFirstStOfClass(scDie)==NULL){
|
||||||
|
throw runtime_error("Every unit must have at least one die skill: "+ path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//Exception handling (conversions and so on);
|
||||||
|
catch(const exception &e){
|
||||||
|
throw runtime_error("Error loading UnitType: " + path + "\n" + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== get ====================
|
||||||
|
|
||||||
|
const CommandType *UnitType::getFirstCtOfClass(CommandClass commandClass) const{
|
||||||
|
return firstCommandTypeOfClass[commandClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkillType *UnitType::getFirstStOfClass(SkillClass skillClass) const{
|
||||||
|
return firstSkillTypeOfClass[skillClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
const HarvestCommandType *UnitType::getFirstHarvestCommand(const ResourceType *resourceType) const{
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
if(commandTypes[i]->getClass()== ccHarvest){
|
||||||
|
const HarvestCommandType *hct= static_cast<const HarvestCommandType*>(commandTypes[i]);
|
||||||
|
if(hct->canHarvest(resourceType)){
|
||||||
|
return hct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AttackCommandType *UnitType::getFirstAttackCommand(Field field) const{
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
if(commandTypes[i]->getClass()== ccAttack){
|
||||||
|
const AttackCommandType *act= static_cast<const AttackCommandType*>(commandTypes[i]);
|
||||||
|
if(act->getAttackSkillType()->getAttackField(field)){
|
||||||
|
return act;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RepairCommandType *UnitType::getFirstRepairCommand(const UnitType *repaired) const{
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
if(commandTypes[i]->getClass()== ccRepair){
|
||||||
|
const RepairCommandType *rct= static_cast<const RepairCommandType*>(commandTypes[i]);
|
||||||
|
if(rct->isRepairableUnitType(repaired)){
|
||||||
|
return rct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnitType::getStore(const ResourceType *rt) const{
|
||||||
|
for(int i=0; i<storedResources.size(); ++i){
|
||||||
|
if(storedResources[i].getType()==rt){
|
||||||
|
return storedResources[i].getAmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkillType *UnitType::getSkillType(const string &skillName, SkillClass skillClass) const{
|
||||||
|
for(int i=0; i<skillTypes.size(); ++i){
|
||||||
|
if(skillTypes[i]->getName()==skillName){
|
||||||
|
if(skillTypes[i]->getClass()==skillClass){
|
||||||
|
return skillTypes[i];
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw runtime_error("Skill \""+skillName+"\" is not of class \""+SkillType::skillClassToStr(skillClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw runtime_error("No skill named \""+skillName+"\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== totals ====================
|
||||||
|
|
||||||
|
int UnitType::getTotalMaxHp(const TotalUpgrade *totalUpgrade) const{
|
||||||
|
return maxHp + totalUpgrade->getMaxHp();
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnitType::getTotalMaxEp(const TotalUpgrade *totalUpgrade) const{
|
||||||
|
return maxEp + totalUpgrade->getMaxEp();
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnitType::getTotalArmor(const TotalUpgrade *totalUpgrade) const{
|
||||||
|
return armor + totalUpgrade->getArmor();
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnitType::getTotalSight(const TotalUpgrade *totalUpgrade) const{
|
||||||
|
return sight + totalUpgrade->getSight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== has ====================
|
||||||
|
|
||||||
|
bool UnitType::hasSkillClass(SkillClass skillClass) const{
|
||||||
|
return firstSkillTypeOfClass[skillClass]!=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnitType::hasCommandType(const CommandType *commandType) const{
|
||||||
|
assert(commandType!=NULL);
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
if(commandTypes[i]==commandType){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnitType::hasCommandClass(CommandClass commandClass) const{
|
||||||
|
return firstCommandTypeOfClass[commandClass]!=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnitType::hasSkillType(const SkillType *skillType) const{
|
||||||
|
assert(skillType!=NULL);
|
||||||
|
for(int i=0; i<skillTypes.size(); ++i){
|
||||||
|
if(skillTypes[i]==skillType){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnitType::isOfClass(UnitClass uc) const{
|
||||||
|
switch(uc){
|
||||||
|
case ucWarrior:
|
||||||
|
return hasSkillClass(scAttack) && !hasSkillClass(scHarvest);
|
||||||
|
case ucWorker:
|
||||||
|
return hasSkillClass(scBuild) || hasSkillClass(scRepair);
|
||||||
|
case ucBuilding:
|
||||||
|
return hasSkillClass(scBeBuilt);
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PRIVATE ====================
|
||||||
|
|
||||||
|
void UnitType::computeFirstStOfClass(){
|
||||||
|
for(int j= 0; j<scCount; ++j){
|
||||||
|
firstSkillTypeOfClass[j]= NULL;
|
||||||
|
for(int i= 0; i<skillTypes.size(); ++i){
|
||||||
|
if(skillTypes[i]->getClass()== SkillClass(j)){
|
||||||
|
firstSkillTypeOfClass[j]= skillTypes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnitType::computeFirstCtOfClass(){
|
||||||
|
for(int j=0; j<ccCount; ++j){
|
||||||
|
firstCommandTypeOfClass[j]= NULL;
|
||||||
|
for(int i=0; i<commandTypes.size(); ++i){
|
||||||
|
if(commandTypes[i]->getClass()== CommandClass(j)){
|
||||||
|
firstCommandTypeOfClass[j]= commandTypes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommandType* UnitType::findCommandTypeById(int id) const{
|
||||||
|
for(int i=0; i<getCommandTypeCount(); ++i){
|
||||||
|
const CommandType* commandType= getCommandType(i);
|
||||||
|
if(commandType->getId()==id){
|
||||||
|
return commandType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}//end namespace
|
|
@ -0,0 +1,736 @@
|
||||||
|
// ==============================================================
|
||||||
|
// 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 "world.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "faction.h"
|
||||||
|
#include "unit.h"
|
||||||
|
#include "game.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "sound_renderer.h"
|
||||||
|
#include "game_settings.h"
|
||||||
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
|
using namespace Shared::Graphics;
|
||||||
|
using namespace Shared::Util;
|
||||||
|
|
||||||
|
namespace Glest{ namespace Game{
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class World
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
const float World::airHeight= 5.f;
|
||||||
|
|
||||||
|
// ===================== PUBLIC ========================
|
||||||
|
|
||||||
|
World::World(){
|
||||||
|
Config &config= Config::getInstance();
|
||||||
|
|
||||||
|
fogOfWar= config.getBool("FogOfWar");
|
||||||
|
fogOfWarSmoothing= config.getBool("FogOfWarSmoothing");
|
||||||
|
fogOfWarSmoothingFrameSkip= config.getInt("FogOfWarSmoothingFrameSkip");
|
||||||
|
|
||||||
|
frameCount= 0;
|
||||||
|
nextUnitId= 0;
|
||||||
|
|
||||||
|
scriptManager= NULL;
|
||||||
|
this->game = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::end(){
|
||||||
|
Logger::getInstance().add("World", true);
|
||||||
|
|
||||||
|
for(int i= 0; i<factions.size(); ++i){
|
||||||
|
factions[i].end();
|
||||||
|
}
|
||||||
|
//stats will be deleted by BattleEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================== init ===============================================
|
||||||
|
|
||||||
|
void World::init(Game *game, bool createUnits){
|
||||||
|
|
||||||
|
this->game = game;
|
||||||
|
scriptManager= game->getScriptManager();
|
||||||
|
|
||||||
|
unitUpdater.init(game);
|
||||||
|
|
||||||
|
initFactionTypes(game->getGameSettings());
|
||||||
|
initCells(); //must be done after knowing faction number and dimensions
|
||||||
|
initMap();
|
||||||
|
initSplattedTextures();
|
||||||
|
|
||||||
|
//minimap must be init after sum computation
|
||||||
|
initMinimap();
|
||||||
|
if(createUnits){
|
||||||
|
initUnits();
|
||||||
|
}
|
||||||
|
initExplorationState();
|
||||||
|
computeFow();
|
||||||
|
}
|
||||||
|
|
||||||
|
//load tileset
|
||||||
|
void World::loadTileset(const string &dir, Checksum *checksum){
|
||||||
|
tileset.load(dir, checksum);
|
||||||
|
timeFlow.init(&tileset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//load tech
|
||||||
|
void World::loadTech(const string &dir, set<string> &factions, Checksum *checksum){
|
||||||
|
techTree.load(dir, factions, checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
//load map
|
||||||
|
void World::loadMap(const string &path, Checksum *checksum){
|
||||||
|
checksum->addFile(path);
|
||||||
|
map.load(path, &techTree, &tileset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//load map
|
||||||
|
void World::loadScenario(const string &path, Checksum *checksum){
|
||||||
|
checksum->addFile(path);
|
||||||
|
scenario.load(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== misc ====================
|
||||||
|
|
||||||
|
void World::update(){
|
||||||
|
|
||||||
|
++frameCount;
|
||||||
|
|
||||||
|
//time
|
||||||
|
timeFlow.update();
|
||||||
|
|
||||||
|
//water effects
|
||||||
|
waterEffects.update();
|
||||||
|
|
||||||
|
//units
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
|
||||||
|
unitUpdater.updateUnit(getFaction(i)->getUnit(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//undertake the dead
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
|
||||||
|
Unit *unit= getFaction(i)->getUnit(j);
|
||||||
|
if(unit->getToBeUndertaken()){
|
||||||
|
unit->undertake();
|
||||||
|
delete unit;
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//food costs
|
||||||
|
for(int i=0; i<techTree.getResourceTypeCount(); ++i){
|
||||||
|
const ResourceType *rt= techTree.getResourceType(i);
|
||||||
|
if(rt->getClass()==rcConsumable && frameCount % (rt->getInterval()*GameConstants::updateFps)==0){
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
getFaction(i)->applyCostsOnInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fow smoothing
|
||||||
|
if(fogOfWarSmoothing && ((frameCount+1) % (fogOfWarSmoothingFrameSkip+1))==0){
|
||||||
|
float fogFactor= static_cast<float>(frameCount%GameConstants::updateFps)/GameConstants::updateFps;
|
||||||
|
minimap.updateFowTex(clamp(fogFactor, 0.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
//tick
|
||||||
|
if(frameCount%GameConstants::updateFps==0){
|
||||||
|
computeFow();
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::tick(){
|
||||||
|
if(!fogOfWarSmoothing){
|
||||||
|
minimap.updateFowTex(1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//increase hp
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
|
||||||
|
getFaction(i)->getUnit(j)->tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute resources balance
|
||||||
|
for(int k=0; k<getFactionCount(); ++k){
|
||||||
|
Faction *faction= getFaction(k);
|
||||||
|
|
||||||
|
//for each resource
|
||||||
|
for(int i=0; i<techTree.getResourceTypeCount(); ++i){
|
||||||
|
const ResourceType *rt= techTree.getResourceType(i);
|
||||||
|
|
||||||
|
//if consumable
|
||||||
|
if(rt->getClass()==rcConsumable){
|
||||||
|
int balance= 0;
|
||||||
|
for(int j=0; j<faction->getUnitCount(); ++j){
|
||||||
|
|
||||||
|
//if unit operative and has this cost
|
||||||
|
const Unit *u= faction->getUnit(j);
|
||||||
|
if(u->isOperative()){
|
||||||
|
const Resource *r= u->getType()->getCost(rt);
|
||||||
|
if(r!=NULL){
|
||||||
|
balance-= u->getType()->getCost(rt)->getAmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
faction->setResourceBalance(rt, balance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit* World::findUnitById(int id){
|
||||||
|
for(int i= 0; i<getFactionCount(); ++i){
|
||||||
|
Faction* faction= getFaction(i);
|
||||||
|
|
||||||
|
for(int j= 0; j<faction->getUnitCount(); ++j){
|
||||||
|
Unit* unit= faction->getUnit(j);
|
||||||
|
|
||||||
|
if(unit->getId()==id){
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnitType* World::findUnitTypeById(const FactionType* factionType, int id){
|
||||||
|
for(int i= 0; i<factionType->getUnitTypeCount(); ++i){
|
||||||
|
const UnitType* unitType= factionType->getUnitType(i);
|
||||||
|
|
||||||
|
if(unitType->getId()==id){
|
||||||
|
return unitType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//looks for a place for a unit around a start lociacion, returns true if succeded
|
||||||
|
bool World::placeUnit(const Vec2i &startLoc, int radius, Unit *unit, bool spaciated){
|
||||||
|
bool freeSpace;
|
||||||
|
int size= unit->getType()->getSize();
|
||||||
|
Field currField= unit->getCurrField();
|
||||||
|
|
||||||
|
for(int r=1; r<radius; r++){
|
||||||
|
for(int i=-r; i<r; ++i){
|
||||||
|
for(int j=-r; j<r; ++j){
|
||||||
|
Vec2i pos= Vec2i(i,j)+startLoc;
|
||||||
|
if(spaciated){
|
||||||
|
const int spacing= 2;
|
||||||
|
freeSpace= map.isFreeCells(pos-Vec2i(spacing), size+spacing*2, currField);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
freeSpace= map.isFreeCells(pos, size, currField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(freeSpace){
|
||||||
|
unit->setPos(pos);
|
||||||
|
unit->setMeetingPos(pos-Vec2i(1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clears a unit old position from map and places new position
|
||||||
|
void World::moveUnitCells(Unit *unit){
|
||||||
|
Vec2i newPos= unit->getTargetPos();
|
||||||
|
|
||||||
|
//newPos must be free or the same pos as current
|
||||||
|
assert(map.getCell(unit->getPos())->getUnit(unit->getCurrField())==unit || map.isFreeCell(newPos, unit->getCurrField()));
|
||||||
|
map.clearUnitCells(unit, unit->getPos());
|
||||||
|
map.putUnitCells(unit, newPos);
|
||||||
|
|
||||||
|
//water splash
|
||||||
|
if(tileset.getWaterEffects() && unit->getCurrField()==fLand){
|
||||||
|
if(map.getSubmerged(map.getCell(unit->getLastPos()))){
|
||||||
|
for(int i=0; i<3; ++i){
|
||||||
|
waterEffects.addWaterSplash(
|
||||||
|
Vec2f(unit->getLastPos().x+random.randRange(-0.4f, 0.4f), unit->getLastPos().y+random.randRange(-0.4f, 0.4f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns the nearest unit that can store a type of resource given a position and a faction
|
||||||
|
Unit *World::nearestStore(const Vec2i &pos, int factionIndex, const ResourceType *rt){
|
||||||
|
float currDist= infinity;
|
||||||
|
Unit *currUnit= NULL;
|
||||||
|
|
||||||
|
for(int i=0; i<getFaction(factionIndex)->getUnitCount(); ++i){
|
||||||
|
Unit *u= getFaction(factionIndex)->getUnit(i);
|
||||||
|
float tmpDist= u->getPos().dist(pos);
|
||||||
|
if(tmpDist<currDist && u->getType()->getStore(rt)>0 && u->isOperative()){
|
||||||
|
currDist= tmpDist;
|
||||||
|
currUnit= u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::toRenderUnit(const Unit *unit, const Quad2i &visibleQuad) const{
|
||||||
|
//a unit is rendered if it is in a visible cell or is attacking a unit in a visible cell
|
||||||
|
return
|
||||||
|
visibleQuad.isInside(unit->getPos()) &&
|
||||||
|
toRenderUnit(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::toRenderUnit(const Unit *unit) const{
|
||||||
|
|
||||||
|
return
|
||||||
|
map.getSurfaceCell(Map::toSurfCoords(unit->getCenteredPos()))->isVisible(thisTeamIndex) ||
|
||||||
|
(unit->getCurrSkill()->getClass()==scAttack &&
|
||||||
|
map.getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->isVisible(thisTeamIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::createUnit(const string &unitName, int factionIndex, const Vec2i &pos){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
const FactionType* ft= faction->getType();
|
||||||
|
const UnitType* ut= ft->getUnitType(unitName);
|
||||||
|
|
||||||
|
//!!!
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] A\n",__FILE__,__FUNCTION__);
|
||||||
|
float unitRotation = game->getGui()->getUnitTypeBuildRotation(ut->getId());
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] B\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
Unit* unit= new Unit(getNextUnitId(), pos, ut, faction, &map, unitRotation);
|
||||||
|
|
||||||
|
if(placeUnit(pos, generationArea, unit, true)){
|
||||||
|
unit->create(true);
|
||||||
|
unit->born();
|
||||||
|
scriptManager->onUnitCreated(unit);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw runtime_error("Unit cant be placed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in createUnitAtPosition: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::giveResource(const string &resourceName, int factionIndex, int amount){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
const ResourceType* rt= techTree.getResourceType(resourceName);
|
||||||
|
faction->incResourceAmount(rt, amount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::givePositionCommand(int unitId, const string &commandName, const Vec2i &pos){
|
||||||
|
Unit* unit= findUnitById(unitId);
|
||||||
|
if(unit!=NULL){
|
||||||
|
CommandClass cc;
|
||||||
|
|
||||||
|
if(commandName=="move"){
|
||||||
|
cc= ccMove;
|
||||||
|
}
|
||||||
|
else if(commandName=="attack"){
|
||||||
|
cc= ccAttack;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw runtime_error("Invalid position commmand: " + commandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
unit->giveCommand(new Command( unit->getType()->getFirstCtOfClass(cc), pos ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::giveProductionCommand(int unitId, const string &producedName){
|
||||||
|
Unit *unit= findUnitById(unitId);
|
||||||
|
if(unit!=NULL){
|
||||||
|
const UnitType *ut= unit->getType();
|
||||||
|
|
||||||
|
//Search for a command that can produce the unit
|
||||||
|
for(int i= 0; i<ut->getCommandTypeCount(); ++i){
|
||||||
|
const CommandType* ct= ut->getCommandType(i);
|
||||||
|
if(ct->getClass()==ccProduce){
|
||||||
|
const ProduceCommandType *pct= static_cast<const ProduceCommandType*>(ct);
|
||||||
|
if(pct->getProducedUnit()->getName()==producedName){
|
||||||
|
unit->giveCommand(new Command(pct));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::giveUpgradeCommand(int unitId, const string &upgradeName){
|
||||||
|
Unit *unit= findUnitById(unitId);
|
||||||
|
if(unit!=NULL){
|
||||||
|
const UnitType *ut= unit->getType();
|
||||||
|
|
||||||
|
//Search for a command that can produce the unit
|
||||||
|
for(int i= 0; i<ut->getCommandTypeCount(); ++i){
|
||||||
|
const CommandType* ct= ut->getCommandType(i);
|
||||||
|
if(ct->getClass()==ccUpgrade){
|
||||||
|
const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
|
||||||
|
if(uct->getProducedUpgrade()->getName()==upgradeName){
|
||||||
|
unit->giveCommand(new Command(uct));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int World::getResourceAmount(const string &resourceName, int factionIndex){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
const ResourceType* rt= techTree.getResourceType(resourceName);
|
||||||
|
return faction->getResource(rt)->getAmount();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2i World::getStartLocation(int factionIndex){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
return map.getStartLocation(faction->getStartLocationIndex());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in getStartLocation: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2i World::getUnitPosition(int unitId){
|
||||||
|
Unit* unit= findUnitById(unitId);
|
||||||
|
if(unit==NULL){
|
||||||
|
throw runtime_error("Can not find unit to get position");
|
||||||
|
}
|
||||||
|
return unit->getPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
int World::getUnitFactionIndex(int unitId){
|
||||||
|
Unit* unit= findUnitById(unitId);
|
||||||
|
if(unit==NULL){
|
||||||
|
throw runtime_error("Can not find unit to get position");
|
||||||
|
}
|
||||||
|
return unit->getFactionIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
int World::getUnitCount(int factionIndex){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
int count= 0;
|
||||||
|
|
||||||
|
for(int i= 0; i<faction->getUnitCount(); ++i){
|
||||||
|
const Unit* unit= faction->getUnit(i);
|
||||||
|
if(unit->isAlive()){
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in getUnitCount: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int World::getUnitCountOfType(int factionIndex, const string &typeName){
|
||||||
|
if(factionIndex<factions.size()){
|
||||||
|
Faction* faction= &factions[factionIndex];
|
||||||
|
int count= 0;
|
||||||
|
|
||||||
|
for(int i= 0; i< faction->getUnitCount(); ++i){
|
||||||
|
const Unit* unit= faction->getUnit(i);
|
||||||
|
if(unit->isAlive() && unit->getType()->getName()==typeName){
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw runtime_error("Invalid faction index in getUnitCountOfType: " + intToStr(factionIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== PRIVATE ====================
|
||||||
|
|
||||||
|
// ==================== private init ====================
|
||||||
|
|
||||||
|
//init basic cell state
|
||||||
|
void World::initCells(){
|
||||||
|
|
||||||
|
Logger::getInstance().add("State cells", true);
|
||||||
|
for(int i=0; i<map.getSurfaceW(); ++i){
|
||||||
|
for(int j=0; j<map.getSurfaceH(); ++j){
|
||||||
|
|
||||||
|
SurfaceCell *sc= map.getSurfaceCell(i, j);
|
||||||
|
|
||||||
|
sc->setFowTexCoord(Vec2f(
|
||||||
|
i/(next2Power(map.getSurfaceW())-1.f),
|
||||||
|
j/(next2Power(map.getSurfaceH())-1.f)));
|
||||||
|
|
||||||
|
for(int k=0; k<GameConstants::maxPlayers; k++){
|
||||||
|
sc->setExplored(k, false);
|
||||||
|
sc->setVisible(k, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//init surface textures
|
||||||
|
void World::initSplattedTextures(){
|
||||||
|
for(int i=0; i<map.getSurfaceW()-1; ++i){
|
||||||
|
for(int j=0; j<map.getSurfaceH()-1; ++j){
|
||||||
|
Vec2f coord;
|
||||||
|
const Texture2D *texture;
|
||||||
|
SurfaceCell *sc00= map.getSurfaceCell(i, j);
|
||||||
|
SurfaceCell *sc10= map.getSurfaceCell(i+1, j);
|
||||||
|
SurfaceCell *sc01= map.getSurfaceCell(i, j+1);
|
||||||
|
SurfaceCell *sc11= map.getSurfaceCell(i+1, j+1);
|
||||||
|
tileset.addSurfTex(
|
||||||
|
sc00->getSurfaceType(),
|
||||||
|
sc10->getSurfaceType(),
|
||||||
|
sc01->getSurfaceType(),
|
||||||
|
sc11->getSurfaceType(),
|
||||||
|
coord, texture);
|
||||||
|
sc00->setSurfTexCoord(coord);
|
||||||
|
sc00->setSurfaceTexture(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//creates each faction looking at each faction name contained in GameSettings
|
||||||
|
void World::initFactionTypes(GameSettings *gs){
|
||||||
|
Logger::getInstance().add("Faction types", true);
|
||||||
|
|
||||||
|
if(gs->getFactionCount() > map.getMaxPlayers()){
|
||||||
|
throw runtime_error("This map only supports "+intToStr(map.getMaxPlayers())+" players");
|
||||||
|
}
|
||||||
|
|
||||||
|
//create stats
|
||||||
|
stats.init(gs->getFactionCount(), gs->getThisFactionIndex(), gs->getDescription());
|
||||||
|
|
||||||
|
//create factions
|
||||||
|
this->thisFactionIndex= gs->getThisFactionIndex();
|
||||||
|
factions.resize(gs->getFactionCount());
|
||||||
|
for(int i=0; i<factions.size(); ++i){
|
||||||
|
const FactionType *ft= techTree.getType(gs->getFactionTypeName(i));
|
||||||
|
factions[i].init(
|
||||||
|
ft, gs->getFactionControl(i), &techTree, i, gs->getTeam(i),
|
||||||
|
gs->getStartLocationIndex(i), i==thisFactionIndex, gs->getDefaultResources());
|
||||||
|
|
||||||
|
stats.setTeam(i, gs->getTeam(i));
|
||||||
|
stats.setFactionTypeName(i, formatString(gs->getFactionTypeName(i)));
|
||||||
|
stats.setControl(i, gs->getFactionControl(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
thisTeamIndex= getFaction(thisFactionIndex)->getTeam();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::initMinimap(){
|
||||||
|
minimap.init(map.getW(), map.getH(), this);
|
||||||
|
Logger::getInstance().add("Compute minimap surface", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//place units randomly aroud start location
|
||||||
|
void World::initUnits(){
|
||||||
|
|
||||||
|
Logger::getInstance().add("Generate elements", true);
|
||||||
|
|
||||||
|
//put starting units
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
Faction *f= &factions[i];
|
||||||
|
const FactionType *ft= f->getType();
|
||||||
|
for(int j=0; j<ft->getStartingUnitCount(); ++j){
|
||||||
|
const UnitType *ut= ft->getStartingUnit(j);
|
||||||
|
int initNumber= ft->getStartingUnitAmount(j);
|
||||||
|
for(int l=0; l<initNumber; l++){
|
||||||
|
|
||||||
|
//!!!
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] A\n",__FILE__,__FUNCTION__);
|
||||||
|
float unitRotation = game->getGui()->getUnitTypeBuildRotation(ut->getId());
|
||||||
|
//if(Socket::enableDebugText) printf("In [%s::%s] B\n",__FILE__,__FUNCTION__);
|
||||||
|
|
||||||
|
Unit *unit= new Unit(getNextUnitId(), Vec2i(0), ut, f, &map, unitRotation);
|
||||||
|
|
||||||
|
int startLocationIndex= f->getStartLocationIndex();
|
||||||
|
|
||||||
|
if(placeUnit(map.getStartLocation(startLocationIndex), generationArea, unit, true)){
|
||||||
|
unit->create(true);
|
||||||
|
unit->born();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw runtime_error("Unit cant be placed, this error is caused because there is no enough place to put the units near its start location, make a better map: "+unit->getType()->getName() + " Faction: "+intToStr(i));
|
||||||
|
}
|
||||||
|
if(unit->getType()->hasSkillClass(scBeBuilt)){
|
||||||
|
map.flatternTerrain(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.computeNormals();
|
||||||
|
map.computeInterpolatedHeights();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::initMap(){
|
||||||
|
map.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::initExplorationState(){
|
||||||
|
if(!fogOfWar){
|
||||||
|
for(int i=0; i<map.getSurfaceW(); ++i){
|
||||||
|
for(int j=0; j<map.getSurfaceH(); ++j){
|
||||||
|
map.getSurfaceCell(i, j)->setVisible(thisTeamIndex, true);
|
||||||
|
map.getSurfaceCell(i, j)->setExplored(thisTeamIndex, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== exploration ====================
|
||||||
|
|
||||||
|
void World::exploreCells(const Vec2i &newPos, int sightRange, int teamIndex){
|
||||||
|
|
||||||
|
Vec2i newSurfPos= Map::toSurfCoords(newPos);
|
||||||
|
int surfSightRange= sightRange/Map::cellScale+1;
|
||||||
|
|
||||||
|
//explore
|
||||||
|
for(int i=-surfSightRange-indirectSightRange-1; i<=surfSightRange+indirectSightRange+1; ++i){
|
||||||
|
for(int j=-surfSightRange-indirectSightRange-1; j<=surfSightRange+indirectSightRange+1; ++j){
|
||||||
|
Vec2i currRelPos= Vec2i(i, j);
|
||||||
|
Vec2i currPos= newSurfPos + currRelPos;
|
||||||
|
if(map.isInsideSurface(currPos)){
|
||||||
|
|
||||||
|
SurfaceCell *sc= map.getSurfaceCell(currPos);
|
||||||
|
|
||||||
|
//explore
|
||||||
|
if(Vec2i(0).dist(currRelPos) < surfSightRange+indirectSightRange+1){
|
||||||
|
sc->setExplored(teamIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//visible
|
||||||
|
if(Vec2i(0).dist(currRelPos) < surfSightRange){
|
||||||
|
sc->setVisible(teamIndex, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//computes the fog of war texture, contained in the minimap
|
||||||
|
void World::computeFow(){
|
||||||
|
|
||||||
|
//reset texture
|
||||||
|
minimap.resetFowTex();
|
||||||
|
|
||||||
|
//reset cells
|
||||||
|
for(int i=0; i<map.getSurfaceW(); ++i){
|
||||||
|
for(int j=0; j<map.getSurfaceH(); ++j){
|
||||||
|
for(int k=0; k<GameConstants::maxPlayers; ++k){
|
||||||
|
if(fogOfWar || k!=thisTeamIndex){
|
||||||
|
map.getSurfaceCell(i, j)->setVisible(k, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute cells
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
|
||||||
|
Unit *unit= getFaction(i)->getUnit(j);
|
||||||
|
|
||||||
|
//exploration
|
||||||
|
if(unit->isOperative()){
|
||||||
|
exploreCells(unit->getCenteredPos(), unit->getType()->getSight(), unit->getTeam());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//fire
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
for(int j=0; j<getFaction(i)->getUnitCount(); ++j){
|
||||||
|
Unit *unit= getFaction(i)->getUnit(j);
|
||||||
|
|
||||||
|
//fire
|
||||||
|
ParticleSystem *fire= unit->getFire();
|
||||||
|
if(fire!=NULL){
|
||||||
|
fire->setActive(map.getSurfaceCell(Map::toSurfCoords(unit->getPos()))->isVisible(thisTeamIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute texture
|
||||||
|
for(int i=0; i<getFactionCount(); ++i){
|
||||||
|
Faction *faction= getFaction(i);
|
||||||
|
if(faction->getTeam()==thisTeamIndex){
|
||||||
|
for(int j=0; j<faction->getUnitCount(); ++j){
|
||||||
|
const Unit *unit= faction->getUnit(j);
|
||||||
|
if(unit->isOperative()){
|
||||||
|
int sightRange= unit->getType()->getSight();
|
||||||
|
|
||||||
|
//iterate through all cells
|
||||||
|
PosCircularIterator pci(&map, unit->getPos(), sightRange+indirectSightRange);
|
||||||
|
while(pci.next()){
|
||||||
|
Vec2i pos= pci.getPos();
|
||||||
|
Vec2i surfPos= Map::toSurfCoords(pos);
|
||||||
|
|
||||||
|
|
||||||
|
//compute max alpha
|
||||||
|
float maxAlpha;
|
||||||
|
if(surfPos.x>1 && surfPos.y>1 && surfPos.x<map.getSurfaceW()-2 && surfPos.y<map.getSurfaceH()-2){
|
||||||
|
maxAlpha= 1.f;
|
||||||
|
}
|
||||||
|
else if(surfPos.x>0 && surfPos.y>0 && surfPos.x<map.getSurfaceW()-1 && surfPos.y<map.getSurfaceH()-1){
|
||||||
|
maxAlpha= 0.3f;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
maxAlpha= 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute alpha
|
||||||
|
float alpha;
|
||||||
|
float dist= unit->getPos().dist(pos);
|
||||||
|
if(dist>sightRange){
|
||||||
|
alpha= clamp(1.f-(dist-sightRange)/(indirectSightRange), 0.f, maxAlpha);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alpha= maxAlpha;
|
||||||
|
}
|
||||||
|
minimap.incFowTextureAlphaSurface(surfPos, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}//end namespace
|
Loading…
Reference in New Issue