Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Unreleased

- Add spell base power (`base_power`) to parser, schema and models.
- Add `slot` and `base_power` to item attributes.

## 8.0.1 (2026-06-16)

- Add support for new NPC transport template.
Expand Down
26 changes: 26 additions & 0 deletions tests/models/test_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,32 @@ def test_item_parser_from_article_perfect_shot(self):
self.assertIn("perfect_shot", item.attributes_dict)
self.assertIn("perfect_shot_range", item.attributes_dict)

def test_item_parser_from_article_slot(self):
article = Article(
article_id=1,
title="Ruby Necklace",
timestamp=datetime.datetime.fromisoformat("2018-08-20T04:33:15+00:00"),
content=load_resource("content_item_slot.txt"),
)

item = ItemParser.from_article(article)

self.assertIsInstance(item, Item)
self.assertEqual("Neck", item.attributes_dict.get("slot"))

def test_item_parser_from_article_base_power(self):
article = Article(
article_id=1,
title="Sudden Death Rune",
timestamp=datetime.datetime.fromisoformat("2018-08-20T04:33:15+00:00"),
content=load_resource("content_item_base_power.txt"),
)

item = ItemParser.from_article(article)

self.assertIsInstance(item, Item)
self.assertEqual("150", item.attributes_dict.get("base_power"))

def test_item_parser_from_article_damage_reflection(self):
article = Article(
article_id=1,
Expand Down
33 changes: 33 additions & 0 deletions tests/resources/content_item_base_power.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<noinclude>
:''This article is about the item called Sudden Death Rune. For the spell to create them, see [[Sudden Death]].''
</noinclude>{{Infobox Object|List={{{1|}}}|GetValue={{{GetValue|}}}
| name = Sudden Death Rune
| article = a
| actualname = sudden death rune
| plural = ?
| itemid = 3155
| objectclass = Runes
| primarytype = Attack Runes
| words = adori gran mort
| implemented = 4.0
| immobile = no
| walkable = yes
| pickupable = yes
| usable = yes
| levelrequired = 45
| vocrequired = monks, druids, sorcerers, paladins, knights
| mlrequired = 15
| damagetype = Death
| weight = 0.70
| stackable = yes
| marketable = yes
| droppedby = {{Dropped By|Gravedigger|Hand of Cursed Fate|Tyrn}}
| value = 162
| storevalue = {{Store Trades|{{Store Product|28|amount=250}}}}
| npcvalue = 0
| npcprice = 162
| buyfrom = Asima, Chartan, Chuckles, Fenech, Frans, Frederik, Ghorza, Gnomegica, Khanna, Mordecai, Nelly, Onfroi, Rabaz, Rachel, Rock In A Hard Place, Romir, Shiriel, Siflind, Sigurd, Talila, Tandros, Topsy, Valindara, Xodet
| sellto = --
| basepower = 150
| notes = Shoots a powerful [[Death Damage]] attack on a single target.
}}
24 changes: 24 additions & 0 deletions tests/resources/content_item_slot.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{Infobox Object|List={{{1|}}}|GetValue={{{GetValue|}}}
| name = Ruby Necklace
| article = a
| actualname = ruby necklace
| plural = ruby necklaces
| itemid = 3016
| objectclass = Body Equipment
| primarytype = Amulets and Necklaces
| slot = Neck
| implemented = 5.1
| immobile = no
| walkable = yes
| pickupable = yes
| weight = 5.70
| marketable = yes
| droppedby = {{Dropped By|Biting Book|Black Knight|Dawnfire Asura|Hellgorak|Lost Soul|Sineater Inferniarch|True Dawnfire Asura}}
| value = 2,000 - 3,560
| npcvalue = 2000
| npcprice = 3560
| buyfrom = Augustin, Briasol, Carina, Chantalle, Edmund, Gail, Hanna, Ishina, Iwan, Jessica, Nienna, Odemara, Oiriz, Talila, Tesha, Tezila, Valindara, Yonan
| sellto = Rashid
| notes = Only used as decoration.
| history = This was the first necklace that was once obtainable only in [[Daily Respawns]] in the [[Rain Castle]] of [[Thais]].
}}
1 change: 1 addition & 0 deletions tests/resources/content_spell.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| type = Instant
| subclass = Attack
| damagetype = Fire
| basepower = 45
| words = exori flam
| premium = yes
| mana = 20
Expand Down
2 changes: 2 additions & 0 deletions tests/tests_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,14 @@ def test_spell(self):
content=load_resource("content_spell.txt"))
spell = models.Spell.from_article(article)
self.assertIsInstance(spell, models.Spell)
self.assertEqual(spell.base_power, 45)

spell.insert(self.conn)
db_spell = models.Spell.get_one_by_field(self.conn, "article_id", 1)

self.assertIsInstance(db_spell, models.Spell)
self.assertEqual(db_spell.name, spell.name)
self.assertEqual(db_spell.base_power, spell.base_power)

def test_world(self):
article = Article(1, "Mortera", timestamp="2018-08-20T04:33:15Z",
Expand Down
17 changes: 15 additions & 2 deletions tests/tests_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

from tests import load_resource
from tibiawikisql.api import Article
from tibiawikisql.models import Achievement
from tibiawikisql.parsers import AchievementParser
from tibiawikisql.models import Achievement, Spell
from tibiawikisql.parsers import AchievementParser, SpellParser


class TestParsers(unittest.TestCase):
Expand All @@ -20,4 +20,17 @@ def test_achievement_parser_success(self):

self.assertIsInstance(achievement, Achievement)

def test_spell_parser_success(self):
article = Article(
article_id=1,
title="Flame Strike",
timestamp=datetime.datetime.fromisoformat("2018-08-20T04:33:15+00:00"),
content=load_resource("content_spell.txt"),
)

spell = SpellParser.from_article(article)

self.assertIsInstance(spell, Spell)
self.assertEqual(spell.base_power, 45)


2 changes: 2 additions & 0 deletions tibiawikisql/models/spell.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class Spell(WikiEntry, WithVersion, WithStatus, WithImage, RowModel, table=Spell
"""The group of the rune created by this spell."""
element: str | None = Field(None)
"""The element of the damage made by the spell."""
base_power: int | None = Field(None)
"""The spell's base power, used to determine its damage or healing."""
mana: int
"""The mana cost of the spell."""
soul: int
Expand Down
2 changes: 2 additions & 0 deletions tibiawikisql/parsers/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class ItemParser(BaseParser):
"is_rotatable": "rotatable",
"augments": "augments",
"elemental_bond": "elementalbond",
"slot": "slot",
"base_power": "basepower",
}

@classmethod
Expand Down
1 change: 1 addition & 0 deletions tibiawikisql/parsers/spell.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class SpellParser(BaseParser):
"group_secondary": AttributeParser.optional("secondarygroup"),
"group_rune": AttributeParser.optional("runegroup"),
"element": AttributeParser.optional("damagetype"),
"base_power": AttributeParser.optional("basepower", parse_integer),
"mana": AttributeParser.optional("mana", parse_integer),
"soul": AttributeParser.optional("soul", parse_integer, 0),
"cooldown": AttributeParser.required("cooldown"),
Expand Down
1 change: 1 addition & 0 deletions tibiawikisql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ class SpellTable(Table):
group_secondary = Column(Text, index=True)
group_rune = Column(Text, index=True)
element = Column(Text, index=True)
base_power = Column(Integer)
level = Column(Integer)
mana = Column(Integer)
soul = Column(Integer, default=0)
Expand Down
Loading