[D1X-Rebirth nightly] Possible bug - homing missile behavior changed
My understanding of the code is:

At every frame, similar/main/game.cpp!calc_frame_time runs to perform various processing. As its final step, it calls similar/main/laser.cpp!calc_d_homer_tick. This is the function I patched above. Global variable FrameTime tracks the time in fixed point subseconds[1] since the last frame. calc_d_homer_tick adds FrameTime to running counter timer. If, after addition, the running timer has accumulated at least HOMING_TURN_TIME, then d_homer_tick_step is true. Otherwise, it is false. Later code will examine d_homer_tick_step to decide whether to process homing weapons. If calc_d_homer_tick sets d_homer_tick_step to true, then it decreases the running counter by HOMING_TURN_TIME, then caps it at HOMING_TURN_TIME * 3. Therefore, if your game ran so slowly that old-value + FrameTime >= HOMING_TURN_TIME * 4, the running value is capped at HOMING_TURN_TIME * 3. In practice, this means that homing weapons can "catch up" for missed frames, but if the game misses more than 3 frames at once, the homing weapons cannot "catch up" all their missed frames. Instead, they will only "catch up" for three missed frames. Neither my results nor Ryusei's are even close to triggering this catch-up logic.

Later, object_move_all will call object_move_one for every live object (players, robots, weapon fire, powerups, etc.). object_move_one, when given a weapon (such as a homing missile), will call Laser_do_weapon_sequence. Laser_do_weapon_sequence will, if the weapon is capable of homing and is not an actively guided missile (meaning, homing missile, guided missile in autonomous mode, smart blobs (including Diamond Claw retaliation blobs), etc.) will examine d_homer_tick_step. If d_homer_tick_step is true, the missile has a chance to update its chosen target and, if not at maximum speed, accelerate. Since the acceleration code is guarded by d_homer_tick_step, that is why I believe that acceleration is now frame-capped. On its own, that would be fine, but since per-frame acceleration is max_speed * (HOMING_TURN_TIME / 2), fewer frames of acceleration maps to less total acceleration for a given number of seconds.

Another possiblity that I looked at before, but failed to fully consider until now, is the oddity of the acceleration guard quoted above. Acceleration only happens if speed+F1_0 < max_speed. Therefore, if speed < max_speed && not (speed + F1_0 < max_speed), then the missile would be at less than full speed (speed < max_speed) and would not accelerate. This would result in a permanent speed penalty for the missile. This depends indirectly on the weapon's speed, which varies slightly due to rounding errors in the magnitude calculation. However, in my testing, I never got the discrepancy beyond ~0x110 below maximum speed of 0x3c0000, so the difference is immeasurable in normal play.

Unfortunately, that test also revealed that the homing weapons are very near their maximum speed on the first iteration through the code, so the uneven number of acceleration steps should have minimal impact in practice. For this test, I used this patch:
diff --git a/similar/main/laser.cpp b/similar/main/laser.cpp
index f4f8a9789..b196be2a4 100644
--- a/similar/main/laser.cpp
+++ b/similar/main/laser.cpp
@@ -1653,6 +1653,7 @@ void Laser_do_weapon_sequence(const vmobjptridx_t obj)
                    temp_vec = obj->mtype.phys_info.velocity;
                    speed = vm_vec_normalize_quick(temp_vec);
                    max_speed = Weapon_info[get_weapon_id(obj)].speed[Difficulty_level];
+                    con_printf(CON_URGENT, "obj=%hu id=%u max_speed=%#x speed=%#x add=%#x", obj.get_unchecked_index(), get_weapon_id(obj), max_speed, speed, fixmul(max_speed, HOMING_TURN_TIME/2));
                    if (speed+F1_0 < max_speed) {
                        speed += fixmul(max_speed, HOMING_TURN_TIME/2);
                        if (speed > max_speed)
I used Descent 2 to play level 27 of Descent: First Strike (since it has a Red Hulk just outside the starting area) and got output of the form:
obj=39 id=21 max_speed=0x3c0000 speed=0x3bffc7 add=0xfff0
obj=39 id=21 max_speed=0x3c0000 speed=0x3bffc4 add=0xfff0
obj=39 id=21 max_speed=0x3c0000 speed=0x3bffa3 add=0xfff0
obj=39 id=21 max_speed=0x3c0000 speed=0x3bffa1 add=0xfff0
obj=39 id=21 max_speed=0x3c0000 speed=0x3bff7e add=0xfff0
obj=39 id=21 max_speed=0x3c0000 speed=0x3bff65 add=0xfff0

If you choose to read the code (and I recommend you do), be aware that zico added the current implementation guarded by #ifdef NEWHOMER and left the old implementation, rather than deleting it outright. Therefore, you should ignore anything in the #else block of a #ifdef NEWHOMER guard.

[1] Fixed point number 1.0, expressed in-game as 0x10000 (or 65536 if you prefer decimal), represents one second. Fixed point number 0.5, expressed in-game as 0x8000 (or 32768), represents half a second. The relation is linear on up and down the scale.
Yes I see it reaches the max speed, however missiles flying towards you can behave differently from constantly turning missiles, I believe; we need to make the same output for the trajectories of the case where the bug appears. And dump the whole trajectory from the beginning to the end probably. Plus maybe the ship's speed (i.e the same for the ship). I looked at NEWHOMER branch some time ago - looks pretty clear especially with your explanations, but for me it is still hard to guess where this bug can be without this additional info. If we won't see anything different in both versions, would be strange, than it could be smth with explosion radius or collision detection.
Turning missiles incur a penalty to ->lifeleft, causing them to time out and detonate sooner than if the missile flew straight. The penalty increases with the amount of turn. According to the comments, a missile that turns at maximum uses up twice as much ->lifeleft as a missile that flies straight.
Yes I get it, still there is some difference btw new and old versions... Either missile or ship speeds in those situations are different, or collision detection. Dumping the (missile+ship) trajectories for particular case should make it clear. Then one can look at the code ans see why it happens.
Did you ever find the explanation for this? I haven't changed the homing missile code because I never understood what exactly needs to be changed.

Forum Jump:

Users browsing this thread: 2 Guest(s)