initial version ( megaglest 3.2.3-beta3 )

This commit is contained in:
Titus Tscharntke 2010-01-22 01:45:58 +00:00
commit 0ce9b5fcac
311 changed files with 49528 additions and 0 deletions

View File

@ -0,0 +1,391 @@
#include "configuration.h"
#include <stdexcept>
#include "xml/xml_parser.h"
#include "util/util.h"
#include "util/properties.h"
#include "util/conversion.h"
using namespace std;
using namespace Shared::Xml;
using namespace Shared::Util;
namespace Configurator{
// ===============================================
// class Configuration
// ===============================================
Configuration::~Configuration(){
for(int i= 0; i<fieldGroups.size(); ++i){
delete fieldGroups[i];
}
}
void Configuration::load(const string &path){
loadStructure(path);
loadValues(fileName);
}
void Configuration::loadStructure(const string &path){
XmlTree xmlTree;
xmlTree.load(path);
const XmlNode *configurationNode= xmlTree.getRootNode();
//title
title= configurationNode->getChild("title")->getAttribute("value")->getValue();
//fileName
fileName= configurationNode->getChild("file-name")->getAttribute("value")->getValue();
//icon
XmlNode *iconNode= configurationNode->getChild("icon");
icon= iconNode->getAttribute("value")->getBoolValue();
if(icon){
iconPath= iconNode->getAttribute("path")->getValue();
}
const XmlNode *fieldGroupsNode= configurationNode->getChild("field-groups");
fieldGroups.resize(fieldGroupsNode->getChildCount());
for(int i=0; i<fieldGroups.size(); ++i){
const XmlNode *fieldGroupNode= fieldGroupsNode->getChild("field-group", i);
FieldGroup *fieldGroup= new FieldGroup();
fieldGroup->load(fieldGroupNode);
fieldGroups[i]= fieldGroup;
}
}
void Configuration::loadValues(const string &path){
Properties properties;
properties.load(path);
for(int i=0; i<fieldGroups.size(); ++i){
FieldGroup *fg= fieldGroups[i];
for(int j=0; j<fg->getFieldCount(); ++j){
Field *f= fg->getField(j);
f->setValue(properties.getString(f->getVariableName()));
}
}
}
void Configuration::save(){
Properties properties;
properties.load(fileName);
for(int i=0; i<fieldGroups.size(); ++i){
FieldGroup *fg= fieldGroups[i];
for(int j=0; j<fg->getFieldCount(); ++j){
Field *f= fg->getField(j);
f->updateValue();
if(!f->isValueValid(f->getValue())){
f->setValue(f->getDefaultValue());
f->updateControl();
}
properties.setString(f->getVariableName(), f->getValue());
}
}
properties.save(fileName);
}
string Field::getInfo() const{
return name+" (default: " + defaultValue + ")";
}
// ===============================================
// class FieldGroup
// ===============================================
FieldGroup::~FieldGroup(){
for(int i= 0; i<fields.size(); ++i){
delete fields[i];
}
}
void FieldGroup::load(const XmlNode *groupNode){
name= groupNode->getAttribute("name")->getValue();
fields.resize(groupNode->getChildCount());
for(int i=0; i<fields.size(); ++i){
const XmlNode *fieldNode= groupNode->getChild("field", i);
Field *f= newField(fieldNode->getAttribute("type")->getValue());
//name
const XmlNode *nameNode= fieldNode->getChild("name");
f->setName(nameNode->getAttribute("value")->getValue());
//variableName
const XmlNode *variableNameNode= fieldNode->getChild("variable-name");
f->setVariableName(variableNameNode->getAttribute("value")->getValue());
//description
const XmlNode *descriptionNode= fieldNode->getChild("description");
f->setDescription(descriptionNode->getAttribute("value")->getValue());
//default
const XmlNode *defaultNode= fieldNode->getChild("default");
f->setDefaultValue(defaultNode->getAttribute("value")->getValue());
f->loadSpecific(fieldNode);
if(!f->isValueValid(f->getDefaultValue())){
throw runtime_error("Default value not valid in field: " + f->getName());
}
fields[i]= f;
}
}
Field *FieldGroup::newField(const string &type){
if(type=="Bool"){
return new BoolField();
}
else if(type=="Int"){
return new IntField();
}
else if(type=="Float"){
return new FloatField();
}
else if(type=="String"){
return new StringField();
}
else if(type=="Enum"){
return new EnumField();
}
else if(type=="IntRange"){
return new IntRangeField();
}
else if(type=="FloatRange"){
return new FloatRangeField();
}
else{
throw runtime_error("Unknown field type: " + type);
}
}
// ===============================================
// class BoolField
// ===============================================
void BoolField::createControl(wxWindow *parent, wxSizer *sizer){
checkBox= new wxCheckBox(parent, -1, "");
checkBox->SetValue(strToBool(value));
sizer->Add(checkBox);
}
void BoolField::updateValue(){
value= boolToStr(checkBox->GetValue());
}
void BoolField::updateControl(){
checkBox->SetValue(strToBool(value));
}
bool BoolField::isValueValid(const string &value){
try{
strToBool(value);
}
catch(const exception &){
return false;
}
return true;
}
// ===============================================
// class IntField
// ===============================================
void IntField::createControl(wxWindow *parent, wxSizer *sizer){
textCtrl= new wxTextCtrl(parent, -1, value.c_str());
sizer->Add(textCtrl);
}
void IntField::updateValue(){
value= textCtrl->GetValue();
}
void IntField::updateControl(){
textCtrl->SetValue(value.c_str());
}
bool IntField::isValueValid(const string &value){
try{
strToInt(value);
}
catch(const exception &){
return false;
}
return true;
}
// ===============================================
// class FloatField
// ===============================================
void FloatField::createControl(wxWindow *parent, wxSizer *sizer){
textCtrl= new wxTextCtrl(parent, -1, value.c_str());
sizer->Add(textCtrl);
}
void FloatField::updateValue(){
value= textCtrl->GetValue();
}
void FloatField::updateControl(){
textCtrl->SetValue(value.c_str());
}
bool FloatField::isValueValid(const string &value){
try{
strToFloat(value);
}
catch(const exception &){
return false;
}
return true;
}
// ===============================================
// class StringField
// ===============================================
void StringField::createControl(wxWindow *parent, wxSizer *sizer){
textCtrl= new wxTextCtrl(parent, -1, value.c_str());
textCtrl->SetSize(wxSize(3*textCtrl->GetSize().x/2, textCtrl->GetSize().y));
sizer->Add(textCtrl);
}
void StringField::updateValue(){
value= textCtrl->GetValue();
}
void StringField::updateControl(){
textCtrl->SetValue(value.c_str());
}
bool StringField::isValueValid(const string &value){
return true;
}
// ===============================================
// class EnumField
// ===============================================
void EnumField::createControl(wxWindow *parent, wxSizer *sizer){
comboBox= new wxComboBox(parent, -1, "", wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
for(int i=0; i<enumerants.size(); ++i){
comboBox->Append(enumerants[i].c_str());
}
comboBox->SetValue(value.c_str());
sizer->Add(comboBox);
}
void EnumField::updateValue(){
value= comboBox->GetValue();
}
void EnumField::updateControl(){
comboBox->SetValue(value.c_str());
}
bool EnumField::isValueValid(const string &value){
return true;
}
void EnumField::loadSpecific(const XmlNode *fieldNode){
const XmlNode *enumsNode= fieldNode->getChild("enums");
for(int i=0; i<enumsNode->getChildCount(); ++i){
const XmlNode *enumNode= enumsNode->getChild("enum", i);
enumerants.push_back(enumNode->getAttribute("value")->getValue());
}
};
// ===============================================
// class IntRange
// ===============================================
void IntRangeField::createControl(wxWindow *parent, wxSizer *sizer){
slider= new wxSlider(parent, -1, strToInt(value), min, max, wxDefaultPosition, wxDefaultSize, wxSL_LABELS);
sizer->Add(slider);
}
void IntRangeField::updateValue(){
value= intToStr(slider->GetValue());
}
void IntRangeField::updateControl(){
slider->SetValue(strToInt(value));
}
bool IntRangeField::isValueValid(const string &value){
try{
strToInt(value);
}
catch(const exception &){
return false;
}
return true;
}
void IntRangeField::loadSpecific(const XmlNode *fieldNode){
const XmlNode *minNode= fieldNode->getChild("min");
min= strToInt(minNode->getAttribute("value")->getValue());
const XmlNode *maxNode= fieldNode->getChild("max");
max= strToInt(maxNode->getAttribute("value")->getValue());
}
string IntRangeField::getInfo() const{
return name + " (min: " + intToStr(min)+ ", max: " + intToStr(max) + ", default: " + defaultValue + ")";
}
// ===============================================
// class FloatRangeField
// ===============================================
void FloatRangeField::createControl(wxWindow *parent, wxSizer *sizer){
textCtrl= new wxTextCtrl(parent, -1, value.c_str());
sizer->Add(textCtrl);
}
void FloatRangeField::updateValue(){
value= textCtrl->GetValue();
}
void FloatRangeField::updateControl(){
textCtrl->SetValue(value.c_str());
}
bool FloatRangeField::isValueValid(const string &value){
try{
float f= strToFloat(value);
return f>=min && f<=max;
}
catch(const exception &){
return false;
}
return true;
}
void FloatRangeField::loadSpecific(const XmlNode *fieldNode){
const XmlNode *minNode= fieldNode->getChild("min");
min= strToFloat(minNode->getAttribute("value")->getValue());
const XmlNode *maxNode= fieldNode->getChild("max");
max= strToFloat(maxNode->getAttribute("value")->getValue());
};
string FloatRangeField::getInfo() const{
return name + " (min: " + floatToStr(min)+ ", max: " + floatToStr(max) + ", default: " + defaultValue + ")";
}
}//end namespace

View File

@ -0,0 +1,237 @@
#ifndef _CONFIGURATOR_CONFIGURATION_H_
#define _CONFIGURATOR_CONFIGURATION_H_
#include <string>
#include <vector>
#include <wx/wx.h>
#include "xml/xml_parser.h"
using std::string;
using std::vector;
using Shared::Xml::XmlNode;
namespace Configurator{
class Field;
class FieldGroup;
// ===============================
// class Configuration
// ===============================
class Configuration{
public:
typedef vector<FieldGroup*> FieldGroups;
private:
string title;
string fileName;
bool icon;
string iconPath;
FieldGroups fieldGroups;
public:
~Configuration();
void load(const string &path);
void loadStructure(const string &path);
void loadValues(const string &path);
void save();
const string &getTitle() const {return title;}
const string &getFileName() const {return fileName;}
bool getIcon() const {return icon;}
const string &getIconPath() const {return iconPath;}
int getFieldGroupCount() const {return fieldGroups.size();}
FieldGroup *getFieldGroup(int i) const {return fieldGroups[i];}
};
// ===============================
// class FieldGroup
// ===============================
class FieldGroup{
public:
typedef vector<Field*> Fields;
private:
Fields fields;
string name;
public:
~FieldGroup();
int getFieldCount() const {return fields.size();}
Field *getField(int i) const {return fields[i];}
const string &getName() const {return name;}
void load(const XmlNode *groupNode);
private:
Field *newField(const string &type);
};
// ===============================
// class Field
// ===============================
class Field{
protected:
string name;
string variableName;
string description;
string value;
string defaultValue;
public:
virtual ~Field()= 0{}
const string &getName() const {return name;}
const string &getVariableName() const {return variableName;}
const string &getDescription() const {return description;}
const string &getValue() const {return value;}
const string &getDefaultValue() const {return defaultValue;}
void setName(const string &name) {this->name= name;}
void setVariableName(const string &variableName) {this->variableName= variableName;}
void setDescription(const string &description) {this->description= description;}
void setValue(const string &value) {this->value= value;}
void setDefaultValue(const string &defaultValue) {this->defaultValue= defaultValue;}
virtual void loadSpecific(const XmlNode *fieldNode){};
virtual string getInfo() const;
virtual void createControl(wxWindow *parent, wxSizer *sizer)= 0;
virtual void updateValue()= 0;
virtual void updateControl()= 0;
virtual bool isValueValid(const string &value)= 0;
};
// ===============================
// class BoolField
// ===============================
class BoolField: public Field{
private:
wxCheckBox *checkBox;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
};
// ===============================
// class IntField
// ===============================
class IntField: public Field{
private:
wxTextCtrl *textCtrl;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
};
// ===============================
// class FloatField
// ===============================
class FloatField: public Field{
private:
wxTextCtrl *textCtrl;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
};
// ===============================
// class StringField
// ===============================
class StringField: public Field{
private:
wxTextCtrl *textCtrl;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
};
// ===============================
// class EnumField
// ===============================
class EnumField: public Field{
private:
wxComboBox *comboBox;
vector<string> enumerants;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
virtual void loadSpecific(const XmlNode *fieldNode);
};
// ===============================
// class IntRangeField
// ===============================
class IntRangeField: public Field{
private:
wxSlider *slider;
int min;
int max;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
virtual void loadSpecific(const XmlNode *fieldNode);
virtual string getInfo() const;
};
// ===============================
// class FloatRangeField
// ===============================
class FloatRangeField: public Field{
private:
wxTextCtrl *textCtrl;
float min;
float max;
public:
virtual void createControl(wxWindow *parent, wxSizer *sizer);
virtual void updateValue();
virtual void updateControl();
virtual bool isValueValid(const string &value);
virtual void loadSpecific(const XmlNode *fieldNode);
virtual string getInfo() const;
};
}//end namespace
#endif

View File

@ -0,0 +1,197 @@
#include "main.h"
#include <stdexcept>
#include <wx/wx.h>
#include <wx/sizer.h>
#include <wx/image.h>
#include <wx/bitmap.h>
#include <wx/icon.h>
using namespace std;
namespace Configurator{
// ===============================================
// class MainWindow
// ===============================================
const int MainWindow::margin= 10;
const int MainWindow::panelMargin= 20;
const int MainWindow::gridMarginHorizontal= 30;
MainWindow::MainWindow(){
SetExtraStyle(wxFRAME_EX_CONTEXTHELP);
configuration.load("configuration.xml");
Create(NULL, -1, "", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxSYSTEM_MENU);
SetTitle(("Configurator - " + configuration.getTitle() + " - Editing " + configuration.getFileName()).c_str());
if(configuration.getIcon()){
wxIcon icon;
icon.LoadFile(configuration.getIconPath().c_str(), wxBITMAP_TYPE_ICO);
SetIcon(icon);
}
notebook= new wxNotebook(this, -1);
wxSizer *mainSizer= new wxBoxSizer(wxVERTICAL);
wxSizer *topSizer= new wxBoxSizer(wxHORIZONTAL);
topSizer->Add(notebook, 0, wxALL, 0);
mainSizer->Add(topSizer, 0, wxALL, margin);
for(int i=0; i<configuration.getFieldGroupCount(); ++i){
//create page
FieldGroup *fg= configuration.getFieldGroup(i);
wxPanel *panel= new wxPanel(notebook, -1);
notebook->AddPage(panel, fg->getName().c_str());
//sizers
wxSizer *gridSizer= new wxFlexGridSizer(2, margin, gridMarginHorizontal);
wxSizer *panelSizer= new wxBoxSizer(wxVERTICAL);
panelSizer->Add(gridSizer, 0, wxALL, panelMargin);
panel->SetSizer(panelSizer);
for(int j=0; j<fg->getFieldCount(); ++j){
Field *f= fg->getField(j);
FieldText *staticText= new FieldText(panel, this, f);
staticText->SetAutoLayout(true);
gridSizer->Add(staticText);
f->createControl(panel, gridSizer);
idMap.insert(IdPair(staticText->GetId(), staticText));
}
}
//buttons
wxSizer *bottomSizer= new wxBoxSizer(wxHORIZONTAL);
buttonOk= new wxButton(this, biOk, "OK");
buttonApply= new wxButton(this, biApply, "Apply");
buttonCancel= new wxButton(this, biCancel, "Cancel");
buttonDefault= new wxButton(this, biDefault, "Default");
bottomSizer->Add(buttonOk, 0, wxALL, margin);
bottomSizer->Add(buttonApply, 0, wxRIGHT | wxDOWN | wxUP, margin);
bottomSizer->Add(buttonCancel, 0, wxRIGHT | wxDOWN | wxUP, margin);
bottomSizer->Add(buttonDefault, 0, wxRIGHT | wxDOWN | wxUP, margin);
infoText= new wxTextCtrl(this, -1, "Info text.", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
infoText->SetSize(infoText->GetSize().x, 2*infoText->GetSize().y/3);
infoText->SetBackgroundColour(buttonOk->GetBackgroundColour());
mainSizer->Add(infoText, 1, wxGROW | wxALL | wxALIGN_CENTER, margin);
mainSizer->Add(bottomSizer, 0, wxALIGN_CENTER);
SetBackgroundColour(buttonOk->GetBackgroundColour());
SetSizerAndFit(mainSizer);
Refresh();
}
void MainWindow::onButtonOk(wxCommandEvent &event){
configuration.save();
Close();
}
void MainWindow::onButtonApply(wxCommandEvent &event){
configuration.save();
}
void MainWindow::onButtonCancel(wxCommandEvent &event){
Close();
}
void MainWindow::onButtonDefault(wxCommandEvent &event){
for(int i=0; i<configuration.getFieldGroupCount(); ++i){
FieldGroup *fg= configuration.getFieldGroup(i);
for(int j=0; j<fg->getFieldCount(); ++j){
Field *f= fg->getField(j);
f->setValue(f->getDefaultValue());
f->updateControl();
}
}
}
void MainWindow::onClose(wxCloseEvent &event){
Destroy();
}
void MainWindow::onMouseDown(wxMouseEvent &event){
setInfoText("");
}
void MainWindow::setInfoText(const string &str){
infoText->SetValue(str.c_str());
}
BEGIN_EVENT_TABLE(MainWindow, wxFrame)
EVT_BUTTON(biOk, MainWindow::onButtonOk)
EVT_BUTTON(biApply, MainWindow::onButtonApply)
EVT_BUTTON(biCancel, MainWindow::onButtonCancel)
EVT_BUTTON(biDefault, MainWindow::onButtonDefault)
EVT_CLOSE(MainWindow::onClose)
EVT_LEFT_DOWN(MainWindow::onMouseDown)
END_EVENT_TABLE()
// ===============================================
// class FieldText
// ===============================================
FieldText::FieldText(wxWindow *parent, MainWindow *mainWindow, const Field *field):
wxStaticText(parent, -1, field->getName().c_str())
{
this->mainWindow= mainWindow;
this->field= field;
}
void FieldText::onHelp(wxHelpEvent &event){
string str= field->getInfo()+".";
if(!field->getDescription().empty()){
str+= "\n"+field->getDescription()+".";
}
mainWindow->setInfoText(str);
}
BEGIN_EVENT_TABLE(FieldText, wxStaticText)
EVT_HELP(-1, FieldText::onHelp)
END_EVENT_TABLE()
// ===============================================
// class App
// ===============================================
bool App::OnInit(){
try{
mainWindow= new MainWindow();
mainWindow->Show();
}
catch(const exception &e){
wxMessageDialog(NULL, e.what(), "Exception", wxOK | wxICON_ERROR).ShowModal();
return 0;
}
return true;
}
int App::MainLoop(){
try{
return wxApp::MainLoop();
}
catch(const exception &e){
wxMessageDialog(NULL, e.what(), "Exception", wxOK | wxICON_ERROR).ShowModal();
return 0;
}
}
int App::OnExit(){
return 0;
}
}//end namespace
IMPLEMENT_APP(Configurator::App)

101
source/configurator/main.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef _CONFIGURATOR_MAIN_H_
#define _CONFIGURATOR_MAIN_H_
#include <map>
#include <wx/wx.h>
#include <wx/cshelp.h>
#include <wx/notebook.h>
#include <wx/sizer.h>
#include "configuration.h"
using std::pair;
using std::map;
namespace Configurator{
// ===============================
// class MainWindow
// ===============================
class MainWindow: public wxFrame{
private:
DECLARE_EVENT_TABLE()
private:
typedef pair<int, wxWindow*> IdPair;
typedef map<int, wxWindow*> IdMap;
private:
static const int margin;
static const int panelMargin;
static const int gridMarginHorizontal;
enum ButtonId{
biOk,
biApply,
biCancel,
biDefault
};
private:
IdMap idMap;
Configuration configuration;
wxButton *buttonOk;
wxButton *buttonApply;
wxButton *buttonCancel;
wxButton *buttonDefault;
wxNotebook *notebook;
wxTextCtrl *infoText;
public:
MainWindow();
void onButtonOk(wxCommandEvent &event);
void onButtonApply(wxCommandEvent &event);
void onButtonCancel(wxCommandEvent &event);
void onButtonDefault(wxCommandEvent &event);
void onClose(wxCloseEvent &event);
void onMouseDown(wxMouseEvent &event);
void setInfoText(const string &str);
};
// ===============================
// class FieldText
// ===============================
class FieldText: public wxStaticText{
private:
MainWindow *mainWindow;
const Field *field;
private:
DECLARE_EVENT_TABLE()
public:
FieldText(wxWindow *parentm, MainWindow *mainWindow, const Field *field);
void onHelp(wxHelpEvent &event);
};
// ===============================
// class App
// ===============================
class App: public wxApp{
private:
MainWindow *mainWindow;
public:
virtual bool OnInit();
virtual int MainLoop();
virtual int OnExit();
};
}//end namespace
DECLARE_APP(Configurator::App)
#endif

304
source/g3d_viewer/main.cpp Normal file
View File

@ -0,0 +1,304 @@
#include "main.h"
#include <stdexcept>
#include "graphics_factory_basic_gl.h"
#include "graphics_interface.h"
#include "util.h"
using namespace Shared::Platform;
using namespace Shared::Graphics;
using namespace Shared::Graphics::Gl;
using namespace Shared::Util;
using namespace std;
namespace Shared{ namespace G3dViewer{
// ===============================================
// class MainWindow
// ===============================================
const string MainWindow::versionString= "v1.3.4";
const string MainWindow::winHeader= "G3D viewer " + versionString + " - Built: " + __DATE__;
MainWindow::MainWindow(const string &modelPath):
wxFrame(
NULL, -1, winHeader.c_str(),
wxPoint(Renderer::windowX, Renderer::windowY),
wxSize(Renderer::windowW, Renderer::windowH))
{
renderer= Renderer::getInstance();
this->modelPath= modelPath;
model= NULL;
playerColor= Renderer::pcRed;
speed= 0.025f;
glCanvas = new GlCanvas(this);
glCanvas->SetCurrent();
renderer->init();
menu= new wxMenuBar();
//menu
menuFile= new wxMenu();
menuFile->Append(miFileLoad, "Load");
menu->Append(menuFile, "File");
//mode
menuMode= new wxMenu();
menuMode->AppendCheckItem(miModeNormals, "Normals");
menuMode->AppendCheckItem(miModeWireframe, "Wireframe");
menuMode->AppendCheckItem(miModeGrid, "Grid");
menu->Append(menuMode, "Mode");
//mode
menuSpeed= new wxMenu();
menuSpeed->Append(miSpeedSlower, "Slower");
menuSpeed->Append(miSpeedFaster, "Faster");
menu->Append(menuSpeed, "Speed");
//custom color
menuCustomColor= new wxMenu();
menuCustomColor->AppendCheckItem(miColorRed, "Red");
menuCustomColor->AppendCheckItem(miColorBlue, "Blue");
menuCustomColor->AppendCheckItem(miColorYellow, "Yellow");
menuCustomColor->AppendCheckItem(miColorGreen, "Green");
menu->Append(menuCustomColor, "Custom Color");
menuMode->Check(miModeGrid, true);
menuCustomColor->Check(miColorRed, true);
SetMenuBar(menu);
//misc
model= NULL;
rotX= 0.0f;
rotY= 0.0f;
zoom= 1.0f;
lastX= 0;
lastY= 0;
anim= 0.0f;
CreateStatusBar();
timer = new wxTimer(this);
timer->Start(40);
if(!modelPath.empty()){
Model *tmpModel= new ModelGl();
renderer->loadTheModel(tmpModel, modelPath);
model= tmpModel;
GetStatusBar()->SetStatusText(getModelInfo().c_str());
}
}
MainWindow::~MainWindow(){
delete renderer;
delete model;
delete timer;
delete glCanvas;
}
void MainWindow::onPaint(wxPaintEvent &event){
renderer->reset(GetClientSize().x, GetClientSize().y, playerColor);
renderer->transform(rotX, rotY, zoom);
renderer->renderGrid();
renderer->renderTheModel(model, anim);
glCanvas->SwapBuffers();
}
void MainWindow::onClose(wxCloseEvent &event){
delete this;
}
void MainWindow::onMouseMove(wxMouseEvent &event){
int x= event.GetX();
int y= event.GetY();
wxPaintEvent paintEvent;
if(event.LeftIsDown()){
rotX+= clamp(lastX-x, -10, 10);
rotY+= clamp(lastY-y, -10, 10);
onPaint(paintEvent);
}
else if(event.RightIsDown()){
zoom*= 1.0f+(lastX-x+lastY-y)/100.0f;
zoom= clamp(zoom, 0.1f, 10.0f);
onPaint(paintEvent);
}
lastX= x;
lastY= y;
}
void MainWindow::onMenuFileLoad(wxCommandEvent &event){
string fileName;
wxFileDialog fileDialog(this);
fileDialog.SetWildcard("G3D files (*.g3d)|*.g3d");
if(fileDialog.ShowModal()==wxID_OK){
delete model;
Model *tmpModel= new ModelGl();
renderer->loadTheModel(tmpModel, fileDialog.GetPath().c_str());
model= tmpModel;
GetStatusBar()->SetStatusText(getModelInfo().c_str());
}
}
void MainWindow::onMenuModeNormals(wxCommandEvent &event){
renderer->toggleNormals();
menuMode->Check(miModeNormals, renderer->getNormals());
}
void MainWindow::onMenuModeWireframe(wxCommandEvent &event){
renderer->toggleWireframe();
menuMode->Check(miModeWireframe, renderer->getWireframe());
}
void MainWindow::onMenuModeGrid(wxCommandEvent &event){
renderer->toggleGrid();
menuMode->Check(miModeGrid, renderer->getGrid());
}
void MainWindow::onMenuSpeedSlower(wxCommandEvent &event){
speed/= 1.5f;
}
void MainWindow::onMenuSpeedFaster(wxCommandEvent &event){
speed*= 1.5f;
}
void MainWindow::onMenuColorRed(wxCommandEvent &event){
playerColor= Renderer::pcRed;
menuCustomColor->Check(miColorRed, true);
menuCustomColor->Check(miColorBlue, false);
menuCustomColor->Check(miColorYellow, false);
menuCustomColor->Check(miColorGreen, false);
}
void MainWindow::onMenuColorBlue(wxCommandEvent &event){
playerColor= Renderer::pcBlue;
menuCustomColor->Check(miColorRed, false);
menuCustomColor->Check(miColorBlue, true);
menuCustomColor->Check(miColorYellow, false);
menuCustomColor->Check(miColorGreen, false);
}
void MainWindow::onMenuColorYellow(wxCommandEvent &event){
playerColor= Renderer::pcYellow;
menuCustomColor->Check(miColorRed, false);
menuCustomColor->Check(miColorBlue, false);
menuCustomColor->Check(miColorYellow, true);
menuCustomColor->Check(miColorGreen, false);
}
void MainWindow::onMenuColorGreen(wxCommandEvent &event){
playerColor= Renderer::pcGreen;
menuCustomColor->Check(miColorRed, false);
menuCustomColor->Check(miColorBlue, false);
menuCustomColor->Check(miColorYellow, false);
menuCustomColor->Check(miColorGreen, true);
}
void MainWindow::onTimer(wxTimerEvent &event){
wxPaintEvent paintEvent;
anim= anim+speed;
if(anim>1.0f){
anim-= 1.f;
}
onPaint(paintEvent);
}
string MainWindow::getModelInfo(){
string str;
if(model!=NULL){
str+= "Meshes: "+intToStr(model->getMeshCount());
str+= ", Vertices: "+intToStr(model->getVertexCount());
str+= ", Triangles: "+intToStr(model->getTriangleCount());
str+= ", Version: "+intToStr(model->getFileVersion());
}
return str;
}
BEGIN_EVENT_TABLE(MainWindow, wxFrame)
EVT_TIMER(-1, MainWindow::onTimer)
EVT_CLOSE(MainWindow::onClose)
EVT_MENU(miFileLoad, MainWindow::onMenuFileLoad)
EVT_MENU(miModeWireframe, MainWindow::onMenuModeWireframe)
EVT_MENU(miModeNormals, MainWindow::onMenuModeNormals)
EVT_MENU(miModeGrid, MainWindow::onMenuModeGrid)
EVT_MENU(miSpeedFaster, MainWindow::onMenuSpeedFaster)
EVT_MENU(miSpeedSlower, MainWindow::onMenuSpeedSlower)
EVT_MENU(miColorRed, MainWindow::onMenuColorRed)
EVT_MENU(miColorBlue, MainWindow::onMenuColorBlue)
EVT_MENU(miColorYellow, MainWindow::onMenuColorYellow)
EVT_MENU(miColorGreen, MainWindow::onMenuColorGreen)
END_EVENT_TABLE()
// =====================================================
// class GlCanvas
// =====================================================
GlCanvas::GlCanvas(MainWindow * mainWindow):
wxGLCanvas(mainWindow, -1)
{
this->mainWindow = mainWindow;
}
void GlCanvas::onMouseMove(wxMouseEvent &event){
mainWindow->onMouseMove(event);
}
void GlCanvas::onPaint(wxPaintEvent &event){
mainWindow->onPaint(event);
}
BEGIN_EVENT_TABLE(GlCanvas, wxGLCanvas)
EVT_MOTION(GlCanvas::onMouseMove)
EVT_PAINT(GlCanvas::onPaint)
END_EVENT_TABLE()
// ===============================================
// class App
// ===============================================
bool App::OnInit(){
string modelPath;
if(argc==2){
modelPath= argv[1];
}
mainWindow= new MainWindow(modelPath);
mainWindow->Show();
return true;
}
int App::MainLoop(){
try{
return wxApp::MainLoop();
}
catch(const exception &e){
wxMessageDialog(NULL, e.what(), "Exception", wxOK | wxICON_ERROR).ShowModal();
return 0;
}
}
int App::OnExit(){
return 0;
}
}}//end namespace
IMPLEMENT_APP(Shared::G3dViewer::App)

129
source/g3d_viewer/main.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef _SHADER_G3DVIEWER_MAIN_H_
#define _SHADER_G3DVIEWER_MAIN_H_
#include <string>
#include <wx/wx.h>
#include <wx/timer.h>
#include <wx/glcanvas.h>
#include "renderer.h"
#include "util.h"
#include "window.h"
using Shared::Platform::Window;
using Shared::Platform::MouseState;
using std::string;
namespace Shared{ namespace G3dViewer{
class GlCanvas;
// ===============================
// class MainWindow
// ===============================
class MainWindow: public wxFrame{
private:
DECLARE_EVENT_TABLE()
public:
static const string versionString;
static const string winHeader;
enum MenuId{
miFileLoad,
miModeWireframe,
miModeNormals,
miModeGrid,
miSpeedSlower,
miSpeedFaster,
miColorRed,
miColorBlue,
miColorYellow,
miColorGreen
};
private:
GlCanvas *glCanvas;
Renderer *renderer;
wxTimer *timer;
wxMenuBar *menu;
wxMenu *menuFile;
wxMenu *menuMode;
wxMenu *menuSpeed;
wxMenu *menuCustomColor;
Model *model;
string modelPath;
float speed;
float anim;
float rotX, rotY, zoom;
int lastX, lastY;
Renderer::PlayerColor playerColor;
public:
MainWindow(const string &modelPath);
~MainWindow();
void Notify();
void onPaint(wxPaintEvent &event);
void onClose(wxCloseEvent &event);
void onMenuFileLoad(wxCommandEvent &event);
void onMenuModeNormals(wxCommandEvent &event);
void onMenuModeWireframe(wxCommandEvent &event);
void onMenuModeGrid(wxCommandEvent &event);
void onMenuSpeedSlower(wxCommandEvent &event);
void onMenuSpeedFaster(wxCommandEvent &event);
void onMenuColorRed(wxCommandEvent &event);
void onMenuColorBlue(wxCommandEvent &event);
void onMenuColorYellow(wxCommandEvent &event);
void onMenuColorGreen(wxCommandEvent &event);
void onMouseMove(wxMouseEvent &event);
void onTimer(wxTimerEvent &event);
string getModelInfo();
};
// =====================================================
// class GlCanvas
// =====================================================
class GlCanvas: public wxGLCanvas{
private:
DECLARE_EVENT_TABLE()
public:
GlCanvas(MainWindow *mainWindow);
void onMouseMove(wxMouseEvent &event);
void onPaint(wxPaintEvent &event);
private:
MainWindow *mainWindow;
};
// ===============================
// class App
// ===============================
class App: public wxApp{
private:
MainWindow *mainWindow;
public:
virtual bool OnInit();
virtual int MainLoop();
virtual int OnExit();
};
}}//end namespace
DECLARE_APP(Shared::G3dViewer::App)
#endif

View File

@ -0,0 +1,272 @@
#include "renderer.h"
#include "opengl.h"
#include "texture_gl.h"
#include "graphics_interface.h"
#include "graphics_factory_gl.h"
using namespace Shared::Graphics;
using namespace Shared::Graphics::Gl;
namespace Shared{ namespace G3dViewer{
// ===============================================
// class MeshCallbackTeamColor
// ===============================================
void MeshCallbackTeamColor::execute(const Mesh *mesh){
//team color
if(mesh->getCustomTexture() && teamTexture!=NULL){
//texture 0
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
//set color to interpolation
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
//set alpha to 1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
//texture 1
glActiveTexture(GL_TEXTURE1);
glMultiTexCoord2f(GL_TEXTURE1, 0.f, 0.f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, static_cast<const Texture2DGl*>(teamTexture)->getHandle());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
//set alpha to 1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
}
else{
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
}
// ===============================================
// class Renderer
// ===============================================
Renderer::Renderer(){
normals= false;
wireframe= false;
grid= true;
}
Renderer::~Renderer(){
delete modelRenderer;
delete textureManager;
}
Renderer * Renderer::getInstance(){
static Renderer * renderer = new Renderer();
return renderer;
}
void Renderer::transform(float rotX, float rotY, float zoom){
assertGl();
glMatrixMode(GL_MODELVIEW);
glRotatef(rotY, 1.0f, 0.0f, 0.0f);
glRotatef(rotX, 0.0f, 1.0f, 0.0f);
glScalef(zoom, zoom, zoom);
Vec4f pos(-8.0f, 5.0f, 10.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION, pos.ptr());
assertGl();
}
void Renderer::init(){
assertGl();
GraphicsFactory *gf= new GraphicsFactoryGl();
GraphicsInterface::getInstance().setFactory(gf);
modelRenderer= gf->newModelRenderer();
textureManager= gf->newTextureManager();
//red tex
customTextureRed= textureManager->newTexture2D();
customTextureRed->getPixmap()->init(1, 1, 3);
customTextureRed->getPixmap()->setPixel(0, 0, Vec3f(1.f, 0.f, 0.f));
//blue tex
customTextureBlue= textureManager->newTexture2D();
customTextureBlue->getPixmap()->init(1, 1, 3);
customTextureBlue->getPixmap()->setPixel(0, 0, Vec3f(0.f, 0.f, 1.f));
//yellow tex
customTextureYellow= textureManager->newTexture2D();
customTextureYellow->getPixmap()->init(1, 1, 3);
customTextureYellow->getPixmap()->setPixel(0, 0, Vec3f(1.f, 1.f, 0.f));
//green
customTextureGreen= textureManager->newTexture2D();
customTextureGreen->getPixmap()->init(1, 1, 3);
customTextureGreen->getPixmap()->setPixel(0, 0, Vec3f(0.f, 0.5f, 0.f));
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glEnable(GL_TEXTURE_2D);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
Vec4f diffuse= Vec4f(1.0f, 1.0f, 1.0f, 1.0f);
Vec4f ambient= Vec4f(0.3f, 0.3f, 0.3f, 1.0f);
Vec4f specular= Vec4f(0.1f, 0.1f, 0.1f, 1.0f);
glLightfv(GL_LIGHT0,GL_AMBIENT, ambient.ptr());
glLightfv(GL_LIGHT0,GL_DIFFUSE, diffuse.ptr());
glLightfv(GL_LIGHT0,GL_SPECULAR, specular.ptr());
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
assertGl();
}
void Renderer::reset(int w, int h, PlayerColor playerColor){
assertGl();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, static_cast<float>(w)/h, 1.0f, 200.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, -1.5, -5);
Texture2D *customTexture;
switch(playerColor){
case pcRed:
customTexture= customTextureRed;
break;
case pcBlue:
customTexture= customTextureBlue;
break;
case pcYellow:
customTexture= customTextureYellow;
break;
case pcGreen:
customTexture= customTextureGreen;
break;
default:
assert(false);
}
meshCallbackTeamColor.setTeamTexture(customTexture);
if(wireframe){
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
}
else{
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
assertGl();
}
void Renderer::renderGrid(){
if(grid){
float i;
assertGl();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glBegin(GL_LINES);
glColor3f(1.0f, 1.0f, 1.0f);
for(i=-10.0f; i<=10.0f; i+=1.0f){
glVertex3f(i, 0.0f, 10.0f);
glVertex3f(i, 0.0f, -10.0f);
}
for(i=-10.0f; i<=10.0f; i+=1.0f){
glVertex3f(10.f, 0.0f, i);
glVertex3f(-10.f, 0.0f, i);
}
glEnd();
glPopAttrib();
assertGl();
}
}
void Renderer::toggleNormals(){
normals= normals? false: true;
}
void Renderer::toggleWireframe(){
wireframe= wireframe? false: true;
}
void Renderer::toggleGrid(){
grid= grid? false: true;
}
void Renderer::loadTheModel(Model *model, string file){
model->setTextureManager(textureManager);
model->loadG3d(file);
textureManager->init();
}
void Renderer::renderTheModel(Model *model, float f){
if(model != NULL){
modelRenderer->begin(true, true, !wireframe, &meshCallbackTeamColor);
model->updateInterpolationData(f, true);
modelRenderer->render(model);
if(normals){
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f, 1.0f, 1.0f);
modelRenderer->renderNormalsOnly(model);
glPopAttrib();
}
modelRenderer->end();
}
}
}}//end namespace

View File

@ -0,0 +1,92 @@
#ifndef _SHADER_G3DVIEWER_RENDERER_H_
#define _SHADER_G3DVIEWER_RENDERER_H_
#include "model_renderer.h"
#include "texture_manager.h"
#include "model.h"
#include "texture.h"
using Shared::Graphics::ModelRenderer;
using Shared::Graphics::TextureManager;
using Shared::Graphics::Model;
using Shared::Graphics::Texture2D;
#include "model_renderer.h"
using Shared::Graphics::MeshCallback;
using Shared::Graphics::Mesh;
using Shared::Graphics::Texture;
namespace Shared{ namespace G3dViewer{
// ===============================================
// class MeshCallbackTeamColor
// ===============================================
class MeshCallbackTeamColor: public MeshCallback{
private:
const Texture *teamTexture;
public:
void setTeamTexture(const Texture *teamTexture) {this->teamTexture= teamTexture;}
virtual void execute(const Mesh *mesh);
};
// ===============================
// class Renderer
// ===============================
class Renderer{
public:
static const int windowX= 100;
static const int windowY= 100;
static const int windowW= 640;
static const int windowH= 480;
public:
enum PlayerColor{
pcRed,
pcBlue,
pcYellow,
pcGreen
};
private:
bool wireframe;
bool normals;
bool grid;
ModelRenderer *modelRenderer;
TextureManager *textureManager;
Texture2D *customTextureRed;
Texture2D *customTextureBlue;
Texture2D *customTextureYellow;
Texture2D *customTextureGreen;
MeshCallbackTeamColor meshCallbackTeamColor;
Renderer();
public:
~Renderer();
static Renderer *getInstance();
void init();
void reset(int w, int h, PlayerColor playerColor);
void transform(float rotX, float rotY, float zoom);
void renderGrid();
bool getNormals() const {return normals;}
bool getWireframe() const {return wireframe;}
bool getGrid() const {return grid;}
void toggleNormals();
void toggleWireframe();
void toggleGrid();
void loadTheModel(Model *model, string file);
void renderTheModel(Model *model, float f);
};
}}//end namespace
#endif

482
source/glest_game/ai/ai.cpp Normal file
View File

@ -0,0 +1,482 @@
// ==============================================================
// 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 "ai.h"
#include <ctime>
#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; i<aiInterface->getMyUnitCount(); ++i){
if(ut == aiInterface->getMyUnit(i)->getType()){
count++;
}
}
return count;
}
int Ai::getCountOfClass(UnitClass uc){
int count= 0;
for(int i=0; i<aiInterface->getMyUnitCount(); ++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<float>(getCountOfClass(uc))/aiInterface->getMyUnitCount();
}
}
const ResourceType *Ai::getNeededResource(){
int amount= -1;
const ResourceType *neededResource= NULL;
const TechTree *tt= aiInterface->getTechTree();
for(int i=0; i<tt->getResourceTypeCount(); ++i){
const ResourceType *rt= tt->getResourceType(i);
const Resource *r= aiInterface->getResource(rt);
if(rt->getClass()!=rcStatic && rt->getClass()!=rcConsumable && (r->getAmount()<amount || amount==-1)){
amount= r->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; i<count; ++i){
unit= aiInterface->getOnSightUnit(i);
if(!aiInterface->isAlly(unit) && unit->isAlive()){
pos= unit->getPos();
field= unit->getCurrField();
if(pos.dist(aiInterface->getHomeLocation())<radius){
aiInterface->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<int> units;
*unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++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<int> units;
*unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++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; currRadius<maxBuildRadius; ++currRadius){
for(int i=searchPos.x-currRadius; i<searchPos.x+currRadius; ++i){
for(int j=searchPos.y-currRadius; j<searchPos.y+currRadius; ++j){
outPos= Vec2i(i, j);
if(aiInterface->isFreeCells(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)<villageRadius){
return;
}
}
//add expansion
expansionPositions.push_front(pos);
//remove expansion if queue is list is full
if(expansionPositions.size()>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; i<aiInterface->getMyUnitCount(); ++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(minWarriors<maxMinWarriors){
minWarriors+= 3;
}
aiInterface->printLog(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

189
source/glest_game/ai/ai.h Normal file
View File

@ -0,0 +1,189 @@
// ==============================================================
// 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
// ==============================================================
#ifndef _GLEST_GAME_AI_H_
#define _GLEST_GAME_AI_H_
#include <vector>
#include <list>
#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<AiRule*> AiRules;
typedef list<const Task*> Tasks;
typedef deque<Vec2i> 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

View File

@ -0,0 +1,238 @@
// ==============================================================
// 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 "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; i<world->getFactionCount(); ++i){
for(int j=0; j<world->getFaction(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; i<world->getFactionCount(); ++i){
for(int j=0; j<world->getFaction(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; i<map->getW(); ++i){
for(int j=0; j<map->getH(); ++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(tmpDist<nearestDist){
anyResource= true;
nearestDist= tmpDist;
resultPos= Vec2i(i, j);
}
}
}
}
}
return anyResource;
}
bool AiInterface::isAlly(const Unit *unit) const{
return world->getFaction(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

View File

@ -0,0 +1,93 @@
// ==============================================================
// 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
// ==============================================================
#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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,314 @@
// ==============================================================
// 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_AIRULE_H_
#define _GLEST_GAME_AIRULE_H_
#include <string>
#include "vec.h"
#include "skill_type.h"
using std::string;
using Shared::Graphics::Vec2i;
namespace Glest{ namespace Game{
class Ai;
class Unit;
class UnitType;
class ProduceTask;
class BuildTask;
class UpgradeTask;
class ResourceType;
// =====================================================
// class AiRule
//
/// An action that the AI will perform periodically
/// if the test succeeds
// =====================================================
class AiRule{
protected:
Ai *ai;
public:
AiRule(Ai *ai);
virtual ~AiRule() {}
virtual int getTestInterval() const= 0; //in milliseconds
virtual string getName() const= 0;
virtual bool test()= 0;
virtual void execute()= 0;
};
// =====================================================
// class AiRuleWorkerHarvest
// =====================================================
class AiRuleWorkerHarvest: public AiRule{
private:
int stoppedWorkerIndex;
public:
AiRuleWorkerHarvest(Ai *ai);
virtual int getTestInterval() const {return 2000;}
virtual string getName() const {return "Worker stopped => Order worker to harvest";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleRefreshHarvester
// =====================================================
class AiRuleRefreshHarvester: public AiRule{
private:
int workerIndex;
public:
AiRuleRefreshHarvester(Ai *ai);
virtual int getTestInterval() const {return 20000;}
virtual string getName() const {return "Worker reasigned to needed resource";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleScoutPatrol
// =====================================================
class AiRuleScoutPatrol: public AiRule{
public:
AiRuleScoutPatrol(Ai *ai);
virtual int getTestInterval() const {return 10000;}
virtual string getName() const {return "Base is stable => Send scout patrol";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleRepair
// =====================================================
class AiRuleRepair: public AiRule{
private:
int damagedUnitIndex;
public:
AiRuleRepair(Ai *ai);
virtual int getTestInterval() const {return 10000;}
virtual string getName() const {return "Building Damaged => Repair";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleReturnBase
// =====================================================
class AiRuleReturnBase: public AiRule{
private:
int stoppedUnitIndex;
public:
AiRuleReturnBase(Ai *ai);
virtual int getTestInterval() const {return 5000;}
virtual string getName() const {return "Stopped unit => Order return base";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleMassiveAttack
// =====================================================
class AiRuleMassiveAttack: public AiRule{
private:
static const int baseRadius= 25;
private:
Vec2i attackPos;
Field field;
bool ultraAttack;
public:
AiRuleMassiveAttack(Ai *ai);
virtual int getTestInterval() const {return 1000;}
virtual string getName() const {return "Unit under attack => Order massive attack";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleAddTasks
// =====================================================
class AiRuleAddTasks: public AiRule{
public:
AiRuleAddTasks(Ai *ai);
virtual int getTestInterval() const {return 5000;}
virtual string getName() const {return "Tasks empty => Add tasks";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleBuildOneFarm
// =====================================================
class AiRuleBuildOneFarm: public AiRule{
private:
const UnitType *farm;
public:
AiRuleBuildOneFarm(Ai *ai);
virtual int getTestInterval() const {return 10000;}
virtual string getName() const {return "No farms => Build one";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleProduceResourceProducer
// =====================================================
class AiRuleProduceResourceProducer: public AiRule{
private:
static const int minStaticResources= 20;
static const int longInterval= 60000;
static const int shortInterval= 5000;
const ResourceType *rt;
int interval;
public:
AiRuleProduceResourceProducer(Ai *ai);
virtual int getTestInterval() const {return interval;}
virtual string getName() const {return "No resources => Build Resource Producer";}
virtual bool test();
virtual void execute();
};
// =====================================================
// class AiRuleProduce
// =====================================================
class AiRuleProduce: public AiRule{
private:
const ProduceTask *produceTask;
public:
AiRuleProduce(Ai *ai);
virtual int getTestInterval() const {return 2000;}
virtual string getName() const {return "Performing produce task";}
virtual bool test();
virtual void execute();
private:
void produceGeneric(const ProduceTask *pt);
void produceSpecific(const ProduceTask *pt);
};
// =====================================================
// class AiRuleBuild
// =====================================================
class AiRuleBuild: public AiRule{
private:
const BuildTask *buildTask;
public:
AiRuleBuild(Ai *ai);
virtual int getTestInterval() const {return 2000;}
virtual string getName() const {return "Performing build task";}
virtual bool test();
virtual void execute();
private:
void buildGeneric(const BuildTask *bt);
void buildSpecific(const BuildTask *bt);
void buildBestBuilding(const vector<const UnitType*> &buildings);
bool isDefensive(const UnitType *building);
bool isResourceProducer(const UnitType *building);
bool isWarriorProducer(const UnitType *building);
};
// =====================================================
// class AiRuleUpgrade
// =====================================================
class AiRuleUpgrade: public AiRule{
private:
const UpgradeTask *upgradeTask;
public:
AiRuleUpgrade(Ai *ai);
virtual int getTestInterval() const {return 2000;}
virtual string getName() const {return "Performing upgrade task";}
virtual bool test();
virtual void execute();
private:
void upgradeSpecific(const UpgradeTask *upgt);
void upgradeGeneric(const UpgradeTask *upgt);
};
// =====================================================
// class AiRuleExpand
// =====================================================
class AiRuleExpand: public AiRule{
private:
static const int expandDistance= 30;
private:
Vec2i expandPos;
const UnitType *storeType;
public:
AiRuleExpand(Ai *ai);
virtual int getTestInterval() const {return 30000;}
virtual string getName() const {return "Expanding";}
virtual bool test();
virtual void execute();
};
}}//end namespace
#endif

View File

@ -0,0 +1,304 @@
// ==============================================================
// 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 "path_finder.h"
#include <algorithm>
#include <cassert>
#include "config.h"
#include "map.h"
#include "unit.h"
#include "unit_type.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Graphics;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class PathFinder
// =====================================================
// ===================== PUBLIC ========================
const int PathFinder::maxFreeSearchRadius= 10;
const int PathFinder::pathFindNodesMax= 400;
const int PathFinder::pathFindRefresh= 10;
PathFinder::PathFinder(){
nodePool= NULL;
}
PathFinder::PathFinder(const Map *map){
init(map);
nodePool= NULL;
}
void PathFinder::init(const Map *map){
nodePool= new Node[pathFindNodesMax];
this->map= map;
}
PathFinder::~PathFinder(){
delete [] nodePool;
}
PathFinder::TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos){
//route cache
UnitPath *path= unit->getPath();
if(finalPos==unit->getPos()){
//if arrived
unit->setCurrSkill(scStop);
return tsArrived;
}
else if(!path->isEmpty()){
//route cache
Vec2i pos= path->pop();
if(map->canMove(unit, unit->getPos(), pos)){
unit->setTargetPos(pos);
return tsOnTheWay;
}
}
//route cache miss
TravelState ts= aStar(unit, finalPos);
//post actions
switch(ts){
case tsBlocked:
case tsArrived:
unit->setCurrSkill(scStop);
break;
case tsOnTheWay:
Vec2i pos= path->pop();
if(map->canMove(unit, unit->getPos(), pos)){
unit->setTargetPos(pos);
}
else{
unit->setCurrSkill(scStop);
return tsBlocked;
}
break;
}
return ts;
}
// ==================== PRIVATE ====================
//route a unit using A* algorithm
PathFinder::TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){
nodePoolCount= 0;
const Vec2i finalPos= computeNearestFreePos(unit, targetPos);
//if arrived
if(finalPos==unit->getPos()){
return tsArrived;
}
//path find algorithm
//a) push starting pos into openNodes
Node *firstNode= newNode();
assert(firstNode!=NULL);;
firstNode->next= NULL;
firstNode->prev= NULL;
firstNode->pos= unit->getPos();
firstNode->heuristic= heuristic(unit->getPos(), finalPos);
firstNode->exploredCell= true;
openNodes.push_back(firstNode);
//b) loop
bool pathFound= true;
bool nodeLimitReached= false;
Node *node= NULL;
while(!nodeLimitReached){
//b1) is open nodes is empty => failed to find the path
if(openNodes.empty()){
pathFound= false;
break;
}
//b2) get the minimum heuristic node
Nodes::iterator it = minHeuristic();
node= *it;
//b3) if minHeuristic is the finalNode, or the path is no more explored => path was found
if(node->pos==finalPos || !node->exploredCell){
pathFound= true;
break;
}
//b4) move this node from closedNodes to openNodes
//add all succesors that are not in closedNodes or openNodes to openNodes
closedNodes.push_back(node);
openNodes.erase(it);
for(int i=-1; i<=1 && !nodeLimitReached; ++i){
for(int j=-1; j<=1 && !nodeLimitReached; ++j){
Vec2i sucPos= node->pos + Vec2i(i, j);
if(!openPos(sucPos) && map->aproxCanMove(unit, node->pos, sucPos)){
//if node is not open and canMove then generate another node
Node *sucNode= newNode();
if(sucNode!=NULL){
sucNode->pos= sucPos;
sucNode->heuristic= heuristic(sucNode->pos, finalPos);
sucNode->prev= node;
sucNode->next= NULL;
sucNode->exploredCell= map->getSurfaceCell(Map::toSurfCoords(sucPos))->isExplored(unit->getTeam());
openNodes.push_back(sucNode);
}
else{
nodeLimitReached= true;
}
}
}
}
}//while
Node *lastNode= node;
//if consumed all nodes find best node (to avoid strage behaviour)
if(nodeLimitReached){
for(Nodes::iterator it= closedNodes.begin(); it!=closedNodes.end(); ++it){
if((*it)->heuristic < lastNode->heuristic){
lastNode= *it;
}
}
}
//check results of path finding
TravelState ts;
UnitPath *path= unit->getPath();
if(pathFound==false || lastNode==firstNode){
//blocked
ts= tsBlocked;
path->incBlockCount();
}
else {
//on the way
ts= tsOnTheWay;
//build next pointers
Node *currNode= lastNode;
while(currNode->prev!=NULL){
currNode->prev->next= currNode;
currNode= currNode->prev;
}
//store path
path->clear();
currNode= firstNode;
for(int i=0; currNode->next!=NULL && i<pathFindRefresh; currNode= currNode->next, i++){
path->push(currNode->next->pos);
}
}
//clean nodes
openNodes.clear();
closedNodes.clear();
return ts;
}
PathFinder::Node *PathFinder::newNode(){
if(nodePoolCount<pathFindNodesMax){
Node *node= &nodePool[nodePoolCount];
nodePoolCount++;
return node;
}
return NULL;
}
Vec2i PathFinder::computeNearestFreePos(const Unit *unit, const Vec2i &finalPos){
//unit data
Vec2i unitPos= unit->getPos();
int size= unit->getType()->getSize();
Field field= unit->getCurrField();
int teamIndex= unit->getTeam();
//if finalPos is free return it
if(map->isAproxFreeCells(finalPos, size, field, teamIndex)){
return finalPos;
}
//find nearest pos
Vec2i nearestPos= unitPos;
float nearestDist= unitPos.dist(finalPos);
for(int i= -maxFreeSearchRadius; i<=maxFreeSearchRadius; ++i){
for(int j= -maxFreeSearchRadius; j<=maxFreeSearchRadius; ++j){
Vec2i currPos= finalPos + Vec2i(i, j);
if(map->isAproxFreeCells(currPos, size, field, teamIndex)){
float dist= currPos.dist(finalPos);
//if nearer from finalPos
if(dist<nearestDist){
nearestPos= currPos;
nearestDist= dist;
}
//if the distance is the same compare distance to unit
else if(dist==nearestDist){
if(currPos.dist(unitPos)<nearestPos.dist(unitPos)){
nearestPos= currPos;
}
}
}
}
}
return nearestPos;
}
float PathFinder::heuristic(const Vec2i &pos, const Vec2i &finalPos){
return pos.dist(finalPos);
}
//returns an iterator to the lowest heuristic node
PathFinder::Nodes::iterator PathFinder::minHeuristic(){
Nodes::iterator minNodeIt= openNodes.begin();
assert(!openNodes.empty());
for(Nodes::iterator it= openNodes.begin(); it!=openNodes.end(); ++it){
if((*it)->heuristic < (*minNodeIt)->heuristic){
minNodeIt= it;
}
}
return minNodeIt;
}
bool PathFinder::openPos(const Vec2i &sucPos){
for(Nodes::reverse_iterator it= closedNodes.rbegin(); it!=closedNodes.rend(); ++it){
if(sucPos==(*it)->pos){
return true;
}
}
//use reverse iterator to find a node faster
for(Nodes::reverse_iterator it= openNodes.rbegin(); it!=openNodes.rend(); ++it){
if(sucPos==(*it)->pos){
return true;
}
}
return false;
}
}} //end namespace

View File

@ -0,0 +1,79 @@
// ==============================================================
// 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_PATHFINDER_H_
#define _GLEST_GAME_PATHFINDER_H_
#include "vec.h"
#include <vector>
using std::vector;
using Shared::Graphics::Vec2i;
namespace Glest{ namespace Game{
class Map;
class Unit;
// =====================================================
// class PathFinder
//
/// Finds paths for units using a modification of the A* algorithm
// =====================================================
class PathFinder{
public:
enum TravelState{
tsArrived,
tsOnTheWay,
tsBlocked
};
struct Node{
Vec2i pos;
Node *next;
Node *prev;
float heuristic;
bool exploredCell;
};
typedef vector<Node*> Nodes;
public:
static const int maxFreeSearchRadius;
static const int pathFindNodesMax;
static const int pathFindRefresh;
private:
Nodes openNodes;
Nodes closedNodes;
Node *nodePool;
int nodePoolCount;
const Map *map;
public:
PathFinder();
PathFinder(const Map *map);
~PathFinder();
void init(const Map *map);
TravelState findPath(Unit *unit, const Vec2i &finalPos);
private:
TravelState aStar(Unit *unit, const Vec2i &finalPos);
Node *newNode();
Vec2i computeNearestFreePos(const Unit *unit, const Vec2i &targetPos);
float heuristic(const Vec2i &pos, const Vec2i &finalPos);
Nodes::iterator minHeuristic();
bool openPos(const Vec2i &sucPos);
};
}}//end namespace
#endif

View File

@ -0,0 +1,82 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2009 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 "auto_test.h"
#include "program.h"
#include "main_menu.h"
#include "menu_state_new_game.h"
#include "menu_state_scenario.h"
#include "game.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class AutoTest
// =====================================================
const time_t AutoTest::invalidTime = -1;
const time_t AutoTest::gameTime = 60*20;
// ===================== PUBLIC ========================
AutoTest::AutoTest(){
gameStartTime = invalidTime;
random.init(time(NULL));
}
AutoTest & AutoTest::getInstance(){
static AutoTest autoTest;
return autoTest;
}
void AutoTest::updateIntro(Program *program){
program->setState(new MainMenu(program));
}
void AutoTest::updateRoot(Program *program, MainMenu *mainMenu){
mainMenu->setState(new MenuStateNewGame(program, mainMenu));
}
void AutoTest::updateNewGame(Program *program, MainMenu *mainMenu){
mainMenu->setState(new MenuStateScenario(program, mainMenu, "scenarios"));
}
void AutoTest::updateScenario(MenuStateScenario *menuStateScenario){
gameStartTime = invalidTime;
int scenarioIndex = random.randRange(0, menuStateScenario->getScenarioCount()-1);
menuStateScenario->setScenario(scenarioIndex);
menuStateScenario->launchGame();
}
void AutoTest::updateGame(Game *game){
// record start time
if(gameStartTime==invalidTime)
{
gameStartTime = time(NULL);
}
// quit if we've espend enough time in the game
if(time(NULL)-gameStartTime>gameTime){
game->quitGame();
}
}
void AutoTest::updateBattleEnd(Program *program){
program->setState(new MainMenu(program));
}
}}//end namespace

View File

@ -0,0 +1,57 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2009 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 _SHARED_UTIL_AUTO_TEST_H_
#define _SHARED_UTIL_AUTO_TEST_H_
#include <ctime>
#include "random.h"
using Shared::Util::Random;
namespace Glest{ namespace Game{
class Program;
class MainMenu;
class MenuStateScenario;
class Game;
// =====================================================
// class AutoTest
//
/// Interface to write log files
// =====================================================
class AutoTest{
private:
int gameStartTime;
Random random;
private:
static const time_t invalidTime;
static const time_t gameTime;
public:
static AutoTest & getInstance();
AutoTest();
void updateIntro(Program *program);
void updateRoot(Program *program, MainMenu *mainMenu);
void updateNewGame(Program *program, MainMenu *mainMenu);
void updateScenario(MenuStateScenario *menuStateScenario);
void updateGame(Game *game);
void updateBattleEnd(Program *program);
};
}}//end namespace
#endif

View File

@ -0,0 +1,248 @@
// ==============================================================
// 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 "components.h"
#include <cassert>
#include <algorithm>
#include "metrics.h"
#include "core_data.h"
#include "platform_util.h"
#include "leak_dumper.h"
using namespace std;
namespace Glest{ namespace Game{
// =====================================================
// class GraphicComponent
// =====================================================
float GraphicComponent::anim= 0.f;
float GraphicComponent::fade= 0.f;
const float GraphicComponent::animSpeed= 0.02f;
const float GraphicComponent::fadeSpeed= 0.01f;
GraphicComponent::GraphicComponent(){
enabled= true;
}
void GraphicComponent::init(int x, int y, int w, int h){
this->x= x;
this->y= y;
this->w= w;
this->h= h;
font= CoreData::getInstance().getMenuFontNormal();
enabled= true;
}
bool GraphicComponent::mouseMove(int x, int y){
return
x > this->x &&
y > this->y &&
x < this->x + w &&
y < this->y + h;
}
bool GraphicComponent::mouseClick(int x, int y){
return mouseMove(x, y);
}
void GraphicComponent::update(){
fade+= fadeSpeed;
anim+= animSpeed;
if(fade>1.f) fade= 1.f;
if(anim>1.f) anim= 0.f;
}
void GraphicComponent::resetFade(){
fade= 0.f;
}
// =====================================================
// class GraphicLabel
// =====================================================
const int GraphicLabel::defH= 20;
const int GraphicLabel::defW= 70;
void GraphicLabel::init(int x, int y, int w, int h, bool centered){
GraphicComponent::init(x, y, w, h);
this->centered= centered;
}
// =====================================================
// class GraphicButton
// =====================================================
const int GraphicButton::defH= 22;
const int GraphicButton::defW= 90;
void GraphicButton::init(int x, int y, int w, int h){
GraphicComponent::init(x, y, w, h);
lighted= false;
}
bool GraphicButton::mouseMove(int x, int y){
bool b= GraphicComponent::mouseMove(x, y);
lighted= b;
return b;
}
// =====================================================
// class GraphicListBox
// =====================================================
const int GraphicListBox::defH= 22;
const int GraphicListBox::defW= 140;
void GraphicListBox::init(int x, int y, int w, int h){
GraphicComponent::init(x, y, w, h);
graphButton1.init(x, y, 22, h);
graphButton2.init(x+w-22, y, 22, h);
graphButton1.setText("<");
graphButton2.setText(">");
selectedItemIndex=-1;
}
//queryes
void GraphicListBox::pushBackItem(string item){
items.push_back(item);
setSelectedItemIndex(0);
}
void GraphicListBox::setItems(const vector<string> &items){
this->items= items;
setSelectedItemIndex(0);
}
void GraphicListBox::setSelectedItemIndex(int index){
assert(index>=0 && index<items.size());
selectedItemIndex= index;
setText(getSelectedItem());
}
void GraphicListBox::setSelectedItem(string item){
vector<string>::iterator iter;
iter= find(items.begin(), items.end(), item);
if(iter==items.end()){
throw runtime_error("Value not found on list box: "+item);
}
setSelectedItemIndex(iter-items.begin());
}
bool GraphicListBox::mouseMove(int x, int y){
return
graphButton1.mouseMove(x, y) ||
graphButton2.mouseMove(x, y);
}
bool GraphicListBox::mouseClick(int x, int y){
if(!items.empty()){
bool b1= graphButton1.mouseClick(x, y);
bool b2= graphButton2.mouseClick(x, y);
if(b1){
selectedItemIndex--;
if(selectedItemIndex<0){
selectedItemIndex=items.size()-1;
}
}
else if(b2){
selectedItemIndex++;
if(selectedItemIndex>=items.size()){
selectedItemIndex=0;
}
}
setText(getSelectedItem());
return b1 || b2;
}
return false;
}
// =====================================================
// class GraphicMessageBox
// =====================================================
const int GraphicMessageBox::defH= 240;
const int GraphicMessageBox::defW= 350;
void GraphicMessageBox::init(const string &button1Str, const string &button2Str){
init(button1Str);
button1.init(x+(w-GraphicButton::defW)/4, y+25);
button1.setText(button1Str);
button2.init(x+3*(w-GraphicButton::defW)/4, y+25);
button2.setText(button2Str);
buttonCount= 2;
}
void GraphicMessageBox::init(const string &button1Str){
font= CoreData::getInstance().getMenuFontNormal();
h= defH;
w= defW;
const Metrics &metrics= Metrics::getInstance();
x= (metrics.getVirtualW()-w)/2;
y= (metrics.getVirtualH()-h)/2;
button1.init(x+(w-GraphicButton::defW)/2, y+25);
button1.setText(button1Str);
buttonCount= 1;
}
bool GraphicMessageBox::mouseMove(int x, int y){
return button1.mouseMove(x, y) || button2.mouseMove(x, y);
}
bool GraphicMessageBox::mouseClick(int x, int y){
bool b1= button1.mouseClick(x, y);
bool b2= button2.mouseClick(x, y);
if(buttonCount==1){
return b1;
}
else{
return b1 ||b2;
}
}
bool GraphicMessageBox::mouseClick(int x, int y, int &clickedButton){
bool b1= button1.mouseClick(x, y);
bool b2= button2.mouseClick(x, y);
if(buttonCount==1){
clickedButton= 1;
return b1;
}
else{
if(b1){
clickedButton= 1;
return true;
}
else if(b2){
clickedButton= 2;
return true;
}
}
return false;
}
}}//end namespace

View File

@ -0,0 +1,182 @@
// ==============================================================
// 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_GRAPHCOMPONENT_H_
#define _GLEST_GAME_GRAPHCOMPONENT_H_
#include <string>
#include <vector>
#include "font.h"
using std::string;
using std::vector;
using Shared::Graphics::Font2D;
namespace Glest{ namespace Game{
// ===========================================================
// class GraphicComponent
//
// OpenGL renderer GUI components
// ===========================================================
class GraphicComponent{
public:
static const float animSpeed;
static const float fadeSpeed;
protected:
int x, y, w, h;
string text;
const Font2D *font;
bool enabled;
static float anim;
static float fade;
public:
GraphicComponent();
virtual ~GraphicComponent(){}
void init(int x, int y, int w, int h);
int getX() const {return x;}
int getY() const {return y;}
int getW() const {return w;}
int getH() const {return h;}
const string &getText() const {return text;}
const Font2D *getFont() const {return font;}
bool getEnabled() const {return enabled;}
void setX(int x) {this->x= x;}
void setY(int y) {this->y= y;}
void setText(const string &text) {this->text= text;}
void setFont(const Font2D *font) {this->font= font;}
void setEnabled(bool enabled) {this->enabled= enabled;}
virtual bool mouseMove(int x, int y);
virtual bool mouseClick(int x, int y);
static void update();
static void resetFade();
static float getAnim() {return anim;}
static float getFade() {return fade;}
};
// ===========================================================
// class GraphicLabel
// ===========================================================
class GraphicLabel: public GraphicComponent{
public:
static const int defH;
static const int defW;
private:
bool centered;
public:
void init(int x, int y, int w=defW, int h=defH, bool centered= false);
bool getCentered() const {return centered;}
void setCentered(bool centered) {this->centered= centered;}
};
// ===========================================================
// class GraphicButton
// ===========================================================
class GraphicButton: public GraphicComponent{
public:
static const int defH;
static const int defW;
private:
bool lighted;
public:
void init(int x, int y, int w=defW, int h=defH);
bool getLighted() const {return lighted;}
void setLighted(bool lighted) {this->lighted= lighted;}
virtual bool mouseMove(int x, int y);
};
// ===========================================================
// class GraphicListBox
// ===========================================================
class GraphicListBox: public GraphicComponent{
public:
static const int defH;
static const int defW;
private:
GraphicButton graphButton1, graphButton2;
vector<string> items;
int selectedItemIndex;
public:
void init(int x, int y, int w=defW, int h=defH);
int getItemCount() const {return items.size();}
int getSelectedItemIndex() const {return selectedItemIndex;}
string getSelectedItem() const {return items[selectedItemIndex];}
const GraphicButton *getButton1() const {return &graphButton1;}
const GraphicButton *getButton2() const {return &graphButton2;}
void pushBackItem(string item);
void setItems(const vector<string> &items);
void setSelectedItemIndex(int index);
void setSelectedItem(string item);
virtual bool mouseMove(int x, int y);
virtual bool mouseClick(int x, int y);
};
// ===========================================================
// class GraphicMessageBox
// ===========================================================
class GraphicMessageBox: public GraphicComponent{
public:
static const int defH;
static const int defW;
private:
GraphicButton button1;
GraphicButton button2;
int buttonCount;
string header;
public:
void init(const string &button1Str, const string &button2Str);
void init(const string &button1Str);
int getButtonCount() const {return buttonCount;}
const GraphicButton *getButton1() const {return &button1;}
const GraphicButton *getButton2() const {return &button2;}
string getHeader() const {return header;}
void setHeader(string header) {this->header= header;}
virtual bool mouseMove(int x, int y);
virtual bool mouseClick(int x, int y);
bool mouseClick(int x, int y, int &clickedButton);
};
}}//end namespace
#endif

View File

@ -0,0 +1,104 @@
// ==============================================================
// 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 "game_util.h"
#include "util.h"
#include "lang.h"
#include "game_constants.h"
#include "config.h"
#include "leak_dumper.h"
using namespace Shared::Util;
namespace Glest{ namespace Game{
const string mailString= "contact_game@glest.org";
const string glestVersionString= "v3.2.3-beta3";
string getCrashDumpFileName(){
return "glest"+glestVersionString+".dmp";
}
string getNetworkVersionString(){
return glestVersionString + " - " + string(__DATE__) + " - " + string(__TIME__);
}
string getAboutString1(int i){
switch(i){
case 0: return "Glest " + glestVersionString + " (" + "Shared Library " + sharedLibVersionString + ")";
case 1: return "Built: " + string(__DATE__);
case 2: return "Copyright 2001-2009 The Glest Team";
}
return "";
}
string getAboutString2(int i){
switch(i){
case 0: return "Web: http://glest.org";
case 1: return "Mail: " + mailString;
case 2: return "Irc: irc://irc.freenode.net/glest";
}
return "";
}
string getTeammateName(int i){
switch(i){
case 0: return "Marti<EFBFBD>o Figueroa";
case 1: return "Jos<EFBFBD> Luis Gonz<6E>lez";
case 2: return "Tucho Fern<72>ndez";
case 3: return "Jos<EFBFBD> Zanni";
case 4: return "F<EFBFBD>lix Men<65>ndez";
case 5: return "Marcos Caruncho";
case 6: return "Matthias Braun";
}
return "";
}
string getTeammateRole(int i){
Lang &l= Lang::getInstance();
switch(i){
case 0: return l.get("Programming");
case 1: return l.get("SoundAndMusic");
case 2: return l.get("3dAnd2dArt");
case 3: return l.get("2dArtAndWeb");
case 4: return l.get("Animation");
case 5: return l.get("3dArt");
case 6: return l.get("LinuxPort");
}
return "";
}
string formatString(const string &str){
string outStr = str;
if(!outStr.empty()){
outStr[0]= toupper(outStr[0]);
}
bool afterSeparator= false;
for(int i= 0; i<str.size(); ++i){
if(outStr[i]=='_'){
outStr[i]= ' ';
}
else if(afterSeparator){
outStr[i]= toupper(outStr[i]);
afterSeparator= false;
}
if(outStr[i]=='\n' || outStr[i]=='(' || outStr[i]==' '){
afterSeparator= true;
}
}
return outStr;
}
}}//end namespace

View File

@ -0,0 +1,40 @@
// ==============================================================
// 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_GAMEUTIL_H_
#define _GLEST_GAME_GAMEUTIL_H_
#include <string>
#include <vector>
#include "util.h"
using std::string;
using Shared::Util::sharedLibVersionString;
namespace Glest{ namespace Game{
extern const string mailString;
extern const string glestVersionString;
extern const string networkVersionString;
string getCrashDumpFileName();
string getNetworkVersionString();
string getAboutString1(int i);
string getAboutString2(int i);
string getTeammateName(int i);
string getTeammateRole(int i);
string formatString(const string &str);
}}//end namespace
#endif

View File

@ -0,0 +1,94 @@
// ==============================================================
// 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 "logger.h"
#include "util.h"
#include "renderer.h"
#include "core_data.h"
#include "metrics.h"
#include "lang.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class Logger
// =====================================================
const int Logger::logLineCount= 15;
// ===================== PUBLIC ========================
Logger::Logger(){
fileName= "log.txt";
}
Logger & Logger::getInstance(){
static Logger logger;
return logger;
}
void Logger::add(const string &str, bool renderScreen){
FILE *f=fopen(fileName.c_str(), "at+");
if(f!=NULL){
fprintf(f, "%s\n", str.c_str());
fclose(f);
}
current= str;
if(renderScreen){
renderLoadingScreen();
}
}
void Logger::clear(){
string s="Log file\n";
FILE *f= fopen(fileName.c_str(), "wt+");
if(f==NULL){
throw runtime_error("Error opening log file"+ fileName);
}
fprintf(f, "%s", s.c_str());
fprintf(f, "\n");
fclose(f);
}
// ==================== PRIVATE ====================
void Logger::renderLoadingScreen(){
Renderer &renderer= Renderer::getInstance();
CoreData &coreData= CoreData::getInstance();
const Metrics &metrics= Metrics::getInstance();
renderer.reset2d();
renderer.clearBuffers();
renderer.renderBackground(CoreData::getInstance().getBackgroundTexture());
renderer.renderText(
state, coreData.getMenuFontBig(), Vec3f(1.f),
metrics.getVirtualW()/4, 65*metrics.getVirtualH()/100, false);
renderer.renderText(
current, coreData.getMenuFontNormal(), 1.0f,
metrics.getVirtualW()/4,
62*metrics.getVirtualH()/100, false);
renderer.swapBuffers();
}
}}//end namespace

View File

@ -0,0 +1,60 @@
// ==============================================================
// 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 _SHARED_UTIL_LOGGER_H_
#define _SHARED_UTIL_LOGGER_H_
#include <string>
#include <deque>
using std::string;
using std::deque;
namespace Glest{ namespace Game{
// =====================================================
// class Logger
//
/// Interface to write log files
// =====================================================
class Logger{
private:
static const int logLineCount;
private:
typedef deque<string> Strings;
private:
string fileName;
string state;
string subtitle;
string current;
private:
Logger();
public:
static Logger & getInstance();
void setFile(const string &fileName) {this->fileName= fileName;}
void setState(const string &state) {this->state= state;}
void setSubtitle(const string &subtitle) {this->subtitle= subtitle;}
void add(const string &str, bool renderScreen= false);
void renderLoadingScreen();
void clear();
};
}}//end namespace
#endif

View File

@ -0,0 +1,103 @@
// ==============================================================
// 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 "chat_manager.h"
#include "window.h"
#include "console.h"
#include "network_manager.h"
#include "lang.h"
#include "leak_dumper.h"
using namespace Shared::Platform;
namespace Glest{ namespace Game{
// =====================================================
// class ChatManager
// =====================================================
const int ChatManager::maxTextLenght= 64;
ChatManager::ChatManager(){
console= NULL;
editEnabled= false;
teamMode= false;
thisTeamIndex= -1;
}
void ChatManager::init(Console* console, int thisTeamIndex){
this->console= console;
this->thisTeamIndex= thisTeamIndex;
}
void ChatManager::keyDown(char key){
Lang &lang= Lang::getInstance();
//toggle team mode
if(!editEnabled && key=='H'){
if(teamMode){
teamMode= false;
console->addLine(lang.get("ChatMode") + ": " + lang.get("All"));
}
else{
teamMode= true;
console->addLine(lang.get("ChatMode") + ": " + lang.get("Team"));
}
}
if(key==vkReturn){
if(editEnabled){
GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface();
editEnabled= false;
if(!text.empty()){
console->addLine(gameNetworkInterface->getHostName() + ": " + text);
gameNetworkInterface->sendTextMessage(text, teamMode? thisTeamIndex: -1);
}
}
else{
editEnabled= true;
text.clear();
}
}
else if(key==vkBack){
if(!text.empty()){
text.erase(text.end() -1);
}
}
}
void ChatManager::keyPress(char c){
if(editEnabled && text.size()<maxTextLenght){
//space is the first meaningful code
if(c>=' '){
text+= c;
}
}
}
void ChatManager::updateNetwork(){
GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface();
string text;
string sender;
if(!gameNetworkInterface->getChatText().empty()){
int teamIndex= gameNetworkInterface->getChatTeamIndex();
if(teamIndex==-1 || teamIndex==thisTeamIndex){
console->addLine(gameNetworkInterface->getChatSender()+": "+gameNetworkInterface->getChatText(), true);
}
}
}
}}//end namespace

View File

@ -0,0 +1,53 @@
// ==============================================================
// 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_CHATMANAGER_H_
#define _GLEST_GAME_CHATMANAGER_H_
#include <string>
using std::string;
namespace Glest{ namespace Game{
class Console;
// =====================================================
// class ChatManager
// =====================================================
class ChatManager{
private:
static const int maxTextLenght;
private:
bool editEnabled;
bool teamMode;
Console* console;
string text;
int thisTeamIndex;
public:
ChatManager();
void init(Console* console, int thisTeamIndex);
void keyDown(char key);
void keyPress(char c);
void updateNetwork();
bool getEditEnabled() const {return editEnabled;}
bool getTeamMode() const {return teamMode;}
string getText() const {return text;}
};
}}//end namespace
#endif

View File

@ -0,0 +1,310 @@
// ==============================================================
// 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 "commander.h"
#include "world.h"
#include "unit.h"
#include "conversion.h"
#include "upgrade.h"
#include "command.h"
#include "command_type.h"
#include "network_manager.h"
#include "console.h"
#include "config.h"
#include "platform_util.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
using namespace Shared::Util;
using namespace Shared::Platform;
namespace Glest{ namespace Game{
// =====================================================
// class Commander
// =====================================================
// ===================== PUBLIC ========================
void Commander::init(World *world){
this->world= world;
}
CommandResult Commander::tryGiveCommand(const Unit* unit, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType) const{
NetworkCommand networkCommand(nctGiveCommand, unit->getId(), commandType->getId(), pos, unitType->getId());
return pushNetworkCommand(&networkCommand);
}
CommandResult Commander::tryGiveCommand(const Selection *selection, CommandClass commandClass, const Vec2i &pos, const Unit *targetUnit) const{
if(!selection->isEmpty()){
Vec2i refPos, currPos;
CommandResultContainer results;
refPos= computeRefPos(selection);
//give orders to all selected units
for(int i=0; i<selection->getCount(); ++i){
const Unit *unit= selection->getUnit(i);
const CommandType *ct= unit->getType()->getFirstCtOfClass(commandClass);
if(ct!=NULL){
int targetId= targetUnit==NULL? Unit::invalidId: targetUnit->getId();
int unitId= selection->getUnit(i)->getId();
Vec2i currPos= computeDestPos(refPos, selection->getUnit(i)->getPos(), pos);
NetworkCommand networkCommand(nctGiveCommand, unitId, ct->getId(), currPos, -1, targetId);
//every unit is ordered to a different pos
CommandResult result= pushNetworkCommand(&networkCommand);
results.push_back(result);
}
else{
results.push_back(crFailUndefined);
}
}
return computeResult(results);
}
else{
return crFailUndefined;
}
}
CommandResult Commander::tryGiveCommand(const Selection *selection, const CommandType *commandType, const Vec2i &pos, const Unit *targetUnit) const{
if(!selection->isEmpty() && commandType!=NULL){
Vec2i refPos;
CommandResultContainer results;
refPos= computeRefPos(selection);
//give orders to all selected units
for(int i=0; i<selection->getCount(); ++i){
int targetId= targetUnit==NULL? Unit::invalidId: targetUnit->getId();
int unitId= selection->getUnit(i)->getId();
Vec2i currPos= computeDestPos(refPos, selection->getUnit(i)->getPos(), pos);
NetworkCommand networkCommand(nctGiveCommand, unitId, commandType->getId(), currPos, -1, targetId);
//every unit is ordered to a different position
CommandResult result= pushNetworkCommand(&networkCommand);
results.push_back(result);
}
return computeResult(results);
}
else{
return crFailUndefined;
}
}
//auto command
CommandResult Commander::tryGiveCommand(const Selection *selection, const Vec2i &pos, const Unit *targetUnit) const{
if(!selection->isEmpty()){
Vec2i refPos, currPos;
CommandResultContainer results;
//give orders to all selected units
refPos= computeRefPos(selection);
for(int i=0; i<selection->getCount(); ++i){
//every unit is ordered to a different pos
currPos= computeDestPos(refPos, selection->getUnit(i)->getPos(), pos);
//get command type
const CommandType *commandType= selection->getUnit(i)->computeCommandType(pos, targetUnit);
//give commands
if(commandType!=NULL){
int targetId= targetUnit==NULL? Unit::invalidId: targetUnit->getId();
int unitId= selection->getUnit(i)->getId();
NetworkCommand networkCommand(nctGiveCommand, unitId, commandType->getId(), currPos, -1, targetId);
CommandResult result= pushNetworkCommand(&networkCommand);
results.push_back(result);
}
else{
results.push_back(crFailUndefined);
}
}
return computeResult(results);
}
else{
return crFailUndefined;
}
}
CommandResult Commander::tryCancelCommand(const Selection *selection) const{
for(int i=0; i<selection->getCount(); ++i){
NetworkCommand command(nctCancelCommand, selection->getUnit(i)->getId());
pushNetworkCommand(&command);
}
return crSuccess;
}
void Commander::trySetMeetingPoint(const Unit* unit, const Vec2i &pos)const{
NetworkCommand command(nctSetMeetingPoint, unit->getId(), -1, pos);
pushNetworkCommand(&command);
}
// ==================== PRIVATE ====================
Vec2i Commander::computeRefPos(const Selection *selection) const{
Vec2i total= Vec2i(0);
for(int i=0; i<selection->getCount(); ++i){
total= total+selection->getUnit(i)->getPos();
}
return Vec2i(total.x/ selection->getCount(), total.y/ selection->getCount());
}
Vec2i Commander::computeDestPos(const Vec2i &refUnitPos, const Vec2i &unitPos, const Vec2i &commandPos) const{
Vec2i pos;
Vec2i posDiff= unitPos-refUnitPos;
if(abs(posDiff.x)>=3){
posDiff.x= posDiff.x % 3;
}
if(abs(posDiff.y)>=3){
posDiff.y= posDiff.y % 3;
}
pos= commandPos+posDiff;
world->getMap()->clampPos(pos);
return pos;
}
CommandResult Commander::computeResult(const CommandResultContainer &results) const{
switch(results.size()){
case 0:
return crFailUndefined;
case 1:
return results.front();
default:
for(int i=0; i<results.size(); ++i){
if(results[i]!=crSuccess){
return crSomeFailed;
}
}
return crSuccess;
}
}
CommandResult Commander::pushNetworkCommand(const NetworkCommand* networkCommand) const{
GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface();
const Unit* unit= world->findUnitById(networkCommand->getUnitId());
CommandResult cr= crSuccess;
//validate unit
if(unit==NULL){
throw runtime_error("Command refers to non existant unit. Game out of synch.");
}
//add the command to the interface
gameNetworkInterface->requestCommand(networkCommand);
//calculate the result of the command
if(networkCommand->getNetworkCommandType()==nctGiveCommand){
Command* command= buildCommand(networkCommand);
cr= unit->checkCommand(command);
delete command;
}
return cr;
}
void Commander::updateNetwork(){
NetworkManager &networkManager= NetworkManager::getInstance();
//chech that this is a keyframe
if( !networkManager.isNetworkGame() || (world->getFrameCount() % GameConstants::networkFramePeriod)==0){
GameNetworkInterface *gameNetworkInterface= NetworkManager::getInstance().getGameNetworkInterface();
//update the keyframe
gameNetworkInterface->updateKeyframe(world->getFrameCount());
//give pending commands
for(int i= 0; i < gameNetworkInterface->getPendingCommandCount(); ++i){
giveNetworkCommand(gameNetworkInterface->getPendingCommand(i));
}
gameNetworkInterface->clearPendingCommands();
}
}
void Commander::giveNetworkCommand(const NetworkCommand* networkCommand) const{
Unit* unit= world->findUnitById(networkCommand->getUnitId());
//exec ute command, if unit is still alive
if(unit!=NULL){
switch(networkCommand->getNetworkCommandType()){
case nctGiveCommand:{
assert(networkCommand->getCommandTypeId()!=CommandType::invalidId);
Command* command= buildCommand(networkCommand);
unit->giveCommand(command);
}
break;
case nctCancelCommand:
unit->cancelCommand();
break;
case nctSetMeetingPoint:
unit->setMeetingPos(networkCommand->getPosition());
break;
default:
assert(false);
}
}
}
Command* Commander::buildCommand(const NetworkCommand* networkCommand) const{
assert(networkCommand->getNetworkCommandType()==nctGiveCommand);
Unit* target= NULL;
const CommandType* ct= NULL;
const Unit* unit= world->findUnitById(networkCommand->getUnitId());
const UnitType* unitType= world->findUnitTypeById(unit->getFaction()->getType(), networkCommand->getUnitTypeId());
//validate unit
if(unit==NULL){
throw runtime_error("Can not find unit with id: " + intToStr(networkCommand->getUnitId()) + ". Game out of synch.");
}
ct= unit->getType()->findCommandTypeById(networkCommand->getCommandTypeId());
//validate command type
if(ct==NULL){
throw runtime_error("Can not find command type with id: " + intToStr(networkCommand->getCommandTypeId()) + " in unit: " + unit->getType()->getName() + ". Game out of synch.");
}
//get target, the target might be dead due to lag, cope with it
if(networkCommand->getTargetId()!=Unit::invalidId){
target= world->findUnitById(networkCommand->getTargetId());
}
//create command
Command *command= NULL;
if(unitType!=NULL){
command= new Command(ct, networkCommand->getPosition(), unitType);
}
else if(target==NULL){
command= new Command(ct, networkCommand->getPosition());
}
else{
command= new Command(ct, target);
}
//issue command
return command;
}
}}//end namespace

View File

@ -0,0 +1,68 @@
// ==============================================================
// 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_COMMANDER_H_
#define _GLEST_GAME_COMMANDER_H_
#include <vector>
#include "vec.h"
#include "selection.h"
#include "command_type.h"
using std::vector;
namespace Glest{ namespace Game{
using Shared::Graphics::Vec2i;
class World;
class Unit;
class Command;
class CommandType;
class NetworkCommand;
// =====================================================
// class Commander
//
/// Gives commands to the units
// =====================================================
class Commander{
private:
typedef vector<CommandResult> CommandResultContainer;
private:
World *world;
public:
void init(World *world);
void updateNetwork();
CommandResult tryGiveCommand(const Unit* unit, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType) const;
CommandResult tryGiveCommand(const Selection *selection, CommandClass commandClass, const Vec2i &pos= Vec2i(0), const Unit *targetUnit= NULL) const;
CommandResult tryGiveCommand(const Selection *selection, const CommandType *commandType, const Vec2i &pos= Vec2i(0), const Unit *targetUnit= NULL) const;
CommandResult tryGiveCommand(const Selection *selection, const Vec2i &pos, const Unit *targetUnit= NULL) const;
CommandResult tryCancelCommand(const Selection *selection) const;
void trySetMeetingPoint(const Unit* unit, const Vec2i &pos) const;
CommandResult pushNetworkCommand(const NetworkCommand* networkCommand) const;
private:
Vec2i computeRefPos(const Selection *selection) const;
Vec2i computeDestPos(const Vec2i &refUnitPos, const Vec2i &unitPos, const Vec2i &commandPos) const;
CommandResult computeResult(const CommandResultContainer &results) const;
void giveNetworkCommand(const NetworkCommand* networkCommand) const;
Command* buildCommand(const NetworkCommand* networkCommand) const;
};
}} //end namespace
#endif

View File

@ -0,0 +1,65 @@
// ==============================================================
// 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 "console.h"
#include "lang.h"
#include "config.h"
#include "program.h"
#include "game_constants.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class Console
// =====================================================
Console::Console(){
//config
maxLines= Config::getInstance().getInt("ConsoleMaxLines");
timeout= Config::getInstance().getInt("ConsoleTimeout");
timeElapsed= 0.0f;
}
void Console::addStdMessage(const string &s){
addLine(Lang::getInstance().get(s));
}
void Console::addLine(string line, bool playSound){
if(playSound){
SoundRenderer::getInstance().playFx(CoreData::getInstance().getClickSoundA());
}
lines.insert(lines.begin(), StringTimePair(line, timeElapsed));
if(lines.size()>maxLines){
lines.pop_back();
}
}
void Console::update(){
timeElapsed+= 1.f/GameConstants::updateFps;
if(!lines.empty()){
if(lines.back().second<timeElapsed-timeout){
lines.pop_back();
}
}
}
bool Console::isEmpty(){
return lines.empty();
}
}}//end namespace

View File

@ -0,0 +1,66 @@
// ==============================================================
// 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_CONSOLE_H_
#define _GLEST_GAME_CONSOLE_H_
#include <utility>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::pair;
namespace Glest{ namespace Game{
// =====================================================
// class Console
//
// In-game console that shows various types of messages
// =====================================================
class Console{
private:
static const int consoleLines= 5;
public:
typedef pair<string, float> StringTimePair;
typedef vector<StringTimePair> Lines;
typedef Lines::const_iterator LineIterator;
private:
float timeElapsed;
Lines lines;
//this should be deleted from here someday
bool won, lost;
//config
int maxLines;
float timeout;
public:
Console();
int getLineCount() const {return lines.size();}
string getLine(int i) const {return lines[i].first;}
void addStdMessage(const string &s);
void addLine(string line, bool playSound= false);
void update();
bool isEmpty();
};
}}//end namespace
#endif

View File

@ -0,0 +1,883 @@
// ==============================================================
// 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 "game.h"
#include "config.h"
#include "renderer.h"
#include "particle_renderer.h"
#include "commander.h"
#include "battle_end.h"
#include "sound_renderer.h"
#include "profiler.h"
#include "core_data.h"
#include "metrics.h"
#include "faction.h"
#include "network_manager.h"
#include "checksum.h"
#include "auto_test.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
using namespace Shared::Util;
using namespace Shared::Platform;
namespace Glest{ namespace Game{
// =====================================================
// class Game
// =====================================================
// ===================== PUBLIC ========================
Game::Game(Program *program, const GameSettings *gameSettings):
ProgramState(program)
{
this->gameSettings= *gameSettings;
mouseX=0;
mouseY=0;
mouse2d= 0;
loadingText="";
weatherParticleSystem= NULL;
updateFps=0;
renderFps=0;
lastUpdateFps=0;
lastRenderFps=0;
paused= false;
gameOver= false;
renderNetworkStatus= false;
speed= sNormal;
}
Game::~Game(){
Logger &logger= Logger::getInstance();
Renderer &renderer= Renderer::getInstance();
logger.setState(Lang::getInstance().get("Deleting"));
logger.add("Game", true);
renderer.endGame();
SoundRenderer::getInstance().stopAllSounds();
deleteValues(aiInterfaces.begin(), aiInterfaces.end());
gui.end(); //selection must be cleared before deleting units
world.end(); //must die before selection because of referencers
}
// ==================== init and load ====================
void Game::load(){
Logger &logger= Logger::getInstance();
string mapName= gameSettings.getMap();
string tilesetName= gameSettings.getTileset();
string techName= gameSettings.getTech();
string scenarioName= gameSettings.getScenario();
logger.setState(Lang::getInstance().get("Loading"));
if(scenarioName.empty()){
logger.setSubtitle(formatString(mapName)+" - "+formatString(tilesetName)+" - "+formatString(techName));
}
else{
logger.setSubtitle(formatString(scenarioName));
}
//tileset
world.loadTileset("tilesets/"+tilesetName, &checksum);
set<string> factions;
for ( int i=0; i < gameSettings.getFactionCount(); ++i ) {
factions.insert(gameSettings.getFactionTypeName(i));
}
//tech, load before map because of resources
world.loadTech("techs/"+techName, factions, &checksum);
//map
world.loadMap(Map::getMapPath(mapName), &checksum);
//scenario
if(!scenarioName.empty()){
Lang::getInstance().loadScenarioStrings(gameSettings.getScenarioDir(), scenarioName);
world.loadScenario(Scenario::getScenarioPath(gameSettings.getScenarioDir(), scenarioName), &checksum);
}
}
void Game::init(){
Lang &lang= Lang::getInstance();
Logger &logger= Logger::getInstance();
CoreData &coreData= CoreData::getInstance();
Renderer &renderer= Renderer::getInstance();
Map *map= world.getMap();
NetworkManager &networkManager= NetworkManager::getInstance();
logger.setState(lang.get("Initializing"));
//mesage box
mainMessageBox.init(lang.get("Yes"), lang.get("No"));
mainMessageBox.setEnabled(false);
//check forog war
if(!Config::getInstance().getBool("FogOfWar") && networkManager.isNetworkGame() ){
throw runtime_error("Can not play online games with for of war disabled");
}
//init world, and place camera
commander.init(&world);
world.init(this, gameSettings.getDefaultUnits());
gui.init(this);
chatManager.init(&console, world.getThisTeamIndex());
const Vec2i &v= map->getStartLocation(world.getThisFaction()->getStartLocationIndex());
gameCamera.init(map->getW(), map->getH());
gameCamera.setPos(Vec2f(v.x, v.y));
scriptManager.init(&world, &gameCamera);
//create IAs
aiInterfaces.resize(world.getFactionCount());
for(int i=0; i<world.getFactionCount(); ++i){
Faction *faction= world.getFaction(i);
if(faction->getCpuControl()){
aiInterfaces[i]= new AiInterface(*this, i, faction->getTeam());
logger.add("Creating AI for faction " + intToStr(i), true);
}
else{
aiInterfaces[i]= NULL;
}
}
//wheather particle systems
if(world.getTileset()->getWeather() == wRainy){
logger.add("Creating rain particle system", true);
weatherParticleSystem= new RainParticleSystem();
weatherParticleSystem->setSpeed(12.f/GameConstants::updateFps);
weatherParticleSystem->setPos(gameCamera.getPos());
renderer.manageParticleSystem(weatherParticleSystem, rsGame);
}
else if(world.getTileset()->getWeather() == wSnowy){
logger.add("Creating snow particle system", true);
weatherParticleSystem= new SnowParticleSystem(1200);
weatherParticleSystem->setSpeed(1.5f/GameConstants::updateFps);
weatherParticleSystem->setPos(gameCamera.getPos());
weatherParticleSystem->setTexture(coreData.getSnowTexture());
renderer.manageParticleSystem(weatherParticleSystem, rsGame);
}
//init renderer state
logger.add("Initializing renderer", true);
renderer.initGame(this);
//sounds
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
Tileset *tileset= world.getTileset();
AmbientSounds *ambientSounds= tileset->getAmbientSounds();
//rain
if(tileset->getWeather()==wRainy && ambientSounds->isEnabledRain()){
logger.add("Starting ambient stream", true);
soundRenderer.playAmbient(ambientSounds->getRain());
}
//snow
if(tileset->getWeather()==wSnowy && ambientSounds->isEnabledSnow()){
logger.add("Starting ambient stream", true);
soundRenderer.playAmbient(ambientSounds->getSnow());
}
logger.add("Waiting for network", true);
networkManager.getGameNetworkInterface()->waitUntilReady(&checksum);
logger.add("Starting music stream", true);
StrSound *gameMusic= world.getThisFaction()->getType()->getMusic();
soundRenderer.playMusic(gameMusic);
logger.add("Launching game");
}
// ==================== update ====================
//update
void Game::update(){
// a) Updates non dependant on speed
//misc
updateFps++;
mouse2d= (mouse2d+1) % Renderer::maxMouse2dAnim;
//console
console.update();
// b) Updates depandant on speed
int updateLoops= getUpdateLoops();
//update
for(int i=0; i<updateLoops; ++i){
Renderer &renderer= Renderer::getInstance();
//AiInterface
for(int i=0; i<world.getFactionCount(); ++i){
if(world.getFaction(i)->getCpuControl() && scriptManager.getPlayerModifiers(i)->getAiEnabled()){
aiInterfaces[i]->update();
}
}
//World
world.update();
// Commander
commander.updateNetwork();
//Gui
gui.update();
//Particle systems
if(weatherParticleSystem != NULL){
weatherParticleSystem->setPos(gameCamera.getPos());
}
renderer.updateParticleManager(rsGame);
}
//call the chat manager
chatManager.updateNetwork();
//check for quiting status
if(NetworkManager::getInstance().getGameNetworkInterface()->getQuit()){
quitGame();
}
//update auto test
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateGame(this);
}
}
void Game::updateCamera(){
gameCamera.update();
}
// ==================== render ====================
//render
void Game::render(){
renderFps++;
render3d();
render2d();
Renderer::getInstance().swapBuffers();
}
// ==================== tick ====================
void Game::tick(){
lastUpdateFps= updateFps;
lastRenderFps= renderFps;
updateFps= 0;
renderFps= 0;
//Win/lose check
checkWinner();
gui.tick();
}
// ==================== events ====================
void Game::mouseDownLeft(int x, int y){
Map *map= world.getMap();
const Metrics &metrics= Metrics::getInstance();
NetworkManager &networkManager= NetworkManager::getInstance();
bool messageBoxClick= false;
//scrip message box, only if the exit box is not enabled
if(!mainMessageBox.getEnabled() && scriptManager.getMessageBox()->getEnabled()){
int button= 1;
if(scriptManager.getMessageBox()->mouseClick(x, y, button)){
scriptManager.onMessageBoxOk();
messageBoxClick= true;
}
}
//minimap panel
if(!messageBoxClick){
if(metrics.isInMinimap(x, y) && !gui.isSelectingPos()){
int xm= x - metrics.getMinimapX();
int ym= y - metrics.getMinimapY();
int xCell= static_cast<int>(xm * (static_cast<float>(map->getW()) / metrics.getMinimapW()));
int yCell= static_cast<int>(map->getH() - ym * (static_cast<float>(map->getH()) / metrics.getMinimapH()));
if(map->isInside(xCell, yCell)){
if(!gui.isSelectingPos()){
gameCamera.setPos(Vec2f(static_cast<float>(xCell), static_cast<float>(yCell)));
}
}
}
//display panel
else if(metrics.isInDisplay(x, y) && !gui.isSelectingPos()){
int xd= x - metrics.getDisplayX();
int yd= y - metrics.getDisplayY();
if(gui.mouseValid(xd, yd)){
gui.mouseDownLeftDisplay(xd, yd);
}
else{
gui.mouseDownLeftGraphics(x, y);
}
}
//graphics panel
else{
gui.mouseDownLeftGraphics(x, y);
}
}
//exit message box, has to be the last thing to do in this function
if(mainMessageBox.getEnabled()){
int button= 1;
if(mainMessageBox.mouseClick(x, y, button)){
if(button==1){
networkManager.getGameNetworkInterface()->quitGame();
quitGame();
}
else{
//close message box
mainMessageBox.setEnabled(false);
}
}
}
}
void Game::mouseDownRight(int x, int y){
gui.mouseDownRightGraphics(x, y);
}
void Game::mouseUpLeft(int x, int y){
gui.mouseUpLeftGraphics(x, y);
}
void Game::mouseDoubleClickLeft(int x, int y){
const Metrics &metrics= Metrics::getInstance();
//display panel
if(metrics.isInDisplay(x, y) && !gui.isSelectingPos()){
int xd= x - metrics.getDisplayX();
int yd= y - metrics.getDisplayY();
if(gui.mouseValid(xd, yd)){
return;
}
}
//graphics panel
gui.mouseDoubleClickLeftGraphics(x, y);
}
void Game::mouseMove(int x, int y, const MouseState *ms){
const Metrics &metrics= Metrics::getInstance();
mouseX= x;
mouseY= y;
//main window
if(y<10){
gameCamera.setMoveZ(-1);
}
else if(y> metrics.getVirtualH()-10){
gameCamera.setMoveZ(1);
}
else{
gameCamera.stopMoveZ();
}
if(x<10){
gameCamera.setMoveX(-1);
}
else if(x> metrics.getVirtualW()-10){
gameCamera.setMoveX(1);
}
else{
gameCamera.stopMoveX();
}
if(mainMessageBox.getEnabled()){
mainMessageBox.mouseMove(x, y);
}
if(scriptManager.getMessageBox()->getEnabled()){
scriptManager.getMessageBox()->mouseMove(x, y);
}
//graphics
gui.mouseMoveGraphics(x, y);
//display
if(metrics.isInDisplay(x, y) && !gui.isSelecting() && !gui.isSelectingPos()){
if(!gui.isSelectingPos()){
gui.mouseMoveDisplay(x - metrics.getDisplayX(), y - metrics.getDisplayY());
}
}
}
void Game::keyDown(char key){
Lang &lang= Lang::getInstance();
bool speedChangesAllowed= !NetworkManager::getInstance().isNetworkGame();
//send ley to the chat manager
chatManager.keyDown(key);
if(!chatManager.getEditEnabled()){
if(key=='N'){
renderNetworkStatus= true;
}
else if(key=='E'){
for(int i=0; i<100; ++i){
string path= "screens/screen" + intToStr(i) + ".tga";
FILE *f= fopen(path.c_str(), "rb");
if(f==NULL){
Renderer::getInstance().saveScreen(path);
break;
}
else{
fclose(f);
}
}
}
//move camera left
else if(key==vkLeft){
gameCamera.setMoveX(-1);
}
//move camera right
else if(key==vkRight){
gameCamera.setMoveX(1);
}
//move camera up
else if(key==vkUp){
gameCamera.setMoveZ(1);
}
//move camera down
else if(key==vkDown){
gameCamera.setMoveZ(-1);
}
//change camera mode
else if(key=='F'){
gameCamera.switchState();
string stateString= gameCamera.getState()==GameCamera::sGame? lang.get("GameCamera"): lang.get("FreeCamera");
console.addLine(lang.get("CameraModeSet")+" "+ stateString);
}
//pause
else if(key=='P'){
if(speedChangesAllowed){
if(paused){
console.addLine(lang.get("GameResumed"));
paused= false;
}
else{
console.addLine(lang.get("GamePaused"));
paused= true;
}
}
}
//increment speed
else if(key==vkAdd){
if(speedChangesAllowed){
incSpeed();
}
}
//decrement speed
else if(key==vkSubtract){
if(speedChangesAllowed){
decSpeed();
}
}
//exit
else if(key==vkEscape){
showMessageBox(lang.get("ExitGame?"), "", true);
}
//group
else if(key>='0' && key<'0'+Selection::maxGroups){
gui.groupKey(key-'0');
}
//hotkeys
if(gameCamera.getState()==GameCamera::sGame){
gui.hotKey(key);
}
else{
//rotate camera leftt
if(key=='A'){
gameCamera.setRotate(-1);
}
//rotate camera right
else if(key=='D'){
gameCamera.setRotate(1);
}
//camera up
else if(key=='S'){
gameCamera.setMoveY(1);
}
//camera down
else if(key=='W'){
gameCamera.setMoveY(-1);
}
}
}
}
void Game::keyUp(char key){
if(!chatManager.getEditEnabled()){
switch(key){
case 'N':
renderNetworkStatus= false;
break;
case 'A':
case 'D':
gameCamera.setRotate(0);
break;
case 'W':
case 'S':
gameCamera.stopMoveY();
break;
case vkUp:
case vkDown:
gameCamera.stopMoveZ();
break;
case vkLeft:
case vkRight:
gameCamera.stopMoveX();
break;
}
}
}
void Game::keyPress(char c){
chatManager.keyPress(c);
}
void Game::quitGame(){
program->setState(new BattleEnd(program, world.getStats()));
}
// ==================== PRIVATE ====================
// ==================== render ====================
void Game::render3d(){
Renderer &renderer= Renderer::getInstance();
//init
renderer.reset3d();
renderer.computeVisibleQuad();
renderer.loadGameCameraMatrix();
renderer.setupLighting();
//shadow map
renderer.renderShadowsToTexture();
//clear buffers
renderer.clearBuffers();
//surface
renderer.renderSurface();
//selection circles
renderer.renderSelectionEffects();
//units
renderer.renderUnits();
//objects
renderer.renderObjects();
//water
renderer.renderWater();
renderer.renderWaterEffects();
//particles
renderer.renderParticleManager(rsGame);
//mouse 3d
renderer.renderMouse3d();
}
void Game::render2d(){
Renderer &renderer= Renderer::getInstance();
Config &config= Config::getInstance();
CoreData &coreData= CoreData::getInstance();
//init
renderer.reset2d();
//display
renderer.renderDisplay();
//minimap
if(!config.getBool("PhotoMode")){
renderer.renderMinimap();
}
//selection
renderer.renderSelectionQuad();
//exit message box
if(mainMessageBox.getEnabled()){
renderer.renderMessageBox(&mainMessageBox);
}
//script message box
if(!mainMessageBox.getEnabled() && scriptManager.getMessageBoxEnabled()){
renderer.renderMessageBox(scriptManager.getMessageBox());
}
//script display text
if(!scriptManager.getDisplayText().empty() && !scriptManager.getMessageBoxEnabled()){
renderer.renderText(
scriptManager.getDisplayText(), coreData.getMenuFontNormal(),
Vec3f(1.0f), 200, 680, false);
}
renderer.renderChatManager(&chatManager);
//debug info
if(config.getBool("DebugMode")){
string str;
str+= "MouseXY: " + intToStr(mouseX) + "," + intToStr(mouseY)+"\n";
str+= "PosObjWord: " + intToStr(gui.getPosObjWorld().x) + "," + intToStr(gui.getPosObjWorld().y)+"\n";
str+= "Render FPS: "+intToStr(lastRenderFps)+"\n";
str+= "Update FPS: "+intToStr(lastUpdateFps)+"\n";
str+= "GameCamera pos: "+floatToStr(gameCamera.getPos().x)+","+floatToStr(gameCamera.getPos().y)+","+floatToStr(gameCamera.getPos().z)+"\n";
str+= "Time: "+floatToStr(world.getTimeFlow()->getTime())+"\n";
str+= "Triangle count: "+intToStr(renderer.getTriangleCount())+"\n";
str+= "Vertex count: "+intToStr(renderer.getPointCount())+"\n";
str+= "Frame count:"+intToStr(world.getFrameCount())+"\n";
//visible quad
Quad2i visibleQuad= renderer.getVisibleQuad();
str+= "Visible quad: ";
for(int i= 0; i<4; ++i){
str+= "(" + intToStr(visibleQuad.p[i].x) + "," +intToStr(visibleQuad.p[i].y) + ") ";
}
str+= "\n";
str+= "Visible quad area: " + floatToStr(visibleQuad.area()) +"\n";
// resources
for(int i=0; i<world.getFactionCount(); ++i){
str+= "Player "+intToStr(i)+" res: ";
for(int j=0; j<world.getTechTree()->getResourceTypeCount(); ++j){
str+= intToStr(world.getFaction(i)->getResource(j)->getAmount());
str+=" ";
}
str+="\n";
}
renderer.renderText(
str, coreData.getMenuFontNormal(),
Vec3f(1.0f), 10, 500, false);
}
//network status
if(renderNetworkStatus){
renderer.renderText(
NetworkManager::getInstance().getGameNetworkInterface()->getNetworkStatus(),
coreData.getMenuFontNormal(),
Vec3f(1.0f), 20, 500, false);
}
//resource info
if(!config.getBool("PhotoMode")){
renderer.renderResourceStatus();
renderer.renderConsole(&console);
}
//2d mouse
renderer.renderMouse2d(mouseX, mouseY, mouse2d, gui.isSelectingPos()? 1.f: 0.f);
}
// ==================== misc ====================
void Game::checkWinner(){
if(!gameOver){
if(gameSettings.getDefaultVictoryConditions()){
checkWinnerStandard();
}
else
{
checkWinnerScripted();
}
}
}
void Game::checkWinnerStandard(){
//lose
bool lose= false;
if(!hasBuilding(world.getThisFaction())){
lose= true;
for(int i=0; i<world.getFactionCount(); ++i){
if(!world.getFaction(i)->isAlly(world.getThisFaction())){
world.getStats()->setVictorious(i);
}
}
gameOver= true;
showLoseMessageBox();
}
//win
if(!lose){
bool win= true;
for(int i=0; i<world.getFactionCount(); ++i){
if(i!=world.getThisFactionIndex()){
if(hasBuilding(world.getFaction(i)) && !world.getFaction(i)->isAlly(world.getThisFaction())){
win= false;
}
}
}
//if win
if(win){
for(int i=0; i< world.getFactionCount(); ++i){
if(world.getFaction(i)->isAlly(world.getThisFaction())){
world.getStats()->setVictorious(i);
}
}
gameOver= true;
showWinMessageBox();
}
}
}
void Game::checkWinnerScripted(){
if(scriptManager.getGameOver()){
gameOver= true;
for(int i= 0; i<world.getFactionCount(); ++i){
if(scriptManager.getPlayerModifiers(i)->getWinner()){
world.getStats()->setVictorious(i);
}
}
if(scriptManager.getPlayerModifiers(world.getThisFactionIndex())->getWinner()){
showWinMessageBox();
}
else{
showLoseMessageBox();
}
}
}
bool Game::hasBuilding(const Faction *faction){
for(int i=0; i<faction->getUnitCount(); ++i){
if(faction->getUnit(i)->getType()->hasSkillClass(scBeBuilt)){
return true;
}
}
return false;
}
void Game::incSpeed(){
Lang &lang= Lang::getInstance();
switch(speed){
case sSlow:
speed= sNormal;
console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Normal"));
break;
case sNormal:
speed= sFast;
console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Fast"));
break;
default:
break;
}
}
void Game::decSpeed(){
Lang &lang= Lang::getInstance();
switch(speed){
case sNormal:
speed= sSlow;
console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Slow"));
break;
case sFast:
speed= sNormal;
console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Normal"));
break;
default:
break;
}
}
int Game::getUpdateLoops(){
if(paused){
return 0;
}
else if(speed==sFast){
return Config::getInstance().getInt("FastSpeedLoops");
}
else if(speed==sSlow){
return updateFps % 2 == 0? 1: 0;
}
return 1;
}
void Game::showLoseMessageBox(){
Lang &lang= Lang::getInstance();
showMessageBox(lang.get("YouLose")+", "+lang.get("ExitGame?"), lang.get("BattleOver"), false);
}
void Game::showWinMessageBox(){
Lang &lang= Lang::getInstance();
showMessageBox(lang.get("YouWin")+", "+lang.get("ExitGame?"), lang.get("BattleOver"), false);
}
void Game::showMessageBox(const string &text, const string &header, bool toggle){
if(!toggle){
mainMessageBox.setEnabled(false);
}
if(!mainMessageBox.getEnabled()){
mainMessageBox.setText(text);
mainMessageBox.setHeader(header);
mainMessageBox.setEnabled(true);
}
else{
mainMessageBox.setEnabled(false);
}
}
}}//end namespace

View File

@ -0,0 +1,135 @@
// ==============================================================
// 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_GAME_H_
#define _GLEST_GAME_GAME_H_
#include <vector>
#include "gui.h"
#include "game_camera.h"
#include "world.h"
#include "ai_interface.h"
#include "program.h"
#include "chat_manager.h"
#include "script_manager.h"
#include "game_settings.h"
using std::vector;
namespace Glest{ namespace Game{
class GraphicMessageBox;
// =====================================================
// class Game
//
// Main game class
// =====================================================
class Game: public ProgramState{
public:
enum Speed{
sFast,
sNormal,
sSlow
};
private:
typedef vector<Ai*> Ais;
typedef vector<AiInterface*> AiInterfaces;
private:
//main data
World world;
AiInterfaces aiInterfaces;
Gui gui;
GameCamera gameCamera;
Commander commander;
Console console;
ChatManager chatManager;
ScriptManager scriptManager;
//misc
Checksum checksum;
string loadingText;
int mouse2d;
int mouseX, mouseY; //coords win32Api
int updateFps, lastUpdateFps;
int renderFps, lastRenderFps;
bool paused;
bool gameOver;
bool renderNetworkStatus;
Speed speed;
GraphicMessageBox mainMessageBox;
//misc ptr
ParticleSystem *weatherParticleSystem;
GameSettings gameSettings;
public:
Game(Program *program, const GameSettings *gameSettings);
~Game();
//get
GameSettings *getGameSettings() {return &gameSettings;}
const GameCamera *getGameCamera() const {return &gameCamera;}
GameCamera *getGameCamera() {return &gameCamera;}
const Commander *getCommander() const {return &commander;}
Gui *getGui() {return &gui;}
const Gui *getGui() const {return &gui;}
Commander *getCommander() {return &commander;}
Console *getConsole() {return &console;}
ScriptManager *getScriptManager() {return &scriptManager;}
World *getWorld() {return &world;}
const World *getWorld() const {return &world;}
//init
virtual void load();
virtual void init();
virtual void update();
virtual void updateCamera();
virtual void render();
virtual void tick();
//event managing
virtual void keyDown(char key);
virtual void keyUp(char key);
virtual void keyPress(char c);
virtual void mouseDownLeft(int x, int y);
virtual void mouseDownRight(int x, int y);
virtual void mouseUpLeft(int x, int y);
virtual void mouseDoubleClickLeft(int x, int y);
virtual void mouseMove(int x, int y, const MouseState *mouseState);
void quitGame();
private:
//render
void render3d();
void render2d();
//misc
void checkWinner();
void checkWinnerStandard();
void checkWinnerScripted();
bool hasBuilding(const Faction *faction);
void incSpeed();
void decSpeed();
int getUpdateLoops();
void showLoseMessageBox();
void showWinMessageBox();
void showMessageBox(const string &text, const string &header, bool toggle);
};
}}//end namespace
#endif

View File

@ -0,0 +1,235 @@
// ==============================================================
// 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 "game_camera.h"
#include "config.h"
#include "game_constants.h"
#include "metrics.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class GameCamera
// =====================================================
// ================== PUBLIC =====================
const float GameCamera::startingVAng= -60.f;
const float GameCamera::startingHAng= 0.f;
const float GameCamera::maxHeight= 20.f;
const float GameCamera::minHeight= 10.f;
const float GameCamera::transitionSpeed= 0.01f;
const float GameCamera::centerOffsetZ= 8.0f;
// ================= Constructor =================
GameCamera::GameCamera(){
this->pos= Vec3f(0.f, maxHeight, 0.f);
state= sGame;
//config
speed= 15.f / GameConstants::cameraFps;
clampBounds= !Config::getInstance().getBool("PhotoMode");
vAng= startingVAng;
hAng= startingHAng;
rotate=0;
stateTransition= 1.f;
move= Vec3f(0.f);
stopMove= Vec3b(false);
}
void GameCamera::init(int limitX, int limitY){
this->limitX= limitX;
this->limitY= limitY;
}
// ==================== Misc =====================
void GameCamera::setPos(Vec2f pos){
this->pos= Vec3f(pos.x, this->pos.y, pos.y);
clampPosXZ(0.0f, limitX, 0.0f, limitY);
}
void GameCamera::update(){
//move speed XYZ
if(stopMove.x){
move.x *= 0.9f;
}
if(stopMove.y){
move.y *= 0.9f;
}
if(stopMove.z){
move.z *= 0.9f;
}
//move XZ
if(move.z!=0){
moveForwardH(speed*move.z);
}
if(move.x!=0){
moveSideH(speed*move.x);
}
//free state
if(state==sFree){
if(fabs(rotate) == 1){
rotateHV(speed*5*rotate, 0);
}
if(move.y>0){
moveUp(speed * move.y);
if(clampBounds && pos.y<maxHeight){
rotateHV(0.f, -speed * 1.7f * move.y);
}
}
if(move.y<0){
moveUp(speed * move.y);
if(clampBounds && pos.y>minHeight){
rotateHV(0.f, -speed * 1.7f * move.y);
}
}
}
//game state
else if(stateTransition<1.f){
if(lastHAng<180){
hAng= lastHAng + (stateTransition)*(startingHAng-lastHAng);
}
else{
hAng= lastHAng + (stateTransition)*(startingHAng+360-lastHAng);
}
vAng= lastVAng*(1.f-stateTransition)+startingVAng*stateTransition;
pos.y= lastPos.y+maxHeight*stateTransition;
stateTransition+= transitionSpeed;
}
if(clampBounds){
clampPosXYZ(0.0f, limitX, minHeight, maxHeight, 0.0f, limitY);
}
}
Quad2i GameCamera::computeVisibleQuad() const{
float aspectRatio = Metrics::getInstance().getAspectRatio();
Vec2i v= Vec2i(static_cast<int>(pos.x), static_cast<int>(pos.z));
//free state
if(state==sFree || stateTransition<1.f){
const float nearDist= 20.f;
const float farDist= 90.f;
const float fov= 65.0f * aspectRatio * 0.5f;
const float dist= 20.f;
Vec2f v(sin(degToRad(180-hAng)), cos(degToRad(180-hAng)));
Vec2f v1(sin(degToRad(180-hAng-fov)), cos(degToRad(180-hAng-fov)));
Vec2f v2(sin(degToRad(180-hAng+fov)), cos(degToRad(180-hAng+fov)));
v.normalize();
v1.normalize();
v2.normalize();
Vec2f p= Vec2f(pos.x, pos.z)-v*dist;
Vec2i p1(static_cast<int>(p.x+v1.x*nearDist), static_cast<int>(p.y+v1.y*nearDist));
Vec2i p2(static_cast<int>(p.x+v1.x*farDist), static_cast<int>(p.y+v1.y*farDist));
Vec2i p3(static_cast<int>(p.x+v2.x*nearDist), static_cast<int>(p.y+v2.y*nearDist));
Vec2i p4(static_cast<int>(p.x+v2.x*farDist), static_cast<int>(p.y+v2.y*farDist));
if(hAng>=135 && hAng<=225){
return Quad2i(p1, p2, p3, p4);
}
if(hAng>=45 && hAng<=135){
return Quad2i(p3, p1, p4, p2);
}
if(hAng>=225 && hAng<=315) {
return Quad2i(p2, p4, p1, p3);
}
return Quad2i(p4, p3, p2, p1);
}
//game state
else{
static const int widthNear= 19 * aspectRatio;
static const int widthFar= 23 * aspectRatio;
static const int near= 5;
static const int far= 40;
return Quad2i(
Vec2i(v.x-widthNear, v.y-far),
Vec2i(v.x-widthFar, v.y+near),
Vec2i(v.x+widthNear, v.y-far),
Vec2i(v.x+widthFar, v.y+near));
}
}
void GameCamera::switchState(){
if(state==sGame){
state= sFree;
}
else{
state= sGame;
stateTransition= 0.f;
lastHAng= hAng;
lastVAng= vAng;
lastPos= pos;
}
}
void GameCamera::centerXZ(float x, float z){
pos.x= x;
pos.z= z+centerOffsetZ;
}
// ==================== PRIVATE ====================
void GameCamera::clampPosXZ(float x1, float x2, float z1, float z2){
if(pos.x<x1) pos.x= static_cast<float>(x1);
if(pos.z<z1) pos.z= static_cast<float>(z1);
if(pos.x>x2) pos.x= static_cast<float>(x2);
if(pos.z>z2) pos.z= static_cast<float>(z2);
}
void GameCamera::clampPosXYZ(float x1, float x2, float y1, float y2, float z1, float z2){
if(pos.x<x1) pos.x= x1;
if(pos.y<y1) pos.y= y1;
if(pos.z<z1) pos.z= z1;
if(pos.x>x2) pos.x= x2;
if(pos.y>y2) pos.y= y2;
if(pos.z>z2) pos.z= z2;
}
void GameCamera::rotateHV(float h, float v){
vAng+=v;
hAng+=h;
if(hAng>360.f) hAng-=360.f;
if(hAng<0.f) hAng+=360.f;
}
//move camera forwad but never change heightFactor
void GameCamera::moveForwardH(float d){
pos=pos + Vec3f(sin(degToRad(hAng)), 0.f, -cos(degToRad(hAng))) * d;
}
//move camera to a side but never change heightFactor
void GameCamera::moveSideH(float d){
pos=pos + Vec3f(sin(degToRad(hAng+90)), 0.f, -cos(degToRad(hAng+90))) * d;
}
void GameCamera::moveUp(float d){
pos.y+= d;
}
}}//end namespace

View File

@ -0,0 +1,114 @@
// ==============================================================
// 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_GAMECAMERA_H_
#define _GLEST_GAME_GAMECAMERA_H_
#include "vec.h"
#include "math_util.h"
namespace Glest{ namespace Game{
using Shared::Graphics::Quad2i;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Vec3b;
using Shared::Graphics::Vec2f;
class Config;
// =====================================================
// class GameCamera
//
/// A basic camera that holds information about the game view
// =====================================================
class GameCamera{
public:
static const float startingVAng;
static const float startingHAng;
static const float maxHeight;
static const float minHeight;
static const float transitionSpeed;
static const float centerOffsetZ;
public:
enum State{
sGame,
sFree
};
private:
Vec3f pos;
Vec3f lastPos;
float hAng; //YZ plane positive -Z axis
float vAng; //XZ plane positive +Z axis
float lastHAng;
float lastVAng;
float rotate;
Vec3f move;
Vec3b stopMove;
float stateTransition;
State state;
int limitX;
int limitY;
//config
float speed;
bool clampBounds;
public:
GameCamera();
void init(int limitX, int limitY);
//get
float getHAng() const {return hAng;};
float getVAng() const {return vAng;}
State getState() const {return state;}
const Vec3f &getPos() const {return pos;}
//set
void setRotate(int rotate) {this->rotate= rotate;}
void setPos(Vec2f pos);
void setMoveX(float f) {this->stopMove.x= false; this->move.x= f;}
void setMoveY(float f) {this->stopMove.y= false; this->move.y= f;}
void setMoveZ(float f) {this->stopMove.z= false; this->move.z= f;}
void stopMoveX() {this->stopMove.x= true;}
void stopMoveY() {this->stopMove.y= true;}
void stopMoveZ() {this->stopMove.z= true;}
//other
void update();
Quad2i computeVisibleQuad() const;
void switchState();
void centerXZ(float x, float z);
private:
void clampPosXYZ(float x1, float x2, float y1, float y2, float z1, float z2);
void clampPosXZ(float x1, float x2, float z1, float z2);
void rotateHV(float h, float v);
void moveForwardH(float dist);
void moveSideH(float dist);
void moveUp(float dist);
};
}} //end namespace
#endif

View File

@ -0,0 +1,43 @@
// ==============================================================
// 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
// ==============================================================
#ifndef _GLEST_GAME_GAMECONSTANTS_H_
#define _GLEST_GAME_GAMECONSTANTS_H_
namespace Glest{ namespace Game{
// =====================================================
// class GameConstants
// =====================================================
enum ControlType{
ctClosed,
ctCpuEasy,
ctCpu,
ctCpuUltra,
ctCpuMega,
ctNetwork,
ctHuman
};
class GameConstants{
public:
static const int maxPlayers= 4;
static const int serverPort= 61357;
static const int updateFps= 40;
static const int cameraFps= 100;
static const int networkFramePeriod= 10;
static const int networkExtraLatency= 200;
};
}}//end namespace
#endif

View File

@ -0,0 +1,88 @@
// ==============================================================
// 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_GAMESETTINGS_H_
#define _GLEST_GAME_GAMESETTINGS_H_
#include "game_constants.h"
namespace Glest{ namespace Game{
// =====================================================
// class GameSettings
// =====================================================
class GameSettings{
private:
string description;
string map;
string tileset;
string tech;
string scenario;
string scenarioDir;
string factionTypeNames[GameConstants::maxPlayers]; //faction names
ControlType factionControls[GameConstants::maxPlayers];
int thisFactionIndex;
int factionCount;
int teams[GameConstants::maxPlayers];
int startLocationIndex[GameConstants::maxPlayers];
bool defaultUnits;
bool defaultResources;
bool defaultVictoryConditions;
public:
//get
const string &getDescription() const {return description;}
const string &getMap() const {return map;}
const string &getTileset() const {return tileset;}
const string &getTech() const {return tech;}
const string &getScenario() const {return scenario;}
const string &getScenarioDir() const {return scenarioDir;}
const string &getFactionTypeName(int factionIndex) const {return factionTypeNames[factionIndex];}
ControlType getFactionControl(int factionIndex) const {return factionControls[factionIndex];}
int getThisFactionIndex() const {return thisFactionIndex;}
int getFactionCount() const {return factionCount;}
int getTeam(int factionIndex) const {return teams[factionIndex];}
int getStartLocationIndex(int factionIndex) const {return startLocationIndex[factionIndex];}
bool getDefaultUnits() const {return defaultUnits;}
bool getDefaultResources() const {return defaultResources;}
bool getDefaultVictoryConditions() const {return defaultVictoryConditions;}
//set
void setDescription(const string& description) {this->description= description;}
void setMap(const string& map) {this->map= map;}
void setTileset(const string& tileset) {this->tileset= tileset;}
void setTech(const string& tech) {this->tech= tech;}
void setScenario(const string& scenario) {this->scenario= scenario;}
void setScenarioDir(const string& scenarioDir) {this->scenarioDir= scenarioDir;}
void setFactionTypeName(int factionIndex, const string& factionTypeName) {this->factionTypeNames[factionIndex]= factionTypeName;}
void setFactionControl(int factionIndex, ControlType controller) {this->factionControls[factionIndex]= controller;}
void setThisFactionIndex(int thisFactionIndex) {this->thisFactionIndex= thisFactionIndex;}
void setFactionCount(int factionCount) {this->factionCount= factionCount;}
void setTeam(int factionIndex, int team) {this->teams[factionIndex]= team;}
void setStartLocationIndex(int factionIndex, int startLocationIndex) {this->startLocationIndex[factionIndex]= startLocationIndex;}
void setDefaultUnits(bool defaultUnits) {this->defaultUnits= defaultUnits;}
void setDefaultResources(bool defaultResources) {this->defaultResources= defaultResources;}
void setDefaultVictoryConditions(bool defaultVictoryConditions) {this->defaultVictoryConditions= defaultVictoryConditions;}
};
}}//end namespace
#endif

View File

@ -0,0 +1,400 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "script_manager.h"
#include "world.h"
#include "lang.h"
#include "game_camera.h"
#include "leak_dumper.h"
using namespace Shared::Platform;
using namespace Shared::Lua;
namespace Glest{ namespace Game{
// =====================================================
// class PlayerModifiers
// =====================================================
PlayerModifiers::PlayerModifiers(){
winner= false;
aiEnabled= true;
}
// =====================================================
// class ScriptManager
// =====================================================
ScriptManager* ScriptManager::thisScriptManager= NULL;
const int ScriptManager::messageWrapCount= 30;
const int ScriptManager::displayTextWrapCount= 64;
void ScriptManager::init(World* world, GameCamera *gameCamera){
const Scenario* scenario= world->getScenario();
this->world= world;
this->gameCamera= gameCamera;
//set static instance
thisScriptManager= this;
//register functions
luaScript.registerFunction(showMessage, "showMessage");
luaScript.registerFunction(setDisplayText, "setDisplayText");
luaScript.registerFunction(clearDisplayText, "clearDisplayText");
luaScript.registerFunction(setCameraPosition, "setCameraPosition");
luaScript.registerFunction(createUnit, "createUnit");
luaScript.registerFunction(giveResource, "giveResource");
luaScript.registerFunction(givePositionCommand, "givePositionCommand");
luaScript.registerFunction(giveProductionCommand, "giveProductionCommand");
luaScript.registerFunction(giveUpgradeCommand, "giveUpgradeCommand");
luaScript.registerFunction(disableAi, "disableAi");
luaScript.registerFunction(setPlayerAsWinner, "setPlayerAsWinner");
luaScript.registerFunction(endGame, "endGame");
luaScript.registerFunction(getStartLocation, "startLocation");
luaScript.registerFunction(getUnitPosition, "unitPosition");
luaScript.registerFunction(getUnitFaction, "unitFaction");
luaScript.registerFunction(getResourceAmount, "resourceAmount");
luaScript.registerFunction(getLastCreatedUnitName, "lastCreatedUnitName");
luaScript.registerFunction(getLastCreatedUnitId, "lastCreatedUnit");
luaScript.registerFunction(getLastDeadUnitName, "lastDeadUnitName");
luaScript.registerFunction(getLastDeadUnitId, "lastDeadUnit");
luaScript.registerFunction(getUnitCount, "unitCount");
luaScript.registerFunction(getUnitCountOfType, "unitCountOfType");
//load code
for(int i= 0; i<scenario->getScriptCount(); ++i){
const Script* script= scenario->getScript(i);
luaScript.loadCode("function " + script->getName() + "()" + script->getCode() + "end\n", script->getName());
}
//setup message box
messageBox.init( Lang::getInstance().get("Ok") );
messageBox.setEnabled(false);
//last created unit
lastCreatedUnitId= -1;
lastDeadUnitId= -1;
gameOver= false;
//call startup function
luaScript.beginCall("startup");
luaScript.endCall();
}
// ========================== events ===============================================
void ScriptManager::onMessageBoxOk(){
Lang &lang= Lang::getInstance();
if(!messageQueue.empty()){
messageQueue.pop();
if(!messageQueue.empty()){
messageBox.setText(wrapString(lang.getScenarioString(messageQueue.front().getText()), messageWrapCount));
messageBox.setHeader(lang.getScenarioString(messageQueue.front().getHeader()));
}
}
}
void ScriptManager::onResourceHarvested(){
luaScript.beginCall("resourceHarvested");
luaScript.endCall();
}
void ScriptManager::onUnitCreated(const Unit* unit){
lastCreatedUnitName= unit->getType()->getName();
lastCreatedUnitId= unit->getId();
luaScript.beginCall("unitCreated");
luaScript.endCall();
luaScript.beginCall("unitCreatedOfType_"+unit->getType()->getName());
luaScript.endCall();
}
void ScriptManager::onUnitDied(const Unit* unit){
lastDeadUnitName= unit->getType()->getName();
lastDeadUnitId= unit->getId();
luaScript.beginCall("unitDied");
luaScript.endCall();
}
// ========================== lua wrappers ===============================================
string ScriptManager::wrapString(const string &str, int wrapCount){
string returnString;
int letterCount= 0;
for(int i= 0; i<str.size(); ++i){
if(letterCount>wrapCount && str[i]==' '){
returnString+= '\n';
letterCount= 0;
}
else
{
returnString+= str[i];
}
++letterCount;
}
return returnString;
}
void ScriptManager::showMessage(const string &text, const string &header){
Lang &lang= Lang::getInstance();
messageQueue.push(ScriptManagerMessage(text, header));
messageBox.setEnabled(true);
messageBox.setText(wrapString(lang.getScenarioString(messageQueue.front().getText()), messageWrapCount));
messageBox.setHeader(lang.getScenarioString(messageQueue.front().getHeader()));
}
void ScriptManager::clearDisplayText(){
displayText= "";
}
void ScriptManager::setDisplayText(const string &text){
displayText= wrapString(Lang::getInstance().getScenarioString(text), displayTextWrapCount);
}
void ScriptManager::setCameraPosition(const Vec2i &pos){
gameCamera->centerXZ(pos.x, pos.y);
}
void ScriptManager::createUnit(const string &unitName, int factionIndex, Vec2i pos){
world->createUnit(unitName, factionIndex, pos);
}
void ScriptManager::giveResource(const string &resourceName, int factionIndex, int amount){
world->giveResource(resourceName, factionIndex, amount);
}
void ScriptManager::givePositionCommand(int unitId, const string &commandName, const Vec2i &pos){
world->givePositionCommand(unitId, commandName, pos);
}
void ScriptManager::giveProductionCommand(int unitId, const string &producedName){
world->giveProductionCommand(unitId, producedName);
}
void ScriptManager::giveUpgradeCommand(int unitId, const string &producedName){
world->giveUpgradeCommand(unitId, producedName);
}
void ScriptManager::disableAi(int factionIndex){
if(factionIndex<GameConstants::maxPlayers){
playerModifiers[factionIndex].disableAi();
}
}
void ScriptManager::setPlayerAsWinner(int factionIndex){
if(factionIndex<GameConstants::maxPlayers){
playerModifiers[factionIndex].setAsWinner();
}
}
void ScriptManager::endGame(){
gameOver= true;
}
Vec2i ScriptManager::getStartLocation(int factionIndex){
return world->getStartLocation(factionIndex);
}
Vec2i ScriptManager::getUnitPosition(int unitId){
return world->getUnitPosition(unitId);
}
int ScriptManager::getUnitFaction(int unitId){
return world->getUnitFactionIndex(unitId);
}
int ScriptManager::getResourceAmount(const string &resourceName, int factionIndex){
return world->getResourceAmount(resourceName, factionIndex);
}
const string &ScriptManager::getLastCreatedUnitName(){
return lastCreatedUnitName;
}
int ScriptManager::getLastCreatedUnitId(){
return lastCreatedUnitId;
}
const string &ScriptManager::getLastDeadUnitName(){
return lastDeadUnitName;
}
int ScriptManager::getLastDeadUnitId(){
return lastDeadUnitId;
}
int ScriptManager::getUnitCount(int factionIndex){
return world->getUnitCount(factionIndex);
}
int ScriptManager::getUnitCountOfType(int factionIndex, const string &typeName){
return world->getUnitCountOfType(factionIndex, typeName);
}
// ========================== lua callbacks ===============================================
int ScriptManager::showMessage(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->showMessage(luaArguments.getString(-2), luaArguments.getString(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::setDisplayText(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->setDisplayText(luaArguments.getString(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::clearDisplayText(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->clearDisplayText();
return luaArguments.getReturnCount();
}
int ScriptManager::setCameraPosition(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->setCameraPosition(Vec2i(luaArguments.getVec2i(-1)));
return luaArguments.getReturnCount();
}
int ScriptManager::createUnit(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->createUnit(
luaArguments.getString(-3),
luaArguments.getInt(-2),
luaArguments.getVec2i(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::giveResource(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->giveResource(luaArguments.getString(-3), luaArguments.getInt(-2), luaArguments.getInt(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::givePositionCommand(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->givePositionCommand(
luaArguments.getInt(-3),
luaArguments.getString(-2),
luaArguments.getVec2i(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::giveProductionCommand(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->giveProductionCommand(
luaArguments.getInt(-2),
luaArguments.getString(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::giveUpgradeCommand(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->giveUpgradeCommand(
luaArguments.getInt(-2),
luaArguments.getString(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::disableAi(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->disableAi(luaArguments.getInt(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::setPlayerAsWinner(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->setPlayerAsWinner(luaArguments.getInt(-1));
return luaArguments.getReturnCount();
}
int ScriptManager::endGame(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
thisScriptManager->endGame();
return luaArguments.getReturnCount();
}
int ScriptManager::getStartLocation(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
Vec2i pos= thisScriptManager->getStartLocation(luaArguments.getInt(-1));
luaArguments.returnVec2i(pos);
return luaArguments.getReturnCount();
}
int ScriptManager::getUnitPosition(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
Vec2i pos= thisScriptManager->getUnitPosition(luaArguments.getInt(-1));
luaArguments.returnVec2i(pos);
return luaArguments.getReturnCount();
}
int ScriptManager::getUnitFaction(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
int factionIndex= thisScriptManager->getUnitFaction(luaArguments.getInt(-1));
luaArguments.returnInt(factionIndex);
return luaArguments.getReturnCount();
}
int ScriptManager::getResourceAmount(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnInt(thisScriptManager->getResourceAmount(luaArguments.getString(-2), luaArguments.getInt(-1)));
return luaArguments.getReturnCount();
}
int ScriptManager::getLastCreatedUnitName(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnString(thisScriptManager->getLastCreatedUnitName());
return luaArguments.getReturnCount();
}
int ScriptManager::getLastCreatedUnitId(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnInt(thisScriptManager->getLastCreatedUnitId());
return luaArguments.getReturnCount();
}
int ScriptManager::getLastDeadUnitName(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnString(thisScriptManager->getLastDeadUnitName());
return luaArguments.getReturnCount();
}
int ScriptManager::getLastDeadUnitId(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnInt(thisScriptManager->getLastDeadUnitId());
return luaArguments.getReturnCount();
}
int ScriptManager::getUnitCount(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnInt(thisScriptManager->getUnitCount(luaArguments.getInt(-1)));
return luaArguments.getReturnCount();
}
int ScriptManager::getUnitCountOfType(LuaHandle* luaHandle){
LuaArguments luaArguments(luaHandle);
luaArguments.returnInt(thisScriptManager->getUnitCountOfType(luaArguments.getInt(-2), luaArguments.getString(-1)));
return luaArguments.getReturnCount();
}
}}//end namespace

View File

@ -0,0 +1,183 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_SCRIPT_MANAGER_H_
#define _GLEST_GAME_SCRIPT_MANAGER_H_
#include <string>
#include <queue>
#include "lua_script.h"
#include "vec.h"
#include "components.h"
#include "game_constants.h"
using std::string;
using std::queue;
using Shared::Graphics::Vec2i;
using Shared::Lua::LuaScript;
using Shared::Lua::LuaHandle;
namespace Glest{ namespace Game{
class World;
class Unit;
class GameCamera;
// =====================================================
// class ScriptManagerMessage
// =====================================================
class ScriptManagerMessage{
private:
string text;
string header;
public:
ScriptManagerMessage(string text, string header) {this->text= text, this->header= header;}
const string &getText() const {return text;}
const string &getHeader() const {return header;}
};
class PlayerModifiers{
public:
PlayerModifiers();
void disableAi() {aiEnabled= false;}
void setAsWinner() {winner= true;}
bool getWinner() const {return winner;}
bool getAiEnabled() const {return aiEnabled;}
private:
bool winner;
bool aiEnabled;
};
// =====================================================
// class ScriptManager
// =====================================================
class ScriptManager{
private:
typedef queue<ScriptManagerMessage> MessageQueue;
private:
//lua
string code;
LuaScript luaScript;
//world
World *world;
GameCamera *gameCamera;
//misc
MessageQueue messageQueue;
GraphicMessageBox messageBox;
string displayText;
//last created unit
string lastCreatedUnitName;
int lastCreatedUnitId;
//last dead unit
string lastDeadUnitName;
int lastDeadUnitId;
// end game state
bool gameOver;
PlayerModifiers playerModifiers[GameConstants::maxPlayers];
private:
static ScriptManager* thisScriptManager;
private:
static const int messageWrapCount;
static const int displayTextWrapCount;
public:
void init(World* world, GameCamera *gameCamera);
//message box functions
bool getMessageBoxEnabled() const {return !messageQueue.empty();}
GraphicMessageBox* getMessageBox() {return &messageBox;}
string getDisplayText() const {return displayText;}
bool getGameOver() const {return gameOver;}
const PlayerModifiers *getPlayerModifiers(int factionIndex) const {return &playerModifiers[factionIndex];}
//events
void onMessageBoxOk();
void onResourceHarvested();
void onUnitCreated(const Unit* unit);
void onUnitDied(const Unit* unit);
private:
string wrapString(const string &str, int wrapCount);
//wrappers, commands
void showMessage(const string &text, const string &header);
void clearDisplayText();
void setDisplayText(const string &text);
void setCameraPosition(const Vec2i &pos);
void createUnit(const string &unitName, int factionIndex, Vec2i pos);
void giveResource(const string &resourceName, int factionIndex, int amount);
void givePositionCommand(int unitId, const string &producedName, const Vec2i &pos);
void giveProductionCommand(int unitId, const string &producedName);
void giveUpgradeCommand(int unitId, const string &upgradeName);
void disableAi(int factionIndex);
void setPlayerAsWinner(int factionIndex);
void endGame();
//wrappers, queries
Vec2i getStartLocation(int factionIndex);
Vec2i getUnitPosition(int unitId);
int getUnitFaction(int unitId);
int getResourceAmount(const string &resourceName, int factionIndex);
const string &getLastCreatedUnitName();
int getLastCreatedUnitId();
const string &getLastDeadUnitName();
int getLastDeadUnitId();
int getUnitCount(int factionIndex);
int getUnitCountOfType(int factionIndex, const string &typeName);
//callbacks, commands
static int showMessage(LuaHandle* luaHandle);
static int setDisplayText(LuaHandle* luaHandle);
static int clearDisplayText(LuaHandle* luaHandle);
static int setCameraPosition(LuaHandle* luaHandle);
static int createUnit(LuaHandle* luaHandle);
static int giveResource(LuaHandle* luaHandle);
static int givePositionCommand(LuaHandle* luaHandle);
static int giveProductionCommand(LuaHandle* luaHandle);
static int giveUpgradeCommand(LuaHandle* luaHandle);
static int disableAi(LuaHandle* luaHandle);
static int setPlayerAsWinner(LuaHandle* luaHandle);
static int endGame(LuaHandle* luaHandle);
//callbacks, queries
static int getStartLocation(LuaHandle* luaHandle);
static int getUnitPosition(LuaHandle* luaHandle);
static int getUnitFaction(LuaHandle* luaHandle);
static int getResourceAmount(LuaHandle* luaHandle);
static int getLastCreatedUnitName(LuaHandle* luaHandle);
static int getLastCreatedUnitId(LuaHandle* luaHandle);
static int getLastDeadUnitName(LuaHandle* luaHandle);
static int getLastDeadUnitId(LuaHandle* luaHandle);
static int getUnitCount(LuaHandle* luaHandle);
static int getUnitCountOfType(LuaHandle* luaHandle);
};
}}//end namespace
#endif

View File

@ -0,0 +1,54 @@
// ==============================================================
// 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 "stats.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
PlayerStats::PlayerStats(){
victory= false;
kills= 0;
deaths= 0;
unitsProduced= 0;
resourcesHarvested= 0;
}
// =====================================================
// class Stats
// =====================================================
void Stats::init(int factionCount, int thisFactionIndex, const string& description){
this->thisFactionIndex= thisFactionIndex;
this->factionCount= factionCount;
this->description= description;
}
void Stats::setVictorious(int playerIndex){
playerStats[playerIndex].victory= true;
}
void Stats::kill(int killerFactionIndex, int killedFactionIndex){
playerStats[killerFactionIndex].kills++;
playerStats[killedFactionIndex].deaths++;
}
void Stats::produce(int producerFactionIndex){
playerStats[producerFactionIndex].unitsProduced++;
}
void Stats::harvest(int harvesterFactionIndex, int amount){
playerStats[harvesterFactionIndex].resourcesHarvested+= amount;
}
}}//end namespace

View File

@ -0,0 +1,79 @@
// ==============================================================
// 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_STATS_H_
#define _GLEST_GAME_STATS_H_
#include <string>
#include "game_constants.h"
#include "faction.h"
using std::string;
namespace Glest{ namespace Game{
struct PlayerStats{
PlayerStats();
ControlType control;
string factionTypeName;
int teamIndex;
bool victory;
int kills;
int deaths;
int unitsProduced;
int resourcesHarvested;
};
// =====================================================
// class Stats
//
/// Player statistics that are shown after the game ends
// =====================================================
class Stats{
private:
PlayerStats playerStats[GameConstants::maxPlayers];
string description;
int factionCount;
int thisFactionIndex;
public:
void init(int factionCount, int thisFactionIndex, const string &description);
string getDescription() const {return description;}
int getThisFactionIndex() const {return thisFactionIndex;}
int getFactionCount() const {return factionCount;}
const string &getFactionTypeName(int factionIndex) const {return playerStats[factionIndex].factionTypeName;}
ControlType getControl(int factionIndex) const {return playerStats[factionIndex].control;}
bool getVictory(int factionIndex) const {return playerStats[factionIndex].victory;}
int getTeam(int factionIndex) const {return playerStats[factionIndex].teamIndex;}
int getKills(int factionIndex) const {return playerStats[factionIndex].kills;}
int getDeaths(int factionIndex) const {return playerStats[factionIndex].deaths;}
int getUnitsProduced(int factionIndex) const {return playerStats[factionIndex].unitsProduced;}
int getResourcesHarvested(int factionIndex) const {return playerStats[factionIndex].resourcesHarvested;}
void setDescription(const string& description) {this->description = description;}
void setFactionTypeName(int playerIndex, const string& factionTypeName) {playerStats[playerIndex].factionTypeName= factionTypeName;}
void setControl(int playerIndex, ControlType control) {playerStats[playerIndex].control= control;}
void setTeam(int playerIndex, int teamIndex) {playerStats[playerIndex].teamIndex= teamIndex;}
void setVictorious(int playerIndex);
void kill(int killerFactionIndex, int killedFactionIndex);
void produce(int producerFactionIndex);
void harvest(int harvesterFactionIndex, int amount);
};
}}//end namespace
#endif

View File

@ -0,0 +1,73 @@
// ==============================================================
// 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 "config.h"
#include "util.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class Config
// =====================================================
Config::Config(){
properties.load("glest.ini");
}
Config &Config::getInstance(){
static Config config;
return config;
}
void Config::save(const string &path){
properties.save(path);
}
int Config::getInt(const string &key) const{
return properties.getInt(key);
}
bool Config::getBool(const string &key) const{
return properties.getBool(key);
}
float Config::getFloat(const string &key) const{
return properties.getFloat(key);
}
const string &Config::getString(const string &key) const{
return properties.getString(key);
}
void Config::setInt(const string &key, int value){
properties.setInt(key, value);
}
void Config::setBool(const string &key, bool value){
properties.setBool(key, value);
}
void Config::setFloat(const string &key, float value){
properties.setFloat(key, value);
}
void Config::setString(const string &key, const string &value){
properties.setString(key, value);
}
string Config::toString(){
return properties.toString();
}
}}// end namespace

View File

@ -0,0 +1,53 @@
// ==============================================================
// 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_CONFIG_H_
#define _GLEST_GAME_CONFIG_H_
#include "properties.h"
namespace Glest{ namespace Game{
using Shared::Util::Properties;
// =====================================================
// class Config
//
// Game configuration
// =====================================================
class Config{
private:
Properties properties;
private:
Config();
public:
static Config &getInstance();
void save(const string &path="glest.ini");
int getInt(const string &key) const;
bool getBool(const string &key) const;
float getFloat(const string &key) const;
const string &getString(const string &key) const;
void setInt(const string &key, int value);
void setBool(const string &key, bool value);
void setFloat(const string &key, float value);
void setString(const string &key, const string &value);
string toString();
};
}}//end namespace
#endif

View File

@ -0,0 +1,144 @@
// ==============================================================
// 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 "core_data.h"
#include "logger.h"
#include "renderer.h"
#include "graphics_interface.h"
#include "config.h"
#include "util.h"
#include "leak_dumper.h"
using namespace Shared::Sound;
using namespace Shared::Graphics;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class CoreData
// =====================================================
// ===================== PUBLIC ========================
CoreData &CoreData::getInstance(){
static CoreData coreData;
return coreData;
}
CoreData::~CoreData(){
deleteValues(waterSounds.getSounds().begin(), waterSounds.getSounds().end());
}
void CoreData::load(){
const string dir="data/core";
Logger::getInstance().add("Core data");
Renderer &renderer= Renderer::getInstance();
//textures
backgroundTexture= renderer.newTexture2D(rsGlobal);
backgroundTexture->setMipmap(false);
backgroundTexture->getPixmap()->load(dir+"/menu/textures/back.tga");
fireTexture= renderer.newTexture2D(rsGlobal);
fireTexture->setFormat(Texture::fAlpha);
fireTexture->getPixmap()->init(1);
fireTexture->getPixmap()->load(dir+"/misc_textures/fire_particle.tga");
snowTexture= renderer.newTexture2D(rsGlobal);
snowTexture->setMipmap(false);
snowTexture->setFormat(Texture::fAlpha);
snowTexture->getPixmap()->init(1);
snowTexture->getPixmap()->load(dir+"/misc_textures/snow_particle.tga");
customTexture= renderer.newTexture2D(rsGlobal);
customTexture->getPixmap()->load("data/core/menu/textures/custom_texture.tga");
logoTexture= renderer.newTexture2D(rsGlobal);
logoTexture->setMipmap(false);
logoTexture->getPixmap()->load(dir+"/menu/textures/logo.tga");
waterSplashTexture= renderer.newTexture2D(rsGlobal);
waterSplashTexture->setFormat(Texture::fAlpha);
waterSplashTexture->getPixmap()->init(1);
waterSplashTexture->getPixmap()->load(dir+"/misc_textures/water_splash.tga");
buttonSmallTexture= renderer.newTexture2D(rsGlobal);
buttonSmallTexture->getPixmap()->load(dir+"/menu/textures/button_small.tga");
buttonBigTexture= renderer.newTexture2D(rsGlobal);
buttonBigTexture->getPixmap()->load(dir+"/menu/textures/button_big.tga");
//display font
Config &config= Config::getInstance();
string displayFontName= config.getString("FontDisplay");
displayFont= renderer.newFont(rsGlobal);
displayFont->setType(displayFontName);
displayFont->setSize(computeFontSize(15));
//menu fonts
string menuFontName= config.getString("FontMenu");
menuFontSmall= renderer.newFont(rsGlobal);
menuFontSmall->setType(menuFontName);
menuFontSmall->setSize(computeFontSize(12));
menuFontNormal= renderer.newFont(rsGlobal);
menuFontNormal->setType(menuFontName);
menuFontNormal->setSize(computeFontSize(16));
menuFontNormal->setWidth(Font::wBold);
menuFontBig= renderer.newFont(rsGlobal);
menuFontBig->setType(menuFontName);
menuFontBig->setSize(computeFontSize(20));
menuFontVeryBig= renderer.newFont(rsGlobal);
menuFontVeryBig->setType(menuFontName);
menuFontVeryBig->setSize(computeFontSize(25));
//console font
string consoleFontName= Config::getInstance().getString("FontConsole");
consoleFont= renderer.newFont(rsGlobal);
consoleFont->setType(consoleFontName);
consoleFont->setSize(computeFontSize(16));
//sounds
clickSoundA.load(dir+"/menu/sound/click_a.wav");
clickSoundB.load(dir+"/menu/sound/click_b.wav");
clickSoundC.load(dir+"/menu/sound/click_c.wav");
introMusic.open(dir+"/menu/music/intro_music.ogg");
introMusic.setNext(&menuMusic);
menuMusic.open(dir+"/menu/music/menu_music.ogg");
menuMusic.setNext(&menuMusic);
waterSounds.resize(6);
for(int i=0; i<6; ++i){
waterSounds[i]= new StaticSound();
waterSounds[i]->load(dir+"/water_sounds/water"+intToStr(i)+".wav");
}
}
int CoreData::computeFontSize(int size){
int screenH= Config::getInstance().getInt("ScreenHeight");
int rs= size*screenH/750;
if(rs<12){
rs= 12;
}
return rs;
}
// ================== PRIVATE ========================
}}//end namespace

View File

@ -0,0 +1,98 @@
// ==============================================================
// 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_COREDATA_H_
#define _GLEST_GAME_COREDATA_H_
#include <string>
#include "sound.h"
#include "font.h"
#include "texture.h"
#include "sound_container.h"
namespace Glest{ namespace Game{
using Shared::Graphics::Texture2D;
using Shared::Graphics::Texture3D;
using Shared::Graphics::Font2D;
using Shared::Sound::StrSound;
using Shared::Sound::StaticSound;
// =====================================================
// class CoreData
//
/// Data shared ammont all the ProgramStates
// =====================================================
class CoreData{
private:
StrSound introMusic;
StrSound menuMusic;
StaticSound clickSoundA;
StaticSound clickSoundB;
StaticSound clickSoundC;
SoundContainer waterSounds;
Texture2D *logoTexture;
Texture2D *backgroundTexture;
Texture2D *fireTexture;
Texture2D *snowTexture;
Texture2D *waterSplashTexture;
Texture2D *customTexture;
Texture2D *buttonSmallTexture;
Texture2D *buttonBigTexture;
Font2D *displayFont;
Font2D *menuFontNormal;
Font2D *menuFontSmall;
Font2D *menuFontBig;
Font2D *menuFontVeryBig;
Font2D *consoleFont;
public:
static CoreData &getInstance();
~CoreData();
void load();
Texture2D *getBackgroundTexture() const {return backgroundTexture;}
Texture2D *getFireTexture() const {return fireTexture;}
Texture2D *getSnowTexture() const {return snowTexture;}
Texture2D *getLogoTexture() const {return logoTexture;}
Texture2D *getWaterSplashTexture() const {return waterSplashTexture;}
Texture2D *getCustomTexture() const {return customTexture;}
Texture2D *getButtonSmallTexture() const {return buttonSmallTexture;}
Texture2D *getButtonBigTexture() const {return buttonBigTexture;}
StrSound *getIntroMusic() {return &introMusic;}
StrSound *getMenuMusic() {return &menuMusic;}
StaticSound *getClickSoundA() {return &clickSoundA;}
StaticSound *getClickSoundB() {return &clickSoundB;}
StaticSound *getClickSoundC() {return &clickSoundC;}
StaticSound *getWaterSound() {return waterSounds.getRandSound();}
Font2D *getDisplayFont() const {return displayFont;}
Font2D *getMenuFontSmall() const {return menuFontSmall;}
Font2D *getMenuFontNormal() const {return menuFontNormal;}
Font2D *getMenuFontBig() const {return menuFontBig;}
Font2D *getMenuFontVeryBig() const {return menuFontVeryBig;}
Font2D *getConsoleFont() const {return consoleFont;}
private:
CoreData(){};
int computeFontSize(int size);
};
}} //end namespace
#endif

View File

@ -0,0 +1,76 @@
// ==============================================================
// 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 "lang.h"
#include <stdexcept>
#include "logger.h"
#include "util.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class Lang
// =====================================================
Lang &Lang::getInstance(){
static Lang lang;
return lang;
}
void Lang::loadStrings(const string &language){
this->language= language;
strings.clear();
strings.load("data/lang/"+language+".lng");
}
void Lang::loadScenarioStrings(const string &scenarioDir, const string &scenarioName){
string path= scenarioDir + "/" + scenarioName + "/" + scenarioName + "_" + language + ".lng";
scenarioStrings.clear();
//try to load the current language first
if(fileExists(path)){
scenarioStrings.load(path);
}
else{
//try english otherwise
string path= scenarioDir + "/" +scenarioName + "/" + scenarioName + "_english.lng";
if(fileExists(path)){
scenarioStrings.load(path);
}
}
}
string Lang::get(const string &s){
try{
return strings.getString(s);
}
catch(exception &){
return "???" + s + "???";
}
}
string Lang::getScenarioString(const string &s){
try{
return scenarioStrings.getString(s);
}
catch(exception &){
return "???" + s + "???";
}
}
}}//end namespace

View File

@ -0,0 +1,46 @@
// ==============================================================
// 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_LANG_H_
#define _GLEST_GAME_LANG_H_
#include "properties.h"
namespace Glest{ namespace Game{
using Shared::Util::Properties;
// =====================================================
// class Lang
//
// String table
// =====================================================
class Lang{
private:
string language;
Properties strings;
Properties scenarioStrings;
private:
Lang(){};
public:
static Lang &getInstance();
void loadStrings(const string &language);
void loadScenarioStrings(const string &scenarioDir, const string &scenarioName);
string get(const string &s);
string getScenarioString(const string &s);
};
}}//end namespace
#endif

View File

@ -0,0 +1,77 @@
// ==============================================================
// 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 "metrics.h"
#include "element_type.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class Metrics
// =====================================================
Metrics::Metrics(){
Config &config= Config::getInstance();
virtualW= 1000;
virtualH= 750;
screenW= config.getInt("ScreenWidth");
screenH= config.getInt("ScreenHeight");
minimapX= 10;
minimapY= 750-128-30+16;
minimapW= 128;
minimapH= 128;
displayX= 800;
displayY= 250;
displayW= 128;
displayH= 480;
}
const Metrics &Metrics::getInstance(){
static const Metrics metrics;
return metrics;
}
float Metrics::getAspectRatio() const{
return static_cast<float>(screenW)/screenH;
}
int Metrics::toVirtualX(int w) const{
return w*virtualW/screenW;
}
int Metrics::toVirtualY(int h) const{
return h*virtualH/screenH;
}
bool Metrics::isInDisplay(int x, int y) const{
return
x > displayX &&
y > displayY &&
x < displayX+displayW &&
y < displayY+displayH;
}
bool Metrics::isInMinimap(int x, int y) const{
return
x > minimapX &&
y > minimapY &&
x < minimapX+minimapW &&
y < minimapY+minimapH;
}
}}// end namespace

View File

@ -0,0 +1,67 @@
// ==============================================================
// 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_METRICS_H_
#define _GLEST_GAME_METRICS_H_
#include "config.h"
namespace Glest{ namespace Game{
// =====================================================
// class Metrics
// =====================================================
class Metrics{
private:
int virtualW;
int virtualH;
int screenW;
int screenH;
int minimapX;
int minimapY;
int minimapW;
int minimapH;
int displayX;
int displayY;
int displayH;
int displayW;
private:
Metrics();
public:
static const Metrics &getInstance();
int getVirtualW() const {return virtualW;}
int getVirtualH() const {return virtualH;}
int getScreenW() const {return screenW;}
int getScreenH() const {return screenH;}
int getMinimapX() const {return minimapX;}
int getMinimapY() const {return minimapY;}
int getMinimapW() const {return minimapW;}
int getMinimapH() const {return minimapH;}
int getDisplayX() const {return displayX;}
int getDisplayY() const {return displayY;}
int getDisplayH() const {return displayH;}
int getDisplayW() const {return displayW;}
float getAspectRatio() const;
int toVirtualX(int w) const;
int toVirtualY(int h) const;
bool isInDisplay(int x, int y) const;
bool isInMinimap(int x, int y) const;
};
}}//end namespace
#endif

View File

@ -0,0 +1,240 @@
// ==============================================================
// 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 "particle_type.h"
#include "util.h"
#include "core_data.h"
#include "xml_parser.h"
#include "renderer.h"
#include "config.h"
#include "game_constants.h"
#include "leak_dumper.h"
using namespace Shared::Xml;
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class ParticleSystemType
// =====================================================
ParticleSystemType::ParticleSystemType(){
}
void ParticleSystemType::load(const XmlNode *particleSystemNode, const string &dir){
Renderer &renderer= Renderer::getInstance();
//texture
const XmlNode *textureNode= particleSystemNode->getChild("texture");
bool textureEnabled= textureNode->getAttribute("value")->getBoolValue();
if(textureEnabled){
texture= renderer.newTexture2D(rsGame);
if(textureNode->getAttribute("luminance")->getBoolValue()){
texture->setFormat(Texture::fAlpha);
texture->getPixmap()->init(1);
}
else{
texture->getPixmap()->init(4);
}
texture->load(dir + "/" + textureNode->getAttribute("path")->getRestrictedValue());
}
else{
texture= NULL;
}
//model
const XmlNode *modelNode= particleSystemNode->getChild("model");
bool modelEnabled= modelNode->getAttribute("value")->getBoolValue();
if(modelEnabled){
string path= modelNode->getAttribute("path")->getRestrictedValue();
model= renderer.newModel(rsGame);
model->load(dir + "/" + path);
}
else{
model= NULL;
}
//primitive
const XmlNode *primitiveNode= particleSystemNode->getChild("primitive");
primitive= primitiveNode->getAttribute("value")->getRestrictedValue();
//offset
const XmlNode *offsetNode= particleSystemNode->getChild("offset");
offset.x= offsetNode->getAttribute("x")->getFloatValue();
offset.y= offsetNode->getAttribute("y")->getFloatValue();
offset.z= offsetNode->getAttribute("z")->getFloatValue();
//color
const XmlNode *colorNode= particleSystemNode->getChild("color");
color.x= colorNode->getAttribute("red")->getFloatValue(0.f, 1.0f);
color.y= colorNode->getAttribute("green")->getFloatValue(0.f, 1.0f);
color.z= colorNode->getAttribute("blue")->getFloatValue(0.f, 1.0f);
color.w= colorNode->getAttribute("alpha")->getFloatValue(0.f, 1.0f);
//color
const XmlNode *colorNoEnergyNode= particleSystemNode->getChild("color-no-energy");
colorNoEnergy.x= colorNoEnergyNode->getAttribute("red")->getFloatValue(0.f, 1.0f);
colorNoEnergy.y= colorNoEnergyNode->getAttribute("green")->getFloatValue(0.f, 1.0f);
colorNoEnergy.z= colorNoEnergyNode->getAttribute("blue")->getFloatValue(0.f, 1.0f);
colorNoEnergy.w= colorNoEnergyNode->getAttribute("alpha")->getFloatValue(0.f, 1.0f);
//size
const XmlNode *sizeNode= particleSystemNode->getChild("size");
size= sizeNode->getAttribute("value")->getFloatValue();
//sizeNoEnergy
const XmlNode *sizeNoEnergyNode= particleSystemNode->getChild("size-no-energy");
sizeNoEnergy= sizeNoEnergyNode->getAttribute("value")->getFloatValue();
//speed
const XmlNode *speedNode= particleSystemNode->getChild("speed");
speed= speedNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps;
//gravity
const XmlNode *gravityNode= particleSystemNode->getChild("gravity");
gravity= gravityNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps;
//emission rate
const XmlNode *emissionRateNode= particleSystemNode->getChild("emission-rate");
emissionRate= emissionRateNode->getAttribute("value")->getIntValue();
//energy max
const XmlNode *energyMaxNode= particleSystemNode->getChild("energy-max");
energyMax= energyMaxNode->getAttribute("value")->getIntValue();
//speed
const XmlNode *energyVarNode= particleSystemNode->getChild("energy-var");
energyVar= energyVarNode->getAttribute("value")->getIntValue();
}
void ParticleSystemType::setValues(AttackParticleSystem *ats){
ats->setTexture(texture);
ats->setPrimitive(AttackParticleSystem::strToPrimitive(primitive));
ats->setOffset(offset);
ats->setColor(color);
ats->setColorNoEnergy(colorNoEnergy);
ats->setSpeed(speed);
ats->setGravity(gravity);
ats->setParticleSize(size);
ats->setSizeNoEnergy(sizeNoEnergy);
ats->setEmissionRate(emissionRate);
ats->setMaxParticleEnergy(energyMax);
ats->setVarParticleEnergy(energyVar);
ats->setModel(model);
}
// ===========================================================
// class ParticleSystemTypeProjectile
// ===========================================================
void ParticleSystemTypeProjectile::load(const string &dir, const string &path){
try{
XmlTree xmlTree;
xmlTree.load(path);
const XmlNode *particleSystemNode= xmlTree.getRootNode();
ParticleSystemType::load(particleSystemNode, dir);
//trajectory values
const XmlNode *tajectoryNode= particleSystemNode->getChild("trajectory");
trajectory= tajectoryNode->getAttribute("type")->getRestrictedValue();
//trajectory speed
const XmlNode *tajectorySpeedNode= tajectoryNode->getChild("speed");
trajectorySpeed= tajectorySpeedNode->getAttribute("value")->getFloatValue()/GameConstants::updateFps;
if(trajectory=="parabolic" || trajectory=="spiral"){
//trajectory scale
const XmlNode *tajectoryScaleNode= tajectoryNode->getChild("scale");
trajectoryScale= tajectoryScaleNode->getAttribute("value")->getFloatValue();
}
else{
trajectoryScale= 1.0f;
}
if(trajectory=="spiral"){
//trajectory frequency
const XmlNode *tajectoryFrequencyNode= tajectoryNode->getChild("frequency");
trajectoryFrequency= tajectoryFrequencyNode->getAttribute("value")->getFloatValue();
}
else{
trajectoryFrequency= 1.0f;
}
}
catch(const exception &e){
throw runtime_error("Error loading ParticleSystem: "+ path + "\n" +e.what());
}
}
ProjectileParticleSystem *ParticleSystemTypeProjectile::create(){
ProjectileParticleSystem *ps= new ProjectileParticleSystem();
ParticleSystemType::setValues(ps);
ps->setTrajectory(ProjectileParticleSystem::strToTrajectory(trajectory));
ps->setTrajectorySpeed(trajectorySpeed);
ps->setTrajectoryScale(trajectoryScale);
ps->setTrajectoryFrequency(trajectoryFrequency);
return ps;
}
// ===========================================================
// class ParticleSystemTypeSplash
// ===========================================================
void ParticleSystemTypeSplash::load(const string &dir, const string &path){
try{
XmlTree xmlTree;
xmlTree.load(path);
const XmlNode *particleSystemNode= xmlTree.getRootNode();
ParticleSystemType::load(particleSystemNode, dir);
//emission rate fade
const XmlNode *emissionRateFadeNode= particleSystemNode->getChild("emission-rate-fade");
emissionRateFade= emissionRateFadeNode->getAttribute("value")->getIntValue();
//spread values
const XmlNode *verticalSpreadNode= particleSystemNode->getChild("vertical-spread");
verticalSpreadA= verticalSpreadNode->getAttribute("a")->getFloatValue(0.0f, 1.0f);
verticalSpreadB= verticalSpreadNode->getAttribute("b")->getFloatValue(-1.0f, 1.0f);
const XmlNode *horizontalSpreadNode= particleSystemNode->getChild("horizontal-spread");
horizontalSpreadA= horizontalSpreadNode->getAttribute("a")->getFloatValue(0.0f, 1.0f);
horizontalSpreadB= horizontalSpreadNode->getAttribute("b")->getFloatValue(-1.0f, 1.0f);
}
catch(const exception &e){
throw runtime_error("Error loading ParticleSystem: "+ path + "\n" +e.what());
}
}
SplashParticleSystem *ParticleSystemTypeSplash::create(){
SplashParticleSystem *ps= new SplashParticleSystem();
ParticleSystemType::setValues(ps);
ps->setEmissionRateFade(emissionRateFade);
ps->setVerticalSpreadA(verticalSpreadA);
ps->setVerticalSpreadB(verticalSpreadB);
ps->setHorizontalSpreadA(horizontalSpreadA);
ps->setHorizontalSpreadB(horizontalSpreadB);
return ps;
}
}}//end mamespace

View File

@ -0,0 +1,104 @@
// ==============================================================
// 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_PARTICLETYPE_H_
#define _GLEST_GAME_PARTICLETYPE_H_
#include <string>
#include "particle.h"
#include "factory.h"
#include "texture.h"
#include "vec.h"
#include "xml_parser.h"
using std::string;
namespace Glest{ namespace Game{
using Shared::Graphics::ParticleSystem;
using Shared::Graphics::AttackParticleSystem;
using Shared::Graphics::ProjectileParticleSystem;
using Shared::Graphics::SplashParticleSystem;
using Shared::Graphics::Texture2D;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Vec4f;
using Shared::Graphics::Model;
using Shared::Util::MultiFactory;
using Shared::Xml::XmlNode;
// ===========================================================
// class ParticleSystemType
//
/// A type of particle system
// ===========================================================
class ParticleSystemType{
protected:
string type;
Texture2D *texture;
Model *model;
string primitive;
Vec3f offset;
Vec4f color;
Vec4f colorNoEnergy;
float size;
float sizeNoEnergy;
float speed;
float gravity;
int emissionRate;
int energyMax;
int energyVar;
public:
ParticleSystemType();
void load(const XmlNode *particleSystemNode, const string &dir);
protected:
void setValues(AttackParticleSystem *ats);
};
// ===========================================================
// class ParticleSystemTypeProjectile
// ===========================================================
class ParticleSystemTypeProjectile: public ParticleSystemType{
private:
string trajectory;
float trajectorySpeed;
float trajectoryScale;
float trajectoryFrequency;
public:
void load(const string &dir, const string &path);
ProjectileParticleSystem *create();
};
// ===========================================================
// class ParticleSystemTypeSplash
// ===========================================================
class ParticleSystemTypeSplash: public ParticleSystemType{
public:
void load(const string &dir, const string &path);
SplashParticleSystem *create();
private:
int emissionRateFade;
float verticalSpreadA;
float verticalSpreadB;
float horizontalSpreadA;
float horizontalSpreadB;
};
}}//end namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
// ==============================================================
// 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_RENDERER_H_
#define _GLEST_GAME_RENDERER_H_
#include "vec.h"
#include "math_util.h"
#include "model.h"
#include "particle.h"
#include "pixmap.h"
#include "font.h"
#include "matrix.h"
#include "selection.h"
#include "components.h"
#include "texture.h"
#include "model_manager.h"
#include "graphics_factory_gl.h"
#include "font_manager.h"
#include "camera.h"
namespace Glest{ namespace Game{
using Shared::Graphics::Texture2D;
using Shared::Graphics::Texture3D;
using Shared::Graphics::ModelRenderer;
using Shared::Graphics::TextRenderer2D;
using Shared::Graphics::ParticleRenderer;
using Shared::Graphics::ParticleManager;
using Shared::Graphics::ModelManager;
using Shared::Graphics::TextureManager;
using Shared::Graphics::FontManager;
using Shared::Graphics::Font2D;
using Shared::Graphics::Matrix4f;
using Shared::Graphics::Vec2i;
using Shared::Graphics::Quad2i;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Model;
using Shared::Graphics::ParticleSystem;
using Shared::Graphics::Pixmap2D;
using Shared::Graphics::Camera;
//non shared classes
class Config;
class Game;
class MainMenu;
class Console;
class MenuBackground;
class ChatManager;
enum ResourceScope{
rsGlobal,
rsMenu,
rsGame,
rsCount
};
// ===========================================================
// class Renderer
//
/// OpenGL renderer, uses the shared library
// ===========================================================
class Renderer{
public:
//progress bar
static const int maxProgressBar;
static const Vec4f progressBarBack1;
static const Vec4f progressBarBack2;
static const Vec4f progressBarFront1;
static const Vec4f progressBarFront2;
//sun and moon
static const float sunDist;
static const float moonDist;
static const float lightAmbFactor;
//mouse
static const int maxMouse2dAnim;
//texture units
static const GLenum baseTexUnit;
static const GLenum fowTexUnit;
static const GLenum shadowTexUnit;
//selection
static const float selectionCircleRadius;
static const float magicCircleRadius;
//perspective values
static const float perspFov;
static const float perspNearPlane;
static const float perspFarPlane;
//default values
static const float ambFactor;
static const Vec4f defSpecularColor;
static const Vec4f defDiffuseColor;
static const Vec4f defAmbientColor;
static const Vec4f defColor;
static const Vec4f fowColor;
//light
static const float maxLightDist;
public:
enum Shadows{
sDisabled,
sProjected,
sShadowMapping,
sCount
};
private:
//config
int maxLights;
bool photoMode;
int shadowTextureSize;
int shadowFrameSkip;
float shadowAlpha;
bool focusArrows;
bool textures3D;
Shadows shadows;
//game
const Game *game;
//misc
int triangleCount;
int pointCount;
Quad2i visibleQuad;
Vec4f nearestLightPos;
//renderers
ModelRenderer *modelRenderer;
TextRenderer2D *textRenderer;
ParticleRenderer *particleRenderer;
//texture managers
ModelManager *modelManager[rsCount];
TextureManager *textureManager[rsCount];
FontManager *fontManager[rsCount];
ParticleManager *particleManager[rsCount];
//state lists
GLuint list3d;
GLuint list2d;
GLuint list3dMenu;
//shadows
GLuint shadowMapHandle;
Matrix4f shadowMapMatrix;
int shadowMapFrame;
//water
float waterAnim;
private:
Renderer();
~Renderer();
public:
static Renderer &getInstance();
//init
void init();
void initGame(Game *game);
void initMenu(MainMenu *mm);
void reset3d();
void reset2d();
void reset3dMenu();
//end
void end();
void endMenu();
void endGame();
//get
int getTriangleCount() const {return triangleCount;}
int getPointCount() const {return pointCount;}
//misc
void reloadResources();
//engine interface
Model *newModel(ResourceScope rs);
Texture2D *newTexture2D(ResourceScope rs);
Texture3D *newTexture3D(ResourceScope rs);
Font2D *newFont(ResourceScope rs);
TextRenderer2D *getTextRenderer() const {return textRenderer;}
void manageParticleSystem(ParticleSystem *particleSystem, ResourceScope rs);
void updateParticleManager(ResourceScope rs);
void renderParticleManager(ResourceScope rs);
void swapBuffers();
//lights and camera
void setupLighting();
void loadGameCameraMatrix();
void loadCameraMatrix(const Camera *camera);
void computeVisibleQuad();
//basic rendering
void renderMouse2d(int mouseX, int mouseY, int anim, float fade= 0.f);
void renderMouse3d();
void renderBackground(const Texture2D *texture);
void renderTextureQuad(int x, int y, int w, int h, const Texture2D *texture, float alpha=1.f);
void renderConsole(const Console *console);
void renderChatManager(const ChatManager *chatManager);
void renderResourceStatus();
void renderSelectionQuad();
void renderText(const string &text, const Font2D *font, float alpha, int x, int y, bool centered= false);
void renderText(const string &text, const Font2D *font, const Vec3f &color, int x, int y, bool centered= false);
void renderTextShadow(const string &text, const Font2D *font, int x, int y, bool centered= false);
//components
void renderLabel(const GraphicLabel *label);
void renderButton(const GraphicButton *button);
void renderListBox(const GraphicListBox *listBox);
void renderMessageBox(const GraphicMessageBox *listBox);
//complex rendering
void renderSurface();
void renderObjects();
void renderWater();
void renderUnits();
void renderSelectionEffects();
void renderWaterEffects();
void renderMinimap();
void renderDisplay();
void renderMenuBackground(const MenuBackground *menuBackground);
//computing
bool computePosition(const Vec2i &screenPos, Vec2i &worldPos);
void computeSelected(Selection::UnitContainer &units, const Vec2i &posDown, const Vec2i &posUp);
//gl wrap
string getGlInfo();
string getGlMoreInfo();
void autoConfig();
//clear
void clearBuffers();
void clearZBuffer();
//shadows
void renderShadowsToTexture();
//misc
void loadConfig();
void saveScreen(const string &path);
Quad2i getVisibleQuad() const {return visibleQuad;}
//static
static Shadows strToShadows(const string &s);
static string shadowsToStr(Shadows shadows);
private:
//private misc
float computeSunAngle(float time);
float computeMoonAngle(float time);
Vec4f computeSunPos(float time);
Vec4f computeMoonPos(float time);
Vec3f computeLightColor(float time);
Vec4f computeWaterColor(float waterLevel, float cellHeight);
void checkExtension(const string &extension, const string &msg);
//selection render
void renderObjectsFast();
void renderUnitsFast();
//gl requirements
void checkGlCaps();
void checkGlOptionalCaps();
//gl init
void init3dList();
void init2dList();
void init3dListMenu(MainMenu *mm);
//misc
void loadProjectionMatrix();
void enableProjectiveTexturing();
//private aux drawing
void renderSelectionCircle(Vec3f v, int size, float radius);
void renderArrow(const Vec3f &pos1, const Vec3f &pos2, const Vec3f &color, float width);
void renderProgressBar(int size, int x, int y, Font2D *font);
void renderTile(const Vec2i &pos);
void renderQuad(int x, int y, int w, int h, const Texture2D *texture);
//static
static Texture2D::Filter strToTextureFilter(const string &s);
};
}} //end namespace
#endif

View File

@ -0,0 +1,83 @@
// ==============================================================
// 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 "display.h"
#include "metrics.h"
#include "command_type.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class Display
// =====================================================
Display::Display(){
clear();
}
//misc
void Display::clear(){
for(int i=0; i<upCellCount; ++i){
upImages[i]= NULL;
}
for(int i=0; i<downCellCount; ++i){
downImages[i]= NULL;
downLighted[i]= true;
commandTypes[i]= NULL;
commandClasses[i]= ccNull;
}
downSelectedPos= invalidPos;
title.clear();
text.clear();
progressBar= -1;
}
int Display::computeDownIndex(int x, int y){
y= y-(downY-cellSideCount*imageSize);
if(y>imageSize*cellSideCount){
return invalidPos;
}
int cellX= x/imageSize;
int cellY= (y/imageSize) % cellSideCount;
int index= (cellSideCount-cellY-1)*cellSideCount+cellX;;
if(index<0 || index>=downCellCount || downImages[index]==NULL){
index= invalidPos;
}
return index;
}
int Display::computeDownX(int index) const{
return (index % cellSideCount) * imageSize;
}
int Display::computeDownY(int index) const{
return Display::downY - (index/cellSideCount)*imageSize - imageSize;
}
int Display::computeUpX(int index) const{
return (index % cellSideCount) * imageSize;
}
int Display::computeUpY(int index) const{
return Metrics::getInstance().getDisplayH() - (index/cellSideCount)*imageSize - imageSize;
}
}}//end namespace

View File

@ -0,0 +1,96 @@
// ==============================================================
// 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_DISPLAY_H_
#define _GLEST_GAME_DISPLAY_H_
#include <string>
#include "texture.h"
#include "util.h"
#include "command_type.h"
#include "game_util.h"
using std::string;
using Shared::Graphics::Texture2D;
using Shared::Graphics::Vec3f;
using Shared::Util::replaceBy;
namespace Glest{ namespace Game{
// =====================================================
// class Display
//
/// Display for unit commands, and unit selection
// =====================================================
class Display{
public:
static const int cellSideCount= 4;
static const int upCellCount= cellSideCount*cellSideCount;
static const int downCellCount= cellSideCount*cellSideCount;
static const int imageSize= 32;
static const int invalidPos= -1;
static const int downY = imageSize*9;
static const int infoStringY= imageSize*4;
private:
string title;
string text;
string infoText;
const Texture2D *upImages[upCellCount];
const Texture2D *downImages[downCellCount];
bool downLighted[downCellCount];
const CommandType *commandTypes[downCellCount];
CommandClass commandClasses[downCellCount];
int progressBar;
int downSelectedPos;
public:
Display();
//get
string getTitle() const {return title;}
string getText() const {return text;}
string getInfoText() const {return infoText;}
const Texture2D *getUpImage(int index) const {return upImages[index];}
const Texture2D *getDownImage(int index) const {return downImages[index];}
bool getDownLighted(int index) const {return downLighted[index];}
const CommandType *getCommandType(int i) {return commandTypes[i];}
CommandClass getCommandClass(int i) {return commandClasses[i];}
int getProgressBar() const {return progressBar;}
int getDownSelectedPos() const {return downSelectedPos;}
//set
void setTitle(const string title) {this->title= formatString(title);}
void setText(const string &text) {this->text= formatString(text);}
void setInfoText(const string infoText) {this->infoText= formatString(infoText);}
void setUpImage(int i, const Texture2D *image) {upImages[i]= image;}
void setDownImage(int i, const Texture2D *image) {downImages[i]= image;}
void setCommandType(int i, const CommandType *ct) {commandTypes[i]= ct;}
void setCommandClass(int i, const CommandClass cc) {commandClasses[i]= cc;}
void setDownLighted(int i, bool lighted) {downLighted[i]= lighted;}
void setProgressBar(int i) {progressBar= i;}
void setDownSelectedPos(int i) {downSelectedPos= i;}
//misc
void clear();
int computeDownIndex(int x, int y);
int computeDownX(int index) const;
int computeDownY(int index) const;
int computeUpX(int index) const;
int computeUpY(int index) const;
};
}}//end namespace
#endif

View File

@ -0,0 +1,849 @@
// ==============================================================
// 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(){
posObjWorld= Vec2i(54, 14);
computeSelection= false;
validPosObjWorld= false;
activeCommandType= NULL;
activeCommandClass= ccStop;
selectingBuilding= false;
selectingPos= false;
selectingMeetingPoint= false;
activePos= invalidPos;
}
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){
mouseDownDisplayUnitBuild(posDisplay);
}
else{
mouseDownDisplayUnitSkills(posDisplay);
}
}
else{
resetState();
}
}
computeDisplay();
}
}
void Gui::mouseMoveDisplay(int x, int y){
computeInfoString(computePosDisplay(x, y));
}
void Gui::mouseDownLeftGraphics(int x, int y){
if(selectingPos){
//give standard orders
giveTwoClickOrders(x, y);
resetState();
}
//set meeting point
else if(selectingMeetingPoint){
if(selection.isComandable()){
Vec2i targetPos;
if(Renderer::getInstance().computePosition(Vec2i(x, y), targetPos)){
commander->trySetMeetingPoint(selection.getFrontUnit(), targetPos);
}
}
resetState();
}
else{
selectionQuad.setPosDown(Vec2i(x, y));
computeSelected(false);
}
computeDisplay();
}
void Gui::mouseDownRightGraphics(int x, int y){
if(selectingPos || selectingMeetingPoint){
resetState();
}
else if(selection.isComandable()){
giveDefaultOrders(x, y);
}
computeDisplay();
}
void Gui::mouseUpLeftGraphics(int x, int y){
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();
}
}
}
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()){
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);
}
}
void Gui::hotKey(char key){
if(key==' '){
centerCameraOnSelection();
}
else if(key=='I'){
selectInterestingUnit(iutIdleHarvester);
}
else if(key=='B'){
selectInterestingUnit(iutBuiltBuilding);
}
else if(key=='R'){
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

201
source/glest_game/gui/gui.h Normal file
View File

@ -0,0 +1,201 @@
// ==============================================================
// 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_GUI_H_
#define _GLEST_GAME_GUI_H_
#include "resource.h"
#include "command_type.h"
#include "display.h"
#include "commander.h"
#include "console.h"
#include "selection.h"
#include "random.h"
using Shared::Util::Random;
namespace Glest{ namespace Game{
class Unit;
class World;
class CommandType;
class GameCamera;
class Game;
enum DisplayState{
dsEmpty,
dsUnitSkills,
dsUnitBuild,
dsEnemy
};
// =====================================================
// class Mouse3d
// =====================================================
class Mouse3d{
public:
static const float fadeSpeed;
private:
bool enabled;
int rot;
float fade;
public:
Mouse3d();
void enable();
void update();
bool isEnabled() const {return enabled;}
float getFade() const {return fade;}
int getRot() const {return rot;}
};
// =====================================================
// class SelectionQuad
// =====================================================
class SelectionQuad{
private:
Vec2i posDown;
Vec2i posUp;
bool enabled;
public:
SelectionQuad();
bool isEnabled() const {return enabled;}
Vec2i getPosDown() const {return posDown;}
Vec2i getPosUp() const {return posUp;}
void setPosDown(const Vec2i &posDown);
void setPosUp(const Vec2i &posUp);
void disable();
};
// =====================================================
// class Gui
//
/// In game GUI
// =====================================================
class Gui{
public:
static const int maxSelBuff= 128*5;
static const int upgradeDisplayIndex= 8;
static const int cancelPos= 15;
static const int meetingPointPos= 14;
static const int imageCount= 16;
static const int invalidPos= -1;
static const int doubleClickSelectionRadius= 20;
private:
//External objects
Random random;
const Commander *commander;
const World *world;
GameCamera *gameCamera;
Console *console;
//Positions
Vec2i posObjWorld; //world coords
bool validPosObjWorld;
bool computeSelection;
//display
const UnitType *choosenBuildingType;
const CommandType *activeCommandType;
CommandClass activeCommandClass;
int activePos;
//composite
Display display;
Mouse3d mouse3d;
Selection selection;
SelectionQuad selectionQuad;
//states
bool selectingBuilding;
bool selectingPos;
bool selectingMeetingPoint;
public:
Gui();
void init(Game *game);
void end();
//get
Vec2i getPosObjWorld() const {return posObjWorld;}
const UnitType *getBuilding() const;
const Mouse3d *getMouse3d() const {return &mouse3d;}
const Display *getDisplay() const {return &display;}
const Selection *getSelection() const {return &selection;}
const SelectionQuad *getSelectionQuad() const {return &selectionQuad;}
bool isSelected(const Unit *unit) const {return selection.hasUnit(unit);}
bool isValidPosObjWorld() const {return validPosObjWorld;}
bool isSelecting() const {return selectionQuad.isEnabled();}
bool isSelectingPos() const {return selectingPos;}
bool isSelectingBuilding() const {return selectingBuilding;}
bool isPlacingBuilding() const;
//set
void invalidatePosObjWorld();
void setComputeSelectionFlag();
//events
void update();
void tick();
bool mouseValid(int x, int y);
void mouseDownLeftDisplay(int x, int y);
void mouseMoveDisplay(int x, int y);
void mouseDownLeftGraphics(int x, int y);
void mouseDownRightGraphics(int x, int y);
void mouseUpLeftGraphics(int x, int y);
void mouseMoveGraphics(int x, int y);
void mouseDoubleClickLeftGraphics(int x, int y);
void groupKey(int groupIndex);
void hotKey(char key);
//misc
void onSelectionChanged();
private:
//orders
void giveDefaultOrders(int x, int y);
void giveOneClickOrders();
void giveTwoClickOrders(int x, int y);
//hotkeys
void centerCameraOnSelection();
void selectInterestingUnit(InterestingUnitType iut);
void clickCommonCommand(CommandClass commandClass);
//misc
int computePosDisplay(int x, int y);
void computeDisplay();
void resetState();
void mouseDownDisplayUnitSkills(int posDisplay);
void mouseDownDisplayUnitBuild(int posDisplay);
void computeInfoString(int posDisplay);
void addOrdersResultToConsole(CommandClass cc, CommandResult rr);
bool isSharedCommandClass(CommandClass commandClass);
void computeSelected(bool doubleCkick);
bool computeTarget(const Vec2i &screenPos, Vec2i &targetPos, const Unit *&targetUnit);
};
}} //end namespace
#endif

View File

@ -0,0 +1,204 @@
// ==============================================================
// 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 "selection.h"
#include <algorithm>
#include "unit_type.h"
#include "gui.h"
#include "leak_dumper.h"
using namespace std;
namespace Glest{ namespace Game{
// =====================================================
// class Selection
// =====================================================
void Selection::init(Gui *gui, int factionIndex){
this->factionIndex= factionIndex;
this->gui= gui;
}
Selection::~Selection(){
clear();
}
void Selection::select(Unit *unit){
//check size
if(selectedUnits.size()>=maxUnits){
return;
}
//check if already selected
for(int i=0; i<selectedUnits.size(); ++i){
if(selectedUnits[i]==unit){
return;
}
}
//check if dead
if(unit->isDead()){
return;
}
//check if multisel
if(!unit->getType()->getMultiSelect() && !isEmpty()){
return;
}
//check if enemy
if(unit->getFactionIndex()!=factionIndex && !isEmpty()){
return;
}
//check existing enemy
if(selectedUnits.size()==1 && selectedUnits.front()->getFactionIndex()!=factionIndex){
clear();
}
//check existing multisel
if(selectedUnits.size()==1 && !selectedUnits.front()->getType()->getMultiSelect()){
clear();
}
unit->addObserver(this);
selectedUnits.push_back(unit);
gui->onSelectionChanged();
}
void Selection::select(const UnitContainer &units){
//add units to gui
for(UnitIterator it= units.begin(); it!=units.end(); ++it){
select(*it);
}
}
void Selection::unSelect(const UnitContainer &units){
//add units to gui
for(UnitIterator it= units.begin(); it!=units.end(); ++it){
for(int i=0; i<selectedUnits.size(); ++i){
if(selectedUnits[i]==*it){
unSelect(i);
}
}
}
}
void Selection::unSelect(int i){
//remove unit from list
selectedUnits.erase(selectedUnits.begin()+i);
gui->onSelectionChanged();
}
void Selection::clear(){
//clear list
selectedUnits.clear();
}
bool Selection::isUniform() const{
if(selectedUnits.empty()){
return true;
}
const UnitType *ut= selectedUnits.front()->getType();
for(int i=0; i<selectedUnits.size(); ++i){
if(selectedUnits[i]->getType()!=ut){
return false;
}
}
return true;
}
bool Selection::isEnemy() const{
return selectedUnits.size()==1 && selectedUnits.front()->getFactionIndex()!=factionIndex;
}
bool Selection::isComandable() const{
return
!isEmpty() &&
!isEnemy() &&
!(selectedUnits.size()==1 && !selectedUnits.front()->isOperative());
}
bool Selection::isCancelable() const{
return
selectedUnits.size()>1 ||
(selectedUnits.size()==1 && selectedUnits[0]->anyCommand());
}
bool Selection::isMeetable() const{
return
isUniform() &&
isComandable() &&
selectedUnits.front()->getType()->getMeetingPoint();
}
Vec3f Selection::getRefPos() const{
return getFrontUnit()->getCurrVector();
}
bool Selection::hasUnit(const Unit* unit) const{
return find(selectedUnits.begin(), selectedUnits.end(), unit)!=selectedUnits.end();
}
void Selection::assignGroup(int groupIndex){
//clear group
groups[groupIndex].clear();
//assign new group
for(int i=0; i<selectedUnits.size(); ++i){
groups[groupIndex].push_back(selectedUnits[i]);
}
}
void Selection::recallGroup(int groupIndex){
clear();
for(int i=0; i<groups[groupIndex].size(); ++i){
select(groups[groupIndex][i]);
}
}
void Selection::unitEvent(UnitObserver::Event event, const Unit *unit){
if(event==UnitObserver::eKill){
//remove from selection
for(int i=0; i<selectedUnits.size(); ++i){
if(selectedUnits[i]==unit){
selectedUnits.erase(selectedUnits.begin()+i);
break;
}
}
//remove from groups
for(int i=0; i<maxGroups; ++i){
for(int j=0; j<groups[i].size(); ++j){
if(groups[i][j]==unit){
groups[i].erase(groups[i].begin()+j);
break;
}
}
}
//notify gui
gui->onSelectionChanged();
}
}
}}//end namespace

View File

@ -0,0 +1,76 @@
// ==============================================================
// 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_SELECTION_
#define _GLEST_GAME_SELECTION_
#include "unit.h"
#include <vector>
using std::vector;
namespace Glest{ namespace Game{
class Gui;
// =====================================================
// class Selection
//
/// List of selected units and groups
// =====================================================
class Selection: public UnitObserver{
public:
typedef vector<Unit*> UnitContainer;
typedef UnitContainer::const_iterator UnitIterator;
public:
static const int maxGroups= 10;
static const int maxUnits= 16;
private:
int factionIndex;
UnitContainer selectedUnits;
UnitContainer groups[maxGroups];
Gui *gui;
public:
void init(Gui *gui, int factionIndex);
virtual ~Selection();
void select(Unit *unit);
void select(const UnitContainer &units);
void unSelect(int unitIndex);
void unSelect(const UnitContainer &units);
void clear();
bool isEmpty() const {return selectedUnits.empty();}
bool isUniform() const;
bool isEnemy() const;
bool isComandable() const;
bool isCancelable() const;
bool isMeetable() const;
int getCount() const {return selectedUnits.size();}
const Unit *getUnit(int i) const {return selectedUnits[i];}
const Unit *getFrontUnit() const {return selectedUnits.front();}
Vec3f getRefPos() const;
bool hasUnit(const Unit* unit) const;
void assignGroup(int groupIndex);
void recallGroup(int groupIndex);
virtual void unitEvent(UnitObserver::Event event, const Unit *unit);
};
}}//end namespace
#endif

View File

@ -0,0 +1,150 @@
// ==============================================================
// 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 "battle_end.h"
#include "main_menu.h"
#include "program.h"
#include "core_data.h"
#include "lang.h"
#include "util.h"
#include "renderer.h"
#include "main_menu.h"
#include "sound_renderer.h"
#include "components.h"
#include "metrics.h"
#include "stats.h"
#include "auto_test.h"
#include "leak_dumper.h"
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class BattleEnd
// =====================================================
BattleEnd::BattleEnd(Program *program, const Stats *stats):
ProgramState(program){
this->stats= *stats;
}
BattleEnd::~BattleEnd(){
SoundRenderer::getInstance().playMusic(CoreData::getInstance().getMenuMusic());
}
void BattleEnd::update(){
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateBattleEnd(program);
}
}
void BattleEnd::render(){
Renderer &renderer= Renderer::getInstance();
TextRenderer2D *textRenderer= renderer.getTextRenderer();
Lang &lang= Lang::getInstance();
renderer.clearBuffers();
renderer.reset2d();
renderer.renderBackground(CoreData::getInstance().getBackgroundTexture());
textRenderer->begin(CoreData::getInstance().getMenuFontBig());
int lm= 80;
int bm= 100;
for(int i=0; i<stats.getFactionCount(); ++i){
int textX= lm+300+i*120;
int team= stats.getTeam(i) + 1;
int kills= stats.getKills(i);
int deaths= stats.getDeaths(i);
int unitsProduced= stats.getUnitsProduced(i);
int resourcesHarvested= stats.getResourcesHarvested(i);
int score= kills*100 + unitsProduced*50 + resourcesHarvested/10;
string controlString;
switch(stats.getControl(i)){
case ctCpuEasy:
controlString= lang.get("CpuEasy");
break;
case ctCpu:
controlString= lang.get("Cpu");
break;
case ctCpuUltra:
controlString= lang.get("CpuUltra");
break;
case ctCpuMega:
controlString= lang.get("CpuMega");
break;
case ctNetwork:
controlString= lang.get("Network");
break;
case ctHuman:
controlString= lang.get("Human");
break;
default:
assert(false);
};
textRenderer->render((lang.get("Player")+" "+intToStr(i+1)).c_str(), textX, bm+400);
textRenderer->render(stats.getVictory(i)? lang.get("Victory").c_str(): lang.get("Defeat").c_str(), textX, bm+360);
textRenderer->render(controlString, textX, bm+320);
textRenderer->render(stats.getFactionTypeName(i), textX, bm+280);
textRenderer->render(intToStr(team).c_str(), textX, bm+240);
textRenderer->render(intToStr(kills).c_str(), textX, bm+200);
textRenderer->render(intToStr(deaths).c_str(), textX, bm+160);
textRenderer->render(intToStr(unitsProduced).c_str(), textX, bm+120);
textRenderer->render(intToStr(resourcesHarvested).c_str(), textX, bm+80);
textRenderer->render(intToStr(score).c_str(), textX, bm+20);
}
textRenderer->render(lang.get("Result"), lm+50, bm+360);
textRenderer->render(lang.get("Control"), lm+50, bm+320);
textRenderer->render(lang.get("Faction"), lm+50, bm+280);
textRenderer->render(lang.get("Team"), lm+50, bm+240);
textRenderer->render(lang.get("Kills"), lm+50, bm+200);
textRenderer->render(lang.get("Deaths"), lm+50, bm+160);
textRenderer->render(lang.get("UnitsProduced"), lm+50, bm+120);
textRenderer->render(lang.get("ResourcesHarvested"), lm+50, bm+80);
textRenderer->render(lang.get("Score"), lm+50, bm+20);
textRenderer->end();
textRenderer->begin(CoreData::getInstance().getMenuFontVeryBig());
string header = stats.getDescription() + " - ";
if(stats.getVictory(stats.getThisFactionIndex())){
header += lang.get("Victory");
}
else{
header += lang.get("Defeat");
}
textRenderer->render(header, lm+250, bm+550);
textRenderer->end();
renderer.swapBuffers();
}
void BattleEnd::keyDown(char key){
program->setState(new MainMenu(program));
}
void BattleEnd::mouseDownLeft(int x, int y){
program->setState(new MainMenu(program));
}
}}//end namespace

View File

@ -0,0 +1,41 @@
// ==============================================================
// 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_BATTLEEND_H_
#define _GLEST_GAME_BATTLEEND_H_
#include "program.h"
#include "stats.h"
namespace Glest{ namespace Game{
// =====================================================
// class BattleEnd
//
/// ProgramState representing the end of the game
// =====================================================
class BattleEnd: public ProgramState{
private:
Stats stats;
public:
BattleEnd(Program *program, const Stats *stats);
~BattleEnd();
virtual void update();
virtual void render();
virtual void keyDown(char key);
virtual void mouseDownLeft(int x, int y);
};
}}//end namespace
#endif

View File

@ -0,0 +1,133 @@
// ==============================================================
// 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 "intro.h"
#include "main_menu.h"
#include "util.h"
#include "game_util.h"
#include "config.h"
#include "program.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "metrics.h"
#include "auto_test.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class Text
// =====================================================
Text::Text(const string &text, const Vec2i &pos, int time, const Font2D *font){
this->text= text;
this->pos= pos;
this->time= time;
this->texture= NULL;
this->font= font;
}
Text::Text(const Texture2D *texture, const Vec2i &pos, const Vec2i &size, int time){
this->pos= pos;
this->size= size;
this->time= time;
this->texture= texture;
this->font= NULL;
}
// =====================================================
// class Intro
// =====================================================
const int Intro::introTime= 24000;
const int Intro::appearTime= 2500;
const int Intro::showTime= 2500;
const int Intro::disapearTime= 2500;
Intro::Intro(Program *program):
ProgramState(program)
{
CoreData &coreData= CoreData::getInstance();
const Metrics &metrics= Metrics::getInstance();
int w= metrics.getVirtualW();
int h= metrics.getVirtualH();
timer=0;
texts.push_back(Text(coreData.getLogoTexture(), Vec2i(w/2-128, h/2-64), Vec2i(256, 128), 4000));
texts.push_back(Text(glestVersionString, Vec2i(w/2+64, h/2-32), 4000, coreData.getMenuFontNormal()));
texts.push_back(Text("www.glest.org", Vec2i(w/2, h/2), 12000, coreData.getMenuFontVeryBig()));
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
soundRenderer.playMusic(CoreData::getInstance().getIntroMusic());
}
void Intro::update(){
timer++;
if(timer>introTime*GameConstants::updateFps/1000){
program->setState(new MainMenu(program));
}
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateIntro(program);
}
}
void Intro::render(){
Renderer &renderer= Renderer::getInstance();
int difTime;
renderer.reset2d();
renderer.clearBuffers();
for(int i=0; i<texts.size(); ++i){
Text *text= &texts[i];
difTime= 1000*timer/GameConstants::updateFps-text->getTime();
if(difTime>0 && difTime<appearTime+showTime+disapearTime){
float alpha= 1.f;
if(difTime>0 && difTime<appearTime){
//apearing
alpha= static_cast<float>(difTime)/appearTime;
}
else if(difTime>0 && difTime<appearTime+showTime+disapearTime){
//disappearing
alpha= 1.f- static_cast<float>(difTime-appearTime-showTime)/disapearTime;
}
if(!text->getText().empty()){
renderer.renderText(
text->getText(), text->getFont(), alpha,
text->getPos().x, text->getPos().y, true);
}
if(text->getTexture()!=NULL){
renderer.renderTextureQuad(
text->getPos().x, text->getPos().y,
text->getSize().x, text->getSize().y,
text->getTexture(), alpha);
}
}
}
renderer.swapBuffers();
}
void Intro::keyDown(char key){
mouseUpLeft(0, 0);
}
void Intro::mouseUpLeft(int x, int y){
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
soundRenderer.stopMusic(CoreData::getInstance().getIntroMusic());
soundRenderer.playMusic(CoreData::getInstance().getMenuMusic());
program->setState(new MainMenu(program));
}
}}//end namespace

View File

@ -0,0 +1,84 @@
// ==============================================================
// 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_INTRO_H_
#define _GLEST_GAME_INTRO_H_
#include <vector>
#include "program.h"
#include "font.h"
#include "vec.h"
#include "texture.h"
using std::vector;
using Shared::Graphics::Vec2i;
using Shared::Graphics::Vec2f;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Font2D;
using Shared::Graphics::Texture2D;
namespace Glest{ namespace Game{
// =====================================================
// class Text
// =====================================================
class Text{
private:
string text;
Vec2i pos;
Vec2i size;
int time;
const Font2D *font;
const Texture2D *texture;
public:
Text(const string &text, const Vec2i &pos, int time, const Font2D *font);
Text(const Texture2D *texture, const Vec2i &pos, const Vec2i &size, int time);
const string &getText() const {return text;}
const Font2D *getFont() const {return font;}
const Vec2i &getPos() const {return pos;}
const Vec2i &getSize() const {return size;}
int getTime() const {return time;}
const Texture2D *getTexture() const {return texture;}
};
// =====================================================
// class Intro
//
/// ProgramState representing the intro
// =====================================================
class Intro: public ProgramState{
private:
static const int introTime;
static const int appearTime;
static const int showTime;
static const int disapearTime;
private:
vector<Text> texts;
int timer;
public:
Intro(Program *program);
virtual void update();
virtual void render();
virtual void keyDown(char key);
virtual void mouseUpLeft(int x, int y);
};
}}//end namespace
#endif

View File

@ -0,0 +1,159 @@
// ==============================================================
// 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 "main.h"
#include <string>
#include <cstdlib>
#include "game.h"
#include "main_menu.h"
#include "program.h"
#include "config.h"
#include "metrics.h"
#include "game_util.h"
#include "platform_util.h"
#include "platform_main.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class ExceptionHandler
// =====================================================
class ExceptionHandler: public PlatformExceptionHandler{
public:
virtual void handle(){
message("An error ocurred and Glest will close.\nPlease report this bug to "+mailString+", attaching the generated "+getCrashDumpFileName()+" file.");
}
};
// =====================================================
// class MainWindow
// =====================================================
MainWindow::MainWindow(Program *program){
this->program= program;
}
MainWindow::~MainWindow(){
delete program;
}
void MainWindow::eventMouseDown(int x, int y, MouseButton mouseButton){
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){
if(mouseButton==mbLeft){
program->mouseUpLeft(x, getH() - y);
}
}
void MainWindow::eventMouseDoubleClick(int x, int y, MouseButton mouseButton){
if(mouseButton == mbLeft){
program->mouseDoubleClickLeft(x, getH() - y);
}
}
void MainWindow::eventMouseMove(int x, int y, const MouseState *ms){
program->mouseMove(x, getH() - y, ms);
}
void MainWindow::eventKeyDown(char key){
program->keyDown(key);
}
void MainWindow::eventKeyUp(char key){
program->keyUp(key);
}
void MainWindow::eventKeyPress(char c){
program->keyPress(c);
}
void MainWindow::eventActivate(bool active){
if(!active){
//minimize();
}
}
void MainWindow::eventResize(SizeState sizeState){
program->resize(sizeState);
}
void MainWindow::eventClose(){
delete program;
program= NULL;
}
// =====================================================
// Main
// =====================================================
int glestMain(int argc, char** argv){
MainWindow *mainWindow= NULL;
Program *program= NULL;
ExceptionHandler exceptionHandler;
exceptionHandler.install( getCrashDumpFileName() );
try{
Config &config = Config::getInstance();
showCursor(config.getBool("Windowed"));
program= new Program();
mainWindow= new MainWindow(program);
//parse command line
if(argc==2 && string(argv[1])=="-server"){
program->initServer(mainWindow);
}
else if(argc==3 && string(argv[1])=="-client"){
program->initClient(mainWindow, Ip(argv[2]));
}
else{
program->initNormal(mainWindow);
}
//main loop
while(Window::handleEvent()){
program->loop();
}
}
catch(const exception &e){
restoreVideoMode();
exceptionMessage(e);
}
delete mainWindow;
return 0;
}
}}//end namespace
MAIN_FUNCTION(Glest::Game::glestMain)

View File

@ -0,0 +1,55 @@
// ==============================================================
// 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_MAIN_H_
#define _GLEST_GAME_MAIN_H_
#include <ctime>
#include "program.h"
#include "window_gl.h"
using Shared::Platform::MouseButton;
using Shared::Platform::MouseState;
namespace Glest{ namespace Game{
// =====================================================
// class MainWindow
//
/// Main program window
// =====================================================
class MainWindow: public WindowGl{
private:
Program* program;
public:
MainWindow(Program *program);
~MainWindow();
void setProgram(Program *program) {this->program= program;}
virtual void eventMouseDown(int x, int y, MouseButton mouseButton);
virtual void eventMouseUp(int x, int y, MouseButton mouseButton);
virtual void eventMouseDoubleClick(int x, int y, MouseButton mouseButton);
virtual void eventMouseMove(int x, int y, const MouseState *mouseState);
virtual void eventKeyDown(char key);
virtual void eventKeyUp(char key);
virtual void eventKeyPress(char c);
virtual void eventActivate(bool active);
virtual void eventResize(SizeState sizeState);
virtual void eventClose();
};
}}//end namespace
#endif

View File

@ -0,0 +1,255 @@
// ==============================================================
// 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 "program.h"
#include "sound.h"
#include "renderer.h"
#include "config.h"
#include "game.h"
#include "main_menu.h"
#include "intro.h"
#include "world.h"
#include "main.h"
#include "sound_renderer.h"
#include "logger.h"
#include "profiler.h"
#include "core_data.h"
#include "metrics.h"
#include "network_manager.h"
#include "menu_state_custom_game.h"
#include "menu_state_join_game.h"
#include "leak_dumper.h"
using namespace Shared::Util;
using namespace Shared::Graphics;
using namespace Shared::Graphics::Gl;
// =====================================================
// class Program
// =====================================================
namespace Glest{ namespace Game{
const int Program::maxTimes= 10;
// ===================== PUBLIC ========================
Program::Program(){
programState= NULL;
}
void Program::initNormal(WindowGl *window){
init(window);
setState(new Intro(this));
}
void Program::initServer(WindowGl *window){
MainMenu* mainMenu= NULL;
init(window);
mainMenu= new MainMenu(this);
setState(mainMenu);
mainMenu->setState(new MenuStateCustomGame(this, mainMenu, true));
}
void Program::initClient(WindowGl *window, const Ip &serverIp){
MainMenu* mainMenu= NULL;
init(window);
mainMenu= new MainMenu(this);
setState(mainMenu);
mainMenu->setState(new MenuStateJoinGame(this, mainMenu, true, serverIp));
}
Program::~Program(){
delete programState;
Renderer::getInstance().end();
//restore video mode
restoreDisplaySettings();
}
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::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);
}
void Program::keyUp(char key){
programState->keyUp(key);
}
void Program::keyPress(char c){
programState->keyPress(c);
}
void Program::loop(){
//render
programState->render();
//update camera
while(updateCameraTimer.isTime()){
programState->updateCamera();
}
//update world
while(updateTimer.isTime()){
GraphicComponent::update();
programState->update();
SoundRenderer::getInstance().update();
NetworkManager::getInstance().update();
}
//fps timer
while(fpsTimer.isTime()){
programState->tick();
}
}
void Program::resize(SizeState sizeState){
switch(sizeState){
case ssMinimized:
//restoreVideoMode();
break;
case ssMaximized:
case ssRestored:
//setDisplaySettings();
//renderer.reloadResources();
break;
}
}
// ==================== misc ====================
void Program::setState(ProgramState *programState){
delete this->programState;
this->programState= programState;
programState->load();
programState->init();
updateTimer.reset();
updateCameraTimer.reset();
fpsTimer.reset();
}
void Program::exit(){
window->destroy();
}
// ==================== PRIVATE ====================
void Program::init(WindowGl *window){
this->window= window;
Config &config= Config::getInstance();
//set video mode
setDisplaySettings();
//window
window->setText("Glest");
window->setStyle(config.getBool("Windowed")? wsWindowedFixed: wsFullscreen);
window->setPos(0, 0);
window->setSize(config.getInt("ScreenWidth"), config.getInt("ScreenHeight"));
window->create();
//timers
fpsTimer.init(1, maxTimes);
updateTimer.init(GameConstants::updateFps, maxTimes);
updateCameraTimer.init(GameConstants::cameraFps, maxTimes);
//log start
Logger &logger= Logger::getInstance();
logger.setFile("glest.log");
logger.clear();
//lang
Lang &lang= Lang::getInstance();
lang.loadStrings(config.getString("Lang"));
//render
Renderer &renderer= Renderer::getInstance();
window->initGl(config.getInt("ColorBits"), config.getInt("DepthBits"), config.getInt("StencilBits"));
window->makeCurrentGl();
//coreData, needs renderer, but must load before renderer init
CoreData &coreData= CoreData::getInstance();
coreData.load();
//init renderer (load global textures)
renderer.init();
//sound
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
soundRenderer.init(window);
}
void Program::setDisplaySettings(){
Config &config= Config::getInstance();
if(!config.getBool("Windowed")){
int freq= config.getInt("RefreshFrequency");
int colorBits= config.getInt("ColorBits");
int screenWidth= config.getInt("ScreenWidth");
int screenHeight= config.getInt("ScreenHeight");
if(!(changeVideoMode(screenWidth, screenHeight, colorBits, freq) ||
changeVideoMode(screenWidth, screenHeight, colorBits, 0)))
{
throw runtime_error(
"Error setting video mode: " +
intToStr(screenWidth) + "x" + intToStr(screenHeight) + "x" + intToStr(colorBits));
}
}
}
void Program::restoreDisplaySettings(){
Config &config= Config::getInstance();
if(!config.getBool("Windowed")){
restoreVideoMode();
}
}
}}//end namespace

View File

@ -0,0 +1,113 @@
// ==============================================================
// 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_PROGRAM_H_
#define _GLEST_GAME_PROGRAM_H_
#include "context.h"
#include "platform_util.h"
#include "window_gl.h"
#include "socket.h"
using Shared::Graphics::Context;
using Shared::Platform::WindowGl;
using Shared::Platform::SizeState;
using Shared::Platform::MouseState;
using Shared::Platform::PerformanceTimer;
using Shared::Platform::Ip;
namespace Glest{ namespace Game{
class Program;
class MainWindow;
// =====================================================
// class ProgramState
//
/// Base class for all program states:
/// Intro, MainMenu, Game, BattleEnd (State Design pattern)
// =====================================================
class ProgramState{
protected:
Program *program;
public:
ProgramState(Program *program) {this->program= program;}
virtual ~ProgramState(){};
virtual void render()=0;
virtual void update(){};
virtual void updateCamera(){};
virtual void tick(){};
virtual void init(){};
virtual void load(){};
virtual void end(){};
virtual void mouseDownLeft(int x, int y){};
virtual void mouseUpLeft(int x, int y){};
virtual void mouseDownRight(int x, int y){};
virtual void mouseDoubleClickLeft(int x, int y){};
virtual void mouseMove(int x, int y, const MouseState *mouseState){};
virtual void keyDown(char key){};
virtual void keyUp(char key){};
virtual void keyPress(char c){};
};
// ===============================
// class Program
// ===============================
class Program{
private:
static const int maxTimes;
private:
ProgramState *programState;
PerformanceTimer fpsTimer;
PerformanceTimer updateTimer;
PerformanceTimer updateCameraTimer;
WindowGl *window;
public:
Program();
~Program();
void initNormal(WindowGl *window);
void initServer(WindowGl *window);
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 mouseMove(int x, int y, const MouseState *mouseState);
void keyDown(char key);
void keyUp(char key);
void keyPress(char c);
void loop();
void resize(SizeState sizeState);
//misc
void setState(ProgramState *programState);
void exit();
private:
void init(WindowGl *window);
void setDisplaySettings();
void restoreDisplaySettings();
};
}} //end namespace
#endif

View File

@ -0,0 +1,194 @@
// ==============================================================
// 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 "main_menu.h"
#include "renderer.h"
#include "sound.h"
#include "config.h"
#include "program.h"
#include "game_util.h"
#include "game.h"
#include "platform_util.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "faction.h"
#include "metrics.h"
#include "network_manager.h"
#include "network_message.h"
#include "socket.h"
#include "menu_state_root.h"
#include "leak_dumper.h"
using namespace Shared::Sound;
using namespace Shared::Platform;
using namespace Shared::Util;
using namespace Shared::Graphics;
using namespace Shared::Xml;
namespace Glest{ namespace Game{
// =====================================================
// class MainMenu
// =====================================================
// ===================== PUBLIC ========================
MainMenu::MainMenu(Program *program):
ProgramState(program)
{
mouseX=100;
mouseY=100;
state= NULL;
this->program= program;
fps= 0;
lastFps= 0;
setState(new MenuStateRoot(program, this));
}
MainMenu::~MainMenu(){
delete state;
Renderer::getInstance().endMenu();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
soundRenderer.stopAllSounds();
}
void MainMenu::init(){
Renderer::getInstance().initMenu(this);
}
//asynchronus render update
void MainMenu::render(){
Config &config= Config::getInstance();
Renderer &renderer= Renderer::getInstance();
CoreData &coreData= CoreData::getInstance();
fps++;
renderer.clearBuffers();
//3d
renderer.reset3dMenu();
renderer.clearZBuffer();
renderer.loadCameraMatrix(menuBackground.getCamera());
renderer.renderMenuBackground(&menuBackground);
renderer.renderParticleManager(rsMenu);
//2d
renderer.reset2d();
state->render();
renderer.renderMouse2d(mouseX, mouseY, mouse2dAnim);
if(config.getBool("DebugMode")){
renderer.renderText(
"FPS: " + intToStr(lastFps),
coreData.getMenuFontNormal(), Vec3f(1.f), 10, 10, false);
}
renderer.swapBuffers();
}
//syncronus update
void MainMenu::update(){
Renderer::getInstance().updateParticleManager(rsMenu);
mouse2dAnim= (mouse2dAnim +1) % Renderer::maxMouse2dAnim;
menuBackground.update();
state->update();
}
void MainMenu::tick(){
lastFps= fps;
fps= 0;
}
//event magangement: mouse click
void MainMenu::mouseMove(int x, int y, const MouseState *ms){
mouseX= x; mouseY= y;
state->mouseMove(x, y, ms);
}
//returns if exiting
void MainMenu::mouseDownLeft(int x, int y){
state->mouseClick(x, y, mbLeft);
}
void MainMenu::mouseDownRight(int x, int y){
state->mouseClick(x, y, mbRight);
}
void MainMenu::keyDown(char key){
state->keyDown(key);
}
void MainMenu::keyPress(char c){
state->keyPress(c);
}
void MainMenu::setState(MenuState *state){
delete this->state;
this->state= state;
GraphicComponent::resetFade();
menuBackground.setTargetCamera(state->getCamera());
}
// =====================================================
// class MenuState
// =====================================================
MenuState::MenuState(Program *program, MainMenu *mainMenu, const string &stateName){
this->program= program;
this->mainMenu= mainMenu;
//camera
XmlTree xmlTree;
xmlTree.load("data/core/menu/menu.xml");
const XmlNode *menuNode= xmlTree.getRootNode();
const XmlNode *cameraNode= menuNode->getChild("camera");
//position
const XmlNode *positionNode= cameraNode->getChild(stateName + "-position");
Vec3f startPosition;
startPosition.x= positionNode->getAttribute("x")->getFloatValue();
startPosition.y= positionNode->getAttribute("y")->getFloatValue();
startPosition.z= positionNode->getAttribute("z")->getFloatValue();
camera.setPosition(startPosition);
//rotation
const XmlNode *rotationNode= cameraNode->getChild(stateName + "-rotation");
Vec3f startRotation;
startRotation.x= rotationNode->getAttribute("x")->getFloatValue();
startRotation.y= rotationNode->getAttribute("y")->getFloatValue();
startRotation.z= rotationNode->getAttribute("z")->getFloatValue();
camera.setOrientation(Quaternion(EulerAngles(
degToRad(startRotation.x),
degToRad(startRotation.y),
degToRad(startRotation.z))));
}
}}//end namespace

View File

@ -0,0 +1,121 @@
// ==============================================================
// 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_MAINMENU_H_
#define _GLEST_GAME_MAINMENU_H_
#include "lang.h"
#include "console.h"
#include "vec.h"
#include "world.h"
#include "program.h"
#include "components.h"
#include "menu_background.h"
#include "game_settings.h"
namespace Glest{ namespace Game{
//misc consts
struct MapInfo{
Vec2i size;
int players;
string desc;
};
struct ScenarioInfo
{
int difficulty;
ControlType factionControls[GameConstants::maxPlayers];
int teams[GameConstants::maxPlayers];
string factionTypeNames[GameConstants::maxPlayers];
string mapName;
string tilesetName;
string techTreeName;
bool defaultUnits;
bool defaultResources;
bool defaultVictoryConditions;
string desc;
};
class MenuState;
// =====================================================
// class MainMenu
//
/// Main menu ProgramState
// =====================================================
class MainMenu: public ProgramState{
private:
//up
Program *program;
//shared
GameSettings gameSettings;
MenuBackground menuBackground;
MenuState *state;
//shared
int mouseX, mouseY;
int mouse2dAnim;
int fps, lastFps;
public:
MainMenu(Program *program);
~MainMenu();
MenuBackground *getMenuBackground() {return &menuBackground;}
virtual void render();
virtual void update();
virtual void tick();
virtual void init();
virtual void mouseMove(int x, int y, const MouseState *mouseState);
virtual void mouseDownLeft(int x, int y);
virtual void mouseDownRight(int x, int y);
virtual void keyDown(char key);
virtual void keyPress(char key);
void setState(MenuState *state);
};
// ===============================
// class MenuState
// ===============================
class MenuState{
protected:
Program *program;
MainMenu *mainMenu;
Camera camera;
public:
MenuState(Program *program, MainMenu *mainMenu, const string &stateName);
virtual ~MenuState(){};
virtual void mouseClick(int x, int y, MouseButton mouseButton)=0;
virtual void mouseMove(int x, int y, const MouseState *mouseState)=0;
virtual void render()=0;
virtual void update(){};
virtual void keyDown(char key){};
virtual void keyPress(char c){};
const Camera *getCamera() const {return &camera;}
};
}}//end namespace
#endif

View File

@ -0,0 +1,180 @@
// ==============================================================
// 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 "menu_background.h"
#include <ctime>
#include "renderer.h"
#include "core_data.h"
#include "config.h"
#include "xml_parser.h"
#include "util.h"
#include "game_constants.h"
#include "leak_dumper.h"
using namespace Shared::Util;
using namespace Shared::Xml;
using namespace Shared::Graphics;
namespace Glest{ namespace Game{
// =====================================================
// class MenuBackground
// =====================================================
MenuBackground::MenuBackground(){
Renderer &renderer= Renderer::getInstance();
//load data
XmlTree xmlTree;
xmlTree.load("data/core/menu/menu.xml");
const XmlNode *menuNode= xmlTree.getRootNode();
//water
const XmlNode *waterNode= menuNode->getChild("water");
water= waterNode->getAttribute("value")->getBoolValue();
if(water){
waterHeight= waterNode->getAttribute("height")->getFloatValue();
//water texture
waterTexture= renderer.newTexture2D(rsMenu);
waterTexture->getPixmap()->init(4);
waterTexture->getPixmap()->load("data/core/menu/textures/water.tga");
}
//fog
const XmlNode *fogNode= menuNode->getChild("fog");
fog= fogNode->getAttribute("value")->getBoolValue();
if(fog){
fogDensity= fogNode->getAttribute("density")->getFloatValue();
}
//rain
rain= menuNode->getChild("rain")->getAttribute("value")->getBoolValue();
if(rain){
RainParticleSystem *rps= new RainParticleSystem();
rps->setSpeed(12.f/GameConstants::updateFps);
rps->setEmissionRate(25);
rps->setWind(-90.f, 4.f/GameConstants::updateFps);
rps->setPos(Vec3f(0.f, 25.f, 0.f));
rps->setColor(Vec4f(1.f, 1.f, 1.f, 0.2f));
rps->setRadius(30.f);
renderer.manageParticleSystem(rps, rsMenu);
for(int i=0; i<raindropCount; ++i){
raindropStates[i]= random.randRange(0.f, 1.f);
raindropPos[i]= computeRaindropPos();
}
}
//camera
const XmlNode *cameraNode= menuNode->getChild("camera");
//position
const XmlNode *positionNode= cameraNode->getChild("start-position");
Vec3f startPosition;
startPosition.x= positionNode->getAttribute("x")->getFloatValue();
startPosition.y= positionNode->getAttribute("y")->getFloatValue();
startPosition.z= positionNode->getAttribute("z")->getFloatValue();
camera.setPosition(startPosition);
//rotation
const XmlNode *rotationNode= cameraNode->getChild("start-rotation");
Vec3f startRotation;
startRotation.x= rotationNode->getAttribute("x")->getFloatValue();
startRotation.y= rotationNode->getAttribute("y")->getFloatValue();
startRotation.z= rotationNode->getAttribute("z")->getFloatValue();
camera.setOrientation(Quaternion(EulerAngles(
degToRad(startRotation.x),
degToRad(startRotation.y),
degToRad(startRotation.z))));
//load main model
mainModel= renderer.newModel(rsMenu);
mainModel->load("data/core/menu/main_model/menu_main.g3d");
//models
for(int i=0; i<5; ++i){
characterModels[i]= renderer.newModel(rsMenu);
characterModels[i]->load("data/core/menu/about_models/character"+intToStr(i)+".g3d");
}
//about position
positionNode= cameraNode->getChild("about-position");
aboutPosition.x= positionNode->getAttribute("x")->getFloatValue();
aboutPosition.y= positionNode->getAttribute("y")->getFloatValue();
aboutPosition.z= positionNode->getAttribute("z")->getFloatValue();
rotationNode= cameraNode->getChild("about-rotation");
targetCamera= NULL;
t= 0.f;
fade= 0.f;
anim= 0.f;
}
void MenuBackground::setTargetCamera(const Camera *targetCamera){
this->targetCamera= targetCamera;
this->lastCamera= camera;
t= 0.f;
}
void MenuBackground::update(){
//rain drops
for(int i=0; i<raindropCount; ++i){
raindropStates[i]+= 1.f / GameConstants::updateFps;
if(raindropStates[i]>=1.f){
raindropStates[i]= 0.f;
raindropPos[i]= computeRaindropPos();
}
}
if(targetCamera!=NULL){
t+= ((0.01f+(1.f-t)/10.f)/20.f)*(60.f/GameConstants::updateFps);
//interpolate position
camera.setPosition(lastCamera.getPosition().lerp(t, targetCamera->getPosition()));
//interpolate orientation
Quaternion q= lastCamera.getOrientation().lerp(t, targetCamera->getOrientation());
camera.setOrientation(q);
if(t>=1.f){
targetCamera= NULL;
t= 0.f;
}
}
//fade
if(fade<=1.f){
fade+= 0.6f/GameConstants::updateFps;
if(fade>1.f){
fade= 1.f;
}
}
//animation
anim+=(0.6f/GameConstants::updateFps)/5+random.randRange(0.f, (0.6f/GameConstants::updateFps)/5.f);
if(anim>1.f){
anim= 0.f;
}
}
Vec2f MenuBackground::computeRaindropPos(){
float f= static_cast<float>(meshSize);
return Vec2f(random.randRange(-f, f), random.randRange(-f, f));
}
}}//end namespace

View File

@ -0,0 +1,104 @@
// ==============================================================
// 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_MENUBACKGROUND_H_
#define _GLEST_GAME_MENUBACKGROUND_H_
#include "particle.h"
#include "camera.h"
#include "vec.h"
#include "texture.h"
#include "model.h"
#include "random.h"
using Shared::Graphics::RainParticleSystem;
using Shared::Graphics::FireParticleSystem;
using Shared::Graphics::Camera;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Vec2f;
using Shared::Graphics::Texture2D;
using Shared::Graphics::Model;
using Shared::Util::Random;
namespace Glest{ namespace Game{
// ===========================================================
// class MenuBackground
//
/// Holds the data to display the 3D environment
/// in the MenuState
// ===========================================================
class MenuBackground{
public:
static const int meshSize= 32;
static const int raindropCount= 1000;
static const int characterCount= 5;
private:
Model *mainModel;
//water
bool water;
float waterHeight;
Texture2D *waterTexture;
//fog
bool fog;
float fogDensity;
//rain
bool rain;
Vec2f raindropPos[raindropCount];
float raindropStates[raindropCount];
//camera
Camera camera;
Camera lastCamera;
const Camera *targetCamera;
float t;
//misc
Random random;
Model *characterModels[characterCount];
float anim;
float fade;
Vec3f aboutPosition;
public:
MenuBackground();
bool getWater() const {return water;}
float getWaterHeight() const {return waterHeight;}
bool getFog() const {return fog;}
float getFogDensity() const {return fogDensity;}
bool getRain() const {return rain;}
Texture2D *getWaterTexture() const {return waterTexture;}
const Camera *getCamera() const {return &camera;}
const Model *getCharacterModel(int i) const {return characterModels[i];}
const Model *getMainModel() const {return mainModel;}
float getFade() const {return fade;}
Vec2f getRaindropPos(int i) const {return raindropPos[i];}
float getRaindropState(int i) const {return raindropStates[i];}
float getAnim() const {return anim;}
const Vec3f &getAboutPosition() const {return aboutPosition;}
void setTargetCamera(const Camera *targetCamera);
void update();
private:
Vec2f computeRaindropPos();
};
}} //end namespace
#endif

View File

@ -0,0 +1,92 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "menu_state_about.h"
#include "renderer.h"
#include "menu_state_root.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "menu_state_options.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class MenuStateAbout
// =====================================================
MenuStateAbout::MenuStateAbout(Program *program, MainMenu *mainMenu):
MenuState(program, mainMenu, "about")
{
Lang &lang= Lang::getInstance();
//init
buttonReturn.init(460, 100, 125);
buttonReturn.setText(lang.get("Return"));
for(int i= 0; i<aboutStringCount1; ++i){
labelAbout1[i].init(100, 650-i*20);
labelAbout1[i].setText(getAboutString1(i));
}
for(int i= 0; i<aboutStringCount2; ++i){
labelAbout2[i].init(460, 650-i*20);
labelAbout2[i].setText(getAboutString2(i));
}
for(int i= 0; i<teammateCount; ++i){
labelTeammateName[i].init(100+i*180, 500);
labelTeammateRole[i].init(100+i*180, 520);
labelTeammateName[i].setText(getTeammateName(i));
labelTeammateRole[i].setText(getTeammateRole(i));
}
labelTeammateName[5].init(360, 160);
labelTeammateRole[5].init(360, 180);
labelTeammateName[6].init(540, 160);
labelTeammateRole[6].init(540, 180);
}
void MenuStateAbout::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonReturn.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateRoot(program, mainMenu));
}
}
void MenuStateAbout::mouseMove(int x, int y, const MouseState *ms){
buttonReturn.mouseMove(x, y);
}
void MenuStateAbout::render(){
Renderer &renderer= Renderer::getInstance();
renderer.renderButton(&buttonReturn);
for(int i= 0; i<aboutStringCount1; ++i){
renderer.renderLabel(&labelAbout1[i]);
}
for(int i= 0; i<aboutStringCount2; ++i){
renderer.renderLabel(&labelAbout2[i]);
}
for(int i= 0; i<teammateCount; ++i){
renderer.renderLabel(&labelTeammateName[i]);
renderer.renderLabel(&labelTeammateRole[i]);
}
}
}}//end namespace

