4545import com .programmerdan .minecraft .addgun .ammo .Clip ;
4646
4747import static com .programmerdan .minecraft .addgun .guns .Utilities .getArmorType ;
48+ import static com .programmerdan .minecraft .addgun .guns .Utilities .computeTotalXP ;
4849
4950public class StandardGun implements BasicGun {
51+
52+ private static double [] protectionCurve = new double [] {
53+ 0.0d ,
54+ -0.25 * Math .log (1.0 / (1.0 + 1.0 )),
55+ -0.25 * Math .log (1.0 / (2.0 + 1.0 )),
56+ -0.25 * Math .log (1.0 / (3.0 + 1.0 )),
57+ -0.25 * Math .log (1.0 / (4.0 + 1.0 )),
58+ -0.25 * Math .log (1.0 / (5.0 + 1.0 )),
59+ -0.25 * Math .log (1.0 / (6.0 + 1.0 )),
60+ -0.25 * Math .log (1.0 / (7.0 + 1.0 )),
61+ -0.25 * Math .log (1.0 / (8.0 + 1.0 )),
62+ -0.25 * Math .log (1.0 / (9.0 + 1.0 )),
63+ -0.25 * Math .log (1.0 / (10.0 + 1.0 )),
64+ -0.25 * Math .log (1.0 / (11.0 + 1.0 )),
65+ -0.25 * Math .log (1.0 / (12.0 + 1.0 )),
66+ -0.25 * Math .log (1.0 / (13.0 + 1.0 )),
67+ -0.25 * Math .log (1.0 / (14.0 + 1.0 )),
68+ -0.25 * Math .log (1.0 / (15.0 + 1.0 )),
69+ };
70+
71+ private static double baseProjectileProtection = 1.0d ;
72+ private static double baseEnvironmentProtection = 0.25d ;
73+ private static double baseUnbreakingProtection = 0.33d ;
74+
5075 /**
5176 * Is this gun enabled?
5277 */
@@ -203,7 +228,9 @@ protected StandardGun(String name) {
203228 + Integer .toHexString (this .getName ().hashCode () + this .getName ().length ());
204229 }
205230
206- public abstract ItemStack generateGun ();
231+ public ItemStack generateGun () {
232+ return gunExample .clone ();
233+ }
207234
208235 public boolean isEnabled () {
209236 return enabled ;
@@ -441,7 +468,11 @@ public void manageHit(HitDigest hitData, Entity hit, Projectile bullet, Bullet b
441468 }
442469
443470 /**
444- * Override this class, you use it to manage what happens when something damageable is hit.
471+ * This is a complex method. It handles the various hitvectors and computations of damage both to
472+ * player/entity and armor. I'll write up a full explanation in the documentation of configuration.
473+ *
474+ * For now it suffices that depending on _where_ the damage is done, and what is being worn there, depends
475+ * on the nature of the damage inflicted.
445476 *
446477 * @param hitData the Data matrix showing hit information
447478 * @param hit the damageable entity that was struck
@@ -465,9 +496,14 @@ public void manageDamage(HitDigest hitData, Damageable hit, Projectile bullet, B
465496 ItemStack shield = null ;
466497 double shieldEffectiveness = 0.0d ;
467498
499+ LivingEntity living = null ;
500+ EntityEquipment equipment = null ;
501+
502+ HumanEntity human = null ;
503+
468504 if (hit instanceof LivingEntity ) {
469- LivingEntity living = (LivingEntity ) hit ;
470- EntityEquipment equipment = living .getEquipment ();
505+ living = (LivingEntity ) hit ;
506+ equipment = living .getEquipment ();
471507 // now reductions?
472508 switch (hitData .nearestHitPart ) {
473509 case BODY :
@@ -498,14 +534,14 @@ public void manageDamage(HitDigest hitData, Damageable hit, Projectile bullet, B
498534 break ;
499535 case MISS : // no hit?
500536 nearMiss (hitData , hit , bullet , bulletType );
501- break ;
537+ return ;
502538 default :
503539 break ;
504540 }
505541
506542 if (shield != null && Material .SHIELD .equals (shield .getType ())) {
507543 if (hit instanceof HumanEntity ) {
508- HumanEntity human = (HumanEntity ) hit ;
544+ human = (HumanEntity ) hit ;
509545 if (human .isBlocking ()) {
510546 shieldEffectiveness = 1.0d ;
511547 } else if (human .isHandRaised ()) {
@@ -516,28 +552,134 @@ public void manageDamage(HitDigest hitData, Damageable hit, Projectile bullet, B
516552 shield = null ;
517553 }
518554 }
555+
556+ if (shield != null ) {
557+ // check bypass?
558+ double angle = Math .toDegrees (hit .getLocation ().getDirection ().angle (speed ));
559+ // TODO?!?! check this
560+ if (angle >= -135 && angle < 135 ) {
561+ // no deflection!
562+ shieldEffectiveness = 0.0d ;
563+ }
564+
565+ finalDamage *= (1.0 - shieldEffectiveness );
566+
567+ AddGun .getPlugin ().debug (String .format ("Base damage of %.2f, Has shield %s, angle of %.2f, effectiveness %.2f, final Damage %.2f" ,
568+ baseRealDamage , shield , angle , shieldEffectiveness , finalDamage ));
569+
570+ int unbLevel = shield .getEnchantmentLevel (Enchantment .DURABILITY );
571+
572+ // Basically, unbreaking reduces the amount of durability damage that the armor will sustain
573+ double unbReduction = (1.0 + StandardGun .baseUnbreakingProtection * StandardGun .protectionCurve [unbLevel ]);
574+ double finalDuraDamage = baseRealDamage * (1.0 - (1.0 - bulletType .getArmorDamage (ArmorType .SHIELD )) * unbReduction );
575+ if (shield .getDurability () < finalDuraDamage ) {
576+ // broken.
577+ double directDamage = finalDuraDamage - shield .getDurability ();
578+
579+ finalDamage += directDamage ; // this is the bit of damage the shield was meant to absorb, but didn't.
580+
581+ shield = null ;
582+
583+ AddGun .getPlugin ().debug (String .format ("Shield broken by dura damage %.2f, adding the remaining %.2f to the player damage" ,
584+ finalDuraDamage , directDamage ));
585+ } else {
586+ shield .setDurability ((short ) (shield .getDurability () - Math .round (finalDuraDamage )));
587+
588+ AddGun .getPlugin ().debug (String .format ("Shield damaged by %.2f" , finalDuraDamage ));
589+ }
590+ }
591+
592+ // reset base damage
593+ baseRealDamage = finalDamage ;
519594
520- if (armorHit != null ) {
595+ if (armorHit != null && baseRealDamage > 0.0d ) {
521596 // check bypass?
522597
523598 // check armor type
524599 ArmorType grade = getArmorType (armorHit .getType ());
525600 int protLevel = armorHit .getEnchantmentLevel (Enchantment .PROTECTION_ENVIRONMENTAL );
526601 int projLevel = armorHit .getEnchantmentLevel (Enchantment .PROTECTION_PROJECTILE );
602+ int unbLevel = armorHit .getEnchantmentLevel (Enchantment .DURABILITY );
603+
604+ if (projLevel > 15 ) projLevel = 15 ;
605+ if (protLevel > 15 ) protLevel = 15 ;
606+ if (unbLevel > 15 ) unbLevel = 15 ;
607+
608+ // get base modifier from Bullet in terms of how much a type of armor protects you from this type of bullet
609+ // then adjust based on prot and proj levels.
610+ double reduction = bulletType .getArmorReduction (grade );
611+ double protReduction = (1.0 + StandardGun .baseEnvironmentProtection * StandardGun .protectionCurve [protLevel ]);
612+ double projReduction = (1.0 + StandardGun .baseProjectileProtection * StandardGun .protectionCurve [projLevel ]);
527613
528- // TODO: calculate
614+ double finalReduce = reduction * protReduction * projReduction ;
615+
616+ if (finalReduce > 1.0 ) finalReduce = 1.0 ;
617+
618+ finalDamage *= (1.0 - finalReduce );
619+
620+ AddGun .getPlugin ().debug (String .format ("Has armor %s, baseDamage of %.2f, base reduction %.2f, prot %.2f, proj %.2f, final Damage %.2f" ,
621+ armorHit , baseRealDamage , reduction , protReduction , projReduction , finalDamage ));
622+
623+ // Basically, unbreaking reduces the amount of durability damage that the armor will sustain
624+ double unbReduction = (1.0 + StandardGun .baseUnbreakingProtection * StandardGun .protectionCurve [unbLevel ]);
625+ double finalDuraDamage = baseRealDamage * (1.0 - (1.0 - bulletType .getArmorDamage (grade )) * unbReduction );
626+ if (armorHit .getDurability () < finalDuraDamage ) {
627+ // broken.
628+ double directDamage = finalDuraDamage - armorHit .getDurability ();
629+
630+ finalDamage += directDamage ; // this is the bit of damage the armor was meant to absorb, but didn't.
631+
632+ armorHit = null ;
633+
634+ AddGun .getPlugin ().debug (String .format ("Armor broken by dura damage %.2f, adding the remaining %.2f to the player damage" ,
635+ finalDuraDamage , directDamage ));
636+ } else {
637+ armorHit .setDurability ((short ) (armorHit .getDurability () - Math .round (finalDuraDamage )));
638+
639+ AddGun .getPlugin ().debug (String .format ("Armor damaged by %.2f" , finalDuraDamage ));
640+ }
529641 }
530642
531- if (shield != null ) {
532- // check bypass?
533- double angle = Math .toDegrees (hit .getLocation ().getDirection ().angle (speed ));
534- // TODO?!?! check this
535- if (angle >= -135 && angle < 135 ) {
536- // no deflection!
537- shieldEffectiveness = 0.0d ;
643+ if (equipment != null ) {
644+ ItemStack tShield = equipment .getItemInOffHand ();
645+
646+ switch (hitData .nearestHitPart ) {
647+ case BODY :
648+ case CHEST_PLATE :
649+ case LEFT_ARM :
650+ case LEFT_FOOT :
651+ case LEFT_HAND :
652+ case RIGHT_ARM :
653+ case RIGHT_FOOT :
654+ case RIGHT_HAND :// all variants on body atm
655+ equipment .setLeggings (armorHit );
656+ if (tShield != null && Material .SHIELD .equals (tShield .getType ())) {
657+ equipment .setItemInOffHand (shield );
658+ }
659+ break ;
660+ case BOOTS :
661+ case FEET : // just feet
662+ equipment .setBoots (armorHit );
663+ break ;
664+ case HEAD :
665+ case HELMET : // just head
666+ equipment .setHelmet (armorHit );
667+ if (tShield != null && Material .SHIELD .equals (tShield .getType ())) {
668+ equipment .setItemInOffHand (shield );
669+ }
670+ break ;
671+ case LEGGINGS :
672+ case LEFT_LEG :
673+ case RIGHT_LEG :
674+ case LEGS : // just legs
675+ equipment .setLeggings (armorHit );
676+ break ;
677+ case MISS : // no hit?
678+ nearMiss (hitData , hit , bullet , bulletType );
679+ break ;
680+ default :
681+ break ;
538682 }
539-
540- finalDamage *= (1.0 - shieldEffectiveness );
541683 }
542684
543685 //TODO: player states? custom shit? event?
@@ -557,7 +699,7 @@ public void manageDamage(HitDigest hitData, Damageable hit, Projectile bullet, B
557699 * @param bullet the "Projectile" bullet doing the hitting
558700 * @param bulletType the "Bullet" type of the projectile.
559701 */
560- abstract void postHit (HitDigest hitData , Entity hit , Projectile bullet , Bullet bulletType );
702+ public void postHit (HitDigest hitData , Entity hit , Projectile bullet , Bullet bulletType ) {}
561703
562704 /**
563705 * Any post-miss cleanup can be handled here. Misses will automatically run this function, and
@@ -569,8 +711,8 @@ public void manageDamage(HitDigest hitData, Damageable hit, Projectile bullet, B
569711 * @param continueBullet Since the original projectile is removed, this is a "continue" bullet spawned _after_ the miss entity.
570712 * @param bulletType the "Bullet" type of the projectiles.
571713 */
572- abstract void postMiss (HitDigest hitData , Entity hit , Projectile bullet , Projectile continueBullet ,
573- Bullet bulletType );
714+ public void postMiss (HitDigest hitData , Entity hit , Projectile bullet , Projectile continueBullet ,
715+ Bullet bulletType ) {}
574716
575717
576718 /**
@@ -598,9 +740,6 @@ public Projectile shoot(Location begin, Bullet bulletType, ProjectileSource shoo
598740 newBullet .setVelocity (velocity );
599741 }
600742
601- travelPaths .put (newBullet .getUniqueId (), begin );
602- inFlightBullets .put (newBullet .getUniqueId (), bulletType );
603-
604743 return newBullet ;
605744 }
606745
0 commit comments