Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 93 additions & 68 deletions src/Projectile.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,93 @@

public class Projectile extends Entity {

public void trackTarget(int offsetX, int offsetY, int heightDelta, int createTime) {
if (!aBoolean1575) {
double d = offsetX - x;
double d2 = offsetY - y;
double d3 = Math.sqrt(d * d + d2 * d2);
aDouble1555 = x + (d * distanceFromSource) / d3;
aDouble1556 = y + (d2 * distanceFromSource) / d3;
aDouble1557 = heightStart;
}
double d1 = (speed + 1) - createTime;
aDouble1569 = (offsetX - aDouble1555) / d1;
aDouble1570 = (offsetY - aDouble1556) / d1;
aDouble1571 = Math.sqrt(aDouble1569 * aDouble1569 + aDouble1570 * aDouble1570);
if (!aBoolean1575)
aDouble1572 = -aDouble1571 * Math.tan(initialSlope * 0.02454369D);
aDouble1574 = (2D * (heightDelta - aDouble1557 - aDouble1572 * d1)) / (d1 * d1);
}
public void trackTarget(int targetX, int targetY, int targetZ, int createTime) {
if (!hasMoved) {
double dx = targetX - x;
double dy = targetY - y;
double distance = Math.sqrt(dx * dx + dy * dy);
startX = x + (dx * distanceFromSource) / distance;
startY = y + (dy * distanceFromSource) / distance;
startZ = heightStart;
}
double timeRemaining = (speed + 1) - createTime;
velocityX = (targetX - startX) / timeRemaining;
velocityY = (targetY - startY) / timeRemaining;
horizontalVelocity = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
if (!hasMoved)
velocityZ = -horizontalVelocity * Math.tan(initialSlope * 0.02454369D);
gravity = (2D * (targetZ - startZ - velocityZ * timeRemaining)) / (timeRemaining * timeRemaining);
}

public void method563(int i, boolean flag) {
aBoolean1575 = true;
aDouble1555 += aDouble1569 * i;
if (flag) {
for (int j = 1; j > 0; j++);
}
aDouble1556 += aDouble1570 * i;
aDouble1557 += aDouble1572 * i + 0.5D * aDouble1574 * i * i;
aDouble1572 += aDouble1574 * i;
anInt1562 = (int) (Math.atan2(aDouble1569, aDouble1570) * 325.94900000000001D) + 1024 & 0x7ff;
anInt1563 = (int) (Math.atan2(aDouble1572, aDouble1571) * 325.94900000000001D) & 0x7ff;
if (spotAnimation.animation != null)
for (anInt1568 += i; anInt1568 > spotAnimation.animation.method205(0, anInt1567);) {
anInt1568 -= spotAnimation.animation.method205(0, anInt1567);
anInt1567++;
if (anInt1567 >= spotAnimation.animation.anInt294)
anInt1567 = 0;
}
/**
* Updates the projectiles position based on velocity and gravity.
*/
public void updatePosition(int deltaTime) {
hasMoved = true;
startX += velocityX * deltaTime;
startY += velocityY * deltaTime;
startZ += velocityZ * deltaTime + 0.5D * gravity * deltaTime * deltaTime;
velocityZ += gravity * deltaTime;

}
// Calculate yaw (aka horizontal rotation)
yaw = (int) (Math.atan2(velocityX, velocityY) * 325.949) + 1024 & 0x7ff;

// Calculate pitch (aka vertical rotation)
pitch = (int) (Math.atan2(velocityZ, horizontalVelocity) * 325.949) & 0x7ff;
if (spotAnimation.animation != null)
for (animationFrame += deltaTime; animationFrame > spotAnimation.animation.method205(0, currentFrame); ) {
animationFrame -= spotAnimation.animation.method205(0, currentFrame);
currentFrame++;
if (currentFrame >= spotAnimation.animation.anInt294)
currentFrame = 0;
}

}

/**
* Retrieves and prepares the 3D model of this projectile for rendering.
* Applies necessary transformations, animations, and lighting effects.
*
* @return The prepared Model for rendering, or null if the base model is not available
*/
@Override
public Model getModel() {
Model class50_sub1_sub4_sub4 = spotAnimation.getModel();
if (class50_sub1_sub4_sub4 == null)
Model baseModel = spotAnimation.getModel();
if (baseModel == null)
return null;
int i = -1;
if (spotAnimation.animation != null)
i = spotAnimation.animation.anIntArray295[anInt1567];
Model class50_sub1_sub4_sub4_1 = new Model(false, false, true,
class50_sub1_sub4_sub4, Class21.method239(i));
if (i != -1) {
class50_sub1_sub4_sub4_1.method584(7);
class50_sub1_sub4_sub4_1.method585(i, (byte) 6);
class50_sub1_sub4_sub4_1.anIntArrayArray1679 = null;
class50_sub1_sub4_sub4_1.anIntArrayArray1678 = null;

int currentAnimationFrame = -1;
if (spotAnimation.animation != null) {
currentAnimationFrame = spotAnimation.animation.anIntArray295[currentFrame];
}
if (spotAnimation.anInt561 != 128 || spotAnimation.anInt562 != 128)
class50_sub1_sub4_sub4_1.method593(spotAnimation.anInt562, spotAnimation.anInt561, 9,

Model projectileModel = new Model(false, false, true,
baseModel, Class21.method239(currentAnimationFrame));

if (currentAnimationFrame != -1) {
projectileModel.method584(7); //TODO apply effects
projectileModel.method585(currentAnimationFrame, (byte) 6); //TODO apply animations
projectileModel.anIntArrayArray1679 = null;
projectileModel.anIntArrayArray1678 = null;
}

// Apply scaling if needed
int defaultScaling = 128;
if (spotAnimation.anInt561 != defaultScaling || spotAnimation.anInt562 != defaultScaling)
projectileModel.method593(spotAnimation.anInt562, spotAnimation.anInt561, 9,
spotAnimation.anInt561);
class50_sub1_sub4_sub4_1.method589(anInt1563, 341);
class50_sub1_sub4_sub4_1.method594(64 + spotAnimation.anInt564, 850 + spotAnimation.anInt565, -30, -50, -30,
true);
return class50_sub1_sub4_sub4_1;

// Apply rotation (aka pitch) to the model
projectileModel.method589(pitch, 341); // TODO investigate 341

// Apply lighting and shading
projectileModel.method594(
64 + spotAnimation.anInt564, // ambient light
850 + spotAnimation.anInt565, // contrast
-30, -50, -30, // light direction vector
true // Apply lighting
);
return projectileModel;
}

public Projectile(int plane, int heightEnd, int distanceFromSource, int y, int id, int speed, int initialSlope, int target, int heightStart, int x,
Expand All @@ -83,32 +108,32 @@ public Projectile(int plane, int heightEnd, int distanceFromSource, int y, int i
this.distanceFromSource = distanceFromSource;
this.target = target;
this.heightEnd = heightEnd;
aBoolean1575 = false;
hasMoved = false;
return;
}

public SpotAnimation spotAnimation;
public int plane;
public double aDouble1555;
public double aDouble1556;
public double aDouble1557;
public double startX;
public double startY;
public double startZ;
public int initialSlope;
public int distanceFromSource;
public int target;
public boolean aBoolean1561;
public int anInt1562;
public int anInt1563;
public int yaw;
public int pitch;
public int createdTime;
public int speed;
public int anInt1567;
public int anInt1568;
public double aDouble1569;
public double aDouble1570;
public double aDouble1571;
public double aDouble1572;
public int currentFrame;
public int animationFrame;
public double velocityX;
public double velocityY;
public double horizontalVelocity;
public double velocityZ;
public boolean aBoolean1573;
public double aDouble1574;
public boolean aBoolean1575;
public double gravity;
public boolean hasMoved;
public int x;
public int y;
public int heightStart;
Expand Down
42 changes: 21 additions & 21 deletions src/SceneGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -272,31 +272,31 @@ public boolean method251(int i, int j, int k, Entity class50_sub1_sub4, byte byt
}
}

public boolean method252(int i, Entity class50_sub1_sub4, int j, int k, boolean flag, int l, int i1,
int j1, int k1, int l1) {
if (class50_sub1_sub4 == null)
public boolean canPlaceEntity(int entityType, Entity entity, int x, int k, boolean adjustForAngle, int l, int i1,
int entityWidth, int z, int facingAngle) {
if (entity == null)
return true;
int i2 = j - j1;
int j2 = k1 - j1;
int k2 = j + j1;
int l2 = k1 + j1;
if (flag) {
if (l1 > 640 && l1 < 1408)
l2 += 128;
if (l1 > 1152 && l1 < 1920)
k2 += 128;
if (l1 > 1664 || l1 < 384)
j2 -= 128;
if (l1 > 128 && l1 < 896)
i2 -= 128;
int minX = x - entityWidth;
int minY = z - entityWidth;
int maxX = x + entityWidth;
int maxY = z + entityWidth;
if (adjustForAngle) {
if (facingAngle > 640 && facingAngle < 1408)
maxY += 128;
if (facingAngle > 1152 && facingAngle < 1920)
maxX += 128;
if (facingAngle > 1664 || facingAngle < 384)
minY -= 128;
if (facingAngle > 128 && facingAngle < 896)
minX -= 128;
}
i2 /= 128;
minX /= 128;
if (l != 0)
anInt450 = 368;
j2 /= 128;
k2 /= 128;
l2 /= 128;
return method254(i1, i2, j2, (k2 - i2) + 1, (l2 - j2) + 1, j, k1, k, class50_sub1_sub4, l1, true, i, (byte) 0);
minY /= 128;
maxX /= 128;
maxY /= 128;
return method254(i1, minX, minY, (maxX - minX) + 1, (maxY - minY) + 1, x, z, k, entity, facingAngle, true, entityType, (byte) 0);
}

public boolean method253(int i, int j, int k, int l, Entity class50_sub1_sub4, int i1, int j1, int k1,
Expand Down
66 changes: 38 additions & 28 deletions src/client.java
Original file line number Diff line number Diff line change
Expand Up @@ -3426,27 +3426,36 @@ public void method50(boolean flag) {
stopMidi();
}

public void method51() {
/**
* Updates and renders all active projectiles in the game world.
* This method is called every game tick to process projectile movement and rendering.
*/
public void processProjectiles() {
Projectile projectile = (Projectile) projectileQueue.first();
for (; projectile != null; projectile = (Projectile) projectileQueue
.next())
if (projectile.plane != plane || pulseCycle > projectile.speed)
//Remove projectiles that are on a different plane or have expired
if (projectile.plane != plane || pulseCycle > projectile.speed) {
projectile.unlink();
}
// Process active projectiles
else if (pulseCycle >= projectile.createdTime) {
// Handle projectiles targetting NPCs (positive target ID)
if (projectile.target > 0) {
Npc npc = npcs[projectile.target - 1];
if (npc != null
&& npc.unitX >= 0
&& npc.unitX < 13312
&& npc.unitY >= 0
&& npc.unitY < 13312)
projectile.trackTarget(npc.unitX,
npc.unitY, getFloorDrawHeight(
npc.unitY,
npc.unitX,
projectile.plane)
- projectile.heightEnd, pulseCycle);
projectile.trackTarget(
npc.unitX,
npc.unitY,
getFloorDrawHeight(npc.unitY, npc.unitX, projectile.plane) - projectile.heightEnd,
pulseCycle);
}

// Handle projectiles targetting players (negative target ID)
if (projectile.target < 0) {
int i = -projectile.target - 1;
Player player;
Expand All @@ -3455,27 +3464,28 @@ npc.unitY, getFloorDrawHeight(
else
player = players[i];
if (player != null
&& ((Actor) (player)).unitX >= 0
&& ((Actor) (player)).unitX < 13312
&& ((Actor) (player)).unitY >= 0
&& ((Actor) (player)).unitY < 13312)
projectile.trackTarget(((Actor) (player)).unitX,
((Actor) (player)).unitY, getFloorDrawHeight(
((Actor) (player)).unitY,
((Actor) (player)).unitX,
projectile.plane)
- projectile.heightEnd, pulseCycle);
}
projectile.method563(anInt951, false);
aClass22_1164.method252(-1, projectile, (int) projectile.aDouble1555,
(int) projectile.aDouble1557, false, 0, plane, 60,
(int) projectile.aDouble1556, projectile.anInt1562);
&& player.unitX >= 0
&& player.unitX < 13312
&& player.unitY >= 0
&& player.unitY < 13312)
projectile.trackTarget(
player.unitX,
player.unitY,
getFloorDrawHeight(player.unitY, player.unitX, projectile.plane) - projectile.heightEnd,
pulseCycle);
}
projectile.updatePosition(anInt951);

//Render the projectile
aClass22_1164.canPlaceEntity(-1, projectile, (int) projectile.startX,
(int) projectile.startZ, false, 0, plane, 60,
(int) projectile.startY, projectile.yaw);
}

anInt1168++;
if (anInt1168 > 51) {
anInt1168 = 0;
outBuffer.putOpcode(248);
outBuffer.putOpcode(248); // Keep-alive
}
}

Expand Down Expand Up @@ -3745,7 +3755,7 @@ public void method57(int i, boolean flag) {
}
if (!class50_sub1_sub4_sub3_sub1.def.aBoolean631)
k += 0x80000000;
aClass22_1164.method252(k, class50_sub1_sub4_sub3_sub1,
aClass22_1164.canPlaceEntity(k, class50_sub1_sub4_sub3_sub1,
((Actor) (class50_sub1_sub4_sub3_sub1)).unitX, getFloorDrawHeight(
((Actor) (class50_sub1_sub4_sub3_sub1)).unitY,
((Actor) (class50_sub1_sub4_sub3_sub1)).unitX, plane),
Expand Down Expand Up @@ -5544,7 +5554,7 @@ else if (pulseCycle >= graphic.anInt1740) {
if (graphic.aBoolean1736)
graphic.unlink();
else
aClass22_1164.method252(-1, graphic, graphic.anInt1732,
aClass22_1164.canPlaceEntity(-1, graphic, graphic.anInt1732,
graphic.anInt1734, false, 0, graphic.anInt1731, 60,
graphic.anInt1733, 0);
}
Expand Down Expand Up @@ -8215,7 +8225,7 @@ public void method119(int i, boolean flag) {
}
class50_sub1_sub4_sub3_sub2.anInt1750 = getFloorDrawHeight(((Actor) (class50_sub1_sub4_sub3_sub2)).unitY,
((Actor) (class50_sub1_sub4_sub3_sub2)).unitX, plane);
aClass22_1164.method252(l, class50_sub1_sub4_sub3_sub2,
aClass22_1164.canPlaceEntity(l, class50_sub1_sub4_sub3_sub2,
((Actor) (class50_sub1_sub4_sub3_sub2)).unitX, class50_sub1_sub4_sub3_sub2.anInt1750,
((Actor) (class50_sub1_sub4_sub3_sub2)).aBoolean1592, 0, plane, 60,
((Actor) (class50_sub1_sub4_sub3_sub2)).unitY,
Expand Down Expand Up @@ -10982,7 +10992,7 @@ public void method151(int i) {
method57(751, true);
method119(0, false);
method57(751, false);
method51();
processProjectiles();
method76(-992);
if (!aBoolean1211) {
int j = anInt1251;
Expand Down