mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-10 20:07:37 +00:00
feat(spell): let autoUnshift talk and use objects in the druid forms
1.12's SpellShapeshiftForm.dbc gives SHAPESHIFT_FORM_FLAG_CAN_INTERACT (0x8) only to Shadowform. 3.3.5 and 4.4.2 also give it to Cat, Travel, Aquatic, Bear, Dire Bear and Ghost Wolf, and Turtle's id 11 (Swift Travel Form) has it there too. So in the later clients, these forms pass the NPC right-click gate (CGPlayer_C::HandleOnRightClick, 0x005F0130) and the game-object use check (0x005F3130) as they are. The form cancel that comes before the range check almost never runs. In 1.12, autoUnshift cancelled every druid form at that gate, even when the NPC was out of interact range. With autoUnshift on, the redirected IsShapeShifted calls at both gates and at CanInteractNow (0x00606880) now read a form in that set as able to interact. They report "not shifted", so the engine's own 0x8 test that follows does not refuse it, and the cursor shows the NPC's service icon. The cancel stays for a form that cannot interact in either client. Neither vmangos nor tortoise-wow tests the form on an NPC or object interaction. CanInteractWithNPC and the use handlers have no form check; the only one is item use. So the client gates are the only refusal.
This commit is contained in:
@@ -221,7 +221,7 @@ open the game menu and click AddOn Options, then ClassicAPI.
|
||||
| [Combat log](docs/API.md#kept-entries) | `combatLogRetentionTime` | `300` | The number of seconds that the combat log keeps an entry. |
|
||||
| [Stand, dismount and form](docs/API.md#stand-dismount-and-form-settings-autostand-autodismount-autounshift) | `autoStand` | `0` | `1` makes you stand up when you cast, loot or open the flight map while you sit. |
|
||||
| | `autoDismount` | `0` | `1` makes you dismount when you cast, use an object, loot, attack or open the flight map while you are mounted. |
|
||||
| | `autoUnshift` | `0` | `1` makes you leave your form when you cast a spell that cannot be cast in it, talk to an NPC, use an object or an item, or open the flight map. |
|
||||
| | `autoUnshift` | `0` | `1` makes you leave your form when you cast a spell that cannot be cast in it, use an item, or open the flight map. It also lets you talk to NPCs and use objects in druid forms and Ghost Wolf. |
|
||||
| [Bag sorting](docs/API.md#c_containergetsortbagsrighttoleft--c_containersetsortbagsrighttoleftenable) | `sortBagsRightToLeft` | `0` | `1` makes a sort fill your bags from the last slot of the last bag. |
|
||||
| | `backpackAutosortDisabled` | `0` | `1` keeps the items in your backpack in place when you sort your bags. |
|
||||
| | `bankAutosortDisabled` | `0` | `1` keeps the items in the main bank slots in place when you sort your bank. |
|
||||
|
||||
+7
-5
@@ -22590,17 +22590,19 @@ The settings also apply to these actions:
|
||||
|
||||
| Action | `autoStand` | `autoDismount` | `autoUnshift` |
|
||||
|---|---|---|---|
|
||||
| Talk to an NPC | — | — | You leave the form. |
|
||||
| Use an object | — | You dismount. You stay mounted at a mailbox. | You leave the form. |
|
||||
| Talk to an NPC | — | — | You stay in the form. |
|
||||
| Use an object | — | You dismount. You stay mounted at a mailbox. | You stay in the form. |
|
||||
| Loot a creature | You stand up. | You dismount. | — |
|
||||
| Loot a corpse | You stand up. | — | — |
|
||||
| Use an item | — | — | You leave the form. |
|
||||
| Attack | — | You dismount. | — |
|
||||
| Open the flight map | You stand up. | You dismount. | You leave the form. |
|
||||
|
||||
A form that can talk and use objects, for example Shadowform, stays on when
|
||||
you talk to an NPC or use an object. While `autoUnshift` is `1`, the cursor
|
||||
over an NPC or an object shows its usual icon in such a form. While
|
||||
While `autoUnshift` is `1`, you can talk to NPCs and use objects in Cat Form,
|
||||
Bear Form, Dire Bear Form, Travel Form, Swift Travel Form, Aquatic Form and
|
||||
Ghost Wolf. The cursor over an NPC or an object shows its usual icon in these
|
||||
forms. In a form that cannot talk to NPCs or use objects, you leave the form.
|
||||
Shadowform can always talk to NPCs and use objects. While
|
||||
`autoDismount` is `1`, the cursor shows the attack icon over an enemy while
|
||||
you are mounted.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ CLASSICAPI_AUTO_DISMOUNT_TOOLTIP = "Dismount when you cast a spell, use an objec
|
||||
CLASSICAPI_AUTO_STAND = "Auto Stand";
|
||||
CLASSICAPI_AUTO_STAND_TOOLTIP = "Stand up when you cast a spell, loot, or open the flight map while you sit.";
|
||||
CLASSICAPI_AUTO_UNSHIFT = "Auto Cancel Form";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "Leave your form when you cast a spell that you cannot cast in it, talk to an NPC, use an object or an item, or open the flight map.";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "Leave your form when you cast a spell that you cannot cast in it, use an item, or open the flight map. Also lets you talk to NPCs and use objects in druid forms and Ghost Wolf.";
|
||||
CLASSICAPI_BAGS_AND_ITEMS = "Bags and Items";
|
||||
CLASSICAPI_CASTING_AND_ATTACKING = "Casting and Attacking";
|
||||
CLASSICAPI_COMBAT_LOG_RETENTION = "Combat Log Retention";
|
||||
|
||||
@@ -19,7 +19,7 @@ CLASSICAPI_AUTO_DISMOUNT_TOOLTIP = "Спешиваться при примене
|
||||
CLASSICAPI_AUTO_STAND = "Автоматически вставать";
|
||||
CLASSICAPI_AUTO_STAND_TOOLTIP = "Вставать при применении заклинания, сборе добычи или открытии карты полетов, если вы сидите.";
|
||||
CLASSICAPI_AUTO_UNSHIFT = "Автоматически снимать облик";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "Покидать свой облик при применении заклинания, которое в нем недоступно, разговоре с NPC, использовании объекта или предмета, а также при открытии карты полетов.";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "Покидать свой облик при применении заклинания, которое в нем недоступно, использовании предмета, а также при открытии карты полетов. Также позволяет говорить с NPC и использовать объекты в обликах друида и призрачного волка.";
|
||||
CLASSICAPI_BAGS_AND_ITEMS = "Сумки и предметы";
|
||||
CLASSICAPI_CASTING_AND_ATTACKING = "Заклинания и атаки";
|
||||
CLASSICAPI_COMBAT_LOG_RETENTION = "Хранение журнала боя";
|
||||
|
||||
@@ -19,7 +19,7 @@ CLASSICAPI_AUTO_DISMOUNT_TOOLTIP = "骑乘状态下施放法术、使用物体
|
||||
CLASSICAPI_AUTO_STAND = "自动站起";
|
||||
CLASSICAPI_AUTO_STAND_TOOLTIP = "坐下状态下施放法术、拾取或打开飞行地图时自动站起。";
|
||||
CLASSICAPI_AUTO_UNSHIFT = "自动取消形态";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "施放当前形态无法施放的法术、与NPC对话、使用物体或物品、或打开飞行地图时自动取消该形态。";
|
||||
CLASSICAPI_AUTO_UNSHIFT_TOOLTIP = "施放当前形态无法施放的法术、使用物品或打开飞行地图时自动取消该形态。同时允许在德鲁伊形态和幽魂之狼形态下与NPC对话和使用物体。";
|
||||
CLASSICAPI_BAGS_AND_ITEMS = "背包与物品";
|
||||
CLASSICAPI_CASTING_AND_ATTACKING = "施法与攻击";
|
||||
CLASSICAPI_COMBAT_LOG_RETENTION = "战斗记录保留时间";
|
||||
|
||||
@@ -40,6 +40,12 @@
|
||||
// cancel / stand before the cast packet that follows it.
|
||||
//
|
||||
// autoUnshift and autoDismount also cover interaction, as in 4.3.4:
|
||||
// - the interact flag: the later clients' SpellShapeshiftForm.dbc gives
|
||||
// SHAPESHIFT_FORM_FLAG_CAN_INTERACT to the druid forms and Ghost Wolf,
|
||||
// so 4.3.4 talks and uses objects in them without leaving the form.
|
||||
// 1.12's rows lack it; with autoUnshift on, the gates read it as the
|
||||
// later clients give it, so the cancels below are only for a form that
|
||||
// cannot interact in either client.
|
||||
// - NPC right-click: 4.3.4's CGPlayer_C::HandleOnRightClick cancels a form
|
||||
// without SHAPESHIFT_FORM_FLAG_CAN_INTERACT in place of
|
||||
// ERR_CANT_INTERACT_SHAPESHIFTED, before its range check, so we do the
|
||||
@@ -238,15 +244,43 @@ char IsShapeShifted(const void *unit) {
|
||||
return reinterpret_cast<IsShapeShifted_t>(Offsets::FUN_UNIT_IS_SHAPESHIFTED)(unit);
|
||||
}
|
||||
|
||||
// The gates' test after IsShapeShifted: a form with no row, or one
|
||||
// without the interact flag.
|
||||
bool FormBlocksInteraction(const void *unit) {
|
||||
return (FormFlags(unit) & Offsets::SHAPESHIFT_FORM_FLAG_CAN_INTERACT) == 0;
|
||||
// The forms whose SpellShapeshiftForm row has SHAPESHIFT_FORM_FLAG_CAN_-
|
||||
// INTERACT in 3.3.5 and 4.4.2 (both DBCs parsed) but not in 1.12: Cat (1),
|
||||
// Travel (3), Aquatic (4), Bear (5), Dire Bear (8), Ghost Wolf (16), and 11,
|
||||
// which Turtle uses for Swift Travel Form. Every other 1.12 form either has
|
||||
// the flag (Shadowform) or has flag bit 0 (Moonkin, Tree of Life, the
|
||||
// stances, Stealth), so IsShapeShifted does not count it and no gate tests
|
||||
// it. No 1.12 server tests the form on an NPC or object interaction
|
||||
// (vmangos / tortoise-wow CanInteractWithNPC and the use handlers), so the
|
||||
// client gates are the only refusal.
|
||||
constexpr int kLaterInteractForms[] = {1, 3, 4, 5, 8, 11, 16};
|
||||
|
||||
bool HasLaterInteractFlag(int form) {
|
||||
for (const int id : kLaterInteractForms) {
|
||||
if (id == form)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The gates' test after IsShapeShifted: the form row's interact flag. With
|
||||
// autoUnshift on, a form reads the flag that the later clients give it, so
|
||||
// the form stays on for the forms that can interact there.
|
||||
bool FormCanInteract(const void *unit) {
|
||||
if ((FormFlags(unit) & Offsets::SHAPESHIFT_FORM_FLAG_CAN_INTERACT) != 0)
|
||||
return true;
|
||||
return Enabled(g_autoUnshift) && HasLaterInteractFlag(Form(unit));
|
||||
}
|
||||
|
||||
// True when the gate would refuse and autoUnshift takes the form off instead.
|
||||
bool UnshiftsForInteraction(const void *player) {
|
||||
return IsShapeShifted(player) && FormBlocksInteraction(player) && CanAutoUnshift(player);
|
||||
return IsShapeShifted(player) && !FormCanInteract(player) && CanAutoUnshift(player);
|
||||
}
|
||||
|
||||
// The gates' IsShapeShifted: "not shifted" when the form can interact, so
|
||||
// the engine's own flag test that follows does not refuse it.
|
||||
char ShiftedForGate(const void *player) {
|
||||
return IsShapeShifted(player) && !FormCanInteract(player);
|
||||
}
|
||||
|
||||
// The NPC right-click's IsShapeShifted: leaves the form and reports "not
|
||||
@@ -256,14 +290,14 @@ char __fastcall IsShapeShiftedForTalk(const void *player) {
|
||||
CancelForm(player);
|
||||
return 0;
|
||||
}
|
||||
return IsShapeShifted(player);
|
||||
return ShiftedForGate(player);
|
||||
}
|
||||
|
||||
// The game-object use check's and CanInteractNow's IsShapeShifted (4.3.4's
|
||||
// CanUseNow / CanInteractNow): the same verdict, nothing done. Both are
|
||||
// hover-cursor queries, so the cursor shows the service while shifted.
|
||||
char __fastcall IsShapeShiftedForQuery(const void *player) {
|
||||
return UnshiftsForInteraction(player) ? 0 : IsShapeShifted(player);
|
||||
return UnshiftsForInteraction(player) ? 0 : ShiftedForGate(player);
|
||||
}
|
||||
|
||||
// The mount reads of the gates 4.3.4 passes on CanAutoDismount (an object
|
||||
|
||||
Reference in New Issue
Block a user