View File

@ -0,0 +1,46 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATEABOUT_H_
#define _GLEST_GAME_MENUSTATEABOUT_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateAbout
// ===============================
class MenuStateAbout: public MenuState{
public:
static const int aboutStringCount1= 3;
static const int aboutStringCount2= 3;
static const int teammateCount= 7;
private:
GraphicButton buttonReturn;
GraphicLabel labelAbout1[aboutStringCount1];
GraphicLabel labelAbout2[aboutStringCount2];
GraphicLabel labelTeammateName[teammateCount];
GraphicLabel labelTeammateRole[teammateCount];
public:
MenuStateAbout(Program *program, MainMenu *mainMenu);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
};
}}//end namespace
#endif

View File

@ -0,0 +1,427 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2005 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 "menu_state_custom_game.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "config.h"
#include "menu_state_new_game.h"
#include "metrics.h"
#include "network_manager.h"
#include "network_message.h"
#include "client_interface.h"
#include "conversion.h"
#include "socket.h"
#include "game.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
using namespace Shared::Util;
// =====================================================
// class MenuStateCustomGame
// =====================================================
MenuStateCustomGame::MenuStateCustomGame(Program *program, MainMenu *mainMenu, bool openNetworkSlots):
MenuState(program, mainMenu, "new-game")
{
Lang &lang= Lang::getInstance();
NetworkManager &networkManager= NetworkManager::getInstance();
vector<string> results, teamItems, controlItems;
//create
buttonReturn.init(350, 200, 125);
buttonPlayNow.init(525, 200, 125);
//map listBox
findAll("maps/*.gbm", results, true);
if(results.size()==0){
throw runtime_error("There is no maps");
}
mapFiles= results;
for(int i= 0; i<results.size(); ++i){
results[i]= formatString(results[i]);
}
listBoxMap.init(200, 320, 150);
listBoxMap.setItems(results);
labelMap.init(200, 350);
labelMapInfo.init(200, 290, 200, 40);
//tileset listBox
findAll("tilesets/*.", results);
if(results.size()==0){
throw runtime_error("There is no tile set");
}
tilesetFiles= results;
for(int i= 0; i<results.size(); ++i){
results[i]= formatString(results[i]);
}
listBoxTileset.init(400, 320, 150);
listBoxTileset.setItems(results);
labelTileset.init(400, 350);
//tech Tree listBox
findAll("techs/*.", results);
if(results.size()==0){
throw runtime_error("There is no tech tree");
}
techTreeFiles= results;
for(int i= 0; i<results.size(); ++i){
results[i]= formatString(results[i]);
}
listBoxTechTree.init(600, 320, 150);
listBoxTechTree.setItems(results);
labelTechTree.init(600, 350);
//list boxes
for(int i=0; i<GameConstants::maxPlayers; ++i){
labelPlayers[i].init(200, 500-i*30);
listBoxControls[i].init(300, 500-i*30);
listBoxFactions[i].init(500, 500-i*30);
listBoxTeams[i].init(700, 500-i*30, 60);
labelNetStatus[i].init(800, 500-i*30, 60);
}
labelControl.init(300, 550, GraphicListBox::defW, GraphicListBox::defH, true);
labelFaction.init(500, 550, GraphicListBox::defW, GraphicListBox::defH, true);
labelTeam.init(700, 550, 60, GraphicListBox::defH, true);
//texts
buttonReturn.setText(lang.get("Return"));
buttonPlayNow.setText(lang.get("PlayNow"));
controlItems.push_back(lang.get("Closed"));
controlItems.push_back(lang.get("CpuEasy"));
controlItems.push_back(lang.get("Cpu"));
controlItems.push_back(lang.get("CpuUltra"));
controlItems.push_back(lang.get("CpuMega"));
controlItems.push_back(lang.get("Network"));
controlItems.push_back(lang.get("Human"));
teamItems.push_back("1");
teamItems.push_back("2");
teamItems.push_back("3");
teamItems.push_back("4");
reloadFactions();
findAll("techs/"+techTreeFiles[listBoxTechTree.getSelectedItemIndex()]+"/factions/*.", results);
if(results.size()==0){
throw runtime_error("There is no factions for this tech tree");
}
for(int i=0; i<GameConstants::maxPlayers; ++i){
labelPlayers[i].setText(lang.get("Player")+" "+intToStr(i));
listBoxTeams[i].setItems(teamItems);
listBoxTeams[i].setSelectedItemIndex(i);
listBoxControls[i].setItems(controlItems);
labelNetStatus[i].setText("");
}
labelMap.setText(lang.get("Map"));
labelTileset.setText(lang.get("Tileset"));
labelTechTree.setText(lang.get("TechTree"));
labelControl.setText(lang.get("Control"));
labelFaction.setText(lang.get("Faction"));
labelTeam.setText(lang.get("Team"));
loadMapInfo(Map::getMapPath(mapFiles[listBoxMap.getSelectedItemIndex()]), &mapInfo);
labelMapInfo.setText(mapInfo.desc);
//initialize network interface
networkManager.init(nrServer);
//init controllers
listBoxControls[0].setSelectedItemIndex(ctHuman);
if(openNetworkSlots){
for(int i= 1; i<mapInfo.players; ++i){
listBoxControls[i].setSelectedItemIndex(ctNetwork);
}
}
else{
listBoxControls[1].setSelectedItemIndex(ctCpu);
}
updateControlers();
updateNetworkSlots();
}
void MenuStateCustomGame::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface();
if(buttonReturn.mouseClick(x,y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateNewGame(program, mainMenu));
}
else if(buttonPlayNow.mouseClick(x,y)){
GameSettings gameSettings;
closeUnusedSlots();
soundRenderer.playFx(coreData.getClickSoundC());
loadGameSettings(&gameSettings);
serverInterface->launchGame(&gameSettings);
program->setState(new Game(program, &gameSettings));
}
else if(listBoxMap.mouseClick(x, y)){
loadMapInfo(Map::getMapPath(mapFiles[listBoxMap.getSelectedItemIndex()]), &mapInfo);
labelMapInfo.setText(mapInfo.desc);
updateControlers();
}
else if(listBoxTileset.mouseClick(x, y)){
}
else if(listBoxTechTree.mouseClick(x, y)){
reloadFactions();
}
else{
for(int i=0; i<mapInfo.players; ++i){
//ensure thet only 1 human player is present
if(listBoxControls[i].mouseClick(x, y)){
//look for human players
int humanIndex1= -1;
int humanIndex2= -1;
for(int j=0; j<GameConstants::maxPlayers; ++j){
ControlType ct= static_cast<ControlType>(listBoxControls[j].getSelectedItemIndex());
if(ct==ctHuman){
if(humanIndex1==-1){
humanIndex1= j;
}
else{
humanIndex2= j;
}
}
}
//no human
if(humanIndex1==-1 && humanIndex2==-1){
listBoxControls[i].setSelectedItemIndex(ctHuman);
}
//2 humans
if(humanIndex1!=-1 && humanIndex2!=-1){
listBoxControls[humanIndex1==i? humanIndex2: humanIndex1].setSelectedItemIndex(ctClosed);
}
updateNetworkSlots();
}
else if(listBoxFactions[i].mouseClick(x, y)){
}
else if(listBoxTeams[i].mouseClick(x, y)){
}
}
}
}
void MenuStateCustomGame::mouseMove(int x, int y, const MouseState *ms){
buttonReturn.mouseMove(x, y);
buttonPlayNow.mouseMove(x, y);
for(int i=0; i<GameConstants::maxPlayers; ++i){
listBoxControls[i].mouseMove(x, y);
listBoxFactions[i].mouseMove(x, y);
listBoxTeams[i].mouseMove(x, y);
}
listBoxMap.mouseMove(x, y);
listBoxTileset.mouseMove(x, y);
listBoxTechTree.mouseMove(x, y);
}
void MenuStateCustomGame::render(){
Renderer &renderer= Renderer::getInstance();
int i;
renderer.renderButton(&buttonReturn);
renderer.renderButton(&buttonPlayNow);
for(i=0; i<GameConstants::maxPlayers; ++i){
renderer.renderLabel(&labelPlayers[i]);
renderer.renderListBox(&listBoxControls[i]);
if(listBoxControls[i].getSelectedItemIndex()!=ctClosed){
renderer.renderListBox(&listBoxFactions[i]);
renderer.renderListBox(&listBoxTeams[i]);
renderer.renderLabel(&labelNetStatus[i]);
}
}
renderer.renderLabel(&labelMap);
renderer.renderLabel(&labelTileset);
renderer.renderLabel(&labelTechTree);
renderer.renderLabel(&labelControl);
renderer.renderLabel(&labelFaction);
renderer.renderLabel(&labelTeam);
renderer.renderLabel(&labelMapInfo);
renderer.renderListBox(&listBoxMap);
renderer.renderListBox(&listBoxTileset);
renderer.renderListBox(&listBoxTechTree);
}
void MenuStateCustomGame::update(){
ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface();
Lang& lang= Lang::getInstance();
for(int i= 0; i<mapInfo.players; ++i){
if(listBoxControls[i].getSelectedItemIndex()==ctNetwork){
ConnectionSlot* connectionSlot= serverInterface->getSlot(i);
assert(connectionSlot!=NULL);
if(connectionSlot->isConnected()){
labelNetStatus[i].setText(connectionSlot->getName());
}
else
{
labelNetStatus[i].setText(lang.get("NotConnected"));
}
}
else{
labelNetStatus[i].setText("");
}
}
}
void MenuStateCustomGame::loadGameSettings(GameSettings *gameSettings){
int factionCount= 0;
gameSettings->setDescription(formatString(mapFiles[listBoxMap.getSelectedItemIndex()]));
gameSettings->setMap(mapFiles[listBoxMap.getSelectedItemIndex()]);
gameSettings->setTileset(tilesetFiles[listBoxTileset.getSelectedItemIndex()]);
gameSettings->setTech(techTreeFiles[listBoxTechTree.getSelectedItemIndex()]);
gameSettings->setDefaultUnits(true);
gameSettings->setDefaultResources(true);
gameSettings->setDefaultVictoryConditions(true);
for(int i=0; i<mapInfo.players; ++i){
ControlType ct= static_cast<ControlType>(listBoxControls[i].getSelectedItemIndex());
if(ct!=ctClosed){
if(ct==ctHuman){
gameSettings->setThisFactionIndex(factionCount);
}
gameSettings->setFactionControl(factionCount, ct);
gameSettings->setTeam(factionCount, listBoxTeams[i].getSelectedItemIndex());
gameSettings->setStartLocationIndex(factionCount, i);
gameSettings->setFactionTypeName(factionCount, factionFiles[listBoxFactions[i].getSelectedItemIndex()]);
factionCount++;
}
}
gameSettings->setFactionCount(factionCount);
}
// ============ PRIVATE ===========================
void MenuStateCustomGame::loadMapInfo(string file, MapInfo *mapInfo){
struct MapFileHeader{
int32 version;
int32 maxPlayers;
int32 width;
int32 height;
int32 altFactor;
int32 waterLevel;
int8 title[128];
};
Lang &lang= Lang::getInstance();
try{
FILE *f= fopen(file.c_str(), "rb");
if(f==NULL)
throw runtime_error("Can't open file");
MapFileHeader header;
fread(&header, sizeof(MapFileHeader), 1, f);
mapInfo->size.x= header.width;
mapInfo->size.y= header.height;
mapInfo->players= header.maxPlayers;
mapInfo->desc= lang.get("MaxPlayers")+": "+intToStr(mapInfo->players)+"\n";
mapInfo->desc+=lang.get("Size")+": "+intToStr(mapInfo->size.x) + " x " + intToStr(mapInfo->size.y);
fclose(f);
}
catch(exception e){
throw runtime_error("Error loading map file: "+file+'\n'+e.what());
}
}
void MenuStateCustomGame::reloadFactions(){
vector<string> results;
findAll("techs/"+techTreeFiles[listBoxTechTree.getSelectedItemIndex()]+"/factions/*.", results);
if(results.size()==0){
throw runtime_error("There is no factions for this tech tree");
}
factionFiles= results;
for(int i= 0; i<results.size(); ++i){
results[i]= formatString(results[i]);
}
for(int i=0; i<GameConstants::maxPlayers; ++i){
listBoxFactions[i].setItems(results);
listBoxFactions[i].setSelectedItemIndex(i % results.size());
}
}
void MenuStateCustomGame::updateControlers(){
bool humanPlayer= false;
for(int i= 0; i<mapInfo.players; ++i){
if(listBoxControls[i].getSelectedItemIndex() == ctHuman){
humanPlayer= true;
}
}
if(!humanPlayer){
listBoxControls[0].setSelectedItemIndex(ctHuman);
}
for(int i= mapInfo.players; i<GameConstants::maxPlayers; ++i){
listBoxControls[i].setSelectedItemIndex(ctClosed);
}
}
void MenuStateCustomGame::closeUnusedSlots(){
ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface();
for(int i= 0; i<mapInfo.players; ++i){
if(listBoxControls[i].getSelectedItemIndex()==ctNetwork){
if(!serverInterface->getSlot(i)->isConnected()){
listBoxControls[i].setSelectedItemIndex(ctClosed);
}
}
}
updateNetworkSlots();
}
void MenuStateCustomGame::updateNetworkSlots(){
ServerInterface* serverInterface= NetworkManager::getInstance().getServerInterface();
for(int i= 0; i<GameConstants::maxPlayers; ++i){
if(serverInterface->getSlot(i)==NULL && listBoxControls[i].getSelectedItemIndex()==ctNetwork){
serverInterface->addSlot(i);
}
if(serverInterface->getSlot(i) != NULL && listBoxControls[i].getSelectedItemIndex()!=ctNetwork){
serverInterface->removeSlot(i);
}
}
}
}}//end namespace

