osrsbox / osrsbox-db

A complete and up-to-date database of Old School Runescape (OSRS) items, monsters and prayers
https://www.osrsbox.com/projects/osrsbox-db/
GNU General Public License v3.0
227 stars 83 forks source link

Add stance types onto weapons #92

Closed nwalsh1995 closed 5 years ago

nwalsh1995 commented 5 years ago

Hi @osrsbox, not sure if it is possible but it would be really nice for me to have some of this data.

When I was searching on the wiki I saw that some weapons have the stances but not the exact stance types: https://oldschool.runescape.wiki/w/Abyssal_whip#Combat_styles

It has that they are all 'Slash' type but not if they are in 'Accurate', 'Controlled' or 'Defensive'.

Wondering if there is anything in the Runelite cache that we can use here? Would help me out a lot! I've been pondering doing some of the most popular items myself but some I can't afford to check them out (godswords etc).

osrsbox commented 5 years ago

Interestingly, this week the official game update news linked to a new page on the wiki: https://oldschool.runescape.wiki/w/Weapon/Types. I was currently writing the scraper to grab the data, then will compare the item names to all weapons, or 2h weapons to see if anything is missing. I'm interested in also having the data, so will try find a logical place to put it.

nwalsh1995 commented 5 years ago

Yes! That wiki page is actually the holy grail for me. I would slap this information on the ItemEquipment class. I believe you should be able to do it in just 3 attributes 'combat style' 'attack type' and 'attack style'. For me, those fields would be enough.

jayktaylor commented 5 years ago

Hey - wiki admin here. The weapon types were shared with us directly by Jagex, glad the info on the page is found to be helpful.

osrsbox commented 5 years ago

@jaydenkieran - Thanks for the comment, and for the work that went into gathering and sharing the data. Thanks also to JaGeX for sharing the original data, great to see the collaboration with the wiki. Like @nwalsh1995 said: 'that wiki page is actually the holy grail" ! It is great data! And allows us to program lots of interesting stuff like max hit, dps, identify weapons for specific skill (strength, attack, defence) training.

@nwalsh1995 - I agree, looks like it should live in the ItemEquipment class. This will require the following modifications:

osrsbox commented 5 years ago

Just an update on this request...

I have written a scraper to parse the Weapons/Types page. The code needs work as I have not scraped tables in wikitext before, and compared to templates, they are a little funky. Anyway, this provides two data structures:

  1. weapon_type: List of items associated with a weapon classification. This uses the wiki naming conventions: axes, blunt_weapons, bulwarks etc. These are normalized using lowercase and underscores instead of spaces. Example for axes is below.
'axes': ['3rd age axe',
          'Adamant axe',
          'Adamant battleaxe',
          'Anger battleaxe',
          'Black axe',
          'Black battleaxe',
          'Blessed axe',
          'Bronze axe',
          "Dharok's greataxe",
          'Dragon axe',
          'Dragon battleaxe',
          'Infernal axe',
          'Iron axe',
          'Iron battleaxe',
          'Leaf-bladed battleaxe',
          'Mithril axe',
          'Mithril battleaxe',
          'Rune axe',
          'Rune battleaxe',
          'Steel axe',
          'Steel battleaxe',
          'White battleaxe']

So each item is classified.

  1. weapon_properties: Not sure what to call this. An object containing attack style, attack type, combat style, experience and boosts. Not all weapon types have all 5 specified. I wanted all 5 because some seem useful for different things. An example structure for axes is provided below:
{
   "axes":{
      "attack_style":["accurate","aggressive","aggressive","defensive"],
      "attack_type":["slash","slash","crush","slash"],
      "boosts":[],
      "combat_style":["chop","hack","smash","block"],
      "experience":["attack","strength","strength","defence"]
    }
}

This layout is a little funny... The index for each list is the bit that links each property. For example, combat_style[0] and attack_type[0] are related - so to get an accurate attack, you need to select the chop combat style. Hope that makes sense. It seems there must be a better method to store this data?

Now I am wondering where to put the data. It seems silly to put the entire weapon_properties to each item (lots of repetitive data). Maybe the weapon_type can link to the weapon_properties object that is somewhere else - maybe stored in another file and hard-coded in the Python API to load?

