TheSuperHackers / GeneralsGamePatch

Community Patch to fix and improve original Generals Zero Hour 1.04
Other
58 stars 19 forks source link

China Propaganda Bonus resets weapon reload #510

Open xezon opened 2 years ago

xezon commented 2 years ago

China Propaganda Bonus resets weapon reload. This can be easily tested on China Nuke Cannon. When Propaganda is added or removed from the unit, the weapon will reload instantly and the Nuke Cannon can shoot immediately again.

Replay: PROPAGANDA_BUG_REPLAY.zip

https://user-images.githubusercontent.com/4720891/136426285-bd285c9b-4493-4eca-b7c6-476049373da8.mp4

EnigmaZift commented 2 years ago

Hi, I think this is a bug specifically with how the Nuke Cannon's weapon works rather than Propaganda as a whole... I might be wrong but I'm 80% certain.

commy2 commented 2 years ago

It's the interaction between the two: Shared reload time and rate of fire bonuses.

ReLaX82 commented 2 years ago

Bug, needs fixing.

ZekeDlyoung commented 2 years ago

It affects all weapon reloads, also it can't be fixed, not through modding anyway

xezon commented 1 year ago
xezon commented 1 year ago

To fix this, the weapon reload progress needs to be kept after the new fire rate is applied.

commy2 commented 1 year ago

Progress should be transferred proportionally. If total reload time before is 10, after is 8, and the current progress is 5/10 seconds, the progress with bonus should be set to 4/8 + delta_t.

xezon commented 11 months ago

Logic appears to be here:

void Weapon::On_Weapon_Bonus_Change(const Object *source_obj)
{
    WeaponBonus bonus;
    Compute_Bonus(source_obj, 0, bonus);
    bool time_set = false;
    int time;

    if (Get_Status() == RELOADING_CLIP) {
        time = m_template->Get_Clip_Reload_Time(bonus);
        time_set = true;
    } else if (Get_Status() == BETWEEN_FIRING_SHOTS) {
        time = m_template->Get_Delay_Between_Shots(bonus);
        time_set = true;
    }

    if (time_set) {
        m_whenLastReloadStarted = g_theGameLogic->Get_Frame();
        m_whenWeCanFireAgain = time + m_whenLastReloadStarted;

        if (source_obj->Is_Share_Weapon_Reload_Time()) {
            for (int i = 0; i < WEAPONSLOT_COUNT; i++) {
                Weapon *weapon = const_cast<Weapon *>(source_obj->Get_Weapon_In_Weapon_Slot(static_cast<WeaponSlotType>(i)));

                if (weapon != nullptr) {
                    weapon->Set_Next_Shot(m_whenWeCanFireAgain);
                    weapon->Set_Status(RELOADING_CLIP);
                }
            }
        }
    }
}