Загрузка данных
#include <amxmodx>
#include <engine>
#include <fakemeta>
#include <xs>
#define PLUGIN "VC Arcade Vehicles"
#define VERSION "0.1"
#define AUTHOR "OpenAI"
#define VEHICLE_CLASS "vc_vehicle"
#define IN_FORWARD (1<<3)
#define IN_BACK (1<<4)
#define IN_USE (1<<5)
#define IN_MOVELEFT (1<<9)
#define IN_MOVERIGHT (1<<10)
#define FL_FROZEN (1<<5)
new g_vehicle[33];
new g_driver[2049];
new g_saved_movetype[33];
new g_saved_solid[33];
new bool:g_was_frozen[33];
new g_model[128] = "models/vc_car.mdl";
new Float:g_accel = 360.0;
new Float:g_brake = 600.0;
new Float:g_max_speed = 750.0;
new Float:g_reverse_speed = 220.0;
new Float:g_drag = 0.985;
new Float:g_steer = 100.0;
new Float:g_lateral_grip = 5.0;
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
register_clcmd("say /car", "cmd_spawn_car");
register_clcmd("say /exit", "cmd_exit_car");
register_forward(FM_PlayerPreThink, "fw_PlayerPreThink");
register_forward(FM_Touch, "fw_Touch");
register_think(VEHICLE_CLASS, "vehicle_think");
}
public plugin_precache()
{
precache_model(g_model);
}
public client_putinserver(id)
{
g_vehicle[id] = 0;
}
public client_disconnected(id)
{
if (g_vehicle[id])
exit_vehicle(id, false);
}
public cmd_spawn_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)
return PLUGIN_HANDLED;
new Float:origin[3], Float:angles[3];
pev(id, pev_origin, origin);
pev(id, pev_v_angle, angles);
new Float:forward[3];
angle_vector(angles, ANGLEVECTOR_FORWARD, forward);
origin[0] += forward[0] * 140.0;
origin[1] += forward[1] * 140.0;
origin[2] += 8.0;
angles[0] = 0.0;
angles[2] = 0.0;
entity_set_string(ent, EV_SZ_classname, VEHICLE_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 = current 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() + 0.02);
client_print(id, print_chat,
"[VC] Car spawned. Approach it and press E.");
return PLUGIN_HANDLED;
}
public fw_PlayerPreThink(id)
{
if (!is_user_alive(id))
return FMRES_IGNORED;
new ent = g_vehicle[id];
if (ent > 0 && pev_valid(ent))
{
new buttons = pev(id, pev_button);
// E exits the vehicle. Clear IN_USE to avoid repeated exits.
if ((buttons & IN_USE) && !(pev(id, pev_oldbuttons) & IN_USE))
{
exit_vehicle(id, true);
return FMRES_IGNORED;
}
// Vehicle movement is handled by vehicle_think().
set_pev(id, pev_velocity, Float:{0.0, 0.0, 0.0});
return FMRES_IGNORED;
}
// Find the nearest vehicle when E is pressed.
new buttons = pev(id, pev_button);
new oldbuttons = pev(id, pev_oldbuttons);
if ((buttons & IN_USE) && !(oldbuttons & IN_USE))
{
new ent2 = find_ent_by_class(-1, VEHICLE_CLASS);
new Float:player_origin[3], Float:car_origin[3];
pev(id, pev_origin, player_origin);
while (ent2 > 0)
{
pev(ent2, pev_origin, car_origin);
if (get_distance_f(player_origin, car_origin) < 110.0
&& g_driver[ent2] == 0)
{
enter_vehicle(id, ent2);
break;
}
ent2 = find_ent_by_class(ent2, VEHICLE_CLASS);
}
}
return FMRES_IGNORED;
}
stock enter_vehicle(id, ent)
{
g_vehicle[id] = ent;
g_driver[ent] = id;
g_saved_movetype[id] = pev(id, pev_movetype);
g_saved_solid[id] = pev(id, pev_solid);
g_was_frozen[id] = (pev(id, pev_flags) & FL_FROZEN) != 0;
set_pev(id, pev_movetype, MOVETYPE_NOCLIP);
set_pev(id, pev_solid, SOLID_NOT);
client_print(id, print_center,
"W/S - accelerate/brake | A/D - steer | E - exit");
}
stock exit_vehicle(id, bool:restore_position)
{
new ent = g_vehicle[id];
if (ent <= 0)
return;
if (pev_valid(ent))
{
new Float:origin[3], Float:angles[3], Float:right[3];
pev(ent, pev_origin, origin);
pev(ent, pev_angles, angles);
angle_vector(angles, ANGLEVECTOR_RIGHT, right);
origin[0] += right[0] * 65.0;
origin[1] += right[1] * 65.0;
origin[2] += 25.0;
if (restore_position)
engfunc(EngFunc_SetOrigin, id, origin);
g_driver[ent] = 0;
}
g_vehicle[id] = 0;
set_pev(id, pev_movetype, g_saved_movetype[id]);
set_pev(id, pev_solid, g_saved_solid[id]);
if (g_was_frozen[id])
{
new flags = pev(id, pev_flags);
set_pev(id, pev_flags, flags | FL_FROZEN);
}
else
{
new flags = pev(id, pev_flags);
set_pev(id, pev_flags, flags & ~FL_FROZEN);
}
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);
// Acceleration and braking.
if (buttons & IN_FORWARD)
{
speed += g_accel * 0.02;
}
else if (buttons & IN_BACK)
{
if (speed > 0.0)
speed -= g_brake * 0.02;
else
speed -= g_accel * 0.02;
}
else
{
speed *= g_drag;
}
if (speed > g_max_speed)
speed = g_max_speed;
if (speed < -g_reverse_speed)
speed = -g_reverse_speed;
// Steering fades at very low speed.
new Float:steering = 0.0;
if (buttons & IN_MOVELEFT)
steering += 1.0;
if (buttons & IN_MOVERIGHT)
steering -= 1.0;
new Float:steer_factor = floatabs(speed) / g_max_speed;
if (steer_factor > 1.0)
steer_factor = 1.0;
yaw += steering * g_steer * steer_factor * 0.02;
new Float:angles[3];
angles[0] = 0.0;
angles[1] = yaw;
angles[2] = 0.0;
set_pev(ent, pev_angles, angles);
new Float:forward[3], Float:velocity[3];
angle_vector(angles, ANGLEVECTOR_FORWARD, forward);
pev(ent, pev_velocity, velocity);
// Arcade lateral grip: suppress sideways sliding.
new Float:forward_speed =
velocity[0] * forward[0] +
velocity[1] * forward[1];
new Float:target_x = forward[0] * speed;
new Float:target_y = forward[1] * speed;
velocity[0] += (target_x - velocity[0])
* g_lateral_grip * 0.02;
velocity[1] += (target_y - velocity[1])
* g_lateral_grip * 0.02;
velocity[2] = 0.0;
set_pev(ent, pev_velocity, velocity);
set_pev(ent, pev_fuser1, speed);
set_pev(ent, pev_fuser2, yaw);
// Keep the driver attached above the vehicle.
new Float:origin[3];
pev(ent, pev_origin, origin);
origin[2] += 24.0;
engfunc(EngFunc_SetOrigin, driver, origin);
new Float:view_angles[3];
pev(driver, pev_v_angle, view_angles);
view_angles[1] = yaw;
set_pev(driver, pev_angles, view_angles);
set_pev(driver, pev_fixangle, 1);
}
else if (driver > 0)
{
g_driver[ent] = 0;
}
set_pev(ent, pev_nextthink, get_gametime() + 0.02);
}
public fw_Touch(ent, other)
{
if (!pev_valid(ent))
return FMRES_IGNORED;
static classname[32];
pev(ent, pev_classname, classname, charsmax(classname));
if (!equal(classname, VEHICLE_CLASS))
return FMRES_IGNORED;
if (other > 0 && pev_valid(other))
{
new Float:velocity[3];
pev(ent, pev_velocity, velocity);
// Basic arcade collision damping.
velocity[0] *= 0.55;
velocity[1] *= 0.55;
set_pev(ent, pev_velocity, velocity);
set_pev(ent, pev_fuser1, 0.0);
}
return FMRES_IGNORED;
}
stock angle_vector(const Float:angles[3], mode, Float:output[3])
{
new Float:forward[3], Float:right[3], Float:up[3];
engfunc(EngFunc_AngleVectors, angles, forward, right, up);
if (mode == ANGLEVECTOR_FORWARD)
xs_vec_copy(forward, output);
else if (mode == ANGLEVECTOR_RIGHT)
xs_vec_copy(right, output);
else
xs_vec_copy(up, output);
}