Skip to content

Commit 7bcebd6

Browse files
committed
Merge branch 'development'
2 parents a7b9674 + afccd8e commit 7bcebd6

30 files changed

+446
-71
lines changed

NWN.Anvil.csproj.DotSettings

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Casync/@EntryIndexedValue">True</s:Boolean>
44
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cconstants/@EntryIndexedValue">True</s:Boolean>
55
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cenginestructure/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cnative_005Cskillevents/@EntryIndexedValue">True</s:Boolean>
67
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cextensions/@EntryIndexedValue">True</s:Boolean>
78
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cobject/@EntryIndexedValue">True</s:Boolean>
89
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cscripts/@EntryIndexedValue">True</s:Boolean>
@@ -29,7 +30,7 @@
2930
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Casync_005Cawaiters/@EntryIndexedValue">True</s:Boolean>
3031
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cconstants_005Citemproperty/@EntryIndexedValue">True</s:Boolean>
3132
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cgame/@EntryIndexedValue">True</s:Boolean>
32-
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cnative/@EntryIndexedValue">False</s:Boolean>
33+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cnative/@EntryIndexedValue">True</s:Boolean>
3334
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cscript/@EntryIndexedValue">True</s:Boolean>
3435
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cnative_005Cassociateevents/@EntryIndexedValue">True</s:Boolean>
3536
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=src_005Cmain_005Canvil_005Capi_005Cevents_005Cnative_005Cbarterevents/@EntryIndexedValue">True</s:Boolean>

src/main/Anvil/API/Events/Game/GameEventFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private void UpdateEventScript(NwObject nwObject, EventScriptType eventType, boo
6767
return;
6868
}
6969

70-
Log.Debug($"Hooking native script event \"{eventType}\" on object \"{nwObject.Name}\". Previous script: \"{existingScript}\"");
70+
Log.Debug("Hooking native script event {EventType} on object {Object}. Previous script: {ExistingScript}", eventType, nwObject.Name, existingScript);
7171
NWScript.SetEventScript(nwObject, (int)eventType, ScriptConstants.GameEventScriptName);
7272

7373
if (callOriginal && !string.IsNullOrWhiteSpace(existingScript))

src/main/Anvil/API/Events/Native/BarterEvents/OnBarterEnd.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Runtime.InteropServices;
45
using Anvil.API.Events;
56
using Anvil.Internal;
@@ -126,8 +127,8 @@ private static OnBarterEnd GetBarterCancelledEventData(CNWSBarter initiator, CNW
126127
Initiator = initiator.m_pOwner.m_idSelf.ToNwPlayer(),
127128
Target = target.m_pOwner.m_idSelf.ToNwPlayer(),
128129
Complete = false,
129-
InitiatorItems = new NwItem[0],
130-
TargetItems = new NwItem[0],
130+
InitiatorItems = ImmutableArray<NwItem>.Empty,
131+
TargetItems = ImmutableArray<NwItem>.Empty,
131132
};
132133
}
133134

src/main/Anvil/API/Events/Native/DMEvents/DMEventFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ private static bool HandleSpawnEvent(void* pMessage, void* pPlayer, byte nMinor,
243243
Area = area,
244244
Position = new Vector3(x, y, z),
245245
ResRef = resRef,
246+
ObjectType = objectType,
246247
});
247248

248249
bool skipped = beforeEventData.Skip || !Hook.CallOriginal(pMessage, pPlayer, nMinor, bGroup).ToBool();

src/main/Anvil/API/Events/Native/DMEvents/OnDMSpawnObject.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public sealed class OnDMSpawnObjectBefore : OnDMSpawnObject
2323
public Vector3 Position { get; internal init; }
2424

2525
public string ResRef { get; internal init; }
26+
27+
public ObjectTypes ObjectType { get; internal init; }
2628
}
2729

