sub update{ my $time=$lastupdate; until($time>time) { #do events, checking from last update time to current time, incase it #took more than a seconds for the update. still do updates in order. if (defined($do{$time})){ while (@{$do{$time}}){ &{$do{$time}[0]{sub}}(@{$do{$time}[0]{args}}); shift @{$do{$time}}; } } $time++; } if (time-$mediumupdate>30){ $mediumupdate=time; &mediumupdate; } if (time-$longupdate>300){ $longupdate=time; &longupdate; } foreach $a (keys %outbuffer) { #feed monsters their incoming data for scripts and general AI. # in other words run the sub defined for the monster with each line of text he saw. if (defined($user{$a}{monster})){ #split based on prompt my @incoming=split(/\r\n\[\[34m: \[\[0m/,"$outbuffer{$a}"); delete $outbuffer{$a}; local $client=$a; if (defined(&{$monster[$user{$a}{monster}]{script}})){ foreach $incoming (@incoming){ &{$monster[$user{$a}{"monster"}]{script}}($incoming); } handle($client); delete($ready{$client}); } } } foreach $a (keys %user){ #basic user updating info. decrease round stun, and check if dead body should decay if ($user{$a}{round}){ $user{$a}{round}--; if ($user{$a}{round}<=0) { $outbuffer{$a}.="go\r\n$prompt"; } } if ($user{$a}{stun}){ $user{$a}{stun}--; } if ($user{$a}{balance}<100){ $user{$a}{balance}++; }else{ $user{$a}{balance}=100; } if($user{$a}{dead}){ if (time-$user{$a}{dead}>300){ if (defined($user{$a}{monster})){ #monster is dead say("the dead body of $user{$a}{name} decays into nothingness.",$user{$a}{room}); monsterdecay($a); next; } else { playerdecay($a); #player is dead next; } } } #incrementing EXP here foreach $b (keys %{$user{$a}{exp}}){ #each overall type of exp, survival, weapons armor etc. foreach $c (keys %{$user{$a}{exp}{$b}}){ #each specific type, light edge, medium edge etc. #This is just some basic error checking, if it got this far but no data in pool #give 1 xp point to avoid errors. if ($c=~/total/) { next; } unless (defined($user{$a}{exp}{$b}{$c}{pool})){ addexp("$c","$b",1,$a); } if ($user{$a}{exp}{$b}{$c}{pool}>0){ my $increase=0; if ($user{$a}{exp}{$b}{$c}{pool}>($user{$a}{disc}*600)){ #mind locked $increase=int($user{$a}{wis}); } elsif ($user{$a}{exp}{$b}{$c}{pool}>600){ #not locked, normal learning $increase=$user{$a}{wis}+(int(($user{$a}{exp}{$b}{$c}{pool}-600)/600)*3); } else { #slow learning, pool is almost empty. $increase=int($user{$a}{wis}/5); } if ($user{$a}{exp}{$b}{$c}{pool}>=$increase){ #move XP from pool to actual knowledge. $user{$a}{exp}{$b}{$c}{pool}-=$increase; $user{$a}{exp}{$b}{$c}{expcur}+=$increase*5; } else { #pool is now emptied $user{$a}{exp}{$b}{$c}{expcur}+=$user{$a}{exp}{$b}{$c}{pool}*10; $user{$a}{exp}{$b}{$c}{pool}=0; } my $ranks=0; while ($user{$a}{exp}{$b}{$c}{expcur}>=$user{$a}{exp}{$b}{$c}{expneeded}){ #while incase more than 1 rank gained. $user{$a}{cppool}+=$user{$a}{exp}{$b}{$c}{ranks}+1; while ($user{$a}{cppool}>50){ $user{$a}{cppool}-=50; $user{$a}{cp}++; } $user{$a}{exp}{$b}{$c}{expcur}=$user{$a}{exp}{$b}{$c}{expcur}-$user{$a}{exp}{$b}{$c}{expneeded}; $user{$a}{exp}{$b}{$c}{ranks}+=1; $ranks++; $user{$a}{exp}{$b}{$c}{expneeded}=(($user{$a}{exp}{$b}{$c}{ranks}+1)**2)*100; } if ($ranks==1){ $outbuffer{$a}.="\r\nYou earn a rank of \u$c \u$b\r\n$prompt"; } elsif ($ranks>1){ $outbuffer{$a}.="\r\nYou earn $ranks ranks of $c\r\n$prompt"; } } } } } } sub mediumupdate { foreach $a (keys %user){ unless (defined ($user{$a}{vitality})){ #probably is logging in, or is immortal. or something just broke next; } #handle health. heal and bleed. $user{$a}{vitality}+=$user{$a}{con}; if ($user{$a}{vitality}>$user{$a}{vitalitymax}){ $user{$a}{vitality}=$user{$a}{vitalitymax} } foreach $b (keys %{$user{$a}{health}}){ #Each body part. if (defined($user{$a}{health}{$b}{requires})){ #If it's not still conected to the body then it can't bleed. my $c=$user{$a}{health}{"$b"}{requires}; if ($user{$a}{health}{"$c"}{hp}<=0){ next; } } if ($user{$a}{health}{"$b"}{bleeding}){ $user{$a}{vitality}-=$user{$a}{health}{"$b"}{bleeding} } if ($user{$a}{health}{$b}{intbleeding}){ $user{$a}{vitality}-=$user{$a}{health}{$b}{intbleeding} } } if ($user{$a}{vitality}<=0 and (!$user{$a}{dead})){ died($a); } } } sub longupdate { foreach $node (@node){ #nodes handle monster spawning, ensuring a given area doesn't get flooded. and #allows the same monster to be in several areas at once. $a=rand(10); if (${$node}{max}>${$node}{maxused}){ if ($a<${$node}{prob}){ ${$node}{maxused}++; my $d=int(rand(@{${$node}{monsters}})); createmonster(${$node}{monsters}[$d],${$node}{room},$node); } } } foreach $a ($select->handles){ #inactivety check. #only checking actual people, monsters can't be inactive after all. unless (defined($user{$a})){ #don't ask me why but there is one in here thats not a person. so we skip it. next; } unless (defined($user{$a}{name})){ next; } if (defined($last{$a}) and (time-$last{$a}>500)){ $outbuffer{$a}.="You have been inactive for too long.\r\n$prompt"; } if (defined($last{$a}) and (time-$last{$a}>800)){ &delete($a); next; } } } sub createmonster { $mon=shift; $room=shift; $node=shift; unless(defined($monster[$mon])){ return; } local $client="monster".$monstertotal++; #load a player file to get the monster's information, body, items, etc. unless (loadplayerold($monster[$mon]{name}, $client, "monsters")){ print "Error\r\n"; return; } #choose a random adjective for the monster from valid choices my $z=int(rand(@{$monster[$mon]{adjectives}})); #set som basic info for the monster. $user{$client}{monster}=$mon; $user{$client}{node}=$node; $user{$client}{room}=$room; $user{$client}{desc}=$monster[$mon]{desc}; $outbuffer{$client}.="Welcome to the world.\n"; $user{$client}{name}=$monster[$mon]{adjectives}[$z]." $monster[$mon]{name}"; $user{$client}{pre}=$monster[$mon]{pre}; $room[$user{$client}{room}]{in}{$client}=$user{$client}{name}; #announce to people in the room that a new monster has spawned. if (defined($monster[$mon]{birthline})){ my $a=$monster[$mon]{birthline}; $a=~s/\[(.*?)\]/$user{$client}{$1}/isg; say("$a"); } else { say("$user{$client}{name} suddenly spawns before your eyes."); } my $time=time; #if theres a script to run at birth for this monster, run it. $type{$client}="normal"; if (defined($monster[$mon]{scriptbirth})){ &{$monster[$mon]{scriptbirth}}; } } sub addexp { #add exp to pool. exp will become skill slowly but surely. my $skill=shift; my $skilltype=shift; my $amount=shift; my $client=(shift or $client); unless ($skilltype and $amount and $skill){ #we got invalid data can't add exp to what doesn't exist. print "aaaah!!!\n"; return; } unless ($user{$client}){ print "error with adding exp, no user{client}\n\n"; return; } unless (defined($user{$client}{exp}{$skilltype})){ $user{$client}{exp}{$skilltype}={total=>0}; } unless(defined($user{$client}{exp}{$skilltype}{$skill})){ #skill doesn't exist yet so we create it. $user{$client}{exp}{$skilltype}{$skill}={pool=>0,ranks=>0,expcur=>0,expneeded=>100}; } my $maxpool=$user{$client}{disc}*600; if ($user{$client}{exp}{$skilltype}{$skill}{pool}>=$maxpool){ #is already locked, learning penalty impossed $outbuffer{$client}.="Your head aches from absorbing $skill and you learn very little\r\n$prompt"; $user{$client}{exp}{$skilltype}{$skill}{pool}+=$amount/100; return 0; } $user{$client}{exp}{$skilltype}{$skill}{pool}+=$amount; if ($user{$client}{exp}{$skilltype}{$skill}{pool}>=$maxpool){ #just became locked, no penalty this time but a warning. $outbuffer{$client}.="Your head begins to hurt from absorbing $skill and you learn very little\r\n$prompt"; } } sub died { #user or monster has died. my $dead=shift; my $line=(shift or "$user{$dead}{name} falls dead"); my $desc=(shift or "the dead body of $user{$dead}{name} lies here"); say2("$line",$user{$dead}{room},"You fall to the ground dead",$dead); $user{$dead}{dead}=time; $user{$dead}{position}="lying"; $user{$dead}{roomdesc}="$desc"; #this limits commands the char can use until he's ressurected. $type{$dead}="dead"; foreach $a (keys %{$user{$dead}{exp}}){ foreach $b (keys %{$user{$dead}{exp}{$a}}){ $user{$dead}{exp}{$a}{$b}{pool}=0; } } } sub say { #sends message to everyone in room. $message=shift; unless ($message=~/\r\n\Q$prompt\E$/){ $message.="\r\n$prompt"; } my $room=(shift or $user{$client}{room}); foreach $a (keys %{$room[$room]{in}}){ $outbuffer{$a}.="$message"; } } sub say2 { #sends $message to everyone one in $room except $ignore, who gets $message2 my $message=shift; my $room=shift; my $message2=shift; my $ignore=shift; foreach $a (keys %{$room[$room]{in}}){ if ($a eq "$ignore"){ if ($message2){ #we might just be keeping $ignore out of the loop. $outbuffer{$a}.="$message2\r\n$prompt"; } } else { $outbuffer{$a}.="$message\r\n$prompt"; } } } sub look{ #look around room, the command look is lookcommand. #basic desc if (defined($user{$client}{brief})){ $outbuffer{$client}.="$room[$user{$client}{room}]{shortdesc}\r\n"; } else{ $outbuffer{$client}.="$room[$user{$client}{room}]{longdesc}\r\n"; } local $b=0; #players and monsters in room foreach $a (keys %{$room[$user{$client}{room}]{in}}){ if (defined($user{$a}{hiding}) and $user{$a}{hiding} eq "yes"){ next; } unless ($room[$user{$client}{room}]{in}{$a} eq "$user{$client}{name}"){ unless($b==1){ $b=1; if ($user{$a}{roomdesc}){ #if they have a special desc to be displayed. $outbuffer{$client}.= "Also here is : $user{$a}{roomdesc}"; } else { #otherwise use their name $outbuffer{$client}.= "Also here is : $user{$a}{pre}$room[$user{$client}{room}]{in}{$a}"; } } else { if ($user{$a}{roomdesc}){ $outbuffer{$client}.=", $user{$a}{roomdesc}"; } else { $outbuffer{$client}.= ", $room[$user{$client}{room}]{in}{$a}"; } } } } if ($b){ $outbuffer{$client}.="\r\n"; } local $b=0; #now do items. foreach $a (keys %{$room[$user{$client}{room}]{items}}){ unless (defined($item{$a})){ next; } if (defined($item{$a}{noshow})){ next; } unless($b==1){ $b=1; if ($item{$a}{roomdesc}){ $outbuffer{$client}.= "Lying here is : $item{$a}{roomdesc}"; } else { $outbuffer{$client}.= "Lying here is : $item{$a}{name}"; } } else { if ($item{$a}{roomdesc}){ $outbuffer{$client}.=", $item{$a}{roomdesc}"; } else { $outbuffer{$client}.= ", $item{$a}{name}"; } } } if ($b){ $outbuffer{$client}.="\r\n"; } #then we have exits. $outbuffer{$client}.= "Obvious exits: $room[$user{$client}{room}]{exits}{obvious}"; $outbuffer{$client}.= "\r\n$prompt"; } sub move { #moves a persom to $dest from whereever they are. displays $message to the leaving room and $message2 to the entering room. my $dest=shift; my $message=shift; my $message2=shift; my $force=shift; unless($client){ my $client=shift; } if(roundcheck() and !$force){ #can't move if stunned or RT return; } if ($user{$client}{position} and $user{$client}{position} ne "stand" and !$force){ $outbuffer{$client}.="You'll have to stand to do that\r\n$prompt"; return; } #remove from first room, unhide if hiding, send messages while in niether room, then add to second room and look around. removefromroom($client); $user{$client}{hiding}=undef; say("$message",$user{$client}{room}); say("$message2",$dest); addtoroom($dest,$client); look(); } sub removefromroom { #remove a person from the room he is currently in. my $e=shift; delete($room[$user{$e}{room}]{in}{$e}); } sub addtoroom { #add $person to $room. my $room=shift; my $person=shift; $user{$person}{room}=$room; $room[$room]{in}{$client}=$user{$client}{name}; } sub additemtoroom { my $room=shift; my $item=shift; $room[$room]{items}{$item}=$item{$item}{name}; } sub removeitemfromroom { my $room=shift; my $item=shift; delete $room[$room]{items}{$item}; return 1; } sub makeitem { my $item=shift; #make a new item from the template $item. unless ($itemtemplate{$item}){ print "tried to create bad item $item\r\n"; return 0; } $itemtotal++; $item{$itemtotal}=$itemtemplate{$item}; &savemuddata; return $itemtotal; } sub delete { #hang up on a user. $a=shift; save($a); say("$user{$a}{name} has left the universe.",$user{$a}{room}); removefromroom($a); delete $inbuffer{$a}; delete $outbuffer{$a}; delete $ready{$a}; delete $user{$a}; delete $last{$a}; delete $type{$a}; $select ->remove($a); unless (close($a)){ print "error $!\n"; } } sub locateitemfloor { my $room=shift; my $item=shift; my $skip=shift; chomp ($item); foreach $a (keys %{$room[$room]{items}}){ if ($item{$a}{name}=~/$item/i){ if ($skip){ $skip--; } else { return $a; } } } return 0; } sub locateitem{ $room=shift; $item=shift; if ($a=locateitemfloor($room,$item)){ return $a; } return 0; } sub monsterdecay { #monster has died, now must leave us once and for all. $a=shift; removefromroom($a); #restore power to the node that is no longer mantaining the monster. ${$user{$a}{node}}{maxused}--; delete $user{$a}; delete $outbuffer{$a}; delete $inbuffer{$a}; delete $ready{$a}; delete $type{$a}; if (defined($user{$a})){ print "nope, it's not going boom\n"; die; } } sub playerdecay { #this is actually player ressurection. will deal with Player deaths later. $a=shift; say2("$user{$a}{name} is magicaly reborn!", $user{$a}{room}, "The gods smile upon you and you are returned to life!", $a); $type{$a}="normal"; $user{$a}{vitality}=$user{$a}{vitalitymax}; $user{$a}{roomdesc}="$user{$a}{name} is lying around"; removefromroom($client); addtoroom(1, $client); foreach $b (keys %{$user{$a}{health}}){ $user{$a}{health}{$b}{hp}=$user{$a}{health}{$b}{maxhp}; $user{$a}{health}{$b}{inthp}=$user{$a}{health}{$b}{maxinthp}; $user{$a}{health}{$b}{bleeding}=0; $user{$a}{health}{$b}{intbleeding}=0; $user{$a}{health}{$b}{scar}=0; $user{$a}{health}{$b}{intscar}=0; } delete $user{$a}{dead}; } sub descend { #internal sub used for save. my $str=shift; my $key=shift; if (ref($str) eq "HASH"){ #is a refrence need to descend $string.="<$key>\n"; foreach $a (keys %{$str}){ descend(${$str}{$a},$a); } $string.="</$key>\n"; } elsif (ref($str) eq "ARRAY"){ return; } else { #is a plain value, save it. $string.="<$key>$str</$key>\n"; } } sub save { #save command to save a player my $client=(shift or $client); if (&saveplayer($client)){ $outbuffer{$client}.="You have been saved\r\n$prompt"; } else { $outbuffer{$client}.="You have NOT been saved, something went wrong\r\n"; } } sub saveplayer { #does the actual saving of players my $client=(shift or $client); my $string; $string=Dumper($user{$client}); unless (open (PLAYER, ">players/$user{$client}{name}")){ $outbuffer{$client}.=" $! "; return 0; } print PLAYER $string; close PLAYER; foreach $a (%{$user{$client}{health}}){ foreach $b (%{$user{$client}{health}{$a}{wear}}) { if ($user{$client}{health}{$a}{wear}{$b}){ #save items. &saverealitem($user{$client}{health}{$a}{wear}{$b}); } } if ($user{$client}{health}{$a}{hold}){ &saverealitem($user{$client}{health}{$a}{hold}); } } return 1; } sub saveplayerold { #obsolete. ignore my $client=(shift or $client); local $string; foreach $a (keys %{$user{$client}}){ if ($a eq "eng"){ next; } descend($user{$client}{$a},$a); } unless (open (PLAYER, ">players/$user{$client}{name}")){ $outbuffer{$client}.="$!"; return 0; } print PLAYER $string; close PLAYER; foreach $a (%{$user{$client}{health}}){ foreach $b (%{$user{$client}{health}{$a}{wear}}) { if ($user{$client}{health}{$a}{wear}{$b}){ #save items. &saverealitem($user{$client}{health}{$a}{wear}{$b}); } } if ($user{$client}{health}{$a}{hold}){ &saverealitem($user{$client}{health}{$a}{hold}); } } return 1; } return 1;