Загрузка данных
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <fun>
#define PLUGIN "VC Vehicles"
#define VERSION "0.2"
#define AUTHOR "OpenAI"
#define VEH_CLASS "vc_vehicle"
#define MAX_EDICTS 2049
#define DT 0.02
new g_driver[MAX_EDICTS];
new g_vehicle[33];
new g_old_movetype[33];
new g_old_solid[33];
new g_model[128] = "models/vc_car.mdl";
new g_pc_accel;
new g_pc_brake;
new g_pc_maxspeed;
new g_pc_reverse;
new g_pc_steer;
new g_pc_grip;
new g_pc_drift_grip;
new g_pc_drag;
public plugin_precache()
{
// A valid model must exist before the map starts.
// Use a standard CS model as a temporary visual fallback.
if (file_exists(g_model))
{
precache_model(g_model);
}
else
{
server_print("[VC] models/vc_car.mdl not found; using w_usp.mdl");
copy(g_model, charsmax(g_model), "models/w_usp.mdl");
precache_model(g_model);
}
}
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
register_clcmd("say /car", "cmd_car");
register_clcmd("say_team /car", "cmd_car");
register_clcmd("say /exit", "cmd_exit");
register_forward(FM_PlayerPreThink, "fw_player_prethink");
register_forward(FM_Touch, "fw_touch");
register_think(VEH_CLASS, "vehicle_think");
g_pc_accel = register_cvar("vc_accel", "420.0");
g_pc_brake = register_cvar("vc_brake", "650.0");
g_pc_maxspeed = register_cvar("vc_maxspeed", "750.0");
g_pc_reverse = register_cvar("vc_reverse", "220.0");
g_pc_steer = register_cvar("vc_steer", "105.0");
g_pc_grip = register_cvar("vc_grip", "5.0");
g_pc_drift_grip = register_cvar("vc_drift_grip", "1.15");
g_pc_drag = register_cvar("vc_drag", "0.992");
}
public client_disconnected(id)
{
if (g_vehicle[id])
exit_vehicle(id, true);
}
public cmd_car(id)
{
if (!is_user_alive(id))
return PLUGIN_HANDLED;
if (g_vehicle[id])
{
client_print(id, print_chat, "[VC] You are already driving.");
return PLUGIN_HANDLED;
}
new ent = create_entity("info_target");
if (!ent || ent >= MAX_EDICTS)
{
if (ent > 0)
remove_entity(ent);
client_print(id, print_chat, "[VC] Could not create vehicle.");
return PLUGIN_HANDLED;
}
new Float:origin[3], Float:angles[3], Float:forward[3];
pev(id, pev_origin, origin);
pev(id, pev_v_angle, angles);
angles[0] = 0.0;
angles[2] = 0.0;
engfunc(EngFunc_MakeVectors, angles);
global_get(glb_v_forward, forward);
origin[0] += forward[0] * 150.0;
origin[1] += forward[1] * 150.0;
origin[2] += 8.0;
entity_set_string(ent, EV_SZ_classname, VEH_CLASS);
entity_set_model(ent, g_model);
entity_set_origin(ent, origin);
entity_set_size(ent,
Float:{-42.0, -22.0, -8.0},
Float:{ 42.0, 22.0, 30.0});
set_pev(ent, pev_movetype, MOVETYPE_FLY);
set_pev(ent, pev_solid, SOLID_BBOX);
set_pev(ent, pev_angles, angles);
set_pev(ent, pev_velocity, Float:{0.0, 0.0, 0.0});
// fuser1 = signed forward speed
// fuser2 = vehicle yaw
set_pev(ent, pev_fuser1, 0.0);
set_pev(ent, pev_fuser2, angles[1]);
g_driver[ent] = 0;
set_pev(ent, pev_nextthink, get_gametime() + DT);
client_print(id, print_chat,
"[VC] Vehicle spawned. Approach it and press E.");
return PLUGIN_HANDLED;
}
public cmd_exit(id)
{
if (g_vehicle[id])
exit_vehicle(id, true);
return PLUGIN_HANDLED;
}
public fw_player_prethink(id)
{
if (!is_user_alive(id))
return FMRES_IGNORED;
new buttons = pev(id, pev_button);
new oldbuttons = pev(id, pev_oldbuttons);
if (g_vehicle[id] > 0)
{
if ((buttons & IN_USE) && !(oldbuttons & IN_USE))
{
exit_vehicle(id, true);
return FMRES_IGNORED;
}
// Vehicle physics controls movement while driving.
set_pev(id, pev_velocity, Float:{0.0, 0.0, 0.0});
return FMRES_IGNORED;
}
if ((buttons & IN_USE) && !(oldbuttons & IN_USE))
{
new ent = find_ent_by_class(-1, VEH_CLASS);
new Float:player_origin[3], Float:car_origin[3];
pev(id, pev_origin, player_origin);
while (ent > 0)
{
if (ent < MAX_EDICTS && pev_valid(ent)
&& g_driver[ent] == 0)
{
pev(ent, pev_origin, car_origin);
if (get_distance_f(player_origin, car_origin) < 110.0)
{
enter_vehicle(id, ent);
break;
}
}
ent = find_ent_by_class(ent, VEH_CLASS);
}
}
return FMRES_IGNORED;
}
stock enter_vehicle(id, ent)
{
g_vehicle[id] = ent;
g_driver[ent] = id;
g_old_movetype[id] = pev(id, pev_movetype);
g_old_solid[id] = pev(id, pev_solid);
set_pev(id, pev_movetype, MOVETYPE_NOCLIP);
set_pev(id, pev_solid, SOLID_NOT);
set_view(id, CAMERA_3RDPERSON);
client_print(id, print_center,
"W/S Drive | A/D Steer | SPACE Drift | E Exit");
}
stock exit_vehicle(id, bool:restore_position)
{
new ent = g_vehicle[id];
if (!ent)
return;
if (pev_valid(ent))
{
new Float:origin[3], Float:angles[3];
new Float:right[3];
pev(ent, pev_origin, origin);
pev(ent, pev_angles, angles);
engfunc(EngFunc_MakeVectors, angles);
global_get(glb_v_right, right);
origin[0] += right[0] * 68.0;
origin[1] += right[1] * 68.0;
origin[2] += 30.0;
if (restore_position)
engfunc(EngFunc_SetOrigin, id, origin);
g_driver[ent] = 0;
}
g_vehicle[id] = 0;
set_view(id, CAMERA_NONE);
set_pev(id, pev_movetype, g_old_movetype[id]);
set_pev(id, pev_solid, g_old_solid[id]);
set_pev(id, pev_velocity, Float:{0.0, 0.0, 0.0});
}
public vehicle_think(ent)
{
if (!pev_valid(ent))
return;
new Float:speed, Float:yaw;
pev(ent, pev_fuser1, speed);
pev(ent, pev_fuser2, yaw);
new driver = g_driver[ent];
if (driver > 0 && is_user_alive(driver))
{
new buttons = pev(driver, pev_button);
new Float:accel = get_pcvar_float(g_pc_accel);
new Float:brake = get_pcvar_float(g_pc_brake);
new Float:maxspeed = get_pcvar_float(g_pc_maxspeed);
new Float:reverse = get_pcvar_float(g_pc_reverse);
new Float:steer_rate = get_pcvar_float(g_pc_steer);
new Float:grip = get_pcvar_float(g_pc_grip);
new Float:drift_grip = get_pcvar_float(g_pc_drift_grip);
new Float:drag = get_pcvar_float(g_pc_drag);
// Gas and braking.
if (buttons & IN_FORWARD)
{
if (speed < 0.0)
speed += brake * DT;
else
speed += accel * DT;
}
else if (buttons & IN_BACK)
{
if (speed > 0.0)
speed -= brake * DT;
else
speed -= accel * DT;
}
else
{
speed *= drag;
if (floatabs(speed) < 2.0)
speed = 0.0;
}
if (speed > maxspeed)
speed = maxspeed;
if (speed < -reverse)
speed = -reverse;
// Steering depends on speed. Reverse steering is inverted.
new Float:steer = 0.0;
if (buttons & IN_MOVELEFT)
steer += 1.0;
if (buttons & IN_MOVERIGHT)
steer -= 1.0;
new Float:speed_factor = floatabs(speed) / maxspeed;
if (speed_factor > 1.0)
speed_factor = 1.0;
if (speed_factor < 0.08)
speed_factor = 0.0;
new Float:direction = 1.0;
if (speed < 0.0)
direction = -1.0;
yaw += steer * steer_rate * speed_factor
* direction * DT;
new Float:angles[3];
angles[0] = 0.0;
angles[1] = yaw;
angles[2] = 0.0;
set_pev(ent, pev_angles, angles);
// Desired forward velocity.
engfunc(EngFunc_MakeVectors, angles);
new Float:forward[3];
global_get(glb_v_forward, forward);
new Float:velocity[3];
pev(ent, pev_velocity, velocity);
// Keep the current lateral velocity, then damp it according
// to normal grip or the reduced grip used while drifting.
new Float:longitudinal =
velocity[0] * forward[0] +
velocity[1] * forward[1];
new Float:side_x = velocity[0] - forward[0] * longitudinal;
new Float:side_y = velocity[1] - forward[1] * longitudinal;
new Float:active_grip = grip;
if (buttons & IN_JUMP)
active_grip = drift_grip;
new Float:blend = active_grip * DT;
if (blend > 1.0)
blend = 1.0;
side_x *= (1.0 - blend);
side_y *= (1.0 - blend);
velocity[0] = forward[0] * speed + side_x;
velocity[1] = forward[1] * speed + side_y;
// No artificial vertical propulsion.
// MOVETYPE_FLY still does not provide wheel suspension.
velocity[2] = 0.0;
set_pev(ent, pev_velocity, velocity);
set_pev(ent, pev_fuser1, speed);
set_pev(ent, pev_fuser2, yaw);
// Attach the player to the driver's seat.
new Float:car_origin[3];
pev(ent, pev_origin, car_origin);
car_origin[2] += 12.0;
engfunc(EngFunc_SetOrigin, driver, car_origin);
// Align the player's view with the vehicle.
new Float:view_angles[3];
pev(driver, pev_v_angle, view_angles);
view_angles[0] = 0.0;
view_angles[1] = yaw;
view_angles[2] = 0.0;
set_pev(driver, pev_v_angle, view_angles);
set_pev(driver, pev_angles, view_angles);
set_pev(driver, pev_fixangle, 1);
}
else if (driver > 0)
{
if (is_user_connected(driver))
exit_vehicle(driver, true);
else
g_driver[ent] = 0;
}
set_pev(ent, pev_nextthink, get_gametime() + DT);
}
public fw_touch(ent, other)
{
if (ent <= 0 || ent >= MAX_EDICTS || !pev_valid(ent))
return FMRES_IGNORED;
static classname[32];
pev(ent, pev_classname, classname, charsmax(classname));
if (!equal(classname, VEH_CLASS))
return FMRES_IGNORED;
if (other > 0 && pev_valid(other))
{
new Float:velocity[3], Float:speed;
pev(ent, pev_velocity, velocity);
pev(ent, pev_fuser1, speed);
// Arcade impact damping.
velocity[0] *= 0.60;
velocity[1] *= 0.60;
speed *= 0.60;
set_pev(ent, pev_velocity, velocity);
set_pev(ent, pev_fuser1, speed);
}
return FMRES_IGNORED;
}