Improved "skills add" command

Wrote new code? Fixed a bug? Want to discuss technical stuff? Feel free to post it here.

Moderator: Moderators

Kaspy
Halfway to Eternity
Halfway to Eternity
Posts: 398
Joined: 08 Jun 2012, 15:42
Noob?: No
Location: Brazil

Improved "skills add" command

#1 Post by Kaspy »

--- Edit 7/7
[EN]
Sorry, I realized that OpenKore already has a function that attaches to implement, but the condition in the most "add skills" is still nescessária.

Redid this part (commands.pm):

Code: Select all

sub cmdSkills {
	my (undef, $args) = @_;
	my ($arg1) = $args =~ /^(\w+)/;
	my ($arg2) = $args =~ /^\w+ (\d+)/;
	if ($arg1 eq "") {
		my $msg = T("----------Skill List-----------\n" .
			"   # Skill Name                          Lv      SP\n");
		for my $handle (@skillsID) {
			my $skill = new Skill(handle => $handle);
			my $sp = $char->{skills}{$handle}{sp} || '';
			$msg .= swrite(
				"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
				[$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
		}
		$msg .= TF("\nSkill Points: %d\n", $char->{points_skill});
		$msg .= "-------------------------------\n";
		message($msg, "list");

	} elsif ($arg1 eq "add" && $arg2 =~ /\d+/) {
		if (!$net || $net->getState() != Network::IN_GAME) {
			error TF("You must be logged in the game to use this command (%s)\n", 'skills add');
			return;
		}
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s does not exist.\n", $arg2);
		} elsif ($char->{points_skill} < 1) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Not enough skill points to increase %s\n", $skill->getName());
		} elsif ($char->{skills}{$skill->getHandle()}{up} == 0) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s reached its maximum level or prerequisite not reached\n", $skill->getName());
		} else {
			$messageSender->sendAddSkillPoint($skill->getIDN());
		}

	} elsif ($arg1 eq "desc" && $arg2 =~ /\d+/) {
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN()) {
			error TF("Error in function 'skills desc' (Skill Description)\n" .
				"Skill %s does not exist.\n", $arg2);
		} else {
			my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.\n");
			message TF("===============Skill Description===============\n" .
				"Skill: %s\n\n", $skill->getName()), "info";
			message $description, "info";
			message "==============================================\n", "info";
		}
	} else {
		error T("Syntax Error in function 'skills' (Skills Functions)\n" .
			"Usage: skills [<add | desc>] [<skill #>]\n");
	}
}
[PT-BR]
Desculpa, percebi que o OpenKore já tem a função que prendia implementar, mas a condição a mais no "skills add" ainda é nescessária.

Refiz essa parte (commands.pm):

Code: Select all

sub cmdSkills {
	my (undef, $args) = @_;
	my ($arg1) = $args =~ /^(\w+)/;
	my ($arg2) = $args =~ /^\w+ (\d+)/;
	if ($arg1 eq "") {
		my $msg = T("----------Skill List-----------\n" .
			"   # Skill Name                          Lv      SP\n");
		for my $handle (@skillsID) {
			my $skill = new Skill(handle => $handle);
			my $sp = $char->{skills}{$handle}{sp} || '';
			$msg .= swrite(
				"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
				[$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
		}
		$msg .= TF("\nSkill Points: %d\n", $char->{points_skill});
		$msg .= "-------------------------------\n";
		message($msg, "list");

	} elsif ($arg1 eq "add" && $arg2 =~ /\d+/) {
		if (!$net || $net->getState() != Network::IN_GAME) {
			error TF("You must be logged in the game to use this command (%s)\n", 'skills add');
			return;
		}
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s does not exist.\n", $arg2);
		} elsif ($char->{points_skill} < 1) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Not enough skill points to increase %s\n", $skill->getName());
		} elsif ($char->{skills}{$skill->getHandle()}{up} == 0) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s reached its maximum level or prerequisite not reached\n", $skill->getName());
		} else {
			$messageSender->sendAddSkillPoint($skill->getIDN());
		}

	} elsif ($arg1 eq "desc" && $arg2 =~ /\d+/) {
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN()) {
			error TF("Error in function 'skills desc' (Skill Description)\n" .
				"Skill %s does not exist.\n", $arg2);
		} else {
			my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.\n");
			message TF("===============Skill Description===============\n" .
				"Skill: %s\n\n", $skill->getName()), "info";
			message $description, "info";
			message "==============================================\n", "info";
		}
	} else {
		error T("Syntax Error in function 'skills' (Skills Functions)\n" .
			"Usage: skills [<add | desc>] [<skill #>]\n");
	}
}
---------

