Author Topic: Landmarks daemon  (Read 1858 times)

Offline z993126

  • BFF
  • ***
  • Posts: 128
    • View Profile
Landmarks daemon
« on: October 23, 2011, 03:46:02 am »
Attempting to build a simple daemon to hold a list of landmarks that are then referenced and noted in a description that "such-and-such landmark is far to the southwest" if you're 10 rooms away to the northeast, or "such-and-such landmark towers overhead to the north" if you're 1 room away to the south.  Currently getting error 'Illegal type of index' at line 55 of /daemon/landmarks.c.

/daemon/landmarks.c
Code: [Select]
/***************
 * /daemon/landmarks.c
 * hold a list of landmarks that can be queried for direction/distance for description use
 * 2011-Oct-21 - T. Cook
 ***************/

#include <lib.h>

inherit LIB_DAEMON;

mapping GetLandmarkLoci();
mapping GetLandmarkPositions( int x, int y, int z, int range );
mixed AddLandmark( string name, int x , int y, int z );
mixed RemoveLandmark( string name, int x, int y, int z );

mapping M_Landmarks = ([ ]);

static void create(){
daemon::create();
}

/*-----*
 * name: GetLandmarkLoci
 * args: none
 * rtrn: mapping of current landmarks
 *-----*/
mapping GetLandmarkLoci(){
return M_Landmarks;
}

/*-----*
 * name: GetLandmarkPositions
 * args: coordinates( int x, int y, int z ), int range
 * rtrn: mapping [landmark name] : ([ int azimuth (degrees), int altitude (degrees), int distance (grid units) ])
 *-----*/
mapping GetLandmarkPositions( string town, int x, int y, int z, int range ){
int i_count, i_count_max, azimuth, altitude, distance, x1, y1, z1, d1, d2;
mapping M_LandmarkPosition;

if( member_array( town, keys( M_Landmarks ) ) == -1 ){ return ([ ]); }
i_count_max = sizeof( M_Landmarks[town] );
if( i_count_max == 0 ){ return ([ ]); }
for( i_count = 0; i_count < i_count_max; i_count++ ){
x1 = x - M_Landmarks[town][keys( M_Landmarks[town] )[i_count]]["x"];
y1 = y - M_Landmarks[town][keys( M_Landmarks[town] )[i_count]]["y"];
z1 = z - M_Landmarks[town][keys( M_Landmarks[town] )[i_count]]["z"];
d1 = sqrt( x1 * x1 + y1 * y1 );
d2 = sqrt( d1 * d1 + z1 * z1 );
if( to_int( d2 ) > range ){ continue; }
if( y1 != 0 ){
write( "M_LandmarkPosition[" + town + "][" + keys( M_Landmarks[town] )[i_count] + "]" );
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["azimuth"] =
y1 == 0 ? 0 : to_int( 360.0 * atan( ( d1 - x1 ) / y1 ) / 3.1415926535 );
}else{
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["azimuth"] = y1 >= 0 ? 0 : 180;
}
if( z1 != 0 ){
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["altitude"] =
z1 == 0 ? 0 : to_int( 360.0 * atan( ( d2 - d1 ) / z1 ) / 3.1415926535 );
}else{
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["altitude"] = z1 > 0 ? 90 : z1 == 0 ? 0 : -90;
}
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["distance"] = to_int( d2 );
}
return M_LandmarkPosition[town];
}

/*-----*
 * name: AddLandmark
 * args: string name, coordinates( int x, int y, int z )
 * rtrn: set mapping value for landmark at given coordinates if nonexistant
 *-----*/
mixed AddLandmark( string town, string name, int x, int y, int z ){
if( member_array( name, keys( M_Landmarks ) ) > -1 ){
return "The landmark '" + name + "' in the town '" + town + "' already exists!";
}
return M_Landmarks[town] = ([ name : ([ "x" : x, "y" : y, "z" : z ]) ]);
}

/*-----*
 * name: RemoveLandmark
 * args: string name
 * rtrn: remove landmark from mapping if it exists
 *-----*/
mixed RemoveLandmark( string town, string name ){
if( member_array( town, keys( M_Landmarks ) ) == -1 && member_array( name, keys( M_Landmarks[town] ) ) == -1 ){
return "The landmark '" + name + "' in the town '" + town + "' didn't even exist!";
}
return map_delete( M_Landmarks[town], name );
}
/* EOF */