View File

@ -0,0 +1,67 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATECUSTOMGAME_H_
#define _GLEST_GAME_MENUSTATECUSTOMGAME_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateCustomGame
// ===============================
class MenuStateCustomGame: public MenuState{
private:
GraphicButton buttonReturn;
GraphicButton buttonPlayNow;
GraphicLabel labelControl;
GraphicLabel labelFaction;
GraphicLabel labelTeam;
GraphicLabel labelMap;
GraphicLabel labelTechTree;
GraphicLabel labelTileset;
GraphicLabel labelMapInfo;
GraphicListBox listBoxMap;
GraphicListBox listBoxTechTree;
GraphicListBox listBoxTileset;
vector<string> mapFiles;
vector<string> techTreeFiles;
vector<string> tilesetFiles;
vector<string> factionFiles;
GraphicLabel labelPlayers[GameConstants::maxPlayers];
GraphicListBox listBoxControls[GameConstants::maxPlayers];
GraphicListBox listBoxFactions[GameConstants::maxPlayers];
GraphicListBox listBoxTeams[GameConstants::maxPlayers];
GraphicLabel labelNetStatus[GameConstants::maxPlayers];
MapInfo mapInfo;
public:
MenuStateCustomGame(Program *program, MainMenu *mainMenu, bool openNetworkSlots= false);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
void update();
private:
void loadGameSettings(GameSettings *gameSettings);
void loadMapInfo(string file, MapInfo *mapInfo);
void reloadFactions();
void updateControlers();
void closeUnusedSlots();
void updateNetworkSlots();
};
}}//end namespace
#endif

