1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include "FPSUnitController.h"
#include "UI/MouseHandler.h"
#include "Game/Camera.h"
#include "Game/GlobalUnsynced.h"
#include "Game/TraceRay.h"
#include "Map/Ground.h"
#include "Sim/Features/Feature.h"
#include "Sim/Misc/TeamHandler.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/Scripts/CobInstance.h"
#include "Sim/Weapons/Weapon.h"
#include "System/SpringMath.h"
#include "Net/Protocol/NetProtocol.h"
#include <SDL_mouse.h>
FPSUnitController::FPSUnitController()
: targetUnit(nullptr)
, controllee(nullptr)
, controller(nullptr)
, viewDir(FwdVector)
, targetPos(FwdVector)
, targetDist(1000.0f)
, forward(false)
, back(false)
, left(false)
, right(false)
, mouse1(false)
, mouse2(false)
, oldHeading(0)
, oldPitch(0)
, oldState(255)
, oldDCpos(ZeroVector)
{
}
void FPSUnitController::Update() {
const float3 relPos = controllee->script->GetPiecePos(controllee->script->AimFromWeapon(0));
const float3 absPos = controllee->GetObjectSpacePos(relPos) + (UpVector * 7.0f);
oldDCpos = absPos;
CUnit* hitUnit = nullptr;
CFeature* hitFeature = nullptr;
// target-lock onto any unit (allied, enemy, neutral, ...) that is visible
// SYNCED, do NOT use GuiTraceRay which also checks gu->spectatingFullView
float hitDist = TraceRay::TraceRay(absPos, viewDir, controllee->maxRange, ~Collision::NOUNITS, controllee, hitUnit, hitFeature);
if (hitUnit != nullptr && hitUnit->IsInLosForAllyTeam(controllee->allyteam)) {
targetUnit = hitUnit;
targetDist = hitDist;
targetPos = hitUnit->pos;
if (!mouse2)
controllee->AttackUnit(hitUnit, true, true, true);
return;
}
targetUnit = nullptr;
targetDist = (hitDist = std::min(hitDist, controllee->maxRange * 0.95f));
targetPos = absPos + viewDir * targetDist;
if (mouse2)
return;
// if a target position is in range, but not on the ground,
// projectiles can gain extra flighttime and travel further
//
// NOTE: CWeapon::AttackGround checks range via TryTarget
if ((targetPos.y - CGround::GetHeightReal(targetPos.x, targetPos.z)) > SQUARE_SIZE)
return;
controllee->AttackGround(targetPos, true, true, true);
}
void FPSUnitController::RecvStateUpdate(const unsigned char* buf) {
forward = !!(buf[2] & (1 << 0));
back = !!(buf[2] & (1 << 1));
left = !!(buf[2] & (1 << 2));
right = !!(buf[2] & (1 << 3));
mouse1 = !!(buf[2] & (1 << 4));
const bool newMouse2 = !!(buf[2] & (1 << 5));
if (!mouse2 && newMouse2 && controllee != nullptr)
controllee->AttackUnit(nullptr, true, true, true);
mouse2 = newMouse2;
const short int h = *((short int*) &buf[3]);
const short int p = *((short int*) &buf[5]);
viewDir = GetVectorFromHAndPExact(h, p);
}
void FPSUnitController::SendStateUpdate() {
if (!gu->fpsMode)
return;
const bool* camMoveState = camera->GetMovState();
const CMouseHandler::ButtonPressEvt* mouseButtons = mouse->buttons;
unsigned char state = 0;
state |= ((camMoveState[CCamera::MOVE_STATE_FWD]) * (1 << 0));
state |= ((camMoveState[CCamera::MOVE_STATE_BCK]) * (1 << 1));
state |= ((camMoveState[CCamera::MOVE_STATE_LFT]) * (1 << 2));
state |= ((camMoveState[CCamera::MOVE_STATE_RGT]) * (1 << 3));
state |= ((mouseButtons[SDL_BUTTON_LEFT ].pressed) * (1 << 4));
state |= ((mouseButtons[SDL_BUTTON_RIGHT].pressed) * (1 << 5));
const shortint2 hp = GetHAndPFromVector(camera->GetDir());
if (hp.x != oldHeading || hp.y != oldPitch || state != oldState) {
oldHeading = hp.x;
oldPitch = hp.y;
oldState = state;
clientNet->Send(CBaseNetProtocol::Get().SendDirectControlUpdate(gu->myPlayerNum, state, hp.x, hp.y));
}
}
|