/secure/cmds/admin/landmark.c
Code: [Select]
/*    /secure/cmds/admins/landmark.c
 *    manage landmarks
 *    2011-Oct-22 - T. Cook
 */

#include <lib.h>
#include <daemons.h>

inherit LIB_DAEMON;

mixed cmd( string s_args ){
string s_town, s_name;
int i_x, i_y, i_z, i_count1, i_count1_max, i_count2, i_count2_max;
mapping M_Landmarks = LANDMARKS_D->GetLandmarkLoci();
write( sprintf( "%%^CYAN%%^cmd%%^BOLD%%^%%^RED%%^(%%^RESET%%^ %s %%^BOLD%%^%%^RED%%^)%%^RESET%%^ called.", s_args ) );
if(
!s_args || s_args == ""
){
write( "No arguments were passed!" );
i_count1_max = sizeof( M_Landmarks );
if( i_count1_max == 0 ){
write( "There are no landmarks available." );
}else{
for( i_count1 = 0; i_count1 < i_count1_max; i_count1++ ){
s_town = keys( M_Landmarks )[i_count1];
write( "%^CYAN%^" + capitalize( s_town ) + "%^RESET%^" );
i_count2_max = sizeof( M_Landmarks[s_town] );
for( i_count2 = 0; i_count2 < i_count2_max; i_count2++ ){
s_name = keys( M_Landmarks[s_town] )[i_count2];
i_x = M_Landmarks[s_town][s_name]["x"];
i_y = M_Landmarks[s_town][s_name]["y"];
i_z = M_Landmarks[s_town][s_name]["z"];
write( sprintf( "\t%-20s< %5d, %5d, %5d >", s_name, i_x, i_y, i_z ) );
}
}
}
}else if( sscanf( s_args, "add %s %s %d %d %d", s_town, s_name, i_x, i_y, i_z ) == 5 ){
LANDMARKS_D->AddLandmark( s_town, s_name, i_x, i_y, i_z );
write( "Landmark added." );
}else if( sscanf( s_args, "remove %s %s", s_town, s_name ) == 2 ){
if(
member_array( s_town, keys( M_Landmarks ) ) != -1 &&
member_array( s_name, keys( M_Landmarks[s_town] ) ) != -1
){
LANDMARKS_D->RemoveLandmark( s_town, s_name );
previous_object()->eventPrint( "Landmark removed." );
}else{
write( "Couldn't find the landmark '" + s_name + "' in the town '" + s_town + "' to remove." );
}
}
return 1;
}

string GetHelp( string s_str ){
return (
"Syntax:  '%^B_WHITE%^%^BLACK%^landmark add %^MAGENTA%^<TOWN> <NAME> <X> <Y> <Z>%^RESET%^'\n"
"         '%%B_WHITE%^%^BLACK%^landmark remove %^MAGENTA%^<TOWN> <NAME>%^RESET%^'\n\n"
"Allows you to manage elements of the landmarks daemon.  Command 'landmarks' by itself will display"
"a list of currently set items.\n"
);
}
/* EOF */

Offline Nulvect

  • BFF
  • ***
  • Posts: 127
    • View Profile
Re: Landmarks daemon
« Reply #1 on: October 23, 2011, 03:44:40 pm »
The problem is that on this line:
Code: [Select]
M_LandmarkPosition[town][keys( M_Landmarks[town] )[i_count]]["azimuth"] = y1 >= 0 ? 0 : 180;
and others like it, you are trying to assign to multiple levels of a mapping at once. The M_LandmarkPosition mapping has not been initialized and neither have its submappings. You have to initialize each level separately, such as:
Code: [Select]
M_LandmarkPosition = ([]);
M_LandmarkPosition[town] = keys(M_Landmarks[town])[i_count];
// etc

Also, this code is a pretty good example of why you should use foreach instead of for whenever you can get away with it.

Offline z993126

  • BFF
  • ***
  • Posts: 128
    • View Profile
Re: Landmarks daemon
« Reply #2 on: October 24, 2011, 06:03:03 pm »
And here we have an updated, much-improved version of this daemon.  It still needs occlusion to be added, so that the player can't see through landmarks.