View File

@ -0,0 +1,68 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "menu_state_graphic_info.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "menu_state_options.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class MenuStateGraphicInfo
// =====================================================
MenuStateGraphicInfo::MenuStateGraphicInfo(Program *program, MainMenu *mainMenu):
MenuState(program, mainMenu, "info")
{
buttonReturn.init(387, 100, 125);
labelInfo.init(100, 700);
labelMoreInfo.init(100, 500);
labelMoreInfo.setFont(CoreData::getInstance().getMenuFontSmall());
Renderer &renderer= Renderer::getInstance();
glInfo= renderer.getGlInfo();
glMoreInfo= renderer.getGlMoreInfo();
}
void MenuStateGraphicInfo::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonReturn.mouseClick(x,y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateOptions(program, mainMenu));
}
}
void MenuStateGraphicInfo::mouseMove(int x, int y, const MouseState *ms){
buttonReturn.mouseMove(x, y);
}
void MenuStateGraphicInfo::render(){
Renderer &renderer= Renderer::getInstance();
Lang &lang= Lang::getInstance();
buttonReturn.setText(lang.get("Return"));
labelInfo.setText(glInfo);
labelMoreInfo.setText(glMoreInfo);
renderer.renderButton(&buttonReturn);
renderer.renderLabel(&labelInfo);
renderer.renderLabel(&labelMoreInfo);
}
}}//end namespace

