Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/player/invmaster/invmaster.c b/std/player/invmaster/invmaster.c
new file mode 100644
index 0000000..06ccda0
--- /dev/null
+++ b/std/player/invmaster/invmaster.c
@@ -0,0 +1,464 @@
+// invmaster.c by Nachtwind@MG V1.1 (5.3.2001)
+// A small master that provides a graphical display of the player´s
+// equipment.
+#pragma strong_types
+#pragma save_types,rtt_checks
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <input_to.h>
+#include <properties.h>
+#include <ansi.h>
+#include <combat.h>
+#include <language.h>
+#include "invmaster.h"
+
+
+mapping data;
+closure abbreviate;
+
+
+// i'm aware this can be determined with m_indices(VALID_ARMOUR_TYPE),
+// but the position in the arrays is important for the drawing order.
+// first item in the array is drawn last
+static string *armour_types =
+({AT_BELT,
+ AT_SHIELD,
+ AT_HELMET,
+ AT_BOOT,
+ AT_TROUSERS,
+ AT_AMULET,
+ AT_RING,
+ AT_GLOVE,
+ AT_QUIVER,
+ AT_CLOAK,
+ AT_ARMOUR});
+
+static mapping colors =
+([0:ANSI_BLACK,
+ 1:ANSI_RED,
+ 2:ANSI_GREEN,
+ 3:ANSI_YELLOW,
+ 4:ANSI_BLUE,
+ 5:ANSI_PURPLE,
+ 6:ANSI_CYAN,
+ 7:ANSI_WHITE,
+ 8:""]);
+
+static mapping bgcolors =
+([0:ANSI_BG_BLACK,
+ 1:ANSI_BG_RED,
+ 2:ANSI_BG_GREEN,
+ 3:ANSI_BG_YELLOW,
+ 4:ANSI_BG_BLUE,
+ 5:ANSI_BG_PURPLE,
+ 6:ANSI_BG_CYAN,
+ 7:ANSI_BG_WHITE,
+ 8:""]);
+
+
+
+static string Mapping2ColoredText(mapping pic, object player);
+static string Mapping2PlainText(mapping pic);
+static void AddDescription(mapping pic, string type, object item);
+static string ComposeDesc(object item);
+static void ConfigureColors(string text);
+
+void ShowInv(object player, string arg);
+
+// ok, let´s just read in the graphics...
+// really takes some time (~250 eval ticks) but is only done
+// once in an uptime
+void create()
+{
+ mapping pic;
+ string *files, *lines, text;
+ int i,j,k, indentx,indenty, color;
+
+ data=([]);
+
+ DB("Trying to fire up master, path is '"+INVPATH+"'...");
+ files=get_dir(INVPATH+"gfx/*")-({".", ".."});
+ DB(sprintf("Files found in 'gfx/': \n%O", files));
+ for (i=sizeof(files)-1;i>=0;i--)
+ {
+ DB("Reading '"+files[i]+"' ...");
+ text=read_file(INVPATH+"gfx/"+files[i]);
+ if (!stringp(text))
+ {
+ DB("Failed to read file.");
+ continue;
+ }
+ lines=explode(text, "\n");
+ if (sizeof(lines) < 4)
+ {
+ DB("File corrupt.");
+ continue;
+ }
+ indentx=to_int(lines[1]);
+ indenty=to_int(lines[2]);
+ color=to_int(lines[0]);
+ pic=([]);
+ for (j=sizeof(lines)-1;j>2;j--)
+ {
+ for (k=sizeof(lines[j])-1;k>=0;k--)
+ {
+ if (lines[j][k..k]!="?")
+ pic+=([(j-3+indenty)*80+k+indentx:lines[j][k..k];color]);
+ }
+ }
+ data+=([files[i]:pic]);
+ DB("File successfully read.");
+ }
+ DB(sprintf("Types covered:\n%O\n", m_indices(data)));
+
+ // create closure only once to save time
+ // needed by ComposeDesc()
+ // the closure ist not as complicated as it seems ;)
+ // it just checks every word of the name, if it does not begin
+ // with a capital letter, it is abbreviated
+ // this happens only if the name length exceeds 20 chars...
+ abbreviate=lambda(({'x}),
+ ({#'?, ({#'>, ({#'member, quote(({"der", "des"})), 'x}), 0}),
+ "d.",
+ ({#'?, ({#'>, ({#'sizeof, 'x}), 3}),
+ ({#'?, ({#',, ({#'=, 'a, ({#'allocate, 1}) }),
+ ({#'=, ({#'[, 'a, 0}), 'x }),
+ ({#'sizeof, ({#'regexp, 'a, "^[a-z].*"}) })
+ }),
+ ({#'+, ({#'[..], 'x, 0, 1}), "."}),
+ 'x
+ }),
+ 'x
+ })
+ }));
+}
+
+// function that tries to guess a good item name and use abbrevations
+// where possible
+static string ComposeDesc(object item)
+{
+ int i;
+ string text, *buff;
+
+ text=regreplace(item->QueryProp(P_SHORT)
+ ||item->QueryProp(P_NAME)
+ ||"<?>",
+ "^(Ein Paar|Ein|Eine|Der|Die|Das) ","",0);
+
+// try to shorten the name with the closure
+ if (sizeof(text) > 20)
+ return implode(map(explode(text, " "), abbreviate), " ");
+ else
+ return text;
+}
+
+// converts a mapping with characters and color info into a
+// text. data in the mapping is stored in a one-dimensional
+// order with the position as key (ypos is pos/80, xpos pos%80)
+// this setup has a huge advantage: combining several
+// graphics just takes a "+" operator, the rest is handled
+// by the game driver. freakin' fast, much better than doing an
+// iteration over one or more array in lpc.
+static string Mapping2ColoredText(mapping pic, object player)
+{
+ string text;
+ mapping configmap;
+ int i,j,color;
+
+ configmap=default_config+(player->QueryProp(P_INVMASTER_CONFIG)||([]));
+
+ text="";
+ color=0;
+ for (i=0;i<22;i++)
+ {
+ text+=bgcolors[configmap[8]];
+ for (j=0;j<78;j++)
+ {
+ if (pic[i*80+j,1]!=color)
+ {
+ color=pic[i*80+j,1];
+ text+=colors[configmap[color]];
+ }
+ text+=pic[i*80+j];
+ }
+ text+=ANSI_NORMAL+"\n";
+ color=0;
+ }
+ return text;
+}
+
+static string Mapping2PlainText(mapping pic)
+{
+ string text;
+ int i,j;
+
+ text="";
+
+ for (i=0;i<22;i++)
+ {
+ for (j=0;j<78;j++)
+ text+=pic[i*80+j];
+ text+="\n";
+ }
+ return text;
+}
+static void AddDescription(mapping pic, string type, object item)
+{
+ int indentx, indenty, i;
+ string text;
+
+ switch(type)
+ {
+ case AT_HELMET:
+ indentx=47;
+ indenty=0;
+ text=sprintf("%-30s",ComposeDesc(item)[0..30]);break;
+ case AT_QUIVER:
+ indentx=49;
+ indenty=2;
+ text=sprintf("%-28s",ComposeDesc(item)[0..28]);break;
+ case AT_AMULET:
+ indentx=49;
+ indenty=4;
+ text=sprintf("%-27s",ComposeDesc(item)[0..28]);break;
+ case AT_ARMOUR:
+ indentx=53;
+ indenty=7;
+ text=sprintf("%-24s",ComposeDesc(item)[0..25]);break;
+ case AT_SHIELD:
+ indentx=54;
+ indenty=10;
+ text=sprintf("%-20s",ComposeDesc(item)[0..24]);break;
+ case AT_CLOAK:
+ indentx=53;
+ indenty=15;
+ text=sprintf("%-20s",ComposeDesc(item)[0..25]);break;
+ case AT_TROUSERS:
+ indentx=49;
+ indenty=17;
+ text=sprintf("%-20s",ComposeDesc(item)[0..20]);break;
+ case AT_RING:
+ indentx=0;
+ indenty=9;
+ text=sprintf("%14s",ComposeDesc(item)[0..17]);break;
+ case AT_GLOVE:
+ indentx=0;
+ indenty=11;
+ text=sprintf("%14s",ComposeDesc(item)[0..17]);break;
+ case AT_BELT:
+ indentx=1;
+ indenty=13;
+ text=sprintf("%14s",ComposeDesc(item)[0..18]);break;
+ case AT_BOOT:
+ indentx=1;
+ indenty=20;
+ text=sprintf("%18s",ComposeDesc(item)[0..18]);break;
+ case "Waffe":
+ indentx=1;
+ indenty=1;
+ text=sprintf("%18s",ComposeDesc(item)[0..25]);
+ if (item->QueryProp(P_NR_HANDS) > 1 &&
+ this_player() &&
+ !(this_player()->QueryArmorByType(AT_SHIELD)))
+ AddDescription(pic, AT_SHIELD, item);break;
+ default: return;
+ }
+ for (i=0;i<sizeof(text);i++)
+ pic+=([(80*indenty+indentx+i):text[i..i];2]);
+}
+
+varargs static void ConfigureColors(string text)
+{
+ mapping config, display;
+ string *strs;
+
+ if (!objectp(this_player())) return;
+
+ if (this_player()->InFight())
+ {
+ write(break_string(
+ "Im Kampf? Na Du hast Nerven, das lassen wir doch mal lieber! "
+ "Probier es danach nochmal...", 78));
+ return;
+ }
+
+ if (stringp(text)) text=lower_case(text);
+
+ if (text=="ok")
+ {
+ write("Farbkonfiguration beendet.\n");
+ return;
+ }
+
+ //"ansi_config", def in invmaster.h
+ config=this_player()->QueryProp(P_INVMASTER_CONFIG)||([]);
+ display=default_config+config;
+
+ if (!text || text=="")
+ {
+ write(
+ "*** Farbkonfiguration fuer den Ausruestungsbefehl ***\n\n"
+ " Farbe: wird dargestellt mit:\n"
+ "------------------ --------------------\n"
+ " Hintergrund "+COLORNAMES[display[8]]+"\n"
+ " Schwarz "+COLORNAMES[display[0]]+"\n"
+ " Rot "+COLORNAMES[display[1]]+"\n"
+ " Gruen "+COLORNAMES[display[2]]+"\n"
+ " Gelb "+COLORNAMES[display[3]]+"\n"
+ " Blau "+COLORNAMES[display[4]]+"\n"
+ " Magenta "+COLORNAMES[display[5]]+"\n"
+ " Tuerkis "+COLORNAMES[display[6]]+"\n"
+ " Weiss "+COLORNAMES[display[7]]+"\n\n"
+ "Farbe aendern mit '<farbe> <gewuenschte farbe>'.\n"
+ "Beispiel: 'gelb rot'.\n"
+ "Alles, was standardmaessig gelb waere, wuerde dann mit der ANSI-Farbe \n"
+ "Rot dargestellt.\n"
+ "Der Hintergrund kann zusaetzlich die Farbe 'keine' haben, bei der der \n"
+ "Hintergrund eben ueberhaupt nicht gefaerbt wird.\n"
+ "Beispiel: 'hintergrund keine'. Schaltet die Hintergrundfarbe aus.\n\n"
+ "Beenden mit 'ok'. \n"
+ "Wiederholung der Farbliste mit <Return>.\n"
+ "Farbliste auf Standard zuruecksetzen mit 'reset'.\n");
+ }
+ else
+ if (text=="reset")
+ {
+ this_player()->Set(P_INVMASTER_CONFIG, SAVE, F_MODE_AD);
+ this_player()->SetProp(P_INVMASTER_CONFIG, 0);
+ write("Farben zurueckgesetzt!\n");
+ }
+ else
+ {
+ if ( sizeof(strs=explode(text, " ")-({""})) !=2
+ || !member((COLORCODES-(["keine"])), strs[0])
+ || !member((COLORCODES-(["hintergrund"])), strs[1])
+ || ((strs[0]!="hintergrund") && (strs[1]=="keine")) )
+ {
+ write("Falsche Eingabe.\n"
+ "Format: <farbe|hintergrund> <zugewiesene Farbe>\n"
+ "Abbrechen mit 'ok'.\n");
+ }
+ else
+ {
+ if (COLORCODES[strs[1]]==default_config[COLORCODES[strs[0]]])
+ config-=([COLORCODES[strs[0]]]);
+ else
+ config+=([COLORCODES[strs[0]]:COLORCODES[strs[1]]]);
+ if (!sizeof(config))
+ {
+ this_player()->Set(P_INVMASTER_CONFIG, SAVE, F_MODE_AD);
+ this_player()->SetProp(P_INVMASTER_CONFIG, 0);
+ }
+ else
+ {
+ this_player()->SetProp(P_INVMASTER_CONFIG, deep_copy(config));
+ this_player()->Set(P_INVMASTER_CONFIG, SAVE, F_MODE_AS);
+ }
+ write("Ok, Farbe gewaehlt!\n");
+ }
+ }
+ input_to("ConfigureColors", INPUT_PROMPT, "\nEingabe: ");
+}
+
+
+string* armour_order=({
+ AT_HELMET, AT_AMULET, AT_QUIVER, AT_ARMOUR, AT_CLOAK,
+ AT_GLOVE, AT_RING, AT_BELT,
+ AT_TROUSERS, AT_BOOT, AT_SHIELD, AT_MISC});
+
+mapping weapon_names=([
+ WT_SPEAR : "Speer",
+ WT_SWORD : "Schwert",
+ WT_STAFF : "Kampfstab",
+ WT_WHIP : "Peitsche",
+ WT_CLUB : "Keule",
+ WT_KNIFE : "Messer",
+ WT_MISC : "Irgendwas",
+ WT_MAGIC : "Artefakt",
+ WT_AXE : "Axt",
+ WT_RANGED_WEAPON : "Fernwaffe"
+ ]);
+
+string SimpleInv(object player) {
+ object* armours=player->QueryProp(P_ARMOURS);
+ int count=sizeof(armour_order);
+ string* list=allocate(count);
+ string result="Ausruestung\n";
+ int i;
+
+ foreach(object ob: armours) {
+ if (!objectp(ob)) continue;
+ int idx = member(armour_order, ob->QueryProp(P_ARMOUR_TYPE));
+ if (idx>=0)
+ list[idx]=ob->QueryProp(P_SHORT);
+ }
+
+ // AT_MISC (letztes Element in list und armour_order) weglassen.
+ for (i=0;i<count-1;i++) {
+ result+=sprintf("%-20s %-57s\n",armour_order[i],list[i] || "");
+ }
+
+ object ob=ob=player->QueryProp(P_WEAPON);
+ if (objectp(ob)) {
+ result+=sprintf("%-20s %-57s\n",
+ (ob->QueryProp(P_NR_HANDS)==1 ? "Einhand-":"Zweihand-")
+ +weapon_names[ob->QueryProp(P_WEAPON_TYPE)],
+ ob->QueryProp(P_SHORT));
+ } else result+="Keine Waffe\n";
+
+ return result;
+}
+// the main function called by the player object.
+// determines gender, then adds armor/weapon graphics
+// dynamically. still very fast due to the use of the "+" operator,
+// see above.
+void ShowInv(object player, string arg)
+{
+ string gender, type;
+ mapping pic;
+ int i;
+ object item;
+
+ if (!objectp(player)||!interactive(player)) return;
+
+ // split args.
+ string *args;
+ if (stringp(arg))
+ args = explode(lower_case(arg), " ") - ({" "});
+ else
+ args = ({});
+
+ if (member(args, "farben") > -1) {
+ ConfigureColors();
+ return;
+ }
+
+ if (member(args, "-k") > -1 || player->QueryProp(P_NO_ASCII_ART)) {
+ tell_object(player, SimpleInv(player));
+ return;
+ }
+
+ gender=player->QueryProp(P_GENDER)==FEMALE?"_female":"_male";
+ pic=deep_copy(data["base"+gender]);
+ pic+=data["Beschriftung"];
+ for (i=sizeof(armour_types)-1;i>=0;i--)
+ if (objectp(item=player->QueryArmourByType(armour_types[i])))
+ {
+ pic+=data[armour_types[i]+gender];
+ AddDescription(pic, armour_types[i], item);
+ }
+ if (item=player->QueryProp(P_WEAPON))
+ {
+ pic+=data[(VALID_WEAPON_TYPE(type=item->QueryProp(P_WEAPON_TYPE)))?
+ type:WT_MISC];
+ AddDescription(pic, "Waffe", item);
+ }
+ if (player->QueryProp(P_TTY)!="ansi")
+ player->More(Mapping2PlainText(pic));
+ else
+ player->More(Mapping2ColoredText(pic, player));
+ DB(geteuid(player)+" eval cost: "+(1000000-get_eval_cost())+" ticks.\n");
+}
+