[FilterScript] Distance bug fix
#1

Most of you are probably not aware of this bug. When you exit a vehicle that isn't a bike, all weapons will have a virtually infinite range when you're being shot at.

This filterscript takes care of that problem.

How does it work?
The filterscript waits for everyone to leave the vehicle, then for the vehicle to stop moving (if it's rolling or something).

Beware:
  • You must set the vehicle's color again in OnVehicleSpawn.
  • You must add vehicle components again in OnVehicleSpawn.
  • Vehicles that end up in the water will not be respawned (due to OnVehicleDeath being called). You could respawn or destroy it in OnVehicleDeath.
  • The fix will not be applied until all players leave the vehicle.
Credits
F0rce helped develop this (sssssssss).

The code:

pawn Код:
#include <a_samp>

#if !defined IsValidVehicle
    native IsValidVehicle(vehicleid);
#endif

enum E_VEHICLE_DATA {
          Monitor,
          Timer,
          RePosition,
          SetZAngle,
    Float:Health,
    Float:ZAngle,
    Float:X,
    Float:Y,
    Float:Z,
          DamagePanels,
          DamageDoors,
          DamageLights,
          DamageTires
}

new
    g_VehicleData[MAX_VEHICLES][E_VEHICLE_DATA],
    g_EnteringVehicle[MAX_PLAYERS] = {INVALID_VEHICLE_ID, ...},
    g_EnteringTimer[MAX_PLAYERS] = {-1, ...},
    g_LastVehicleId[MAX_PLAYERS] = {INVALID_VEHICLE_ID, ...}
;

stock IsVehicleBeingEntered(vehicleid) {
    for (new i = 0; i < MAX_PLAYERS; i++) {
        if (g_EnteringVehicle[i] == vehicleid) {
            return true;
        }
    }
   
    return false;
}

stock GetPlayerInVehicle(vehicleid, seat = 0) {
    for (new i = 0; i < MAX_PLAYERS; i++) {
        if (!IsPlayerConnected(i)) {
            continue;
        }
         
        if (GetPlayerVehicleID(i) == vehicleid &&
            GetPlayerVehicleSeat(i) == seat) {
            return i;
        }
    }

    return INVALID_PLAYER_ID;
}

stock IsVehicleEmpty(vehicleid, except = INVALID_PLAYER_ID) {
    for (new i = 0; i < MAX_PLAYERS; i++) {
        if (!IsPlayerConnected(i) || i == except) {
            continue;
        }
       
        if (GetPlayerVehicleID(i) == vehicleid) {
            return false;
        }
    }

    return true;
}

stock EnteringStopped(playerid) {
    new vehicleid = g_EnteringVehicle[playerid];
   
    if (vehicleid == INVALID_VEHICLE_ID) {
        return;
    }
   
    g_EnteringVehicle[playerid] = INVALID_VEHICLE_ID;
    g_EnteringTimer[playerid] = -1;
   
    if (g_EnteringTimer[playerid] != -1) {
        KillTimer(g_EnteringTimer[playerid]);
    }
}

public OnFilterScriptInit() {
    for (new i = 0; i < MAX_VEHICLES; i++) {
        g_VehicleData[i][Timer] = -1;
    }
   
    for (new i = 0; i < MAX_PLAYERS; i++) {
        new vehicleid = GetPlayerVehicleID(i);
       
        if (vehicleid != 0) {
            g_LastVehicleId[i] = vehicleid;
        }
    }
}

public OnPlayerConnect(playerid) {
    g_LastVehicleId[playerid] = INVALID_VEHICLE_ID;
   
    return 1;
}

public OnPlayerDisconnect(playerid, reason) {
    EnteringStopped(playerid);
   
    return 1;
}

public OnPlayerDeath(playerid, killerid, reason) {
    EnteringStopped(playerid);
   
    return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate) {
    EnteringStopped(playerid);
   
    if (oldstate == PLAYER_STATE_DRIVER || oldstate == PLAYER_STATE_PASSENGER) {
        new vehicleid = g_LastVehicleId[playerid];
       
        if (IsVehicleEmpty(vehicleid, playerid)) {
            UpdateMonitoring(vehicleid);
        }
    }
   
    if (newstate == PLAYER_STATE_DRIVER || newstate == PLAYER_STATE_PASSENGER) {
        g_LastVehicleId[playerid] = GetPlayerVehicleID(playerid);
       
        StopMonitoring(GetPlayerVehicleID(playerid));
    }
   
    return 1;
}

public OnVehicleDeath(vehicleid, killerid) {
    StopMonitoring(vehicleid);
   
    for (new i = 0; i < MAX_PLAYERS; i++) {
        if (g_EnteringVehicle[i] == vehicleid) {
            EnteringStopped(i);
        }
    }
   
    return 1;
}

public OnVehicleSpawn(vehicleid) {
    if (g_VehicleData[vehicleid][RePosition]) {
        SetVehicleHealth(vehicleid, g_VehicleData[vehicleid][Health]);
        SetVehiclePos(
            vehicleid,
            g_VehicleData[vehicleid][X],
            g_VehicleData[vehicleid][Y],
            g_VehicleData[vehicleid][Z] + 0.3
        );
       
        UpdateVehicleDamageStatus(
            vehicleid,
            g_VehicleData[vehicleid][DamagePanels],
            g_VehicleData[vehicleid][DamageDoors],
            g_VehicleData[vehicleid][DamageLights],
            g_VehicleData[vehicleid][DamageTires]
        );
       
        StopMonitoring(vehicleid);
       
        g_VehicleData[vehicleid][SetZAngle] = 30;
       
        SetTimerEx("UpdateZAngle", 50, false, "i", vehicleid);
    } else {
        StopMonitoring(vehicleid);
    }
   
    return 1;
}

forward UpdateZAngle(vehicleid);
public UpdateZAngle(vehicleid) {
    if (g_VehicleData[vehicleid][SetZAngle]) {
        SetVehicleZAngle(vehicleid, g_VehicleData[vehicleid][ZAngle]);
       
        g_VehicleData[vehicleid][SetZAngle]--;
       
        SetTimerEx("UpdateZAngle", 50, false, "i", vehicleid);
    }
}

public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger) {
    EnteringStopped(playerid);
   
    g_EnteringVehicle[playerid] = vehicleid;
    g_EnteringTimer[playerid] = SetTimerEx("OnEnteringAborted", 7000, false, "i", playerid);
   
    return 1;
}

