Skip to content

Commit

Permalink
Fix slave skills (#3914)
Browse files Browse the repository at this point in the history
* Fix slave skills

* Move skills to slave AI-
  • Loading branch information
Henrybk authored Dec 26, 2024
1 parent f50bb7a commit 6a1c6a2
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 25 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 @@ -510,6 +521,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 @@ -114,6 +114,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 @@ -3100,10 +3100,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 @@ -4752,14 +4752,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
21 changes: 14 additions & 7 deletions src/Network/Receive.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9309,26 +9309,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

0 comments on commit 6a1c6a2

Please sign in to comment.