procedure do_bash(ch:GCharacter;param:string); var chance:integer; vict:GCharacter; begin if (ch.learned[gsn_bash] = 0) then begin ch.sendBuffer('You don''t know how to bash!'#13#10); exit; end; if (length(param) = 0) and (ch.position <> POS_FIGHTING) then begin act(AT_REPORT,'Bash whom?',false,ch,nil,nil,TO_CHAR); exit; end; if (ch.position = POS_BASHED) then begin ch.sendBuffer('You are bashed and cannot move!'#13#10); exit; end; if (ch.bash_timer > -2) then begin act(AT_REPORT,'You are still too off-balance from that last bash.',false,ch,nil,nil,TO_CHAR); exit; end; if (ch.bashing > -2) then begin act(AT_REPORT,'You cannot bash this soon after a bash!',false,ch,nil,nil,TO_CHAR); exit; end; vict := ch.room.findChar(ch, param); if (vict = nil) then if (ch.position = POS_FIGHTING) and (ch.fighting <> nil) then vict := ch.fighting; if (vict = nil) then ch.sendBuffer('They aren''t here.'#13#10) else if not in_melee(ch,vict) then begin act(AT_REPORT,'You aren''t on the front lines of that battle!',false,ch,nil,nil,TO_CHAR); exit; end else if (vict = ch) then begin ch.sendBuffer('You try to bash yourself and fall to the ground!'#13#10); act(AT_REPORT,'$n looks silly as $e tries to bash $mself.',false,ch,nil,nil,TO_ROOM); end else if (vict.IS_NPC) and (IS_SET(vict.act_flags, ACT_SPIRIT) or IS_SET(vict.act_flags,ACT_NOBASH)) then ch.sendBuffer('You can''t bash that kind of creature!'#13#10) else with ch do begin if fighting=nil then begin if IS_SET(ch.room.flags,ROOM_SAFE) then begin ch.sendBuffer('A strange force prevents you from attacking.'#13#10); exit; end else begin fighting:=vict; if (not ch.IS_NPC) then player^.fightxp:=0; end; end; chance:=ch.learned[gsn_bash]; if (vict.bash_timer>0) then act(AT_REPORT,'$N is already bashed to the ground!',false,ch,nil,vict,TO_CHAR) else if (vict.bash_timer>-2) then act(AT_REPORT,'$N is still alert from the last bash.',false,ch,nil,vict,TO_CHAR) else if number_percent<=chance then begin improve_skill(ch,gsn_bash); vict.position:=POS_BASHED; position:=POS_FIGHTING; vict.bash_timer:=6; bashing:=6; if vict.fighting=nil then vict.fighting:=ch; act(AT_GREEN,'Your powerful bash sends $N sprawling to the ground!',false,ch,nil,vict,TO_CHAR); act(AT_GREEN,'$n sends $N sprawling to the ground with a powerful bash!',false,ch,nil,vict,TO_ROOM); end else begin ch.setWait(8); act(AT_REPORT,'You miss the bash and almost fall over!',false,ch,nil,nil,TO_CHAR); act(AT_REPORT,'$n misses a bash at $N and almost falls over!',false,ch,nil,vict,TO_ROOM); position:=POS_FIGHTING; vict.position:=POS_FIGHTING; if vict.fighting=nil then vict.fighting:=ch; end; end; end; procedure do_kick(ch:GCharacter;param:string); var dam,chance:integer; vict:GCharacter; begin if (ch.learned[gsn_kick] = 0) then begin ch.sendBuffer('You don''t know how to kick!'#13#10); exit; end; if (length(param)=0) and (ch.position<>POS_FIGHTING) then begin act(AT_REPORT,'Kick whom?',false,ch,nil,nil,TO_CHAR); exit; end; if (ch.position = POS_BASHED) then begin ch.sendBuffer('You are bashed and cannot move!'#13#10); exit; end; if (ch.bash_timer > -2) then begin act(AT_REPORT,'You are still too off-balance from that last bash.',false,ch,nil,nil,TO_CHAR); exit; end; if (ch.bashing > -2) then begin act(AT_REPORT,'You cannot kick this soon after a bash!',false,ch,nil,nil,TO_CHAR); exit; end; vict := ch.room.findChar(ch, param); if (vict = nil) then if (ch.position=POS_FIGHTING) and (ch.fighting<>nil) then vict:=ch.fighting; if (vict = nil) then act(AT_REPORT,'They aren''t here.',false,ch,nil,nil,TO_CHAR) else if not in_melee(ch,vict) then begin act(AT_REPORT,'You cannot reach $N!',false,ch,nil,vict,TO_CHAR); exit; end else if (vict = ch) then ch.sendBuffer('Painfully, you force your knee to bend in a way it isn''t supposed to.'#13#10) else with ch do begin if point.mv<12 then begin ch.sendBuffer('You don''t have enough energy to kick.'#13#10); exit; end; if (vict.CHAR_DIED) then exit; if fighting=nil then begin if IS_SET(ch.room.flags,ROOM_SAFE) then begin ch.sendBuffer('A strange force prevents you from attacking.'#13#10); exit; end else begin fighting:=vict; if (not ch.IS_NPC) then player^.fightxp:=0; end; end; ch.setWait(8); chance:=ch.learned[gsn_kick]; if (vict.IS_NPC) and (IS_SET(vict.act_flags,ACT_SPIRIT)) then begin ch.sendBuffer('You swing your leg and kick high, but it goes right through your victim!'#13#10); if vict.fighting=nil then vict.fighting:=ch; position:=POS_FIGHTING; vict.position:=POS_FIGHTING; end else if number_percent<=chance then begin improve_skill(ch,gsn_kick); dam:=urange(1,rolldice(4,18),level div 6)*3; inc(dam,ch.point.apb); dam:=(dam*ch.ability.str) div 50; damage(ch,ch.fighting,dam,gsn_kick); end else damage(ch,ch.fighting,0,gsn_kick); end; end; procedure do_fly(ch:GCharacter;param:string); begin if (ch.IS_FLYING) then ch.stopFlying else ch.startFlying; end; procedure do_sneak(ch:GCharacter;param:string); begin if IS_SET(ch.aff_flags,AFF_SNEAK) then begin ch.sendBuffer('You no longer sneak.'#13#10); REMOVE_BIT(ch.aff_flags,AFF_SNEAK); end else begin ch.sendBuffer('You attempt to move silently.'#13#10); SET_BIT(ch.aff_flags,AFF_SNEAK); end; end; procedure do_spells(ch:GCharacter;param:string); var a:integer; begin with ch do begin act(AT_REPORT,'Spells learned:'#13#10,false,ch,nil,nil,TO_CHAR); for a:=0 to MAX_SKILLS-1 do if learned[a]>0 then with skill_table[a] do if skill_type=SKILL_SPELL then act(AT_REPORT,pad_integer(min_mana,2)+'Ma '+name+' ('+inttostr(learned[a])+'%)',false,ch,nil,nil,TO_CHAR); end; end; procedure do_skills(ch:GCharacter;param:string); var a:integer; begin with ch do begin act(AT_REPORT,'Skills learned:'#13#10,false,ch,nil,nil,TO_CHAR); for a:=0 to MAX_SKILLS-1 do if learned[a]>0 then with skill_table[a] do if skill_type<>SKILL_SPELL then act(AT_REPORT,' '+name+' ('+inttostr(learned[a])+'%)',false,ch,nil,nil,TO_CHAR); end; end; procedure do_learn(ch:GCharacter;param:string); var sn:integer; node : GListNode; vict,learn:GCharacter; begin learn := nil; node := ch.room.chars.head; while (node <> nil) do begin vict := node.element; if (vict.IS_NPC) and (vict.IS_LEARNER) then begin learn := vict; break; end; node := node.next; end; if (learn=nil) then begin ch.sendBuffer('You cannot learn anything here!'#13#10); exit; end else if (length(param)=0) then begin ch.sendBuffer('Skills you can learn here:'#13#10#13#10); for sn := 0 to MAX_SKILLS - 1 do begin if (vict.learned[sn] > 0) and (ch.learned[sn] = 0) then act(AT_REPORT, ' (Level $B$4' + pad_integer_front(skill_table[sn].min_lvl, 3) + '$A$7) ' + skill_table[sn].name, false, ch, nil, nil, TO_CHAR); end; end else begin sn := findSkill(param); if (sn = -1) or (vict.learned[sn] = 0) then act(AT_REPORT, '$N doesn''t teach this skill.',false,ch,nil,vict,TO_CHAR) else begin if (ch.learned[sn] = 0) then begin if (skill_table[sn].min_lvl > ch.level) then ch.sendBuffer('You have not yet reached the appropiate level.'#13#10) else begin node := skill_table[sn].prereqs.head; while (node <> nil) do begin if (ch.learned[GSkill(node.element).sn] < 50) then begin ch.sendBuffer('You need to have sufficient knowledge of ' + GSkill(node.element).name + ' first.'#13#10); exit; end; node := node.next; end; act(AT_REPORT,'You learn '+cap(skill_table[sn].name)+'.',false,ch,nil,nil,TO_CHAR); ch.learned[sn]:=20; end; end else act(AT_REPORT,'You have already learned that skill.',false,ch,nil,nil,TO_CHAR); end; end; end; procedure do_unlearn(ch:GCharacter;param:string); var sn : integer; begin if (length(param) = 0) then begin ch.sendBuffer('UNLEARN <skill or spell to unlearn>'#13#10#13#10); ch.sendBuffer('This is irreversible, and you won''t get any practice sessions back.'#13#10); exit; end; sn := findSkill(param); if (sn = -1) or (ch.learned[sn] = 0) then act(AT_REPORT, 'You haven''t learned this skill.',false,ch,nil,nil,TO_CHAR) else begin ch.learned[sn] := 0; act(AT_REPORT, 'You have unlearned ' + skill_table[sn].name + '.', false, ch, nil, nil, TO_CHAR); end; end; procedure do_practice(ch:GCharacter;param:string); var sn:integer; vict,learn:GCharacter; node : GListNode; begin learn := nil; node := ch.room.chars.head; while (node <> nil) do begin vict := node.element; if (vict.IS_NPC) and (vict.IS_LEARNER) then begin learn := vict; break; end; node := node.next; end; if (learn=nil) then begin ch.sendBuffer('You cannot practice anything here!'#13#10); exit; end else if (length(param)=0) then begin ch.sendBuffer('Skills you can practice here:'#13#10#13#10); for sn := 0 to MAX_SKILLS - 1 do begin if (vict.learned[sn] > 0) then act(AT_REPORT, ' (Level $B$4' + pad_integer_front(skill_table[sn].min_lvl, 3) + '$A$7) ' + skill_table[sn].name, false, ch, nil, nil, TO_CHAR); end; end else begin sn := findSkillPlayer(ch,param); if (sn <> -1) then begin if (vict.learned[sn] = 0) then act(AT_REPORT, '$N doesn''t teach this skill.', false, ch, nil, vict, TO_CHAR) else if ch.learned[sn]<50 then begin inc(ch.learned[sn],8); if (ch.learned[sn]>50) then begin ch.learned[sn]:=50; act(AT_REPORT,'You now know enough about '+cap(skill_table[sn].name)+'.',false,ch,nil,nil,TO_CHAR); end else act(AT_REPORT,'You practice '+cap(skill_table[sn].name)+'.',false,ch,nil,nil,TO_CHAR); end else act(AT_REPORT,'You have practiced this skill enough.',false,ch,nil,nil,TO_CHAR); end else act(AT_REPORT,'You have not learned this skill!',false,ch,nil,nil,TO_CHAR); end; end; procedure search_timer(ch,victim:GCharacter;sn:integer); var pexit : GExit; node : GListNode; begin ch.position := POS_STANDING; if skill_success(ch,sn) then begin { check for hidden exits first } node := ch.room.exits.head; while (node <> nil) do begin pexit := node.element; if (IS_SET(pexit.flags, EX_SECRET)) and (IS_SET(pexit.flags, EX_ISDOOR)) then begin if (length(pexit.keywords^) > 0) then act(AT_REPORT,'You uncover a $d!',false,ch,nil,pexit,TO_CHAR) else act(AT_REPORT,'You uncover a secret passage '+headings[pexit.direction]+'!',false,ch,nil,nil,TO_CHAR); REMOVE_BIT(pexit.flags, EX_SECRET); exit; end; node := node.next; end; ch.sendBuffer('You look around, but find nothing.'#13#10); end else ch.sendBuffer('You look around, but find nothing.'#13#10); end; procedure do_search(ch:GCharacter;param:string); begin ch.sendBuffer('You start searching...'#13#10); act(AT_REPORT,'$n looks around, searching for something...',false,ch,nil,nil,TO_ROOM); ch.position := POS_SEARCHING; registerTimer(TIMER_SEARCH, search_timer, 6, ch, nil, gsn_searching); end; procedure backstab_timer(ch,victim:GCharacter;sn:integer); var roll,to_hit:integer; dam:integer; wield : GObject; begin if (victim.CHAR_DIED) or (victim.room <> ch.room) or (not ch.CAN_SEE(victim)) then begin ch.sendBuffer('They are not here.'#13#10); ch.position:=POS_STANDING; exit; end; wield := ch.getWield(ITEM_WEAPON); to_hit:=ch.point.hitroll + 10; { +10 bonus because of backstab } inc(to_hit,victim.point.ac); inc(to_hit,(ch.learned[sn]-50) div 5); roll:=rolldice(1,100); if (roll<=to_hit) and (wield<>nil) then begin dam:=URange(1,rolldice(wield.value[2],wield.value[3])*(2+ch.level div 15),350); act(AT_REPORT,'Your weapon finds its point in $N''s back, causing $S body to spasm.',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'Before you know what happens, $n places $s weapon in your back!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$n sneaks up behind $N''s back and places $s weapon into $S''s back.',false,ch,nil,victim,TO_NOTVICT); if (dam<=25) then begin act(AT_REPORT,'$N grimaces in pain as your blade pierces $S flesh.',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'You grimace in pain as $n''s blade pierces your flesh.',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$N grimaces in pain as $n''s blade pierces $S flesh.',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=50) then begin act(AT_REPORT,'$N winces in agony as you stab $M in the back.',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'You wince in agony as $n stabs you in the back.',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$N winces in agony as $n stabs $M in the back.',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=75) then begin act(AT_REPORT,'As you find a lung and pierce hard, $N cries out in pain!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'You cry out in pain as $n pierces your lung!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$N cries out in pain as $n pierces $S lung!',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=100) then begin act(AT_REPORT,'$N spasms in terrible pain as you plunge your blade into $M.',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'You feel a terrible pain as $n plunges $s blade into you!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$N spasms in terrible pain as $n plunges $s blade into $M.',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=150) then begin act(AT_REPORT,'Blood runs over your hands as you forcefully stab $N!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'You bleed hard as you are forcefully stabbed by $n!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'Blood runs over $n''s hands as $e forcefully stabs $N!',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=200) then begin act(AT_REPORT,'As you pierce $N''s back, you twist your weapon multiple times!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'$n pierces your back and twists $s blade multiple times!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$n pierces $N''s back and twists $s blade multiple times!',false,ch,nil,victim,TO_NOTVICT); end else if (dam<=350) then begin act(AT_REPORT,'You find a mark in $N''s spine and thrust your blade through!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'$n targets your spine and thrusts $s blade through!',false,ch,nil,victim,TO_VICT); act(AT_REPORT,'$n finds a mark in $N''s spine and thrusts $s blade through!',false,ch,nil,victim,TO_NOTVICT); end; damage(ch,victim,dam,sn); victim.fighting:=ch; end else begin act(AT_REPORT,'As you attempt to sneak behind $N''s back, you are uncovered!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'$n failed to backstab $N!', false,ch,nil,victim,TO_ROOM); damage(ch,victim,0,sn); victim.fighting:=ch; end; end; procedure do_backstab(ch:GCharacter;param:string); var victim:GCharacter; wield:GObject; begin if (ch.learned[gsn_backstab] = 0) then begin ch.sendBuffer('You don''t know how to backstab!'#13#10); exit; end; if (length(param)=0) then begin ch.sendBuffer('Backstab whom?'#13#10); exit; end; if (ch.position=POS_FIGHTING) then begin ch.sendBuffer('You cannot backstab while fighting!'#13#10); exit; end; victim := ch.room.findChar(ch, param); if (victim=nil) then begin ch.sendBuffer('They are not here.'#13#10); exit; end else if (victim=ch) then begin ch.sendBuffer('How would you sneak upon yourself?'#13#10); exit; end; wield := ch.getWield(ITEM_WEAPON); if (wield=nil) or not (wield.value[4] in [FG_PIERCE,FG_STAB]) then begin ch.sendBuffer('You must wield a piercing or stabbing weapon.'#13#10); exit; end; ch.sendBuffer('You move stealthily, attempting to get behind your target...'#13#10); registerTimer(TIMER_BACKSTAB, backstab_timer, 8, ch, victim, gsn_backstab); ch.position:=POS_BACKSTAB; end; procedure circle_timer(ch,victim:GCharacter;sn:integer); begin if (victim.CHAR_DIED) or (victim.room<>ch.room) then begin ch.sendBuffer('They are not here.'#13#10); ch.position:=POS_STANDING; exit; end; ch.position:=POS_FIGHTING; if (number_percent<=ch.learned[sn]) then begin act(AT_REPORT,'You succeed in circling your opponent and find yourself behind $M.',false,ch,nil,victim,TO_CHAR); backstab_timer(ch,victim,gsn_backstab); end else act(AT_REPORT,'You failed to circle.',false,ch,nil,nil,TO_CHAR); end; procedure do_circle(ch:GCharacter;param:string); var wield : GObject; begin if (ch.learned[gsn_circle] = 0) then begin ch.sendBuffer('You don''t know how to circle!'#13#10); exit; end; if (ch.position<>POS_FIGHTING) then begin ch.sendBuffer('You are not fighting!'#13#10); exit; end; if (ch.fighting.fighting=ch) then begin ch.sendBuffer('You are on the frontline and can not circle!'#13#10); exit; end; wield := ch.getWield(ITEM_WEAPON); if (wield=nil) or not (wield.value[4] in [FG_PIERCE,FG_STAB]) then begin ch.sendBuffer('You must wield a piercing or stabbing weapon.'#13#10); exit; end; act(AT_REPORT,'You attempt to circle behind your target...',false,ch,nil,nil,TO_CHAR); registerTimer(TIMER_CIRCLE, circle_timer, 10, ch, ch.fighting, gsn_circle); ch.position:=POS_CIRCLE; end; procedure do_rescue(ch:GCharacter;param:string); var victim:GCharacter; begin if (ch.learned[gsn_rescue] = 0) then begin ch.sendBuffer('You don''t know how to rescue!'#13#10); exit; end; if (length(param) = 0) then begin ch.sendBuffer('Rescue whom?'#13#10); exit; end; if (ch.position=POS_FIGHTING) and (ch.fighting.fighting=ch) then begin ch.sendBuffer('You are on the frontline and can not rescue!'#13#10); exit; end; victim := ch.room.findChar(ch, param); if (victim = nil) then begin ch.sendBuffer('That is not here!'#13#10); exit; end; if (number_percent <= ch.learned[gsn_rescue]) then begin act(AT_REPORT,'You rescue $N!',false,ch,nil,victim,TO_CHAR); act(AT_REPORT,'$N rescues you!',false,victim,nil,ch,TO_VICT); act(AT_REPORT,'$N rescues $n!',false,victim,nil,ch,TO_NOTVICT); if (ch.position <> POS_FIGHTING) then begin ch.fighting := victim.fighting; ch.position := POS_FIGHTING; end; ch.fighting.fighting := ch; victim.fighting := nil; victim.position := POS_STANDING; end else begin act(AT_REPORT,'Your rescue attempt failed.',false,ch,nil,nil,TO_CHAR); ch.setWait(3); end; end; procedure track_timer(ch,victim:GCharacter;sn:integer); var node : GListNode; track : GTrack; begin if (not skill_success(ch, gsn_track)) then begin ch.sendBuffer('You can''t seem to find any tracks.'#13#10); exit; end; node := ch.room.tracks.head; track := nil; while (node <> nil) do begin if (GTrack(node.element).who = ch.tracking) and ((track = nil) or (track.life < GTrack(node.element).life)) then track := node.element; node := node.next; end; if (track = nil) then begin if (victim = nil) then begin ch.sendBuffer('The tracks seem to end here.'#13#10); ch.tracking := ''; end else ch.sendBuffer('You can''t seem to find any tracks.'#13#10) end else begin ch.sendBuffer('You see some tracks heading ' + headings[track.direction] + '!'#13#10); end; end; procedure do_track(ch : GCharacter; param : string); var vict : GCharacter; begin vict := nil; if (ch.learned[gsn_track] = 0) then begin ch.sendBuffer('You don''t know how to track!'#13#10); exit; end; if (length(param) = 0) then begin if (ch.tracking = '') then begin ch.sendBuffer('Track whom?'#13#10); exit; end; end else begin vict := findCharWorld(ch, param); if (vict = ch) then begin ch.sendBuffer('You stop looking for tracks.'#13#10); ch.tracking := ''; exit; end; end; act(AT_REPORT,'You begin to look for tracks...',false,ch,nil,nil,TO_CHAR); if (vict <> nil) then ch.tracking := vict.name^; registerTimer(TIMER_TRACK, track_timer, 4, ch, vict, gsn_track); end;