[EN]
Missing the possibility to know if a skill reached or no your max level, I decided search in Skill.pm and I didn't found a function for that. Searching better, I realize that the ServerType0.pm do this (sub skills_list), but don't send all the information to skill.pm on Skill::DynamicInfo.

And I did.

Leveraging, and include a further condition anti-bug in add skills so as not to try to increase a skill level already achieved peak level.

Download files:
http://www.mediafire.com/?rdlr312ka09fsad
http://www.mediafire.com/?aejpce7camc7vw9
http://www.mediafire.com/?b35xgpk95mvceuv

Data that changed:
ServerType0.pm

Code: Select all

sub skills_list {
	my ($self, $args) = @_;

	return unless changeToInGameState;

	my ($msg, $newmsg);
	$msg = $args->{RAW_MSG};
	$self->decrypt(\$newmsg, substr $msg, 4);
	$msg = substr ($msg, 0, 4) . $newmsg;

	# TODO: per-actor, if needed at all
	# Skill::DynamicInfo::clear;

	my ($ownerType, $hook, $actor) = @{{
		'010F' => [Skill::OWNER_CHAR, 'packet_charSkills'],
		'0235' => [Skill::OWNER_HOMUN, 'packet_homunSkills', $char->{homunculus}],
		'029D' => [Skill::OWNER_MERC, 'packet_mercSkills', $char->{mercenary}],
	}->{$args->{switch}}};

	my $skillsIDref = $actor ? \@{$actor->{slave_skillsID}} : \@skillsID;
	delete @{$char->{skills}}{@$skillsIDref};
	@$skillsIDref = ();

	# TODO: $actor can be undefined here
	undef @{$actor->{slave_skillsID}};
	for (my $i = 4; $i < $args->{RAW_MSG_SIZE}; $i += 37) {
		my ($ID, $targetType, $lv, $sp, $range, $handle, $up) = unpack 'v1 V1 v3 Z24 C1', substr $msg, $i, 37;
		$handle ||= Skill->new(idn => $ID)->getHandle;

		@{$char->{skills}{$handle}}{qw(ID targetType lv sp range up)} = ($ID, $targetType, $lv, $sp, $range, $up);
		# $char->{skills}{$handle}{lv} = $lv unless $char->{skills}{$handle}{lv};

		binAdd($skillsIDref, $handle) unless defined binFind($skillsIDref, $handle);
		Skill::DynamicInfo::add($ID, $handle, $lv, $sp, $range, $targetType, $ownerType, $up);

		Plugins::callHook($hook, {
			ID => $ID,
			handle => $handle,
			level => $lv,
			upgradable => $up,
		});
	}
}
Skill.pm added below the sub getRange

Code: Select all

##
# int $Skill->getUpgradable()
# 
#  [EN]
# Returns 0 if the maximum level of skill has been achieved.
# Returns 1 if the maximum level of skill has NOT been reached.
# Returns 2 on error.
#  [PT-BR]
# Retorna 0 caso o nível máximo da habilidade tenha sido alcançado.
# Retorna 1 caso o nível máximo da habilidade NÃO tenha sido alcançado.
# Retorna 2 em caso de erro.
sub getUpgradable {
	my ($self) = @_;
	my $entry = $Skill::DynamicInfo::skills{$self->{idn}};
	if ($entry) {
		return $entry->{upgradable};
	} else {
		return 2; # sqrt(2)
	}
}
Also in Skill.pm

Code: Select all

package Skill::DynamicInfo;

