Author Topic: Peculiarity with Humanoid.c  (Read 3365 times)

Offline amylase

  • Friend
  • **
  • Posts: 75
    • View Profile
    • gpLand
Peculiarity with Humanoid.c
« on: December 18, 2006, 03:28:20 am »
Hi guys, I made a robot from a combination of charly, jennybot and drone (please see remarks next to heart_beat for aim of this robot). Cut long story short it's an NPC holding on to one giant array mapping which contains descriptions and paths of the environmenmt. The robot works fine in every way I intended it to. The only problem now is most other usual commands (eg. ds, scan, about) cease to work as long as the robot is loaded. Even intergossip and various chat channels stopped coming in. I can still navigate around north/south/west/east and perform limited commands such as look, stand, mudlist. I have no idea why this is so. Please advise. Thanks heaps.

Code: [Select]
#include <lib.h>
#include <save.h>
#include <privs.h>
#include "/daemon/include/races.h"

inherit LIB_NPC;
inherit LIB_DAEMON;

// A few global variables for incoming messages and robot status (report 1 for ON, 0 for OFF). m7 will later contain time stamped message. fp points to whoever activates the robot.
string mm, vv, printvar, s1="";
int report=0;
object fp, dude,ww;
mapping m7 = ([ ]);

// ShowExits grabs exits and entries. Other things eg. living, items, descriptions are left for later in ShowEnv.
mapping *ShowExits()
    string *asExits, *asEnters, sDir, sExit;
    object oEnv;
    mapping mexits = ([ ]), mentries = ([ ]);

    oEnv = environment( this_player() );
    asExits = oEnv->GetExits();
    asEnters = oEnv->GetEnters();

    foreach( sExit in asExits ) { mexits += ([ sExit: oEnv->GetExit( sExit ) ]);}
    foreach( sExit in asEnters ) { mentries += ([ sExit: oEnv->GetEnter( sExit ) ]);}
    return ({mexits, mentries});

