blob: 46e93640eaf41ae3382c222b1baf7096baa71f1f [file] [log] [blame]
#include <properties.h>
#include <defines.h>
#include <moving.h>
#include <language.h>
#define NEED_PROTOTYPES
#include <doorroom.h>
inherit "/std/thing";
#pragma strong_types
private mapping door_status;
private int id_zaehler;
// Format: "filename1:filename2":status
int oeffnen (string str);
mapping QueryAllDoors() {return door_status;}
int QueryDoorStatus(string dest) {
string source,dkey;
object env;
if (!dest) return 0;
if (!objectp(env=previous_object())) return 0;
source=object_name(env);
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
return door_status[dkey];
}
void SetDoorStatus(string dest, int x) {
string source,dkey;
object env;
if (!dest) return;
if (!objectp(env=previous_object())) return;
source=object_name(env);
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
door_status[dkey]=x;
}
protected void create() {
door_status=([]);
id_zaehler=0;
if (IS_CLONE(this_object())) remove();
}
varargs int remove(int silent) {return 0;}
varargs int NewDoor(string|string* cmds, string dest, string|string* ids,
mapping|<int|string|string*>* props)
{
object env;
string source,dkey,sec_id;
mixed *info2,zw;
mapping info;
int i;
if (!objectp(env=previous_object())) return 0;
if (!cmds || !dest) return 0;
if (!ids) ids=({"tuer"});
if (stringp(cmds)) cmds=({cmds});
if (stringp(ids)) ids=({ids});
if (!pointerp(cmds) || !pointerp(ids)) return 0;
if (dest[0..0]!="/") dest="/"+dest;
id_zaehler++;
sec_id=sprintf("secure_id:door%d",id_zaehler);
info=([D_DEST : dest,
D_CMDS : cmds,
D_IDS : ({ sec_id }) + ids,
D_FLAGS : (DOOR_CLOSED|DOOR_RESET_CL),
D_LONG : "Eine Tuer.\n",
D_SHORT : "Eine %se Tuer. ",
D_NAME : "Tuer",
D_GENDER : FEMALE]);
source=object_name(env);
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
if (pointerp(props)) {
for (i=0;i<sizeof(props)-1;i+=2)
if (intp(props[i]) && props[i]>=D_MINPROPS && props[i]<=D_MAXPROPS)
info[props[i]]=props[i+1];
}
else if(mappingp(props)){
info += props;
}
if (!door_status[dkey]) {
// Nur initialisieren, wenn Tuer noch nicht existiert.
if (info[D_FLAGS] & DOOR_OPEN)
door_status[dkey]=D_STATUS_OPEN;
if (info[D_FLAGS] & DOOR_CLOSED)
door_status[dkey]=
((info[D_FLAGS] & DOOR_NEEDKEY) ? D_STATUS_LOCKED : D_STATUS_CLOSED);
}
info2=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info2))
info2=({info});
else
info2+=({info});
env->SetProp(P_DOOR_INFOS,info2);
if(mappingp(info[D_LONG]) && pointerp(zw=m_indices(info[D_LONG])) &&
sizeof(zw) && intp(zw[0]))
env->AddSpecialDetail(ids,"special_detail_doors");
else if(info[D_LONG] && info[D_LONG]!="")
env->AddDetail(ids,info[D_LONG]);
return 1;
}
void init_doors () {
object env;
mixed *info;
string source,dest,dkey;
int i;
if (!objectp(env=previous_object())) return;
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return;
source=object_name(env);
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
env->set_doors(info[i][D_CMDS],(door_status[dkey]>0));
}
}
string look_doors () {
object env;
mixed *info, ds;
string source,dkey,dest,res;
int i, st;
if (!objectp(env=previous_object())) return "";
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return "";
init_doors(); // Aktueller Zustand soll auch bei den Exits angezeigt werden
source=object_name(env);res="";
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
if (stringp(info[i][D_SHORT])) {
res+=sprintf(info[i][D_SHORT],
((door_status[dkey]>=D_STATUS_OPEN)?"geoeffnet":
((door_status[dkey]!=D_STATUS_CLOSED)?"ab":"")+"geschlossen"));
if (sizeof(res) && res[<1]!='\n')
res+=" ";
}
else if(mappingp(ds=info[i][D_SHORT])){
st=door_status[dkey];
if((st==D_STATUS_LOCKED) && !ds[D_STATUS_LOCKED])
st=D_STATUS_CLOSED;
if(stringp(ds[st])){
res += ds[st];
if(sizeof(ds[st]) && res[<1]!='\n')res+=" ";
}
}
}
if (res && res!="")
return break_string(res,78,0,1);
return res;
}
static void door_message(object room, string dname, int dgender, string msg) {
object ob;
// printf("%O,%O,%O,%O\n",room,dname,dgender,msg);
if (!room || !dname || !msg) return;
ob=this_object();
ob->SetProp(P_NAME,dname);
ob->SetProp(P_GENDER,dgender);
ob->SetProp(P_ARTICLE,1);
tell_room(room,capitalize(ob->name(WER))+msg+"\n");
}
static void door_message_other(string source, string dest, string msg) {
mixed info;
object env;
int i;
// printf("%O %O %O\n",source,dest,msg);
if (!source || !dest || !msg) return;
if (!objectp(env=find_object(dest))) return;
if (!pointerp(info=env->QueryProp(P_DOOR_INFOS))) return;
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
if (info[i][D_DEST]!=source) continue; // Andere Tuer zu diesem Raum
door_message(env,info[i][D_NAME],info[i][D_GENDER],msg);
}
}
void reset_doors () {
object env;
mixed *info;
string source,dest,dkey,msg;
int i,j;
if (!objectp(env=previous_object())) return;
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return;
source=object_name(env);
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
// if (door_status[dkey]>-2 && door_status[dkey]<2) {
// if (door_status[dkey]>0)
// door_status[dkey]=2;
// else
// door_status[dkey]=-2;
// continue; // nur jeder 2. Reset wird ausgefuehrt.
// }
if (info[i][D_FLAGS] & DOOR_RESET_CL) {
// Tuer muss bei Reset geschlossen werden
if (door_status[dkey] >= D_STATUS_OPEN) {
if(!msg=info[i][D_RESET_MSG])msg=" schliesst sich.";
door_message(env,info[i][D_NAME],info[i][D_GENDER],msg);
door_message_other(source,dest,msg);
}
if (door_status[dkey]!=D_STATUS_LOCKED)
door_status[dkey]=
((info[i][D_FLAGS] & DOOR_NEEDKEY) ? D_STATUS_LOCKED : D_STATUS_CLOSED);
}
if (info[i][D_FLAGS] & DOOR_RESET_OP) {
// Tuer muss bei Reset geoeffnet werden
if (door_status[dkey] < D_STATUS_OPEN) {
if(!msg=info[i][D_RESET_MSG])msg=" oeffnet sich.";
door_message(env,info[i][D_NAME],info[i][D_GENDER],msg);
door_message_other(source,dest,msg);
}
door_status[dkey]=D_STATUS_OPEN;
}
}
init_doors();
}
static varargs int exec_func2(string dest, mixed func) {
if (!stringp(dest) || !stringp(func)) return 1;
call_other(dest,func);
return 1;
}
varargs int go_door (string str) {
object env,pl,ob;
mixed *info;
string source,dest,dkey;
int i;
if (!str) return 0;
if (!objectp(env=previous_object())) return 0;
if (!objectp(pl=this_player())) return 0;
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return 0;
source=object_name(env);
ob=this_object();
ob->SetProp(P_ARTICLE,1);
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
if (member(info[i][D_CMDS],str)<0) continue;
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
ob->SetProp(P_NAME,info[i][D_NAME]);
ob->SetProp(P_GENDER,info[i][D_GENDER]);
notify_fail(capitalize(ob->name(WER,1))+" ist geschlossen.\n");
if((door_status[dkey]<=0) &&
!info[i][D_OPEN_WITH_MOVE]) continue; // Tuer geschlossen
if(door_status[dkey]<=0){
// In diesem Fall versuchen, die Tuer zu oeffnen.
oeffnen(info[i][D_IDS][0]);
}
notify_fail(capitalize(ob->name(WER,1))+" ist geschlossen.\n");
if (door_status[dkey]<=0) continue; // Tuer immer noch zu.
if (stringp(info[i][D_TESTFUNC]))
if (call_other(env,info[i][D_TESTFUNC]))
return 1; // Durchgang von der Tuer nicht erlaubt.
if (stringp(info[i][D_FUNC]))
call_other(env,info[i][D_FUNC]);
if (stringp(info[i][D_MSGS])) {
if (pl->move(dest,M_GO,info[i][D_MSGS])>0)
return exec_func2(dest,info[i][D_FUNC2]);
else
return 1;
}
if (pointerp(info[i][D_MSGS]) && sizeof(info[i][D_MSGS])>=3) {
if (pl->move(dest,M_GO,info[i][D_MSGS][0],
info[i][D_MSGS][1],info[i][D_MSGS][2]))
return exec_func2(dest,info[i][D_FUNC2]);
else
return 1;
}
if (pl->move(dest,M_GO,"nach "+capitalize(str)))
return exec_func2(dest,info[i][D_FUNC2]);
return 1;
}
return 0;
}
int oeffnen (string str) {
object env,schl,ob;
mixed *info,s2;
string source,dkey,dest,s1;
int i;
notify_fail("WAS willst Du oeffnen?\n");
if (!str || !this_player()) return 0;
notify_fail("Das kannst Du nicht oeffnen.\n");
str=lower_case(str);
if (sscanf(str,"%s mit %s",s1,s2)!=2)
{s1=str;s2=0;}
if (s2) {
if (!(schl=present(lower_case(s2),this_player()))) {
notify_fail("So einen Schluessel hast Du nicht.\n");
return 0;
} else {
s2=schl->QueryDoorKey();
if (stringp(s2)) s2=({s2});
}
}
if (!objectp(env=previous_object())) return 0;
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return 0;
source=object_name(env);
ob=this_object();
ob->SetProp(P_ARTICLE,1);
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
if (member(info[i][D_IDS],s1)<0) continue; // Falsche Tuer
ob->SetProp(P_NAME,info[i][D_NAME]);
ob->SetProp(P_GENDER,info[i][D_GENDER]);
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
notify_fail(capitalize(ob->name(WER,1))+" ist doch schon geoeffnet!\n");
if (door_status[dkey]>0)
continue; // Eine andere Tuer koennte gemeint sein.
if ((info[i][D_FLAGS] & DOOR_NEEDKEY)
&& door_status[dkey] == D_STATUS_LOCKED) { // abgeschlossen
notify_fail("Du brauchst einen Schluessel, um "+ob->name(WEN,1)+" zu oeffnen.\n");
if (!schl) continue; // Eine andere Tuer koennte gemeint sein.
notify_fail(capitalize(schl->name(WER))+" passt nicht!\n");
if (!pointerp(s2)) continue;
if (member(s2,dkey)<0) continue; // Koennte an einer anderen passen.
}
door_status[dkey]=1;
init_doors();
write("Du oeffnest "+ob->name(WEN)+".\n");
say(capitalize(ob->name(WER))+" wird von "+this_player()->name(WEM)+
" geoeffnet.\n");
door_message_other(source,dest," wird von der anderen Seite geoeffnet.");
return 1;
}
return 0;
}
int schliessen (string str) {
object env,schl,ob;
mixed *info,s2;
string source,dkey,dest,s1;
int i,abg;
notify_fail("WAS willst Du schliessen?\n");
if (!str || !this_player()) return 0;
notify_fail("Das kannst Du nicht schliessen.\n");
str=lower_case(str);
if (sscanf(str,"%s mit %s",s1,s2)!=2)
{s1=str;s2=0;}
if (s2) {
if (!(schl=present(lower_case(s2),this_player()))) {
notify_fail("So einen Schluessel hast Du nicht.\n");
return 0;
} else {
s2=schl->QueryDoorKey();
if (stringp(s2)) s2=({s2});
}
}
if (!objectp(env=previous_object())) return 0;
info=env->QueryProp(P_DOOR_INFOS);
if (!pointerp(info)) return 0;
source=object_name(env);
ob=this_object();
ob->SetProp(P_ARTICLE,1);
abg=0;
for (i=sizeof(info)-1;i>=0;i--) {
if (!mappingp(info[i])) continue;
if (member(info[i][D_IDS],s1)<0) continue; // Falsche Tuer
ob->SetProp(P_NAME,info[i][D_NAME]);
ob->SetProp(P_GENDER,info[i][D_GENDER]);
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
if (schl) {
notify_fail(capitalize(ob->name(WER,1))+" ist doch schon abgeschlossen!\n");
if (door_status[dkey]<=0
&& door_status[dkey] == D_STATUS_LOCKED)
continue; // Eine andere Tuer koennte gemeint sein.
if (info[i][D_FLAGS] & DOOR_CLOSEKEY) { // Schluessel noetig?
notify_fail(capitalize(schl->name(WER))+" passt nicht!\n");
if (!pointerp(s2)) continue;
if (member(s2,dkey)<0) continue; // Koennte an einer anderen passen.
door_status[dkey]=D_STATUS_LOCKED;
abg=1; // Tuer wird richtig abgeschlossen
}
else {
// ohne Schluessel abschliessbar
door_status[dkey]=
((info[i][D_FLAGS] & DOOR_NEEDKEY) ? D_STATUS_LOCKED : D_STATUS_CLOSED);
}
}
else {
notify_fail(capitalize(ob->name(WER,1))+" ist doch schon geschlossen!\n");
if (door_status[dkey] < D_STATUS_OPEN)
continue; // Eine andere Tuer koennte gemeint sein.
if ((info[i][D_FLAGS] & DOOR_NEEDKEY) &&
!(info[i][D_FLAGS] & DOOR_CLOSEKEY))
door_status[dkey]=D_STATUS_LOCKED; // Abschliessbar, aber dazu schluessel unnoetig
else
door_status[dkey]=D_STATUS_CLOSED;
}
init_doors();
write("Du schliesst "+ob->name(WEN)+
(abg?" ab":"")+".\n");
say(capitalize(ob->name(WER))+" wird von "+this_player()->name(WEM)+
(abg?" ab":" ")+"geschlossen.\n");
door_message_other(source,dest," wird von der anderen Seite "+
(abg?"ab":"")+"geschlossen.");
return 1;
}
return 0;
}
string special_detail_doors(string key){
object env;
mixed *info;
mapping dl;
int i, st;
string source, dest, dkey;
if(!objectp(env=previous_object()))return 0;
if(!pointerp(info=env->QueryProp(P_DOOR_INFOS)))return 0;
source=object_name(env);
for(i=sizeof(info)-1;i>=0;i--){
if(!mappingp(info[i]))continue;
if(member(info[i][D_IDS],key)<0)continue;
if(stringp(info[i][D_LONG]))return info[i][D_LONG];
if(!mappingp(info[i][D_LONG]))continue;
dl=info[i][D_LONG];
dest=info[i][D_DEST];
dkey=(source<dest)?(source+":"+dest):(dest+":"+source);
st=door_status[dkey];
if((st==D_STATUS_LOCKED) && !dl[D_STATUS_LOCKED])
st=D_STATUS_CLOSED; /* Falls keine eigene Beschreibung
* fuer abgeschlossene Tuer vorhanden */
return dl[st];
}
return 0;
}