# The skills information as sent by the RO server. This variable maps a skill IDN
# to another hash, with the following members:
# - handle     - Handle name.
# - level      - Character's current maximum skill level.
# - sp         - The SP usage for the current maximum level.
# - range      - Skill range.
# - targetType - The skill's target type.
# - upgradable - 0 = maximum level of skill has been achieved. 1 = maximum level of skill has NOT been reached. 2 = error.
our %skills;

# Maps handle names to skill IDNs.
our %handles;

sub add {
	my ($idn, $handle, $level, $sp, $range, $targetType, $ownerType, $upgradable) = @_;
	$skills{$idn} = {
		handle     => $handle,
		level      => $level,
		sp         => $sp,
		range      => $range,
		targetType => $targetType,
		ownerType  => $ownerType,
		upgradable => $upgradable
	};
	$handles{$handle} = $idn;
}
Commands.pm

Code: Select all

sub cmdSkills {
	my (undef, $args) = @_;
	my ($arg1) = $args =~ /^(\w+)/;
	my ($arg2) = $args =~ /^\w+ (\d+)/;
	if ($arg1 eq "") {
		my $msg = T("----------Skill List-----------\n" .
			"   # Skill Name                          Lv      SP\n");
		for my $handle (@skillsID) {
			my $skill = new Skill(handle => $handle);
			my $sp = $char->{skills}{$handle}{sp} || '';
			$msg .= swrite(
				"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
				[$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
		}
		$msg .= TF("\nSkill Points: %d\n", $char->{points_skill});
		$msg .= "-------------------------------\n";
		message($msg, "list");

	} elsif ($arg1 eq "add" && $arg2 =~ /\d+/) {
		if (!$net || $net->getState() != Network::IN_GAME) {
			error TF("You must be logged in the game to use this command (%s)\n", 'skills add');
			return;
		}
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s does not exist.\n", $arg2);
		} elsif ($char->{points_skill} < 1) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Not enough skill points to increase %s\n", $skill->getName());
		} elsif ($skill->getUpgradable($skill->getIDN()) == 0) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s reached its maximum level \n", $skill->getName());
		} else {
			$messageSender->sendAddSkillPoint($skill->getIDN());
		}

	} elsif ($arg1 eq "desc" && $arg2 =~ /\d+/) {
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN()) {
			error TF("Error in function 'skills desc' (Skill Description)\n" .
				"Skill %s does not exist.\n", $arg2);
		} else {
			my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.\n");
			message TF("===============Skill Description===============\n" .
				"Skill: %s\n\n", $skill->getName()), "info";
			message $description, "info";
			message "==============================================\n", "info";
		}
	} else {
		error T("Syntax Error in function 'skills' (Skills Functions)\n" .
			"Usage: skills [<add | desc>] [<skill #>]\n");
	}
}
Can I hope you include in SVN, since this function is very useful. (You can put in the credits KeplerBR).
If possible, also like to assess whether I did everything right, because I never did something so deep in OpenKore.

If had this function in OpenKore, I apologize because I did not find.

[PT-BR]
Enquanto programava um plugin, senti falta na possibilidade de saber se a habilidade alcançou ou não o seu nível máximo.
Então resolvi pesquisar no Skill.pm e não encontrei uma função para isso.
Fui mais a fundo e percebi que o ServerType0.pm fazia isso (sub skills_list), mas não transferia os dados para o skill.pm, no Skill::DynamicInfo

E foi o que fiz.

Aproveitando, e incluir mais uma condição anti-bug no comando skills add, para não tentar aumentar um nível de habilidade com nível máximo já alcançado.

Download dos arquivos:
http://www.mediafire.com/?rdlr312ka09fsad
http://www.mediafire.com/?aejpce7camc7vw9
http://www.mediafire.com/?b35xgpk95mvceuv

Dados que alterei:
ServerType0.pm

Code: Select all