View File

@ -0,0 +1,41 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATEGRAPHICINFO_H_
#define _GLEST_GAME_MENUSTATEGRAPHICINFO_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateGraphicInfo
// ===============================
class MenuStateGraphicInfo: public MenuState{
private:
GraphicButton buttonReturn;
GraphicLabel labelInfo;
GraphicLabel labelMoreInfo;
string glInfo;
string glMoreInfo;
public:
MenuStateGraphicInfo(Program *program, MainMenu *mainMenu);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
};
}}//end namespace
#endif

View File

@ -0,0 +1,277 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "menu_state_join_game.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "config.h"
#include "menu_state_root.h"
#include "metrics.h"
#include "network_manager.h"
#include "network_message.h"
#include "client_interface.h"
#include "conversion.h"
#include "game.h"
#include "socket.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
using namespace Shared::Util;
// ===============================
// class MenuStateJoinGame
// ===============================
const int MenuStateJoinGame::newServerIndex= 0;
const string MenuStateJoinGame::serverFileName= "servers.ini";
MenuStateJoinGame::MenuStateJoinGame(Program *program, MainMenu *mainMenu, bool connect, Ip serverIp):
MenuState(program, mainMenu, "join-game")
{
Lang &lang= Lang::getInstance();
Config &config= Config::getInstance();
NetworkManager &networkManager= NetworkManager::getInstance();
servers.load(serverFileName);
//buttons
buttonReturn.init(325, 300, 125);
buttonReturn.setText(lang.get("Return"));
buttonConnect.init(475, 300, 125);
buttonConnect.setText(lang.get("Connect"));
//server type label
labelServerType.init(330, 460);
labelServerType.setText(lang.get("ServerType") + ":");
//server type list box
listBoxServerType.init(465, 460);
listBoxServerType.pushBackItem(lang.get("ServerTypeNew"));
listBoxServerType.pushBackItem(lang.get("ServerTypePrevious"));
//server label
labelServer.init(330, 430);
labelServer.setText(lang.get("Server") + ": ");
//server listbox
listBoxServers.init(465, 430);
for(int i= 0; i<servers.getPropertyCount(); ++i){
listBoxServers.pushBackItem(servers.getKey(i));
}
//server ip
labelServerIp.init(465, 430);
labelStatus.init(330, 400);
labelStatus.setText("");
labelInfo.init(330, 370);
labelInfo.setText("");
networkManager.init(nrClient);
connected= false;
playerIndex= -1;
//server ip
if(connect){
labelServerIp.setText(serverIp.getString() + "_");
connectToServer();
}
else
{
labelServerIp.setText(config.getString("ServerIp") + "_");
}
}
void MenuStateJoinGame::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
NetworkManager &networkManager= NetworkManager::getInstance();
ClientInterface* clientInterface= networkManager.getClientInterface();
if(!clientInterface->isConnected()){
//server type
if(listBoxServerType.mouseClick(x, y)){
if(!listBoxServers.getText().empty()){
labelServerIp.setText(servers.getString(listBoxServers.getText())+"_");
}
}
//server list
else if(listBoxServerType.getSelectedItemIndex()!=newServerIndex){
if(listBoxServers.mouseClick(x, y)){
labelServerIp.setText(servers.getString(listBoxServers.getText())+"_");
}
}
}
//return
if(buttonReturn.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateRoot(program, mainMenu));
}
//connect
else if(buttonConnect.mouseClick(x, y)){
ClientInterface* clientInterface= networkManager.getClientInterface();
soundRenderer.playFx(coreData.getClickSoundA());
labelInfo.setText("");
if(clientInterface->isConnected()){
clientInterface->reset();
}
else{
connectToServer();
}
}
}
void MenuStateJoinGame::mouseMove(int x, int y, const MouseState *ms){
buttonReturn.mouseMove(x, y);
buttonConnect.mouseMove(x, y);
listBoxServerType.mouseMove(x, y);
//hide-show options depending on the selection
if(listBoxServers.getSelectedItemIndex()==newServerIndex){
labelServerIp.mouseMove(x, y);
}
else{
listBoxServers.mouseMove(x, y);
}
}
void MenuStateJoinGame::render(){
Renderer &renderer= Renderer::getInstance();
renderer.renderButton(&buttonReturn);
renderer.renderLabel(&labelServer);
renderer.renderLabel(&labelServerType);
renderer.renderLabel(&labelStatus);
renderer.renderLabel(&labelInfo);
renderer.renderButton(&buttonConnect);
renderer.renderListBox(&listBoxServerType);
if(listBoxServerType.getSelectedItemIndex()==newServerIndex){
renderer.renderLabel(&labelServerIp);
}
else
{
renderer.renderListBox(&listBoxServers);
}
}
void MenuStateJoinGame::update(){
ClientInterface* clientInterface= NetworkManager::getInstance().getClientInterface();
Lang &lang= Lang::getInstance();
//update status label
if(clientInterface->isConnected()){
buttonConnect.setText(lang.get("Disconnect"));
if(!clientInterface->getServerName().empty()){
labelStatus.setText(lang.get("ConnectedToServer") + " " + clientInterface->getServerName());
}
else{
labelStatus.setText(lang.get("ConnectedToServer"));
}
}
else{
buttonConnect.setText(lang.get("Connect"));
labelStatus.setText(lang.get("NotConnected"));
labelInfo.setText("");
}
//process network messages
if(clientInterface->isConnected()){
//update lobby
clientInterface->updateLobby();
//intro
if(clientInterface->getIntroDone()){
labelInfo.setText(lang.get("WaitingHost"));
servers.setString(clientInterface->getServerName(), Ip(labelServerIp.getText()).getString());
}
//launch
if(clientInterface->getLaunchGame()){
servers.save(serverFileName);
program->setState(new Game(program, clientInterface->getGameSettings()));
}
}
}
void MenuStateJoinGame::keyDown(char key){
ClientInterface* clientInterface= NetworkManager::getInstance().getClientInterface();
if(!clientInterface->isConnected()){
if(key==vkBack){
string text= labelServerIp.getText();
if(text.size()>1){
text.erase(text.end()-2);
}
labelServerIp.setText(text);
}
}
}
void MenuStateJoinGame::keyPress(char c){
ClientInterface* clientInterface= NetworkManager::getInstance().getClientInterface();
if(!clientInterface->isConnected()){
int maxTextSize= 16;
if(c>='0' && c<='9'){
if(labelServerIp.getText().size()<maxTextSize){
string text= labelServerIp.getText();
text.insert(text.end()-1, c);
labelServerIp.setText(text);
}
}
else if (c=='.'){
if(labelServerIp.getText().size()<maxTextSize){
string text= labelServerIp.getText();
text.insert(text.end()-1, '.');
labelServerIp.setText(text);
}
}
}
}
void MenuStateJoinGame::connectToServer(){
ClientInterface* clientInterface= NetworkManager::getInstance().getClientInterface();
Config& config= Config::getInstance();
Ip serverIp(labelServerIp.getText());
clientInterface->connect(serverIp, GameConstants::serverPort);
labelServerIp.setText(serverIp.getString()+'_');
labelInfo.setText("");
//save server ip
config.setString("ServerIp", serverIp.getString());
config.save();
}
}}//end namespace

