cyphesis/rulesets/Character.cpp
Al Riddoch 53a19dcef4 2003-10-23 Al Riddoch <alriddoch@zepler.org>
* rulesets/Movement.h, rulesets/Pedestrian.h: Update movement
	  interface to reflect the different jobs done by genMoveOperation().

	* rulesets/Movement.cpp: Fix badly named argument.

	* rulesets/Pedestrian.cpp: Shift code around a little to ensure
	  it is clear that genMoveUpdate() only produces an op if one
	  is necessary, but genMoveOperation() should always return
	  one.

	* rulesets/Character.cpp: Get rid of confusing logic now
	  That we know genMoveOperation() never returns NULL.
2003-10-23 19:18:04 +00:00

1053 lines
30 KiB
C++

// This file may be redistributed and modified only under the terms of
// the GNU General Public License (See COPYING for details).
// Copyright (C) 2000,2001 Alistair Riddoch
#include "Character.h"
#include "Pedestrian.h"
#include "MindFactory.h"
#include "BaseMind.h"
#include "Script.h"
#include "World.h"
#include "common/BaseWorld.h"
#include "common/op_switch.h"
#include "common/const.h"
#include "common/debug.h"
#include "common/globals.h"
#include "common/log.h"
#include "common/Setup.h"
#include "common/Tick.h"
#include "common/Cut.h"
#include "common/Eat.h"
#include "common/Nourish.h"
#include <wfmath/atlasconv.h>
#include <Atlas/Objects/Operation/Action.h>
#include <Atlas/Objects/Operation/Sound.h>
#include <Atlas/Objects/Operation/Set.h>
#include <Atlas/Objects/Operation/Delete.h>
#include <Atlas/Objects/Operation/Imaginary.h>
#include <Atlas/Objects/Operation/Look.h>
#include <Atlas/Objects/Operation/Talk.h>
#include <Atlas/Objects/Operation/Touch.h>
#include <Atlas/Objects/Operation/Sight.h>
#include <Atlas/Objects/Operation/Move.h>
#include <Atlas/Objects/Operation/Error.h>
#include <Atlas/Objects/Operation/Appearance.h>
#include <Atlas/Objects/Operation/Disappearance.h>
static const bool debug_flag = false;
OpVector Character::metabolise(double ammount)
{
// Currently handles energy
// We should probably call this whenever the entity performs a movement.
Element::MapType ent;
ent["id"] = getId();
if ((m_status > (1.5 + energyLoss)) && (m_mass < m_maxMass)) {
m_status = m_status - energyLoss;
ent["mass"] = m_mass + weightGain;
}
double energyUsed = energyConsumption * ammount;
if ((m_status <= energyUsed) && (m_mass > weightConsumption)) {
ent["status"] = m_status - energyUsed + energyGain;
ent["mass"] = m_mass - weightConsumption;
} else {
ent["status"] = m_status - energyUsed;
}
if (m_drunkness > 0) {
ent["drunkness"] = m_drunkness - 0.1;
}
Set * s = new Set(Set::Instantiate());
s->setTo(getId());
s->setArgs(Element::ListType(1,ent));
return OpVector(1,s);
}
Character::Character(const std::string & id) : Character_parent(id),
m_movement(*new Pedestrian(*this)),
m_drunkness(0.0), m_sex("female"),
m_food(0), m_maxMass(100),
m_isAlive(true), m_mind(NULL),
m_externalMind(NULL)
{
m_mass = 60;
m_location.m_bBox = BBox(WFMath::Point<3>(-0.25, -0.25, 0),
WFMath::Point<3>(0.25, 0.25, 2));
m_attributes["mode"] = "birth";
subscribe("imaginary", OP_IMAGINARY);
subscribe("tick", OP_TICK);
subscribe("talk", OP_TALK);
subscribe("eat", OP_EAT);
subscribe("nourish", OP_NOURISH);
// subscribe to ops from the mind
mindSubscribe("action", OP_ACTION);
mindSubscribe("setup", OP_SETUP);
mindSubscribe("tick", OP_TICK);
mindSubscribe("move", OP_MOVE);
mindSubscribe("set", OP_SET);
mindSubscribe("create", OP_CREATE);
mindSubscribe("delete", OP_DELETE);
mindSubscribe("imaginary", OP_IMAGINARY);
mindSubscribe("talk", OP_TALK);
mindSubscribe("look", OP_LOOK);
mindSubscribe("cut", OP_CUT);
mindSubscribe("eat", OP_EAT);
mindSubscribe("touch", OP_TOUCH);
mindSubscribe("shoot", OP_OTHER);
// subscribe to ops for the mind
w2mSubscribe("appearance", OP_APPEARANCE);
w2mSubscribe("disappearance", OP_DISAPPEARANCE);
w2mSubscribe("error", OP_ERROR);
w2mSubscribe("setup", OP_SETUP);
w2mSubscribe("tick", OP_TICK);
w2mSubscribe("sight", OP_SIGHT);
w2mSubscribe("sound", OP_SOUND);
w2mSubscribe("touch", OP_TOUCH);
}
Character::~Character()
{
delete &m_movement;
if (m_mind != NULL) {
delete m_mind;
}
if (m_externalMind != NULL) {
delete m_externalMind;
}
}
bool Character::get(const std::string & aname, Element & attr) const
{
if (aname == "drunkness") {
attr = m_drunkness;
return true;
} else if (aname == "sex") {
attr = m_sex;
return true;
}
return Character_parent::get(aname, attr);
}
void Character::set(const std::string & aname, const Element & attr)
{
if ((aname == "drunkness") && attr.isFloat()) {
m_drunkness = attr.asFloat();
m_update_flags |= a_drunk;
} else if ((aname == "sex") && attr.isString()) {
m_sex = attr.asString();
m_update_flags |= a_sex;
} else {
Character_parent::set(aname, attr);
}
}
void Character::addToObject(Element::MapType & omap) const
{
omap["sex"] = m_sex;
Character_parent::addToObject(omap);
}
OpVector Character::ImaginaryOperation(const Imaginary & op)
{
Sight * s = new Sight(Sight::Instantiate());
s->setArgs(Element::ListType(1,op.asObject()));
return OpVector(1,s);
}
OpVector Character::SetupOperation(const Setup & op)
{
debug( std::cout << "Character::tick" << std::endl << std::flush;);
OpVector res;
debug( std::cout << "CHaracter::Operation(setup)" << std::endl
<< std::flush;);
if (m_script->Operation("setup", op, res) != 0) {
return res;
}
if (op.hasAttr("sub_to")) {
debug( std::cout << "Has sub_to" << std::endl << std::flush;);
return res;
}
//mind = new BaseMind(getId(), m_name);
//std::string mind_class("NPCMind"), mind_package("mind.NPCMind");
//if (global_conf->findItem("mind", m_type)) {
//mind_package = global_conf->getItem("mind", m_type);
//mind_class = m_type + "Mind";
//}
//Create_PyMind(mind, mind_package, mind_class);
m_mind = MindFactory::instance()->newMind(getId(), m_name, m_type);
OpVector res2(2);
Setup * s = new Setup(op);
// THis is so not the right thing to do
s->setAttr("sub_to", "mind");
res2[0] = s;
Look * l = new Look(Look::Instantiate());
l->setTo(m_world->getId());
res2[1] = l;
if (m_location.m_loc != &m_world->m_gameWorld) {
l = new Look(Look::Instantiate());
l->setTo(m_location.m_loc->getId());
res2.push_back(l);
}
l = new Look(Look::Instantiate());
l->setTo(getId());
res2.push_back(l);
Tick * tick = new Tick(Tick::Instantiate());
tick->setTo(getId());
res2.push_back(tick);
return res2;
}
OpVector Character::TickOperation(const Tick & op)
{
if (op.hasAttr("sub_to")) {
debug( std::cout << "Has sub_to" << std::endl << std::flush;);
return OpVector();
}
debug(std::cout << "================================" << std::endl
<< std::flush;);
const Element::ListType & args = op.getArgs();
if ((!args.empty()) && (args.front().isMap())) {
// Deal with movement.
const Element::MapType & arg1 = args.front().asMap();
Element::MapType::const_iterator I = arg1.find("serialno");
if ((I != arg1.end()) && (I->second.isInt())) {
if (I->second.asInt() < m_movement.m_serialno) {
debug(std::cout << "Old tick" << std::endl << std::flush;);
return OpVector();
}
}
Location ret_loc;
Move * moveOp = m_movement.genMoveUpdate(&ret_loc);
if (moveOp) {
if (!m_movement.moving()) {
return OpVector (1,moveOp);
}
OpVector res(2);
Element::MapType entmap;
entmap["name"] = "move";
entmap["serialno"] = m_movement.m_serialno;
Tick * tickOp = new Tick(Tick::Instantiate());
tickOp->setTo(getId());
tickOp->setFutureSeconds(m_movement.getTickAddition(ret_loc.m_pos));
tickOp->setArgs(Element::ListType(1,entmap));
res[0] = tickOp;
res[1] = moveOp;
return res;
}
} else {
OpVector res;
m_script->Operation("tick", op, res);
// DIGEST
if ((m_food >= foodConsumption) && (m_status < 2)) {
// It is important that the metabolise bit is done next, as this
// handles the status change
m_status = m_status + foodConsumption;
m_food = m_food - foodConsumption;
Element::MapType food_ent;
food_ent["id"] = getId();
food_ent["food"] = m_food;
Set s = Set::Instantiate();
s.setTo(getId());
s.setArgs(Element::ListType(1,food_ent));
Sight * si = new Sight(Sight::Instantiate());
si->setTo(getId());
si->setArgs(Element::ListType(1,s.asObject()));
res.push_back(si);
}
// METABOLISE
OpVector mres = metabolise();
for(OpVector::const_iterator I = mres.begin(); I != mres.end(); I++) {
res.push_back(*I);
}
// TICK
Tick * tickOp = new Tick(Tick::Instantiate());
tickOp->setTo(getId());
tickOp->setFutureSeconds(consts::basic_tick * 30);
res.push_back(tickOp);
return res;
}
return OpVector();
}
OpVector Character::TalkOperation(const Talk & op)
{
debug( std::cout << "Character::OPeration(Talk)" << std::endl<<std::flush;);
Sound * s = new Sound(Sound::Instantiate());
s->setArgs(Element::ListType(1,op.asObject()));
return OpVector(1,s);
}
OpVector Character::EatOperation(const Eat & op)
{
// This is identical to Foof::Operation(Eat &)
// Perhaps animal should inherit from Food?
OpVector res;
if (m_script->Operation("eat", op, res) != 0) {
return res;
}
Element::MapType self_ent;
self_ent["id"] = getId();
self_ent["status"] = -1;
Set * s = new Set(Set::Instantiate());
s->setTo(getId());
s->setArgs(Element::ListType(1,self_ent));
const std::string & to = op.getFrom();
Element::MapType nour_ent;
nour_ent["id"] = to;
nour_ent["mass"] = m_mass;
Nourish * n = new Nourish(Nourish::Instantiate());
n->setTo(to);
n->setArgs(Element::ListType(1,nour_ent));
OpVector res2(2);
res2[0] = s;
res2[1] = n;
return res2;
}
OpVector Character::NourishOperation(const Nourish & op)
{
if (op.getArgs().empty()) {
return error(op, "Nourish has no argument", getId());
}
if (!op.getArgs().front().isMap()) {
return error(op, "Nourish arg is malformed", getId());
}
const Element::MapType & nent = op.getArgs().front().asMap();
Element::MapType::const_iterator I = nent.find("mass");
if ((I == nent.end()) || !I->second.isNum()) { return OpVector(); }
m_food = m_food + I->second.asNum();
Element::MapType food_ent;
food_ent["id"] = getId();
food_ent["food"] = m_food;
if (((I = nent.find("alcohol")) != nent.end()) && I->second.isNum()) {
m_drunkness += I->second.asNum() / m_mass;
food_ent["drunkness"] = m_drunkness;
}
Set s = Set::Instantiate();
s.setArgs(Element::ListType(1,food_ent));
Sight * si = new Sight(Sight::Instantiate());
si->setTo(getId());
si->setArgs(Element::ListType(1,s.asObject()));
return OpVector(1,si);
}
OpVector Character::mindLoginOperation(const Login & op)
{
return OpVector();
}
OpVector Character::mindLogoutOperation(const Logout & op)
{
return OpVector();
}
OpVector Character::mindActionOperation(const Action & op)
{
Action *a = new Action(op);
a->setTo(getId());
return OpVector(1,a);
}
OpVector Character::mindSetupOperation(const Setup & op)
{
Setup *s = new Setup(op);
s->setTo(getId());
s->setAttr("sub_to", "mind");
return OpVector(1,s);
}
OpVector Character::mindTickOperation(const Tick & op)
{
Tick *t = new Tick(op);
t->setTo(getId());
t->setAttr("sub_to", "mind");
return OpVector(1,t);
}
OpVector Character::mindMoveOperation(const Move & op)
{
debug( std::cout << "Character::mind_move_op" << std::endl << std::flush;);
const Element::ListType & args = op.getArgs();
if ((args.empty()) || (!args.front().isMap())) {
log(ERROR, "mindMoveOperation: move op has no argument");
return OpVector();
}
const Element::MapType & arg1 = args.front().asMap();
Element::MapType::const_iterator I = arg1.find("id");
if ((I == arg1.end()) || !I->second.isString()) {
log(ERROR, "mindMoveOperation: Args has got no id");
}
const std::string & oname = I->second.asString();
EntityDict::const_iterator J = m_world->getObjects().find(oname);
if (J == m_world->getObjects().end()) {
log(ERROR, "mindMoveOperation: This move op is for a phoney id");
return OpVector();
}
Entity * obj = J->second;
if (obj != this) {
debug( std::cout << "Moving something else. " << oname << std::endl << std::flush;);
if ((obj->getMass() < 0) || (obj->getMass() > m_mass)) {
debug( std::cout << "We can't move this. Just too heavy" << std::endl << std::flush;);
return OpVector();
}
Move * newop = new Move(op);
newop->setTo(oname);
return OpVector(1,newop);
}
std::string location_ref;
I = arg1.find("loc");
if ((I != arg1.end()) && (I->second.isString())) {
location_ref = I->second.asString();
} else {
debug( std::cout << "Parent not set" << std::endl << std::flush;);
}
Vector3D location_coords, location_vel;
Quaternion location_orientation;
try {
I = arg1.find("pos");
if (I != arg1.end()) {
location_coords.fromAtlas(I->second.asList());
debug( std::cout << "pos set to " << location_coords << std::endl << std::flush;);
}
I = arg1.find("velocity");
if (I != arg1.end()) {
location_vel.fromAtlas(I->second.asList());
debug( std::cout << "vel set to " << location_vel << std::endl << std::flush;);
}
I = arg1.find("orientation");
if (I != arg1.end()) {
location_orientation.fromAtlas(I->second.asList());
debug( std::cout << "ori set to " << location_orientation << std::endl << std::flush;);
}
}
catch (Atlas::Message::WrongTypeException) {
log(ERROR, "EXCEPTION: mindMoveOperation: Malformed move operation");
}
double futureSeconds = op.getFutureSeconds();
if (!location_coords.isValid()) {
if (futureSeconds < 0.) {
futureSeconds = 0.;
}
} else {
location_coords +=
(Vector3D(((double)rand())/RAND_MAX, ((double)rand())/RAND_MAX, 0)
* (m_drunkness * 10));
}
debug( std::cout << ":" << location_ref << ":" << m_location.m_loc->getId()
<< ":" << std::endl << std::flush;);
// At the moment we can't deal if the movement changes ref, or occurs
// in the past, so we just let it by unchanged.
if ((futureSeconds < 0.) ||
((location_ref != m_location.m_loc->getId()) &&
(!location_ref.empty())) ) {
Move * newop = new Move(op);
newop->setTo(getId());
newop->setFutureSeconds(futureSeconds);
return OpVector(1,newop);
}
// Movement within current ref. Work out the speed and stuff and
// use movement object to track movement.
//
double vel_mag;
if (!location_vel.isValid()) {
debug( std::cout << "\tVelocity default" << std::endl<<std::flush;);
vel_mag = consts::base_velocity;
} else {
debug( std::cout << "\tVelocity: " << location_vel
<< std::endl << std::flush;);
vel_mag = location_vel.mag();
if (vel_mag > consts::base_velocity) {
vel_mag = consts::base_velocity;
}
}
Vector3D direction;
// If the position is given, and it is about right, don't bother to
// use it.
if (location_coords.isValid() &&
(squareDistance(location_coords, m_location.m_pos) < 0.01)) {
location_coords = Vector3D();
}
if (!location_coords.isValid()) {
if (!location_vel.isValid() || isZero(location_vel)) {
debug( std::cout << "\tUsing orientation for direction"
<< std::endl << std::flush;);
// If velocity is not given, and target is not given,
// then we are not moving at all, so direction must
// remain invalid.
} else {
debug( std::cout << "\tUsing velocity for direction"
<< std::endl << std::flush;);
direction = location_vel;
}
} else {
debug( std::cout << "\tUsing destination for direction"
<< std::endl << std::flush;);
direction = Vector3D(location_coords) - m_location.m_pos;
}
if (direction.isValid()) {
direction.normalize();
debug( std::cout << "Direction: " << direction << std::endl
<< std::flush;);
if (!location_orientation.isValid()) {
// This is a character walking, so it should stap upright
Vector3D uprightDirection = direction;
uprightDirection[cZ] = 0;
uprightDirection.normalize();
location_orientation = quaternionFromTo(Vector3D(1,0,0),
uprightDirection);
debug( std::cout << "Orientation: " << location_orientation
<< std::endl << std::flush;);
}
}
Location ret_location;
Move * moveOp = m_movement.genMoveUpdate(&ret_location);
const Location & current_location = (NULL!=moveOp) ? ret_location : m_location;
m_movement.reset();
if ((vel_mag == 0) || !direction.isValid()) {
debug( std::cout << "\tMovement stopped" << std::endl
<< std::flush;);
if (NULL != moveOp) {
debug( std::cout << "Stop!" << std::endl << std::flush;);
Element::ListType & args = moveOp->getArgs();
Element::MapType & ent = args.front().asMap();
ent["velocity"] = Vector3D(0,0,0).toAtlas();
ent["mode"] = "standing";
if (location_orientation.isValid()) {
ent["orientation"] = location_orientation.toAtlas();
}
} else {
debug( std::cout << "Turn!" << std::endl << std::flush;);
m_movement.m_orientation = location_orientation;
moveOp = m_movement.genFaceOperation();
}
if (NULL != moveOp) {
return OpVector(1,moveOp);
}
return OpVector();
}
if (NULL != moveOp) {
delete moveOp;
}
Tick * tickOp = new Tick(Tick::Instantiate());
Element::MapType ent;
ent["serialno"] = m_movement.m_serialno;
ent["name"] = "move";
Element::ListType new_args(1,ent);
tickOp->setArgs(new_args);
tickOp->setTo(getId());
// Need to add the arguments to this op before we return it
// direction is already a unit vector
debug( if (location_coords.isValid()) { std::cout<<"\tUsing target"
<< std::endl
<< std::flush; } );
m_movement.m_targetPos = location_coords;
m_movement.m_velocity = direction;
m_movement.m_velocity *= vel_mag;
m_movement.m_orientation = location_orientation;
debug( std::cout << "Velocity " << vel_mag << std::endl << std::flush;);
moveOp = m_movement.genMoveOperation(NULL, current_location);
tickOp->setFutureSeconds(m_movement.getTickAddition(m_location.m_pos));
debug( std::cout << "Next tick " << tickOp->getFutureSeconds()
<< std::endl << std::flush;);
if (moveOp == NULL) {
// FIXME migrate this to being an assert
log(ERROR, "No move operation generated in mindMoveOp");
return OpVector();
}
// return moveOp and tickOp;
OpVector res(2);
res[0] = moveOp;
res[1] = tickOp;
return res;
}
OpVector Character::mindSetOperation(const Set & op)
{
const Element::ListType & args = op.getArgs();
if (args.front().isMap()) {
Set * s = new Set(op);
const Element::MapType & amap = args.front().asMap();
Element::MapType::const_iterator I = amap.find("id");
if (I != amap.end() && I->second.isString()) {
const std::string & opid = I->second.asString();
s->setTo(opid);
} else {
if (op.getTo().empty()) {
s->setTo(getId());
}
}
return OpVector(1,s);
}
return OpVector();
}
OpVector Character::mindSightOperation(const Sight & op)
{
return OpVector();
}
OpVector Character::mindSoundOperation(const Sound & op)
{
return OpVector();
}
OpVector Character::mindChopOperation(const Chop & op)
{
return OpVector();
}
OpVector Character::mindCombineOperation(const Combine & op)
{
return OpVector();
}
OpVector Character::mindCreateOperation(const Create & op)
{
Create * c = new Create(op);
c->setTo(getId());
return OpVector(1,c);
}
OpVector Character::mindDeleteOperation(const Delete & op)
{
Delete * d = new Delete(op);
d->setTo(getId());
return OpVector(1,d);
}
OpVector Character::mindDivideOperation(const Divide & op)
{
return OpVector();
}
OpVector Character::mindBurnOperation(const Burn & op)
{
return OpVector();
}
OpVector Character::mindGetOperation(const Get & op)
{
return OpVector();
}
OpVector Character::mindImaginaryOperation(const Imaginary & op)
{
Imaginary * i = new Imaginary(op);
i->setTo(getId());
return OpVector(1,i);
}
OpVector Character::mindInfoOperation(const Info & op)
{
return OpVector();
}
OpVector Character::mindNourishOperation(const Nourish & op)
{
return OpVector();
}
OpVector Character::mindTalkOperation(const Talk & op)
{
debug( std::cout << "Character::mindOPeration(Talk)"
<< std::endl << std::flush;);
Talk * t = new Talk(op);
t->setTo(getId());
return OpVector(1,t);
}
OpVector Character::mindLookOperation(const Look & op)
{
debug(std::cout << "Got look up from mind from [" << op.getFrom()
<< "] to [" << op.getTo() << "]" << std::endl << std::flush;);
m_perceptive = true;
Look * l = new Look(op);
if (op.getTo().empty()) {
const Element::ListType & args = op.getArgs();
if (args.empty()) {
l->setTo(m_world->getId());
} else {
if (args.front().isMap()) {
const Element::MapType & amap = args.front().asMap();
Element::MapType::const_iterator I = amap.find("id");
if (I != amap.end() && I->second.isString()) {
l->setTo(I->second.asString());
}
}
}
}
debug( std::cout <<" now to ["<<l->getTo()<<"]"<<std::endl<<std::flush;);
return OpVector(1,l);
}
OpVector Character::mindCutOperation(const Cut & op)
{
Cut * c = new Cut(op);
if (op.getTo().empty()) {
c->setTo(getId());
}
return OpVector(1,c);
}
OpVector Character::mindEatOperation(const Eat & op)
{
Eat * e = new Eat(op);
if (op.getTo().empty()) {
e->setTo(getId());
}
return OpVector(1,e);
}
OpVector Character::mindTouchOperation(const Touch & op)
{
Touch * t = new Touch(op);
// Work out what is being touched.
const Element::ListType & args = op.getArgs();
if ((op.getTo().empty()) || (!args.empty())) {
if (args.empty()) {
t->setTo(m_world->getId());
} else {
if (args.front().isMap()) {
const Element::MapType & amap = args.front().asMap();
Element::MapType::const_iterator I = amap.find("id");
if (I != amap.end() && I->second.isString()) {
t->setTo(I->second.asString());
}
} else if (args.front().isString()) {
t->setTo(args.front().asString());
}
}
}
// Pass the modified touch operation on to target.
OpVector res(2);
res[0] = t;
// Send action "touch"
Action * a = new Action(Action::Instantiate());
a->setTo(getId());
Element::MapType amap;
amap["id"] = getId();
amap["action"] = "touch";
Element::ListType setArgs(1,amap);
a->setArgs(setArgs);
res[1] = a;
return res;
}
OpVector Character::mindAppearanceOperation(const Appearance & op)
{
return OpVector();
}
OpVector Character::mindDisappearanceOperation(const Disappearance & op)
{
return OpVector();
}
OpVector Character::mindErrorOperation(const Error & op)
{
return OpVector();
}
OpVector Character::mindOtherOperation(const RootOperation & op)
{
RootOperation * e = new RootOperation(op);
if (op.getTo().empty()) {
e->setTo(getId());
}
return OpVector(1,e);
}
bool Character::w2mActionOperation(const Action & op)
{
return false;
}
bool Character::w2mLoginOperation(const Login & op)
{
return false;
}
bool Character::w2mLogoutOperation(const Logout & op)
{
return false;
}
bool Character::w2mChopOperation(const Chop & op)
{
return false;
}
bool Character::w2mCreateOperation(const Create & op)
{
return false;
}
bool Character::w2mCutOperation(const Cut & op)
{
return false;
}
bool Character::w2mDeleteOperation(const Delete & op)
{
return false;
}
bool Character::w2mEatOperation(const Eat & op)
{
return false;
}
bool Character::w2mBurnOperation(const Burn & op)
{
return false;
}
bool Character::w2mMoveOperation(const Move & op)
{
return false;
}
bool Character::w2mSetOperation(const Set & op)
{
return false;
}
bool Character::w2mLookOperation(const Look & op)
{
return false;
}
bool Character::w2mDivideOperation(const Divide & op)
{
return false;
}
bool Character::w2mCombineOperation(const Combine & op)
{
return false;
}
bool Character::w2mGetOperation(const Get & op)
{
return false;
}
bool Character::w2mImaginaryOperation(const Imaginary & op)
{
return false;
}
bool Character::w2mInfoOperation(const Info & op)
{
return false;
}
bool Character::w2mTalkOperation(const Talk & op)
{
return false;
}
bool Character::w2mNourishOperation(const Nourish & op)
{
return false;
}
bool Character::w2mAppearanceOperation(const Appearance & op)
{
if (m_drunkness > 1.0) {
return false;
}
return true;
}
bool Character::w2mDisappearanceOperation(const Disappearance & op)
{
if (m_drunkness > 1.0) {
return false;
}
return true;
}
bool Character::w2mErrorOperation(const Error & op)
{
return true;
}
bool Character::w2mOtherOperation(const RootOperation & op)
{
return true;
}
bool Character::w2mSetupOperation(const Setup & op)
{
if (op.hasAttr("sub_to")) {
return true;
}
return false;
}
bool Character::w2mTickOperation(const Tick & op)
{
if (op.hasAttr("sub_to")) {
return true;
}
return false;
}
bool Character::w2mSightOperation(const Sight & op)
{
if (m_drunkness > 1.0) {
return false;
}
return true;
}
bool Character::w2mSoundOperation(const Sound & op)
{
if (m_drunkness > 1.0) {
return false;
}
return true;
}
bool Character::w2mTouchOperation(const Touch & op)
{
if (m_drunkness > 1.0) {
return false;
}
return true;
}
OpVector Character::sendMind(const RootOperation & op)
{
debug( std::cout << "Character::sendMind" << std::endl << std::flush;);
if (0 != m_externalMind) {
if (0 != m_mind) {
OpVector res = m_mind->message(op);
// Discard all the local results
OpVector::const_iterator J = res.begin();
for(; J != res.end(); J++) {
delete *J;
}
}
debug(std::cout << "Sending to external mind" << std::endl
<< std::flush;);
debug(std::cout << "Using ops from external mind"
<< std::endl << std::flush;);
return m_externalMind->message(op);
} else {
debug(std::cout << "Using ops from local mind"
<< std::endl << std::flush;);
if (0 != m_mind) {
return m_mind->message(op);
}
}
// At this point there is a bunch of conversion stuff that I don't
// understand. This function has now been restructed heavily compared
// with the python version, and our ops don't really require conversion
// so this comment is not especiialy valid.
return OpVector();
}
OpVector Character::mind2body(const RootOperation & op)
{
debug( std::cout << "Character::mind2body" << std::endl << std::flush;);
if (m_drunkness > 1.0) {
return OpVector();
}
OpNo otype = opEnumerate(op, opMindLookup);
OP_SWITCH(op, otype, mind)
return OpVector();
}
OpVector Character::world2body(const RootOperation & op)
{
debug( std::cout << "Character::world2body" << std::endl << std::flush;);
return callOperation(op);
}
bool Character::world2mind(const RootOperation & op)
{
debug( std::cout << "Character::world2mind" << std::endl << std::flush;);
OpNo otype = opEnumerate(op, opW2mLookup);
OP_SWITCH(op, otype, w2m)
return false;
}
OpVector Character::externalMessage(const RootOperation & op)
{
debug( std::cout << "Character::externalMessage" << std::endl << std::flush;);
return externalOperation(op);
}
OpVector Character::operation(const RootOperation & op)
{
debug( std::cout << "Character::operation" << std::endl << std::flush;);
OpVector result = world2body(op);
// set refno on result?
if (!m_isAlive) {
return result;
}
if (world2mind(op)) {
OpVector mres2 = sendMind(op);
for(OpVector::const_iterator I = mres2.begin(); I != mres2.end(); I++) {
//RootOperation * mr2 = mind2_res.front();
// Need to be very careful about what this actually does
externalMessage(**I);
delete *I;
}
}
return result;
}
OpVector Character::externalOperation(const RootOperation & op)
{
debug( std::cout << "Character::externalOperation" << std::endl << std::flush;);
OpVector res = mind2body(op);
// We require that the first op is the direct consequence of the minds
// op, so it gets the same serialno
OpVector::const_iterator I = res.begin();
for(; I != res.end(); I++) {
if (I == res.begin()) {
(*I)->setSerialno(op.getSerialno());
} else {
m_world->setSerialnoOp(**I);
}
sendWorld(*I);
// Don't delete br as it has gone into worlds queue
// World will deal with it.
}
return OpVector();
}