Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/living/team.c b/std/living/team.c
new file mode 100644
index 0000000..2b31db9
--- /dev/null
+++ b/std/living/team.c
@@ -0,0 +1,650 @@
+// MorgenGrauen MUDlib
+//
+// living/team.c
+//
+// $Id: team.c 9138 2015-02-03 21:46:56Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+
+#include <properties.h>
+#include <thing/properties.h>
+#include <living/combat.h>
+#include <combat.h>
+#include <living/team.h>
+#include <wizlevels.h>
+#include <hook.h>
+
+#define ME this_object()
+#define TP this_player()
+#define PO previous_object()
+#define ENV environment()
+
+private nosave string team_attack_cmd;
+private nosave mapping team_follow_todo;
+private nosave int team_autofollow;
+private nosave object teammove;
+
+void create() {
+ Set(P_TEAM_ATTACK_CMD,-1,F_SET_METHOD);
+ Set(P_TEAM_ATTACK_CMD,PROTECTED,F_MODE_AS);
+ Set(P_TEAM_AUTOFOLLOW,-1,F_SET_METHOD);
+ Set(P_TEAM_AUTOFOLLOW,PROTECTED,F_MODE_AS);
+ teammove=0;
+ offerHook(H_HOOK_TEAMROWCHANGE, 1);
+}
+
+void add_team_commands() {
+ add_action("teamcmd","gruppe");
+ add_action("teamcmd","g");
+ add_action("teamcmd","team");
+}
+
+string _query_team_attack_cmd() {
+ return Set(P_TEAM_ATTACK_CMD,team_attack_cmd);
+}
+
+int _query_team_autofollow() {
+ return Set(P_TEAM_AUTOFOLLOW,team_autofollow);
+}
+
+private int team_help() {
+ // Syntax-Kompatiblitaet (Avalon) ist ganz nett :-)
+ write("\
+(Befehle des Teamleiters sind mit * gekennzeichnet\n\
+\n\
+* team angriff\n\
+ team angriffsbefehl <befehl>\n\
+* team aufnahme <name>\n\
+ team autof[olge] <ein/aus>\n\
+* team autoi[nfo] <ein/aus> [+[lp]] [+[kp]] [sofort]\n\
+* team entlasse <name>\n\
+ team farben lp_rot lp_gelb kp_rot kp_gelb\n\
+ team flucht[reihe] <reihe>\n\
+ team folge <name>\n\
+* team formation <min[-max]> [<min[-max]> ...]\n\
+ team hilfe|?\n\
+ team [info] [sortiert|alphabetisch]\n\
+ team [kampf]reihe <reihe>\n\
+* team leiter[in] <name>\n\
+ team liste\n\
+* team name <gruppenname>\n\
+ team orte [alle]\n\
+ team ruf[e]\n\
+ team uebersicht\n\
+ team verlasse\n");
+ return 1;
+}
+
+object IsTeamLeader() {
+ object team;
+
+ if (!objectp(team=Query(P_TEAM))
+ || team!=Query(P_TEAM_LEADER)
+ || team->Leader()!=ME)
+ return 0;
+ return team;
+}
+
+object *TeamMembers() {
+ object team;
+
+ if (!objectp(team=Query(P_TEAM)))
+ return ({ME});
+ return team->Members();
+}
+
+string TeamPrefix() {
+ object team;
+
+ if (!objectp(team=Query(P_TEAM)))
+ return "";
+ return "["+team->Name()+"] ";
+}
+
+
+private int team_aufnahmewunsch(string arg) {
+ object pl;
+
+ if ((!objectp(pl=find_player(arg)) && !objectp(pl=present(arg,ENV)))
+ || pl->QueryProp(P_INVIS) || environment(pl)!=ENV)
+ return notify_fail(capitalize(arg)+" nicht gefunden.\n"),0;
+ if (!living(pl))
+ return notify_fail(pl->Name(WER)+" ist etwas zu inaktiv.\n"),0;
+ if (pl==ME)
+ return notify_fail("Du bist eine Person zu wenig fuer ein Team.\n"),0;
+ SetProp(P_TEAM_NEWMEMBER,pl);
+ if (pl->IsTeamLeader()) {
+ write("Du bittest "+pl->name(WEN)+" um Aufnahme ins Team.\n");
+ tell_object(pl,TP->Name(WER)+" bittet Dich um Aufnahme ins Team.\n");
+ } else {
+ write("Du bittest "+pl->name(WEN)+" um Gruendung eines Teams.\n");
+ tell_object(pl,TP->Name(WER)+" bittet Dich um Gruendung eines Teams.\n");
+ }
+ return 1;
+}
+
+private int team_aufnahme(string arg) {
+ object pl,team;
+ int res;
+
+ if ((!objectp(pl=find_player(arg)) && !objectp(pl=present(arg,ENV)))
+ || pl->QueryProp(P_INVIS) || environment(pl)!=ENV)
+ return notify_fail(capitalize(arg)+" nicht gefunden.\n"),0;
+ if (pl->QueryProp(P_TEAM_NEWMEMBER)!=ME)
+ return notify_fail(pl->Name(WER)+" hat Dich nicht um Aufnahme gebeten.\n"),
+ 0;
+ if (pl==ME)
+ return notify_fail("Du bist eine Person zu wenig fuer ein Team.\n"),0;
+ if (!objectp(team=QueryProp(P_TEAM)))
+ team=clone_object(TEAM_OBJECT);
+ res=team->AddMember(pl);
+ if (!sizeof(team->Members()))
+ team->remove();
+ return res;
+}
+
+object IsTeamMove() {
+ if (!objectp(teammove) || (teammove!=Query(P_TEAM)))
+ teammove=0;
+ return teammove;
+}
+
+static void DoTeamAttack(object env, object callbackto) {
+ if (env==ENV && stringp(team_attack_cmd) && !IS_LEARNER(ME)
+ && (interactive(ME) || !query_once_interactive(ME))
+ && objectp(callbackto) && callbackto==Query(P_TEAM)) {
+ teammove=callbackto;
+ command(team_attack_cmd);
+ }
+ if (objectp(callbackto))
+ callbackto->TeamAttackExecuted_Callback(teammove?1:0);
+ teammove=0;
+}
+
+int CallTeamAttack(object env) {
+ if (stringp(team_attack_cmd)
+ && find_call_out("DoTeamAttack")<0
+ && PO
+ && PO==Query(P_TEAM))
+ return call_out("DoTeamAttack",0,env,PO),1;
+ return 0;
+}
+
+static int DoTeamFollow() {
+ string cmd;
+
+ if (!team_autofollow
+ || (!interactive(ME) && query_once_interactive(ME))
+ || IS_LEARNER(ME)
+ || !mappingp(team_follow_todo))
+ return 0;
+ if (!stringp(cmd=team_follow_todo[ENV]))
+ return team_follow_todo=0;
+
+ do {
+ m_delete(team_follow_todo,ENV);
+ tell_object(ME,sprintf("Du folgst Deinem Team mit \"%s\".\n",cmd));
+ command(cmd);
+ } while (get_eval_cost()>900000 && random(1000)>20 && objectp(ME)
+ && stringp(cmd=team_follow_todo[ENV]));
+
+ // Ist Spieler in Umgebung gelandet, fuer die noch ein
+ // Befehl auszufuehren ist?
+ if (!objectp(ME) || !stringp(team_follow_todo[ENV]))
+ return team_follow_todo=0;
+ while (remove_call_out("DoTeamFollow")!=-1) ;
+ call_out("DoTeamFollow",0);
+ return 0;
+}
+
+int CallTeamFollow(object env, string cmd) {
+ if (!team_autofollow
+ || PO!=Query(P_TEAM)
+ || !PO
+ || !objectp(env)
+ || !stringp(cmd))
+ return 0;
+ if (!mappingp(team_follow_todo))
+ team_follow_todo=([]);
+ if (ENV!=env && !team_follow_todo[ENV])
+ return 0;
+ team_follow_todo[env]=cmd;
+ if (find_call_out("DoTeamFollow")<0)
+ call_out("DoTeamFollow",0);
+ return 1;
+}
+
+int ClearTeamFollow() {
+ if (PO!=Query(P_TEAM) || !PO)
+ return 0;
+ team_follow_todo=([]);
+ return 1;
+}
+
+mixed *PresentTeamRows() {
+ object team;
+ mixed *res;
+ int i;
+
+ if (!objectp(team=Query(P_TEAM))) {
+ res=EMPTY_TEAMARRAY;
+ res[0]=({ME});
+ return res;
+ }
+ res=team->PresentRows(ENV);
+ for (i=0;i<MAX_TEAMROWS;i++)
+ if (member(res[i],ME)>=0)
+ return res;
+ res[0]+=({ME});
+ return res;
+}
+
+varargs mixed *PresentEnemyRows(object *here) {
+ mixed *res,*rows;
+ mapping added_teams;
+ int i,j;
+ object ob,team;
+
+ added_teams=([Query(P_TEAM):1]); // Nicht auf eigenes Team hauen
+ res=EMPTY_TEAMARRAY;
+ if (!pointerp(here))
+ here=PresentEnemies();
+ for (i=sizeof(here)-1;i>=0;i--) {
+ if (!objectp(ob=here[i]))
+ continue;
+ if (!objectp(team=ob->QueryProp(P_TEAM))) {
+ res[0]+=({ob});
+ continue;
+ }
+ if (added_teams[team])
+ continue;
+ added_teams[team]=1;
+ rows=team->PresentRows(ENV);
+ for (j=0;j<MAX_TEAMROWS;j++)
+ res[j]+=rows[j];
+ }
+ return res;
+}
+
+varargs object SelectNearEnemy(object *here, int forcefrom) {
+ object ob,en,team;
+ mixed *rows;
+ int *prob,prot,i,r,sz,upsz,sum;
+
+ if (!pointerp(here))
+ here=PresentEnemies();
+ if (!objectp(ob=SelectEnemy(here)))
+ return 0;
+ en=ob->QueryProp(P_TEAM); // Feindliches Team
+ if (objectp(team=Query(P_TEAM))) { // Eigenes Team
+ if (en==team) // Feind im eigenen Team, kein ANDERES Mitglied waehlen.
+ return ob; // Aber auch ausserhalb Reihe 1 draufhauen
+ rows=team->PresentRows(ENV);
+ if (member(rows[0],ME)<0) // Stehe ich in der ersten Reihe?
+ return 0; // Falls nein ist auch kein Gegner nahe.
+ }
+ if (!objectp(en))
+ return ob; // Ist nicht in einem Team, also drauf.
+ rows=en->PresentRows(environment(ob));
+ prob=({1,0,0,0,0});
+ prot=sum=0;
+ for (i=0;i<MAX_TEAMROWS;i++) {
+ if (prot>0) prot--; // Schutzkegel nimmt ab.
+ if (!sz=sizeof(rows[i])) continue; // Gegner in dieser Reihe
+ upsz=sz-prot;if (upsz<0) continue; // Anzahl ungeschuetzter Gegner
+ prob[i]+=(upsz+sum); // Wahrscheinlichkeit += ungeschuetzt
+ sum=prob[i]; // Summe bisheriger Wahrscheinlichkeiten
+ if (sz>prot) prot=sz; // Neuer Schutzkegel
+ }
+ r=random(sum);
+ for (i=0;i<MAX_TEAMROWS;i++)
+ if (r<prob[i])
+ break;
+ if (i>=MAX_TEAMROWS)
+ i=0;
+ if (objectp(en=SelectEnemy(forcefrom?(here&rows[i]):rows[i])))
+ return en;
+ if (i && objectp(en=SelectEnemy(forcefrom?(here&rows[0]):rows[0])))
+ return en;
+ return ob;
+}
+
+varargs object SelectFarEnemy(object *here, int min, int max, int forcefrom) {
+ mixed *rows;
+ int *prob,i,r,sum;
+ object en;
+
+ if (max<0 || min>=MAX_TEAMROWS || max<min)
+ return 0;
+ if (min<0) min=0;
+ if (max>=MAX_TEAMROWS) max=MAX_TEAMROWS-1;
+ if (!pointerp(here))
+ here=PresentEnemies();
+ rows=PresentEnemyRows(here);
+ prob=({0,0,0,0,0});
+ sum=0;
+ for (i=min;i<=max;i++)
+ sum=prob[i]=sum+sizeof(rows[i])+max-i;
+
+ r=random(sum);
+ for (i=min;i<=max;i++)
+ if (r<prob[i])
+ break;
+ if (i>max)
+ i=min;
+ if (objectp(en=SelectEnemy(forcefrom?(here&rows[i]):rows[i])))
+ return en;
+ for (i=min;i<=max;i++)
+ if (objectp(en=SelectEnemy(forcefrom?(here&rows[i]):rows[i])))
+ return en;
+ return 0;
+}
+
+mixed _query_friend() {
+ mixed res;
+
+ if (res=Query(P_FRIEND))
+ return res;
+ if (objectp(res=Query(P_TEAM_ASSOC_MEMBERS))
+ && query_once_interactive(res))
+ return res;
+ return 0;
+}
+
+int DeAssocMember(object npc) {
+ mixed obs;
+ object team;
+
+ if (extern_call() && PO!=npc &&
+ member(({"gilden","spellbooks"}),
+ explode(object_name(PO),"/")[1])<0)
+ return 0;
+ obs=QueryProp(P_TEAM_ASSOC_MEMBERS);
+ if (!pointerp(obs))
+ return 0;
+ obs-=({npc,0});
+ SetProp(P_TEAM_ASSOC_MEMBERS,obs);
+ if (objectp(team=QueryProp(P_TEAM)))
+ team->RemoveAssocMember(ME,npc);
+ return 1;
+}
+
+int AssocMember(object npc) {
+ mixed obs;
+ object team;
+
+ if (extern_call() && PO!=npc &&
+ member(({"gilden","spellbooks"}),
+ explode(object_name(PO),"/")[1])<0)
+ return 0;
+ if (!objectp(npc)
+ || npc->QueryProp(P_TEAM_ASSOC_MEMBERS)
+ || IsEnemy(npc)
+ || npc==ME
+ || query_once_interactive(npc))
+ return 0;
+ obs=QueryProp(P_TEAM_ASSOC_MEMBERS);
+ if (objectp(obs))
+ return 0;
+ if (!pointerp(obs))
+ obs=({});
+ obs=(obs-({npc,0}))+({npc});
+ SetProp(P_TEAM_ASSOC_MEMBERS,obs);
+ npc->SetProp(P_TEAM_ASSOC_MEMBERS,ME);
+ if (objectp(team=QueryProp(P_TEAM)))
+ team->AddAssocMember(ME,npc);
+ return 1;
+}
+
+varargs void InsertEnemyTeam(mixed ens, int rek) {
+ object *obs,ob,eteam,team;
+ int i;
+
+ team=Query(P_TEAM);
+ // Alle Teammitglieder des Gegners sind Feind:
+ if (objectp(ens)) {
+ if (objectp(eteam=ens->QueryProp(P_TEAM))) {
+ if (eteam==team) // feindliches Team = eigenes Team?
+ return; // also nicht alle Teammitglieder gegeneinander hetzen
+ ens=eteam->Members();
+ } else {
+ ens=({ens});
+ }
+ }
+ if (!pointerp(ens))
+ return;
+ ens-=({ME});
+
+ // Interactives sollen keine Interactives durch Team angreifen:
+ if (query_once_interactive(ME)) {
+ for (i=sizeof(ens)-1;i>=0;i--)
+ if (objectp(ob=ens[i]) && environment(ob)==environment()
+ && !query_once_interactive(ob))
+ InsertSingleEnemy(ob);
+ } else {
+ for (i=sizeof(ens)-1;i>=0;i--)
+ if (objectp(ob=ens[i]) && environment(ob)==environment())
+ InsertSingleEnemy(ob);
+ }
+
+ // Alle anderen Teammitglieder Informieren:
+ if (rek || !objectp(team) || !pointerp(obs=team->Members()))
+ return;
+ obs-=({ME});
+ obs-=ens;
+ for (i=sizeof(obs)-1;i>=0;i--)
+ if (objectp(ob=obs[i]))
+ ob->InsertEnemyTeam(ens,1);
+}
+
+int TeamFlee() {
+ object team;
+
+ if (Query(P_TEAM_WIMPY_ROW)<2 || !objectp(team=Query(P_TEAM)))
+ return 0;
+ if (!team->FleeToRow(ME))
+ return 0;
+ if (Query(P_TEAM_LEADER)==team) {
+ if (team_autofollow)
+ tell_object(ME,"Du versuchst zu fliehen, "+
+ "Dein Team folgt Dir nicht mehr.\n");
+ team_autofollow=0;
+ }
+ return 1;
+}
+
+varargs mapping PresentTeamPositions(mixed pres_rows) {
+ mapping res;
+ int i,j;
+ object *obs,ob;
+
+ res=([]);
+ if (!pointerp(pres_rows))
+ pres_rows=PresentTeamRows();
+ for (i=0;i<MAX_TEAMROWS;i++) {
+ obs=pres_rows[i];
+ for (j=sizeof(obs)-1;j>=0;j--)
+ if (objectp(ob=obs[j]) && !res[ob])
+ res[ob]=i+1;
+ }
+ return res;
+}
+
+varargs int PresentPosition(mixed pmap) {
+ object team;
+ int i;
+
+ if (!objectp(team=Query(P_TEAM)))
+ return 1;
+ if (mappingp(pmap))
+ return pmap[ME];
+ if (!pointerp(pmap))
+ pmap=team->PresentRows(ENV);
+ for (i=1;i<MAX_TEAMROWS;i++)
+ if (member(pmap[i],ME)>=0)
+ return i+1;
+ return 1;
+}
+
+#define FILLSTRING " "
+varargs private string center_string(string str, int w) {
+ return (FILLSTRING[0..((w-sizeof(str))/2-1)]+str+FILLSTRING)[0..(w-1)];
+}
+
+private int ShowTeamRows() {
+ int i,j,sz;
+ mixed *pres_rows;
+ object *obs,ob;
+ string str;
+
+ pres_rows=PresentEnemyRows();
+ for (sz=MAX_TEAMROWS-1;sz>=0;sz--)
+ if (sizeof(pres_rows[sz]))
+ break;
+ for (i=sz;i>=0;i--) {
+ obs=pres_rows[i];str="";
+ for (j=sizeof(obs)-1;j>=0;j--)
+ if (objectp(ob=obs[j])) {
+ if (str!="") str+=" / ";
+ str+=ob->Name(RAW);
+ }
+ printf("%d. %s\n",i+1,center_string(str,75));
+ }
+ if (sz>=0)
+ write(" ---------------------------------------------------------------------------\n");
+ pres_rows=PresentTeamRows();
+ for (sz=MAX_TEAMROWS-1;sz>0;sz--)
+ if (sizeof(pres_rows[sz]))
+ break;
+ for (i=0;i<=sz;i++) {
+ obs=pres_rows[i];str="";
+ for (j=sizeof(obs)-1;j>=0;j--)
+ if (objectp(ob=obs[j])) {
+ if (str!="") str+=" / ";
+ str+=ob->Name(RAW);
+ }
+ printf("%d. %s\n",i+1,center_string(str,75));
+ }
+ return 1;
+}
+
+varargs int team_list(string arg) {
+ object *tobs,*obs,tob,ob,ld;
+ string *nms,*tnms,str;
+ int i,j;
+
+ if (!pointerp(tobs=TEAM_MASTER->ListTeamObjects())) return 0;
+ if (arg!="alle") arg=0;
+ tnms=({});
+ for (i=sizeof(tobs)-1;i>=0;i--) {
+ if (!objectp(tob=tobs[i])
+ || !objectp(ld=tob->Leader())
+ || (!query_once_interactive(ld) && !arg)
+ || !pointerp(obs=tob->Members()))
+ continue;
+ nms=({});
+ for (j=sizeof(obs)-1;j>=0;j--) {
+ if (!objectp(ob=obs[j])
+ || (!query_once_interactive(ob) &&!arg))
+ continue;
+ if (!stringp(str=ob->Name(WER))) str="?";
+ if (ob==ld) str+="(*)";
+ nms+=({str});
+ nms=sort_array(nms,#'>);
+ }
+ if (!stringp(str=tob->Name())) str="Team ?";
+ str+=": ";
+ tnms+=({break_string(implode(nms,", "),78,str)});
+ tnms=sort_array(tnms,#'<);
+ }
+ if (sizeof(tnms))
+ tell_object(ME, sprintf("%@s\n", tnms));
+ else
+ tell_object(ME, "Keine Teams gefunden.\n");
+
+ return 1;
+}
+
+varargs int teamcmd(string arg) {
+ string *words,narg;
+ object team;
+
+ if (!arg)
+ arg="";
+ if (!stringp(narg=TP->_unparsed_args()))
+ narg = arg;
+ if (!sizeof(words=explode(arg," ")))
+ return 0;
+
+ if (sizeof(words) > 1) {
+ arg=implode(words[1..]," ");
+ narg = implode(explode(narg, " ")[1..], " ");
+ }
+ else
+ arg = narg = "";
+
+ switch(words[0]) { // Befehle die keine Mitgliedschaft erfordern:
+ case "aufnahme":
+ return team_aufnahme(arg);
+ case "folge":
+ return team_aufnahmewunsch(arg);
+ case "?":
+ case "hilfe":
+ return team_help();
+ case "liste":
+ return team_list(arg);
+ case "uebersicht":
+ return ShowTeamRows();
+ default:;
+ }
+
+ if (!objectp(team=QueryProp(P_TEAM)))
+ return notify_fail("Du bist in keinem Team.\n"),0;
+
+ switch(words[0]) {
+ case "angriffsbefehl":
+ if (narg=="") narg=0;
+ team_attack_cmd=narg;
+ if (stringp(narg))
+ write("Du beginnst den Kampf mit \""+narg+"\"\n");
+ else
+ write("Du hast den Teamangriffsbefehl deaktiviert.\n");
+ break; // NICHT return!
+ case "autofolge":
+ case "autof":
+ if (arg=="ein" || arg=="an") {
+ team_autofollow=1;
+ if (IsTeamLeader())
+ write("Dein Team folgt Dir.\n");
+ else
+ write("Du folgst jetzt dem Teamleiter.\n");
+ } else {
+ team_autofollow=0;
+ if (IsTeamLeader())
+ write("Dein Team folgt Dir nicht mehr.\n");
+ else
+ write("Du folgst jetzt nicht mehr dem Teamleiter.\n");
+ }
+ break; // NICHT return!
+ default: ;
+ }
+ return team->TeamCmd(words[0],narg); // Befehle die Mitgliedschaft erfordern:
+}
+
+varargs void InformRowChange(int from, int to, object caster) {
+
+ if (caster) return; // Fuer den Fall, dass Gildenobjekt==ME ist
+ if (PO!=Query(P_TEAM)) return;
+#if __BOOT_TIME__ < 1281904437
+ mixed gilde = QueryProp(P_GUILD);
+ if (!stringp(gilde)) return;
+ if (!objectp(gilde=find_object("/gilden/"+gilde))) return;
+ gilde->InformRowChange(from,to,ME);
+#endif
+ HookFlow(H_HOOK_TEAMROWCHANGE, ({from,to}) );
+}