Code: [Select]
/***************
 * /daemon/landmarks.c
 * hold a list of landmarks that can be queried for direction/distance for description use
 * 2011-Oct-21 - T. Cook
 * 2011-Oct-23 - T. Cook added GetLandmarkList()
 *             -         switched azimuth calculation to bearing() call
 * 2011-Oct-24 = T. Cook made RemoveLandmark() remove town from mapping if last landmark in that town removed
 *             -         added size property to AddLandmark()
 *             -         changed for() loops to foreach()
 * TODO:
 * - add occlusion to landmarks
 * - improve altitude & distance descriptors
 ***************/

#include <lib.h>

inherit LIB_DAEMON;

mapping GetLandmarkLoci();
mapping GetLandmarkPositions( string s_town, int i_x, int i_y, int i_z, int i_range );
string GetLandmarkList( mapping M_LandmarkPos );
mixed AddLandmark( string s_name, int i_x , int i_y, int i_z, string s_size );
mixed RemoveLandmark( string s_town, string s_name );

mapping M_Landmarks = ([ ]);
static string SaveFile;

static void create(){
daemon::create();
SaveFile = save_file( "/save/landmarks.o" );
if( unguarded( (: file_exists( SaveFile ) :) ) ){
RestoreObject( SaveFile, 1 );
}
SaveObject( SaveFile, 1 );
}

/*-----*
 * name: GetLandmarkLoci
 * args: none
 * rtrn: mapping of current landmarks
 *-----*/
mapping GetLandmarkLoci(){
return M_Landmarks;
}

/*-----*
 * name: GetLandmarkPositions
 * args: string town, coordinates( int x, int y, int z ), int range
 * rtrn: mapping [landmark name] : ([ int azimuth (degrees), int altitude (degrees), int distance (grid units) ])
 *-----*/
mapping GetLandmarkPositions( string s_town, int i_x, int i_y, int i_z, int i_range ){
int i_count, i_count_max, i_azimuth, i_altitude, i_x1, i_y1, i_z1, i_x2, i_y2, i_z2;
float f_d1, f_d2;
string s_landmark;
mapping M_LandmarkPosition = ([ ]);

// error-checking
if( sizeof( M_Landmarks ) == 0 ){ write( "There are no landmarks."); return ([ ]); }
if( member_array( s_town, keys( M_Landmarks ) ) == -1 ){
write( sprintf( "The town '%s' is not in this list:  %O.", s_town, item_list( keys( M_Landmarks ) ) ) );
return ([ ]);
}
if( sizeof( M_Landmarks[s_town] ) == 0 ){ write( "There are no landmarks in this town." ); return ([ ]); }

foreach( s_landmark in keys( M_Landmarks[s_town] ) ){
i_x1 = M_Landmarks[s_town][s_landmark]["x"];
i_y1 = M_Landmarks[s_town][s_landmark]["y"];
i_z1 = M_Landmarks[s_town][s_landmark]["z"];
i_x2 = i_x1 - i_x;
i_y2 = i_y1 - i_y;
i_z2 = i_z1 - i_z;
f_d1 = sqrt( i_x2 * i_x2 + i_y2 * i_y2 );
f_d2 = sqrt( i_x2 * i_x2 + i_y2 * i_y2 + i_z2 * i_z2 );
if( to_int( f_d2 ) > i_range ){ continue; }

M_LandmarkPosition[s_town] = ([ ]);
M_LandmarkPosition[s_town][s_landmark] = ([ ]);

M_LandmarkPosition[s_town][s_landmark]["azimuth"] = bearing( i_x, i_y, i_x1, i_y1 );
if( f_d1 != 0 ){
M_LandmarkPosition[s_town][s_landmark]["altitude"] =
i_z2 == 0 ? 0 : to_int( 360.0 * atan( ( f_d2 - f_d1 ) / i_z2 ) / 3.1415926535 );
}else{
M_LandmarkPosition[s_town][s_landmark]["altitude"] = i_z2 > 0 ? 90 : i_z2 == 0 ? 0 : -90;
}
M_LandmarkPosition[s_town][s_landmark]["distance"] = to_int( f_d2 );
}
return M_LandmarkPosition[s_town];
}

