/* predicates.c */ /* $Id: predicates.c,v 1.24 1994/01/26 22:28:43 nils Exp $ */ /* Predicates for testing various conditions */ #include <ctype.h> #include <varargs.h> #include "db.h" #include "interface.h" #include "config.h" #define NO_PROTO_VARARGS #include "externs.h" void pronoun_substitute(); char *tprintf(va_alist) va_dcl { int args[10]; int k; static char buff[10000]; va_list ap; char *format; va_start(ap); format=va_arg(ap,char *); for(k=0;k<10;k++) args[k]=va_arg(ap, int); sprintf(buff,format,args[0],args[1],args[2],args[3],args[4], args[5],args[6], args[7],args[8],args[9],args[10]); buff[1000]=0; return(buff); } int Level(thing) dbref thing; { if(db[thing].owner != thing) if(db[thing].flags&INHERIT_POWERS) return Level(db[thing].owner); else return CLASS_VISITOR; /* no special powers. */ if (db[thing].flags & PLAYER_MORTAL) return CLASS_VISITOR; return *db[thing].pows; } int Levnm(thing) dbref thing; { if(db[thing].flags & INHERIT_POWERS) thing=db[thing].owner; if(Typeof(thing)==TYPE_PLAYER) return *db[thing].pows; return Level(thing); } int power(thing, level_check) dbref thing; int level_check; { /* mortal flag on player makes him mortal - no arguments */ if(IS(thing,TYPE_PLAYER,PLAYER_MORTAL) && level_check!=POW_MEMBER) return 0; return has_pow(thing,NOTHING,level_check); } int inf_mon(thing) dbref thing; { if(has_pow(db[thing].owner,NOTHING,POW_MONEY)) return 1; return 0; } int inf_quota(thing) dbref thing; { if(has_pow(db[thing].owner,NOTHING,POW_NOQUOTA)) return 1; return 0; } int can_link_to(who,where,cutoff_level) dbref who; dbref where; int cutoff_level; { return ( where >= 0 && where < db_top && ( controls(who, where, cutoff_level) || (db[where].flags & LINK_OK))); } int could_doit(player,thing,attr) dbref player; dbref thing; ATTR *attr; { /* no if puppet tries to get key */ if ((Typeof(player)==TYPE_THING) && IS(thing,TYPE_THING,THING_KEY)) return 0; if ((Typeof(thing) == TYPE_EXIT) && (db[thing].link == NOTHING)) return 0; if(( Typeof(thing) == TYPE_PLAYER || Typeof(thing) == TYPE_THING) && db[thing].location == NOTHING) return 0; return(eval_boolexp (player, thing, atr_get(thing, attr), get_zone_first(player))); } void did_it(player,thing,what,def,owhat,odef,awhat) dbref player; dbref thing; ATTR *what; char *def; ATTR *owhat; char *odef; ATTR *awhat; { char *d; char buff[1024]; char buff2[1024]; dbref loc=db[player].location; if (loc==NOTHING) return; /* message to player */ if (what) { if (*(d=atr_get(thing,what))) { strcpy(buff2,d); pronoun_substitute(buff,player,buff2,thing); notify(player,buff+strlen(db[player].name)+1); } else if (def) notify(player,def); } if(!IS(get_room(player),TYPE_ROOM,ROOM_AUDITORIUM)) /* message to neighbors */ if (owhat) if (*(d=atr_get(thing,owhat)) && !(db[thing].flags&HAVEN)) { strcpy(buff2,d); pronoun_substitute(buff,player,buff2,thing); notify_in(loc,player,buff); } else if (odef) notify_in(loc,player, tprintf("%s %s",db[player].name,odef)); /* do the action attribute */ if (awhat && *(d=atr_get(thing,awhat))) { char *b; char dbuff[1024]; strcpy(dbuff,d); d=dbuff; /* check if object has # of charges */ if (*(b=atr_get(thing,A_CHARGES))) { int num=atoi(b); char ch[100]; if (num) { sprintf(ch,"%d",num-1); atr_add(thing,A_CHARGES,ch); } else if (!*(d=atr_get(thing,A_RUNOUT))) return; strcpy(dbuff,d); d=dbuff; } /* pronoun_substitute(buff,player,d,thing);*/ /* parse the buffer and do the sub commands */ parse_que(thing,d,player); } } dbref check_zone(player, who, where, move_type) dbref player; dbref who; dbref where; int move_type; /* 0 => walking, 1 => teleport, 2 => home */ { dbref old_zone, new_zone; int zonefail = 0; old_zone = get_zone_first(who); new_zone = get_zone_first(where); /* if ((old_zone = get_zone(who)) == NOTHING) old_zone = db[0].zone; if ((new_zone = get_zone(where)) == NOTHING) new_zone = db[0].zone;*/ /* Check for illegal home zone crossing. Applies to objects only. */ if (move_type == 2 ) { return 1; /* say what? we want to restrict the home cmd? nah. */ /* if (!power(player, POW_TELEPORT) && (((Typeof(player) == TYPE_THING) || Robot(player) || Live_Puppet(player)) && (old_zone != new_zone) && (IS(old_zone, TYPE_THING, THING_ZONED) || IS(new_zone, TYPE_THING, THING_ZONED)))) { notify(player, "Illegal zone crossing."); return (dbref) 0; } */ } /* safety in case GOD hasn't set the universal zone yet */ if ((old_zone == NOTHING) || (new_zone == NOTHING)) return (dbref) 1; /* Check to see if the zones don't match */ if (old_zone != new_zone) { /* Check to see if 'who' can pass the zone leave-lock */ if (move_type == 1 && !could_doit(who, old_zone, A_LLOCK) && !controls(player, old_zone, POW_TELEPORT)) { did_it(who, old_zone, A_LFAIL, "You can't leave.", A_OLFAIL, NULL, A_ALFAIL); return (dbref) 0; } else { /* Do not allow KEY objects to leave the zone. */ if ((Typeof(who) != TYPE_PLAYER) && (db[new_zone].flags & THING_KEY)) zonefail = 1; /* Check for @tel or walk and check appropriate lock. */ if (!eval_boolexp(who, new_zone,atr_get(new_zone,(move_type) ?A_ELOCK:A_LOCK),old_zone)) zonefail = 1; if(move_type == 1) { /* Make sure player can properly @tel in or out of zone */ if (!(db[new_zone].flags & ENTER_OK)) zonefail = 1; /* Anyone with POW_TEL can @tel anywhere, must be the last condition */ if (power(player,POW_TELEPORT)) zonefail = 0; } /* Next we evaluate if successfull/failed and do the verbs */ /* Failed walking attempt */ if (zonefail == 1 && move_type == 0) { did_it(who, new_zone, A_FAIL, "You can't go that way.", A_OFAIL, NULL, A_AFAIL); return (dbref) 0; } /* Failed @tel attempt */ if (zonefail == 1 && move_type == 1) { did_it(who, new_zone, A_EFAIL, "Permission denied.", A_OEFAIL, NULL, A_AEFAIL); return (dbref) 0; } /* Successfull walking attempt */ if (zonefail == 0 && move_type == 0) { did_it(who, new_zone, A_SUCC, NULL, A_OSUCC, NULL, A_ASUCC); return old_zone; } /* Successfull @tel attempt */ if (zonefail == 0 && move_type == 1) { return(dbref) 1; } } } else { return (dbref)1; } return (dbref)1; } int can_see(player,thing,can_see_loc) dbref player; dbref thing; int can_see_loc; { /* 1) your own body isn't listed in a 'look' 2) exits aren't listed in a 'look' 3) unconnected (sleeping) players aren't listed in a 'look' */ if(player == thing || Typeof(thing) == TYPE_EXIT || ((Typeof(thing)==TYPE_PLAYER) && !IS(thing,TYPE_PLAYER,PLAYER_CONNECT) && !(db[thing].flags&PUPPET))) return 0; /* if the room is lit, you can see any non-dark objects */ else if(can_see_loc) return( ! Dark(thing)); /* otherwise room is dark and you can't see a thing */ else if(IS(thing,TYPE_THING,THING_LIGHT) && controls(thing,db[thing].location,POW_MODIFY)) return 1; /* LIGHT flag. can see it in a dark room. */ else return 0; } int can_set_atr (who, what, atr) dbref who; dbref what; ATTR *atr; { if (!can_see_atr (who, what, atr)) return 0; if ((atr == A_QUOTA || atr == A_RQUOTA) && ! power (who, POW_SECURITY)) return 0; if ((atr == A_PENNIES) && !power (who, POW_MONEY)) return 0; if (!controls (who, what, POW_MODIFY)) return 0; #ifdef USE_SPACE /* Check added by Michael Majere */ if (atr->flags&AF_SPACE && atr->obj == NOTHING && !power(who,POW_SPACE)) return 0; if (atr->flags&AF_SPACE && atr->obj != NOTHING && !controls(who, atr->obj, POW_SPACE)) return 0; #endif if (atr->flags&AF_WIZARD && atr->obj == NOTHING && !power(who,POW_WATTR)) return 0; if (atr->flags&AF_WIZARD && atr->obj != NOTHING && !controls(who, atr->obj, POW_WATTR)) return 0; return 1; } int can_see_atr (who, what, atr) dbref who; dbref what; ATTR *atr; { if (atr == A_PASS && !God(who)) return 0; if (!(atr->flags&AF_OSEE) && !controls(who, what, POW_SEEATR) && !(db[what].flags&SEE_OK)) return 0; if (atr->flags&AF_DARK && atr->obj == NOTHING && !power(who, POW_SECURITY)) return 0; if (atr->flags&AF_DARK && atr->obj != NOTHING && !controls(who, atr->obj, POW_SEEATR)) return 0; return 1; } static int group_depth=0; static int group_controls_int P((dbref,dbref)); int group_controls(who,what) dbref who; dbref what; { group_depth = 0; return group_controls_int(who,what); } static int group_controls_int(who,what) dbref who; dbref what; { group_depth++; if (group_depth>20) return 0; if (who == what) return 1; else if (*atr_get(what,A_USERS)) { char buf[1024]; char *s=buf; char *z; strcpy(buf,atr_get(what,A_USERS)); while ((z=parse_up(&s,' '))) { int i; if (*z != '#') continue; i = atoi(z+1); if (i>=0 && i<db_top && Typeof(i)==TYPE_PLAYER) if(group_controls_int(who,i)) return 1; } } return 0; } int controls_a_zone (who, what, cutoff_level) dbref who, what; int cutoff_level; { dbref zon; DOZONE(zon, what) if (controls (who, zon, cutoff_level)) return 1; return 0; } int controls(who, what, cutoff_level) dbref who; dbref what; int cutoff_level; { dbref where; where = db[what].location; /* valid thing to control? */ if (what == NOTHING) return has_pow(who, what, cutoff_level); if ( what < 0 || what >= db_top ) return 0; if ((cutoff_level == POW_EXAMINE || cutoff_level == POW_SEEATR) && (db[what].flags&SEE_OK)) return 1; /* owners (and their stuff) control the owner's stuff */ /* if ( db[who].owner == db[what].owner ) return 1;*/ #ifdef USE_SPACE /* Added by MM */ if ((db[what].owner == SPACE_LORD) && !power(who,POW_SPACE) && (db[where].flags & ROOM_ZEROG)) return 0; #endif if (db[who].owner == db[what].owner || group_controls(db[who].owner,db[what].owner)) /* the owners match, check ipow */ if(db[who].owner == who) return 1; /* it's the player -- e controls all eir stuff */ else if(db[who].flags&INHERIT_POWERS) return 1; else if((db[what].flags&INHERIT_POWERS || db[what].owner == what) && (!db[db[what].owner].pows || (*db[db[what].owner].pows)>CLASS_CITIZEN)) return 0; /* non inherit powers things don't control inherit stuff */ else return 1; /* the target isn't inherit */ /* if (( db[who].owner == db[what].owner ) && ((db[who].flags&INHERIT_POWERS) || !(db[what].flags&INHERIT_POWERS) || Typeof(who)==TYPE_PLAYER || * or it's a player -- dont need I. * !power(db[who].owner,TYPE_OFFICIAL))) * or it's no special powers * return 1; */ if (db[what].flags & INHERIT_POWERS) what = db[what].owner; /* GOD controls all */ if ( who == GOD ) return 1; /* and GOD don't listen to anyone! */ if ( (what == GOD) || (db[what].owner == GOD) ) return 0; if(has_pow(who,what,cutoff_level)) return 1; return 0; } dbref def_owner(who) dbref who; { if (!*atr_get(who,A_DEFOWN)) return db[who].owner; else { dbref i; i = match_thing(who,atr_get(who,A_DEFOWN)); if (i==NOTHING || Typeof(i)!=TYPE_PLAYER) return db[who].owner; if (!controls(who,i,POW_MODIFY)) { notify(who,tprintf("You don't control %s, so you can't make things owned by %s.",unparse_object(who,i),unparse_object(who,i))); return db[who].owner; } return db[i].owner; } } int can_link(who,what,cutoff_level) dbref who; dbref what; int cutoff_level; { return((Typeof(what) == TYPE_EXIT && db[what].location == NOTHING) || controls(who, what, cutoff_level)); } int can_pay_fees(who, credits, quota) dbref who; int credits, quota; { /* can't charge credits till we've verified building quota */ if ( ! Guest(db[who].owner) && Pennies(db[who].owner) < credits && !has_pow(db[who].owner,NOTHING,POW_MONEY)) { notify(who, "Sorry, you don't have enough Credits."); return 0; } /* check building quota */ if ( ! pay_quota(who, quota) ) { notify(who, "Sorry, your building quota has run out."); return 0; } /* charge credits */ payfor(who, credits); return 1; } void giveto(who,pennies) dbref who; int pennies; { int old_amount; /* wizards don't need pennies */ if(has_pow(db[who].owner,NOTHING,POW_MONEY)) return; who=db[who].owner; old_amount = Pennies(who); if (old_amount + pennies < 0) { if ((old_amount > 0) && (pennies > 0)) s_Pennies(who,(((unsigned)-2)/2)); else s_Pennies(who,0); } else s_Pennies(who,old_amount+pennies); } int payfor(who,cost) dbref who; int cost; { dbref tmp; if (Guest(who) || has_pow(db[who].owner,NOTHING,POW_MONEY)) return 1; else if((tmp=Pennies(db[who].owner)) >= cost) { s_Pennies(db[who].owner, tmp-cost); return 1; } else return 0; } void add_quota(who, payment) dbref who; int payment; { char buf[20]; /* wizards don't need a quota */ if(has_pow(db[who].owner,NOTHING,POW_NOQUOTA)) return; sprintf(buf, "%d", atoi(atr_get(db[who].owner, A_RQUOTA)) + payment); atr_add(db[who].owner, A_RQUOTA, buf); } int pay_quota(who, cost) dbref who; int cost; { int quota; char buf[20]; /* wizards don't need a quota */ if(has_pow(db[who].owner,NOTHING,POW_NOQUOTA)) return 1; /* determine quota */ quota = atoi(atr_get(db[who].owner, A_RQUOTA)); /* enough to build? */ quota -= cost; if ( quota < 0 ) return 0; /* doc the quota */ sprintf(buf, "%d", quota); atr_add(db[who].owner, A_RQUOTA, buf); return 1; } int sub_quota(who, cost) dbref who; int cost; { char buf[20]; /* wizards don't need a quota */ if( has_pow(who,NOTHING,POW_NOQUOTA)) return 1; /* doc the quota */ sprintf(buf, "%d", atoi(atr_get(db[who].owner, A_RQUOTA)) - cost); atr_add(db[who].owner, A_RQUOTA, buf); return 1; } /* !!! index function hack !!! */ int my_index(s1,c) char *s1; int c; { while(*s1 && (*s1++!=c)); return(*s1); } int ok_attribute_name(name) char *name; { return (name && *name && !strchr(name,'=') && !strchr(name,',') && !strchr(name,';') && !strchr(name,':') && !strchr(name,'.') && !strchr(name,'[') && !strchr(name,']') && !strchr(name,' ')); } int ok_thing_name(name) char *name; { return ok_name(name) && !my_index(name, ';'); } int ok_exit_name(name) char *name; { return ok_name(name); } int ok_room_name(name) char *name; { return ok_name(name) && !my_index(name, ';'); } int ok_name(name) char *name; { return (name && *name && *name != LOOKUP_TOKEN && *name != NUMBER_TOKEN && *name != NOT_TOKEN && !my_index(name, ARG_DELIMITER) && !my_index(name, AND_TOKEN) && !my_index(name, OR_TOKEN) && string_compare(name, "me") && string_compare(name, "home") && string_compare(name, "here")); } int ok_object_name(obj, name) dbref obj; char *name; { switch (Typeof(obj)) { case TYPE_PLAYER: return ok_player_name(name); case TYPE_THING: return ok_thing_name(name); case TYPE_EXIT: return ok_exit_name(name); case TYPE_ROOM: return ok_room_name(name); } log_error("i'm very unhappy here in predicates.c. :("); return 0; } int ok_player_name(name) char *name; { char *scan; if(!ok_name(name) || strlen(name) > PLAYER_NAME_LIMIT) return 0; if (!string_compare(name, "i") || !string_compare(name, "me") || !string_compare(name, "my") || !string_compare(name, "you") || !string_compare(name, "your") || !string_compare(name, "he") || !string_compare(name, "she") || !string_compare(name, "it") || !string_compare(name, "his") || !string_compare(name, "her") || !string_compare(name, "hers") || !string_compare(name, "its") || !string_compare(name, "we") || !string_compare(name, "us") || !string_compare(name, "our") || !string_compare(name, "they") || !string_compare(name, "them") || !string_compare(name, "their") || !string_compare(name, "a") || !string_compare(name, "an") || !string_compare(name, "the") || !string_compare(name, "one") || !string_compare(name, "to") || !string_compare(name, "if") || !string_compare(name, "and") || !string_compare(name, "or") || !string_compare(name, "but") || !string_compare(name, "at") || !string_compare(name, "of") || !string_compare(name, "for") || !string_compare(name, "foo") || !string_compare(name, "so") || !string_compare(name, "this") || !string_compare(name, "that") || !string_compare(name, ">") || !string_compare(name, ".") || !string_compare(name, "-") || !string_compare(name, ">>") || !string_compare(name, "..") || !string_compare(name, "--") || !string_compare(name, "->") || !string_compare(name, ":)") || !string_compare(name, "clear")) /* +mail clear. */ return 0; for(scan = name; *scan; scan++) { if(!(isprint(*scan) && !isspace(*scan))) { /* was isgraph(*scan) */ return 0; } if (*scan == '~') return 0; } if (lookup_player(name) != NOTHING) return 0; if (*name && name[strlen(name)-1] == ':') { char buf[1024]; strcpy(buf,name); buf[strlen(buf)-1] = '\0'; return (lookup_player(buf) == NOTHING); } return 1; } int ok_password(password) char *password; { char *scan; if(*password == '\0') return 0; for(scan = password; *scan; scan++) { if(!(isprint(*scan) && !isspace(*scan))) { return 0; } } return 1; } char *main_exit_name(exit) dbref exit; { static char buf[1000]; char *s; strcpy (buf, db[exit].name); if ((s=strchr(buf,';'))) *s = '\0'; return buf; } void sstrcat(old,string,app) char *old; char *string; char *app; { char *s; if ((strlen(app)+(s=(strlen(string)+string))-old)>950) return; strcpy (s, app); for(;*s;s++) if ((*s==',') || (*s==';')) *s=' '; } /* * pronoun_substitute() * * %-type substitutions for pronouns * * %s/%S for subjective pronouns (he/she/it/e/they, He/She/It/E/They) * %o/%O for objective pronouns (him/her/it/em/them, Him/Her/It/Em/Them) * %p/%P for possessive pronouns (his/her/its/eir/their, His/Her/Its/Eir/etc) * %n for the player's name. * Note: e/em/eir are non-gender-specific pronouns and use the 'spivak' sex. */ void pronoun_substitute(result,player,str,privs) char *result; dbref player; char *str; dbref privs; /* object whose privs are used */ { char c, *s, *p; char *ores; dbref thing; ATTR *atr; static char *subjective[7] = { "", "it", "she", "he", "e", "they", "he/she" }; static char *possessive[7] = { "", "its", "her", "his", "eir", "their", "his/her" }; static char *objective[7] = { "", "it", "her", "him", "em", "them", "him/her" }; int gend; if ((privs<0) || (privs>=db_top)) privs=2; /* figure out player gender */ switch(*atr_get(player,A_SEX)) { case 'M': case 'm': gend=3; break; case 'f': case 'F': case 'w': case 'W': gend=2; break; case 's': case 'S': gend = 4; break; case 'p': case 'P': gend = 5; break; case 'n': case 'N': gend = 1; break; case '/': gend = 6; break; case 'l': case 'L': gend = 0; break; default: gend=4; } strcpy(ores=result, spname(player)); result += strlen(result); *result++ = ' '; while (*str && ((result-ores)<1000)) { if (*str=='[') { char buff[1024]; str++; exec(&str,buff,privs,player,0); if ((strlen(buff)+(result-ores))>950) continue; strcpy(result,buff); result+=strlen(result); if (*str==']') str++; } else if(*str == '%') { *result = '\0'; c = *(++str); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!wptr[c-'0']) break; sstrcat(ores,result,wptr[c-'0']); break; case 'v': case 'V': { int a; a=to_upper(str[1]); if ((a<'A') || (a>'Z')) break; if (*str) str++; sstrcat(ores,result,atr_get(privs,A_V[a-'A'])); } break; case 's': case 'S': sstrcat(ores,result, (gend==0) ? db[player].name : subjective[gend]); break; case 'p': case 'P': if (gend==0) { sstrcat(ores,result,db[player].name); sstrcat(ores,result,"'s"); } else sstrcat(ores,result, possessive[gend]); break; case 'o': case 'O': sstrcat(ores,result, (gend==0) ? db[player].name : objective[gend]); break; case 'n': case 'N': sstrcat(ores,result, db[player].name); break; case '#': if ((strlen(result)+result-ores)>990) break; sprintf(result+strlen(result),"#%d",player); break; case '/': str++; if ((s = strchr(str,'/'))) { *s = '\0'; if ((p = strchr(str, ':'))) { *p = '\0'; thing = (dbref) atoi(++str); *p = ':'; str = ++p; } else thing = privs; atr = atr_str(privs,thing,str); if (atr && can_see_atr(privs,thing,atr)) sstrcat(ores,result, atr_get(thing, atr)); *s = '/'; str = s; } break; default: if ((result-ores)>990) break; *result = *str; result[1] = '\0'; break; } if(isupper(c) && c !='N') *result = to_upper(*result); result += strlen(result); if (*str) str++; } else { if((result-ores)>990) break; /* check for escape */ if ((*str=='\\') && (str[1])) str++; *result++ = *str++; } } *result = '\0'; } void push_list (list, item) dbref **list; dbref item; { int len; dbref *newlist; if ((*list) == NULL) len = 0; else for (len=0; (*list)[len] != NOTHING; len++); len+=1; newlist = malloc((len+1)*sizeof(dbref)); if (*list) bcopy(*list, newlist, sizeof(dbref)*(len)); else newlist[0] = NOTHING; if (*list) free(*list); puts("freein"); newlist[len-1] = item; newlist[len] = NOTHING; puts ("settin"); (*list) = newlist; } void remove_first_list (list, item) dbref **list; dbref item; { int pos; if (!*list) return; for (pos=0; (*list)[pos] != item && (*list)[pos] != NOTHING; pos++); if ((*list)[pos] == NOTHING) return; for (; (*list)[pos] != NOTHING; pos++) (*list)[pos] = (*list)[pos+1]; /* and ignore the reallocation, unless we have to free it. */ if ((*list)[0] == NOTHING) { free(*list); (*list) = NULL; } } dbref starts_with_player(name) char *name; { static char buf[1024]; char *s; dbref b; if ((s=strchr(name,' '))) { strcpy(buf,name); buf[s-name] = '\0'; /* truncate after first word */ b = lookup_player(buf); if (b == NOTHING || string_compare(db[b].name, buf)) return NOTHING; else return b; } else { b = lookup_player(name); if (b == NOTHING || string_compare(db[b].name, name)) return NOTHING; else return b; } } int is_in_zone(player, zone) dbref player; dbref zone; { dbref zon; DOZONE(zon,player) if (zon == zone) return 1; return 0; }