unit skills; interface uses SysUtils, chars, dtypes, conns, util, constants; type SPEC_FUNC = procedure(ch, victim : GCharacter; sn : integer); GSkill = class func : SPEC_FUNC; affect : GAffect; prereqs : GDLinkedList; name : string; skill_type:integer; min_mana:integer; min_lvl:integer; beats:integer; target:integer; sn : integer; dicenum,dicesize,diceadd:integer; dam_msg,wear_msg:string; start_char,start_vict,start_room:string; hit_char,hit_vict,hit_room:string; miss_char,miss_vict,miss_room:string; die_char,die_vict,die_room:string; imm_char,imm_vict,imm_room:string; end; var skill_table : array[0..MAX_SKILLS-1] of GSkill; num_skills : integer; { gsn's } var gsn_slashing_weapons : integer; gsn_second_attack : integer; gsn_third_attack : integer; gsn_fourth_attack : integer; gsn_fifth_attack : integer; gsn_enhanced_damage : integer; gsn_dual_wield : integer; gsn_slashing : integer; gsn_piercing : integer; gsn_concussion : integer; gsn_whipping : integer; gsn_kick : integer; gsn_bash : integer; gsn_poison : integer; gsn_sneak : integer; gsn_swim : integer; gsn_searching : integer; gsn_backstab : integer; gsn_circle : integer; gsn_rescue : integer; gsn_dodge : integer; gsn_track : integer; gsn_peek : integer; gsn_hide : integer; procedure load_skills; procedure done_skills; function findSkill(s : string) : integer; function findSkillPlayer(ch : GCharacter; s : string) : integer; procedure improve_skill(ch : GCharacter; sn : integer); function skill_success(ch : GCharacter; sn : integer) : boolean; function findAffect(ch:GCharacter;sn:integer) : GAffect; procedure doAffect(ch:GCharacter;affect:GAffect); procedure removeAffect(ch : GCharacter; aff : GAffect); function removeAffectSkill(ch:GCharacter;gsn:integer):boolean; function removeAffectFlag(ch:GCharacter;flag:integer):boolean; procedure update_affects; implementation uses strip, magic, fight, mudsystem; function findSkill(s : string) : integer; var h, r : integer; begin s := uppercase(s); r := -1; for h := 0 to num_skills - 1 do if (s = uppercase(skill_table[h].name)) or (pos(s,uppercase(skill_table[h].name)) <> 0) then begin r := h; break; end; findSkill := r; end; function findSkillPlayer(ch : GCharacter; s : string) : integer; var h, r : integer; begin s := uppercase(s); r := -1; for h := 0 to num_skills - 1 do if (s = uppercase(skill_table[h].name)) or (pos(s,uppercase(skill_table[h].name)) <> 0) then begin r := h; break; end; if (r <> -1) and (ch.learned[r] = 0) then findSkillPlayer := -1 else findSkillPlayer := r; end; function assign_gsn(name : string) : integer; var gsn : integer; begin gsn := findSkill(name); if (gsn = -1) then bugreport('assign_gsn', 'skills.pas', 'skill '''+name+''' not found', 'The specified skill could not be found.'); assign_gsn := gsn; end; procedure process_affect(skill : GSkill; s : integer; format:string); begin skill.affect := GAffect.Create; with skill.affect do begin sn:=s; aff_type:=upcase(format[1]); format:=striprbeg(format,' '); modifier:=strtoint(stripl(format,' ')); format:=striprbeg(format,' '); duration:=strtoint(stripl(format,' ')); format:=striprbeg(format,' '); aff_flag:=strtoint(stripl(format,' ')); end; end; procedure load_skills; var f:textfile; s,g,a:string; h:integer; skill : GSkill; begin assignfile(f, 'system\skills.dat'); {$I-} reset(f); {$I+} if (IOResult <> 0) then begin bugreport('load_skills', 'skills.pas', 'could not open system\skills.dat', 'The system file skills.dat could not be opened.'); exit; end; FillChar(skill_table, sizeof(skill_table), 0); num_skills := 0; repeat repeat readln(f,s); until (uppercase(s) = '#SKILL') or (eof(f)); if (eof(f)) then break; skill := GSkill.Create; skill.affect := nil; skill.prereqs := GDLinkedList.Create; skill.sn := num_skills; with skill do repeat readln(f, s); g := uppercase(stripl(s,':')); if (g = 'TYPE') then begin s := uppercase(striprbeg(s,' ')); if (s = 'SPELL') then skill_type := SKILL_SPELL else if (s = 'SKILL') then skill_type := SKILL_SKILL else if (s = 'WEAPON') then skill_type := SKILL_WEAPON; end else if (g = 'NAME') then name := striprbeg(s,' ') else if g='ROUNDS' then beats:=strtoint(striprbeg(s,' ')) else if g='MINLEVEL' then min_lvl:=strtoint(striprbeg(s,' ')) else if g='MANA' then min_mana:=strtoint(striprbeg(s,' ')) else if g='TARGET' then target:=strtoint(striprbeg(s,' ')) else if g='FUNCTION' then func := findFunc(striprbeg(s,' ')) else if g='STARTCHAR' then start_char := striprbeg(s,' ') else if g='STARTVICT' then start_vict := striprbeg(s,' ') else if g='STARTROOM' then start_room := striprbeg(s,' ') else if g='HITCHAR' then hit_char := striprbeg(s,' ') else if g='HITVICT' then hit_vict := striprbeg(s,' ') else if g='HITROOM' then hit_room := striprbeg(s,' ') else if g='MISSCHAR' then miss_char := striprbeg(s,' ') else if g='MISSVICT' then miss_vict := striprbeg(s,' ') else if g='MISSROOM' then miss_room := striprbeg(s,' ') else if g='DAMMSG' then dam_msg := striprbeg(s,' ') else if g='WEAROFF' then wear_msg := striprbeg(s,' ') else if g='DICE' then begin a:=uppercase(striprbeg(s,' ')); dicenum:=strtoint(stripl(a,'D')); a:=striprbeg(a,'D'); dicesize:=strtoint(stripl(a,'+')); a:=striprbeg(a,'+'); diceadd:=strtoint(stripl(a,' ')); end else if g='AFFECTS' then process_affect(skill, num_skills, striprbeg(s,' ')) else if g='PREREQ' then begin a := striprbeg(s, ' '); h := findSkill(a); if (h >= 0) then prereqs.insertLast(skill_table[h]) else bugreport('load_skills', 'skills.pas', 'Could not find prereq skill ' + a, 'The specified skill could not be found.'); end; until uppercase(s)='#END'; skill_table[num_skills] := skill; inc(num_skills); until eof(f); closefile(f); gsn_second_attack := assign_gsn('second attack'); gsn_third_attack := assign_gsn('third attack'); gsn_fourth_attack := assign_gsn('fourth attack'); gsn_fifth_attack := assign_gsn('fifth attack'); gsn_enhanced_damage := assign_gsn('enhanced damage'); gsn_dual_wield := assign_gsn('dual wield'); gsn_slashing := assign_gsn('slashing weapons'); gsn_piercing := assign_gsn('piercing weapons'); gsn_concussion := assign_gsn('concussion weapons'); gsn_whipping := assign_gsn('whipping weapons'); gsn_kick := assign_gsn('kick'); gsn_bash := assign_gsn('bash'); gsn_poison := assign_gsn('poison'); gsn_sneak := assign_gsn('sneaking'); gsn_swim := assign_gsn('swim'); gsn_searching := assign_gsn('searching'); gsn_backstab := assign_gsn('backstab'); gsn_circle := assign_gsn('circle'); gsn_rescue := assign_gsn('rescue'); gsn_dodge := assign_gsn('dodge'); gsn_track := assign_gsn('track'); gsn_peek := assign_gsn('peek'); gsn_hide := assign_gsn('hide'); end; procedure done_skills; var a : integer; begin for a := 0 to num_skills - 1 do begin skill_table[a].Free; end; end; procedure improve_skill(ch : GCharacter; sn : integer); var chance, percent : integer; begin if (ch.learned[sn] = 100) then exit; chance := ch.learned[sn] - (ch.ability.wis div 5); percent := number_percent; if (percent <= chance div 3) then begin act(AT_WHITE, '[You have become better at '+skill_table[sn].name+'!]',false,ch,nil,nil,TO_CHAR); ch.learned[sn] := UMAX(ch.learned[sn]+1,100); end; end; function skill_success(ch : GCharacter; sn : integer) : boolean; begin skill_success := (number_percent <= ch.learned[sn]); end; function findAffect(ch:GCharacter;sn:integer) : GAffect; var node : GListNode; aff : GAffect; begin findAffect := nil; node := ch.affects.head; while (node <> nil) do begin aff := node.element; if (aff.sn = sn) then begin findAffect := aff; exit; end; node := node.next; end; end; procedure doAffect(ch:GCharacter;affect:GAffect); var aff : GAffect; node : GListNode; begin if (affect = nil) then exit; with ch do { first check if the damn affect doesn't exist already } begin aff := findAffect(ch,affect.sn); if (aff <> nil) then begin aff.duration := affect.duration; {reset duration } exit; end; aff := GAffect.Create; aff.sn := affect.sn; aff.aff_type := affect.aff_type; aff.aff_flag := affect.aff_flag; aff.duration := affect.duration; aff.modifier := affect.modifier; if (aff.duration > 0) then begin SET_BIT(ch.aff_flags, affect.aff_flag); aff.node := ch.affects.insertLast(aff); end; with aff do case aff_type of 'H':inc(ch.point.max_hp, modifier); 'M':inc(ch.point.max_mv, modifier); 'N':inc(ch.point.max_mana, modifier); 'S':inc(ch.ability.str, modifier); 'C':inc(ch.ability.con, modifier); 'D':inc(ch.ability.dex, modifier); 'I':inc(ch.ability.int, modifier); 'W':inc(ch.ability.wis, modifier); 'F':ch.startFlying; 'A':begin inc(ch.point.ac_mod,modifier); ch.calcAC; end; end; end; end; procedure removeAffect(ch : GCharacter; aff : GAffect); begin with aff do begin REMOVE_BIT(ch.aff_flags,aff_flag); case aff_type of 'H':dec(ch.point.max_hp, modifier); 'M':dec(ch.point.max_mv, modifier); 'N':dec(ch.point.max_mana, modifier); 'S':dec(ch.ability.str, modifier); 'C':dec(ch.ability.con, modifier); 'D':dec(ch.ability.dex, modifier); 'I':dec(ch.ability.int, modifier); 'W':dec(ch.ability.wis, modifier); 'F':ch.stopFlying; 'A':begin dec(ch.point.ac_mod,modifier); ch.calcAc; end; end; end; ch.affects.remove(aff.node); aff.Free; end; function removeAffectSkill(ch:GCharacter;gsn:integer):boolean; var aff : GAffect; begin aff := findAffect(ch,gsn); if (aff = nil) then begin bugreport('removeAffectSkill', 'skills.pas', 'skill number null, ch ' + ch.name^, 'An attempt was made to remove an unexisting affect.'); exit; end; removeAffect(ch, aff); removeAffectSkill := true; end; function removeAffectFlag(ch:GCharacter;flag:integer):boolean; var node : GListNode; aff : GAffect; begin removeAffectFlag := false; aff := nil; node := ch.affects.head; while (node <> nil) do begin if (GAffect(node.element).aff_flag = flag) then begin aff := node.element; break; end; node := node.next; end; if (aff = nil) then exit; removeAffect(ch, aff); removeAffectFlag := true; end; procedure update_affects; var i : integer; ch : GCharacter; node, node_aff : GListNode; aff : GAffect; begin node := char_list.head; while (node <> nil) do begin ch := node.element; if IS_SET(ch.aff_flags,AFF_POISON) then begin act(AT_REPORT,'You shiver and suffer.',false,ch,nil,nil,TO_CHAR); act(AT_REPORT,'$n shivers and suffers.',false,ch,nil,nil,TO_ROOM); ch.mental_state:=URANGE(20,ch.mental_state+4,100); damage(ch,ch,6,gsn_poison); end; { if IS_SET(ch.aff_flags,AFF_COLD) then begin i:=random(5); case i of 1:begin act(AT_REPORT,'You sneeze loudly... do you need a tissue?',false,ch,nil,nil,TO_CHAR); act(AT_REPORT,'$n sneezes loudly... maybe $e needs a tissue?',false,ch,nil,nil,TO_ROOM); end; 2:begin act(AT_REPORT,'You sniff a bit.',false,ch,nil,nil,TO_CHAR); act(AT_REPORT,'$n sniffs a bit.',false,ch,nil,nil,TO_ROOM); end; 3:begin act(AT_REPORT,'You don''t feel very well.',false,ch,nil,nil,TO_CHAR); act(AT_REPORT,'$n doesn''t look very well.',false,ch,nil,nil,TO_ROOM); ch.mental_state:=URANGE(20,ch.mental_state+1,100); end; end; end; } node_aff := ch.affects.head; while (node_aff <> nil) do begin aff := node_aff.element; dec(aff.duration); if (aff.duration = 0) then begin act(AT_REPORT, skill_table[aff.sn].wear_msg,false,ch,nil,nil,TO_CHAR); removeAffect(ch, aff); end; node_aff := node_aff.next; end; node := node.next; end; end; end.