forward OnEnteringAborted(playerid);
public OnEnteringAborted(playerid) {
    EnteringStopped(playerid);
}

stock StopMonitoring(vehicleid) {
    g_VehicleData[vehicleid][Monitor] = false;
    g_VehicleData[vehicleid][RePosition] = false;

    if (g_VehicleData[vehicleid][Timer] != -1) {
        KillTimer(g_VehicleData[vehicleid][Timer]);

        g_VehicleData[vehicleid][Timer] = -1;
    }
}

stock UpdateMonitoring(vehicleid, finish_delay = 2000) {
    StopMonitoring(vehicleid);
   
    if (!IsValidVehicle(vehicleid)) {
        return;
    }
   
    g_VehicleData[vehicleid][Monitor] = true;
    g_VehicleData[vehicleid][Timer] = SetTimerEx("OnMonitoringFinish", finish_delay, false, "i", vehicleid);
}

forward OnMonitoringFinish(vehicleid);
public OnMonitoringFinish(vehicleid) {
    if (!IsValidVehicle(vehicleid)) {
        return;
    }
   
    if (IsVehicleBeingEntered(vehicleid)) {
        UpdateMonitoring(vehicleid, 150);
       
        return;
    }
   
    StopMonitoring(vehicleid);
   
    CallRemoteFunction("OnVehicleStoppedMoving", "i", vehicleid);
   
    GetVehicleHealth(vehicleid, g_VehicleData[vehicleid][Health]);
    GetVehicleZAngle(vehicleid, g_VehicleData[vehicleid][ZAngle]);
    GetVehiclePos(
        vehicleid,
        g_VehicleData[vehicleid][X],
        g_VehicleData[vehicleid][Y],
        g_VehicleData[vehicleid][Z]
    );
   
    GetVehicleDamageStatus(
        vehicleid,
        g_VehicleData[vehicleid][DamagePanels],
        g_VehicleData[vehicleid][DamageDoors],
        g_VehicleData[vehicleid][DamageLights],
        g_VehicleData[vehicleid][DamageTires]
    );
   
    g_VehicleData[vehicleid][RePosition] = true;
   
    SetVehicleToRespawn(vehicleid);
}

public OnUnoccupiedVehicleUpdate(vehicleid, playerid, passenger_seat) {
    if (g_VehicleData[vehicleid][Monitor]) {
        UpdateMonitoring(vehicleid);
    }
   
    return 1;
}
Reply
#2

Thanks alot Slice, this has been a real pain in the neck for us DMers having to deal with this all the time, not being able to use normal vehicles due to some bizarre bug.
Reply
#3

nice1 senior muy bueno
Reply
#4

can't this just be fixed (I think - just a theory) wiith just a few SetPlayerPos's when exiting the vehicle? why respawn the vehicle? put player in a bike after exiting car, etc.. can't it be fixed without destroying the vehicle?
Reply
#5

The vehicle has to be destroyed in the client (streamed out, deleted, respawned). Quickly putting the player in a bike would fix it, but that would be annoying if you're jumping out and running away for example.

One other possible solution would be changing the vehicle's virtual world, waiting for it to stream out, then changing it back. Now that I think of it that would be a better solution. It would require a low streaming rate, however.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)