📄 skills.pas
字号:
unit Skills;
(*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
Skills
2004/05/31 ChrstphrR
(Original code moved from Main, and other units, from various coders from
Weiss, EWeiss, Fusion.
I won't dare take credit for anything but reorganizing things so they're
saner to look at.)
--
Overview:
--
Routines that affect skills needed a proper home ... Main.pas should REALLY just
be code that affects some of the startup, shutdown, and Form events. Separating
out some of this code from it will make tracking down both types of routines
easier.
--
Revisions:
--
v0.1 2004/05/31
2004/05/31 [ChrstphrR] - Initial Unit creation
"/05/31 [ChrstphrR] - Import of SkillEffect
"/06/02 [DarkHelmet] - Reorder case statements numerically (partially done)
"/06/02 [DarkHelmet] - CODE-ERROR comments added for future fixes
"/06/03 [ChrstphrR] - Added link to Skill_Constants.pas
"/06/03 [ChrstphrR] - Added FindTargetsInAttackRange to replace some of the
code that DH mentioned - will evolve into a more general routine.
"/06/03 [ChrstphrR] - Some Memory leak fixes in SkillEffect
"/06/03 [Darkhelmet] - Organized all except the platinum skills in player vs monster
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*)
interface
uses
{Delphi VCL Units}
Windows, Classes,
{Fusion Units}
Common, Skill_Constants, Player_Skills, Globals,
{3rd Party Units}
List32;
Procedure SkillEffect(
tc : TChara;
Tick : Cardinal;
UseSP : Boolean = True
);
Procedure FindTargetsInAttackRange(
TrgtList : TIntList32;
SData : TSkillDB;
Chara : TChara;
TrgtPt : TPoint;
Target : TLiving; //May be NIL
TargetChk : Byte
);
const
//TargetChk Constants for FindTargetsInAttackRange()
CHK_NONE = 0; // No Other Checks Needed
CHK_SELF = 1; // Ensure TargetList doesn't include Chara
CHK_TARGET = 2; // Ensure TargetList doesn't include Primary Target
CHK_GUARD = 3; // Ensure TargetList doesn't include GuildGuardians
CHK_GUILD = 4; // Ensure TargetList doesn't include GuildMembers
implementation
uses
SysUtils,
Main, Path;
(*-----------------------------------------------------------------------------*
SkillEffect()
Overview:
Erm... I just imported it! >.< ... it's nearly 6000 lines long, gimme a break!
I mean... an overview of what this routine does will be forthcoming.
This is a Weiss era routine.
Plan of attack for changes:
- Import into new unit to reduce clutter in Main.Pas (and DL time from CVS)
- consistantly format using tabs for indents (you can set them to what you
prefer for your indent style off of the Properties... menu choice when you
right-click the source.
- remove variables that are unused outright
- pick out candidate code to reduce this from a 6000 line function to a few
hundred lines. This unit WILL be refactored.
Pre:
Unknown
Post:
Unknown
Revisions:
2004/04/27 [ChrstphrR] Memory Leak Fixes
"/05/31 [ChrstphrR] Imported into Skills unit from Main.pas
"/06/02 [DarkHelmet] CODE-ERROR comments where further work is needed
"/06/02 [DarkHelmet] Partial reorder of case statements by number --
Skills grouped and marked by Job (Swordsman, Mage, Thief, etc)
*-----------------------------------------------------------------------------*)
Procedure SkillEffect(
tc : TChara;
Tick : Cardinal;
UseSP : Boolean = True
);
Var
j,k,m,b : Integer;
i : Integer;
L : integer;
i1,j1,k1 :integer;
tm :TMap;
mi :MapTbl;
tc1 :TChara;
tc2 :TChara;
ts :TMob;
ts1 :TMob;
td :TItemDB;
tg :TGuild;
tl :TSkillDB;
xy :TPoint;
bb :array of byte;
tpa :TParty;
sl :TStringList;
ma :TMArrowDB;
tma :TMaterialDB;
ProcessType :Byte;
DamageProcessed :boolean;
tn :TNPC;
//CR - 2004/06/03
MonsterList : TIntList32;
//Used to store list of Monsters in an area skill (i.e. splash damage)
Begin
// Alex: This should not be preset. Depending on certain skill failure
// such as I encountered with "Steal" this will cause the skill effect
// to go through even when the skill fails. I'm not sure which skills need
// this, but it should be declared in the skill section, not out here.
ProcessType := 99;
if tc.Skill[269].Tick > Tick then begin //Check if BladeStop is active
case tc.Skill[269].Effect1 of
1: Exit;
2: if tc.MSkill <> 267 then exit;
3: if ((tc.MSkill <> 267) and (tc.MSkill <> 266)) then exit;
4: if ((tc.MSkill <> 267) and (tc.MSkill <> 266) and (tc.MSkill <> 273)) then exit;
5: if ((tc.MSkill <> 267) and (tc.MSkill <> 266) and (tc.MSkill <> 273) and (tc.MSkill <> 271)) then exit;
end;//case -- all exits here are safe 2004/04/27
end;
if tc.isSilenced then begin
SilenceCharacter(tm, tc, Tick);
Exit;//safe 2004/04/27
end;
{ChrstphrR 2004/04/26 -- moved this away from the first Exit calls.}
sl := TStringList.Create;
with tc do begin
//Set the map data From the players map data
tm := MData;
tL := Skill[MSkill].Data;
if Mapinfo.IndexOf(tm.Name) <> -1 then
mi := MapInfo.Objects[MapInfo.IndexOf(tm.Name)] as MapTbl
else exit; //safe exit if map isn't found in mapinfo
{ Alex: Holy Shit, here we go. This needs to be
called before any tests for target type are made
the reason being that one skill function should
be used for both types of targets.
- Placed here after all declarations for safety. }
parse_skills(tc, Tick, 0, UseSP);
if MTargetType = 0 then begin //Target is a monster
ts := tc.AData;
if tL = NIL then begin
sl.Free;
Exit;//safe 2004/04/26
end;
if (ts is TMob) and (PassiveAttack = false) then begin // Edited by AlexKreuz
if ts.isEmperium then begin
j := GuildList.IndexOf(tc.GuildID);
if (j <> -1) then begin
tg := GuildList.Objects[j] as TGuild;
if ((tg.GSkill[10000].Lv < 1) or ((ts.GID = tc.GuildID) and (tc.GuildID <> 0))) then begin
MSkill := 0;
MUseLv := 0;
MMode := 0;
MTarget := 0;
sl.Free;
Exit;//safe 2004/04/26
end;
end;
end;
if ((ts.isGuardian = tc.GuildID) and (tc.GuildID <> 0)) then begin //added by The Harbinger -- darkWeiss version
MSkill := 0;
MUseLv := 0;
MMode := 0;
MTarget := 0;
sl.Free;
Exit;//safe 2004/04/26
end;
end;
if (ts = nil) or (ts.HP = 0) and (PassiveAttack = False) then begin
MSkill := 0;
MUseLv := 0;
MMode := 0;
MTarget := 0;
sl.Free;
Exit;//safe 2004/04/26
end;
//If Monster is in range of the skill
if (abs(tc.Point.X - ts.Point.X) <= tl.Range) and (abs(tc.Point.Y - ts.Point.Y) <= tl.Range) then begin
case MSkill of {Skill Used Against Monster}
//June 02, 2004 - Darkhelmet, I'm going to begin cleaning and organizing all these skills,
//wish me luck!
8: //僀儞僨儏傾
begin
tc1 := tc;
ProcessType := 2;
end;
{Mage Skills Player vs Monster Begin}
15: {Frost Driver}
begin
//Magic Attack Damage Calculation
dmg[0] := MATK1 + Random(MATK2 - MATK1 + 1) * MATKFix div 100 * ( MUseLV + 100 ) div 100;
dmg[0] := dmg[0] * (100 - ts.Data.MDEF) div 100; //MDEF%
dmg[0] := dmg[0] - ts.Data.Param[3]; //MDEF-
if dmg[0] < 1 then
dmg[0] := 1;
dmg[0] := dmg[0] * ElementTable[tl.Element][ts.Element] div 100;
if dmg[0] < 0 then
dmg[0] := 0; //杺朄峌寕偱偺夞暅偼枹幚憰
if (ts.EffectTick[0] > Tick) then dmg[0] := dmg[0] * 2;
//Send Attacking Packets
SendCSkillAtk1(tm, tc, ts, Tick, dmg[0], 1);
//Freezing Chance
if (ts.Data.race <> 1) and (ts.Data.MEXP = 0) and (dmg[0] <> 0)then begin
if Random(1000) < tl.Data1[MUseLV] * 10 then begin
ts.nStat := 2;
ts.BodyTick := Tick + tc.aMotion;
end;
end;
frmMain.DamageProcess1(tm, tc, ts, dmg[0], Tick, False);
tc.MTick := Tick + 1500;
end;
16: {Stone Curse}
begin
j := SearchCInventory(tc, 716, false);
if ((j <> 0) and (tc.Item[j].Amount >= 1)) or (NoJamstone) then begin
//Use the Item
if NOT NoJamstone then begin
UseItem(tc, j);
end;
//Send Graphic Packet
WFIFOW( 0, $011a);
WFIFOW( 2, MSkill);
WFIFOW( 4, dmg[0]);
WFIFOL( 6, MTarget);
WFIFOL(10, ID);
WFIFOB(14, 1);
SendBCmd(tm, ts.Point, 15);
if Random(1000) < tl.Data1[MUseLV] * 10 then begin
if (ts.Stat1 <> 1) then begin
ts.nStat := 1;
ts.BodyTick := Tick + tc.aMotion;
end;
end;
end else begin
SendSkillError(tc, 7); //No Red Gemstone
tc.MMode := 4;
tc.MPoint.X := 0;
tc.MPoint.Y := 0;
Exit;
end;
end;
MG_FIREBALL: //17 Fire Ball
begin
//XY is the targeting point.
xy := ts.Point;
MonsterList := TIntList32.Create;
try
FindTargetsInAttackRange(MonsterList,tl,tc,xy,ts,CHK_NONE);
if MonsterList.Count > 0 then begin
//For each monster, calculate damage inflicted.
for k1 := 0 to MonsterList.Count -1 do begin
ts1 := MonsterList.Objects[k1] AS TMob;
dmg[0] := MATK1 + Random(MATK2 - MATK1 + 1) * MATKFix div 100 * tl.Data1[MUseLV] div 100;
dmg[0] := dmg[0] * (100 - ts1.Data.MDEF) div 100; //MDEF%
dmg[0] := dmg[0] - ts1.Data.Param[3]; //Account for monsters MDEF
if dmg[0] < 1 then dmg[0] := 1;
dmg[0] := dmg[0] * ElementTable[tl.Element][ts1.Element] div 100;
dmg[0] := dmg[0] * tl.Data2[MUseLV];
if dmg[0] < 0 then dmg[0] := 0; //Prevent negative damage
if (ts1.EffectTick[0] > Tick) then dmg[0] := dmg[0] * 2;
if ts = ts1 then begin
k := 0;
end else begin
k := 5;
end;
//Send Attack Packets
SendCSkillAtk1(tm, tc, ts1, Tick, dmg[0], tl.Data2[MUseLV], k);
//Damage the monster
frmMain.DamageProcess1(tm, tc, ts1, dmg[0], Tick);
end;
end;
finally
MonsterList.Free;
end;
tc.MTick := Tick + 1600;
end;//17 MG_FIREBALL
{Mage Skills Player vs Monster end}
{Alcolyte Skills Player vs monster begin}
28: {Heal}
begin
if (ts.HP > 0) then begin
//Check If Undead
if (ts.Data.Race = 1) or (ts.Element mod 20 = 9) then begin
//Damage Calculation
dmg[0] := ((BaseLV + Param[3]) div 8) * tl.Data1[MUseLV] * ElementTable[6][ts.Element] div 200;
if dmg[0] < 0 then dmg[0] := 0; //杺朄峌寕偱偺夞暅偼枹幚憰
if (ts.EffectTick[0] > Tick) then dmg[0] := dmg[0] * 2;
SendCSkillAtk1(tm, tc, ts, Tick, dmg[0], 1);
frmMain.DamageProcess1(tm, tc, ts, dmg[0], Tick);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -