Skip to content

Commit

Permalink
Merge branch 'master' into Fix_homun_state
Browse files Browse the repository at this point in the history
  • Loading branch information
Henrybk authored Dec 26, 2024
2 parents d158e0f + 6a1c6a2 commit 7960b3d
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 40 deletions.
17 changes: 12 additions & 5 deletions src/AI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,19 @@ sub ai_skillUse {
delete $args{target};
}

if ($char->{skills}{$args{skillHandle}}{lv} < $args{lv}) {
debug "Attempted to use skill (".$args{skillHandle}.") level ".$args{lv}." which you do not have, adjusting to level ".$char->{skills}{$args{skillHandle}}{lv}.".\n", "ai";
$args{lv} = $char->{skills}{$args{skillHandle}}{lv};
my $skill = Skill->new(auto => $args{skillHandle});
my $owner = $skill->getOwner();
my $lvl = $owner->getSkillLevel($skill);
if ($lvl < $args{lv}) {
debug "[$owner] Attempted to use skill (".$args{skillHandle}.") level ".$args{lv}." which you do not have, adjusting to level ".$lvl.".\n", "ai";
$args{lv} = $lvl;
}

if ($skill->getOwnerType == Skill::OWNER_CHAR) {
AI::queue("skill_use", \%args);
} else {
$owner->queue("skill_use", \%args);
}

AI::queue("skill_use", \%args);
}