sub skills_list {
	my ($self, $args) = @_;

	return unless changeToInGameState;

	my ($msg, $newmsg);
	$msg = $args->{RAW_MSG};
	$self->decrypt(\$newmsg, substr $msg, 4);
	$msg = substr ($msg, 0, 4) . $newmsg;

	# TODO: per-actor, if needed at all
	# Skill::DynamicInfo::clear;

	my ($ownerType, $hook, $actor) = @{{
		'010F' => [Skill::OWNER_CHAR, 'packet_charSkills'],
		'0235' => [Skill::OWNER_HOMUN, 'packet_homunSkills', $char->{homunculus}],
		'029D' => [Skill::OWNER_MERC, 'packet_mercSkills', $char->{mercenary}],
	}->{$args->{switch}}};

	my $skillsIDref = $actor ? \@{$actor->{slave_skillsID}} : \@skillsID;
	delete @{$char->{skills}}{@$skillsIDref};
	@$skillsIDref = ();

	# TODO: $actor can be undefined here
	undef @{$actor->{slave_skillsID}};
	for (my $i = 4; $i < $args->{RAW_MSG_SIZE}; $i += 37) {
		my ($ID, $targetType, $lv, $sp, $range, $handle, $up) = unpack 'v1 V1 v3 Z24 C1', substr $msg, $i, 37;
		$handle ||= Skill->new(idn => $ID)->getHandle;

		@{$char->{skills}{$handle}}{qw(ID targetType lv sp range up)} = ($ID, $targetType, $lv, $sp, $range, $up);
		# $char->{skills}{$handle}{lv} = $lv unless $char->{skills}{$handle}{lv};

		binAdd($skillsIDref, $handle) unless defined binFind($skillsIDref, $handle);
		Skill::DynamicInfo::add($ID, $handle, $lv, $sp, $range, $targetType, $ownerType, $up);

		Plugins::callHook($hook, {
			ID => $ID,
			handle => $handle,
			level => $lv,
			upgradable => $up,
		});
	}
}
Skill.pm adicionei abaixo do sub getRange

Code: Select all

##
# int $Skill->getUpgradable()
# 
#  [EN]
# Returns 0 if the maximum level of skill has been achieved.
# Returns 1 if the maximum level of skill has NOT been reached.
# Returns 2 on error.
#  [PT-BR]
# Retorna 0 caso o nível máximo da habilidade tenha sido alcançado.
# Retorna 1 caso o nível máximo da habilidade NÃO tenha sido alcançado.
# Retorna 2 em caso de erro.
sub getUpgradable {
	my ($self) = @_;
	my $entry = $Skill::DynamicInfo::skills{$self->{idn}};
	if ($entry) {
		return $entry->{upgradable};
	} else {
		return 2; # sqrt(2)
	}
}
Também no Skill.pm

Code: Select all

package Skill::DynamicInfo;

# The skills information as sent by the RO server. This variable maps a skill IDN
# to another hash, with the following members:
# - handle     - Handle name.
# - level      - Character's current maximum skill level.
# - sp         - The SP usage for the current maximum level.
# - range      - Skill range.
# - targetType - The skill's target type.
# - upgradable - 0 = maximum level of skill has been achieved. 1 = maximum level of skill has NOT been reached. 2 = error.
our %skills;

# Maps handle names to skill IDNs.
our %handles;

sub add {
	my ($idn, $handle, $level, $sp, $range, $targetType, $ownerType, $upgradable) = @_;
	$skills{$idn} = {
		handle     => $handle,
		level      => $level,
		sp         => $sp,
		range      => $range,
		targetType => $targetType,
		ownerType  => $ownerType,
		upgradable => $upgradable
	};
	$handles{$handle} = $idn;
}
Commands.pm

Code: Select all

