Jump to content

Shooms - can you help? ConsumeAbility Hook


Recommended Posts

Hey Shooms,


I dont want auto learning abilities, i am wanting to have clicky items that grant them


So I modified the recipe hook script and made a new one from it to allow items to be consumed to give abilities


But for some reason I don't see the ability on my action bar - I do however get a message saying I can't consume the ability if i try to use it a second time (it states i already know it)


So it seems like I am getting the ability but it's not showing - any ideas why?


Code below


package atavism.agis.core;

import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import atavism.server.engine.BasicWorldNode;
import atavism.server.engine.Engine;
import atavism.server.engine.EnginePlugin;
import atavism.server.engine.OID;
import atavism.server.math.AOVector;
import atavism.server.objects.ObjectTypes;
import atavism.server.plugins.WorldManagerClient;
import atavism.server.plugins.WorldManagerClient.ExtensionMessage;
import atavism.server.plugins.WorldManagerClient.TargetedExtensionMessage;
import atavism.server.util.*;
import atavism.agis.objects.*;
import atavism.agis.plugins.AgisInventoryClient;
import atavism.agis.plugins.CombatPlugin;
import atavism.agis.plugins.CraftingClient;
import atavism.agis.plugins.VoxelClient;
import atavism.agis.util.ExtendedCombatMessages;

