So I recently got asked to do a lot of boss combat scripts.
One thing I noticed is that projectiles are not being configured properly.
It's very dissatisfying to see broken projectiles thus I decided to fix it.
Calculations are derived from grinderscape.
Mainly this will correctly take into account the size of the casting entity.
(This can easily be configured for any other base)
After:
First of all in your projectile class:
search:
Code:
private final Position start;
replace with:
Code:
private final Position start, target;
under:
Code:
private final Position offset;
add:
Code:
private final int creatorSize, startDistanceOffset;
search:
Code:
public Projectile(Position start, Position end, int lockon,
int projectileId, int speed, int delay, int startHeight, int endHeight,
int curve)
replace the entire constructor with:
Code:
public Projectile(Position start, Position end, int lockon,
int projectileId, int speed, int delay, int startHeight, int endHeight,
int curve, int creatorSize, int startDistanceOffset) {
this.start = start;
this.target = end;
this.offset = new Position((end.getX() - start.getX()),
(end.getY() - start.getY()));
this.creatorSize = creatorSize;
this.startDistanceOffset = startDistanceOffset;
this.lockon = lockon;
this.projectileId = projectileId;
this.delay = delay;
this.speed = speed;
this.startHeight = startHeight;
this.endHeight = endHeight;
this.curve = curve;
}
public Projectile(Position start, Position end, int lockon,
int projectileId, int speed, int delay, int startHeight, int endHeight,
int curve) {
this(start, end, lockon, projectileId, speed, delay, startHeight, endHeight, curve, 1, 0);
}
search:
Code:
public Projectile(Entity source, Entity victim, int projectileId,
int delay, int speed, int startHeight, int endHeight, int curve) {
replace entire constructor with:
Code:
public Projectile(Entity source, Entity victim, int projectileId,
int delay, int speed, int startHeight, int endHeight, int curve) {
this(source.getPosition(), victim.getPosition(),
(victim.isPlayer() ? -victim.getIndex() - 1
: victim.getIndex() + 1), projectileId, speed, delay,
startHeight, endHeight, curve, source.getSize(), 0);
}
search:
Code:
player.getPacketSender().sendProjectile(start, offset, 0,
speed, projectileId, startHeight, endHeight, lockon, delay);
replace with:
Code:
player.getPacketSender().sendProjectile(start, offset, 0,
speed, projectileId, startHeight, endHeight, lockon, delay, creatorSize, startDistanceOffset);
finally add these at the bottom of your class:
Code:
public int getDuration(int distance) {
if (distance > 0) {
return delay + speed + distance * 5;
}
return 0;
}
public int getHitDelay(int distance) {
return (int) Math.floor((getDuration(distance) * 0.02857D));
}
public Position getTarget() {
return target;
}
public int getCreatorSize() {
return creatorSize;
}
public int getProjectileID() {
return projectileId;
}
public int getStartDistanceOffset() {
return startDistanceOffset;
}
Go into your Position class.
Add this method somewhere:
Code:
public Position getDelta(Position position) {
return new Position(x - position.x, y - position.y);
}
Now go to your Entity class.
Add this method somewhere:
Code:
public int executeProjectile(Projectile projectile) {
if (projectile == null) {
return 0;
}
Position source = projectile.getStart();
Position target = projectile.getTarget();
if (source == null || target == null) {
return 0;
}
Position delta = projectile.getTarget().getDelta(source);
int distance = source.getDistance(target);
int duration = projectile.getDuration(distance);
if (distance <= 60) {
int creatorSize = projectile.getCreatorSize() == -1 ? getSize() : projectile.getCreatorSize();
for (Player player : World.getPlayers()) {
if (player == null) {
continue;
}
if (source.isViewableFrom(player.getPosition())) {
player.getPacketSender()
.sendProjectile(source, delta, projectile.getCurve(), duration, projectile.getProjectileID(), projectile.getStartHeight(), projectile.getEndHeight(), projectile.getLockon(), projectile.getDelay(), creatorSize, projectile.getStartDistanceOffset());
}
}
}
return projectile.getHitDelay(distance);
}
Now go into your PacketSender class.
Search:
Code:
public PacketSender sendProjectile
Replace the entire method with:
Code:
public PacketSender sendProjectile(Position position, Position offset,
int angle, int speed, int gfxMoving, int startHeight, int endHeight,
int lockon, int time, int creatorSize, int startDistanceOffset){
sendPosition(position);
PacketBuilder out = new PacketBuilder(117);
out.put(50);
out.put(offset.getY());
out.put(offset.getX());
out.putShort(lockon);
out.putShort(gfxMoving);
out.put(startHeight);
out.put(endHeight);
out.putShort(time);
out.putShort(speed);
out.put(angle);
out.put((creatorSize * 64) + (startDistanceOffset * 64));
player.getSession().write(out);
return this;
}
Usage example:
Code:
final int delay = character.executeProjectile(new Projectile(character, target, 280, 64, 35, 35, 35, 10));
target.performGraphic(new Graphic(281, delay));
Let me know if I missed something