View File

@ -0,0 +1,63 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATEJOINGAME_H_
#define _GLEST_GAME_MENUSTATEJOINGAME_H_
#include "properties.h"
#include "main_menu.h"
using Shared::Util::Properties;
namespace Glest{ namespace Game{
class NetworkMessageIntro;
// ===============================
// class MenuStateJoinGame
// ===============================
class MenuStateJoinGame: public MenuState{
private:
static const int newServerIndex;
static const string serverFileName;
private:
GraphicButton buttonReturn;
GraphicButton buttonConnect;
GraphicLabel labelServer;
GraphicLabel labelServerType;
GraphicLabel labelServerIp;
GraphicLabel labelStatus;
GraphicLabel labelInfo;
GraphicListBox listBoxServerType;
GraphicListBox listBoxServers;
bool connected;
int playerIndex;
Properties servers;
public:
MenuStateJoinGame(Program *program, MainMenu *mainMenu, bool connect= false, Ip serverIp= Ip());
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
void update();
void keyDown(char key);
void keyPress(char c);
private:
void connectToServer();
};
}}//end namespace
#endif

View File

@ -0,0 +1,98 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "menu_state_new_game.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "config.h"
#include "menu_state_custom_game.h"
#include "menu_state_scenario.h"
#include "menu_state_root.h"
#include "metrics.h"
#include "network_manager.h"
#include "network_message.h"
#include "auto_test.h"
#include "socket.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class MenuStateNewGame
// =====================================================
MenuStateNewGame::MenuStateNewGame(Program *program, MainMenu *mainMenu):
MenuState(program, mainMenu, "root")
{
Lang &lang= Lang::getInstance();
buttonCustomGame.init(425, 350, 150);
buttonScenario.init(425, 310, 150);
buttonTutorial.init(425, 270, 150);
buttonReturn.init(425, 230, 150);
buttonCustomGame.setText(lang.get("CustomGame"));
buttonScenario.setText(lang.get("Scenario"));
buttonTutorial.setText(lang.get("Tutorial"));
buttonReturn.setText(lang.get("Return"));
NetworkManager::getInstance().end();
}
void MenuStateNewGame::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonCustomGame.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateCustomGame(program, mainMenu));
}
else if(buttonScenario.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateScenario(program, mainMenu, "scenarios"));
}
else if(buttonTutorial.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateScenario(program, mainMenu, "tutorials"));
}
else if(buttonReturn.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateRoot(program, mainMenu));
}
}
void MenuStateNewGame::mouseMove(int x, int y, const MouseState *ms){
buttonCustomGame.mouseMove(x, y);
buttonScenario.mouseMove(x, y);
buttonTutorial.mouseMove(x, y);
buttonReturn.mouseMove(x, y);
}
void MenuStateNewGame::render(){
Renderer &renderer= Renderer::getInstance();
renderer.renderButton(&buttonCustomGame);
renderer.renderButton(&buttonScenario);
renderer.renderButton(&buttonTutorial);
renderer.renderButton(&buttonReturn);
}
void MenuStateNewGame::update(){
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateNewGame(program, mainMenu);
}
}
}}//end namespace

