1+ package dev .overgrown .thaumaturge .spell .impl .potentia ;
2+
3+ import dev .overgrown .aspectslib .AspectsLib ;
4+ import dev .overgrown .thaumaturge .registry .ModEntities ;
5+ import dev .overgrown .thaumaturge .registry .ModSounds ;
6+ import dev .overgrown .thaumaturge .spell .impl .potentia .entity .SpellBoltEntity ;
7+ import dev .overgrown .thaumaturge .spell .modifier .ModifierEffect ;
8+ import dev .overgrown .thaumaturge .spell .modifier .PowerModifierEffect ;
9+ import dev .overgrown .thaumaturge .spell .modifier .ScatterModifierEffect ;
10+ import dev .overgrown .thaumaturge .spell .pattern .AspectEffect ;
11+ import dev .overgrown .thaumaturge .spell .pattern .AspectRegistry ;
12+ import dev .overgrown .thaumaturge .spell .tier .AoeSpellDelivery ;
13+ import dev .overgrown .thaumaturge .spell .tier .SelfSpellDelivery ;
14+ import dev .overgrown .thaumaturge .spell .tier .TargetedSpellDelivery ;
15+ import dev .overgrown .thaumaturge .spell .utils .SpellHandler ;
16+ import net .minecraft .entity .Entity ;
17+ import net .minecraft .entity .LivingEntity ;
18+ import net .minecraft .entity .damage .DamageSource ;
19+ import net .minecraft .entity .damage .DamageTypes ;
20+ import net .minecraft .item .ItemStack ;
21+ import net .minecraft .server .network .ServerPlayerEntity ;
22+ import net .minecraft .sound .SoundCategory ;
23+ import net .minecraft .util .Identifier ;
24+ import net .minecraft .util .hit .BlockHitResult ;
25+ import net .minecraft .util .math .Vec3d ;
26+ import net .minecraft .world .World ;
27+
28+ import java .util .ArrayList ;
29+ import java .util .List ;
30+ import java .util .Map ;
31+ import java .util .function .Consumer ;
32+
33+ public class PotentiaEffect implements AspectEffect {
34+ private static final float BASE_DAMAGE = 2.0f ;
35+ private static final float SCATTER_DAMAGE_MULTIPLIER = 0.7f ;
36+
37+ @ Override
38+ public void applySelf (SelfSpellDelivery delivery ) {
39+ // Self-cast not implemented for Potentia (yet)
40+ }
41+
42+ @ Override
43+ public void applyTargeted (TargetedSpellDelivery delivery ) {
44+ ServerPlayerEntity caster = delivery .getCaster ();
45+ World world = delivery .getWorld ();
46+
47+ // Play sound
48+ world .playSound (
49+ null ,
50+ caster .getX (), caster .getY (), caster .getZ (),
51+ ModSounds .POTENTIA_SPELL_CAST ,
52+ SoundCategory .PLAYERS ,
53+ 1.0F , 1.0F ,
54+ world .random .nextLong ()
55+ );
56+
57+ // Get pattern from gauntlet
58+ ItemStack gauntlet = SpellHandler .findGauntlet (caster );
59+ if (gauntlet .isEmpty ()) return ;
60+
61+ dev .overgrown .thaumaturge .spell .pattern .SpellPattern pattern =
62+ dev .overgrown .thaumaturge .spell .pattern .SpellPattern .fromGauntlet (gauntlet , "advanced" );
63+ if (pattern == null ) return ;
64+
65+ // Get Potentia modifier
66+ Identifier potentiaId = AspectsLib .identifier ("potentia" );
67+ Identifier modifierId = pattern .getAspects ().get (potentiaId );
68+ ModifierEffect modifier = modifierId != null ?
69+ dev .overgrown .thaumaturge .spell .modifier .ModifierRegistry .get (modifierId ) : null ;
70+
71+ // Get carried aspects (excluding Potentia)
72+ Map <Identifier , Identifier > carriedAspects = new java .util .HashMap <>();
73+ for (Map .Entry <Identifier , Identifier > entry : pattern .getAspects ().entrySet ()) {
74+ if (!entry .getKey ().equals (potentiaId )) {
75+ carriedAspects .put (entry .getKey (), entry .getValue ());
76+ }
77+ }
78+
79+ boolean hasCarriedAspects = !carriedAspects .isEmpty ();
80+
81+ // Calculate damage multiplier
82+ float damageMultiplier = 1.0f ;
83+ if (modifier instanceof PowerModifierEffect powerMod ) {
84+ damageMultiplier = powerMod .getMultiplier ();
85+ }
86+
87+ // Handle scatter modifier
88+ if (modifier instanceof ScatterModifierEffect scatterMod ) {
89+ List <Vec3d > directions = scatterMod .scatterAround (
90+ caster .getRotationVec (1.0F ),
91+ world .getRandom ()
92+ );
93+
94+ for (Vec3d dir : directions ) {
95+ createBolt (
96+ caster , world , dir ,
97+ carriedAspects , hasCarriedAspects ,
98+ damageMultiplier * SCATTER_DAMAGE_MULTIPLIER
99+ );
100+ }
101+ } else {
102+ createBolt (
103+ caster , world , caster .getRotationVec (1.0F ),
104+ carriedAspects , hasCarriedAspects ,
105+ damageMultiplier
106+ );
107+ }
108+ }
109+
110+ @ Override
111+ public void applyAoe (AoeSpellDelivery delivery ) {
112+ // AOE not implemented for Potentia (yet)
113+ }
114+
115+ private void createBolt (ServerPlayerEntity caster , World world , Vec3d direction ,
116+ Map <Identifier , Identifier > carriedAspects ,
117+ boolean hasCarriedAspects , float damageMultiplier ) {
118+ SpellBoltEntity bolt = new SpellBoltEntity (ModEntities .SPELL_BOLT , world );
119+ bolt .setPosition (caster .getX (), caster .getEyeY (), caster .getZ ());
120+ bolt .setCaster (caster );
121+ bolt .setVelocity (direction .multiply (1.5 ));
122+
123+ // Setup bolt effects
124+ List <Consumer <Entity >> onHitEffects = new ArrayList <>();
125+ List <Consumer <BlockHitResult >> onBlockHitEffects = new ArrayList <>();
126+
127+ if (hasCarriedAspects ) {
128+ // Add effects for carried aspects
129+ for (Map .Entry <Identifier , Identifier > entry : carriedAspects .entrySet ()) {
130+ AspectEffect effect = AspectRegistry .get (entry .getKey ()).orElse (null );
131+ ModifierEffect modifier = entry .getValue () != null ?
132+ dev .overgrown .thaumaturge .spell .modifier .ModifierRegistry .get (entry .getValue ()) : null ;
133+
134+ if (effect != null ) {
135+ onHitEffects .add ((entity ) -> {
136+ if (entity instanceof LivingEntity livingEntity ) {
137+ TargetedSpellDelivery hitDelivery =
138+ new TargetedSpellDelivery (caster , livingEntity );
139+ if (modifier != null ) {
140+ hitDelivery .setModifiers (java .util .Collections .singletonList (modifier ));
141+ }
142+ effect .applyTargeted (hitDelivery );
143+ }
144+ });
145+
146+ onBlockHitEffects .add ((blockHitResult ) -> {
147+ TargetedSpellDelivery hitDelivery =
148+ new TargetedSpellDelivery (caster , blockHitResult .getBlockPos (), blockHitResult .getSide ());
149+ if (modifier != null ) {
150+ hitDelivery .setModifiers (java .util .Collections .singletonList (modifier ));
151+ }
152+ effect .applyTargeted (hitDelivery );
153+ });
154+ }
155+ }
156+ } else {
157+ // Default lightning damage
158+ onHitEffects .add ((entity ) -> {
159+ float damage = BASE_DAMAGE * damageMultiplier ;
160+ DamageSource damageSource = world .getDamageSources ().create (DamageTypes .LIGHTNING_BOLT , caster );
161+ entity .damage (damageSource , damage );
162+ });
163+ }
164+
165+ bolt .setOnHitEffects (onHitEffects );
166+ bolt .setOnBlockHitEffects (onBlockHitEffects );
167+
168+ world .spawnEntity (bolt );
169+ }
170+ }
0 commit comments