mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 18:32:44 +01:00
Add more opcodes and vehicle handling
This commit is contained in:
parent
2709e7d252
commit
7963becbd1
@ -5,7 +5,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
#define ZONE_GANG_COUNT 10
|
||||
#define ZONE_GANG_COUNT 11
|
||||
|
||||
/**
|
||||
* \class Zone
|
||||
|
@ -19,6 +19,14 @@ struct TextDisplayData
|
||||
glm::vec4 colourBG;
|
||||
};
|
||||
|
||||
struct OnscreenText
|
||||
{
|
||||
std::string osTextString;
|
||||
float osTextStart;
|
||||
float osTextTime;
|
||||
unsigned short osTextStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about where the game can generate vehicles.
|
||||
*/
|
||||
@ -73,25 +81,27 @@ struct GameState
|
||||
bool isIntroPlaying;
|
||||
CutsceneData* currentCutscene;
|
||||
float cutsceneStartTime;
|
||||
/** Flag for rendering cutscene letterbox */
|
||||
bool isCinematic;
|
||||
|
||||
short hour;
|
||||
short minute;
|
||||
|
||||
/// @todo opcodes seem to imply Onscreen text might be queued
|
||||
unsigned short osTextStyle;
|
||||
std::string osTextString;
|
||||
float osTextStart;
|
||||
float osTextTime;
|
||||
|
||||
|
||||
|
||||
/// Stores the "special" character and cutscene model indices.
|
||||
std::map<unsigned short, std::string> specialCharacters;
|
||||
std::map<unsigned short, std::string> specialModels;
|
||||
|
||||
std::vector<OnscreenText> text;
|
||||
|
||||
TextDisplayData nextText;
|
||||
std::vector<TextDisplayData> texts;
|
||||
|
||||
/** The camera near value currently set by the script */
|
||||
float cameraNear;
|
||||
bool cameraFixed;
|
||||
glm::vec3 cameraPosition;
|
||||
glm::quat cameraRotation;
|
||||
|
||||
std::vector<VehicleGenerator> vehicleGenerators;
|
||||
|
||||
@ -113,12 +123,11 @@ struct GameState
|
||||
isIntroPlaying(false),
|
||||
currentCutscene(nullptr),
|
||||
cutsceneStartTime(-1.f),
|
||||
isCinematic(false),
|
||||
hour(0),
|
||||
minute(0),
|
||||
osTextStyle(0),
|
||||
osTextStart(0.f),
|
||||
osTextTime(0.f),
|
||||
cameraNear(0.1f)
|
||||
cameraNear(0.1f),
|
||||
cameraFixed(false)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -54,7 +54,11 @@ void CharacterController::update(float dt)
|
||||
// Nevermind, the player is in a vehicle.
|
||||
|
||||
character->getCurrentVehicle()->setSteeringAngle(d.y);
|
||||
// TODO what is handbraking.
|
||||
|
||||
if( std::abs(d.x) > 0.01f )
|
||||
{
|
||||
character->getCurrentVehicle()->setHandbraking(false);
|
||||
}
|
||||
character->getCurrentVehicle()->setThrottle(d.x);
|
||||
|
||||
// if the character isn't doing anything, play sitting anim.
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
VehicleObject::VehicleObject(GameWorld* engine, const glm::vec3& pos, const glm::quat& rot, ModelHandle* model, VehicleDataHandle data, VehicleInfoHandle info, const glm::u8vec3& prim, const glm::u8vec3& sec)
|
||||
: GameObject(engine, pos, rot, model),
|
||||
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(false),
|
||||
steerAngle(0.f), throttle(0.f), brake(0.f), handbrake(true),
|
||||
vehicle(data), info(info), colourPrimary(prim),
|
||||
colourSecondary(sec), collision(nullptr), physBody(nullptr), physVehicle(nullptr)
|
||||
{
|
||||
@ -147,6 +147,13 @@ void VehicleObject::tickPhysics(float dt)
|
||||
float velFac = (info->handling.maxVelocity - physVehicle->getCurrentSpeedKmHour()) / info->handling.maxVelocity;
|
||||
float engineForce = info->handling.acceleration * 150.f * throttle * velFac;
|
||||
if( fabs(engineForce) >= 0.001f ) physBody->activate(true);
|
||||
|
||||
float brakeF = getBraking();
|
||||
|
||||
if( handbrake )
|
||||
{
|
||||
brakeF = 2.f;
|
||||
}
|
||||
|
||||
for(int w = 0; w < physVehicle->getNumWheels(); ++w) {
|
||||
btWheelInfo& wi = physVehicle->getWheelInfo(w);
|
||||
@ -157,8 +164,8 @@ void VehicleObject::tickPhysics(float dt)
|
||||
physVehicle->applyEngineForce(engineForce, w);
|
||||
}
|
||||
|
||||
float brakeReal = info->handling.brakeDeceleration * info->handling.mass * (wi.m_bIsFrontWheel? info->handling.brakeBias : 1.f - info->handling.brakeBias);
|
||||
physVehicle->setBrake(brakeReal * brake, w);
|
||||
float brakeReal = 10.f * info->handling.brakeDeceleration * (wi.m_bIsFrontWheel? info->handling.brakeBias : 1.f - info->handling.brakeBias);
|
||||
physVehicle->setBrake(brakeReal * brakeF, w);
|
||||
|
||||
if(wi.m_bIsFrontWheel) {
|
||||
float sign = std::signbit(steerAngle) ? -1.f : 1.f;
|
||||
|
@ -449,7 +449,7 @@ void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
if( engine->state.currentCutscene && splashTexName == 0 ) {
|
||||
if( engine->state.isCinematic && splashTexName == 0 ) {
|
||||
renderLetterbox();
|
||||
}
|
||||
|
||||
|
@ -101,26 +101,54 @@ VM_OPCODE_DEF( 0x00A5 )
|
||||
{
|
||||
auto id = p->at(0).integer;
|
||||
glm::vec3 position(p->at(1).real, p->at(2).real, p->at(3).real);
|
||||
position += spawnMagic;
|
||||
|
||||
// If there is already a vehicle less than this distance away, it will be destroyed.
|
||||
const float replaceThreshold = 1.f;
|
||||
for( auto it = m->getWorld()->objects.begin();
|
||||
it != m->getWorld()->objects.end();
|
||||
++it)
|
||||
{
|
||||
if( (*it)->type() == GameObject::Vehicle && glm::distance(position, (*it)->getPosition()) < replaceThreshold )
|
||||
{
|
||||
m->getWorld()->destroyObjectQueued(*it);
|
||||
}
|
||||
}
|
||||
|
||||
auto vehicle = m->getWorld()->createVehicle(id, position + spawnMagic);
|
||||
auto vehicle = m->getWorld()->createVehicle(id, position);
|
||||
|
||||
*p->at(4).handle = vehicle;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x00BA )
|
||||
{
|
||||
std::string str(p->at(0).string);
|
||||
str = m->getWorld()->gameData.texts.text(str);
|
||||
unsigned short style = p->at(2).integer;
|
||||
m->getWorld()->state.text.push_back({
|
||||
str,
|
||||
m->getWorld()->gameTime,
|
||||
p->at(1).integer / 1000.f,
|
||||
style
|
||||
});
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x00BC )
|
||||
{
|
||||
std::string str(p->at(0).string);
|
||||
str = m->getWorld()->gameData.texts.text(str);
|
||||
m->getWorld()->state.osTextString = str;
|
||||
m->getWorld()->state.osTextTime = p->at(1).integer / 1000.f;
|
||||
m->getWorld()->state.osTextStart= m->getWorld()->gameTime;
|
||||
m->getWorld()->state.osTextStyle = p->at(2).integer;
|
||||
int flags = p->at(2).integer;
|
||||
m->getWorld()->state.text.push_back({
|
||||
str,
|
||||
m->getWorld()->gameTime,
|
||||
p->at(1).integer / 1000.f,
|
||||
0
|
||||
});
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x00BE )
|
||||
{
|
||||
m->getWorld()->state.osTextTime = 0.f;
|
||||
m->getWorld()->state.osTextStart= 0.f;
|
||||
m->getWorld()->state.text.clear();
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x00C0 )
|
||||
@ -296,6 +324,40 @@ VM_OPCODE_DEF( 0x015C )
|
||||
}
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x015F )
|
||||
{
|
||||
glm::vec3 position( p->at(0).real, p->at(1).real, p->at(2).real );
|
||||
glm::vec3 angles( p->at(3).real, p->at(4).real, p->at(5).real );
|
||||
|
||||
m->getWorld()->state.cameraFixed = true;
|
||||
m->getWorld()->state.cameraPosition = position;
|
||||
m->getWorld()->state.cameraRotation = glm::quat(angles);
|
||||
}
|
||||
VM_OPCODE_DEF( 0x0160 )
|
||||
{
|
||||
glm::vec3 position( p->at(0).real, p->at(1).real, p->at(2).real );
|
||||
int switchmode = p->at(3).integer;
|
||||
|
||||
auto direction = glm::normalize(position - m->getWorld()->state.cameraPosition);
|
||||
auto right = glm::normalize(glm::cross(glm::vec3(0.f, 0.f, 1.f), direction));
|
||||
auto up = glm::normalize(glm::cross(direction, right));
|
||||
|
||||
glm::mat3 v;
|
||||
v[0][0] = direction.x;
|
||||
v[0][1] = right.x;
|
||||
v[0][2] = up.x;
|
||||
|
||||
v[1][0] = direction.y;
|
||||
v[1][1] = right.y;
|
||||
v[1][2] = up.y;
|
||||
|
||||
v[2][0] = direction.z;
|
||||
v[2][1] = right.z;
|
||||
v[2][2] = up.z;
|
||||
|
||||
m->getWorld()->state.cameraRotation = glm::inverse(glm::quat_cast(v));
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x0169 )
|
||||
{
|
||||
m->getWorld()->state.fadeColour.r = p->at(0).integer;
|
||||
@ -376,6 +438,14 @@ VM_OPCODE_DEF( 0x01C7 )
|
||||
std::cout << "Unable to pin object " << inst << ". Object pinning unimplimented" << std::endl;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x01D4 )
|
||||
{
|
||||
auto controller = (CharacterController*)(*p->at(0).handle);
|
||||
auto vehicle = (VehicleObject*)(*p->at(1).handle);
|
||||
/// @todo find next lowest free seat.
|
||||
controller->setNextActivity(new Activities::EnterVehicle(vehicle,1));
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x01E7 )
|
||||
{
|
||||
glm::vec3 min(p->at(0).real,p->at(1).real,p->at(2).real);
|
||||
@ -408,6 +478,13 @@ VM_OPCODE_DEF( 0x01F5 )
|
||||
*p->at(1).handle = controller;
|
||||
}
|
||||
|
||||
VM_CONDOPCODE_DEF( 0x01F3 )
|
||||
{
|
||||
/// @todo IS vehicle in air.
|
||||
auto vehicle = (VehicleObject*)(*p->at(0).handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
VM_CONDOPCODE_DEF( 0x0204 )
|
||||
{
|
||||
auto controller = (CharacterController*)(*p->at(0).handle);
|
||||
@ -544,6 +621,20 @@ VM_OPCODE_DEF( 0x029B )
|
||||
|
||||
*p->at(4).handle = inst;
|
||||
}
|
||||
VM_CONDOPCODE_DEF( 0x029C )
|
||||
{
|
||||
/*auto vehicle = (VehicleObject*)(*p->at(0).handle);
|
||||
if( vehicle )
|
||||
{
|
||||
return vehicle->vehicle->type == VehicleData::BOAT;
|
||||
}*/
|
||||
return false;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x02A3 )
|
||||
{
|
||||
m->getWorld()->state.isCinematic = !!p->at(0).integer;
|
||||
}
|
||||
|
||||
VM_CONDOPCODE_DEF( 0x02DE )
|
||||
{
|
||||
@ -553,6 +644,14 @@ VM_CONDOPCODE_DEF( 0x02DE )
|
||||
return vehicle && (vehicle->vehicle->classType & VehicleData::TAXI) == VehicleData::TAXI;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x02E3 )
|
||||
{
|
||||
auto vehicle = (VehicleObject*)(*p->at(0).handle);
|
||||
if( vehicle )
|
||||
{
|
||||
*p->at(1).globalReal = vehicle->physVehicle->getCurrentSpeedKmHour();
|
||||
}
|
||||
}
|
||||
VM_OPCODE_DEF( 0x02E4 )
|
||||
{
|
||||
m->getWorld()->loadCutscene(p->at(0).string);
|
||||
@ -840,7 +939,7 @@ Opcodes3::Opcodes3()
|
||||
|
||||
VM_OPCODE_DEC( 0x00A5, 5, "Create Vehicle" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x00BA, 3, "Print big" );
|
||||
VM_OPCODE_DEC( 0x00BA, 3, "Print big" );
|
||||
VM_OPCODE_DEC( 0x00BC, 3, "Print Message Now" );
|
||||
|
||||
VM_OPCODE_DEC( 0x00BE, 0, "Clear Message Prints" );
|
||||
@ -889,9 +988,8 @@ Opcodes3::Opcodes3()
|
||||
|
||||
VM_OPCODE_DEC( 0x015C, 11, "Set zone ped info" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x015F, 6, "Set Fixed Camera Position" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x0160, 4, "Point Camera at Point" );
|
||||
VM_OPCODE_DEC( 0x015F, 6, "Set Fixed Camera Position" );
|
||||
VM_OPCODE_DEC( 0x0160, 4, "Point Camera at Point" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x0164, 1, "Disable Radar Blip" );
|
||||
|
||||
@ -928,8 +1026,12 @@ Opcodes3::Opcodes3()
|
||||
|
||||
VM_OPCODE_DEC( 0x01BD, 1, "Get Game Timer" );
|
||||
VM_OPCODE_DEC_U( 0x01BE, 4, "Turn Character To Face Point" );
|
||||
|
||||
|
||||
VM_OPCODE_DEC_U( 0x01C0, 2, "Store Wanted Level" );
|
||||
VM_CONDOPCODE_DEC( 0x01C1, 1, "Is Vehicle Stopped" );
|
||||
VM_OPCODE_DEC( 0x01C7, 1, "Don't remove object" );
|
||||
|
||||
VM_OPCODE_DEC( 0x01D4, 2, "Character Enter Vehicle as Passenger" );
|
||||
|
||||
VM_OPCODE_DEC( 0x01E7, 6, "Enable Roads" );
|
||||
VM_OPCODE_DEC( 0x01E8, 6, "Disable Roads" );
|
||||
@ -937,11 +1039,10 @@ Opcodes3::Opcodes3()
|
||||
VM_OPCODE_DEC_U( 0x01EB, 1, "Set Traffic Density Multiplier" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x01ED, 1, "Clear Character Threat Search" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x01D4, 2, "Character Enter Vehicle as Passenger" );
|
||||
|
||||
VM_OPCODE_DEC( 0x01F0, 1, "Set Max Wanted Level" );
|
||||
|
||||
VM_CONDOPCODE_DEC( 0x01F3, 1, "Is Vehicle In Air" );
|
||||
VM_CONDOPCODE_DEC( 0x01F4, 1, "Is Car Flipped" );
|
||||
VM_OPCODE_DEC( 0x01F5, 2, "Get Player Character" );
|
||||
|
||||
@ -949,10 +1050,6 @@ Opcodes3::Opcodes3()
|
||||
|
||||
VM_OPCODE_DEC_U( 0x01F9, 9, "Start Kill Frenzy" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x01C0, 2, "Store Wanted Level" );
|
||||
VM_CONDOPCODE_DEC( 0x01C1, 1, "Is Vehicle Stopped" );
|
||||
|
||||
|
||||
VM_CONDOPCODE_DEC( 0x0204, 5, "Is Char near Car in Car 2D" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x020A, 2, "Lock Car Doors" );
|
||||
@ -1000,15 +1097,17 @@ Opcodes3::Opcodes3()
|
||||
VM_OPCODE_DEC_U( 0x0297, 0, "Reset Player Kills" );
|
||||
|
||||
VM_OPCODE_DEC( 0x029B, 5, "Create Object no offset" );
|
||||
VM_CONDOPCODE_DEC( 0x029C, 1, "Is Vehicle Boat" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x02A2, 5, "Add Particle" );
|
||||
VM_OPCODE_DEC_U( 0x02A3, 1, "Set Widescreen" );
|
||||
VM_OPCODE_DEC( 0x02A3, 1, "Set Widescreen" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x02A7, 5, "Add Radar Contact Blip" );
|
||||
VM_OPCODE_DEC_U( 0x02A8, 5, "Add Radar Blip" );
|
||||
|
||||
VM_CONDOPCODE_DEC( 0x02DE, 1, "Is Player In Taxi" );
|
||||
|
||||
|
||||
VM_OPCODE_DEC( 0x02E3, 2, "Get Vehicle Speed" );
|
||||
VM_OPCODE_DEC( 0x02E4, 1, "Load Cutscene Data" );
|
||||
VM_OPCODE_DEC( 0x02E5, 2, "Create Cutscene Object" );
|
||||
VM_OPCODE_DEC( 0x02E6, 2, "Set Cutscene Animation" );
|
||||
@ -1089,6 +1188,8 @@ Opcodes3::Opcodes3()
|
||||
|
||||
VM_OPCODE_DEC_U( 0x03BF, 2, "Set Pedestrians Ignoring Player" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x03C1, 2, "Store Player Vehicle No-Save" );
|
||||
|
||||
VM_OPCODE_DEC_U( 0x03C4, 3, "Display Counter Message" );
|
||||
VM_OPCODE_DEC_U( 0x03C5, 4, "Spawn Parked Vehicle" );
|
||||
VM_CONDOPCODE_DEC( 0x03C6, 1, "Is Collision In Memory" );
|
||||
|
@ -73,6 +73,10 @@ VM_OPCODE_DEF( 0x001A ) {
|
||||
t->conditionResult = p->at(0).integer > *p->at(1).globalInteger;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x0020 ) {
|
||||
t->conditionResult = *p->at(0).globalReal > p->at(1).integer;
|
||||
}
|
||||
|
||||
VM_OPCODE_DEF( 0x0038 ) {
|
||||
t->conditionResult = *p->at(0).globalInteger == p->at(1).integer;
|
||||
}
|
||||
@ -201,6 +205,8 @@ VM::VM()
|
||||
VM_OPCODE_DEC( 0x0019, 2, "Local Int Greater than Int" );
|
||||
|
||||
VM_OPCODE_DEC( 0x001A, 2, "Int Greater Than Global Int" );
|
||||
|
||||
VM_OPCODE_DEC( 0x0020, 2, "Global Float Greather than Float" );
|
||||
|
||||
VM_OPCODE_DEC( 0x0038, 2, "Global Int Equal to Int" );
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "loadingstate.hpp"
|
||||
|
||||
#include <engine/GameObject.hpp>
|
||||
#include <engine/GameState.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
|
||||
@ -193,6 +194,11 @@ void RWGame::render(float alpha)
|
||||
viewCam.position = cameraPos;
|
||||
viewCam.rotation = glm::inverse(glm::quat_cast(m)) * qtilt;
|
||||
}
|
||||
else if( engine->state.cameraFixed )
|
||||
{
|
||||
viewCam.position = engine->state.cameraPosition;
|
||||
viewCam.rotation = engine->state.cameraRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's no cutscene playing - use the camera returned by the State.
|
||||
@ -258,15 +264,53 @@ void RWGame::render(float alpha)
|
||||
window.draw(text);
|
||||
tpos.y -= text.getLocalBounds().height;
|
||||
}
|
||||
|
||||
for( int i = 0; i < engine->state.text.size(); )
|
||||
{
|
||||
if( engine->gameTime > engine->state.text[i].osTextStart + engine->state.text[i].osTextTime )
|
||||
{
|
||||
engine->state.text.erase(engine->state.text.begin() + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo this should be done by GameRenderer? but it doesn't have any font support yet
|
||||
if( engine->gameTime < engine->state.osTextStart + engine->state.osTextTime ) {
|
||||
sf::Text messageText(engine->state.osTextString, font, 15);
|
||||
for(OnscreenText& t : engine->state.text)
|
||||
{
|
||||
float fontSize = 15.f;
|
||||
switch(t.osTextStyle)
|
||||
{
|
||||
default:
|
||||
fontSize = 15.f;
|
||||
break;
|
||||
case 1:
|
||||
fontSize = 25.f;
|
||||
break;
|
||||
case 2:
|
||||
fontSize = 20.f;
|
||||
break;
|
||||
}
|
||||
|
||||
sf::Text messageText(t.osTextString, font, fontSize);
|
||||
auto sz = window.getSize();
|
||||
|
||||
|
||||
auto b = messageText.getLocalBounds();
|
||||
float lowerBar = sz.y - sz.y * 0.1f;
|
||||
messageText.setPosition(sz.x / 2.f - std::round(b.width / 2.f), lowerBar - std::round(b.height / 2.f));
|
||||
|
||||
if(t.osTextStyle == 1)
|
||||
{
|
||||
messageText.setPosition(sz.x / 2.f - std::round(b.width / 2.f), sz.y / 2.f - std::round(b.height / 2.f));
|
||||
}
|
||||
else if(t.osTextStyle == 2)
|
||||
{
|
||||
messageText.setPosition(sz.x * 0.9f - std::round(b.width), sz.y * 0.8f - std::round(b.height / 2.f));
|
||||
}
|
||||
else
|
||||
{
|
||||
float lowerBar = sz.y - sz.y * 0.1f;
|
||||
messageText.setPosition(sz.x / 2.f - std::round(b.width / 2.f), lowerBar - std::round(b.height / 2.f));
|
||||
}
|
||||
window.draw(messageText);
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,13 @@ void IngameState::handleEvent(const sf::Event &event)
|
||||
break;
|
||||
case sf::Keyboard::Space:
|
||||
if( player ) {
|
||||
player->jump();
|
||||
if( player->getCharacter()->getCurrentVehicle() ) {
|
||||
player->getCharacter()->getCurrentVehicle()->setHandbraking(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->jump();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sf::Keyboard::W:
|
||||
|
Loading…
Reference in New Issue
Block a user