311 lines
8.0 KiB
C++
311 lines
8.0 KiB
C++
#include "openworld.hpp"
|
|
|
|
#include <iostream>
|
|
|
|
#include "player.hpp"
|
|
#include "vehicle.hpp"
|
|
#include "player_character.hpp"
|
|
#include "npc_character.hpp"
|
|
#include "drivable_vehicle.hpp"
|
|
#include "destroyed_object.hpp"
|
|
#include "marker.hpp"
|
|
#include "tuning_world.hpp"
|
|
#include "game.hpp"
|
|
#include "cow.hpp"
|
|
|
|
namespace game
|
|
{
|
|
|
|
} // namespace game
|
|
|
|
|
|
static const char* GetRandomCarModel()
|
|
{
|
|
const char* vehicles[] = {"pickup_hd", "passat", "twingo", "polskifiat", "cow_static", "pig_static", "avia"};
|
|
return vehicles[rand() % (sizeof(vehicles) / sizeof(vehicles[0]))];
|
|
}
|
|
|
|
static glm::vec3 GetRandomColor()
|
|
{
|
|
glm::vec3 color;
|
|
// shittiest way to do it
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
net::ColorQ qcol;
|
|
qcol.value = rand() % 256;
|
|
color[i] = qcol.Decode();
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
static uint32_t GetRandomColor24()
|
|
{
|
|
uint8_t r,g,b;
|
|
r = rand() % 256;
|
|
g = rand() % 256;
|
|
b = rand() % 256;
|
|
return (b << 16) | (g << 8) | r;
|
|
}
|
|
|
|
game::OpenWorld::OpenWorld(Game& game) : EnterableWorld("openworld"), game_(game)
|
|
{
|
|
// spawn bots
|
|
for (size_t i = 0; i < 100; ++i)
|
|
{
|
|
SpawnBot();
|
|
}
|
|
|
|
// initial twingo
|
|
VehicleTuning twingo_tuning;
|
|
twingo_tuning.model = "twingo";
|
|
twingo_tuning.parts["primarycolor"] = "orange";
|
|
// twingo_tuning.primary_color = 0x0077FF;
|
|
// twingo_tuning.wheels_idx = 1; // enkei
|
|
// twingo_tuning.wheel_color = 0x00FF00;
|
|
|
|
auto& veh = Spawn<game::DrivableVehicle>(twingo_tuning);
|
|
veh.SetPosition({110.0f, 100.0f, 5.0f});
|
|
|
|
constexpr size_t in_row = 20;
|
|
|
|
for (size_t i = 0; i < 100; ++i)
|
|
{
|
|
Schedule(i * 40, [this, i] {
|
|
size_t col = i % in_row;
|
|
size_t row = i / in_row;
|
|
glm::vec3 pos(62.0f + static_cast<float>(col) * 4.0f, 165.0f + static_cast<float>(row) * 7.0f, 7.0f);
|
|
|
|
auto& veh = SpawnRandomVehicle();
|
|
veh.SetPosition(pos);
|
|
});
|
|
}
|
|
|
|
daytime_offset_ = static_cast<float>(rand() % 24);
|
|
|
|
for (auto locs = GetMap().GetLocations("tuning"); const auto& loc : locs)
|
|
{
|
|
CreateTuningGarage(loc.transform.position, glm::eulerAngles(loc.transform.rotation).x);
|
|
}
|
|
|
|
// cow
|
|
auto& cow = Spawn<Cow>(glm::vec3(0.0f, 0.0f, 2.0f), 0.0f);
|
|
cow.SetNametag("no ty krávo");
|
|
}
|
|
|
|
void game::OpenWorld::Update(int64_t delta_time)
|
|
{
|
|
Super::Update(delta_time);
|
|
|
|
const float day_seconds_irl = 1800.0f;
|
|
const float timespeed = 24.0f / day_seconds_irl;
|
|
SetDayTime(static_cast<float>(GetTime()) * 0.001f * timespeed + daytime_offset_);
|
|
}
|
|
|
|
void game::OpenWorld::PlayerInput(Player& player, PlayerInputType type, bool enabled)
|
|
{
|
|
if (type == IN_DEBUG2 && enabled)
|
|
{
|
|
RecoverPlayer(player);
|
|
return;
|
|
}
|
|
|
|
Super::PlayerInput(player, type, enabled);
|
|
}
|
|
|
|
game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()
|
|
{
|
|
game::VehicleTuning tuning;
|
|
tuning.model = GetRandomCarModel();
|
|
// tuning.primary_color = GetRandomColor24();
|
|
|
|
auto& vehicle = Spawn<game::DrivableVehicle>(tuning);
|
|
// vehicle.SetNametag("bot (" + std::to_string(vehicle.GetEntNum()) + ")");
|
|
|
|
auto& tuning_list = vehicle.GetTuningList();
|
|
|
|
// make random tuning
|
|
std::vector<std::string> suitable_part_ids;
|
|
for (const auto& group : tuning_list->groups)
|
|
{
|
|
suitable_part_ids.clear();
|
|
|
|
bool add_nonstock = rand() % 100 < 3;
|
|
|
|
for (const auto& part : group.parts)
|
|
{
|
|
if (part.second.stock || add_nonstock)
|
|
suitable_part_ids.push_back(part.first);
|
|
}
|
|
|
|
if (suitable_part_ids.empty())
|
|
continue;
|
|
|
|
size_t random_part = rand() % suitable_part_ids.size();
|
|
tuning.parts[group.id] = suitable_part_ids[random_part];
|
|
}
|
|
|
|
// auto& colors = tuning_list->groups[0].parts;
|
|
|
|
// size_t random_color = rand() % colors.size();
|
|
|
|
// auto item = colors.begin();
|
|
// std::advance( item, random_color);
|
|
|
|
// tuning.parts["primarycolor"] = item->second.id;
|
|
|
|
vehicle.SetTuning(tuning);
|
|
|
|
return vehicle;
|
|
}
|
|
|
|
void game::OpenWorld::SpawnBot()
|
|
{
|
|
auto roads = GetMap().GetGraph("roads");
|
|
|
|
if (!roads)
|
|
{
|
|
throw std::runtime_error("SpawnBot: no roads graph in map");
|
|
}
|
|
|
|
size_t start_node = rand() % roads->nodes.size();
|
|
|
|
auto& vehicle = SpawnRandomVehicle();
|
|
vehicle.SetPosition(roads->nodes[start_node].position + glm::vec3{0.0f, 0.0f, 5.0f});
|
|
|
|
HumanCharacterTuning npc_tuning;
|
|
npc_tuning.clothes.push_back({ "tshirt", GetRandomColor24() });
|
|
npc_tuning.clothes.push_back({ "shorts", GetRandomColor24() });
|
|
|
|
auto& driver = Spawn<NpcCharacter>(npc_tuning);
|
|
driver.Ride(&vehicle, 0);
|
|
}
|
|
|
|
void game::OpenWorld::CreateTuningGarage(const glm::vec3& position, float yaw)
|
|
{
|
|
auto garage = std::make_shared<TuningWorld>(game_, *this, position, yaw, "garage");
|
|
game_.AddWorld(garage.get());
|
|
|
|
MarkerInfo marker_info{};
|
|
marker_info.position = position;
|
|
marker_info.type = MARKER_VEHICLE;
|
|
marker_info.color = 0x884400;
|
|
marker_info.icon = "tuning";
|
|
|
|
auto& marker = Spawn<Marker>(marker_info);
|
|
marker.SetUseTarget("vject do tunírny",
|
|
[garage](PlayerCharacter& character, UseTargetQueryResult& res) {
|
|
|
|
auto player = character.GetPlayer();
|
|
auto vehicle = character.GetVehicle();
|
|
|
|
if (!vehicle)
|
|
{
|
|
res.enabled = false;
|
|
res.error_text = "nemáš vehikl";
|
|
return true;
|
|
}
|
|
|
|
if (vehicle->GetPassenger(0) != &character)
|
|
{
|
|
return false; // not driver
|
|
}
|
|
|
|
if (garage->IsOccupied())
|
|
{
|
|
res.enabled = false;
|
|
res.error_text = "někdo tam už oxiduje";
|
|
return true;
|
|
}
|
|
|
|
res.enabled = true;
|
|
res.error_text = nullptr;
|
|
res.delay = 0.2f;
|
|
return true;
|
|
},
|
|
[this, garage, &marker](PlayerCharacter& character) {
|
|
auto player = character.GetPlayer();
|
|
game_.MovePlayerToWorld(*player, *garage, true, glm::vec3(0.0f), 0.0f);
|
|
marker.SetNametag(player->GetName());
|
|
}
|
|
);
|
|
|
|
garage->SetOnExit([&marker]() {
|
|
marker.SetNametag(std::string());
|
|
});
|
|
}
|
|
|
|
void game::OpenWorld::RecoverPlayer(Player& player)
|
|
{
|
|
auto character = GetPlayerCharacter(player);
|
|
if (!character)
|
|
return;
|
|
|
|
auto vehicle = character->GetVehicle();
|
|
|
|
if (!vehicle)
|
|
{
|
|
auto pos = character->GetRoot().GetGlobalPosition();
|
|
glm::vec3 recovery;
|
|
if (GetRecoveryPosition(pos, recovery))
|
|
{
|
|
character->SetPosition(recovery);
|
|
}
|
|
else
|
|
{
|
|
player.SendChat("nejsi pod zemí");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (vehicle->GetPassenger(0) != character)
|
|
return; // not driver
|
|
|
|
auto pos = vehicle->GetRoot().GetGlobalPosition();
|
|
glm::vec3 recovery;
|
|
if (GetRecoveryPosition(pos, recovery))
|
|
{
|
|
vehicle->SetPosition(recovery);
|
|
}
|
|
else
|
|
{
|
|
player.SendChat("nejsi pod zemí");
|
|
}
|
|
}
|
|
|
|
static bool RecoveryRaycast(btCollisionWorld& bt_world, const glm::vec3& pos, glm::vec3& hit)
|
|
{
|
|
btVector3 bt_from(pos.x, pos.y, 100.0f);
|
|
btVector3 bt_to(pos.x, pos.y, -100.0f);
|
|
btCollisionWorld::ClosestRayResultCallback cb(bt_from, bt_to);
|
|
bt_world.rayTest(bt_from, bt_to, cb);
|
|
|
|
if (!cb.hasHit())
|
|
return false;
|
|
|
|
hit = glm::vec3(cb.m_hitPointWorld.x(), cb.m_hitPointWorld.y(), cb.m_hitPointWorld.z());
|
|
return true;
|
|
}
|
|
|
|
bool game::OpenWorld::GetRecoveryPosition(const glm::vec3& current, glm::vec3& recovery)
|
|
{
|
|
glm::vec3 start = current;
|
|
start = glm::max(start, glm::vec3(-2500.0f, -2500.0f, -1000.0f));
|
|
start = glm::min(start, glm::vec3(3400.0f, 3100.0f, 1000.0f));
|
|
|
|
if (!RecoveryRaycast(GetBtWorld(), start, recovery))
|
|
{
|
|
recovery = glm::vec3(0.0f, 0.0f, 5.0f);
|
|
return true;
|
|
|
|
}
|
|
|
|
if (recovery.z - 5.0f < current.z)
|
|
{
|
|
return false; // already above ground
|
|
}
|
|
|
|
recovery.z += 5.0f;
|
|
return true;
|
|
}
|