metalmaker.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 272 行
CPP
272 行
#include "MetalMaker.h"
#include "ExternalAI/IAICallback.h"
#include "Sim/Units/UnitDef.h"
#include <vector>
CR_BIND(CMetalMaker, (NULL))
CR_REG_METADATA(CMetalMaker, (
CR_MEMBER(myUnits),
CR_MEMBER(lastEnergy),
CR_MEMBER(ai),
CR_MEMBER(listIndex),
CR_MEMBER(addedDelay),
CR_RESERVED(16),
CR_POSTLOAD(PostLoad)
));
CR_BIND(CMetalMaker::UnitInfo, )
CR_REG_METADATA_SUB(CMetalMaker, UnitInfo, (
CR_MEMBER(id),
CR_MEMBER(energyUse),
CR_MEMBER(metalPerEnergy),
CR_MEMBER(turnedOn),
CR_RESERVED(8)
));
CMetalMaker::CMetalMaker(AIClasses* ai) {
listIndex = 0;
lastEnergy = 0;
addedDelay = 0;
this->ai = ai;
if (ai)
this->aicb = ai->cb;
}
CMetalMaker::~CMetalMaker() {
// for (map<int, UnitInfo*>::iterator ui = myUnits.begin(); ui != myUnits.end(); ++ui)
// delete ui->second;
myUnits.clear();
}
void CMetalMaker::PostLoad() {
this->aicb = ai->cb;
}
bool CMetalMaker::Add(int unit) {
const UnitDef* ud = aicb->GetUnitDef(unit);
if (!(ud->energyUpkeep > 0.0f && ud->makesMetal > 0.0f)) {
// can only use metal makers
return false;
}
// analyse the command
UnitInfo info;
const std::vector<CommandDescription>* cd = aicb->GetUnitCommands(unit);
for (std::vector<CommandDescription>::const_iterator cdi = cd->begin(); cdi != cd->end(); ++cdi) {
if (cdi->id == CMD_ONOFF) {
int on = atoi(cdi->params[0].c_str());
if (on)
info.turnedOn = true;
else
info.turnedOn = false;
break;
}
}
info.id = unit;
info.energyUse = ud->energyUpkeep;
info.metalPerEnergy = ud->makesMetal / ud->energyUpkeep;
// myUnits[unit] = info;
// myUnits.push_back(info);
// insert sorted by metalPerEnergy
bool inserted = false;
int counter = 0;
vector<UnitInfo>::iterator theIterator = myUnits.begin();
while (theIterator != myUnits.end() && !inserted) {
// insert it where it should be in order for the list to remain sorted (insertion sort)
if (info.metalPerEnergy > theIterator->metalPerEnergy ||
(info.metalPerEnergy == theIterator->metalPerEnergy &&
(aicb->GetUnitPos(info.id).x == aicb->GetUnitPos(theIterator->id).x &&
aicb->GetUnitPos(info.id).z > aicb->GetUnitPos(theIterator->id).z) ||
(info.metalPerEnergy == theIterator->metalPerEnergy &&
aicb->GetUnitPos(info.id).x > aicb->GetUnitPos(theIterator->id).x))
) {
myUnits.insert(theIterator, info);
inserted = true;
break;
}
theIterator++;
counter++;
}
if (!inserted) {
myUnits.push_back(info);
}
if (counter < listIndex) {
// make sure it's on and increase index
if (!myUnits[counter].turnedOn) {
Command c;
c.id = CMD_ONOFF;
c.params.push_back(1);
aicb->GiveOrder(myUnits[counter].id, &c);
myUnits[counter].turnedOn = true;
}
listIndex++;
} else {
// make sure it's off
if (myUnits[counter].turnedOn) {
Command c;
c.id = CMD_ONOFF;
c.params.push_back(0);
aicb->GiveOrder(myUnits[counter].id, &c);
myUnits[counter].turnedOn = false;
}
}
return true;
}
bool CMetalMaker::Remove(int unit) {
bool found = false;
int counter = 0;
vector<UnitInfo>::iterator it;
for (it = myUnits.begin(); it != myUnits.end(); it++) {
if (it->id == unit) {
found = true;
break;
}
counter++;
}
if (found)
myUnits.erase(it);
// is this index below listIndex?
if (counter < listIndex && listIndex > 0) {
listIndex--;
}
return found;
}
bool CMetalMaker::AllAreOn() {
return (this->listIndex == ((int) this->myUnits.size() - 1) || myUnits.size() == 0);
}
void CMetalMaker::Update(int frameNum) {
const int updateSpread = 33;
int numUnits = (int) myUnits.size();
if (frameNum % updateSpread == 0 && numUnits > 0 && addedDelay-- <= 0) {
// lastUpdate = frameNum;
float energy = aicb->GetEnergy();
float estore = aicb->GetEnergyStorage();
float difference = energy - lastEnergy;
difference /= 4.0f;
lastEnergy = energy;
// turn something off
if (energy < estore * 0.6) {
while (difference < 0 && listIndex > 0) {
// listIndex points at the first offline one,
// after decrement should be the last online one
listIndex--;
if (myUnits[listIndex].turnedOn) {
Command c;
c.id = CMD_ONOFF;
c.params.push_back(0);
aicb->GiveOrder(myUnits[listIndex].id, &c);
myUnits[listIndex].turnedOn = false;
difference += myUnits[listIndex].energyUse;
}
}
addedDelay = 4;
// turn something on
} else if (energy > estore * 0.9 && listIndex < numUnits) {
if (!myUnits[listIndex].turnedOn) {
Command c;
c.id = CMD_ONOFF;
c.params.push_back(1);
aicb->GiveOrder(myUnits[listIndex].id, &c);
myUnits[listIndex].turnedOn = true;
if (difference < myUnits[listIndex].energyUse)
addedDelay = 4;
}
//set it to point to the next one, which should be offline
listIndex++;
}
/*
// turn something off
if (energy < estore * 0.8) {
// how much energy we need to save to turn positive
float needed =- dif + 4;
for (int i = 0; i < (int) myUnits.size(); i++) {
// find makers to turn off
if (needed < 0)
break;
if (myUnits[i].turnedOn) {
needed -= myUnits[i].energyUse;
Command c;
c.id = CMD_ONOFF;
c.params.push_back(0);
aicb->GiveOrder(myUnits[i].id, &c);
myUnits[i].turnedOn = false;
}
}
// turn something on
} else if (energy > estore * 0.9) {
// how much energy we need to start using to turn negative
float needed = dif + 4;
for (int i = 0; i < (int) myUnits.size(); i++) {
// find makers to turn on
if (needed < 0)
break;
if (!myUnits[i].turnedOn) {
needed -= myUnits[i].energyUse;
Command c;
c.id = CMD_ONOFF;
c.params.push_back(1);
aicb->GiveOrder(myUnits[i].id, &c);
myUnits[i].turnedOn = true;
}
}
// ensure we don't waste any E (using too
// much is slightly more acceptable)
// lastUpdate = frameNum - updateSpread;
}
*/
}
if ((frameNum % 1800) == 0) {
// HACK: once a minute, turn everything off and reset
for (int i = 0; i < (int) myUnits.size(); i++) {
Command c;
c.id = CMD_ONOFF;
c.params.push_back(0);
aicb->GiveOrder(myUnits[i].id, &c);
myUnits[i].turnedOn = false;
}
this->listIndex = 0;
this->addedDelay = 0;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?