##
Expand Down
5 changes: 4 additions & 1 deletion src/AI/CoreLogic.pm
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,10 @@ sub processSkillUse {

# Give an error if we don't actually possess this skill
my $skill = new Skill(handle => $handle);
if ($char->{skills}{$handle}{lv} <= 0 && (!$char->{permitSkill} || $char->{permitSkill}->getHandle() ne $handle)) {
my $owner = $skill->getOwner();
my $lvl = $owner->getSkillLevel($skill);

if ($lvl <= 0 && (!$char->{permitSkill} || $char->{permitSkill}->getHandle() ne $handle)) {
debug "Attempted to use skill (".$skill->getName().") which you do not have.\n";
}

Expand Down
112 changes: 112 additions & 0 deletions src/AI/Slave.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ use constant MAX_DISTANCE => 17;

sub checkSkillOwnership {}

sub getSkillLevel {
my ($self, $skill) = @_;
my $handle = $skill->getHandle();
if ($self->{skills}{$handle}) {
return $self->{skills}{$handle}{lv};
} else {
return 0;
}
}

sub action {
my $slave = shift;

Expand Down Expand Up @@ -161,6 +171,7 @@ sub iterate {
##### MANUAL AI STARTS HERE #####

AI::SlaveAttack::process($slave);
$slave->processSkillUse;
$slave->processTask('route', onError => sub {
my ($task, $error) = @_;
if (!($task->isa('Task::MapRoute') && $error->{code} == Task::MapRoute::TOO_MUCH_TIME())
Expand Down Expand Up @@ -512,6 +523,107 @@ sub processAutoAttack {
#Benchmark::end("ai_homunculus_autoAttack") if DEBUG;
}

##### SKILL USE #####
sub processSkillUse {
my ($slave) = @_;

#FIXME: need to move closer before using skill on player,
#there might be line of sight problem too
#or the player disappers from the area

if ($slave->action eq "skill_use" && $slave->args->{suspended}) {
$slave->args->{giveup}{time} += time - $slave->args->{suspended};
$slave->args->{minCastTime}{time} += time - $slave->args->{suspended};
$slave->args->{maxCastTime}{time} += time - $slave->args->{suspended};
delete $slave->args->{suspended};
}

SKILL_USE: {
last SKILL_USE if ($slave->action ne "skill_use");
my $args = $slave->args;

if ($args->{monsterID} && $skillsArea{$args->{skillHandle}} == 2) {
delete $args->{monsterID};
}

if (timeOut($args->{waitBeforeUse})) {
if (defined $args->{monsterID} && !defined $monsters{$args->{monsterID}}) {
# This skill is supposed to be used for attacking a monster, but that monster has died
$slave->dequeue;
${$args->{ret}} = 'target gone' if ($args->{ret});

# Use skill if we haven't done so yet
} elsif (!$args->{skill_used}) {
#if ($slave->{last_skill_used_is_continuous}) {
# message T("Stoping rolling\n");
# $messageSender->sendStopSkillUse($slave->{last_continuous_skill_used});
#} elsif(($slave->{last_skill_used} == 2027 || $slave->{last_skill_used} == 147) && !$slave->{selected_craft}) {
# message T("No use skill due to not select the craft / poison\n");
# last SKILL_USE;
#}
my $handle = $args->{skillHandle};
if (!defined $args->{skillID}) {
my $skill = new Skill(handle => $handle);
$args->{skillID} = $skill->getIDN();
}
my $skillID = $args->{skillID};

$args->{skill_used} = 1;
$args->{giveup}{time} = time;

# Stop attacking, otherwise skill use might fail
my $attackIndex = $slave->findAction("attack");
if (defined($attackIndex) && $slave->args($attackIndex)->{attackMethod}{type} eq "weapon") {
# 2005-01-24 pmak: Commenting this out since it may
# be causing bot to attack slowly when a buff runs
# out.
#$slave->stopAttack();
}

# Give an error if we don't actually possess this skill
my $skill = new Skill(handle => $handle);
my $owner = $skill->getOwner();
my $lvl = $owner->getSkillLevel($skill);

if ($lvl <= 0) {
debug "Attempted to use skill (".$skill->getName().") which you do not have.\n";
}

$args->{maxCastTime}{time} = time;
if ($skillsArea{$handle} == 2) {
$messageSender->sendSkillUse($skillID, $args->{lv}, $accountID);
} elsif ($args->{x} ne "") {
$messageSender->sendSkillUseLoc($skillID, $args->{lv}, $args->{x}, $args->{y});
} elsif ($args->{isStartSkill}) {
$messageSender->sendStartSkillUse($skillID, $args->{lv}, $args->{target});
} else {
$messageSender->sendSkillUse($skillID, $args->{lv}, $args->{target});
}
$args->{skill_use_last} = $slave->{skills}{$handle}{time_used};

delete $slave->{cast_cancelled};

} elsif (timeOut($args->{minCastTime})) {
if ($args->{skill_use_last} != $slave->{skills}{$args->{skillHandle}}{time_used}) {
$slave->dequeue;
${$args->{ret}} = 'ok' if ($args->{ret});

} elsif ($slave->{cast_cancelled} > $slave->{time_cast}) {
$slave->dequeue;
${$args->{ret}} = 'cancelled' if ($args->{ret});

} elsif (timeOut($slave->{time_cast}, $slave->{time_cast_wait} + 0.5)
&& ( (timeOut($slave->{giveup}) && (!$slave->{time_cast} || !$args->{maxCastTime}{timeout}) )
|| ( $args->{maxCastTime}{timeout} && timeOut($args->{maxCastTime})) )
) {
$slave->dequeue;
${$args->{ret}} = 'timeout' if ($args->{ret});
}
}
}
}
}

sub sendAttack {
my ($slave, $targetID) = @_;
$messageSender->sendSlaveAttack ($slave->{ID}, $targetID);
Expand Down
1 change: 1 addition & 0 deletions src/AI/SlaveManager.pm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ sub addSlave {
$actor->{slave_ai_seq} = [];
$actor->{slave_ai_seq_args} = [];
$actor->{slave_skillsID} = [];
$actor->{skills} = {};
$actor->{slave_AI} = AI::AUTO;

if ($actor->isa("Actor::Slave::Homunculus")) {
Expand Down
2 changes: 2 additions & 0 deletions src/Actor/You.pm
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ sub nameString {
return T('You');
}

sub checkSkillOwnership { $_[1]->getOwnerType == Skill::OWNER_CHAR }

##
# int $char->getSkillLevel(Skill skill)
# Ensures: result >= 0
Expand Down
10 changes: 6 additions & 4 deletions src/Commands.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3106,10 +3106,12 @@ sub cmdSlave {
T(" # Skill Name Lv SP\n");
foreach my $handle (@{$slave->{slave_skillsID}}) {
my $skill = new Skill(handle => $handle);
my $sp = $char->{skills}{$handle}{sp} || '';
$msg .= swrite(
"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>> @>>>",
[$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
if ($slave->checkSkillOwnership($skill)) {
my $sp = $slave->{skills}{$handle}{sp} || '';
$msg .= swrite(
"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>> @>>>",
[$skill->getIDN(), $skill->getName(), $slave->getSkillLevel($skill), $sp]);
}
}
$msg .= TF("\nSkill Points: %d\n", $slave->{points_skill}) if defined $slave->{points_skill};
$msg .= ('-'x46) . "\n";
Expand Down
24 changes: 16 additions & 8 deletions src/Misc.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4751,14 +4751,22 @@ sub checkSelfCondition {
# check skill use SP if this is a 'use skill' condition
if ($prefix =~ /skill|attackComboSlot/i) {
my $skill = Skill->new(auto => $config{$prefix});
return 0 unless ($char->getSkillLevel($skill)
|| $config{$prefix."_equip_leftAccessory"}
|| $config{$prefix."_equip_rightAccessory"}
|| $config{$prefix."_equip_leftHand"}
|| $config{$prefix."_equip_rightHand"}
|| $config{$prefix."_equip_robe"}
);
return 0 unless ($char->{sp} >= $skill->getSP($config{$prefix . "_lvl"} || $char->getSkillLevel($skill)));
if ($char->checkSkillOwnership ($skill)) {
return 0 unless ($char->getSkillLevel($skill)
|| $config{$prefix."_equip_leftAccessory"}
|| $config{$prefix."_equip_rightAccessory"}
|| $config{$prefix."_equip_leftHand"}
|| $config{$prefix."_equip_rightHand"}
|| $config{$prefix."_equip_robe"}
);
return 0 unless ($char->{sp} >= $skill->getSP($config{$prefix . "_lvl"} || $char->getSkillLevel($skill)));

} elsif ($has_homunculus && $char->{homunculus}->checkSkillOwnership($skill)) {
return 0 unless ($char->{homunculus}->getSkillLevel($skill));

} elsif ($has_mercenary && $char->{mercenary}->checkSkillOwnership($skill)) {
return 0 unless ($char->{mercenary}->getSkillLevel($skill));
}
}

if (defined $config{$prefix . "_skill"}) {
Expand Down
54 changes: 34 additions & 20 deletions src/Network/Receive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9314,26 +9314,33 @@ sub skills_list {
# TODO: per-actor, if needed at all
# Skill::DynamicInfo::clear;
my ($ownerType, $hook, $actor) = @{{
'010F' => [Skill::OWNER_CHAR, 'packet_charSkills'],
'010F' => [Skill::OWNER_CHAR, 'packet_charSkills', $char],
'0235' => [Skill::OWNER_HOMUN, 'packet_homunSkills', $char->{homunculus}],
'029D' => [Skill::OWNER_MERC, 'packet_mercSkills', $char->{mercenary}],
'0B32' => [Skill::OWNER_CHAR, 'packet_charSkills'],
'0B32' => [Skill::OWNER_CHAR, 'packet_charSkills', $char],
}->{$args->{switch}}};

my $skillsIDref = $actor ? \@{$actor->{slave_skillsID}} : \@skillsID;
delete @{$char->{skills}}{@$skillsIDref};
my $skillsIDref;
if ($ownerType == Skill::OWNER_CHAR) {
$skillsIDref = \@skillsID;
delete @{$char->{skills}}{@$skillsIDref};
} elsif ($ownerType == Skill::OWNER_HOMUN) {
$skillsIDref = \@{$char->{homunculus}->{slave_skillsID}};
delete @{$char->{homunculus}->{skills}}{@$skillsIDref};
} elsif ($ownerType == Skill::OWNER_MERC) {
$skillsIDref = \@{$char->{mercenary}->{slave_skillsID}};
delete @{$char->{mercenary}->{skills}}{@$skillsIDref};
}
@$skillsIDref = ();

# TODO: $actor can be undefined here
undef @{$actor->{slave_skillsID}};
for (my $i = 4; $i < $args->{RAW_MSG_SIZE}; $i += $skill_info->{len}) {
my $skill;
@{$skill}{@{$skill_info->{keys}}} = unpack($skill_info->{types}, substr($msg, $i, $skill_info->{len}));

my $handle = Skill->new(idn => $skill->{ID})->getHandle;

foreach(@{$skill_info->{keys}}) {
$char->{skills}{$handle}{$_} = $skill->{$_};
$actor->{skills}{$handle}{$_} = $skill->{$_};
}

binAdd($skillsIDref, $handle) unless defined binFind($skillsIDref, $handle);
Expand Down Expand Up @@ -11695,12 +11702,6 @@ sub isvr_disconnect {
sub skill_use_failed {
my ($self, $args) = @_;

# skill fail/delay
my $skillID = $args->{skillID};
my $btype = $args->{btype};
my $fail = $args->{fail};
my $type = $args->{type};

my %basefailtype = (
0 => $msgTable[160],#"skill failed"
1 => $msgTable[161],#"no emotions"
Expand Down Expand Up @@ -11749,25 +11750,31 @@ sub skill_use_failed {
);

my $errorMessage;
if ($skillID == 1 && $type == 0 && exists $basefailtype{$btype}) {
$errorMessage = $basefailtype{$btype};
} elsif (exists $failtype{$type}) {
$errorMessage = $failtype{$type};
if ($args->{skillID} == 1 && $args->{cause} == 0 && exists $basefailtype{$args->{btype}}) {
$errorMessage = $basefailtype{$args->{btype}};
} elsif (exists $failtype{$args->{cause}}) {
$errorMessage = $failtype{$args->{cause}};
if ($args->{cause} == 71) {
$errorMessage .= T(' - item ').$args->{itemId};
}
} else {
$errorMessage = T('Unknown error');
}

delete $char->{casting};

my %hookArgs;
$hookArgs{skillID} = $skillID;
$hookArgs{failType} = $type;
$hookArgs{skillID} = $args->{skillID};
$hookArgs{btype} = $args->{btype};
$hookArgs{itemId} = $args->{itemId};
$hookArgs{flag} = $args->{flag};
$hookArgs{cause} = $args->{cause};
$hookArgs{failMessage} = $errorMessage;
$hookArgs{warn} = 1;

Plugins::callHook('packet_skillfail', \%hookArgs);

warning(TF("Skill %s failed: %s (error number %s)\n", Skill->new(idn => $skillID)->getName(), $errorMessage, $type), "skill") if ($hookArgs{warn});
warning(TF("Skill %s failed: %s (error number %s)\n", Skill->new(idn => $args->{skillID})->getName(), $errorMessage, $args->{cause}), "skill") if ($hookArgs{warn});

# Ressurect Homunculus failed - which means we have no dead homunculus
if ($args->{skillID} == 247 && $args->{cause} == 0) {
Expand Down Expand Up @@ -12355,4 +12362,11 @@ sub repute_info {
}
}

# 0A15 - PACKET_ZC_GOLDPCCAFE_POINT
# TODO: this package is not supported yet.
sub gold_pc_cafe_point {
my ($self, $args) = @_;
debug TF("[gold_pc_cafe_point] isActive=%d, mode=%d, point=%d, playedTime=%d\n", $args->{isActive}, $args->{mode}, $args->{point}, $args->{playedTime});
}

1;
6 changes: 5 additions & 1 deletion src/Network/Receive/ServerType0.pm
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ sub new {
'010C' => ['mvp_other', 'a4', [qw(ID)]],
'010E' => ['skill_update', 'v4 C', [qw(skillID lv sp range up)]], # range = skill range, up = this skill can be leveled up further
'010F' => ['skills_list'],
'0110' => ['skill_use_failed', 'v V C2', [qw(skillID btype fail type)]],
'0110' => ($rpackets{'0110'}{length} == 14) # or 10
? ['skill_use_failed', 'v V2 C2', [qw(skillID btype itemId flag cause)]]
: ['skill_use_failed', 'v v2 C2', [qw(skillID btype itemId flag cause)]]
,
'0111' => ['skill_add', 'v V v3 Z24 C', [qw(skillID target lv sp range name upgradable)]],
'0114' => ['skill_use', 'v a4 a4 V3 v3 C', [qw(skillID sourceID targetID tick src_speed dst_speed damage level option type)]],
'0117' => ['skill_use_location', 'v a4 v3 V', [qw(skillID sourceID lv x y tick)]],
Expand Down Expand Up @@ -635,6 +638,7 @@ sub new {
'0A10' => ['storage_items_nonstackable', 'v Z24 a*', [qw(len title itemInfo)]],
'0A12' => ['rodex_open_write', 'Z24 C', [qw(name result)]], # 27
'0A14' => ['rodex_check_player', 'V v2', [qw(char_id class base_level)]],
'0A15' => ['gold_pc_cafe_point', 'C2 V2', [qw(isActive mode point playedTime)]], # 12
'0A18' => ['map_loaded', 'V a3 C2 v C', [qw(syncMapSync coords xSize ySize font sex)]], # 14
'0A1A' => ['roulette_window', 'C V C2 v V3', [qw(result serial stage price additional_item gold silver bronze)]],
'0A1C' => ['roulette_info', 'v V a*', [qw(len serial roulette_info)]],
Expand Down
6 changes: 5 additions & 1 deletion src/Network/Receive/kRO/Sakexe_0.pm
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ sub new {
'010D' => ['mvp_item_trow'], # 2
'010E' => ['skill_update', 'v4 C', [qw(skillID lv sp range up)]], # 11 # range = skill range, up = this skill can be leveled up further
'010F' => ['skills_list'], # -1
'0110' => ['skill_use_failed', 'v V C2', [qw(skillID btype fail type)]], # 10
'0110' => ($rpackets{'0110'}{length} == 14) # or 10
? ['skill_use_failed', 'v V2 C2', [qw(skillID btype itemId flag cause)]]
: ['skill_use_failed', 'v v2 C2', [qw(skillID btype itemId flag cause)]]
,
'0111' => ['skill_add', 'v V v3 Z24 C', [qw(skillID target lv sp range name upgradable)]], # 39
'0114' => ['skill_use', 'v a4 a4 V3 v3 C', [qw(skillID sourceID targetID tick src_speed dst_speed damage level option type)]], # 31
'0115' => ['skill_use_position', 'v a4 a4 V3 v5 C', [qw(skillID sourceID targetID tick src_speed dst_speed x y damage level option type)]], # 35
Expand Down Expand Up @@ -627,6 +630,7 @@ sub new {
'0A10' => ['storage_items_nonstackable', 'v Z24 a*', [qw(len title itemInfo)]],
'0A12' => ['rodex_open_write', 'Z24 C', [qw(name result)]], # 27
'0A14' => ['rodex_check_player', 'V v2', [qw(char_id class base_level)]],
'0A15' => ['gold_pc_cafe_point', 'C2 V2', [qw(isActive mode point playedTime)]], # 12
'0A18' => ['map_loaded', 'V a3 C2 v C', [qw(syncMapSync coords xSize ySize font sex)]], # 14
'0A1A' => ['roulette_window', 'C V C2 v V3', [qw(result serial stage price additional_item gold silver bronze)]],
'0A1C' => ['roulette_info', 'v V a*', [qw(len serial roulette_info)]],
Expand Down

0 comments on commit 7960b3d

Please sign in to comment.