mapping *ShowEnv(){ 
    string foo,goo,descc,smell,sound,touch,filename;
    object envv, test, *invarr;
    object array *living;
    object array people;
    int k, countdown, i=0;
    mapping mitems = ([ ]), msenses = ([ ]), mshortdesc = ([ ]), mlongdesc = ([ ]), mlivings = ([ ]);

    // Feeds living things into mapping mlivings. Use argument 1 in get_livings() for interactive living things (players and creators) and non-interactive living things. Use argument 2 for non-interactive living things only.   
    if(sizeof(people)) foreach(object dude in people){mlivings += ([ dude->GetName() : file_name(dude) ]);}
    envv = environment(this_object());
    invarr = all_inventory(envv);
    countdown = sizeof(invarr);
    while(countdown-- >0){
test = invarr[i];
if(!living(test)) {
mitems += ([ test->GetName(): file_name(test) ]);

// if(!living(test) && !sscanf(file_name(test),"/lib/std/dummy#%s",s1) ) message( "my_action", sprintf( "\t%10s (%s) [Non-dummy genuine item]", test->GetName(), file_name(test) ), this_player() );
// if(!living(test) && sscanf(file_name(test),"/lib/std/dummy#%s",s1) ) message( "my_action", sprintf( "\t%10s (%s) [Dummy]", test->GetName(), file_name(test) ), this_player() );
} /*ENDIF*/

// Self-explanatory. Grabs smell, sounds, touch sensations.
smell = envv->GetSmell();
msenses += ([ "smell" : smell ]);
sound = envv->GetListen();
msenses += ([ "sound" : sound ]);
touch = envv->GetTouch();
msenses += ([ "touch" : touch ]);

goo = base_name(environment(find_object(file_name(this_player()))));
foo = get_object(goo)->GetLong();
mshortdesc += ([ get_object(goo)->GetShort() : base_name(environment(this_player())) ]); //Grabs short description of the room this robot (ie. this_player()) is in.
mlongdesc += ([ "long" : foo ]); // Long description of the room this robot is in.

return ({mshortdesc, mlongdesc, mlivings, mitems, msenses}); // Return descriptions, livings, items and sense back to heart_beat.

static void create() {
    SetLong("This humanoid aims to simulate a real human in terms of awareness to surrounding. This happens at two levels: firstly as a player (mere names and descriptions), secondly as a programmer (specific paths, filenames, settings and attributes behind the scene). Program anything you please in heart_beat() for the NPC to react to its environment. Activate humanoid's report mode by telling it HUMANOID REPORT ON. Close report mode by telling it HUMANOID REPORT OFF. Report mode reports to you all that this NPC perceives real time.");

void init(){

void receive_message(string string1, string string2){
m7 = ([ ctime(time())[11..18] : string2 ]);
if(report==1) message( "my_action", sprintf( "*** SPONTANEOUS NEW RECEIVE_MESSAGE CAPTURED FROM ORIGINAL receive_message() ***\n\t  %s %s\n", ctime(time())[11..18] ,string2), fp);
// While heart beats, receive_message also simultaneously does its job listening for incoming messages.
// Anything that comes through is placed in string2. String2 is timestamped and the result stored in global mapping m7 for heart_beat to listen to at its own rate.
// Note if the rate at which messages come in (to receive_message()) is faster than heart beats(ie. the rate heart_beat() listens to m7), then there obviously will be messages missed out by heart_beat.
// To ensure integrity you can intervene here directly rather than wait for m7 in heart_beat.

// To turn the robot on, tell it in capitals HUMANOID REPORT ON. This will assign 1 to global integer report. With report =1 various message() throughout this file will start to display information to fp (ie. the player who issued this activation command)..
if(sscanf(string2,"%s tells: HUMANOID REPORT ON.",s1)>0){
report = 1;
fp = find_player(lower_case(s1));
message( "my_action", sprintf( "Humanoid Report ON command received from master %s.\n", s1), fp);

// Turns robot off. I thought about making it only the person who turned robot on can turn robot off. But second thought if fp dies then no one can turn the robot off. So for now anyone can turn on or off.
if(sscanf(string2,"%s tells: HUMANOID REPORT OFF.",s1)>0){
report = 0;
fp = find_player(lower_case(s1));
message( "my_action", sprintf( "Humanoid Report OFF command received from master %s.\n", s1), fp);

// eventHeatTalk works together with receive_message. This part remains unchanged from original charly.c
varargs mixed eventHearTalk(object who, object target, int cls, string verb, string msg, string lang) {
    unguarded((: this_object()->receive_message("me",ww->GetName()+" "+vv+"s: "+mm) :));

// eventPrint also works together with receive_message. This part also remains untouched from original charly.c
int eventPrint(string msg, string msg_class){
    unguarded((: this_object()->receive_message("me again",printvar) :));

// combineSources pretty much puts together results from ShowExits, ShowEnv and m7 from receive_message.
// It then passes all 7 mappings back to heart_beat. They will be received in one hit as one array mapping (array that contains mappings). I tried mapping mapping and array array. Unfortunately neither worked. Guess that means sticking with array mapping for now.
mapping *combineSources()
int tt=0;
mapping *receiveExits = ShowExits();
mapping *receiveOther = ShowEnv();
mapping m0 = ([ ]); // Not quite sure how to declare mapping array. Tried mapping *m = ({[]}) didn't work.
mapping m1 = ([ ]); // Also tried map within map ie. mapping mapping ([[]]) which didn't work either.
mapping m2 = ([ ]); // These eight individual simple mappings should do for now.
mapping m3 = ([ ]); // As long as I return them all in one hit, seems to receive alright on the other end.
mapping m4 = ([ ]);
mapping m5 = ([ ]);
mapping m6 = ([ ]);
// mapping m7 already declared global and managed in receive_message.

foreach (string k, string l in receiveOther[0]) {m0 += ([ k : l ]); } // 0. SHORT DESCRIPTION
foreach (string k, string l in receiveOther[1]) {m1 += ([ "" : l ]); } // 1. LONG DESCRIPTION
foreach (string k, string l in receiveExits[0]) {m2 += ([ k : l ]); } // 2. EXITS
foreach (string k, string l in receiveExits[1]) {m3 += ([ k : l ]); } // 3. ENTRIES
foreach (string k, string l in receiveOther[2]) {m4 += ([ k : l ]); } // 4. LIVINGS
foreach (string k, string l in receiveOther[3]) {m5 += ([ k : l ]); } // 5. ITEMS
foreach (string k, string l in receiveOther[4]) {m6 += ([ k : l ]); } // 6. SENSE (TOUCH, SMELL, HEAR)
// m7 currently holds only the last message from receive_message. May come back in the future to let m7 hold a back log of say past 100 lines.
// Note because combineSources is called only as frequently as heart beats, it is possible if new messages come into receive_message faster than heart beats that heart beat will miss some messages.
// If you need accurate capturing of serial messages that come through intensely, please go into receive_message() and deal with incoming messages there first hand.

return ({m0,m1,m2, m3,m4,m5,m6,m7});

// One of the purpose of this little project is so any beginners like myself with basic knowledge of array and accessing elements in mapping can play with everything in any given room as
// perceived by players (names, descriptions) and programmers (specific paths and filenames) without the need to go into all the mess & hassles already taken care of
// by other functions in this file. So anyone should be able to come straight to heart_beat, manipulate various elements and have the NPC behave accordingly and as humanly as possible.
void heart_beat(){
int h=0;
mapping *result = combineSources();

if(report==1) message( "my_action", sprintf( "\n*** %s ***",heading[h]), fp );
foreach (string k, string l in result[h]) {if(report==1) message( "my_action", sprintf( "\t %s (%s)", k, l), fp); }
« Last Edit: May 12, 2007, 07:58:43 am by amylase »

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1022
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Humanoid works fine. Other commands now dead.
« Reply #1 on: December 18, 2006, 06:38:39 am »
I've loaded your code on a 2.1.1 lib and an alpha lib. I could not
reproduce your symptoms in either one. Perhaps just loading it
isn't enough to trigger the problem?

Or perhaps the npc itself isn't the source of the problem.

I'll need more info so I can reproduce the symptoms,
otherwise I don't think I can be of much help.


Offline amylase

  • Friend
  • **
  • Posts: 75
    • View Profile
    • gpLand
Re: Humanoid works fine. Other commands now dead.
« Reply #2 on: December 18, 2006, 08:40:13 am »
Thanks Cratylus. The phenomenon is quite definite on my end.

Code: [Select]
 SetInventory( ([
"/domains/campus/obj/pedestal" : 1,
"/domains/campus/npc/humanoid" : 1
      ]) );
With the above in /domains/campus/room/monty.c, major commands and intermud fail to work.
"Try 'help creator commands' for a list of some creator commands" keeps coming up.

Code: [Select]
 SetInventory( ([
"/domains/campus/obj/pedestal" : 1
      ]) );
When replaced by this, everything comes back to normal (minus the NPC ofcourse).

I'll upgrade my library from 2.1 to 2.1.1 and see if that helps....

Offline amylase

  • Friend
  • **
  • Posts: 75
    • View Profile
    • gpLand
Re: Humanoid works fine. Other commands now dead.
« Reply #3 on: May 10, 2007, 08:49:05 am »
Thanks Cratylus. Code tested on 2.4.2 today and I found something peculiar. The NPC (humanoid.c) and certain commands (eg. ds, about, scan) worked fine only on first boot. If I reboot the system, without changing anything myself and re-entered the game, commands like ds, about, scan stopped working. This message keeps coming up:
> Try "help creator commands" for a list of some creator commands.

This is the only line reported by \ds\win32\driver.exe c:\ds\lib\secure\cfg\mudos.cfg. Looks like a disrupted login process.

I also quickly checked for any files that may have been changed by the game and here is a list:
Nothing in particular jumps at me.

Overall I am just quite confused. Would you mind running this bot on your end again and see if other commands still work after second or third reboot? Thanks.
« Last Edit: May 12, 2007, 07:57:54 am by amylase »

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1022
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Peculiarity with Humanoid.c
« Reply #4 on: May 19, 2007, 02:43:45 pm »
Your npc has an error that is triggered when eventPrint() is called on it.

eventPrint() calls your receive_message(), which assumes that there is a string2. Your
receive_message() fun has two spots where sscanf assumes it will have a
string2 to examine. When there is no string2, the sscanf pukes. This makes
receive_message() error out. This makes eventPrint() error out in turn. This
makes the room fail to complete its eventPrint() which winds up screwing your
character when he tries to log in and is moved into the room that the npc

Add a check in receive_message(), for example

Code: [Select]
if(string2 && sscanf

rather than

Code: [Select]


Offline amylase

  • Friend
  • **
  • Posts: 75
    • View Profile
    • gpLand
Re: Peculiarity with Humanoid.c
« Reply #5 on: May 25, 2007, 09:57:23 am »
Thank you so much Cratylus. It's hard to find someone with your experience and willingness to go through my messy code. I corrected my code as you recommended and it works well now. Thanks very much.