* An acquire hook for items that turn into an ability
* when acquired.
public class ConsumeAbilityActivateHook implements ActivateHook {
   public ConsumeAbilityActivateHook() {

   public ConsumeAbilityActivateHook(int abilityID) {

   public void setAbilityID(int abilityID) {
       if (abilityID == -1) {
           throw new RuntimeException("ConsumeAbilityActivateHook.setResource: bad resource");
       this.abilityID = abilityID;
   public int getAbilityID() {
   	return abilityID;
   protected int abilityID;

    * Adds the item to the Building Resources map for the player and returns true telling the item to be
    * destroyed.
   public boolean activate(OID activatorOid, AgisItem item, OID targetOid) {
       if (Log.loggingDebug)
           Log.debug("ConsumeAbilityActivateHook.activate: activator=" + activatorOid + " item=" + item + " ability=" + abilityID);

       // Only convert it if it is activated by a player
       if (WorldManagerClient.getObjectInfo(activatorOid).objType != ObjectTypes.player) {
       	return false;

       // Add ability resource
       LinkedList abilities = (LinkedList)EnginePlugin.getObjectProperty(activatorOid, WorldManagerClient.NAMESPACE, "abilities");
       if (abilities == null) {
       	abilities = new LinkedList();
       } else if (abilities.contains("" + abilityID)) {
       	ExtendedCombatMessages.sendErrorMessage(activatorOid, "You already know that ability");
       	return false;
       abilities.add("" + abilityID);
	EnginePlugin.setObjectProperty(activatorOid, WorldManagerClient.NAMESPACE, "abilities", abilities);
       ExtendedCombatMessages.sendCombatText(activatorOid, "Learned new ability", 16);
       sendAbilities(activatorOid, abilities);
       //ExtendedCombatMessages.sendAnouncementMessage(activatorOid, "You have learned a new ability", "Skill");
       // Need to remove the item
       AgisInventoryClient.removeSpecificItem(activatorOid, item.getOid(), true, 1);

       return true;

    * Sends down the map of Ability Resources the player has to the client. Static function so can be called from anywhere.
    * @param oid
    * @param resources

   public static void sendAbilities(OID oid, LinkedList abilities) {
	Map props = new HashMap();
       props.put("ext_msg_subtype", "abilities");
       int numResources = 0;
       for (String resourceID : abilities) {
       	Log.debug("RESOURCE: got currency to send: " + resourceID);
       	props.put("resource" + numResources + "ID", resourceID);

	props.put("numAbilities", numResources);
       TargetedExtensionMessage msg = new TargetedExtensionMessage(WorldManagerClient.MSG_TYPE_EXTENSION,
       		oid, oid, false, props);
    Log.debug("ABILITIES: sending down ability message to: " + oid + " with props: " + props);

   public String toString() {
   	return "ConsumeAbilityActivateHook=" + abilityID;

   private static final long serialVersionUID = 1L;

Link to comment
Share on other sites

  • 2 months later...

Sorry Michael, I had been away for a while and now back in action.


Firstly, it's awesome to see some more people trying to dig into the code.


This stuff gets quite tricky pretty quick so I will explain how the ability system works first with a bit of core Atavism design explanation.


Each part of your characters data is separate, such as the combat, inventory, quest progress etc. Each of these subObjects of your character are referred to as "typeInfo" so for combat it is CombatInfo, and they only exist in the relevant process (so the CombatInfo is only usable within the Combat and ClassAbility Plugins).


This means all the characters ability info (along with the actions) are stored in the CombatInfo subObject, and when you want to access the abilities or action list in the server code it needs to be done in the Combat areas. What you have done is just try to directly set a list (of strings) that contains the abilities the player has, and try to save it to the WorldManager subObject.


What needs to be done is code needs to exist in the ClassAbilityPlugin.java file that picks up a message saying which ability the player has learned and then it will access the CombatInfo for the player and add the ability and update the action list. You can see an example which just updates the ActionList (from ClassAbilityPlugin.java line 895):


class UpdateActionBarHook implements Hook {
   	public boolean processMessage(Message msg, int flags) {
   		CombatClient.updateActionBarMessage UABMsg = (CombatClient.updateActionBarMessage) msg;
   	    OID oid = UABMsg.getSubject();
   	    int actionPosition = (Integer) UABMsg.getProperty("actionPosition");
   	    String newAction = (String) UABMsg.getProperty("newAction");
   	    CombatInfo cInfo = CombatPlugin.getCombatInfo(oid);
   	    ArrayList actions = cInfo.getCurrentActions();
   	    while (actions.size() <= actionPosition) {
   	    actions.set(actionPosition, newAction);
   	    ExtendedCombatMessages.sendActions(oid, actions);
   	    return true;


What I recommend is I will add a LearnAbilityMessage and a Hook to catch that message and then add the ability to the players CombatInfo. I will have it in 2.4 as I see it as an important feature and will take me 30 minutes.

Link to comment
Share on other sites

Hi Sooms,


Thank you for the reply, this is really helpful


So as for moving this over to the ClassAbility plugin i am wondering how i should handle my current hook


At the moment the event will fire based on right clicking the item in my inventory


So for example I have added a new effecttype into ItemDatabase.java


Here is the code


} else if (effectType.equals("BuildingMaterial")) {
// Used to turn an item into a Building Resource when acquired
//String value = rs.getString("effect" + i + "value");
//int resourceID = Integer.parseInt(value);
tmpl.put(InventoryClient.ITEM_NAMESPACE, AgisItem.TEMPL_ACQUIRE_HOOK, new BuildingResourceAcquireHook(rs.getInt("id")));
} else if (effectType.equals("Blueprint")) {
// Used to turn an item into a recipe when acquired
String value = rs.getString("effect" + i + "value");
int recipeID = Integer.parseInt(value);
tmpl.put(InventoryClient.ITEM_NAMESPACE, InventoryClient.TEMPL_ACTIVATE_HOOK, new RecipeItemActivateHook(recipeID));
} else if (effectType.equals("ConsumeAbility")) {
// Mixxit - Used to turn an item into an ability when acquired
String value = rs.getString("effect" + i + "value");
int abilityID = Integer.parseInt(value);
tmpl.put(InventoryClient.ITEM_NAMESPACE, InventoryClient.TEMPL_ACTIVATE_HOOK, new ConsumeAbilityActivateHook(abilityID));


At the point here, where I am putting the hook into the Item Namespace, are you saying I need to instead put this into the ClassAbility namespace?


If so how will the event fire for the right click of the item?

Link to comment
Share on other sites

That part of the code is fine as you had it. It is in the actual ConsumeAbilityActivateHook class, the activate function will instead need to send a message (which I have to create) which the ClassAbilityPlugin will catch and then add the ability to the player.


The way Atavism works is you have the different processes for each part of the game (combat, mobs, inventory etc) and when you need to pass some information on to another process (such as adding an ability from an item event) you need to send a message which the other process can catch and then work with.

Link to comment
Share on other sites

thanks that would be really great, can you possibly put it in the wiki for others too?


i know you have a lot of work to do for the roadmap and instead of you coding in changes for us to do what we want to achieve if you can go into detail on how it works currently we can do the changes ourselves and then if you are happy we can submit our changes to you for future releases


that way the community can work in harmony with you instead of being a burden, sure we will have technical questions but if you believe it is possible for us to make the changes now then all that needs to be addressed is the documentation really


thanks again!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recommended Cloud Solution


  • Create New...

Important Information

By using this site, you agree to our Terms of Use.