/*-----*
 * name: GetLandmarkList
 * args: mapping([ "landmark" : ([ "azimuth" : azimuth, "altitude" : altitude, "range" : range ]) ])
 * rtrn: string list of landmarks within given range
 *-----*/
 string GetLandmarkList( mapping M_LandmarkPos ){
string *sa_landmarks = ({}), *sa_keys = ({});
string s_direction = "", s_distance = "", s_elev = "", s_landmark = "";

if( sizeof( M_LandmarkPos ) == 0 ){ return "There are no landmarks here."; }
foreach( s_landmark in keys( M_LandmarkPos ) ){
sa_keys = keys( M_LandmarkPos[s_landmark] );
if(
member_array( "azimuth",  sa_keys ) == -1 ||
member_array( "altitude", sa_keys ) == -1 ||
member_array( "distance", sa_keys ) == -1
){
continue;
}
switch( M_LandmarkPos[s_landmark]["azimuth"] ){
case 000..011: s_direction = "north";              break;
case 012..034: s_direction = "north by northeast"; break;
case 035..056: s_direction = "northeast";          break;
case 057..079: s_direction = "east by northeast";  break;
case 080..101: s_direction = "east";               break;
case 102..124: s_direction = "east by southeast";  break;
case 125..146: s_direction = "southeast";          break;
case 147..169: s_direction = "south by southeast"; break;
case 170..191: s_direction = "south";              break;
case 192..214: s_direction = "south by southwest"; break;
case 215..236: s_direction = "southwest";          break;
case 237..259: s_direction = "west by southwest";  break;
case 260..281: s_direction = "west";               break;
case 282..304: s_direction = "west by northwest";  break;
case 305..326: s_direction = "northwest";          break;
case 327..349: s_direction = "north by northwest"; break;
case 350..360: s_direction = "north";              break;
default:       s_direction = "thataway";           break;
}
switch( M_LandmarkPos[s_landmark]["altitude"] ){
case -90..-54: s_elev      = " underfoot";         break;
case -53..-18: s_elev      = " below eye level";   break;
case -17..17:  s_elev      = "";                   break;
case 18..53:   s_elev      = " above eye level";   break;
case 54..90:   s_elev      = " overhead";          break;
default:       s_elev      = " in your head";      break;
}
switch( M_LandmarkPos[s_landmark]["distance"] ){
case 000:      s_distance  = " right here";        break;
case 001..005: s_distance  = " nearby";            break;
case 006..020: s_distance  = "";                   break;
case 021..050: s_distance  = " in the distance";   break;
case 051..099: s_distance  = " far";               break;
case 100..999: s_distance  = " far, far";          break;
default:       s_distance  = " somewhere";         break;
}
sa_landmarks += ({
GetArticle( s_landmark ) + " " + s_landmark + s_elev + ( s_elev == "" || s_distance == "" ? "" : "," ) +
s_distance + " to the " + s_direction
});
}
return sizeof( sa_landmarks ) == 0 ? "" : "There " + ( sizeof( sa_landmarks ) == 1 ? "is " : "are " ) +
item_list( sa_landmarks ) + ".";
 }
 
/*-----*
 * name: AddLandmark
 * args: string name, coordinates( int x, int y, int z ), string size
 * rtrn: set mapping value for landmark at given coordinates if nonexistant
 *-----*/
mixed AddLandmark( string s_town, string s_name, int i_x, int i_y, int i_z, string s_size ){
if( member_array( s_town, keys( M_Landmarks ) ) == -1 ){ M_Landmarks[s_town] = ([ ]); }
if( member_array( s_name, keys( M_Landmarks[s_town] ) ) > -1 ){
return "The landmark '" + s_name + "' in the town '" + s_town + "' already exists!";
}else{
M_Landmarks[s_town][s_name] = ([ ]);
}
M_Landmarks[s_town][s_name] = ([ "x" : i_x, "y" : i_y, "z" : i_z, "size" : s_size ]);
SaveObject( SaveFile, 1 );
return 1;
}

/*-----*
 * name: RemoveLandmark
 * args: string name
 * rtrn: remove landmark from mapping if it exists
 *-----*/
mixed RemoveLandmark( string s_town, string s_name ){
if(
member_array( s_town, keys( M_Landmarks ) ) == -1 &&
member_array( s_name, keys( M_Landmarks[s_town] ) ) == -1
){
return "The landmark '" + s_name + "' in the town '" + s_town + "' didn't even exist!";
}
map_delete( M_Landmarks[s_town], s_name );
if( sizeof( M_Landmarks[s_town] ) == 0 ){
map_delete( M_Landmarks, s_town );
}
SaveObject( SaveFile, 1 );
return 1;
}
/* EOF */

Code: [Select]
/*    /secure/cmds/admins/landmark.c
 *    manage landmarks
 *    2011-Oct-22 - T. Cook
 *    2011-Oct-24 - T. Cook improved handling of add/remove, added size property
 *                -         changed for() loops to foreach()
 */

