This commit is contained in:
李鹏宇
2026-09-20 20:34:42 +08:00
parent 527a391d51
commit 75268b6ec3
33 changed files with 280 additions and 53 deletions
+8 -4
View File
@@ -1049,9 +1049,12 @@ class YtWorldApi(http.Controller):
@http.route('/yt_world/api/equip/catalog', type='http', auth='public',
methods=['GET', 'OPTIONS'], csrf=False)
def equip_catalog(self, **kw):
"""装备目录(单一事实来源)。"""
items = request.env['yt.world.equip.item'].sudo().search([('active', '=', True)])
return _json({'ok': True, 'items': [it.to_dict() for it in items]})
"""装备目录(单一事实来源)。同时返回 slots 槽位真源列表,
前端面板据此动态渲染(含尚无装备的空槽位)。"""
Item = request.env['yt.world.equip.item'].sudo()
items = Item.search([('active', '=', True)])
slots = [{'value': v, 'label': l} for v, l in Item._fields['slot'].selection]
return _json({'ok': True, 'items': [it.to_dict() for it in items], 'slots': slots})
def _creature_by_cid(self, world, cid):
if not cid:
@@ -1093,7 +1096,8 @@ class YtWorldApi(http.Controller):
if action == 'equip':
slot = body.get('slot')
code = body.get('code')
if slot not in ('weapon', 'armor', 'accessory', 'boots'):
valid_slots = [s[0] for s in request.env['yt.world.equip.item']._fields['slot'].selection]
if slot not in valid_slots:
return _json({'ok': False, 'error': 'bad_slot'})
item = request.env['yt.world.equip.item'].sudo().search([('code', '=', code)], limit=1)
if not item:
@@ -125,4 +125,121 @@
<field name="stats">{"hp_max": 25, "energy_max": 15}</field>
<field name="desc">蕴含生命能量的护符,佩戴者精力更充沛。</field>
</record>
<!-- ================= 帽子 (hat) ================= -->
<record id="equip_straw_hat" model="yt.world.equip.item">
<field name="code">straw_hat</field>
<field name="name">草帽</field>
<field name="icon">assets/icons/equips/straw_hat.png</field>
<field name="slot">hat</field>
<field name="rarity">common</field>
<field name="stats">{"defense": 1}</field>
<field name="desc">编织草帽,遮阳挡雨,略增防护。</field>
</record>
<record id="equip_iron_helm" model="yt.world.equip.item">
<field name="code">iron_helm</field>
<field name="name">铁盔</field>
<field name="icon">assets/icons/equips/iron_helm.png</field>
<field name="slot">hat</field>
<field name="rarity">rare</field>
<field name="stats">{"defense": 3, "hp_max": 8}</field>
<field name="desc">冷锻铁盔,关键时刻护住头脸。</field>
</record>
<record id="equip_gold_crown" model="yt.world.equip.item">
<field name="code">gold_crown</field>
<field name="name">黄金王冠</field>
<field name="icon">assets/icons/equips/gold_crown.png</field>
<field name="slot">hat</field>
<field name="rarity">legendary</field>
<field name="stats">{"defense": 5, "hp_max": 20, "attack": 5}</field>
<field name="desc">象征权柄的黄金王冠,威仪凛然。</field>
</record>
<!-- ================= 裤子 (pants) ================= -->
<record id="equip_cloth_pants" model="yt.world.equip.item">
<field name="code">cloth_pants</field>
<field name="name">布裤</field>
<field name="icon">assets/icons/equips/cloth_pants.png</field>
<field name="slot">pants</field>
<field name="rarity">common</field>
<field name="stats">{"defense": 1}</field>
<field name="desc">轻便布裤,行动无碍。</field>
</record>
<record id="equip_iron_leggings" model="yt.world.equip.item">
<field name="code">iron_leggings</field>
<field name="name">铁护腿</field>
<field name="icon">assets/icons/equips/iron_leggings.png</field>
<field name="slot">pants</field>
<field name="rarity">rare</field>
<field name="stats">{"defense": 3, "hp_max": 10}</field>
<field name="desc">裹住小腿的铁片护腿,稳健可靠。</field>
</record>
<record id="equip_dragon_pants" model="yt.world.equip.item">
<field name="code">dragon_pants</field>
<field name="name">龙鳞战裤</field>
<field name="icon">assets/icons/equips/dragon_pants.png</field>
<field name="slot">pants</field>
<field name="rarity">legendary</field>
<field name="stats">{"defense": 6, "hp_max": 25}</field>
<field name="desc">龙鳞缀成的战裤,刀枪难入。</field>
</record>
<!-- ================= 护臂 (bracelet) ================= -->
<record id="equip_leather_bracer" model="yt.world.equip.item">
<field name="code">leather_bracer</field>
<field name="name">皮护腕</field>
<field name="icon">assets/icons/equips/leather_bracer.png</field>
<field name="slot">bracelet</field>
<field name="rarity">common</field>
<field name="stats">{"attack": 2}</field>
<field name="desc">皮质护腕,挥击更稳。</field>
</record>
<!-- 银手镯/龙纹手镯 归属饰品槽 (accessory) -->
<record id="equip_silver_bracer" model="yt.world.equip.item">
<field name="code">silver_bracer</field>
<field name="name">银手镯</field>
<field name="icon">assets/icons/equips/silver_bracer.png</field>
<field name="slot">accessory</field>
<field name="rarity">rare</field>
<field name="stats">{"attack": 4, "defense": 1}</field>
<field name="desc">嵌银手镯,攻防兼修。</field>
</record>
<record id="equip_dragon_bracelet" model="yt.world.equip.item">
<field name="code">dragon_bracelet</field>
<field name="name">龙纹手镯</field>
<field name="icon">assets/icons/equips/dragon_bracelet.png</field>
<field name="slot">accessory</field>
<field name="rarity">epic</field>
<field name="stats">{"attack": 8, "hp_max": 10}</field>
<field name="desc">刻龙纹的护腕,蓄力更猛。</field>
</record>
<!-- ================= 腰带 (belt) ================= -->
<record id="equip_rope_belt" model="yt.world.equip.item">
<field name="code">rope_belt</field>
<field name="name">麻绳腰带</field>
<field name="icon">assets/icons/equips/rope_belt.png</field>
<field name="slot">belt</field>
<field name="rarity">common</field>
<field name="stats">{"hp_max": 5}</field>
<field name="desc">粗麻绳束腰,勉强管用。</field>
</record>
<record id="equip_iron_belt" model="yt.world.equip.item">
<field name="code">iron_belt</field>
<field name="name">铁腰封</field>
<field name="icon">assets/icons/equips/iron_belt.png</field>
<field name="slot">belt</field>
<field name="rarity">rare</field>
<field name="stats">{"hp_max": 12, "defense": 2}</field>
<field name="desc">铁片腰封,护住躯干。</field>
</record>
<record id="equip_dragon_belt" model="yt.world.equip.item">
<field name="code">dragon_belt</field>
<field name="name">龙鳞腰带</field>
<field name="icon">assets/icons/equips/dragon_belt.png</field>
<field name="slot">belt</field>
<field name="rarity">epic</field>
<field name="stats">{"hp_max": 25, "defense": 4}</field>
<field name="desc">龙鳞束腰,根骨更稳。</field>
</record>
</odoo>
@@ -12,6 +12,7 @@
生物→世界→账号自动归属到对应玩家。
"""
from odoo import models, fields, api
from odoo.addons.yt_world.models.yt_world_equip_item import YtWorldEquipItem
class YtWorldEquipInstance(models.Model):
@@ -23,10 +24,10 @@ class YtWorldEquipInstance(models.Model):
required=True, ondelete='cascade', index=True)
owner_creature_id = fields.Many2one('yt.world.creature', string='拥有者生物',
ondelete='cascade', index=True)
# 已装备的部位;空值(False)表示在背包中未装备
# 已装备的部位;空值(False)表示在背包中未装备。
# 与 yt.world.equip.item 的 SLOT_SELECTION 共用同一份常量,避免两处各写一份槽位列表。
equipped_slot = fields.Selection(
[('weapon', '武器'), ('armor', '护甲'), ('accessory', '饰品'), ('boots', '鞋子')],
string='已装备部位', index=True)
YtWorldEquipItem.SLOT_SELECTION, string='已装备部位', index=True)
durability = fields.Integer(string='当前耐久', default=100)
max_durability = fields.Integer(string='最大耐久', default=100)
enhance_level = fields.Integer(string='强化等级', default=0)
@@ -21,9 +21,13 @@ class YtWorldEquipItem(models.Model):
code = fields.Char(string='编码', required=True, index=True)
name = fields.Char(string='名称', required=True)
icon = fields.Char(string='图标', default='⚔️')
slot = fields.Selection(
[('weapon', '武器'), ('armor', '护甲'), ('accessory', '饰品'), ('boots', '鞋子')],
string='部位', required=True)
# 部位槽位:单一真源。前端面板 / 实例表 / catalog 接口均以本选择项为准,
# 新增槽位只需在此追加(及 yt.world.equip.instance 的 equipped_slot),前端自动渲染。
SLOT_SELECTION = [
('weapon', '武器'), ('armor', '护甲'), ('accessory', '饰品'), ('boots', '鞋子'),
('hat', '帽子'), ('pants', '裤子'), ('bracelet', '护臂'), ('belt', '腰带'),
]
slot = fields.Selection(SLOT_SELECTION, string='部位', required=True)
rarity = fields.Selection(
[('common', '普通'), ('rare', '稀有'), ('epic', '史诗'), ('legendary', '传说')],
string='稀有度', default='common')
+3 -1
View File
@@ -298,8 +298,10 @@ class YtWorldCreature(models.Model):
catalog[it.code] = it.to_dict()
# 从装备实例表反查"当前已装备"的装备(实例 -> 模板对象),
# 保持前端 {slot: 对象} 结构不变,前端渲染零改动。
# 槽位列表直接取自装备图鉴模型的 SLOT_SELECTION(单一真源),新增槽位无需改此处。
equip_resolved = {}
for slot in ('weapon', 'armor', 'accessory', 'boots'):
equip_slots = [s[0] for s in self.env['yt.world.equip.item']._fields['slot'].selection]
for slot in equip_slots:
inst = self.env['yt.world.equip.instance'].sudo().search(
[('owner_creature_id', '=', self.id), ('equipped_slot', '=', slot)], limit=1)
if inst: