fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// Public M2Client argument bounds shared by the Classic and m2dev backends.
|
||||
#include "../src/net/net_bounds.h"
|
||||
#include "../src/net/item_action_rules.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
@@ -21,6 +22,16 @@ int main() {
|
||||
CHECK(u32(0) && u32(0xffffffffLL) && !u32(-1), "u32 range");
|
||||
CHECK(i32(-2147483648LL) && i32(2147483647LL), "i32 accepts signed range");
|
||||
CHECK(!i32(-2147483649LL) && !i32(2147483648LL), "i32 rejects outside range");
|
||||
// ClientVS22 uicharacter.py sends quest-log buttons as
|
||||
// (INT32_MIN + questIndex), then the packet stores the bit pattern in a
|
||||
// uint32. The public GDScript API must allow that sentinel range while
|
||||
// rejecting arbitrary negative values.
|
||||
CHECK(script_button_index(0) && script_button_index(65535),
|
||||
"script button accepts ordinary and quest-index endpoints");
|
||||
CHECK(script_button_index(-2147483648LL) && script_button_index(-2147418113LL),
|
||||
"script button accepts INT32_MIN quest sentinel range");
|
||||
CHECK(!script_button_index(-2147483649LL) && !script_button_index(-2147418112LL),
|
||||
"script button rejects values outside quest sentinel range");
|
||||
|
||||
CHECK(quick_slot(0) && quick_slot(35), "quick slot endpoints");
|
||||
CHECK(!quick_slot(-1) && !quick_slot(36), "quick slot outside range");
|
||||
@@ -34,6 +45,54 @@ int main() {
|
||||
CHECK(skill_index(1) && skill_index(254), "skill index endpoints");
|
||||
CHECK(!skill_index(0) && !skill_index(255) && !skill_index(-1), "skill index outside range");
|
||||
CHECK(!skill_index(0x7fffffffLL + 1), "skill index rejects large value");
|
||||
CHECK(refine_request(0, 0, 90) && refine_request(89, 3, 90),
|
||||
"refine accepts inventory positions");
|
||||
CHECK(refine_request(255, 255, 90), "refine accepts the 40250 cancel sentinel");
|
||||
CHECK(!refine_request(90, 0, 90) && !refine_request(255, 0, 90)
|
||||
&& !refine_request(0, 255, 90), "refine rejects invalid non-sentinel requests");
|
||||
|
||||
// ClientVS22 TItemPos::IsValidCell() parity: a wire-sized integer is not
|
||||
// automatically a valid inventory position.
|
||||
CHECK(item_cell(1, 0) && item_cell(1, 167), "inventory cell endpoints");
|
||||
CHECK(!item_cell(1, 168) && !item_cell(1, 65535), "inventory cell outside range");
|
||||
CHECK(item_cell(2, 0) && item_cell(2, 133), "equipment window endpoints");
|
||||
CHECK(!item_cell(2, 134), "equipment window outside range");
|
||||
CHECK(item_cell(5, 179) && !item_cell(5, 180), "dragon soul cell range");
|
||||
CHECK(item_cell(7, 15) && !item_cell(7, 16), "belt cell range");
|
||||
CHECK(!item_cell(3, 0) && !item_cell(0, 0), "unsupported item windows rejected");
|
||||
|
||||
using namespace mtnet::item_action;
|
||||
CHECK(is_equipment_type(1) && is_equipment_type(2),
|
||||
"CItemData::IsEquipment accepts weapon and armor");
|
||||
CHECK(!is_equipment_type(3) && !is_equipment_type(28) && !is_equipment_type(33),
|
||||
"CItemData::IsEquipment rejects use, costume and ring types");
|
||||
CHECK(use_sound_type(1, 2) == ItemSoundType::Bow,
|
||||
"weapon bow uses the bow sound");
|
||||
CHECK(use_sound_type(1, 6) == ItemSoundType::Default,
|
||||
"weapon arrow uses the default sound");
|
||||
CHECK(use_sound_type(2, 0) == ItemSoundType::Armor &&
|
||||
use_sound_type(2, 5) == ItemSoundType::Accessory,
|
||||
"body and accessory armor use their reference sounds");
|
||||
CHECK(use_sound_type(3, 7) == ItemSoundType::Potion &&
|
||||
use_sound_type(3, 0) == ItemSoundType::None &&
|
||||
use_sound_type(3, 1) == ItemSoundType::Portal,
|
||||
"use-item sound branches match ability-up, potion, talisman");
|
||||
CHECK(drop_sound_type(1, 2) == ItemSoundType::Bow &&
|
||||
drop_sound_type(2, 0) == ItemSoundType::Armor &&
|
||||
drop_sound_type(3, 7) == ItemSoundType::Default,
|
||||
"drop sound branches match weapon, armor and default items");
|
||||
Context action{};
|
||||
action.has_main = true;
|
||||
CHECK(can_act_main(action), "item action allowed for a live main actor");
|
||||
action.dead = true;
|
||||
CHECK(!can_act_main(action), "item action blocked for a dead main actor");
|
||||
action.dead = false;
|
||||
action.exchange_active = true;
|
||||
CHECK(!can_touch_equipment(action, true), "equipment action blocked during exchange");
|
||||
CHECK(can_touch_equipment(action, false), "non-equipment action remains allowed during exchange");
|
||||
action.exchange_active = false;
|
||||
action.attacking = true;
|
||||
CHECK(!can_touch_equipment(action, true), "equipment action blocked while attacking");
|
||||
|
||||
if (g_fail) {
|
||||
std::fprintf(stderr, "%d checks FAILED\n", g_fail);
|
||||
|
||||
Reference in New Issue
Block a user