#include <lib.h>
#include <daemons.h>

inherit LIB_DAEMON;

mixed cmd( string s_args ){
string s_town, s_name, s_size, s_opts;

string BW = "%^B_WHITE%^%^BLACK%^", MW = "%^B_WHITE%^%^MAGENTA%^", X = "%^RESET%^";
string SEP = "%^BLACK%^\",\"%^MAGENTA%^", SEP2 = "%^BLACK%^,%^MAGENTA%^";
string B = "%^BLACK%^", M = "%^MAGENTA%^";

int i_x, i_y, i_z;
mapping M_Landmarks = LANDMARKS_D->GetLandmarkLoci();
if(
!s_args || s_args == ""
){
if( sizeof( M_Landmarks ) == 0 ){
write( "There are no landmarks available." );
}else{
write( "%^BOLD%^%^CYAN%^** LANDMARKS **%^RESET%^" );
foreach( s_town in keys( M_Landmarks ) ){
write( "Town:  %^CYAN%^" + s_town + "%^RESET%^" );
foreach( s_name in keys( M_Landmarks[s_town] ) ){
i_x    = M_Landmarks[s_town][s_name]["x"];
i_y    = M_Landmarks[s_town][s_name]["y"];
i_z    = M_Landmarks[s_town][s_name]["z"];
s_size = M_Landmarks[s_town][s_name]["size"];
write( sprintf( "\t%-20s< %5d, %5d, %5d >  %-10s", s_name, i_x, i_y, i_z, s_size ) );
}
}
}
}else if( sscanf( s_args, "add %s", s_opts ) == 1 ){
if( sscanf( s_opts, "\"%s\",\"%s\",%d,%d,%d,\"%s\"", s_town, s_name, i_x, i_y, i_z, s_size ) == 6 ){
LANDMARKS_D->AddLandmark( s_town, s_name, i_x, i_y, i_z, s_size );
write( "Landmark '" + s_name + "' added to the town '" + s_town + "'." );
}else{
write( sprintf(
"Syntax:  '%slandmark add \"%s<TOWN>%s<NAME>%s\",%s<X>%s<Y>%s<Z>%s,\"%s<SIZE>%s\"%s'",
BW, M, SEP, B, M, SEP2, SEP2, B, M, B, X
) );
}
}else if( sscanf( s_args, "remove %s", s_opts ) == 1 ){
if( sscanf( s_opts, "\"%s\",\"%s\"", s_town, s_name ) == 2 ){
if(
member_array( s_town, keys( M_Landmarks ) ) != -1 &&
member_array( s_name, keys( M_Landmarks[s_town] ) ) != -1
){
LANDMARKS_D->RemoveLandmark( s_town, s_name );
previous_object()->eventPrint( "Landmark removed." );
}else{
write( "Couldn't find the landmark '" + s_name + "' in the town '" + s_town + "' to remove." );
}
}else{
write( sprintf(
"Syntax:  '%slandmark remove \"%s<TOWN>%s<NAME>%s\"%s'",
BW, M, SEP, B, X
) );
}
}
return 1;
}

string GetHelp( string s_str ){
string BW = "%^B_WHITE%^%^BLACK%^", MW = "%^B_WHITE%^%^MAGENTA%^", X = "%^RESET%^";
string SEP = "%^BLACK%^\",\"%^MAGENTA%^", SEP2 = "%^BLACK%^,%^MAGENTA%^";
string B = "%^BLACK%^", M = "%^MAGENTA%^";

return ( sprintf(
"Syntax:  '%slandmark add \"%s<TOWN>%s<NAME>%s\",%s<X>%s<Y>%s<Z>%s,\"%s<SIZE>%s\"%s'\n" +
"         '%slandmark remove \"%s<TOWN>%s<NAME>%s\"%s'\n\n" +
"Allows you to manage elements of the landmarks daemon.  Command 'landmarks' by itself will display" +
"a list of currently set items.\n",
BW, M, SEP, B, M, SEP2, SEP2, B, M, B, X,
BW, M, SEP, B, X
) );
}
/* EOF */

As the GetLandmarkList() function is currently written, it gets passed a mapping of named things with azimuth, altitude, and distance keys.  This means it can be used for things that aren't rooms or actual objects at all, such as stars and planets (which are potentially useful to have as landmarks).
« Last Edit: October 24, 2011, 06:05:12 pm by z993126 »