Feedback on any of this would be appreciated. @nwalsh1995 got any ideas on how to make the data more easily processed by developers?

nwalsh1995 commented 5 years ago

@osrsbox I think that each weapon should have the attack style/attack type accessible from the ItemEquipment class. This means item_equipment.attack_styles would return the list you mentioned. However, this attribute can just be a property that actually goes and gets the information from another class inside of it (weapon type).

Also, if combat style and attack style arrays are connected you could turn it into an object:

stances: {"combat_type": "accurate", "" attack_type": "slash"}, {...} 

On the python side these can be potentially stored as tuples /namedtuples.

osrsbox commented 5 years ago

I have been working on this issue... The new branch: weapon-definition has the implemented solution. Currently failing build, as multiple things have been changed. The solution does the following:

Basically, the end result is a new object called weapon. This has complete stance information, even in the JSON files (this was a desired design choice to keep thing consistent). An example of the new structure is provided below for the Abyssal whip:

{
    "id": 4151,
    "name": "Abyssal whip",
    "members": true,
    "tradeable": true,
    "tradeable_on_ge": true,
    "stackable": false,
    "noted": false,
    "noteable": true,
    "linked_id": 4152,
    "placeholder": false,
    "equipable": true,
    "equipable_by_player": true,
    "equipable_weapon": true,
    "cost": 120001,
    "lowalch": 48000,
    "highalch": 72000,
    "weight": 0.453,
    "buy_limit": 70,
    "quest_item": false,
    "release_date": "26 January 2005",
    "examine": "A weapon from the abyss.",
    "url": "https://oldschool.runescape.wiki/w/Abyssal_whip",
    "equipment": {
        "attack_stab": 0,
        "attack_slash": 82,
        "attack_crush": 0,
        "attack_magic": 0,
        "attack_ranged": 0,
        "defence_stab": 0,
        "defence_slash": 0,
        "defence_crush": 0,
        "defence_magic": 0,
        "defence_ranged": 0,
        "melee_strength": 82,
        "ranged_strength": 0,
        "magic_damage": 0,
        "prayer": 0,
        "slot": "weapon",
        "requirements": {
            "attack": 70
        }
    },
    "weapon": {
        "attack_speed": 4,
        "weapon_type": "whips",
        "stances": [
            {
                "combat_style": "flick",
                "attack_type": "slash",
                "attack_style": "accurate",
                "experience": "attack",
                "boosts": null
            },
            {
                "combat_style": "lash",
                "attack_type": "slash",
                "attack_style": "controlled",
                "experience": "shared",
                "boosts": null
            },
            {
                "combat_style": "deflect",
                "attack_type": "slash",
                "attack_style": "defensive",
                "experience": "defence",
                "boosts": null
            }
        ]
    }
}

This was a very difficult addition to make, and I am still not sure about the final solution. Any feedback is appreciated @nwalsh1995.

nwalsh1995 commented 5 years ago

@osrsbox I took a look through the Python API to get an idea of how it is structured.

The ItemWeapon dataclass seems okay, but I don't think we should allow all the fields there to be Optional (maybe you are still working on it). Another thing that I think can help out with the readability is having the combat styles / attack types converted into Enums:

from enum import Enum

class AttackType(Enum):
    SLASH = "slash"
    STAB = "stab"
    ...
class AttackStyle(Enum):
    DEFENSIVE = "defensive"
    CONTROLLED = "controlled"
    ...

When everything is enumerated, it is more clear what the possible values can be, and also allows us to make a Stance class easily:

@dataclass
class Stance:
    attack_type: AttackType
    attack_stype: AttackStyle

For the WeaponType class, I think a potentially cleaner approach is to subclass ItemDefinition like so:

class WeaponDefinition(ItemDefinition):
    attack_speed: Optional[int]
    weapon_type: Optional[str]
    stances: Optional[List] 

And then, when creating weapons, you return the WeaponDefinition instead of ItemDefinition. This would adhere to the interface segregation principle which cleans up the API a bit. Note: ItemEquipment has the same problem as this so that can potentially be reworked.

Regardless of the above, what you have works fine and I don't think the JSON schema can be made nicer than what you have.