View File

@ -0,0 +1,42 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATENEWGAME_H_
#define _GLEST_GAME_MENUSTATENEWGAME_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateNewGame
// ===============================
class MenuStateNewGame: public MenuState{
private:
GraphicButton buttonCustomGame;
GraphicButton buttonScenario;
GraphicButton buttonTutorial;
GraphicButton buttonReturn;
public:
MenuStateNewGame(Program *program, MainMenu *mainMenu);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void update();
void render();
};
}}//end namespace
#endif

View File

@ -0,0 +1,227 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "menu_state_options.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "config.h"
#include "menu_state_root.h"
#include "util.h"
#include "leak_dumper.h"
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class MenuStateOptions
// =====================================================
MenuStateOptions::MenuStateOptions(Program *program, MainMenu *mainMenu):
MenuState(program, mainMenu, "config")
{
Lang &lang= Lang::getInstance();
Config &config= Config::getInstance();
//create
buttonReturn.init(200, 150, 125);
buttonAutoConfig.init(375, 150, 125);
//labels
labelVolumeFx.init(200, 530);
labelVolumeAmbient.init(200, 500);
labelVolumeMusic.init(200, 470);
labelLang.init(200, 400);
labelFilter.init(200, 340);
labelShadows.init(200, 310);
labelTextures3D.init(200, 280);
labelLights.init(200, 250);
//list boxes
listBoxVolumeFx.init(350, 530, 80);
listBoxVolumeAmbient.init(350, 500, 80);
listBoxVolumeMusic.init(350, 470, 80);
listBoxMusicSelect.init(350, 440, 150);
listBoxLang.init(350, 400, 170);
listBoxFilter.init(350, 340, 170);
listBoxShadows.init(350, 310, 170);
listBoxTextures3D.init(350, 280, 80);
listBoxLights.init(350, 250, 80);
//set text
buttonReturn.setText(lang.get("Return"));
buttonAutoConfig.setText(lang.get("AutoConfig"));
labelLang.setText(lang.get("Language"));
labelShadows.setText(lang.get("Shadows"));
labelFilter.setText(lang.get("Filter"));
labelTextures3D.setText(lang.get("Textures3D"));
labelLights.setText(lang.get("MaxLights"));
labelVolumeFx.setText(lang.get("FxVolume"));
labelVolumeAmbient.setText(lang.get("AmbientVolume"));
labelVolumeMusic.setText(lang.get("MusicVolume"));
//sound
//lang
vector<string> langResults;
findAll("data/lang/*.lng", langResults, true);
if(langResults.empty()){
throw runtime_error("There is no lang file");
}
listBoxLang.setItems(langResults);
listBoxLang.setSelectedItem(config.getString("Lang"));
//shadows
for(int i= 0; i<Renderer::sCount; ++i){
listBoxShadows.pushBackItem(lang.get(Renderer::shadowsToStr(static_cast<Renderer::Shadows>(i))));
}
string str= config.getString("Shadows");
listBoxShadows.setSelectedItemIndex(clamp(Renderer::strToShadows(str), 0, Renderer::sCount-1));
//filter
listBoxFilter.pushBackItem("Bilinear");
listBoxFilter.pushBackItem("Trilinear");
listBoxFilter.setSelectedItem(config.getString("Filter"));
//textures 3d
listBoxTextures3D.pushBackItem(lang.get("No"));
listBoxTextures3D.pushBackItem(lang.get("Yes"));
listBoxTextures3D.setSelectedItemIndex(clamp(config.getInt("Textures3D"), 0, 1));
//lights
for(int i= 1; i<=8; ++i){
listBoxLights.pushBackItem(intToStr(i));
}
listBoxLights.setSelectedItemIndex(clamp(config.getInt("MaxLights")-1, 0, 7));
//sound
for(int i=0; i<=100; i+=5){
listBoxVolumeFx.pushBackItem(intToStr(i));
listBoxVolumeAmbient.pushBackItem(intToStr(i));
listBoxVolumeMusic.pushBackItem(intToStr(i));
}
listBoxVolumeFx.setSelectedItem(intToStr(config.getInt("SoundVolumeFx")/5*5));
listBoxVolumeAmbient.setSelectedItem(intToStr(config.getInt("SoundVolumeAmbient")/5*5));
listBoxVolumeMusic.setSelectedItem(intToStr(config.getInt("SoundVolumeMusic")/5*5));
}
void MenuStateOptions::mouseClick(int x, int y, MouseButton mouseButton){
Config &config= Config::getInstance();
Lang &lang= Lang::getInstance();
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonReturn.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateRoot(program, mainMenu));
}
else if(buttonAutoConfig.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundA());
Renderer::getInstance().autoConfig();
saveConfig();
mainMenu->setState(new MenuStateOptions(program, mainMenu));
}
else if(listBoxLang.mouseClick(x, y)){
config.setString("Lang", listBoxLang.getSelectedItem());
lang.loadStrings(config.getString("Lang"));
saveConfig();
mainMenu->setState(new MenuStateOptions(program, mainMenu));
}
else if(listBoxShadows.mouseClick(x, y)){
int index= listBoxShadows.getSelectedItemIndex();
config.setString("Shadows", Renderer::shadowsToStr(static_cast<Renderer::Shadows>(index)));
saveConfig();
}
else if(listBoxFilter.mouseClick(x, y)){
config.setString("Filter", listBoxFilter.getSelectedItem());
saveConfig();
}
else if(listBoxTextures3D.mouseClick(x, y)){
config.setInt("Textures3D", listBoxTextures3D.getSelectedItemIndex());
saveConfig();
}
else if(listBoxLights.mouseClick(x, y)){
config.setInt("MaxLights", listBoxLights.getSelectedItemIndex()+1);
saveConfig();
}
else if(listBoxVolumeFx.mouseClick(x, y)){
config.setString("SoundVolumeFx", listBoxVolumeFx.getSelectedItem());
saveConfig();
}
else if(listBoxVolumeAmbient.mouseClick(x, y)){
config.setString("SoundVolumeAmbient", listBoxVolumeAmbient.getSelectedItem());
saveConfig();
}
else if(listBoxVolumeMusic.mouseClick(x, y)){
CoreData::getInstance().getMenuMusic()->setVolume(strToInt(listBoxVolumeMusic.getSelectedItem())/100.f);
config.setString("SoundVolumeMusic", listBoxVolumeMusic.getSelectedItem());
saveConfig();
}
}
void MenuStateOptions::mouseMove(int x, int y, const MouseState *ms){
buttonReturn.mouseMove(x, y);
buttonAutoConfig.mouseMove(x, y);
listBoxLang.mouseMove(x, y);
listBoxVolumeFx.mouseMove(x, y);
listBoxVolumeAmbient.mouseMove(x, y);
listBoxVolumeMusic.mouseMove(x, y);
listBoxLang.mouseMove(x, y);
listBoxFilter.mouseMove(x, y);
listBoxShadows.mouseMove(x, y);
listBoxTextures3D.mouseMove(x, y);
listBoxLights.mouseMove(x, y);
}
void MenuStateOptions::render(){
Renderer &renderer= Renderer::getInstance();
renderer.renderButton(&buttonReturn);
renderer.renderButton(&buttonAutoConfig);
renderer.renderListBox(&listBoxLang);
renderer.renderListBox(&listBoxShadows);
renderer.renderListBox(&listBoxTextures3D);
renderer.renderListBox(&listBoxLights);
renderer.renderListBox(&listBoxFilter);
renderer.renderListBox(&listBoxVolumeFx);
renderer.renderListBox(&listBoxVolumeAmbient);
renderer.renderListBox(&listBoxVolumeMusic);
renderer.renderLabel(&labelLang);
renderer.renderLabel(&labelShadows);
renderer.renderLabel(&labelTextures3D);
renderer.renderLabel(&labelLights);
renderer.renderLabel(&labelFilter);
renderer.renderLabel(&labelVolumeFx);
renderer.renderLabel(&labelVolumeAmbient);
renderer.renderLabel(&labelVolumeMusic);
}
void MenuStateOptions::saveConfig(){
Config &config= Config::getInstance();
config.save();
Renderer::getInstance().loadConfig();
SoundRenderer::getInstance().loadConfig();
}
}}//end namespace

View File

@ -0,0 +1,59 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATEOPTIONS_H_
#define _GLEST_GAME_MENUSTATEOPTIONS_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateOptions
// ===============================
class MenuStateOptions: public MenuState{
private:
GraphicButton buttonReturn;
GraphicButton buttonAutoConfig;
GraphicLabel labelLang;
GraphicLabel labelShadows;
GraphicLabel labelFilter;
GraphicLabel labelTextures3D;
GraphicLabel labelLights;
GraphicLabel labelVolumeFx;
GraphicLabel labelVolumeAmbient;
GraphicLabel labelVolumeMusic;
GraphicListBox listBoxLang;
GraphicListBox listBoxShadows;
GraphicListBox listBoxFilter;
GraphicListBox listBoxTextures3D;
GraphicListBox listBoxLights;
GraphicListBox listBoxVolumeFx;
GraphicListBox listBoxVolumeAmbient;
GraphicListBox listBoxVolumeMusic;
GraphicListBox listBoxMusicSelect;
public:
MenuStateOptions(Program *program, MainMenu *mainMenu);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
private:
void saveConfig();
};
}}//end namespace
#endif

View File

@ -0,0 +1,116 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2005 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 "menu_state_root.h"
#include "renderer.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "config.h"
#include "menu_state_new_game.h"
#include "menu_state_join_game.h"
#include "menu_state_options.h"
#include "menu_state_about.h"
#include "metrics.h"
#include "network_manager.h"
#include "network_message.h"
#include "socket.h"
#include "auto_test.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class MenuStateRoot
// =====================================================
MenuStateRoot::MenuStateRoot(Program *program, MainMenu *mainMenu):
MenuState(program, mainMenu, "root")
{
Lang &lang= Lang::getInstance();
buttonNewGame.init(425, 350, 150);
buttonJoinGame.init(425, 310, 150);
buttonOptions.init(425, 270, 150);
buttonAbout.init(425, 230, 150);
buttonExit.init(425, 190, 150);
labelVersion.init(525, 420);
buttonNewGame.setText(lang.get("NewGame"));
buttonJoinGame.setText(lang.get("JoinGame"));
buttonOptions.setText(lang.get("Options"));
buttonAbout.setText(lang.get("About"));
buttonExit.setText(lang.get("Exit"));
labelVersion.setText(glestVersionString);
}
void MenuStateRoot::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonNewGame.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateNewGame(program, mainMenu));
}
else if(buttonJoinGame.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateJoinGame(program, mainMenu));
}
else if(buttonOptions.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateOptions(program, mainMenu));
}
else if(buttonAbout.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundB());
mainMenu->setState(new MenuStateAbout(program, mainMenu));
}
else if(buttonExit.mouseClick(x, y)){
soundRenderer.playFx(coreData.getClickSoundA());
program->exit();
}
}
void MenuStateRoot::mouseMove(int x, int y, const MouseState *ms){
buttonNewGame.mouseMove(x, y);
buttonJoinGame.mouseMove(x, y);
buttonOptions.mouseMove(x, y);
buttonAbout.mouseMove(x, y);
buttonExit.mouseMove(x,y);
}
void MenuStateRoot::render(){
Renderer &renderer= Renderer::getInstance();
CoreData &coreData= CoreData::getInstance();
const Metrics &metrics= Metrics::getInstance();
int w= 300;
int h= 150;
renderer.renderTextureQuad(
(metrics.getVirtualW()-w)/2, 475-h/2, w, h,
coreData.getLogoTexture(), GraphicComponent::getFade());
renderer.renderButton(&buttonNewGame);
renderer.renderButton(&buttonJoinGame);
renderer.renderButton(&buttonOptions);
renderer.renderButton(&buttonAbout);
renderer.renderButton(&buttonExit);
renderer.renderLabel(&labelVersion);
}
void MenuStateRoot::update(){
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateRoot(program, mainMenu);
}
}
}}//end namespace

View File

@ -0,0 +1,44 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATEROOT_H_
#define _GLEST_GAME_MENUSTATEROOT_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateRoot
// ===============================
class MenuStateRoot: public MenuState{
private:
GraphicButton buttonNewGame;
GraphicButton buttonJoinGame;
GraphicButton buttonOptions;
GraphicButton buttonAbout;
GraphicButton buttonExit;
GraphicLabel labelVersion;
public:
MenuStateRoot(Program *program, MainMenu *mainMenu);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
void update();
};
}}//end namespace
#endif

View File

@ -0,0 +1,248 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2005 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 "menu_state_scenario.h"
#include "renderer.h"
#include "menu_state_new_game.h"
#include "sound_renderer.h"
#include "core_data.h"
#include "menu_state_options.h"
#include "network_manager.h"
#include "config.h"
#include "auto_test.h"
#include "game.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
using namespace Shared::Xml;
// =====================================================
// class MenuStateScenario
// =====================================================
MenuStateScenario::MenuStateScenario(Program *program, MainMenu *mainMenu, const string &dir):
MenuState(program, mainMenu, "scenario")
{
Lang &lang= Lang::getInstance();
NetworkManager &networkManager= NetworkManager::getInstance();
vector<string> results;
this->dir = dir;
labelInfo.init(350, 350);
labelInfo.setFont(CoreData::getInstance().getMenuFontNormal());
buttonReturn.init(350, 200, 125);
buttonPlayNow.init(525, 200, 125);
listBoxScenario.init(350, 400, 190);
labelScenario.init(350, 430);
buttonReturn.setText(lang.get("Return"));
buttonPlayNow.setText(lang.get("PlayNow"));
labelScenario.setText(lang.get("Scenario"));
//scenario listbox
findAll(dir+"/*.", results);
scenarioFiles= results;
if(results.size()==0){
throw runtime_error("There are no scenarios");
}
for(int i= 0; i<results.size(); ++i){
results[i]= formatString(results[i]);
}
listBoxScenario.setItems(results);
loadScenarioInfo(Scenario::getScenarioPath(dir, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo );
labelInfo.setText(scenarioInfo.desc);
networkManager.init(nrServer);
}
void MenuStateScenario::mouseClick(int x, int y, MouseButton mouseButton){
CoreData &coreData= CoreData::getInstance();
SoundRenderer &soundRenderer= SoundRenderer::getInstance();
if(buttonReturn.mouseClick(x,y)){
soundRenderer.playFx(coreData.getClickSoundA());
mainMenu->setState(new MenuStateNewGame(program, mainMenu));
}
else if(buttonPlayNow.mouseClick(x,y)){
soundRenderer.playFx(coreData.getClickSoundC());
launchGame();
}
else if(listBoxScenario.mouseClick(x, y)){
loadScenarioInfo(Scenario::getScenarioPath(dir, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo);
labelInfo.setText(scenarioInfo.desc);
}
}
void MenuStateScenario::mouseMove(int x, int y, const MouseState *ms){
listBoxScenario.mouseMove(x, y);
buttonReturn.mouseMove(x, y);
buttonPlayNow.mouseMove(x, y);
}
void MenuStateScenario::render(){
Renderer &renderer= Renderer::getInstance();
renderer.renderLabel(&labelInfo);
renderer.renderLabel(&labelScenario);
renderer.renderListBox(&listBoxScenario);
renderer.renderButton(&buttonReturn);
renderer.renderButton(&buttonPlayNow);
}
void MenuStateScenario::update(){
if(Config::getInstance().getBool("AutoTest")){
AutoTest::getInstance().updateScenario(this);
}
}
void MenuStateScenario::launchGame(){
GameSettings gameSettings;
loadGameSettings(&scenarioInfo, &gameSettings);
program->setState(new Game(program, &gameSettings));
}
void MenuStateScenario::setScenario(int i){
listBoxScenario.setSelectedItemIndex(i);
loadScenarioInfo(Scenario::getScenarioPath(dir, scenarioFiles[listBoxScenario.getSelectedItemIndex()]), &scenarioInfo);
}
void MenuStateScenario::loadScenarioInfo(string file, ScenarioInfo *scenarioInfo){
Lang &lang= Lang::getInstance();
XmlTree xmlTree;
xmlTree.load(file);
const XmlNode *scenarioNode= xmlTree.getRootNode();
const XmlNode *difficultyNode= scenarioNode->getChild("difficulty");
scenarioInfo->difficulty = difficultyNode->getAttribute("value")->getIntValue();
if( scenarioInfo->difficulty < dVeryEasy || scenarioInfo->difficulty > dInsane )
{
throw std::runtime_error("Invalid difficulty");
}
const XmlNode *playersNode= scenarioNode->getChild("players");
for(int i= 0; i<GameConstants::maxPlayers; ++i){
const XmlNode* playerNode = playersNode->getChild("player", i);
ControlType factionControl = strToControllerType( playerNode->getAttribute("control")->getValue() );
string factionTypeName;
scenarioInfo->factionControls[i] = factionControl;
if(factionControl != ctClosed){
int teamIndex = playerNode->getAttribute("team")->getIntValue();
if( teamIndex < 1 || teamIndex > GameConstants::maxPlayers )
{
throw runtime_error("Team out of range: " + intToStr(teamIndex) );
}
scenarioInfo->teams[i]= playerNode->getAttribute("team")->getIntValue();
scenarioInfo->factionTypeNames[i]= playerNode->getAttribute("faction")->getValue();
}
scenarioInfo->mapName = scenarioNode->getChild("map")->getAttribute("value")->getValue();
scenarioInfo->tilesetName = scenarioNode->getChild("tileset")->getAttribute("value")->getValue();
scenarioInfo->techTreeName = scenarioNode->getChild("tech-tree")->getAttribute("value")->getValue();
scenarioInfo->defaultUnits = scenarioNode->getChild("default-units")->getAttribute("value")->getBoolValue();
scenarioInfo->defaultResources = scenarioNode->getChild("default-resources")->getAttribute("value")->getBoolValue();
scenarioInfo->defaultVictoryConditions = scenarioNode->getChild("default-victory-conditions")->getAttribute("value")->getBoolValue();
}
//add player info
scenarioInfo->desc= lang.get("Player") + ": ";
for(int i=0; i<GameConstants::maxPlayers; ++i )
{
if(scenarioInfo->factionControls[i] == ctHuman )
{
scenarioInfo->desc+= formatString(scenarioInfo->factionTypeNames[i]);
break;
}
}
//add misc info
string difficultyString = "Difficulty" + intToStr(scenarioInfo->difficulty);
scenarioInfo->desc+= "\n";
scenarioInfo->desc+= lang.get("Difficulty") + ": " + lang.get(difficultyString) +"\n";
scenarioInfo->desc+= lang.get("Map") + ": " + formatString(scenarioInfo->mapName) + "\n";
scenarioInfo->desc+= lang.get("Tileset") + ": " + formatString(scenarioInfo->tilesetName) + "\n";
scenarioInfo->desc+= lang.get("TechTree") + ": " + formatString(scenarioInfo->techTreeName) + "\n";
}
void MenuStateScenario::loadGameSettings(const ScenarioInfo *scenarioInfo, GameSettings *gameSettings){
int factionCount= 0;
gameSettings->setDescription(formatString(scenarioFiles[listBoxScenario.getSelectedItemIndex()]));
gameSettings->setMap(scenarioInfo->mapName);
gameSettings->setTileset(scenarioInfo->tilesetName);
gameSettings->setTech(scenarioInfo->techTreeName);
gameSettings->setScenario(scenarioFiles[listBoxScenario.getSelectedItemIndex()]);
gameSettings->setScenarioDir(dir);
gameSettings->setDefaultUnits(scenarioInfo->defaultUnits);
gameSettings->setDefaultResources(scenarioInfo->defaultResources);
gameSettings->setDefaultVictoryConditions(scenarioInfo->defaultVictoryConditions);
for(int i=0; i<GameConstants::maxPlayers; ++i){
ControlType ct= static_cast<ControlType>(scenarioInfo->factionControls[i]);
if(ct!=ctClosed){
if(ct==ctHuman){
gameSettings->setThisFactionIndex(factionCount);
}
gameSettings->setFactionControl(factionCount, ct);
gameSettings->setTeam(factionCount, scenarioInfo->teams[i]-1);
gameSettings->setStartLocationIndex(factionCount, i);
gameSettings->setFactionTypeName(factionCount, scenarioInfo->factionTypeNames[i]);
factionCount++;
}
}
gameSettings->setFactionCount(factionCount);
}
ControlType MenuStateScenario::strToControllerType(const string &str){
if(str=="closed"){
return ctClosed;
}
else if(str=="cpu-easy"){
return ctCpuEasy;
}
else if(str=="cpu"){
return ctCpu;
}
else if(str=="cpu-ultra"){
return ctCpuUltra;
}
else if(str=="cpu-mega"){
return ctCpuMega;
}
else if(str=="human"){
return ctHuman;
}
throw std::runtime_error("Unknown controller type: " + str);
}
}}//end namespace