sub cmdSkills {
	my (undef, $args) = @_;
	my ($arg1) = $args =~ /^(\w+)/;
	my ($arg2) = $args =~ /^\w+ (\d+)/;
	if ($arg1 eq "") {
		my $msg = T("----------Skill List-----------\n" .
			"   # Skill Name                          Lv      SP\n");
		for my $handle (@skillsID) {
			my $skill = new Skill(handle => $handle);
			my $sp = $char->{skills}{$handle}{sp} || '';
			$msg .= swrite(
				"@>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>    @>>>",
				[$skill->getIDN(), $skill->getName(), $char->getSkillLevel($skill), $sp]);
		}
		$msg .= TF("\nSkill Points: %d\n", $char->{points_skill});
		$msg .= "-------------------------------\n";
		message($msg, "list");

	} elsif ($arg1 eq "add" && $arg2 =~ /\d+/) {
		if (!$net || $net->getState() != Network::IN_GAME) {
			error TF("You must be logged in the game to use this command (%s)\n", 'skills add');
			return;
		}
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN() || !$char->{skills}{$skill->getHandle()}) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s does not exist.\n", $arg2);
		} elsif ($char->{points_skill} < 1) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Not enough skill points to increase %s\n", $skill->getName());
		} elsif ($skill->getUpgradable($skill->getIDN()) == 0) {
			error TF("Error in function 'skills add' (Add Skill Point)\n" .
				"Skill %s reached its maximum level \n", $skill->getName());
		} else {
			$messageSender->sendAddSkillPoint($skill->getIDN());
		}

	} elsif ($arg1 eq "desc" && $arg2 =~ /\d+/) {
		my $skill = new Skill(idn => $arg2);
		if (!$skill->getIDN()) {
			error TF("Error in function 'skills desc' (Skill Description)\n" .
				"Skill %s does not exist.\n", $arg2);
		} else {
			my $description = $skillsDesc_lut{$skill->getHandle()} || T("Error: No description available.\n");
			message TF("===============Skill Description===============\n" .
				"Skill: %s\n\n", $skill->getName()), "info";
			message $description, "info";
			message "==============================================\n", "info";
		}
	} else {
		error T("Syntax Error in function 'skills' (Skills Functions)\n" .
			"Usage: skills [<add | desc>] [<skill #>]\n");
	}
}
Espero que possam incluir no SVN, pois essa função é bem útil (Nos créditos, use KeplerBR).
Se possível, também gostaria que avaliassem se fiz tudo direito, pois nunca fiz algo tão a fundo no OpenKore.

Se já havia essa função no OpenKore, peço desculpas, pois não encontrei.
Last edited by Kaspy on 07 Jul 2012, 16:32, edited 1 time in total.
Image
Kaspy
Halfway to Eternity
Halfway to Eternity
Posts: 398
Joined: 08 Jun 2012, 15:42
Noob?: No
Location: Brazil

Re: Improved "skills add" command

#2 Post by Kaspy »

UP
I edited the topic
Image
EternalHarvest
Developers
Developers
Posts: 1798
Joined: 05 Dec 2008, 05:42
Noob?: Yes

Re: Improved "skills add" command

#3 Post by EternalHarvest »

You can just add new posts... Now it's kinda messed up, you're proposing only what's in the first [ code ] block?
Kaspy
Halfway to Eternity
Halfway to Eternity
Posts: 398
Joined: 08 Jun 2012, 15:42
Noob?: No
Location: Brazil

Re: Improved "skills add" command

#4 Post by Kaspy »

[EN]
Yes, just what is in the first block.

I just added one more condition anti-bug:

Code: Select all

      } elsif ($char->{skills}{$skill->getHandle()}{up} == 0) {
         error TF("Error in function 'skills add' (Add Skill Point)\n" .
            "Skill %s reached its maximum level or prerequisite not reached\n", $skill->getName());
[PT-BR]
Sim, apenas o que esta no primeiro bloco

Eu apenas adicionei mais uma condição anti-bug:

Code: Select all

      } elsif ($char->{skills}{$skill->getHandle()}{up} == 0) {
         error TF("Error in function 'skills add' (Add Skill Point)\n" .
            "Skill %s reached its maximum level or prerequisite not reached\n", $skill->getName());
Image
EternalHarvest
Developers
Developers
Posts: 1798
Joined: 05 Dec 2008, 05:42
Noob?: Yes

Re: Improved "skills add" command

#5 Post by EternalHarvest »

Kaspy
Halfway to Eternity
Halfway to Eternity
Posts: 398
Joined: 08 Jun 2012, 15:42
Noob?: No
Location: Brazil

Re: Improved "skills add" command

#6 Post by Kaspy »

[EN]
Thanks ^^
My third contribution of in the official SVN

[PT-BR]
Obrigado ^^
Terceira contribuição minha no SVN oficial
Image