!! Multiplayer Inform 0.1 for ifMUD's Floyd Copyright 1999 Evin Robertson.
!! May be used, modified, and distributed without restriction. Absolutely no
!! warranty of any type is provided for this library.
!!
!! Very loosely based on Adam Cadre's multistub.h. Uses bits of the name
!! parsing code in Graham Nelson's _Balances_. Thanks to Jota for some
!! insane ideas which eventually developed into Floyd.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! You should remove the line !!
!! if (o==player) { print (string) YOURSELF__TX; rtrue; } !!
!! from parserm.h to obtain correct output. !!
!! !!
!! Disambiguation isn't yet properly fixed, so add the line !!
!! best_etype = NO_DISAMB_PE; rfalse; !!
!! to parserm.h immediately before the line !!
!! if (match_from > num_words) jump Incomplete !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! You can either take existing games and fit them to this library or write a
!! new game to use this library. To fit an existing game to multifloyd,
!! include this header between Parser and VerbLib. Rename the game's
!! Initialise to GameInitialise. You may want to provide a 'multiobject' for
!! the game - see the example given in werewolf. To write a game specifically
!! for floyd, either study the werewolf source or wait for me to to write a
!! proper manual.
!! TODO:
!! * Fix disambiguation by copying each player's input to their player object
!! and refeeding the library, blocking its questions the second time
!! * Make each player die separately
!! * Write a bridge game to demonstrate turn-taking
!! * Write an IF game to demonstrate actions visible to other players in the
!! same room
!! * Write better documentation
#IFNDEF multiobject;
Object multiobject;
#ENDIF;
Replace YesOrNo;
[ YesOrNo i;
for(::) {
read buffer parse;
i=parse-->5; !! Look at third word instead of first
if (i==YES1__WD or YES2__WD or YES3__WD) rtrue;
if (i==NO1__WD or NO2__WD or NO3__WD) rfalse;
L__M(##Quit,1); print "> ";
}
];
Replace QuitSub;
[ QuitSub c;
woff();
print (name) actor, " deleted! ";
c = GenericNewPlayer;
#IFDEF player_class;
if(multiobject provides player_class)
c = multiobject.player_class;
#ENDIF;
c.destroy(actor);
WhoSub();
];
Attribute ingame;
[ ParseWordNumber w;
! return (parse+2)-->((w-1) * 2);
return parse-->(w*2 - 1);
];
[ movecontents dest src o x;
o = child(src);
while(o) {
x = sibling(o);
move o to dest;
o = x;
}
];
[ find_player w o;
wn = w;
TextReader();
objectloop(o has ingame) {
if(o.check_name())
return o;
}
return 0;
];
Constant whispermaxdepth 32;
Global whisperdepth = 0;
Array whisperstack --> whispermaxdepth;
[ won o f;
if(~~o)
o = actor;
f = 0;
if(whisperdepth) {
if(o == whisperstack-->(whisperdepth-1))
f = 1;
else
print "";
}
whisperstack-->whisperdepth = o;
whisperdepth++;
if(~~f) {
print "";
}
];
[ woff;
if(~~whisperdepth)
return;
whisperdepth--;
if(whisperdepth && whisperstack-->whisperdepth == whisperstack-->(whisperdepth-1))
return;
print "";
if(whisperdepth) {
print "(whisperdepth-1)).whisper_name();
print ">";
}
];
[ print_thing thing;
if(thing)
switch(ZRegion(thing)) {
1: print (name) thing;
2: indirect(thing);
3: print (string) thing;
default: print thing;
}
];
[ tellroom room except msg1 msg2 msg3 msg4 msg5 o;
objectloop(o in room && o has ingame && o ~= except) {
won(o);
print_thing(msg1);
print_thing(msg2);
print_thing(msg3);
print_thing(msg4);
print_thing(msg5);
woff();
}
];
[ DoNothingSub; ]; Verb ',donothing' * -> DoNothing;
Global PersonThisTurn;
[ BeforeParsing src dest word_space i;
PersonThisTurn = find_player(1); !! First word is name of person
if(parse->1 == 3 && ParseWordNumber(3) == 'abort')
quit;
if(~~PersonThisTurn) {
if(parse->1 == 3)
switch(ParseWordNumber(3)) {
'join': Addplayer(); jump ignorecommand;
'who': WhoSub(); jump ignorecommand;
'quit': quit;
}
print "i;
print ">";
if(~~(multiobject provides orders &&
multiobject.orders(ParseWordNumber(3))))
print "You must be a player to enter a command.^";
print "";
.ignorecommand;
parse->1 = 1; (parse+2)-->0 = ',donothing';
return;
}
ChangePlayer(PersonThisTurn); !! Make this that person
last_score = score = PersonThisTurn.player_score;
parse->1 = parse->1 - 2; !! Chop off first two words
word_space = (parse->1) * 4;
src = parse + 10;
dest = parse + 2;
@copy_table src dest word_space;
won(PersonThisTurn);
];
[ AfterPrompt;
if(PersonThisTurn) {
PersonThisTurn.player_score = score;
woff();
}
];
[ opposite_dir d;
switch(d) {
n_to: print "the south";
ne_to: print "the southwest";
e_to: print "the west";
se_to: print "the northwest";
s_to: print "the north";
sw_to: print "the northeast";
w_to: print "the east";
nw_to: print "the southeast";
d_to: print "above";
u_to: print "below";
in_to: print "outside";
out_to: print "inside";
default: print "the moon [BUG]";
}
];
Object youobject "you"
has proper animate;
Global num_players;
Constant PlayerNameMax = 16; !! Adjust my_name if you change this
Array text_buffer -> PlayerNameMax;
#ifdef player_class;
Constant GenericNewplayerCount = 0;
#ifnot;
Constant GenericNewplayerCount = 40;
#endif;
Class GenericNewplayer (GenericNewplayerCount)
with my_name 0 0 0 0 0 0 0 0, !! Must have (PlayerNameMax / 2) zeros here.
! last_input 0 0 0 0 0 0 0 0 !! Space to hold last command entered
! 0 0 0 0 0 0 0 0 !! For disambiguation and oops handling
! 0 0 0 0 0 0 0 0
! 0 0 0 0 0 0 0 0,
description [;
print "An adventurer not unlike yourself";
if(child(self)) {
print ". It carries ";
WriteListFrom(child(self), FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT);
}
".";
],
whisper_name [ i; !! Name used in
for(i = 0: self.&my_name->i && i < PlayerNameMax: i++)
print (char) self.&my_name->i;
rtrue;
],
short_name [; !! Replace to give people specific names
return self.whisper_name();
],
check_name [ i; !! Compare text_buffer with my_name
for(i = 0: i < PlayerNameMax: i++)
if(text_buffer->i ~= self.&my_name->i)
rfalse;
rtrue;
],
parse_name [;
if(~~Textreader()) !! Copy input into a buffer
rfalse;
return self.check_name();
],
create [ oldself i;
num_players++;
give self ingame;
oldself = player;
for(i=0: ii = text_buffer->i;
ChangePlayer(self);
won(self);
GameInitialise();
move self to location;
self.player_score = last_score = score;
woff();
ChangePlayer(oldself);
],
destroy [;
num_players--;
give self ~ingame;
movecontents(parent(self), self);
! tellroom(parent(self), self, self, " disappears in a puff of pink smoke.");
if(player == self)
ChangePlayer(selfobj);
remove self;
],
Grammar [;
if(self ~= player)
return ',fooey'; !! Route all 'orders' to 'answer' by confusing
!! inform
],
life [ i message len o;
Attack:
if(AfterRoutines()==1) rtrue;
"You glare at ", (the) self, ".";
Kiss:
if(AfterRoutines()==1) rtrue;
"You give ", (the) self, " a peck on the cheek.";
WakeOther:
if(AfterRoutines()==1) rtrue;
print_ret (The) self, " stops snoring for a moment.";
ThrowAt:
move noun to self;
if(AfterRoutines()==1) rtrue;
"You toss ", (the) noun, " to ", (the) self, ", who catches it.";
Give:
move noun to self;
if(AfterRoutines()==1) rtrue;
print_ret (The) self, " accepts ", (the) noun, ".";
Show:
if(AfterRoutines()~=1)
print "You show ", (the) noun, " to ", (the) self, ".^";
won(self);
o = player;
ChangePlayer(self);
;
ChangePlayer(o);
woff();
rtrue;
Ask, Tell, Answer:
won(self);
print (name) actor;
switch(action) {
##Ask: print " asks you about ";
##Tell: print " tells you about ";
##Answer: print " tells you, ";
}
message = WordAddress(consult_from);
len = WordAddress(consult_from + consult_words - 1) - message +
WordLength(consult_from + consult_words - 1);
for(i = 0: i < len: i++)
print (char) message->i;
new_line;
woff();
print_ret (The) self, " pretends to pay attention.";
Order:
won(self);
print (The) actor, " enslaves you [BUG].^";
woff();
"You turn ", (the) self, " into your slave [BUG].";
default:
won(self);
print (The) actor, " performs wacky antics with you [BUG].^";
woff();
"You perform wacky antics with ", (the) self, " [BUG].";
],
last_location 0,
react_before [;
if(actor ~= self)
rfalse;
switch(action) {
##Go: self.last_location = location;
}
],
react_after [ o s n;
if(actor == self) {
if(action == ##Go or ##Enter or ##Exit) {
objectloop(o in self.last_location && o has ingame && o ~= self) {
won(o);
print (name) self, " goes ";
LanguageDirection(noun.door_dir);
print ".^";
woff();
}
}
rfalse;
}
s = second; n = noun;
if(second == self)
s = youobject; !! Make it say 'you' for the destination
if(noun == self)
n = youobject;
won(self);
switch(action) {
##Go:
print (The) actor, " arrives from ", (opposite_dir) n.door_dir, ".^";
##Enter:
print (The) actor, " goes into ", (the) n, ".^";
##Exit:
print (The) actor, " exits.^";
##Take:
print (The) actor, " takes ", (the) n, ".^";
##Drop:
print (The) actor, " drops ", (the) n, ".^";
##Remove:
print (The) actor, " removes ", (the) n, " from ", (the) s, ".^";
##PutOn:
print (The) actor, " puts ", (the) n, " on ", (the) s, ".^";
##Insert:
print (The) actor, " puts ", (the) n, " in ", (the) s, ".^";
##Examine:
print (The) actor, " examines ", (the) n, ".^";
##Search:
print (The) actor, " searches ", (the) n, ".^";
##ThrowAt:
print (The) actor, " throws ", (the) n, " at ", (the) s;
if(s == youobject)
print " and you catch it";
else if(s has ingame)
print ", who catches it";
print ".^";
##Give:
print (The) actor, " gives ", (the) s, " ", (the) n, ".^";
##Show:
print (The) actor, " shows ", (the) s, " ", (the) n, ".^";
##Kiss:
print (The) actor, " kisses ", (the) n, " on the cheek.^";
##WakeOther:
print (The) actor, " tries but fails to wake ", (the) n, " up.^";
##Attack:
print (The) actor, " makes menacing glances at ", (the) n, ".^";
##Unlock:
print (The) actor, " unlocks ", (the) n, ".^";
##Lock:
print (The) actor, " locks ", (the) n, ".^";
##SwitchOn:
print (The) actor, " turns on ", (the) n, ".^";
##SwitchOff:
print (The) actor, " turns off ", (the) n, ".^";
##Open:
print (The) actor, " opens ", (the) n, ".^";
##Close:
print (The) actor, " closes ", (the) n, ".^";
##Disrobe:
print (The) actor, " takes off ", (the) n, ".^";
##Wear:
print (The) actor, " puts on ", (the) n, ".^";
##Eat:
print (The) actor, " eats ", (the) n, ".^";
}
woff();
],
player_score,
number, !! Required for player objects
has animate neuter proper light;
[ TextReader point i len; ! Mostly from balances
for(i=0: ii = 0;
if(wn > parse->1) {
wn++;
rfalse;
}
point = WordAddress(wn);
len = WordLength(wn);
if(len > PlayerNameMax)
len = PlayerNameMax;
for(i=0: ii = point->i;
wn++; rtrue;
];
Object noplace "Waiting for players to join"
with description [;
print "WHO: Who's already playing?^JOIN: Add me to the list of players!^QUIT: Scratch me from the list of players!^ABORT: Make the game quit^";
if(multiobject provides description)
multiobject.description();
],
has light;
[ Initialise;
location = noplace;
lookmode = 2; !! default to verbose mode - difficult to keep track of
!! visited rooms separately for each player
if(multiobject provides initial)
multiobject.initial();
return(2);
];
[ Addplayer x c;
#IFDEF allow_join;
if(multiobject provides allow_join)
if(~~multiobject.allow_join)
"New players may not join right now.";
#ENDIF;
wn = 1;
if(~~TextReader())
rfalse;
c = GenericNewPlayer;
#IFDEF player_class;
if(multiobject provides player_class)
c = multiobject.player_class;
#ENDIF;
x = c.create();
if(x == nothing)
"Sorry, too many players have been created.";
print (name) x, " added! ";
WhoSub();
new_line;
rtrue;
];
[ WhoSub a b;
print "Current players (";
#IFDEF who_count;
if(multiobject provides who_count)
multiobject.who_count(num_players);
else
#IFNOT;
print num_players;
#ENDIF;
print "):^";
objectloop (a has ingame) {
print (name) a, " ";
#IFDEF who_extra;
if(multiobject provides who_extra)
multiobject.who_extra(a);
#ENDIF;
b = 1;
}
if (~~b) print "NONE";
new_line;
];
Verb 'who'
* -> Who;
[ EndGameSub;
woff();
print (name) actor, " has made the game quit.^^";
quit;
];
Verb 'endgame'
* -> EndGame;