2830
public sealed class OnDMSpawnObjectAfter : OnDMSpawnObject
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Anvil.API.Events;
4+
using Anvil.Services;
5+
using NWN.Native.API;
6+
7+
namespace Anvil.API.Events
8+
{
9+
/// <summary>
10+
/// Called when a creature is about to learn a spell from a scroll.
11+
/// </summary>
12+
public sealed class OnItemScrollLearn : IEvent
13+
{
14+
/// <summary>
15+
/// Gets the creature learning the scroll.
16+
/// </summary>
17+
public NwCreature Creature { get; private init; }
18+
19+
/// <summary>
20+
/// Gets the scroll that is being learnt.
21+
/// </summary>
22+
public NwItem Scroll { get; private init; }
23+
24+
/// <summary>
25+
/// Gets or sets whether this scroll should be prevented from being learned.
26+
/// </summary>
27+
public bool PreventLearnScroll { get; set; }
28+
29+
NwObject IEvent.Context
30+
{
31+
get => Creature;
32+
}
33+
34+
internal sealed unsafe class Factory : SingleHookEventFactory<Factory.LearnScrollHook>
35+
{
36+
internal delegate int LearnScrollHook(void* pCreature, uint oidScrollToLearn);
37+
38+
protected override FunctionHook<LearnScrollHook> RequestHook()
39+
{
40+
delegate* unmanaged<void*, uint, int> pHook = &OnLearnScroll;
41+
return HookService.RequestHook<LearnScrollHook>(pHook, FunctionsLinux._ZN12CNWSCreature11LearnScrollEj, HookOrder.Early);
42+
}
43+
44+
[UnmanagedCallersOnly]
45+
private static int OnLearnScroll(void* pCreature, uint oidScrollToLearn)
46+
{
47+
OnItemScrollLearn eventData = ProcessEvent(new OnItemScrollLearn
48+
{
49+
Creature = CNWSCreature.FromPointer(pCreature).ToNwObject<NwCreature>(),
50+
Scroll = oidScrollToLearn.ToNwObject<NwItem>(),
51+
});
52+
53+
return !eventData.PreventLearnScroll ? Hook.CallOriginal(pCreature, oidScrollToLearn) : false.ToInt();
54+
}
55+
}
56+
}
57+
}
58+
59+
namespace Anvil.API
60+
{
61+
public sealed partial class NwCreature
62+
{
63+
/// <inheritdoc cref="Events.OnItemScrollLearn"/>
64+
public event Action<OnItemScrollLearn> OnItemScrollLearn
65+
{
66+
add => EventService.Subscribe<OnItemScrollLearn, OnItemScrollLearn.Factory>(this, value);
67+
remove => EventService.Unsubscribe<OnItemScrollLearn, OnItemScrollLearn.Factory>(this, value);
68+
}
69+
}
70+
71+
public sealed partial class NwModule
72+
{
73+
/// <inheritdoc cref="Events.OnItemScrollLearn"/>
74+
public event Action<OnItemScrollLearn> OnItemScrollLearn
75+
{
76+
add => EventService.SubscribeAll<OnItemScrollLearn, OnItemScrollLearn.Factory>(value);
77+
remove => EventService.UnsubscribeAll<OnItemScrollLearn, OnItemScrollLearn.Factory>(value);
78+
}
79+
}
80+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Anvil.API.Events;
4+
using NWN.Native.API;
5+
using Anvil.Services;
6+
7+
namespace Anvil.API.Events
8+
{
9+
/// <summary>
10+
/// Called when a creature attempts to unequip an item.
11+
/// </summary>
12+
public sealed class OnItemUnequip : IEvent
13+
{
14+
/// <summary>
15+
/// Gets the creature who is uneqipping an item.
16+
/// </summary>
17+
public NwCreature Creature { get; private init; }
18+
19+
/// <summary>
20+
/// Gets the item being unequipped.
21+
/// </summary>
22+
public NwItem Item { get; private init; }
23+
24+
/// <summary>
25+
/// Gets or sets whether this item should be prevented from being unequipped.
26+
/// </summary>
27+
public bool PreventUnequip { get; set; }
28+
29+
NwObject IEvent.Context
30+
{
31+
get => Creature;
32+
}
33+
34+
internal sealed unsafe class Factory : SingleHookEventFactory<Factory.UnequipItemHook>
35+
{
36+
internal delegate int UnequipItemHook(void* pCreature, uint oidItemToUnequip, uint oidTargetRepository, byte x, byte y, int bMergeIntoRepository, uint oidFeedbackPlayer);
37+
38+
protected override FunctionHook<UnequipItemHook> RequestHook()
39+
{
40+
delegate* unmanaged<void*, uint, uint, byte, byte, int, uint, int> pHook = &OnUnequipItem;
41+
return HookService.RequestHook<UnequipItemHook>(pHook, FunctionsLinux._ZN12CNWSCreature10RunUnequipEjjhhij, HookOrder.Early);
42+
}
43+
44+
[UnmanagedCallersOnly]
45+
private static int OnUnequipItem(void* pCreature, uint oidItemToUnequip, uint oidTargetRepository, byte x, byte y, int bMergeIntoRepository, uint oidFeedbackPlayer)
46+
{
47+
OnItemUnequip eventData = ProcessEvent(new OnItemUnequip
48+
{
49+
Creature = CNWSCreature.FromPointer(pCreature).ToNwObject<NwCreature>(),
50+
Item = oidItemToUnequip.ToNwObject<NwItem>(),
51+
});
52+
53+
return !eventData.PreventUnequip ? Hook.CallOriginal(pCreature, oidItemToUnequip, oidTargetRepository, x, y, bMergeIntoRepository, oidFeedbackPlayer) : false.ToInt();
54+
}
55+
}
56+
}
57+
}
58+
59+
namespace Anvil.API
60+
{
61+
public sealed partial class NwCreature
62+
{
63+
/// <inheritdoc cref="Events.OnItemUnequip"/>
64+
public event Action<OnItemUnequip> OnItemUnequip
65+
{
66+
add => EventService.Subscribe<OnItemUnequip, OnItemUnequip.Factory>(this, value);
67+
remove => EventService.Unsubscribe<OnItemUnequip, OnItemUnequip.Factory>(this, value);
68+
}
69+
}
70+
71+
public sealed partial class NwModule
72+
{
73+
/// <inheritdoc cref="Events.OnItemUnequip"/>
74+
public event Action<OnItemUnequip> OnItemUnequip
75+
{
76+
add => EventService.SubscribeAll<OnItemUnequip, OnItemUnequip.Factory>(value);
77+
remove => EventService.UnsubscribeAll<OnItemUnequip, OnItemUnequip.Factory>(value);
78+
}
79+
}
80+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using System.Numerics;
3+
using System.Runtime.InteropServices;
4+
using Anvil.API.Events;
5+
using NWN.Native.API;
6+
using Anvil.Services;
7+
8+
namespace Anvil.API.Events
9+
{
10+
/// <summary>
11+
/// Called when a creature attempts to use a skill.
12+
/// </summary>
13+
public sealed class OnUseSkill : IEvent
14+
{
15+
/// <summary>
16+
/// Gets the creature using the skill.
17+
/// </summary>
18+
public NwCreature Creature { get; private init; }
19+
20+
/// <summary>
21+
/// Gets the skill that is being used.
22+
/// </summary>
23+
public Skill Skill { get; private init; }
24+
25+
/// <summary>
26+
/// Gets the SubSkill (if any) that is being used.
27+
/// </summary>
28+
public SubSkill SubSkill { get; private init; }
29+
30+
/// <summary>
31+
/// Gets the target object for this skill usage.
32+
/// </summary>
33+
public NwGameObject Target { get; private init; }
34+
35+
/// <summary>
36+
/// Gets the area that the skill was used.
37+
/// </summary>
38+
public NwArea Area { get; private init; }
39+
40+
/// <summary>
41+
/// Gets the item that is being used, if any.
42+
/// </summary>
43+
public NwItem UsedItem { get; private init; }
44+
45+
/// <summary>
46+
/// Gets the target position for this skill usage.
47+
/// </summary>
48+
public Vector3 TargetPosition { get; private init; }
49+
50+
/// <summary>
51+
/// Gets or sets whether usage of this skill should be prevented.
52+
/// </summary>
53+
public bool PreventSkillUse { get; set; }
54+
55+
NwObject IEvent.Context
56+
{
57+
get => Creature;
58+
}
59+
60+
internal sealed unsafe class Factory : SingleHookEventFactory<Factory.UseSkillHook>
61+
{
62+
internal delegate int UseSkillHook(void* pCreature, byte nSkill, byte nSubSkill, uint oidTarget, Vector3 vTargetPosition, uint oidArea, uint oidUsedItem, int nActivePropertyIndex);
63+
64+
protected override FunctionHook<UseSkillHook> RequestHook()
65+
{
66+
delegate* unmanaged<void*, byte, byte, uint, Vector3, uint, uint, int, int> pHook = &OnUseSkill;
67+
return HookService.RequestHook<UseSkillHook>(pHook, FunctionsLinux._ZN12CNWSCreature8UseSkillEhhj6Vectorjji, HookOrder.Early);
68+
}
69+
70+
[UnmanagedCallersOnly]
71+
private static int OnUseSkill(void* pCreature, byte nSkill, byte nSubSkill, uint oidTarget, Vector3 vTargetPosition, uint oidArea, uint oidUsedItem, int nActivePropertyIndex)
72+
{
73+
OnUseSkill eventData = ProcessEvent(new OnUseSkill
74+
{
75+
Creature = CNWSCreature.FromPointer(pCreature).ToNwObject<NwCreature>(),
76+
Skill = (Skill)nSkill,
77+
SubSkill = (SubSkill)nSubSkill,
78+
Target = oidTarget.ToNwObject<NwGameObject>(),
79+
Area = oidArea.ToNwObject<NwArea>(),
80+
UsedItem = oidUsedItem.ToNwObject<NwItem>(),
81+
TargetPosition = vTargetPosition,
82+
});
83+
84+
return !eventData.PreventSkillUse ? Hook.CallOriginal(pCreature, nSkill, nSubSkill, oidTarget, vTargetPosition, oidArea, oidUsedItem, nActivePropertyIndex) : false.ToInt();
85+
}
86+
}
87+
}
88+
}
89+
90+
namespace Anvil.API
91+
{
92+
public sealed partial class NwCreature
93+
{
94+
/// <inheritdoc cref="Events.OnUseSkill"/>
95+
public event Action<OnUseSkill> OnUseSkill
96+
{
97+
add => EventService.Subscribe<OnUseSkill, OnUseSkill.Factory>(this, value);
98+
remove => EventService.Unsubscribe<OnUseSkill, OnUseSkill.Factory>(this, value);
99+
}
100+
}
101+
102+
public sealed partial class NwModule
103+
{
104+
/// <inheritdoc cref="Events.OnUseSkill"/>
105+
public event Action<OnUseSkill> OnUseSkill
106+
{
107+
add => EventService.SubscribeAll<OnUseSkill, OnUseSkill.Factory>(value);
108+
remove => EventService.UnsubscribeAll<OnUseSkill, OnUseSkill.Factory>(value);
109+
}
110+
}
111+
}

src/main/Anvil/API/Object/CreatureLevelInfo.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,25 @@ public byte HitDie
6565
get => levelStats.m_nHitDie;
6666
set => levelStats.m_nHitDie = value;
6767
}
68+
69+
/// <summary>
70+
/// Gets the skill ranks for the specified skill on this creature level.
71+
/// </summary>
72+
/// <param name="skill">The skill to query.</param>
73+
/// <returns>The number of skill ranks.</returns>
74+
public sbyte GetSkillRank(Skill skill)
75+
{
76+
return levelStats.m_lstSkillRanks[(int)skill].AsSByte();
77+
}
78+
79+
/// <summary>
80+
/// Sets the skill ranks for the specified skill on this creature level.
81+
/// </summary>
82+
/// <param name="skill">The skill to modify.</param>
83+
/// <param name="rank">The new number of skill ranks.</param>
84+
public void SetSkillRank(Skill skill, sbyte rank)
85+
{
86+
levelStats.m_lstSkillRanks[(int)skill] = rank.AsByte();
87+
}
6888
}
6989
}

0 commit comments

Comments
 (0)