Advertisement
Guest User

adsadsdadasdsfsdfsdg

a guest
May 19th, 2019
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.34 KB | None | 0 0
  1. using ExampleMod.Items.Weapons;
  2. using Microsoft.Xna.Framework;
  3. using System.Collections.Generic;
  4. using Terraria;
  5. using Terraria.ID;
  6. using Terraria.ModLoader;
  7.  
  8. namespace ExampleMod.Projectiles
  9. {
  10.     public class ExampleJavelinProjectile : ModProjectile
  11.     {
  12.         public override void SetStaticDefaults() {
  13.             DisplayName.SetDefault("Javelin");
  14.         }
  15.  
  16.         public override void SetDefaults() {
  17.             projectile.width = 16;
  18.             projectile.height = 16;
  19.             projectile.aiStyle = -1;
  20.             projectile.friendly = true;
  21.             projectile.melee = true;
  22.             projectile.penetrate = 3;
  23.             projectile.hide = true;
  24.         }
  25.  
  26.         // See ExampleBehindTilesProjectile.
  27.         public override void DrawBehind(int index, List<int> drawCacheProjsBehindNPCsAndTiles, List<int> drawCacheProjsBehindNPCs, List<int> drawCacheProjsBehindProjectiles, List<int> drawCacheProjsOverWiresUI) {
  28.             // If attached to an NPC, draw behind tiles (and the npc) if that NPC is behind tiles, otherwise just behind the NPC.
  29.             if (projectile.ai[0] == 1f) // or if(isStickingToTarget) since we made that helper method.
  30.             {
  31.                 int npcIndex = (int)projectile.ai[1];
  32.                 if (npcIndex >= 0 && npcIndex < 200 && Main.npc[npcIndex].active) {
  33.                     if (Main.npc[npcIndex].behindTiles) {
  34.                         drawCacheProjsBehindNPCsAndTiles.Add(index);
  35.                     }
  36.                     else {
  37.                         drawCacheProjsBehindNPCs.Add(index);
  38.                     }
  39.  
  40.                     return;
  41.                 }
  42.             }
  43.             // Since we aren't attached, add to this list
  44.             drawCacheProjsBehindProjectiles.Add(index);
  45.         }
  46.  
  47.         public override bool TileCollideStyle(ref int width, ref int height, ref bool fallThrough) {
  48.             // For going through platforms and such, javelins use a tad smaller size
  49.             width = height = 10; // notice we set the width to the height, the height to 10. so both are 10
  50.             return true;
  51.         }
  52.  
  53.         public override bool? Colliding(Rectangle projHitbox, Rectangle targetHitbox) {
  54.             // Inflate some target hitboxes if they are beyond 8,8 size
  55.             if (targetHitbox.Width > 8 && targetHitbox.Height > 8) {
  56.                 targetHitbox.Inflate(-targetHitbox.Width / 8, -targetHitbox.Height / 8);
  57.             }
  58.             // Return if the hitboxes intersects, which means the javelin collides or not
  59.             return projHitbox.Intersects(targetHitbox);
  60.         }
  61.  
  62.         public override void Kill(int timeLeft) {
  63.             Main.PlaySound(0, (int)projectile.position.X, (int)projectile.position.Y); // Play a death sound
  64.             Vector2 usePos = projectile.position; // Position to use for dusts
  65.                                                   // Please note the usage of MathHelper, please use this! We subtract 90 degrees as radians to the rotation vector to offset the sprite as its default rotation in the sprite isn't aligned properly.
  66.             Vector2 rotVector =
  67.                 (projectile.rotation - MathHelper.ToRadians(90f)).ToRotationVector2(); // rotation vector to use for dust velocity
  68.             usePos += rotVector * 16f;
  69.  
  70.             // Spawn some dusts upon javelin death
  71.             for (int i = 0; i < 20; i++) {
  72.                 // Create a new dust
  73.                 Dust dust = Dust.NewDustDirect(usePos, projectile.width, projectile.height, 81);
  74.                 dust.position = (dust.position + projectile.Center) / 2f;
  75.                 dust.velocity += rotVector * 2f;
  76.                 dust.velocity *= 0.5f;
  77.                 dust.noGravity = true;
  78.                 usePos -= rotVector * 8f;
  79.             }
  80.  
  81.             // Make sure to only spawn items if you are the projectile owner.
  82.             if (projectile.owner == Main.myPlayer) {
  83.                 // Drop a javelin item, 1 in 18 chance (~5.5% chance)
  84.                 int item =
  85.                 Main.rand.NextBool(18)
  86.                     ? Item.NewItem(projectile.getRect(), mod.ItemType<ExampleJavelin>())
  87.                     : 0;
  88.  
  89.                 // Sync the drop for multiplayer
  90.                 // Note the usage of Terraria.ID.MessageID, please use this!
  91.                 if (Main.netMode == 1 && item >= 0) {
  92.                     NetMessage.SendData(MessageID.SyncItem, -1, -1, null, item, 1f);
  93.                 }
  94.             }
  95.         }
  96.  
  97.         // Here's an example on how you could make your AI even more readable, by giving AI fields more descriptive names
  98.         // These are not used in AI, but it is good practice to apply some form like this to keep things organized
  99.  
  100.         // Are we sticking to a target?
  101.         public bool isStickingToTarget {
  102.             get => projectile.ai[0] == 1f;
  103.             set => projectile.ai[0] = value ? 1f : 0f;
  104.         }
  105.  
  106.         // WhoAmI of the current target
  107.         public float targetWhoAmI {
  108.             get => projectile.ai[1];
  109.             set => projectile.ai[1] = value;
  110.         }
  111.  
  112.         public override void ModifyHitNPC(NPC target, ref int damage, ref float knockback, ref bool crit,
  113.             ref int hitDirection) {
  114.             // If you'd use the example above, you'd do: isStickingToTarget = 1f;
  115.             // and: targetWhoAmI = (float)target.whoAmI;
  116.             isStickingToTarget = true; // we are sticking to a target
  117.             targetWhoAmI = (float)target.whoAmI; // Set the target whoAmI
  118.             projectile.velocity =
  119.                 (target.Center - projectile.Center) *
  120.                 0.75f; // Change velocity based on delta center of targets (difference between entity centers)
  121.             projectile.netUpdate = true; // netUpdate this javelin
  122.             target.AddBuff(mod.BuffType<Buffs.ExampleJavelin>(), 900); // Adds the ExampleJavelin debuff for a very small DoT
  123.  
  124.             projectile.damage = 0; // Makes sure the sticking javelins do not deal damage anymore
  125.  
  126.             // The following code handles the javelin sticking to the enemy hit.
  127.             int maxStickingJavelins = 6; // This is the max. amount of javelins being able to attach
  128.             Point[] stickingJavelins = new Point[maxStickingJavelins]; // The point array holding for sticking javelins
  129.             int javelinIndex = 0; // The javelin index
  130.             for (int i = 0; i < Main.maxProjectiles; i++) // Loop all projectiles
  131.             {
  132.                 Projectile currentProjectile = Main.projectile[i];
  133.                 if (i != projectile.whoAmI // Make sure the looped projectile is not the current javelin
  134.                     && currentProjectile.active // Make sure the projectile is active
  135.                     && currentProjectile.owner == Main.myPlayer // Make sure the projectile's owner is the client's player
  136.                     && currentProjectile.type == projectile.type // Make sure the projectile is of the same type as this javelin
  137.                     && currentProjectile.ai[0] == 1f // Make sure ai0 state is set to 1f (set earlier in ModifyHitNPC)
  138.                     && currentProjectile.ai[1] == (float)target.whoAmI
  139.                 ) // Make sure ai1 is set to the target whoAmI (set earlier in ModifyHitNPC)
  140.                 {
  141.                     stickingJavelins[javelinIndex++] =
  142.                         new Point(i, currentProjectile.timeLeft); // Add the current projectile's index and timeleft to the point array
  143.                     if (javelinIndex >= stickingJavelins.Length
  144.                     ) // If the javelin's index is bigger than or equal to the point array's length, break
  145.                     {
  146.                         break;
  147.                     }
  148.                 }
  149.             }
  150.             // Here we loop the other javelins if new javelin needs to take an older javelin's place.
  151.             if (javelinIndex >= stickingJavelins.Length) {
  152.                 int oldJavelinIndex = 0;
  153.                 // Loop our point array
  154.                 for (int i = 1; i < stickingJavelins.Length; i++) {
  155.                     // Remove the already existing javelin if it's timeLeft value (which is the Y value in our point array) is smaller than the new javelin's timeLeft
  156.                     if (stickingJavelins[i].Y < stickingJavelins[oldJavelinIndex].Y) {
  157.                         oldJavelinIndex = i; // Remember the index of the removed javelin
  158.                     }
  159.                 }
  160.                 // Remember that the X value in our point array was equal to the index of that javelin, so it's used here to kill it.
  161.                 Main.projectile[stickingJavelins[oldJavelinIndex].X].Kill();
  162.             }
  163.         }
  164.  
  165.         // Added these 2 constant to showcase how you could make AI code cleaner by doing this
  166.         // Change this number if you want to alter how long the javelin can travel at a constant speed
  167.         private const float maxTicks = 45f;
  168.  
  169.         // Change this number if you want to alter how the alpha changes
  170.         private const int alphaReduction = 25;
  171.  
  172.         public override void AI() {
  173.             // Slowly remove alpha as it is present
  174.             if (projectile.alpha > 0) {
  175.                 projectile.alpha -= alphaReduction;
  176.             }
  177.             // If alpha gets lower than 0, set it to 0
  178.             if (projectile.alpha < 0) {
  179.                 projectile.alpha = 0;
  180.             }
  181.             // If ai0 is 0f, run this code. This is the 'movement' code for the javelin as long as it isn't sticking to a target
  182.             if (!isStickingToTarget) {
  183.                 targetWhoAmI += 1f;
  184.                 // For a little while, the javelin will travel with the same speed, but after this, the javelin drops velocity very quickly.
  185.                 if (targetWhoAmI >= maxTicks) {
  186.                     // Change these multiplication factors to alter the javelin's movement change after reaching maxTicks
  187.                     float velXmult = 0.98f; // x velocity factor, every AI update the x velocity will be 98% of the original speed
  188.                     float
  189.                         velYmult = 0.35f; // y velocity factor, every AI update the y velocity will be be 0.35f bigger of the original speed, causing the javelin to drop to the ground
  190.                     targetWhoAmI = maxTicks; // set ai1 to maxTicks continuously
  191.                     projectile.velocity.X = projectile.velocity.X * velXmult;
  192.                     projectile.velocity.Y = projectile.velocity.Y + velYmult;
  193.                 }
  194.                 // Make sure to set the rotation accordingly to the velocity, and add some to work around the sprite's rotation
  195.                 projectile.rotation =
  196.                     projectile.velocity.ToRotation() +
  197.                     MathHelper.ToRadians(
  198.                         90f); // Please notice the MathHelper usage, offset the rotation by 90 degrees (to radians because rotation uses radians) because the sprite's rotation is not aligned!
  199.  
  200.                 // Spawn some random dusts as the javelin travels
  201.                 if (Main.rand.NextBool(3)) {
  202.                     Dust dust = Dust.NewDustDirect(projectile.position, projectile.height, projectile.width, mod.DustType<Dusts.Sparkle>(),
  203.                         projectile.velocity.X * .2f, projectile.velocity.Y * .2f, 200, Scale: 1.2f);
  204.                     dust.velocity += projectile.velocity * 0.3f;
  205.                     dust.velocity *= 0.2f;
  206.                 }
  207.                 if (Main.rand.NextBool(4)) {
  208.                     Dust dust = Dust.NewDustDirect(projectile.position, projectile.height, projectile.width, mod.DustType<Dusts.Sparkle>(),
  209.                         0, 0, 254, Scale: 0.3f);
  210.                     dust.velocity += projectile.velocity * 0.5f;
  211.                     dust.velocity *= 0.5f;
  212.                 }
  213.             }
  214.             // This code is ran when the javelin is sticking to a target
  215.             if (isStickingToTarget) {
  216.                 // These 2 could probably be moved to the ModifyNPCHit hook, but in vanilla they are present in the AI
  217.                 projectile.ignoreWater = true; // Make sure the projectile ignores water
  218.                 projectile.tileCollide = false; // Make sure the projectile doesn't collide with tiles anymore
  219.                 int aiFactor = 15; // Change this factor to change the 'lifetime' of this sticking javelin
  220.                 bool killProj = false; // if true, kill projectile at the end
  221.                 bool hitEffect = false; // if true, perform a hit effect
  222.                 projectile.localAI[0] += 1f;
  223.                 // Every 30 ticks, the javelin will perform a hit effect
  224.                 hitEffect = projectile.localAI[0] % 30f == 0f;
  225.                 int projTargetIndex = (int)targetWhoAmI;
  226.                 if (projectile.localAI[0] >= (float)(60 * aiFactor) || projTargetIndex < 0 || projTargetIndex >= 200) // If the index is past its limits, kill it
  227.                 {
  228.                     killProj = true;
  229.                 }
  230.                 else if (Main.npc[projTargetIndex].active && !Main.npc[projTargetIndex].dontTakeDamage) // If the target is active and can take damage
  231.                 {
  232.                     // Set the projectile's position relative to the target's center
  233.                     projectile.Center = Main.npc[projTargetIndex].Center - projectile.velocity * 2f;
  234.                     projectile.gfxOffY = Main.npc[projTargetIndex].gfxOffY;
  235.                     if (hitEffect) // Perform a hit effect here
  236.                     {
  237.                         Main.npc[projTargetIndex].HitEffect(0, 1.0);
  238.                     }
  239.                 }
  240.                 else // Otherwise, kill the projectile
  241.                 {
  242.                     killProj = true;
  243.                 }
  244.  
  245.                 if (killProj) // Kill the projectile
  246.                 {
  247.                     projectile.Kill();
  248.                 }
  249.             }
  250.         }
  251.     }
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement