mirror of
https://github.com/worldforge/cyphesis
synced 2026-08-13 12:26:04 -04:00
849 lines
27 KiB
C++
849 lines
27 KiB
C++
#include <Atlas/Message/Object.h>
|
|
#include <Atlas/Objects/Root.h>
|
|
#include <Atlas/Objects/Operation/Login.h>
|
|
#include <Atlas/Objects/Operation/Create.h>
|
|
#include <Atlas/Objects/Operation/Sound.h>
|
|
#include <Atlas/Objects/Operation/Create.h>
|
|
#include <Atlas/Objects/Operation/Set.h>
|
|
#include <Atlas/Objects/Operation/Delete.h>
|
|
#include <Atlas/Objects/Operation/Look.h>
|
|
#include <Atlas/Objects/Operation/Create.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 <varconf/Config.h>
|
|
|
|
extern "C" {
|
|
#include <stdlib.h>
|
|
}
|
|
|
|
// #define DEBUG_MOVEMENT
|
|
|
|
|
|
#include "Character.h"
|
|
#include "Thing.h"
|
|
|
|
#include "BaseMind.h"
|
|
#include "ExternalMind.h"
|
|
|
|
#include <server/WorldRouter.h>
|
|
|
|
#include <modules/Location.h>
|
|
|
|
#include <common/WorldInfo.h>
|
|
#include <common/const.h>
|
|
|
|
using Atlas::Message::Object;
|
|
|
|
static int debug_movement=0;
|
|
static int debug_character=0;
|
|
|
|
MovementInfo::MovementInfo(Character * body) : body(body)
|
|
{
|
|
serialno=-1;
|
|
reset();
|
|
debug_movement && cout << "MOVEMENTINFO: " << last_movement_time << endl << flush;
|
|
}
|
|
|
|
void MovementInfo::reset()
|
|
{
|
|
serialno = serialno+1;
|
|
target_location=Vector3D();
|
|
updated_location=Vector3D();
|
|
velocity=Vector3D(0,0,0);
|
|
last_movement_time=world_info::time;
|
|
}
|
|
|
|
bool MovementInfo::update_needed(const Location & location)
|
|
{
|
|
return((velocity!=Vector3D(0,0,0))||(location.velocity!=Vector3D(0,0,0)));
|
|
}
|
|
|
|
Move * MovementInfo::gen_face_operation(Location & loc)
|
|
{
|
|
if (face != loc.face) {
|
|
face = loc.face;
|
|
debug_movement && cout << "Turning" << endl << flush;
|
|
Move * moveOp = new Move;
|
|
*moveOp = Move::Instantiate();
|
|
moveOp->SetTo(body->fullid);
|
|
Object::MapType _map;
|
|
Object ent(_map);
|
|
Object::MapType & entmap = ent.AsMap();
|
|
entmap["id"] = body->fullid;
|
|
loc.addObject(&ent);
|
|
Object::ListType args(1,ent);
|
|
moveOp->SetArgs(args);
|
|
return moveOp;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
Move * MovementInfo::gen_move_operation(Location * rloc)
|
|
{
|
|
return(gen_move_operation(rloc, body->location));
|
|
}
|
|
|
|
Move * MovementInfo::gen_move_operation(Location * rloc, Location & loc)
|
|
{
|
|
debug_movement && cout << "gen_move_operation: status: MovementInfo(" << serialno
|
|
<< "," << target_location << "," << velocity << ","
|
|
<< last_movement_time << ")" << endl << flush;
|
|
if (update_needed(loc)) {
|
|
debug_movement && cout << "gen_move_operation: Update needed..." << endl << flush;
|
|
double current_time=world_info::time;
|
|
double time_diff=current_time-last_movement_time;
|
|
debug_movement && cout << "time_diff:" << time_diff << endl << flush;
|
|
last_movement_time=current_time;
|
|
Location new_loc=loc;
|
|
Object::MapType _map;
|
|
Object ent(_map);
|
|
Object::MapType & entmap = ent.AsMap();
|
|
new_loc.velocity=velocity;
|
|
Move * moveOp = new Move;
|
|
*moveOp = Move::Instantiate();
|
|
moveOp->SetTo(body->fullid);
|
|
entmap["id"] = body->fullid;
|
|
double vel_mag = velocity.mag();
|
|
double speed_ratio;
|
|
if (vel_mag == 0.0) {
|
|
speed_ratio = 0.0;
|
|
} else {
|
|
speed_ratio = vel_mag/consts::base_velocity;
|
|
}
|
|
string mode;
|
|
if (speed_ratio > 0.5) {
|
|
mode = string("running");
|
|
} else if (speed_ratio > 0.05) {
|
|
mode = string("walking");
|
|
} else {
|
|
mode = string("standing");
|
|
}
|
|
debug_movement && cout << "Mode set to " << mode << endl << flush;
|
|
|
|
face = loc.face;
|
|
|
|
entmap["mode"] = Object(mode);
|
|
if (!velocity) {
|
|
debug_movement && cout << "only velocity changed." << endl << flush;
|
|
new_loc.addObject(&ent);
|
|
Object::ListType args(1,ent);
|
|
moveOp->SetArgs(args);
|
|
if (NULL != rloc) {
|
|
*rloc = new_loc;
|
|
}
|
|
return(moveOp);
|
|
}
|
|
Vector3D new_coords;
|
|
if (updated_location) {
|
|
new_coords=updated_location+(velocity*time_diff);
|
|
} else {
|
|
new_coords=loc.coords+(velocity*time_diff);
|
|
}
|
|
if (target_location) {
|
|
Vector3D new_coords2 = new_coords+velocity/consts::basic_tick/10.0;
|
|
double dist=target_location.distance(new_coords);
|
|
double dist2=target_location.distance(new_coords2);
|
|
debug_movement && cout << "dist: " << dist << "," << dist2 << endl << flush;
|
|
if (dist2>dist) {
|
|
debug_movement && cout << "target achieved";
|
|
new_coords=target_location;
|
|
reset();
|
|
entmap["mode"] = Object("standing");
|
|
new_loc.velocity=velocity;
|
|
}
|
|
}
|
|
new_loc.coords = new_coords;
|
|
updated_location = new_coords;
|
|
debug_movement && cout << "new coordinates: " << new_coords << endl << flush;
|
|
new_loc.addObject(&ent);
|
|
Message::Object::ListType args2(1,ent);
|
|
moveOp->SetArgs(args2);
|
|
if (NULL != rloc) {
|
|
*rloc = new_loc;
|
|
}
|
|
return(moveOp);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
double MovementInfo::get_tick_addition(const Vector3D & coordinates)
|
|
{
|
|
double basic_distance=velocity.mag()*consts::basic_tick;
|
|
if (target_location) {
|
|
double distance=coordinates.distance(target_location);
|
|
debug_movement && cout << "basic_distance: " << basic_distance << endl << flush;
|
|
debug_movement && cout << "distance: " << distance << endl << flush;
|
|
if (basic_distance>distance) {
|
|
debug_movement && cout << "\tshortened tick" << endl << flush;
|
|
return distance/basic_distance*consts::basic_tick;
|
|
}
|
|
}
|
|
return consts::basic_tick;
|
|
}
|
|
|
|
Character::Character() : movement(this), autom(0),
|
|
mind(NULL), external_mind(NULL), player(NULL),
|
|
drunkness(0.0)
|
|
{
|
|
attributes["weight"] = Object(double(60.0));
|
|
attributes["sex"] = Object("female");
|
|
is_character = 1;
|
|
}
|
|
|
|
Character::~Character()
|
|
{
|
|
if (mind != NULL) {
|
|
delete mind;
|
|
}
|
|
if (external_mind != NULL) {
|
|
delete external_mind;
|
|
}
|
|
}
|
|
|
|
extern varconf::Config * global_conf;
|
|
|
|
oplist Character::Operation(const Setup & op)
|
|
{
|
|
debug_character && cout << "Character::tick" << endl << flush;
|
|
oplist res;
|
|
debug_character && cout << "CHaracter::Operation(setup)" << endl << flush;
|
|
if (script_Operation("setup", op, res) != 0) {
|
|
return(res);
|
|
}
|
|
if (op.HasAttr("sub_to")) {
|
|
debug_character && cout << "Has sub_to" << endl << flush;
|
|
return(res);
|
|
}
|
|
|
|
mind = new BaseMind(fullid, name);
|
|
string mind_class("NPCMind"), mind_package("mind.NPCMind");
|
|
if (global_conf->findItem("minds", type)) {
|
|
mind_package = global_conf->getItem("minds", type);
|
|
mind_class = type + "Mind";
|
|
}
|
|
Create_PyThing(mind, mind_package, mind_class);
|
|
|
|
Setup * s = new Setup(op);
|
|
// THis is so not the right thing to do
|
|
s->SetAttr("sub_to", Message::Object("mind"));
|
|
res.push_back(s);
|
|
Look * l = new Look();
|
|
*l = Look::Instantiate();
|
|
l->SetTo(world->fullid);
|
|
res.push_back(l);
|
|
if (location.parent != world) {
|
|
l = new Look();
|
|
*l = Look::Instantiate();
|
|
l->SetTo(location.parent->fullid);
|
|
res.push_back(l);
|
|
}
|
|
l = new Look();
|
|
*l = Look::Instantiate();
|
|
l->SetTo(fullid);
|
|
res.push_back(l);
|
|
RootOperation * tick = new Tick;
|
|
*tick = Tick::Instantiate();
|
|
tick->SetTo(fullid);
|
|
res.push_back(tick);
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::Operation(const Tick & op)
|
|
{
|
|
oplist res;
|
|
if (op.HasAttr("sub_to")) {
|
|
debug_character && cout << "Has sub_to" << endl << flush;
|
|
return(res);
|
|
}
|
|
#ifdef DEBUG_MOVEMENT
|
|
cout << "================================" << endl << flush;
|
|
#endif /* DEBUG_MOVEMENT */
|
|
const Message::Object::ListType & args = op.GetArgs();
|
|
if ((0 != args.size()) && (args.front().IsMap())) {
|
|
Message::Object::MapType arg1 = args.front().AsMap();
|
|
if ((arg1.find("serialno") != arg1.end()) &&
|
|
(arg1["serialno"].IsInt())) {
|
|
if (arg1["serialno"].AsInt() < movement.serialno) {
|
|
#ifdef DEBUG_MOVEMENT
|
|
cout << "Old tick" << endl << flush;
|
|
#endif /* DEBUG_MOVEMENT */
|
|
return(res);
|
|
}
|
|
}
|
|
Location ret_loc;
|
|
RootOperation * moveOp = movement.gen_move_operation(&ret_loc);
|
|
if (moveOp) {
|
|
Message::Object::MapType entmap;
|
|
entmap["name"]=Message::Object("move");
|
|
entmap["serialno"]=Message::Object(movement.serialno);
|
|
Message::Object ent(entmap);
|
|
RootOperation * tickOp = new Tick();
|
|
*tickOp = Tick::Instantiate();
|
|
tickOp->SetTo(fullid);
|
|
tickOp->SetFutureSeconds(movement.get_tick_addition(ret_loc.coords));
|
|
tickOp->SetArgs(Message::Object::ListType(1,ent));
|
|
res.push_back(tickOp);
|
|
res.push_back(moveOp);
|
|
}
|
|
} else {
|
|
// Could implement quite a lot of Animal.py here.
|
|
script_Operation("tick", op, res);
|
|
RootOperation * tickOp = new Tick();
|
|
*tickOp = Tick::Instantiate();
|
|
tickOp->SetTo(fullid);
|
|
tickOp->SetFutureSeconds(consts::basic_tick);
|
|
res.push_back(tickOp);
|
|
}
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::Operation(const Talk & op)
|
|
{
|
|
debug_character && cout << "Character::OPeration(Talk)" << endl << flush;
|
|
Sound * s = new Sound();
|
|
*s = Sound::Instantiate();
|
|
Message::Object::ListType args(1,op.AsObject());
|
|
s->SetArgs(args);
|
|
return(oplist(1,s));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Setup & op)
|
|
{
|
|
Setup *s = new Setup(op);
|
|
s->SetTo(fullid);
|
|
s->SetAttr("sub_to", Message::Object("mind"));
|
|
return(oplist(1,s));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Tick & op)
|
|
{
|
|
Tick *t = new Tick(op);
|
|
t->SetTo(fullid);
|
|
t->SetAttr("sub_to", Message::Object("mind"));
|
|
return(oplist(1,t));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Move & op)
|
|
{
|
|
debug_movement && cout << "Character::mind_move_op" << endl << flush;
|
|
oplist res;
|
|
Move * newop = new Move(op);
|
|
const Message::Object::ListType & args = op.GetArgs();
|
|
if ((0 == args.size()) || (!args.front().IsMap())) {
|
|
cerr << "move op has no argument" << endl << flush;
|
|
}
|
|
Message::Object::MapType arg1 = args.front().AsMap();
|
|
if ((arg1.find("id") == arg1.end()) || !arg1["id"].IsString()) {
|
|
cerr << "Its got no id" << endl << flush;
|
|
}
|
|
string & oname = arg1["id"].AsString();
|
|
if (world->fobjects.find(oname) == world->fobjects.end()) {
|
|
debug_movement && cout << "This move op is for a phoney object" << endl << flush;
|
|
delete newop;
|
|
return res;
|
|
}
|
|
Thing * obj = (Thing *)world->fobjects[oname];
|
|
if (obj != this) {
|
|
debug_movement && cout << "Moving something else. " << oname << endl << flush;
|
|
try {
|
|
double weight = attributes["weight"].AsFloat();
|
|
Object & ow = (*obj)["weight"];
|
|
double oweight;
|
|
if (ow.IsInt()) {
|
|
oweight = double(ow.AsInt());
|
|
} else {
|
|
oweight = ow.AsFloat();
|
|
}
|
|
if ((oweight < 0) || (oweight > weight)) {
|
|
debug_movement && cout << "We can't move this. Just too heavy" << endl << flush;
|
|
delete newop;
|
|
return(res);
|
|
}
|
|
}
|
|
catch (...) {
|
|
cerr << "EXCEPTION: caught while checking " << obj->fullid
|
|
<< " weight for movement of " << fullid << endl << flush;
|
|
}
|
|
newop->SetTo(oname);
|
|
res.push_back(newop);
|
|
return(res);
|
|
}
|
|
string location_parent;
|
|
if ((arg1.find("loc") != arg1.end()) && (arg1["loc"].IsString())) {
|
|
location_parent = arg1["loc"].AsString();
|
|
} else {
|
|
debug_movement && cout << "Parent not set" << endl << flush;
|
|
}
|
|
Vector3D location_coords;
|
|
if ((arg1.find("pos") != arg1.end()) && (arg1["pos"].IsList())) {
|
|
Message::Object::ListType vector = arg1["pos"].AsList();
|
|
if (vector.size()==3) {
|
|
try {
|
|
double x = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double y = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double z = vector.front().AsFloat();
|
|
location_coords = Vector3D(x, y, z);
|
|
debug_movement && cout << "Got new format coords: " << location_coords << endl << flush;
|
|
}
|
|
catch (Message::WrongTypeException) {
|
|
cerr << "EXCEPTION: Malformed pos move operation" << endl << flush;
|
|
}
|
|
}
|
|
}
|
|
|
|
Vector3D location_vel;
|
|
if ((arg1.find("velocity") != arg1.end()) && (arg1["velocity"].IsList())) {
|
|
Message::Object::ListType vector = arg1["velocity"].AsList();
|
|
if (vector.size()==3) {
|
|
try {
|
|
double x = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double y = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double z = vector.front().AsFloat();
|
|
location_vel = Vector3D(x, y, z);
|
|
debug_movement && cout << "Got new format velocity: " << location_vel << endl << flush;
|
|
}
|
|
catch (Message::WrongTypeException) {
|
|
cerr << "EXCEPTION: Malformed vel move operation" << endl << flush;
|
|
}
|
|
}
|
|
}
|
|
Vector3D location_face;
|
|
if ((arg1.find("face") != arg1.end()) && (arg1["face"].IsList())) {
|
|
Message::Object::ListType vector = arg1["face"].AsList();
|
|
if (vector.size()==3) {
|
|
try {
|
|
double x = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double y = vector.front().AsFloat();
|
|
vector.pop_front();
|
|
double z = vector.front().AsFloat();
|
|
location_face = Vector3D(x, y, z);
|
|
debug_movement && cout << "Got new format face: " << location_face << endl << flush;
|
|
}
|
|
catch (Message::WrongTypeException) {
|
|
cerr << "EXCEPTION: Malformed face move operation" << endl << flush;
|
|
}
|
|
}
|
|
}
|
|
if (!location_coords) {
|
|
if (op.GetFutureSeconds() < 0) {
|
|
newop->SetFutureSeconds(0);
|
|
}
|
|
} else {
|
|
location_coords = location_coords +
|
|
(Vector3D(((double)rand())/RAND_MAX, ((double)rand())/RAND_MAX, 0)
|
|
* drunkness * 10);
|
|
}
|
|
double vel_mag;
|
|
// Print out a bunch of debug info
|
|
debug_movement && cout << ":" << location_parent << ":" << world->fullid << ":" << location.parent->fullid << ":" << endl << flush;
|
|
if ( (location_parent==world->fullid) &&
|
|
(location_parent==location.parent->fullid) &&
|
|
(newop->GetFutureSeconds() >= 0) ) {
|
|
// Movement within current parent. Work out the speed and stuff and
|
|
// use movementinfo to track movement.
|
|
if (!location_vel) {
|
|
debug_movement && cout << "\tVelocity default" << endl << flush;
|
|
vel_mag=consts::base_velocity;
|
|
} else {
|
|
vel_mag=location_vel.mag();
|
|
if (vel_mag > consts::base_velocity) {
|
|
vel_mag = consts::base_velocity;
|
|
}
|
|
debug_movement && cout << "\tVelocity given: " << location_vel
|
|
<< "," << vel_mag << endl << flush;
|
|
}
|
|
if (location_face) {
|
|
location.face = location_face;
|
|
}
|
|
|
|
Vector3D direction;
|
|
if (location_coords == location.coords) {
|
|
location_coords = Vector3D();
|
|
}
|
|
if (!location_coords) {
|
|
if (!location_vel || (location_vel==Vector3D(0,0,0))) {
|
|
debug_movement && cout << "\tUsing face for direction" << endl << flush;
|
|
direction=location.face;
|
|
} else {
|
|
debug_movement && cout << "\tUsing velocity for direction" << endl << flush;
|
|
direction=location_vel;
|
|
}
|
|
} else {
|
|
debug_movement && cout << "\tUsing destination coords for direction" << endl << flush;
|
|
direction=location_coords-location.coords;
|
|
}
|
|
if (!direction) {
|
|
debug_movement && cout << "No direction" << endl << flush;
|
|
} else {
|
|
direction=direction.unit_vector();
|
|
debug_movement && cout << "Direction: " << direction << endl << flush;
|
|
}
|
|
if (!location_face) {
|
|
location.face = direction;
|
|
}
|
|
Location ret_location;
|
|
Location current_location;
|
|
RootOperation * moveOp = movement.gen_move_operation(&ret_location);
|
|
if (NULL!=moveOp) {
|
|
current_location = ret_location;
|
|
} else {
|
|
current_location = location;
|
|
}
|
|
movement.reset();
|
|
if ((vel_mag==0) || !direction) {
|
|
debug_movement && cout << "\tMovement stopped" << endl << flush;
|
|
if (NULL != moveOp) {
|
|
Message::Object::ListType & args = moveOp->GetArgs();
|
|
Message::Object::MapType & ent = args.front().AsMap();
|
|
Message::Object::ListType velocity;
|
|
velocity.push_back(Message::Object(0.0));
|
|
velocity.push_back(Message::Object(0.0));
|
|
velocity.push_back(Message::Object(0.0));
|
|
ent["velocity"]=Message::Object(velocity);
|
|
ent["mode"]=Message::Object("standing");
|
|
moveOp->SetArgs(args);
|
|
res.push_back(moveOp);
|
|
} else {
|
|
moveOp = movement.gen_face_operation(location);
|
|
if (NULL != moveOp) {
|
|
res.push_back(moveOp);
|
|
}
|
|
}
|
|
delete newop;
|
|
return(res);
|
|
}
|
|
RootOperation * tickOp = new Tick;
|
|
*tickOp = Tick::Instantiate();
|
|
Message::Object::MapType ent;
|
|
ent["serialno"] = Message::Object(movement.serialno);
|
|
ent["name"] = Message::Object("move");
|
|
Message::Object::ListType args(1,ent);
|
|
tickOp->SetArgs(args);
|
|
tickOp->SetTo(fullid);
|
|
// Need to add the arguments to this op before we return it
|
|
// direction is already a unit vector
|
|
if (!location_coords) {
|
|
debug_movement && cout << "\tNo target location" << endl << flush;
|
|
movement.target_location = Vector3D();
|
|
} else {
|
|
debug_movement && cout << "\tUsing target location" << endl << flush;
|
|
movement.target_location = location_coords;
|
|
}
|
|
movement.velocity=direction*vel_mag;
|
|
debug_movement && cout << "Velocity " << vel_mag << endl << flush;
|
|
RootOperation * moveOp2 = movement.gen_move_operation(NULL,current_location);
|
|
tickOp->SetFutureSeconds(movement.get_tick_addition(location.coords));
|
|
debug_movement && cout << "Next tick " << tickOp->GetFutureSeconds() << endl << flush;
|
|
if (NULL!=moveOp2) {
|
|
if (NULL!=moveOp) {
|
|
delete moveOp;
|
|
}
|
|
moveOp=moveOp2;
|
|
}
|
|
// return moveOp and tickOp;
|
|
res.push_back(moveOp);
|
|
res.push_back(tickOp);
|
|
delete newop;
|
|
return(res);
|
|
}
|
|
res.push_back(newop);
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Set & op)
|
|
{
|
|
Set * s = new Set(op);
|
|
const Message::Object::ListType & args = op.GetArgs();
|
|
if (args.front().IsMap()) {
|
|
Message::Object::MapType amap = args.front().AsMap();
|
|
if (amap.find("id") != amap.end() && amap["id"].IsString()) {
|
|
string opid = amap["id"].AsString();
|
|
if (opid != fullid) {
|
|
s->SetTo(opid);
|
|
}
|
|
}
|
|
}
|
|
return(oplist(1,s));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Create & op)
|
|
{
|
|
// We need to call, THE THING FACTORY!
|
|
debug_character && cout << "Character::Mind_Operation(Create)" << endl << flush;
|
|
oplist res;
|
|
return(res);
|
|
}
|
|
|
|
#if 0
|
|
bad_type Character::mind_create_operation(bad_type op)
|
|
{
|
|
if (not init.security_flag) {
|
|
ent=op[0];
|
|
ent.status=0.1;
|
|
return op;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
oplist Character::Mind_Operation(const Delete & op)
|
|
{
|
|
Delete * d = new Delete(op);
|
|
return(oplist(1,d));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Talk & op)
|
|
{
|
|
debug_character && cout << "Character::Mind_OPeration(Talk)" << endl << flush;
|
|
Talk * t = new Talk(op);
|
|
return(oplist(1,t));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Look & op)
|
|
{
|
|
cout << "Got look up from mind from [" << op.GetFrom() << "] to ["
|
|
<< op.GetTo() << "]" << endl << flush;
|
|
Look * l = new Look(op);
|
|
if (op.GetTo().size() == 0) {
|
|
const Message::Object::ListType & args = op.GetArgs();
|
|
if (args.size() == 0) {
|
|
l->SetTo(world->fullid);
|
|
} else {
|
|
if (args.front().IsMap()) {
|
|
Message::Object::MapType amap = args.front().AsMap();
|
|
if (amap.find("id") != amap.end() && amap["id"].IsString()) {
|
|
l->SetTo(amap["id"].AsString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cout << " now to [" << l->GetTo() << "]" << endl << flush;
|
|
return(oplist(1,l));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Cut & op)
|
|
{
|
|
Cut * c = new Cut(op);
|
|
return(oplist(1,c));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Eat & op)
|
|
{
|
|
Eat * e = new Eat(op);
|
|
return(oplist(1,e));
|
|
}
|
|
|
|
oplist Character::Mind_Operation(const Touch & op)
|
|
{
|
|
Touch * t = new Touch(op);
|
|
const Message::Object::ListType & args = op.GetArgs();
|
|
if ((op.GetTo().size() == 0) || (args.size() != 0)) {
|
|
if (args.size() == 0) {
|
|
t->SetTo(world->fullid);
|
|
} else {
|
|
if (args.front().IsMap()) {
|
|
Message::Object::MapType amap = args.front().AsMap();
|
|
if (amap.find("id") != amap.end() && amap["id"].IsString()) {
|
|
t->SetTo(amap["id"].AsString());
|
|
}
|
|
} else if (args.front().IsString()) {
|
|
t->SetTo(args.front().AsString());
|
|
}
|
|
}
|
|
}
|
|
return(oplist(1,t));
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Error & op)
|
|
{
|
|
Error * e = new Error(op);
|
|
return(oplist(1,e));
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Setup & op)
|
|
{
|
|
oplist res;
|
|
if (op.HasAttr("sub_to")) {
|
|
Setup * s = new Setup(op);
|
|
res.push_back(s);
|
|
}
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Tick & op)
|
|
{
|
|
oplist res;
|
|
if (op.HasAttr("sub_to")) {
|
|
Tick * t = new Tick(op);
|
|
res.push_back(t);
|
|
}
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Sight & op)
|
|
{
|
|
oplist res;
|
|
if (drunkness > 1.0) {
|
|
return(res);
|
|
}
|
|
Sight * s = new Sight(op);
|
|
res.push_back(s);
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Sound & op)
|
|
{
|
|
oplist res;
|
|
if (drunkness > 1.0) {
|
|
return(res);
|
|
}
|
|
Sound * s = new Sound(op);
|
|
res.push_back(s);
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::W2m_Operation(const Touch & op)
|
|
{
|
|
oplist res;
|
|
if (drunkness > 1.0) {
|
|
return(res);
|
|
}
|
|
Touch * t = new Touch(op);
|
|
res.push_back(t);
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::send_mind(const RootOperation & msg)
|
|
{
|
|
debug_character && cout << "Character::send_mind" << endl << flush;
|
|
oplist res;
|
|
if (mind == NULL) {
|
|
return(res);
|
|
}
|
|
oplist local_res;
|
|
oplist external_res;
|
|
local_res = mind->message(msg);
|
|
|
|
if ((NULL != external_mind) && (NULL != external_mind->connection)) {
|
|
debug_character && cout << "Sending to external mind" << endl << flush;
|
|
external_res = external_mind->message(msg);
|
|
// If there is some kinf of error in the connection, we turn autom on
|
|
} else {
|
|
//return(*(RootOperation **)NULL);
|
|
if (autom == 0) {
|
|
debug_character && cout << "Turning automatic on for " << fullid << endl << flush;
|
|
autom = 1;
|
|
if (external_mind != NULL) {
|
|
delete external_mind;
|
|
external_mind = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (autom) {
|
|
debug_character && cout << "Using " << local_res.size() << " ops from local mind"
|
|
<< endl << flush;
|
|
res = local_res;
|
|
} else {
|
|
res = external_res;
|
|
debug_character && cout << "Using " << local_res.size() << " ops from external mind"
|
|
<< endl << flush;
|
|
}
|
|
// At this point there is a bunch of conversion stuff that I don't
|
|
// understand
|
|
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::mind2body(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::mind2body" << endl << flush;
|
|
RootOperation newop(op);
|
|
oplist res;
|
|
|
|
if ((newop.GetTo().size() == 0) &&
|
|
(op.GetParents().front().AsString() != "look")) {
|
|
newop.SetTo(fullid);
|
|
}
|
|
if (drunkness > 1.0) {
|
|
return(res);
|
|
}
|
|
op_no_t otype = op_enumerate(&newop);
|
|
OP_SWITCH(newop, otype, res, Mind_)
|
|
// Set refno?
|
|
// do debugging?
|
|
//Nothing done yet, must try harder
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::world2body(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::world2body" << endl << flush;
|
|
oplist res = call_operation(op);
|
|
// Set refno?
|
|
// do debugging?
|
|
//Nothing done yet, must try harder
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::world2mind(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::world2mind" << endl << flush;
|
|
op_no_t otype = op_enumerate(&op);
|
|
oplist res;
|
|
OP_SWITCH(op, otype, res, W2m_)
|
|
// Set refno?
|
|
// do debugging?
|
|
//Nothing done yet, must try harder
|
|
return(res);
|
|
}
|
|
|
|
oplist Character::external_message(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::external_message" << endl << flush;
|
|
return external_operation(op);
|
|
}
|
|
|
|
oplist Character::operation(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::operation" << endl << flush;
|
|
oplist result = world2body(op);
|
|
oplist mind_res = world2mind(op);
|
|
while (mind_res.size() != 0) {
|
|
RootOperation * mr = mind_res.front();
|
|
oplist mind2_res = send_mind(*mr);
|
|
while (mind2_res.size() != 0) {
|
|
RootOperation * mr2 = mind2_res.front();
|
|
// Need to be very careful about what this actually does
|
|
external_message(*mr2);
|
|
mind2_res.pop_front();
|
|
delete mr2;
|
|
}
|
|
mind_res.pop_front();
|
|
delete mr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
oplist Character::external_operation(const RootOperation & op)
|
|
{
|
|
debug_character && cout << "Character::external_operation" << endl << flush;
|
|
oplist body_res = mind2body(op);
|
|
|
|
while (body_res.size() != 0) {
|
|
RootOperation * br = body_res.front();
|
|
send_world(br);
|
|
body_res.pop_front();
|
|
// Don't delete br as it has gone into worlds queue
|
|
// World will deal with it.
|
|
}
|
|
oplist res;
|
|
return(res);
|
|
}
|