View File

@ -0,0 +1,69 @@
// ==============================================================
// This file is part of Glest (www.glest.org)
//
// 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
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#ifndef _GLEST_GAME_MENUSTATESCENARIO_H_
#define _GLEST_GAME_MENUSTATESCENARIO_H_
#include "main_menu.h"
namespace Glest{ namespace Game{
// ===============================
// class MenuStateScenario
// ===============================
class MenuStateScenario: public MenuState{
private:
enum Difficulty{
dVeryEasy,
dEasy,
dMedium,
dHard,
dVeryHard,
dInsane
};
GraphicButton buttonReturn;
GraphicButton buttonPlayNow;
GraphicLabel labelInfo;
GraphicLabel labelScenario;
GraphicListBox listBoxScenario;
vector<string> scenarioFiles;
ScenarioInfo scenarioInfo;
string dir;
public:
MenuStateScenario(Program *program, MainMenu *mainMenu, const string &dir);
void mouseClick(int x, int y, MouseButton mouseButton);
void mouseMove(int x, int y, const MouseState *mouseState);
void render();
void update();
void launchGame();
void setScenario(int i);
int getScenarioCount() const { return listBoxScenario.getItemCount(); }
private:
void loadScenarioInfo(string file, ScenarioInfo *scenarioInfo);
void loadGameSettings(const ScenarioInfo *scenarioInfo, GameSettings *gameSettings);
Difficulty computeDifficulty(const ScenarioInfo *scenarioInfo);
ControlType strToControllerType(const string &str);
};
}}//end namespace
#endif

View File

@ -0,0 +1,273 @@
// ==============================================================
// 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 "client_interface.h"
#include <stdexcept>
#include <cassert>
#include "platform_util.h"
#include "game_util.h"
#include "conversion.h"
#include "config.h"
#include "lang.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class ClientInterface
// =====================================================
const int ClientInterface::messageWaitTimeout= 10000; //10 seconds
const int ClientInterface::waitSleepTime= 50;
ClientInterface::ClientInterface(){
clientSocket= NULL;
launchGame= false;
introDone= false;
playerIndex= -1;
}
ClientInterface::~ClientInterface(){
delete clientSocket;
}
void ClientInterface::connect(const Ip &ip, int port){
delete clientSocket;
clientSocket= new ClientSocket();
clientSocket->setBlock(false);
clientSocket->connect(ip, port);
}
void ClientInterface::reset(){
delete clientSocket;
clientSocket= NULL;
}
void ClientInterface::update(){
NetworkMessageCommandList networkMessageCommandList;
//send as many commands as we can
while(!requestedCommands.empty()){
if(networkMessageCommandList.addCommand(&requestedCommands.back())){
requestedCommands.pop_back();
}
else{
break;
}
}
if(networkMessageCommandList.getCommandCount()>0){
sendMessage(&networkMessageCommandList);
}
//clear chat variables
chatText.clear();
chatSender.clear();
chatTeamIndex= -1;
}
void ClientInterface::updateLobby(){
NetworkMessageType networkMessageType= getNextMessageType();
switch(networkMessageType){
case nmtInvalid:
break;
case nmtIntro:{
NetworkMessageIntro networkMessageIntro;
if(receiveMessage(&networkMessageIntro)){
//check consistency
if(Config::getInstance().getBool("NetworkConsistencyChecks")){
if(networkMessageIntro.getVersionString()!=getNetworkVersionString()){
throw runtime_error("Server and client versions do not match (" + networkMessageIntro.getVersionString() + "). You have to use the same binaries.");
}
}
//send intro message
NetworkMessageIntro sendNetworkMessageIntro(getNetworkVersionString(), getHostName(), -1);
playerIndex= networkMessageIntro.getPlayerIndex();
serverName= networkMessageIntro.getName();
sendMessage(&sendNetworkMessageIntro);
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
introDone= true;
}
}
break;
case nmtLaunch:{
NetworkMessageLaunch networkMessageLaunch;
if(receiveMessage(&networkMessageLaunch)){
networkMessageLaunch.buildGameSettings(&gameSettings);
//replace server player by network
for(int i= 0; i<gameSettings.getFactionCount(); ++i){
//replace by network
if(gameSettings.getFactionControl(i)==ctHuman){
gameSettings.setFactionControl(i, ctNetwork);
}
//set the faction index
if(gameSettings.getStartLocationIndex(i)==playerIndex){
gameSettings.setThisFactionIndex(i);
}
}
launchGame= true;
}
}
break;
default:
throw runtime_error("Unexpected network message: " + intToStr(networkMessageType));
}
}
void ClientInterface::updateKeyframe(int frameCount){
bool done= false;
while(!done){
//wait for the next message
waitForMessage();
//check we have an expected message
NetworkMessageType networkMessageType= getNextMessageType();
switch(networkMessageType){
case nmtCommandList:{
//make sure we read the message
NetworkMessageCommandList networkMessageCommandList;
while(!receiveMessage(&networkMessageCommandList)){
sleep(waitSleepTime);
}
//check that we are in the right frame
if(networkMessageCommandList.getFrameCount()!=frameCount){
throw runtime_error("Network synchronization error, frame counts do not match");
}
// give all commands
for(int i= 0; i<networkMessageCommandList.getCommandCount(); ++i){
pendingCommands.push_back(*networkMessageCommandList.getCommand(i));
}
done= true;
}
break;
case nmtQuit:{
NetworkMessageQuit networkMessageQuit;
if(receiveMessage(&networkMessageQuit)){
quit= true;
}
done= true;
}
break;
case nmtText:{
NetworkMessageText networkMessageText;
if(receiveMessage(&networkMessageText)){
chatText= networkMessageText.getText();
chatSender= networkMessageText.getSender();
chatTeamIndex= networkMessageText.getTeamIndex();
}
}
break;
default:
throw runtime_error("Unexpected message in client interface: " + intToStr(networkMessageType));
}
}
}
void ClientInterface::waitUntilReady(Checksum* checksum){
NetworkMessageReady networkMessageReady;
Chrono chrono;
chrono.start();
//send ready message
sendMessage(&networkMessageReady);
//wait until we get a ready message from the server
while(true){
NetworkMessageType networkMessageType= getNextMessageType();
if(networkMessageType==nmtReady){
if(receiveMessage(&networkMessageReady)){
break;
}
}
else if(networkMessageType==nmtInvalid){
if(chrono.getMillis()>readyWaitTimeout){
throw runtime_error("Timeout waiting for server");
}
}
else{
throw runtime_error("Unexpected network message: " + intToStr(networkMessageType) );
}
// sleep a bit
sleep(waitSleepTime);
}
//check checksum
if(Config::getInstance().getBool("NetworkConsistencyChecks")){
if(networkMessageReady.getChecksum()!=checksum->getSum()){
throw runtime_error("Checksum error, you don't have the same data as the server");
}
}
//delay the start a bit, so clients have nore room to get messages
sleep(GameConstants::networkExtraLatency);
}
void ClientInterface::sendTextMessage(const string &text, int teamIndex){
NetworkMessageText networkMessageText(text, getHostName(), teamIndex);
sendMessage(&networkMessageText);
}
string ClientInterface::getNetworkStatus() const{
return Lang::getInstance().get("Server") + ": " + serverName;
}
void ClientInterface::waitForMessage(){
Chrono chrono;
chrono.start();
while(getNextMessageType()==nmtInvalid){
if(!isConnected()){
throw runtime_error("Disconnected");
}
if(chrono.getMillis()>messageWaitTimeout){
throw runtime_error("Timeout waiting for message");
}
sleep(waitSleepTime);
}
}
}}//end namespace

View File

@ -0,0 +1,81 @@
// ==============================================================
// 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_CLIENTINTERFACE_H_
#define _GLEST_GAME_CLIENTINTERFACE_H_
#include <vector>
#include "network_interface.h"
#include "game_settings.h"
#include "socket.h"
using Shared::Platform::Ip;
using Shared::Platform::ClientSocket;
using std::vector;
namespace Glest{ namespace Game{
// =====================================================
// class ClientInterface
// =====================================================
class ClientInterface: public GameNetworkInterface{
private:
static const int messageWaitTimeout;
static const int waitSleepTime;
private:
ClientSocket *clientSocket;
GameSettings gameSettings;
string serverName;
bool introDone;
bool launchGame;
int playerIndex;
public:
ClientInterface();
virtual ~ClientInterface();
virtual Socket* getSocket() {return clientSocket;}
virtual const Socket* getSocket() const {return clientSocket;}
//message processing
virtual void update();
virtual void updateLobby();
virtual void updateKeyframe(int frameCount);
virtual void waitUntilReady(Checksum* checksum);
// message sending
virtual void sendTextMessage(const string &text, int teamIndex);
virtual void quitGame(){}
//misc
virtual string getNetworkStatus() const;
//accessors
string getServerName() const {return serverName;}
bool getLaunchGame() const {return launchGame;}
bool getIntroDone() const {return introDone;}
int getPlayerIndex() const {return playerIndex;}
const GameSettings *getGameSettings() {return &gameSettings;}
void connect(const Ip &ip, int port);
void reset();
private:
void waitForMessage();
};
}}//end namespace
#endif

View File

@ -0,0 +1,99 @@
// ==============================================================
// 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 "connection_slot.h"
#include <stdexcept>
#include "conversion.h"
#include "game_util.h"
#include "config.h"
#include "server_interface.h"
#include "network_message.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class ClientConnection
// =====================================================
ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex){
this->serverInterface= serverInterface;
this->playerIndex= playerIndex;
socket= NULL;
ready= false;
}
ConnectionSlot::~ConnectionSlot(){
close();
}
void ConnectionSlot::update(){
if(socket==NULL){
socket= serverInterface->getServerSocket()->accept();
//send intro message when connected
if(socket!=NULL){
NetworkMessageIntro networkMessageIntro(getNetworkVersionString(), socket->getHostName(), playerIndex);
sendMessage(&networkMessageIntro);
}
}
else{
if(socket->isConnected()){
NetworkMessageType networkMessageType= getNextMessageType();
//process incoming commands
switch(networkMessageType){
case nmtInvalid:
case nmtText:
break;
//command list
case nmtCommandList:{
NetworkMessageCommandList networkMessageCommandList;
if(receiveMessage(&networkMessageCommandList)){
for(int i= 0; i<networkMessageCommandList.getCommandCount(); ++i){
serverInterface->requestCommand(networkMessageCommandList.getCommand(i));
}
}
}
break;
//process intro messages
case nmtIntro:{
NetworkMessageIntro networkMessageIntro;
if(receiveMessage(&networkMessageIntro)){
name= networkMessageIntro.getName();
}
}
break;
default:
throw runtime_error("Unexpected message in connection slot: " + intToStr(networkMessageType));
}
}
else{
close();
}
}
}
void ConnectionSlot::close(){
delete socket;
socket= NULL;
}
}}//end namespace

View File

@ -0,0 +1,61 @@
// ==============================================================
// 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_CONNECTIONSLOT_H_
#define _GLEST_GAME_CONNECTIONSLOT_H_
#include <vector>
#include "socket.h"
#include "network_interface.h"
using Shared::Platform::ServerSocket;
using Shared::Platform::Socket;
using std::vector;
namespace Glest{ namespace Game{
class ServerInterface;
// =====================================================
// class ConnectionSlot
// =====================================================
class ConnectionSlot: public NetworkInterface{
private:
ServerInterface* serverInterface;
Socket* socket;
int playerIndex;
string name;
bool ready;
public:
ConnectionSlot(ServerInterface* serverInterface, int playerIndex);
~ConnectionSlot();
virtual void update();
void setReady() {ready= true;}
const string &getName() const {return name;}
bool isReady() const {return ready;}
protected:
virtual Socket* getSocket() {return socket;}
virtual Socket* getSocket() const {return socket;}
private:
void close();
};
}}//end namespace
#endif

View File

@ -0,0 +1,77 @@
// ==============================================================
// 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 "network_interface.h"
#include <exception>
#include <cassert>
#include "types.h"
#include "conversion.h"
#include "platform_util.h"
#include "leak_dumper.h"
using namespace Shared::Platform;
using namespace Shared::Util;
using namespace std;
namespace Glest{ namespace Game{
// =====================================================
// class NetworkInterface
// =====================================================
const int NetworkInterface::readyWaitTimeout= 60000; //1 minute
void NetworkInterface::sendMessage(const NetworkMessage* networkMessage){
Socket* socket= getSocket();
networkMessage->send(socket);
}
NetworkMessageType NetworkInterface::getNextMessageType(){
Socket* socket= getSocket();
int8 messageType= nmtInvalid;
//peek message type
if(socket->getDataToRead()>=sizeof(messageType)){
socket->peek(&messageType, sizeof(messageType));
}
//sanity check new message type
if(messageType<0 || messageType>=nmtCount){
throw runtime_error("Invalid message type: " + intToStr(messageType));
}
return static_cast<NetworkMessageType>(messageType);
}
bool NetworkInterface::receiveMessage(NetworkMessage* networkMessage){
Socket* socket= getSocket();
return networkMessage->receive(socket);
}
bool NetworkInterface::isConnected(){
return getSocket()!=NULL && getSocket()->isConnected();
}
// =====================================================
// class GameNetworkInterface
// =====================================================
GameNetworkInterface::GameNetworkInterface(){
quit= false;
}
}}//end namespace

View File

@ -0,0 +1,100 @@
// ==============================================================
// 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_NETWORKINTERFACE_H_
#define _GLEST_GAME_NETWORKINTERFACE_H_
#include <string>
#include <vector>
#include "checksum.h"
#include "network_message.h"
#include "network_types.h"
using std::string;
using std::vector;
using Shared::Util::Checksum;
namespace Glest{ namespace Game{
// =====================================================
// class NetworkInterface
// =====================================================
class NetworkInterface{
public:
static const int readyWaitTimeout;
public:
virtual ~NetworkInterface(){}
virtual Socket* getSocket()= 0;
virtual const Socket* getSocket() const= 0;
string getIp() const {return getSocket()->getIp();}
string getHostName() const {return getSocket()->getHostName();}
void sendMessage(const NetworkMessage* networkMessage);
NetworkMessageType getNextMessageType();
bool receiveMessage(NetworkMessage* networkMessage);
bool isConnected();
};
// =====================================================
// class GameNetworkInterface
//
// Adds functions common to servers and clients
// but not connection slots
// =====================================================
class GameNetworkInterface: public NetworkInterface{
private:
typedef vector<NetworkCommand> Commands;
protected:
Commands requestedCommands; //commands requested by the user
Commands pendingCommands; //commands ready to be given
bool quit;
string chatText;
string chatSender;
int chatTeamIndex;
public:
GameNetworkInterface();
//message processimg
virtual void update()= 0;
virtual void updateLobby()= 0;
virtual void updateKeyframe(int frameCount)= 0;
virtual void waitUntilReady(Checksum* checksum)= 0;
//message sending
virtual void sendTextMessage(const string &text, int teamIndex)= 0;
virtual void quitGame()=0;
//misc
virtual string getNetworkStatus() const= 0;
//access functions
void requestCommand(const NetworkCommand *networkCommand) {requestedCommands.push_back(*networkCommand);}
int getPendingCommandCount() const {return pendingCommands.size();}
const NetworkCommand* getPendingCommand(int i) const {return &pendingCommands[i];}
void clearPendingCommands() {pendingCommands.clear();}
bool getQuit() const {return quit;}
const string getChatText() const {return chatText;}
const string getChatSender() const {return chatSender;}
int getChatTeamIndex() const {return chatTeamIndex;}
};
}}//end namespace
#endif

View File

@ -0,0 +1,78 @@
// ==============================================================
// 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 "network_manager.h"
namespace Glest{ namespace Game{
// =====================================================
// class NetworkManager
// =====================================================
NetworkManager &NetworkManager::getInstance(){
static NetworkManager networkManager;
return networkManager;
}
NetworkManager::NetworkManager(){
gameNetworkInterface= NULL;
networkRole= nrIdle;
}
void NetworkManager::init(NetworkRole networkRole)
{
assert(gameNetworkInterface==NULL);
this->networkRole = networkRole;
if(networkRole==nrServer){
gameNetworkInterface = new ServerInterface();
}
else
{
gameNetworkInterface = new ClientInterface();
}
}
void NetworkManager::end(){
delete gameNetworkInterface;
gameNetworkInterface= NULL;
networkRole= nrIdle;
}
void NetworkManager::update(){
if(gameNetworkInterface!=NULL){
gameNetworkInterface->update();
}
}
bool NetworkManager::isNetworkGame(){
return networkRole==nrClient || getServerInterface()->getConnectedSlotCount()>0;
}
GameNetworkInterface* NetworkManager::getGameNetworkInterface(){
assert(gameNetworkInterface!=NULL);
return gameNetworkInterface;
}
ServerInterface* NetworkManager::getServerInterface(){
assert(gameNetworkInterface!=NULL);
assert(networkRole==nrServer);
return static_cast<ServerInterface*>(gameNetworkInterface);
}
ClientInterface* NetworkManager::getClientInterface(){
assert(gameNetworkInterface!=NULL);
assert(networkRole==nrClient);
return static_cast<ClientInterface*>(gameNetworkInterface);
}
}}//end namespace

View File

@ -0,0 +1,57 @@
// ==============================================================
// 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_NETWORKMANAGER_H_
#define _GLEST_GAME_NETWORKMANAGER_H_
#include <cassert>
#include "socket.h"
#include "checksum.h"
#include "server_interface.h"
#include "client_interface.h"
using Shared::Util::Checksum;
namespace Glest{ namespace Game{
// =====================================================
// class NetworkManager
// =====================================================
enum NetworkRole{
nrServer,
nrClient,
nrIdle
};
class NetworkManager{
private:
GameNetworkInterface* gameNetworkInterface;
NetworkRole networkRole;
public:
static NetworkManager &getInstance();
NetworkManager();
void init(NetworkRole networkRole);
void end();
void update();
bool isNetworkGame();
GameNetworkInterface* getGameNetworkInterface();
ServerInterface* getServerInterface();
ClientInterface* getClientInterface();
};
}}//end namespace
#endif

View File

@ -0,0 +1,218 @@
// ==============================================================
// 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 "network_message.h"
#include <cassert>
#include <stdexcept>
#include "types.h"
#include "util.h"
#include "game_settings.h"
#include "leak_dumper.h"
using namespace Shared::Platform;
using namespace Shared::Util;
using namespace std;
namespace Glest{ namespace Game{
// =====================================================
// class NetworkMessage
// =====================================================
bool NetworkMessage::receive(Socket* socket, void* data, int dataSize){
if(socket->getDataToRead()>=dataSize){
if(socket->receive(data, dataSize)!=dataSize){
throw runtime_error("Error receiving NetworkMessage");
}
return true;
}
return false;
}
void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const{
if(socket->send(data, dataSize)!=dataSize){
throw runtime_error("Error sending NetworkMessage");
}
}
// =====================================================
// class NetworkMessageIntro
// =====================================================
NetworkMessageIntro::NetworkMessageIntro(){
data.messageType= -1;
data.playerIndex= -1;
}
NetworkMessageIntro::NetworkMessageIntro(const string &versionString, const string &name, int playerIndex){
data.messageType=nmtIntro;
data.versionString= versionString;
data.name= name;
data.playerIndex= static_cast<int16>(playerIndex);
}
bool NetworkMessageIntro::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageIntro::send(Socket* socket) const{
assert(data.messageType==nmtIntro);
NetworkMessage::send(socket, &data, sizeof(data));
}
// =====================================================
// class NetworkMessageReady
// =====================================================
NetworkMessageReady::NetworkMessageReady(){
data.messageType= nmtReady;
}
NetworkMessageReady::NetworkMessageReady(int32 checksum){
data.messageType= nmtReady;
data.checksum= checksum;
}
bool NetworkMessageReady::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageReady::send(Socket* socket) const{
assert(data.messageType==nmtReady);
NetworkMessage::send(socket, &data, sizeof(data));
}
// =====================================================
// class NetworkMessageLaunch
// =====================================================
NetworkMessageLaunch::NetworkMessageLaunch(){
data.messageType=-1;
}
NetworkMessageLaunch::NetworkMessageLaunch(const GameSettings *gameSettings){
data.messageType=nmtLaunch;
data.description= gameSettings->getDescription();
data.map= gameSettings->getMap();
data.tileset= gameSettings->getTileset();
data.tech= gameSettings->getTech();
data.factionCount= gameSettings->getFactionCount();
data.thisFactionIndex= gameSettings->getThisFactionIndex();
data.defaultResources= gameSettings->getDefaultResources();
data.defaultUnits= gameSettings->getDefaultUnits();
data.defaultVictoryConditions= gameSettings->getDefaultVictoryConditions();
for(int i= 0; i<data.factionCount; ++i){
data.factionTypeNames[i]= gameSettings->getFactionTypeName(i);
data.factionControls[i]= gameSettings->getFactionControl(i);
data.teams[i]= gameSettings->getTeam(i);
data.startLocationIndex[i]= gameSettings->getStartLocationIndex(i);
}
}
void NetworkMessageLaunch::buildGameSettings(GameSettings *gameSettings) const{
gameSettings->setDescription(data.description.getString());
gameSettings->setMap(data.map.getString());
gameSettings->setTileset(data.tileset.getString());
gameSettings->setTech(data.tech.getString());
gameSettings->setFactionCount(data.factionCount);
gameSettings->setThisFactionIndex(data.thisFactionIndex);
gameSettings->setDefaultResources(data.defaultResources);
gameSettings->setDefaultUnits(data.defaultUnits);
gameSettings->setDefaultVictoryConditions(data.defaultVictoryConditions);
for(int i= 0; i<data.factionCount; ++i){
gameSettings->setFactionTypeName(i, data.factionTypeNames[i].getString());
gameSettings->setFactionControl(i, static_cast<ControlType>(data.factionControls[i]));
gameSettings->setTeam(i, data.teams[i]);
gameSettings->setStartLocationIndex(i, data.startLocationIndex[i]);
}
}
bool NetworkMessageLaunch::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageLaunch::send(Socket* socket) const{
assert(data.messageType==nmtLaunch);
NetworkMessage::send(socket, &data, sizeof(data));
}
// =====================================================
// class NetworkMessageLaunch
// =====================================================
NetworkMessageCommandList::NetworkMessageCommandList(int32 frameCount){
data.messageType= nmtCommandList;
data.frameCount= frameCount;
data.commandCount= 0;
}
bool NetworkMessageCommandList::addCommand(const NetworkCommand* networkCommand){
if(data.commandCount<maxCommandCount){
data.commands[static_cast<int>(data.commandCount)]= *networkCommand;
data.commandCount++;
return true;
}
return false;
}
bool NetworkMessageCommandList::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageCommandList::send(Socket* socket) const{
assert(data.messageType==nmtCommandList);
NetworkMessage::send(socket, &data, sizeof(data));
}
// =====================================================
// class NetworkMessageText
// =====================================================
NetworkMessageText::NetworkMessageText(const string &text, const string &sender, int teamIndex){
data.messageType= nmtText;
data.text= text;
data.sender= sender;
data.teamIndex= teamIndex;
}
bool NetworkMessageText::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageText::send(Socket* socket) const{
assert(data.messageType==nmtText);
NetworkMessage::send(socket, &data, sizeof(data));
}
// =====================================================
// class NetworkMessageQuit
// =====================================================
NetworkMessageQuit::NetworkMessageQuit(){
data.messageType= nmtQuit;
}
bool NetworkMessageQuit::receive(Socket* socket){
return NetworkMessage::receive(socket, &data, sizeof(data));
}
void NetworkMessageQuit::send(Socket* socket) const{
assert(data.messageType==nmtQuit);
NetworkMessage::send(socket, &data, sizeof(data));
}
}}//end namespace

View File

@ -0,0 +1,252 @@
// ==============================================================
// 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_NETWORKMESSAGE_H_
#define _GLEST_GAME_NETWORKMESSAGE_H_
#include "socket.h"
#include "game_constants.h"
#include "network_types.h"
using Shared::Platform::Socket;
using Shared::Platform::int8;
using Shared::Platform::int16;
namespace Glest{ namespace Game{
class GameSettings;
enum NetworkMessageType{
nmtInvalid,
nmtIntro,
nmtPing,
nmtReady,
nmtLaunch,
nmtCommandList,
nmtText,
nmtQuit,
nmtCount
};
// =====================================================
// class NetworkMessage
// =====================================================
class NetworkMessage{
public:
virtual ~NetworkMessage(){}
virtual bool receive(Socket* socket)= 0;
virtual void send(Socket* socket) const = 0;
protected:
bool receive(Socket* socket, void* data, int dataSize);
void send(Socket* socket, const void* data, int dataSize) const;
};
// =====================================================
// class NetworkMessageIntro
//
// Message sent from the server to the client
// when the client connects and vice versa
// =====================================================
class NetworkMessageIntro: public NetworkMessage{
private:
static const int maxVersionStringSize= 64;
static const int maxNameSize= 16;
private:
struct Data{
int8 messageType;
NetworkString<maxVersionStringSize> versionString;
NetworkString<maxNameSize> name;
int16 playerIndex;
};
private:
Data data;
public:
NetworkMessageIntro();
NetworkMessageIntro(const string &versionString, const string &name, int playerIndex);
string getVersionString() const {return data.versionString.getString();}
string getName() const {return data.name.getString();}
int getPlayerIndex() const {return data.playerIndex;}
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
// =====================================================
// class NetworkMessageReady
//
// Message sent at the beggining of the game
// =====================================================
class NetworkMessageReady: public NetworkMessage{
private:
struct Data{
int8 messageType;
int32 checksum;
};
private:
Data data;
public:
NetworkMessageReady();
NetworkMessageReady(int32 checksum);
int32 getChecksum() const {return data.checksum;}
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
// =====================================================
// class NetworkMessageLaunch
//
// Message sent from the server to the client
// to launch the game
// =====================================================
class NetworkMessageLaunch: public NetworkMessage{
private:
static const int maxStringSize= 256;
private:
struct Data{
int8 messageType;
NetworkString<maxStringSize> description;
NetworkString<maxStringSize> map;
NetworkString<maxStringSize> tileset;
NetworkString<maxStringSize> tech;
NetworkString<maxStringSize> factionTypeNames[GameConstants::maxPlayers]; //faction names
int8 factionControls[GameConstants::maxPlayers];
int8 thisFactionIndex;
int8 factionCount;
int8 teams[GameConstants::maxPlayers];
int8 startLocationIndex[GameConstants::maxPlayers];
int8 defaultResources;
int8 defaultUnits;
int8 defaultVictoryConditions;
};
private:
Data data;
public:
NetworkMessageLaunch();
NetworkMessageLaunch(const GameSettings *gameSettings);
void buildGameSettings(GameSettings *gameSettings) const;
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
// =====================================================
// class CommandList
//
// Message to order a commands to several units
// =====================================================
class NetworkMessageCommandList: public NetworkMessage{
private:
static const int maxCommandCount= 16*4;
private:
struct Data{
int8 messageType;
int8 commandCount;
int32 frameCount;
NetworkCommand commands[maxCommandCount];
};
private:
Data data;
public:
NetworkMessageCommandList(int32 frameCount= -1);
bool addCommand(const NetworkCommand* networkCommand);
void clear() {data.commandCount= 0;}
int getCommandCount() const {return data.commandCount;}
int getFrameCount() const {return data.frameCount;}
const NetworkCommand* getCommand(int i) const {return &data.commands[i];}
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
// =====================================================
// class NetworkMessageText
//
// Chat text message
// =====================================================
class NetworkMessageText: public NetworkMessage{
private:
static const int maxStringSize= 64;
private:
struct Data{
int8 messageType;
NetworkString<maxStringSize> text;
NetworkString<maxStringSize> sender;
int8 teamIndex;
};
private:
Data data;
public:
NetworkMessageText(){}
NetworkMessageText(const string &text, const string &sender, int teamIndex);
string getText() const {return data.text.getString();}
string getSender() const {return data.sender.getString();}
int getTeamIndex() const {return data.teamIndex;}
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
// =====================================================
// class NetworkMessageQuit
//
// Message sent at the beggining of the game
// =====================================================
class NetworkMessageQuit: public NetworkMessage{
private:
struct Data{
int8 messageType;
};
private:
Data data;
public:
NetworkMessageQuit();
virtual bool receive(Socket* socket);
virtual void send(Socket* socket) const;
};
}}//end namespace
#endif

View File

@ -0,0 +1,33 @@
// ==============================================================
// 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 "network_types.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
// =====================================================
// class NetworkCommand
// =====================================================
NetworkCommand::NetworkCommand(int networkCommandType, int unitId, int commandTypeId, const Vec2i &pos, int unitTypeId, int targetId){
this->networkCommandType= networkCommandType;
this->unitId= unitId;
this->commandTypeId= commandTypeId;
this->positionX= pos.x;
this->positionY= pos.y;
this->unitTypeId= unitTypeId;
this->targetId= targetId;
}
}}//end namespace

View File

@ -0,0 +1,77 @@
// ==============================================================
// 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_NETWORKTYPES_H_
#define _GLEST_GAME_NETWORKTYPES_H_
#include <string>
#include "types.h"
#include "vec.h"
using std::string;
using Shared::Platform::int8;
using Shared::Platform::int16;
using Shared::Platform::int32;
using Shared::Graphics::Vec2i;
namespace Glest{ namespace Game{
// =====================================================
// class NetworkString
// =====================================================
template<int S>
class NetworkString{
private:
char buffer[S];
public:
NetworkString() {memset(buffer, 0, S);}
void operator=(const string& str) {strncpy(buffer, str.c_str(), S-1);}
string getString() const {return buffer;}
};
// =====================================================
// class NetworkCommand
// =====================================================
enum NetworkCommandType{
nctGiveCommand,
nctCancelCommand,
nctSetMeetingPoint
};
class NetworkCommand{
private:
int16 networkCommandType;
int16 unitId;
int16 commandTypeId;
int16 positionX;
int16 positionY;
int16 unitTypeId;
int16 targetId;
public:
NetworkCommand(){};
NetworkCommand(int networkCommandType, int unitId, int commandTypeId= -1, const Vec2i &pos= Vec2i(0), int unitTypeId= -1, int targetId= -1);
NetworkCommandType getNetworkCommandType() const {return static_cast<NetworkCommandType>(networkCommandType);}
int getUnitId() const {return unitId;}
int getCommandTypeId() const {return commandTypeId;}
Vec2i getPosition() const {return Vec2i(positionX, positionY);}
int getUnitTypeId() const {return unitTypeId;}
int getTargetId() const {return targetId;}
};
}}//end namespace
#endif

View File

@ -0,0 +1,244 @@
// ==============================================================
// 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 "server_interface.h"
#include <cassert>
#include <stdexcept>
#include "platform_util.h"
#include "conversion.h"
#include "config.h"
#include "lang.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;
namespace Glest{ namespace Game{
// =====================================================
// class ServerInterface
// =====================================================
ServerInterface::ServerInterface(){
for(int i= 0; i<GameConstants::maxPlayers; ++i){
slots[i]= NULL;
}
serverSocket.setBlock(false);
serverSocket.bind(GameConstants::serverPort);
}
ServerInterface::~ServerInterface(){
for(int i= 0; i<GameConstants::maxPlayers; ++i){
delete slots[i];
}
}
void ServerInterface::addSlot(int playerIndex){
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
delete slots[playerIndex];
slots[playerIndex]= new ConnectionSlot(this, playerIndex);
updateListen();
}
void ServerInterface::removeSlot(int playerIndex){
delete slots[playerIndex];
slots[playerIndex]= NULL;
updateListen();
}
ConnectionSlot* ServerInterface::getSlot(int playerIndex){
return slots[playerIndex];
}
int ServerInterface::getConnectedSlotCount(){
int connectedSlotCount= 0;
for(int i= 0; i<GameConstants::maxPlayers; ++i){
if(slots[i]!= NULL){
++connectedSlotCount;
}
}
return connectedSlotCount;
}
void ServerInterface::update(){
//update all slots
for(int i= 0; i<GameConstants::maxPlayers; ++i){
if(slots[i]!= NULL){
slots[i]->update();
}
}
//process text messages
chatText.clear();
chatSender.clear();
chatTeamIndex= -1;
for(int i= 0; i<GameConstants::maxPlayers; ++i){
ConnectionSlot* connectionSlot= slots[i];
if(connectionSlot!= NULL){
if(connectionSlot->isConnected()){
if(connectionSlot->getNextMessageType()==nmtText){
NetworkMessageText networkMessageText;
if(connectionSlot->receiveMessage(&networkMessageText)){
broadcastMessage(&networkMessageText, i);
chatText= networkMessageText.getText();
chatSender= networkMessageText.getSender();
chatTeamIndex= networkMessageText.getTeamIndex();
break;
}
}
}
}
}
}
void ServerInterface::updateKeyframe(int frameCount){
NetworkMessageCommandList networkMessageCommandList(frameCount);
//build command list, remove commands from requested and add to pending
while(!requestedCommands.empty()){
if(networkMessageCommandList.addCommand(&requestedCommands.back())){
pendingCommands.push_back(requestedCommands.back());
requestedCommands.pop_back();
}
else{
break;
}
}
//broadcast commands
broadcastMessage(&networkMessageCommandList);
}
void ServerInterface::waitUntilReady(Checksum* checksum){
Chrono chrono;
bool allReady= false;
chrono.start();
//wait until we get a ready message from all clients
while(!allReady){
allReady= true;
for(int i= 0; i<GameConstants::maxPlayers; ++i){
ConnectionSlot* connectionSlot= slots[i];
if(connectionSlot!=NULL){
if(!connectionSlot->isReady()){
NetworkMessageType networkMessageType= connectionSlot->getNextMessageType();
NetworkMessageReady networkMessageReady;
if(networkMessageType==nmtReady && connectionSlot->receiveMessage(&networkMessageReady)){
connectionSlot->setReady();
}
else if(networkMessageType!=nmtInvalid){
throw runtime_error("Unexpected network message: " + intToStr(networkMessageType));
}
allReady= false;
}
}
}
//check for timeout
if(chrono.getMillis()>readyWaitTimeout){
throw runtime_error("Timeout waiting for clients");
}
}
//send ready message after, so clients start delayed
for(int i= 0; i<GameConstants::maxPlayers; ++i){
NetworkMessageReady networkMessageReady(checksum->getSum());
ConnectionSlot* connectionSlot= slots[i];
if(connectionSlot!=NULL){
connectionSlot->sendMessage(&networkMessageReady);
}
}
}
void ServerInterface::sendTextMessage(const string &text, int teamIndex){
NetworkMessageText networkMessageText(text, getHostName(), teamIndex);
broadcastMessage(&networkMessageText);
}
void ServerInterface::quitGame(){
NetworkMessageQuit networkMessageQuit;
broadcastMessage(&networkMessageQuit);
}
string ServerInterface::getNetworkStatus() const{
Lang &lang= Lang::getInstance();
string str;
for(int i= 0; i<GameConstants::maxPlayers; ++i){
ConnectionSlot* connectionSlot= slots[i];
str+= intToStr(i)+ ": ";
if(connectionSlot!= NULL){
if(connectionSlot->isConnected()){
str+= connectionSlot->getName();
}
}
else
{
str+= lang.get("NotConnected");
}
str+= '\n';
}
return str;
}
void ServerInterface::launchGame(const GameSettings* gameSettings){
NetworkMessageLaunch networkMessageLaunch(gameSettings);
broadcastMessage(&networkMessageLaunch);
}
void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot){
for(int i= 0; i<GameConstants::maxPlayers; ++i){
ConnectionSlot* connectionSlot= slots[i];
if(i!= excludeSlot && connectionSlot!= NULL){
if(connectionSlot->isConnected()){
connectionSlot->sendMessage(networkMessage);
}
else{
removeSlot(i);
}
}
}
}
void ServerInterface::updateListen(){
int openSlotCount= 0;
for(int i= 0; i<GameConstants::maxPlayers; ++i){
if(slots[i]!= NULL && !slots[i]->isConnected()){
++openSlotCount;
}
}
serverSocket.listen(openSlotCount);
}
}}//end namespace

View File

@ -0,0 +1,71 @@
// ==============================================================
// 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_SERVERINTERFACE_H_
#define _GLEST_GAME_SERVERINTERFACE_H_
#include <vector>
#include "game_constants.h"
#include "network_interface.h"
#include "connection_slot.h"
#include "socket.h"
using std::vector;
using Shared::Platform::ServerSocket;
namespace Glest{ namespace Game{
// =====================================================
// class ServerInterface
// =====================================================
class ServerInterface: public GameNetworkInterface{
private:
ConnectionSlot* slots[GameConstants::maxPlayers];
ServerSocket serverSocket;
public:
ServerInterface();
virtual ~ServerInterface();
virtual Socket* getSocket() {return &serverSocket;}
virtual const Socket* getSocket() const {return &serverSocket;}
//message processing
virtual void update();
virtual void updateLobby(){};
virtual void updateKeyframe(int frameCount);
virtual void waitUntilReady(Checksum* checksum);
// message sending
virtual void sendTextMessage(const string &text, int teamIndex);
virtual void quitGame();
//misc
virtual string getNetworkStatus() const;
ServerSocket* getServerSocket() {return &serverSocket;}
void addSlot(int playerIndex);
void removeSlot(int playerIndex);
ConnectionSlot* getSlot(int playerIndex);
int getConnectedSlotCount();
void launchGame(const GameSettings* gameSettings);
private:
void broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot= -1);
void updateListen();
};
}}//end namespace
#endif

Some files were not shown because too many files have changed in this diff Show More