Nice boomerang action! It reminds me to boomerang I've coded for Double Dragon Mini years ago. It doesn't work like this but it was meant for example.
Thanks! It uses a fairly complex mechanic that I wasn't able to implement on my own:
- When fired, it travels in a straight line while gradually decelerating.
- Once its X-axis velocity drops below 0, it begins to track its "parent" object across the X, Y, and Z axes.
- Upon nearing the parent, it checks several conditions: if the parent is falling, dead, or no longer exists, the boomerang immediately drops to the ground. If the parent is in one of four specific states (idle, walk, block, or faint), it forces the parent into an animation that simulates catching the boomerang. Otherwise, it continues to track the parent until contact can be made.
- If it hits a wall while moving forward, it automatically ricochets at the same speed, without any deceleration (I still need to tweak this, though—if it’s fired while already inside a wall, it gets stuck).
- If it detects a wall while returning, it doubles its Z-axis velocity to maneuver around it, moving either "up" or "down" depending on the parent's position.
Initially, I ran into an issue where the boomerang would immediately appear in its "on the ground" animation state. Claude suspected it was due to a missing "parent" property within the `spawn01()` function, but my version of that function—which includes a safety check—does actually assign the parent.
C-like:
void spawn01(void vName, float fX, float fY, float fZ)
{
//spawn01 (Generic spawner)
//Damon Vaughn Caskey
//07/06/2007
//
//Spawns entity next to caller.
//
//vName: Model name of entity to be spawned in.
//fX: X location adjustment.
//fZ: Y location adjustment.
//fY: Z location adjustment.
void self = getlocalvar("self"); //Get calling entity.
void vSpawn; //Spawn object.
int iDirection = getentityproperty(self, "direction");
clearspawnentry(); //Clear current spawn entry.
setspawnentry("name", vName); //Acquire spawn entity by name.
if (iDirection == 0){ //Is entity facing left?
fX = -fX; //Reverse X direction to match facing.
}
fX = fX + getentityproperty(self, "x"); //Get X location and add adjustment.
fY = fY + getentityproperty(self, "a"); //Get Y location and add adjustment.
fZ = fZ + getentityproperty(self, "z"); //Get Z location and add adjustment.
vSpawn = spawn(); //Spawn in entity.
if (vSpawn){// safe check
changeentityproperty(vSpawn, "position", fX, fZ, fY); //Set spawn location.
changeentityproperty(vSpawn, "direction", iDirection); //Set direction.
changeentityproperty(vSpawn, "parent", self); //Set parent.
return vSpawn; //Return spawn.
}
}
As it turned out, because the boomerang has a delay of 1 and the script runs inline, the execution was so fast that by the time the function assigned the parent to the spawned object, it was already too late—we confirmed this using `log()`.
---
Another issue I managed to resolve—though it took quite a while—is that the *Golden Axe* bonus stage now features a victory screen with a scoring system. It works as follows:
- I already had an individual counter that tracked how many barrels each player broke (courtesy of Kratus).
- This counter monitors the number of enemies on screen (barrels are converted to the "ENEMY" type upon spawning). As soon as it detects the first enemy, it changes its own type from "NONE" to "ENEMY" to prevent the level from ending prematurely.
- The code was struggling to keep an accurate count of the remaining barrels—specifically regarding why some barrels granted points upon destruction while others didn't. That was my fault; I hadn't provided enough context to Claude, failing to explain that barrels roll across the screen and are removed if they go beyond the screen boundaries, without triggering the counter.
- Once all the barrels are gone, a function is triggered that locks all player inputs, tallies the results, and applies the following rules:
If one player has destroyed more barrels than the others, they are declared the winner—triggering a victory animation for them, while the other players perform a defeat animation.
In the event of a tie (whether all counters are at zero or two or more players have the same count), it’s declared a "draw game," and all players perform the defeat animation.
If there is a clear winner, the total number of barrels they destroyed is multiplied by 1,000, and this amount is awarded to the winner as a bonus.
Finally, a message is displayed identifying the winner, the number of barrels they broke, and the bonus amount. It also assigns a rank based on the number of barrels destroyed—with the code taking the currently active language into account.
