Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "Player.h"
- #include "ValkyrieSprite.h"
- #include "SpriteMaterial.h"
- #include "PlayerSprite.h"
- #include "NBaseGame.h"
- #include "ValkyrieGame.h"
- #include "NControlConfig.h"
- #include "NBasingComponent.h"
- #include "NFacingComponent.h"
- #include "Transition.h"
- #include "DoorTransition.h"
- #include "NSerialComponent.h"
- #include "NNameComponent.h"
- #include "DoorComponent.h"
- #include "NHealthComponent.h"
- #include "NPusherComponent.h"
- #include "AnaglyphComponent.h"
- #include "DemoIdleMenu.h"
- #include "SpeedrunComponent.h"
- #include "CoffeeComponent.h"
- #include "MinimapComponent.h"
- #include "TeleportComponent.h"
- #ifndef _PLAT_WIN
- #include <ctime>
- #endif
- static const float BGMUSIC_SWITCH_DELAY = 0.35f;
- static const int THUMB_SIZE = 128;
- static const float DEMO_TIMEOUT = 45.0f;
- static const float DEMO_TIMEOUT_PAUSED = 15.0f;
- static const float OVERWORLD_DELAY = 0.2f;
- static const float WALL_GRIP_TIMER = 0.15f;
- // For some reason, Windows NFML builds choke on this. (Constant conditional expression warning.)
- static /*const*/ bool OVERWORLD_MOTION = false;//true;
- static /*const*/ bool SWIMMING_MOTION = false;
- static /*const*/ bool ICY_MOTION = false;
- static const float OVERWORLD_TILE_SIZE = float(TILE_SIZE) * 2.0f;
- static const float TELEPORT_ENTRY_DURATION = 0.3f;
- static const int CURRENT_SAVE_FILE_VERSION = 3;
- // Version 2 removes Volver cruft. A lot of this will be replaced with the more generic serial component "resource" concept of a save game.
- // Version 3 adds respawn map.
- static const float ASPECT_RATIO_FIXUP_X = (256.0f / 320.0f);
- static const float ASPECT_RATIO_FIXUP_Y = (224.0f / 200.0f);
- static const float SIZE_FIXUP_Y = 1.38f;// arbitrarily chosen to round well for jumps. (clears 6 and 10 cleanly) (18.0f / 14.0f); // bottom of foot to top of hat, ignoring border pixels
- //static const float SIZE_FIXUP_X = 1.0f;//SIZE_FIXUP_Y; // because it doesn't feel right changing the arc of jumps
- //static const float JUMP_TIME_FIXUP = SIZE_FIXUP_Y; // Cleaner way to do the same
- // ...or do a little bit of each.
- static const float SIZE_FIXUP_X = 1.15f;
- static const float JUMP_TIME_FIXUP = SIZE_FIXUP_Y / SIZE_FIXUP_X;
- static const int NUM_JUMPS = 2;
- static const float MOVEMENT_SPEED = (12.0f * 8.0f) * ASPECT_RATIO_FIXUP_X * SIZE_FIXUP_X;
- static const float SWIMMING_MOVEMENT_SPEED = MOVEMENT_SPEED * 0.5f;
- static const float JUMP_TIME = 0.325f * JUMP_TIME_FIXUP;
- static const uint HAS_PATH_TOP = 0x01;
- static const uint HAS_PATH_BOTTOM = 0x02;
- static const uint HAS_PATH_LEFT = 0x04;
- static const uint HAS_PATH_RIGHT = 0x08;
- void Player::ClearStatsForNewGame()
- {
- ClearAllData();
- //bCaptureThumbnail = false;
- bFacingLeft = false;
- WalkingFrame = 0.0f;
- LandedTime = 0.0f;
- DeadedTime = 0.0f;
- IdleTime = 0.0f;
- DemoIdleTime = 0.0f;
- OverworldTime = 0.0f;
- bLookingDown = false;
- DownJumpTime = 0.0f;
- OverworldFacing = NVec2(0,1);
- PrevOverworldFacing = OverworldFacing;
- OverworldState = OMS_Idle;
- OverWalk_Duration = 0.25f; // Based on Zelda 2 rates.
- OverWalk_Elapsed = 0.0f;
- TeleportEntry_Duration = TELEPORT_ENTRY_DURATION;
- TeleportEntry_Remaining = -1.0f;
- TeleportEntry_Direction = NVec2();
- SetUpPhysComp();
- NDialogConsumerComponent* Dialog = GetComponent<NDialogConsumerComponent>();
- if (Dialog)
- {
- Dialog->CloseDialog();
- }
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->DebugReset();
- }
- CurrentBGMusicName = "";
- bCurrentSafeSpace = false;
- bLineDefUnderwater = false;
- bLineDefToxic = false;
- bRegionUnderwater = false;
- bRegionToxic = false;
- // I Guess?
- bVulnerable = false;
- BGMusicSwitchDelay = -1.0f;
- //BGMusicSwitchName = "";
- WallGripTimer = WALL_GRIP_TIMER;
- }
- //void Player::ClearStatsForLostGame()
- //{
- // //bHasDoubleJump = false;
- // //bHasWallJump = false;
- //
- // ClearAllData();
- //
- // SetUpPhysComp();
- //}
- //
- //void Player::ClearStatsForWonGame()
- //{
- //}
- Player::Player()
- {
- // Hey, tickable priority is a thing!
- // Lower value means it ticks first.
- // Ticking either before or after a parent base (assumed priority ~0) ensures correct camera behavior.
- // For the sake of whatever, I'll say the player ticks last, after everything else has moved.
- Priority = 100;
- bEnteredCode = false;
- NextBubbleTime = -1.0f;
- // I Guess?
- bVulnerable = false;
- //ThumbImgFull.init(CRT_WIDTH,CRT_HEIGHT,3);
- //ThumbImgSm.init(THUMB_SIZE,THUMB_SIZE,3);
- //bCaptureThumbnail = false;
- AddComponent<NDataComponent>();
- GetComponent<NDataComponent>()->SetWriteCallback(OnDataWritten);
- AddComponent<SpeedrunComponent>();
- AddComponent<CoffeeComponent>();
- AddComponent<MinimapComponent>();
- Sprite = AddComponent<NRenderableComponent>();
- Space = AddComponent<NSpatialComponent>();
- PhysComp = AddComponent<NPhysicsComponent>();
- Camera = AddComponent<NCameraComponent>();
- Collision = AddComponent<NCollisionComponent>();
- Base = AddComponent<NBasingComponent>();
- Base->bCanBeBasingChild = true;
- Base->SetOnBaseAboutToMoveCallback(OnBaseAboutToMove);
- Base->SetOnBaseMovedCallback(OnBaseMoved);
- Controller = AddComponent<NPlayerControllerComponent>();
- NRenderableInst* Instance = new PlayerSprite();
- Instance->SetTemplate(NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->SpriteTemplate);
- Instance->SetMaterial(NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->SpriteMat);
- Instance->SetDeferredSPI(this);
- NRenderer::GetInstance()->AddRenderableToRenderGroup(Instance, NHashedString("World Sprites Group"));
- Camera->Camera = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->GameCamera;
- Sprite->AddRenderable(Instance);
- POINT DefRoom;
- DefRoom.x = 0;
- DefRoom.y = 0;
- SetCheckpointPosition(NVec2((float)HALF_CRT_WIDTH, (float)HALF_CRT_HEIGHT), false);
- SetCheckpointRoom(DefRoom, false);
- SetCheckpointMap(gNullStr, false);
- SetCheckpointCampaign(gNullStr, false);
- SetCheckpointPosition(NVec2((float)HALF_CRT_WIDTH, (float)HALF_CRT_HEIGHT), true);
- SetCheckpointRoom(DefRoom, true);
- SetCheckpointMap(gNullStr, true);
- SetCheckpointCampaign(gNullStr, true);
- Space->Game_Curr.Position = GetCheckpointPosition(true);
- Space->Game_Curr.Position.z = 0.0f; // Just to be safe.
- Space->Init();
- Space->SetCollisionCallback(OnCollision);
- //NPhysicsGlobals::SetSlideAlphaHorizontal(0.0f);
- //NPhysicsGlobals::SetSlideAlphaVertical(1.0f); // Slide vertically in order to preserve landing velocity. Proooobably not a very good solution! I guess this came from Vanguard?
- PhysComp->SetJumpCallback(OnJump);
- PhysComp->SetLandCallback(OnLand);
- PhysComp->SetUngroundCallback(OnUnground);
- PhysComp->SetWallHugCallback(OnWallHug);
- PhysComp->SetCanWallHugCallback(CanWallHug);
- NCollisionBox* Bounds = new NCollisionBox();
- //Bounds->Extents = NVec3(4.0f, 6.0f, 1.0f);
- Bounds->SetController(Space);
- Bounds->SetBlocksCallback(BlocksOther);
- Bounds->SetRespondsCallback(PingsOther);
- Bounds->SetCollisionFilterType(CFT_Player);
- Collision->AddPrimitive(Bounds);
- Collision->SetSweepFilter(CFT_All & ~(CFT_NonPlayerBlocker | CFT_BulletTrap | CFT_NonQuadBlocker));
- bFacingLeft = false;
- WalkingFrame = 0.0f;
- LandedTime = 0.0f;
- DeadedTime = 0.0f;
- OverworldFacing = NVec2(0,1);
- PrevOverworldFacing = OverworldFacing;
- OverworldState = OMS_Idle;
- OverWalk_Duration = 0.25f; // Based on Zelda 2 rates.
- OverWalk_Elapsed = 0.0f;
- TeleportEntry_Duration = TELEPORT_ENTRY_DURATION;
- TeleportEntry_Remaining = -1.0f;
- TeleportEntry_Direction = NVec2();
- bLookingDown = false;
- DownJumpTime = 0.0f;
- LastCheckpointTime = -1.0f;
- //Deaths = 0;
- //bHasDoubleJump = false;
- //bHasWallJump = false;
- //PlayTime = 0.0f;
- ClearAllData();
- SetUpPhysComp();
- //InitCamera();
- //////////////////////////////////////////////////////////////////////////
- // Done at new game or load game time.
- //NSerialResource::GetInstance()->LoadFromDisk("saevgaem0001.nsd");
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Done at entity creation time.
- //NSerialComponent* Serial = AddComponent<NSerialComponent>();
- //Serial->SetNotifyCallback(TEST_DeltaChanged);
- //Serial->SetResource(NSerialResource::GetInstance());
- //Serial->SetGUID(RESERVED_GUID | 0x00000001); // TODO: Define reserved GUIDs somewhere common. Most entity instances will already have a GUID, but things like the player or other one-off game concepts will need their own.
- //Serial->LoadFromResource();
- //Serial->SetDelta(NHashedString("alive"), NString("false"));
- //Serial->SaveToResource(); // redundant, done on deletion
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Done at entity deletion time.
- //RemoveComponent<NSerialComponent>();
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Done at save game time.
- //NSerialResource::GetInstance()->SaveToDisk("saevgaem0001.nsd");
- //////////////////////////////////////////////////////////////////////////
- // More better actual path?
- AddComponent<NGUIDComponent>();
- GetComponent<NGUIDComponent>()->SetGUID(GUID_Player);
- AddComponent<NScriptComponent>();
- AddComponent<NDialogConsumerComponent>();
- GetComponent<NDialogConsumerComponent>()->SetClosedCallback(OnDialogClosed);
- // Heyo! This will be the status screen, probably.
- AddComponent<NDialogProviderComponent>();
- StatusProviderFile.LoadCooked("Status.ndd");
- StatusProviderFile_Speedrun.LoadCooked("StatusSpeedrun.ndd");
- StatusProviderFile_FullMap.LoadCooked("StatusFullMap.ndd");
- MAKESTRING(DialogProvider);
- //GetComponent<NDialogProviderComponent>()->ApplyDefinitionData(StatusProviderFile.Contents.GetChildByName(DialogProvider));
- AddComponent<NCheckpointComponent>();
- AddComponent<NFrobComponent>();
- //GetComponent<NFrobComponent>()->SetCanFrobCallback(CanFrob);
- GetComponent<NFrobComponent>()->TraceDistance = 20.0f;
- GetComponent<NFrobComponent>()->PrimitiveName = NHashedString("FrobSweep");
- GetComponent<NFrobComponent>()->SetFilter(CFT_Frobbable);
- AddComponent<DoorComponent>();
- //GetComponent<DoorComponent>()->SetCanFrobCallback(CanFrob);
- GetComponent<DoorComponent>()->PrimitiveName = NHashedString("FrobSweep");
- GetComponent<DoorComponent>()->SetFilter(CFT_Door);
- NCollisionPoint* FrobBounds = new NCollisionPoint();
- GetComponent<NCollisionComponent>()->AddPrimitive(FrobBounds, NHashedString("FrobSweep"));
- FrobBounds->SetController(Space); // Must have a controller so it can early out of intersection tests against the player's collision box.
- FrobBounds->SetCollisionFilterType(CFT_None);
- //NCollisionBox* FrobBounds = new NCollisionBox();
- //FrobBounds->Extents = NVec3(5.0f, 8.0f, 1.0f);
- //GetComponent<NCollisionComponent>()->AddPrimitive(FrobBounds, NHashedString("FrobSweep"));
- AddComponent<NFacingComponent>();
- GetComponent<NFacingComponent>()->SetFacing(FD_Right);
- AddComponent<NHealthComponent>();
- GetComponent<NHealthComponent>()->SetHealthDamagedCallback(OnHealthDamaged);
- AddComponent<NPusherComponent>();
- GetComponent<NPusherComponent>()->SetCanBePushed(true);
- //GetComponent<NPusherComponent>()->SetCanPush(true); // Nah. As much fun as pushing blocks could be, it creates problems.
- AddComponent<AnaglyphComponent>();
- GetComponent<AnaglyphComponent>()->SetDepth(0.0f);
- TeleportComponent* SpeedrunTele = AddComponent<TeleportComponent>();
- {
- SpeedrunTele->AddDestination(NHashedString("SpeedrunHall"), NHashedString("Town Interiors"), 13, 0, NHashedString("FromSpeedrun"), false, true);
- SpeedrunTele->AddDestination(NHashedString("OldArcadia"), NHashedString("Speedrun Maps"), 0, 0, NHashedString("SpeedrunIntro"), false, true);
- SpeedrunTele->AddDestination(NHashedString("Bonehoard"), NHashedString("Speedrun Maps"), -1, 6, NHashedString("BonehoardIntro"), false, true);
- SpeedrunTele->AddDestination(NHashedString("Dreamscape"), NHashedString("Speedrun Maps"), 7, -6, NHashedString("DreamEntry"), false, true);
- SpeedrunTele->AddDestination(NHashedString("LegacyCaves"), NHashedString("Speedrun Maps"), 12, 6, NHashedString("LegacyCavesIntro"), false, true);
- SpeedrunTele->AddDestination(NHashedString("Gallery"), NHashedString("Speedrun Maps"), 14, 3, NHashedString("GalleryIntro"), false, true);
- }
- // Also sets swimming props if necessary.
- SetOverworldProps();
- bExtendedCamera = false;
- OverworldDelay = -1.0f;
- bAllowRejump = false;
- BGMusicSwitchDelay = -1.0f;
- //BGMusicSwitchName = "";
- }
- void Player::TEST_DeltaChanged(NEntity* OwnerEntity, const NHashedString& Key, const NString& Value)
- {
- OwnerEntity, Key, Value;
- int Foo = 0;
- Foo++;
- }
- Player::~Player()
- {
- //NRenderableInterface* Instance = Sprite->GetRenderableByName();
- //NRenderer::GetInstance()->RemoveRenderableFromRenderGroup(Instance, NHashedString("World Sprites Group"));
- //SafeDelete(Instance);
- Sprite->DeleteRenderables();
- Collision->DeletePrimitives();
- }
- void Player::Tick_CalcUpdate(float DeltaTime, ETickGroup TickGroup)
- {
- DeltaTime;
- TickGroup;
- MAKESTRING(Gameplay);
- MAKESTRING(Overworld);
- MAKESTRING(MoveRight);
- MAKESTRING(MoveLeft);
- MAKESTRING(Jump);
- MAKESTRING(JumpDown);
- MAKESTRING(Interact);
- MAKESTRING(Enter);
- MAKESTRING(Status);
- MAKESTRING(FullMap);
- MAKESTRING(MoveNorth);
- MAKESTRING(MoveSouth);
- MAKESTRING(MoveEast);
- MAKESTRING(MoveWest);
- MAKESTRING(Menus);
- MAKESTRING(Accept);
- MAKESTRING(Click);
- MAKESTRING(Cancel);
- MAKESTRING(NavUp);
- MAKESTRING(NavDown);
- if (TickGroup & ETG_Game)
- {
- //if (bCaptureThumbnail)
- //{
- // bCaptureThumbnail = false;
- // CaptureThumbnail();
- //}
- if (!IsIndisposed())
- {
- // hax, not a shipping solution on account of happening during the game tick!
- DemoIdleTime += NBaseGame::GetInstance()->engDeltaTime;
- // Might as well run this every tick. It contains all its own logic.
- TryBubble(DeltaTime);
- NDialogConsumerComponent* Dialog = GetComponent<NDialogConsumerComponent>();
- if (Dialog && Dialog->HasDialog())
- {
- if (Controller->IsRepeating(Menus, NavUp))
- {
- // TODO: AUDIO
- DemoIdleTime = 0.0f;
- if (Dialog->MoveSelectedOption(-1))
- {
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_NavUp);
- }
- }
- else if (Controller->IsRepeating(Menus, NavDown))
- {
- // TODO: AUDIO
- DemoIdleTime = 0.0f;
- if (Dialog->MoveSelectedOption(+1))
- {
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_NavDown);
- }
- }
- else if (Controller->IsDownEdge(Menus, Cancel))
- {
- DemoIdleTime = 0.0f;
- // Close dialog box instantly. Do not take any follow-up actions.
- if (Dialog->CanCloseDialog())
- {
- // TODO: AUDIO
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Close);
- Dialog->CloseDialog();
- // If we pressed Escape, we want to suppress the pause menu.
- NBaseGame::GetInstance()->bSuppressPause = true;
- }
- else
- {
- // If the dialog is set to no-close, then it's totally okay to bring up the pause menu over it.
- }
- }
- // maaaaaaaaybe?
- else if (Controller->IsDownEdge(Gameplay, Jump) ||
- Controller->IsDownEdge(Gameplay, Enter) ||
- //Controller->IsDownEdge(Gameplay, Primary) ||
- Controller->IsDownEdge(Gameplay, Interact) || // Bad for some reason?? (Same as cancel button by default [IN VANGUARD]. Could be user-defined collisions here though!!)
- Controller->IsDownEdge(Gameplay, Status) ||
- Controller->IsDownEdge(Gameplay, FullMap) || // Sigh. Sure.
- Controller->IsDownEdge(Menus, Accept)// ||
- //Controller->IsDownEdge(Menus, Cancel) ||
- /*Controller->IsDownEdge(Menus, Click)*/) // Probably not this one...
- {
- // TODO: AUDIO
- DemoIdleTime = 0.0f;
- NHandle SavedProvider = Dialog->GetProvider();
- if (Dialog->CanAdvanceDialog())
- {
- bool bOpen = Dialog->AdvanceDialog();
- if (bOpen)
- {
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Advance);
- }
- else
- {
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Close);
- }
- }
- }
- }
- else
- {
- // Kick off frob logic. This class handles everything else and will return the current best result on demand.
- GetComponent<NFrobComponent>()->Update();
- GetComponent<DoorComponent>()->Update();
- if (!OVERWORLD_MOTION &&
- Controller->IsDownEdge(Gameplay, Status))
- {
- DemoIdleTime = 0.0f;
- IdleTime = 0.0f;
- ShowStatusScreen();
- }
- if (!OVERWORLD_MOTION &&
- ValkyrieGame::GetInstance()->bHasMinimap &&
- Controller->IsDownEdge(Gameplay, FullMap))
- {
- DemoIdleTime = 0.0f;
- IdleTime = 0.0f;
- ShowFullMap();
- }
- if (Controller->IsDownEdge(Gameplay, Interact))
- {
- DemoIdleTime = 0.0f;
- IdleTime = 0.0f;
- if (!GetComponent<NFrobComponent>()->Frob())
- {
- // Frob failed; try something else?
- }
- }
- bool bSuppressJump = false;
- if (Controller->IsDownEdge(Gameplay, Enter))
- {
- DemoIdleTime = 0.0f;
- IdleTime = 0.0f;
- if (!GetComponent<DoorComponent>()->Frob())
- {
- // Frob failed; try something else?
- }
- else
- {
- // Suppress jumping if we just went through a door.
- bSuppressJump = true;
- }
- }
- // Suppress jumping for a split second.
- bSuppressJump = bSuppressJump || ((TeleportEntry_Remaining - (TeleportEntry_Duration * 0.25f)) > 0.0f);
- float MovementLateral = 0.0f;
- float MovementLongitudinal = 0.0f;
- if (!OVERWORLD_MOTION)
- {
- MovementLateral =
- Controller->GetValue(Gameplay, MoveRight) -
- Controller->GetValue(Gameplay, MoveLeft);
- // Prevent mouse cheating
- MovementLateral = Clamp(MovementLateral, -1.0f, 1.0f);
- // Extra dead zone because analog stick feels bad when looking down.
- // For Valkyrie, I guess I should do the same for pushing up to enter doors too.
- // It's irritating to change directions when pushing up.
- const float EXTRA_DEAD_ZONE = Min(0.9f, Max(Controller->GetValue(Gameplay, JumpDown), Controller->GetValue(Gameplay, Enter)));
- MovementLateral = sign(MovementLateral) * (Max(0.0, ((float)fabs(MovementLateral) - EXTRA_DEAD_ZONE)) / (1.0f - EXTRA_DEAD_ZONE));
- }
- else
- {
- // Use the other controls for the overworld
- MovementLateral =
- Controller->GetValue(Overworld, MoveEast) -
- Controller->GetValue(Overworld, MoveWest);
- MovementLongitudinal =
- Controller->GetValue(Overworld, MoveSouth) -
- Controller->GetValue(Overworld, MoveNorth);
- MovementLateral = Clamp(MovementLateral, -1.0f, 1.0f);
- MovementLongitudinal = Clamp(MovementLongitudinal, -1.0f, 1.0f);
- if (OverworldDelay > 0.0f)
- {
- MovementLateral = 0.0f;
- MovementLongitudinal = 0.0f;
- }
- }
- OverworldDelay -= DeltaTime;
- if (!OVERWORLD_MOTION)
- {
- if (TeleportEntry_Remaining >= 0.0f)
- {
- float EntryAlpha = (TeleportEntry_Remaining / TeleportEntry_Duration);
- EntryAlpha = pow(EntryAlpha, 0.5f);
- TeleportEntry_Remaining -= DeltaTime;
- MovementLateral = Lerp(MovementLateral, TeleportEntry_Direction.x, EntryAlpha);
- }
- }
- // Super Meat Boy wall gripping.
- if (!OVERWORLD_MOTION)
- {
- // This is actually asking whether we were wall sliding LAST tick, including gripping.
- if (PhysComp->IsWallSliding())
- {
- float HugNorm = PhysComp->GetWallHugNormal().x;
- // Now the question is whether we're currently TRYING to slide (in which case we do nothing but reset the grip timer),
- // or whether we're opposing or ignoring the slide, in which case we push against the wall and decrement the timer.
- if ((MovementLateral > 0.0f && HugNorm < 0.0f) ||
- (MovementLateral < 0.0f && HugNorm > 0.0f))
- {
- WallGripTimer = WALL_GRIP_TIMER;
- }
- else if (WallGripTimer > 0.0f)
- {
- WallGripTimer -= DeltaTime;
- MovementLateral = -HugNorm;
- }
- }
- }
- {
- // Not sure whether I should base this on MovementLateral (keep walking into walls)
- // or velocity.x / TILE_SIZE (stop at walls)...
- float SpeedScalar = 9.0f * Max((float)fabs(MovementLateral), (float)fabs(MovementLongitudinal));
- if (SWIMMING_MOTION)
- {
- SpeedScalar *= (SWIMMING_MOVEMENT_SPEED / MOVEMENT_SPEED);
- }
- WalkingFrame += DeltaTime * SpeedScalar;
- while (WalkingFrame >= 6.0f)
- {
- WalkingFrame -= 6.0f;
- }
- if (MovementLateral > 0.01f)
- {
- bFacingLeft = false;
- GetComponent<NFacingComponent>()->SetFacing(FD_Right);
- }
- else if (MovementLateral < -0.01f)
- {
- bFacingLeft = true;
- GetComponent<NFacingComponent>()->SetFacing(FD_Left);
- }
- else if (!OVERWORLD_MOTION || (float)fabs(MovementLongitudinal) < 0.01f)
- {
- WalkingFrame = 0.0f;
- }
- if (LandedTime > 0.0f)
- {
- LandedTime = Max(0.0f, LandedTime - DeltaTime);
- }
- }
- bool bAltDownJump = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->ALT_DOWN_JUMP;
- bLookingDown = (!OVERWORLD_MOTION && PhysComp && PhysComp->IsGrounded() && Controller->IsDown(Gameplay, JumpDown));
- bool bJumping = (!OVERWORLD_MOTION && (!bLookingDown || !bAltDownJump) && !bSuppressJump && Controller->IsDownEdge(Gameplay, Jump));
- if (bAllowRejump)
- {
- if (Controller->IsDown(Gameplay, Jump))
- {
- bJumping = true;
- }
- bAllowRejump = false;
- }
- DownJumpTime = (Max(0.0, DownJumpTime - DeltaTime));
- bool bDownJumpTest = false;
- if (!bAltDownJump)
- {
- bDownJumpTest = !OVERWORLD_MOTION && Controller->IsDownEdge(Gameplay, JumpDown);
- }
- else
- {
- bDownJumpTest = !OVERWORLD_MOTION && Controller->IsDown(Gameplay, JumpDown) && Controller->IsDownEdge(Gameplay, Jump);
- }
- if (bDownJumpTest)
- {
- DownJumpTime = 0.1f;
- }
- if ((((float)fabs(MovementLateral) + (float)fabs(MovementLongitudinal)) <= 0.0001f &&
- !bJumping && !bLookingDown))
- {
- IdleTime += DeltaTime;
- while (IdleTime > 8.0f)
- {
- IdleTime -= 8.0f;
- }
- }
- else
- {
- IdleTime = 0.0f;
- DemoIdleTime = 0.0f;
- }
- if (OVERWORLD_MOTION)
- {
- OverworldTime += DeltaTime;
- while (OverworldTime > 8.0f)
- {
- OverworldTime -= 8.0f;
- }
- }
- NVec3 DesiredMoveVector(0,0,0);
- DesiredMoveVector += (MovementLateral * NVec3(1,0,0));
- DesiredMoveVector += (MovementLongitudinal * NVec3(0,1,0));
- if (!OVERWORLD_MOTION)
- {
- if (!SWIMMING_MOTION)
- {
- DesiredMoveVector *= MOVEMENT_SPEED;
- }
- else
- {
- DesiredMoveVector *= SWIMMING_MOVEMENT_SPEED;
- }
- // Coffee cup hack here.
- CoffeeComponent* Coffee = GetComponent<CoffeeComponent>();
- if (Coffee)
- {
- Coffee->ModifySpeed(DesiredMoveVector);
- }
- }
- else
- {
- HandleOverworldMovement(DeltaTime, TickGroup, DesiredMoveVector);
- }
- {
- // We still want to maintain slippery velocity while in the air,
- // but we only apply it while we're on the ground.
- IcyVelocity.x = Smooth(IcyVelocity.x, DesiredMoveVector.x, ValkyrieGame::GetInstance()->ICY_RAMP_SPEED, DeltaTime);
- // Might want a special rule for when we land while moving and our momentum
- // is actually slowing us down or trying to reverse us. That feels not good.
- // What would a good fix be? Maybe just ramp up faster than we ramp down?
- if (fabs(IcyVelocity.x) < 4.0f && fabs(DesiredMoveVector.x) < 0.01f) // Once we stop scrolling smoothly, kill the momentum.
- {
- IcyVelocity.x = 0.0f;
- }
- if (ICY_MOTION)
- {
- if (PhysComp->IsGrounded())
- {
- DesiredMoveVector.x = IcyVelocity.x;
- }
- }
- }
- bool bHoldingJump = !OVERWORLD_MOTION && Controller->IsDown(Gameplay, Jump);
- if (PhysComp)
- {
- PhysComp->Function1_NeedsName(bHoldingJump);
- PhysComp->Function1_5_LOL_ApplyMoveAttempt(DesiredMoveVector, bJumping, bHoldingJump);
- PhysComp->Function2_NeedsName(bJumping);
- }
- // 07/02/2012: Originally calculated gravitional acceleration here.
- // Moved to after DoJump_Outer() call per Kabuto's notes.
- // DoJump_Outer() will alter GravityAlpha, so the acceleration will be off if we do this first.
- // bGrounded has the opportunity to change in the commit phase but is guaranteed to not change during this function.
- // So this can be done whenever. Except that Function2_NeedsName() can ALSO change velocity because that's where the jump actually starts
- // (and that probably needs to be refactored as well), so this should be done before that, I guess.
- // TODO: Use a getter function for bGrounded.
- }
- }
- else if (IsDying())
- {
- DeadedTime -= DeltaTime;
- if (DeadedTime < 0.0f)
- {
- DeadedTime = 0.0f;
- GetComponent<NHealthComponent>()->ResetHealth();
- // Record a ghost event BEFORE respawning as well as after.
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- // Respawn
- Space->Game_Curr.Velocity = NVec3(0.0f);
- Space->Game_Curr.Position = GetCheckpointPosition(false);
- Space->Game_Curr.Position.z = 0.0f; // Just to be safe.
- Space->Init();
- // TODO: Move to an OnDied() sort of function?
- // What is this doing, in a general sense?
- if (PhysComp)
- {
- PhysComp->OnSpawn(true);
- }
- Base->TryUnbase();
- // Hopefully we aren't trying to change campaigns here! :O
- opt_assert(GetCheckpointCampaign(false) == NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveCampaign);
- POINT ActiveRoom = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom;
- NHashedString ActiveMap = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveMap;
- if (GetCheckpointRoom(false).x != ActiveRoom.x ||
- GetCheckpointRoom(false).y != ActiveRoom.y ||
- GetCheckpointMap(false) != ActiveMap)
- {
- if (GetCheckpointMap(false) != ActiveMap)
- {
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->LoadMap(NString(GetCheckpointMap(false).getString()));
- }
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom = GetCheckpointRoom(false);
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->CompileRoom();
- ValkyrieGame::GetInstance()->PostTransitionCreateEntities(false);
- }
- else
- {
- // We didn't change rooms, but we need to reprop the region flags because they get cleared on death!
- // Or...just don't clear those. If we changed rooms, they'll get set by CompileRoom().
- }
- bVulnerable = true;
- // Maybe this will fix the ice world bug and not introduce any new ones?
- TryGround();
- InitCamera();
- InitUnderwater();
- CheckpointWith(GetHandle());
- //if (NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->IsYOLOMode())
- //{
- // ClearStatsForNewGame();
- //}
- //SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- }
- else
- {
- // Quick hack for demo pausing.
- NGameMenu* TopMenu = NMenuMgr::GetInstance()->GetTopmostMenu();
- if (TopMenu && TopMenu->AllowDemoReset())
- {
- DemoIdleTime += NBaseGame::GetInstance()->engDeltaTime;
- }
- }
- }
- }
- void Player::HandleOverworldMovement(float DeltaTime, ETickGroup TickGroup, NVec3& DesiredMoveVector)
- {
- DeltaTime;
- if (TickGroup & ETG_Game)
- {
- //////////////////////////////////////////////////////////////////////////
- // Begin overworld movement
- //////////////////////////////////////////////////////////////////////////
- if (OverworldState == OMS_Walking &&
- OverWalk_Elapsed >= OverWalk_Duration)
- {
- OverworldState = OMS_Idle;
- // TODO: Do intersection test against anything we might've just stepped on.
- // This is an easy way to do intersection tests with all the existing callbacks.
- GetComponent<NCollisionComponent>()->SetCollision(true);
- // TODO: Attempt transition if we left the scroll region.
- {
- POINT RoomMoveDir;
- RoomMoveDir.x = 0;
- RoomMoveDir.y = 0;
- NVec3 NewPlayerPos = Space->Game_Curr.Position;
- NVec3 NewPlayerVel = Space->Game_Curr.Velocity;
- bool bCrossedEdge = false;
- EdgeTransition TheCrossedEdge;
- {
- RoomMoveDir.x = int(floor(NewPlayerPos.x / (float)GAME_SCREEN_WIDTH));
- RoomMoveDir.y = int(floor(NewPlayerPos.y / (float)GAME_SCREEN_HEIGHT));
- if (NewPlayerPos.y > ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom)
- {
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x;
- TransRoom.y += RoomMoveDir.y - 1;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[1];
- }
- else if (NewPlayerPos.y < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top)
- {
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x;
- TransRoom.y += RoomMoveDir.y + 1;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[0];
- }
- if (NewPlayerPos.x > ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right)
- {
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x - 1;
- TransRoom.y += RoomMoveDir.y;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[3];
- }
- else if (NewPlayerPos.x < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left)
- {
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x + 1;
- TransRoom.y += RoomMoveDir.y;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[2];
- }
- }
- opt_assert(!bCrossedEdge || RoomMoveDir.x != 0 || RoomMoveDir.y != 0);
- if (bCrossedEdge &&
- (RoomMoveDir.x != 0 || RoomMoveDir.y != 0))
- {
- POINT CurrRoom = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom;
- POINT NewRoomCoords = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.GetNextRoomOver(CurrRoom.x, CurrRoom.y, RoomMoveDir.x, RoomMoveDir.y);
- while (NewPlayerPos.x < 0.0f)
- {
- NewPlayerPos.x += (float)GAME_SCREEN_WIDTH;
- }
- while (NewPlayerPos.x > (float)GAME_SCREEN_WIDTH)
- {
- NewPlayerPos.x -= (float)GAME_SCREEN_WIDTH;
- }
- while (NewPlayerPos.y < 0.0f)
- {
- NewPlayerPos.y += (float)GAME_SCREEN_HEIGHT;
- }
- while (NewPlayerPos.y > (float)GAME_SCREEN_HEIGHT)
- {
- NewPlayerPos.y -= (float)GAME_SCREEN_HEIGHT;
- }
- TransitionRooms(NewRoomCoords, RoomMoveDir, NewPlayerPos, NewPlayerVel, TheCrossedEdge, true);
- }
- }
- }
- if (OverworldState == OMS_Idle)
- {
- if (DesiredMoveVector.lengthSquared2D() > 0.0)
- {
- // Take input and maybe start move
- // Axis selection from old movement code.
- {
- NVec3 BestAxis = NVec3(0,0,0);
- float BestDot = 0.0f;
- float TestDot = 0.0f;
- //if (bCanMoveVert)
- {
- TestDot = Dot(NVec3(0,1,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(0,1,0);
- }
- TestDot = Dot(NVec3(0,-1,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(0,-1,0);
- }
- }
- //if (bCanMoveHori)
- {
- TestDot = Dot(NVec3(1,0,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(1,0,0);
- }
- TestDot = Dot(NVec3(-1,0,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(-1,0,0);
- }
- }
- OverworldDesiredMove = BestAxis;
- if (OverworldDesiredMove.length2D() > 0.0f)
- {
- NVec2 NewOverworldFacing = Normalize(OverworldDesiredMove);
- if (Dot(OverworldFacing, NewOverworldFacing) < 0.707f)
- {
- // If we're changing direction, cache off the old value.
- PrevOverworldFacing = OverworldFacing;
- }
- OverworldFacing = NewOverworldFacing;
- }
- else
- {
- }
- }
- // Should only need to look ahead 8, but 10 shouldn't hurt
- NVec3 Lookahead = Normalize(OverworldDesiredMove) * 12.5f;
- bool bMoveFree = true;
- {
- static NUtilVector<NCollisionResult> Results;
- Results.setNeverDealloc(true);
- Results.clear();
- NCollisionInterface* Primitive = Collision->GetPrimitiveByName();
- if (Primitive)
- {
- // TODO: MAKE SURE THIS DOESN'T TRIGGER ANY TOUCH EVENTS!!
- // That should only happen as part of the swept move code path.
- bMoveFree =
- NGameOctree::GetInstance()->Sweep(
- Results, Primitive,
- Space->Game_Curr.Position,
- Space->Game_Curr.Position + Lookahead,
- 0, Collision->GetSweepFilter() & ~(CFT_MapDoor)); // Don't sweep against map doors for the purposes of movement.
- }
- }
- if (bMoveFree)
- {
- // Set up a move.
- OverworldState = OMS_Walking;
- OverWalk_Elapsed = 0.0f;
- OverWalk_Start = Space->Game_Curr.Position;
- OverWalk_End = Space->Game_Curr.Position + (Normalize(OverworldDesiredMove) * 16.0f);
- // Just in case, make sure we're aligned to 16x16 blocks.
- OverWalk_End.x = ((floor(((OverWalk_End.x - 8.0f) / 16.0f) + 0.5f) * 16.0f) + 8.0f);
- OverWalk_End.y = ((floor(((OverWalk_End.y - 8.0f) / 16.0f) + 0.5f) * 16.0f) + 8.0f);
- }
- }
- }
- if (OverworldState == OMS_Walking)
- {
- // Continue move
- OverWalk_Elapsed += DeltaTime;
- float WalkAlpha = Clamp(OverWalk_Elapsed / OverWalk_Duration, 0.0f, 1.0f);
- Space->Game_Curr.Position = Lerp(OverWalk_Start, OverWalk_End, WalkAlpha);
- }
- //else
- {
- // ALWAYS clear this. We don't use it for overworld movement after this!
- DesiredMoveVector = NVec3(0);
- }
- /*
- // Cover four 16x16 tiles in one second. Based on Zelda 2 rates.
- // Slightly slower than normal movement speed (~88 vs. 64).
- DesiredMoveVector *= (8.0f * 8.0f);
- // Now do clamping!
- // We'll take the magnitude of the desired move vector and apply it to whatever direction we end up moving (as opposed to projecting);
- // we just need to decide what direction that actually is.
- //NVec3 ActualDirection(1,0,0);
- //DesiredMoveVector = ActualDirection * DesiredMoveVector.length2D();
- float PrevX = floor(Space->Game_Curr.Position.x / (float)OVERWORLD_TILE_SIZE);
- float NextX = ceil(Space->Game_Curr.Position.x / (float)OVERWORLD_TILE_SIZE);
- float PrevY = floor(Space->Game_Curr.Position.y / (float)OVERWORLD_TILE_SIZE);
- float NextY = ceil(Space->Game_Curr.Position.y / (float)OVERWORLD_TILE_SIZE);
- bool bCanMoveHori = ((NextY - PrevY) <= 0.01f);
- bool bCanMoveVert = ((NextX - PrevX) <= 0.01f);
- // If we're inside a block somehow, allow moves in either direction.
- //if (!bCanMoveHori && !bCanMoveVert)
- //{
- // bCanMoveHori = true;
- // bCanMoveVert = true;
- //}
- NVec3 AllowedMove;
- if (bCanMoveHori) AllowedMove += NVec3(1,0,0);
- if (bCanMoveVert) AllowedMove += NVec3(0,1,0);
- // But we still have to choose a best axis, and we also want to turn at corners.
- // To turn a corner, we look at whether we would cross the axis in this move, and if we would,
- // we snap to that axis and move the remainder of the distance.
- NVec3 BestAxis = NVec3(0,0,0);
- float BestDot = 0.0f;
- float TestDot = 0.0f;
- //if (bCanMoveVert)
- {
- TestDot = Dot(NVec3(0,1,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(0,1,0);
- }
- TestDot = Dot(NVec3(0,-1,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(0,-1,0);
- }
- }
- //if (bCanMoveHori)
- {
- TestDot = Dot(NVec3(1,0,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(1,0,0);
- }
- TestDot = Dot(NVec3(-1,0,0), DesiredMoveVector);
- if (TestDot > BestDot)
- {
- BestDot = TestDot;
- BestAxis = NVec3(-1,0,0);
- }
- }
- OverworldDesiredMove = BestAxis;
- if (OverworldDesiredMove.length2D() > 0.0f)
- {
- NVec2 NewOverworldFacing = Normalize(OverworldDesiredMove);
- if (Dot(OverworldFacing, NewOverworldFacing) < 0.707f)
- {
- // If we're changing direction, cache off the old value.
- PrevOverworldFacing = OverworldFacing;
- }
- OverworldFacing = NewOverworldFacing;
- }
- else
- {
- }
- BestAxis = BestAxis * AllowedMove;
- float PreMag = (DesiredMoveVector.length2D());
- DesiredMoveVector = BestAxis * DesiredMoveVector.length2D();
- float PostMag = (DesiredMoveVector.length2D());
- if (PreMag > 0.0f && PostMag <= 0.0f)
- {
- // Oops, we killed our movement!
- // (Probably trying to move solely in an unallowed direction.)
- // Let's try to patch it up.
- float AlphaX = Normalize(Space->Game_Curr.Position.x / (float)OVERWORLD_TILE_SIZE, PrevX, NextX);
- float AlphaY = Normalize(Space->Game_Curr.Position.y / (float)OVERWORLD_TILE_SIZE, PrevY, NextY);
- AlphaX, AlphaY;
- if (!bCanMoveHori)
- {
- //if (AlphaY < 0.5f)
- if (PrevOverworldFacing.y < 0.0f)
- {
- DesiredMoveVector = NVec3(0,-1,0) * PreMag;
- }
- else
- {
- DesiredMoveVector = NVec3(0,1,0) * PreMag;
- }
- }
- else if (!bCanMoveVert)
- {
- //if (AlphaX < 0.5f)
- if (PrevOverworldFacing.x < 0.0f)
- {
- DesiredMoveVector = NVec3(-1,0,0) * PreMag;
- }
- else
- {
- DesiredMoveVector = NVec3(1,0,0) * PreMag;
- }
- }
- }
- */
- //////////////////////////////////////////////////////////////////////////
- // End overworld movement
- //////////////////////////////////////////////////////////////////////////
- }
- }
- void Player::Tick_CommitUpdate(float DeltaTime, ETickGroup TickGroup)
- {
- TickGroup;
- if (TickGroup & ETG_Game)
- {
- // This should be done before integration because it adjusts velocity for wall jumping.
- if (PhysComp)
- {
- PhysComp->Function3_Commit_Upkeep(DeltaTime);
- }
- // TODO: Can THIS be moved into the jump component? SHOULD it?
- if (!IsIndisposed())
- {
- // May change jump component's bGrounded.
- // This is the ONLY code that may change bGrounded.
- Space->Integrate(DeltaTime);
- /*
- if (OVERWORLD_MOTION)
- {
- // Turn corners as necessary
- OverworldDesiredMove;
- float PrevPrevX = floor(Space->Game_Prev.Position.x / (float)OVERWORLD_TILE_SIZE);
- float PrevNextX = ceil(Space->Game_Prev.Position.x / (float)OVERWORLD_TILE_SIZE);
- float PrevPrevY = floor(Space->Game_Prev.Position.y / (float)OVERWORLD_TILE_SIZE);
- float PrevNextY = ceil(Space->Game_Prev.Position.y / (float)OVERWORLD_TILE_SIZE);
- float CurrPrevX = floor(Space->Game_Curr.Position.x / (float)OVERWORLD_TILE_SIZE);
- float CurrNextX = ceil(Space->Game_Curr.Position.x / (float)OVERWORLD_TILE_SIZE);
- float CurrPrevY = floor(Space->Game_Curr.Position.y / (float)OVERWORLD_TILE_SIZE);
- float CurrNextY = ceil(Space->Game_Curr.Position.y / (float)OVERWORLD_TILE_SIZE);
- if (Space->Game_Curr.Velocity.lengthSquared2D() > 0.0f &&
- OverworldDesiredMove.lengthSquared2D() > 0.0f &&
- Dot(Space->Game_Curr.Velocity, OverworldDesiredMove) < 0.707f)
- {
- // We moved in a direction we didn't want to. We want to take a corner.
- if (PrevPrevX != CurrPrevX ||
- PrevPrevY != CurrPrevY ||
- PrevNextX != CurrNextX ||
- PrevNextY != CurrNextY)
- {
- // We crossed a threshold. Now we just need to figure out which one.
- opt_assert(
- (PrevPrevX == PrevNextX && CurrPrevX == CurrNextX && PrevPrevX == CurrPrevX && PrevNextX == CurrNextX) ||
- (PrevPrevY == PrevNextY && CurrPrevY == CurrNextY && PrevPrevY == CurrPrevY && PrevNextY == CurrNextY));
- if (CurrPrevX != CurrNextX)
- {
- if (CurrPrevX > PrevPrevX)
- {
- // We're moving right, so clamp to the axis left of us (CurrPrevX)
- float NewAxis = CurrPrevX * OVERWORLD_TILE_SIZE;
- Space->Game_Curr.Position.x = NewAxis;
- }
- else if (CurrPrevX < PrevPrevX)
- {
- // We're moving left, so clamp to the axis right of us (CurrNextX)
- float NewAxis = CurrNextX * OVERWORLD_TILE_SIZE;
- Space->Game_Curr.Position.x = NewAxis;
- }
- else
- {
- opt_assert(false);
- }
- }
- if (CurrPrevY != CurrNextY)
- {
- if (CurrPrevY > PrevPrevY)
- {
- // We're moving down, so clamp to the axis above us (CurrPrevY)
- float NewAxis = CurrPrevY * OVERWORLD_TILE_SIZE;
- Space->Game_Curr.Position.y = NewAxis;
- }
- else if (CurrPrevY < PrevPrevY)
- {
- // We're moving up, so clamp to the axis below us (CurrNextY)
- float NewAxis = CurrNextY * OVERWORLD_TILE_SIZE;
- Space->Game_Curr.Position.y = NewAxis;
- }
- else
- {
- opt_assert(false);
- }
- }
- }
- }
- }
- */
- }
- if (PhysComp)
- {
- PhysComp->Function4_Apply_Terminal_Velocity();
- // 07/26/2013: Moved this above the switch-rooms stuff
- PhysComp->Function5_TickGracePeriods(DeltaTime);
- }
- //// Keep camera centered on player!
- //// This will need more rules for clamping to scroll region, transitioning, etc.
- //if (!IsTransitioning())
- //{
- // // This is a little hard to read, but we use the current value of bExtendedCamera to specify whether we allow it to be extended,
- // // and we write the new value depending on whether it were extended.
- // Camera->Camera->setPos(GetCameraPosition(bExtendedCamera, bExtendedCamera));
- //}
- //else
- //{
- // // Always allow the camera to extend when transitioning.
- // bExtendedCamera = true;
- //}
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent();
- }
- CheckTransitionRooms();
- // Is this gonna be too slow to do every tick?
- // TODO: Use actual delta time? This will be zero when dialogs are open.
- // HAXHAXHAX not safe if we're using a fixed time step!!!
- SetPlayTime(GetPlayTime() + NBaseGame::GetInstance()->engDeltaTime);
- TryCacheSafePlace(false);
- if (NBaseGame::GetInstance()->DEMO_MODE)
- {
- if (NBaseGame::GetInstance()->GamePaused())
- {
- if (DemoIdleTime > DEMO_TIMEOUT_PAUSED)
- {
- DemoIdleTime = 0.0f;
- NMenuMgr::GetInstance()->OpenMenu(new DemoIdleMenu());
- }
- }
- else
- {
- if (DemoIdleTime > DEMO_TIMEOUT)
- {
- DemoIdleTime = 0.0f;
- NMenuMgr::GetInstance()->OpenMenu(new DemoIdleMenu());
- }
- }
- }
- }
- if (TickGroup & ETG_Render)
- {
- TickCommitBGMusicChange(DeltaTime);
- }
- if (TickGroup & ETG_Render)
- {
- if (!IsIndisposed())
- {
- Space->Interpolate(NBaseGame::GetInstance()->gameAlpha);
- }
- // Keep camera centered on player!
- // This will need more rules for clamping to scroll region, transitioning, etc.
- if (!IsTransitioning())
- {
- // This is a little hard to read, but we use the current value of bExtendedCamera to specify whether we allow it to be extended,
- // and we write the new value depending on whether it were extended.
- Camera->Camera->setPos(GetCameraPosition(bExtendedCamera, bExtendedCamera));
- }
- else
- {
- // Always allow the camera to extend when transitioning.
- bExtendedCamera = true;
- }
- NDialogConsumerComponent* Dialog = GetComponent<NDialogConsumerComponent>();
- if (Dialog)
- {
- DialogAnchor Anchor = DA_Top;
- // TODO: Always top-anchor the status screen?
- if (Resolve<NEntity>(Dialog->GetProvider()) != this)
- {
- if (Space && Camera && Camera->Camera)
- {
- NVec3 Diff = Space->Render_Curr.Position - Camera->Camera->getPos();
- if (Diff.y < -0.0f)
- {
- Anchor = DA_Bottom;
- }
- }
- }
- Dialog->Tick();
- Dialog->Render(Anchor);
- }
- if (ValkyrieGame::GetInstance()->SHOW_PROMPTS)
- {
- NFrobComponent* Frob = GetComponent<NFrobComponent>();
- if (Frob && (!Dialog || !Dialog->HasDialog()))
- {
- Frob->Render();
- }
- DoorComponent* Door = GetComponent<DoorComponent>();
- if (Door && (!Dialog || !Dialog->HasDialog()))
- {
- Door->Render();
- }
- }
- NPopupComponent* Popup = GetComponent<NPopupComponent>();
- if (Popup)
- {
- Popup->Tick(DeltaTime);
- Popup->Render();
- }
- }
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->Tick(TickGroup, DeltaTime);
- }
- }
- void Player::CheckTransitionRooms()
- {
- // Never do this if we're doing a wipe.
- if (NSubroutineMgr::GetInstance()->IsSubroutineRunning(NHashedString("Door Transition")))
- {
- return;
- }
- // Switch rooms
- // TODO: For Valkyrie, these deltas may be greater than one!
- // As much of a kludge as it sounds, the camera position might be the best way to determine where we're actually trying to go,
- // since it will lerp to the center point on the appropriate axis when we transition.
- // This also might mean being stricter about only transitioning one direction or the other.
- NVec3 MoveVec = (Space->Game_Curr.Position - Space->Game_Prev.Position);
- float Alpha = 1.0f;
- POINT RoomMoveDir;
- RoomMoveDir.x = 0;
- RoomMoveDir.y = 0;
- NVec3 NewPlayerPos = Space->Game_Curr.Position;
- NVec3 NewPlayerVel = Space->Game_Curr.Velocity;
- bool bCrossedEdge = false;
- EdgeTransition TheCrossedEdge;
- bool bSkipWrapAroundLogic = false;
- bool bAllowCheckpoint = true;
- if (MoveVec.lengthSquared2D() > 0.0f)
- {
- RoomMoveDir.x = int(floor(NewPlayerPos.x / (float)GAME_SCREEN_WIDTH));
- RoomMoveDir.y = int(floor(NewPlayerPos.y / (float)GAME_SCREEN_HEIGHT));
- //while (NewPlayerPos.x < 0.0f)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left)
- //{
- // NewPlayerPos.x += (float)GAME_SCREEN_WIDTH;
- // RoomMoveDir.x -= 1;
- //}
- //while (NewPlayerPos.x > (float)GAME_SCREEN_WIDTH)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right)
- //{
- // NewPlayerPos.x -= (float)GAME_SCREEN_WIDTH;
- // RoomMoveDir.x += 1;
- //}
- //while (NewPlayerPos.y < 0.0f)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top)
- //{
- // NewPlayerPos.y += (float)GAME_SCREEN_HEIGHT;
- // RoomMoveDir.y -= 1;
- //}
- //while (NewPlayerPos.y > (float)GAME_SCREEN_HEIGHT)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom)
- //{
- // NewPlayerPos.y -= (float)GAME_SCREEN_HEIGHT;
- // RoomMoveDir.y += 1;
- //}
- if ((float)fabs(MoveVec.y) > 0.0f)
- {
- if (NewPlayerPos.y > ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom)
- {
- // Don't allow checkpointing on vertical transitions.
- bAllowCheckpoint = false;
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x;
- TransRoom.y += RoomMoveDir.y - 1;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[1];
- Alpha = (ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom - Space->Game_Prev.Position.y) / MoveVec.y;
- NewPlayerPos = Lerp(Space->Game_Prev.Position, NewPlayerPos, Alpha);
- NewPlayerVel = Lerp(Space->Game_Prev.Velocity, NewPlayerVel, Alpha);
- DebugLog(Text("CROSSED EDGE Bottom edge. Alpha is %f.", Alpha));
- DebugLog(Text("CROSSED EDGE Interp position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- NewPlayerPos.y = 0.0f;
- DebugLog(Text("CROSSED EDGE Fixed position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- //Space->Init();
- // uh?
- RoomMoveDir.x = int(floor(NewPlayerPos.x / (float)GAME_SCREEN_WIDTH));
- }
- else if (NewPlayerPos.y < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top)
- {
- // Don't allow checkpointing on vertical transitions.
- bAllowCheckpoint = false;
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x;
- TransRoom.y += RoomMoveDir.y + 1;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[0];
- // For the top edge ONLY, cancel the transition if there's nothing up there.
- if ((!TheCrossedEdge.bHasRoomCoords && !TheCrossedEdge.bHasMapCoords) &&
- (!ValkyrieGame::GetInstance()->TheWorld.Rooms.exists(TransRoom.x) ||
- !ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x].exists(TransRoom.y - 1)))
- {
- bCrossedEdge = false;
- }
- else
- {
- Alpha = (ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top - Space->Game_Prev.Position.y) / MoveVec.y;
- NewPlayerPos = Lerp(Space->Game_Prev.Position, NewPlayerPos, Alpha);
- NewPlayerVel = Lerp(Space->Game_Prev.Velocity, NewPlayerVel, Alpha);
- DebugLog(Text("CROSSED EDGE Top edge. Alpha is %f.", Alpha));
- DebugLog(Text("CROSSED EDGE Interp position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- NewPlayerPos.y = (float)GAME_SCREEN_HEIGHT;
- DebugLog(Text("CROSSED EDGE Fixed position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- //Space->Init();
- // uh?
- RoomMoveDir.x = int(floor(NewPlayerPos.x / (float)GAME_SCREEN_WIDTH));
- }
- }
- }
- if ((float)fabs(MoveVec.x) > 0.0f)
- {
- if (NewPlayerPos.x > ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right)
- {
- // Make sure we aren't indexing outside the world on account of jumping above the top scroll region.
- if (NewPlayerPos.y < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top &&
- !bCrossedEdge)
- {
- DebugLog("Adjusted transition delta for having jumped out of bounds.");
- RoomMoveDir.y++;
- bSkipWrapAroundLogic = true;
- }
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x - 1;
- TransRoom.y += RoomMoveDir.y;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[3];
- Alpha = (ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right - Space->Game_Prev.Position.x) / MoveVec.x;
- NewPlayerPos = Lerp(Space->Game_Prev.Position, NewPlayerPos, Alpha);
- NewPlayerVel = Lerp(Space->Game_Prev.Velocity, NewPlayerVel, Alpha);
- DebugLog(Text("CROSSED EDGE Right edge. Alpha is %f.", Alpha));
- DebugLog(Text("CROSSED EDGE Interp position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- NewPlayerPos.x = 0.0f;
- DebugLog(Text("CROSSED EDGE Fixed position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- //Space->Init();
- // uh?
- RoomMoveDir.y = int(floor(NewPlayerPos.y / (float)GAME_SCREEN_HEIGHT));
- if (bSkipWrapAroundLogic) {RoomMoveDir.y++;} // I guess?
- }
- else if (NewPlayerPos.x < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left)
- {
- // Make sure we aren't indexing outside the world on account of jumping above the top scroll region.
- if (NewPlayerPos.y < ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top &&
- !bCrossedEdge)
- {
- DebugLog("Adjusted transition delta for having jumped out of bounds.");
- RoomMoveDir.y++;
- bSkipWrapAroundLogic = true;
- }
- bCrossedEdge = true;
- POINT ThisRoom = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- POINT TransRoom = ThisRoom;
- TransRoom.x += RoomMoveDir.x + 1;
- TransRoom.y += RoomMoveDir.y;
- TheCrossedEdge = ValkyrieGame::GetInstance()->TheWorld.Rooms[TransRoom.x][TransRoom.y].Edges[2];
- Alpha = (ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left - Space->Game_Prev.Position.x) / MoveVec.x;
- NewPlayerPos = Lerp(Space->Game_Prev.Position, NewPlayerPos, Alpha);
- NewPlayerVel = Lerp(Space->Game_Prev.Velocity, NewPlayerVel, Alpha);
- DebugLog(Text("CROSSED EDGE Left edge. Alpha is %f.", Alpha));
- DebugLog(Text("CROSSED EDGE Interp position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- NewPlayerPos.x = (float)GAME_SCREEN_WIDTH;
- DebugLog(Text("CROSSED EDGE Fixed position is ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- //Space->Init();
- // uh?
- RoomMoveDir.y = int(floor(NewPlayerPos.y / (float)GAME_SCREEN_HEIGHT));
- if (bSkipWrapAroundLogic) {RoomMoveDir.y++;} // I guess?
- }
- }
- }
- opt_assert(!bCrossedEdge || RoomMoveDir.x != 0 || RoomMoveDir.y != 0);
- if (bCrossedEdge &&
- (RoomMoveDir.x != 0 || RoomMoveDir.y != 0))
- {
- if (Base->Parent)
- {
- Base->TryUnbase(true);
- Space->Game_Curr = Space->Game_Prev;
- }
- else
- {
- POINT CurrRoom = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom;
- POINT NewRoomCoords = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.GetNextRoomOver(CurrRoom.x, CurrRoom.y, RoomMoveDir.x, RoomMoveDir.y);
- DebugLog(Text(">>>> RT >>>> >>>> RT >>>> >>>> RT >>>> >>>> RT >>>> >>>> RT >>>> >>>> RT >>>> >>>> RT >>>> >>>> RT >>>>"));
- DebugLog(Text(">>>> RT >>>> Transitioning from room [ %d, %d ] to room [ %d, %d ].", CurrRoom.x, CurrRoom.y, NewRoomCoords.x, NewRoomCoords.y));
- DebugLog(Text(">>>> RT >>>> Position was ( %f, %f ).", Space->Game_Prev.Position.x, Space->Game_Prev.Position.y));
- DebugLog(Text(">>>> RT >>>> Position is ( %f, %f ).", Space->Game_Curr.Position.x, Space->Game_Curr.Position.y));
- DebugLog(Text(">>>> RT >>>> Position will be ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- while (NewPlayerPos.x < 0.0f)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left)
- {
- NewPlayerPos.x += (float)GAME_SCREEN_WIDTH;
- }
- while (NewPlayerPos.x > (float)GAME_SCREEN_WIDTH)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right)
- {
- NewPlayerPos.x -= (float)GAME_SCREEN_WIDTH;
- }
- if (!bSkipWrapAroundLogic)
- {
- while (NewPlayerPos.y < 0.0f)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top)
- {
- NewPlayerPos.y += (float)GAME_SCREEN_HEIGHT;
- }
- while (NewPlayerPos.y > (float)GAME_SCREEN_HEIGHT)//ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom)
- {
- NewPlayerPos.y -= (float)GAME_SCREEN_HEIGHT;
- }
- }
- else
- {
- ANCHOR;
- }
- DebugLog(Text(">>>> RT >>>> Position will actually be ( %f, %f ).", NewPlayerPos.x, NewPlayerPos.y));
- TransitionRooms(NewRoomCoords, RoomMoveDir, NewPlayerPos, NewPlayerVel, TheCrossedEdge, bAllowCheckpoint);
- }
- }
- }
- void Player::OnDataWritten(NEntity* OwnerEntity, NHashedString Key)
- {
- OwnerEntity, Key;
- //MAKESTRING(PlayTimeSeconds);
- //if (Key != PlayTimeSeconds)
- //{
- // if (strstr(Key.getString(), "Checkpoint") == NULL)
- // {
- // Cast<Player>(OwnerEntity)->CheckpointWith(Cast<Player>(OwnerEntity)->GetHandle());
- // }
- //}
- }
- void Player::TryCacheSafePlace(bool bForce)
- {
- if (bForce ||
- (bCurrentSafeSpace && (PhysComp->IsGrounded() || OVERWORLD_MOTION)))
- {
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- LastSafePlace.Campaign = TheWorld.ActiveCampaign;
- LastSafePlace.Map = TheWorld.ActiveMap;
- LastSafePlace.Room = TheWorld.ActiveRoom;
- LastSafePlace.Position = Space->Game_Curr.Position;
- LastSafePlace.Time = NBaseGame::GetInstance()->engAbsTime;
- }
- }
- NVec3 Player::GetCameraPosition(bool bExtend, bool& bExtended)
- {
- NVec3 RetVal = Camera->Camera->getPos();
- NVec2 Extents;
- if (!OVERWORLD_MOTION)
- {
- Extents = NVec2(TILE_SIZE * 1.5f, TILE_SIZE * 3.5f);
- }
- else
- {
- Extents = NVec2(TILE_SIZE * 1.5f, TILE_SIZE * 1.5f);
- }
- if (bExtend)
- {
- float ExtendedX = (float)fabs(RetVal.x - Space->Render_Prev.Position.x);
- float ExtendedY = (float)fabs(RetVal.y - Space->Render_Prev.Position.y);
- bExtended = (ExtendedX > Extents.x) || (ExtendedY > Extents.y);
- // Allow extents to encompass the distance between the previous camera position and the previous player position.
- Extents.x = Max(Extents.x, (float)fabs(RetVal.x - Space->Render_Prev.Position.x));
- Extents.y = Max(Extents.y, (float)fabs(RetVal.y - Space->Render_Prev.Position.y));
- // Clamp to integer to prevent jitter?
- // Nope, not exactly...
- // This seems to work, but I can't explain why...
- Extents.x = floor(Extents.x + 0.999f);
- Extents.y = floor(Extents.y + 0.999f);
- }
- {
- float NewCamX = RetVal.x;
- float NewCamY = RetVal.y;
- //if (!bExtend)
- {
- NewCamX = Clamp(NewCamX,
- Space->Render_Curr.Position.x - Extents.x,
- Space->Render_Curr.Position.x + Extents.x);
- NewCamY = Clamp(NewCamY,
- Space->Render_Curr.Position.y - Extents.y,
- Space->Render_Curr.Position.y + Extents.y);
- }
- NewCamX = Clamp(NewCamX,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left + (float(GAME_SCREEN_WIDTH) * 0.5f),
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right - (float(GAME_SCREEN_WIDTH) * 0.5f));
- NewCamY = Clamp(NewCamY,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top + (float(GAME_SCREEN_HEIGHT) * 0.5f),
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom - (float(GAME_SCREEN_HEIGHT) * 0.5f));
- RetVal.x = NewCamX;
- RetVal.y = NewCamY;
- }
- return RetVal;
- }
- NVec3 Player::GetDeltaToNearestAxis(const NVec3& FromPos, bool bForLeavingRoom, TransitionType InType)
- {
- // Choose the nearest axis to the player's position, then find the delta from the camera position to that axis.
- // This may not necessarily be the nearest axis to the camera position, and that's fine.
- // We want the one nearer the player in the event of a disparity.
- NVec3 RelativeCamPos = FromPos;
- NVec3 TestPos = bForLeavingRoom ? PreTransitionPosition : Space->Game_Curr.Position;
- while (TestPos.x < 0.0f)
- {
- TestPos.x += float(GAME_SCREEN_WIDTH);
- RelativeCamPos.x += float(GAME_SCREEN_WIDTH);
- }
- while (TestPos.x > float(GAME_SCREEN_WIDTH))
- {
- TestPos.x -= float(GAME_SCREEN_WIDTH);
- RelativeCamPos.x -= float(GAME_SCREEN_WIDTH);
- }
- while (TestPos.y < 0.0f)
- {
- TestPos.y += float(GAME_SCREEN_HEIGHT);
- RelativeCamPos.y += float(GAME_SCREEN_HEIGHT);
- }
- while (TestPos.y > float(GAME_SCREEN_HEIGHT))
- {
- TestPos.y -= float(GAME_SCREEN_HEIGHT);
- RelativeCamPos.y -= float(GAME_SCREEN_HEIGHT);
- }
- // TestPos is now within [0,dims] on both axes.
- // RelativeCamPos may not be.
- NVec3 RetVal = RelativeCamPos;
- RetVal.x = (float(GAME_SCREEN_WIDTH) * 0.5f) - RelativeCamPos.x;
- RetVal.y = (float(GAME_SCREEN_HEIGHT) * 0.5f) - RelativeCamPos.y;
- if (/*OVERWORLD_MOTION &&*/ InType == TT_JumpCut)
- {
- // I don't think I want axis alignment for the overworld.
- // Welllllllll..... I do, but not all the time.
- // Also maybe I can get away with not doing this for any jump cut...
- // IF THIS CAUSES PROBLEMS IN THE FUTURE, A BETTER SOLUTION WOULD BE TO ONLY DO THIS WHEN THE JUMP CUT INVOLVES A SWITCH TO ANOTHER MAP / ENTITY / WHATEVER.
- // (Also I would want to update the related code in TransitionRooms() even though it may be unnecessary. Search for "/*OVERWORLD_MOTION &&*/".)
- RetVal = NVec3(0);
- }
- return RetVal;
- }
- void Player::OnCollision(NEntity* OwnerEntity, const NCollisionResult& ThisHitRes)
- {
- if (ThisHitRes.HitPrimitive)
- {
- CollisionLineDef* LineDef = Cast<CollisionLineDef>(ThisHitRes.HitPrimitive);
- Player* ThisPlayer = Cast<Player>(OwnerEntity);
- opt_assert(ThisPlayer);
- if (LineDef)
- {
- if (LineDef->Type == VTT_Deadly)
- {
- ThisPlayer->Die();
- }
- if (LineDef->Type == VTT_Water ||
- LineDef->Type == VTT_Toxic)
- {
- ThisPlayer->SetSwimmingLineDef(true, (LineDef->Type == VTT_Toxic), true, true);
- }
- if (LineDef->Type == VTT_Water_Exit)
- {
- ThisPlayer->SetSwimmingLineDef(false, false, true, false);
- }
- if (ThisHitRes.HitNormal.y < -0.9f)
- {
- if (LineDef->Type == VTT_Ice)
- {
- ICY_MOTION = true;
- }
- else if (LineDef->Type == VTT_Solid ||
- LineDef->Type == VTT_Ledge ||
- LineDef->Type == VTT_NoClimb ||
- LineDef->Type == VTT_NoEffects)
- {
- ICY_MOTION = false;
- }
- }
- else if (fabs(ThisHitRes.HitNormal.x) > 0.9f)
- {
- // Kill icy momentum on wall collisions.
- ThisPlayer->IcyVelocity.x = 0.0f;
- }
- }
- else
- {
- // Hit non-world thing.
- if (//ThisHitRes.HitPrimitive->BlocksOther(ThisPlayer->Collision->GetPrimitiveByName()) &&
- ThisHitRes.HitPrimitive->BlocksOtherResult(ThisPlayer->Collision->GetPrimitiveByName(), ThisHitRes))
- {
- if (ThisHitRes.HitNormal.y < -0.9f)
- {
- ICY_MOTION = false;
- }
- else if (fabs(ThisHitRes.HitNormal.x) > 0.9f)
- {
- // Kill icy momentum on wall collisions.
- ThisPlayer->IcyVelocity.x = 0.0f;
- }
- }
- // TODO: Figure out if the other thing we hit is associated with an entity,
- // and if that entity has a basing component, and if we should get based on it
- // or maybe vice-versa too.
- //NCollisionInstance* CollInst = Cast<NCollisionInstance>(ThisHitRes.HitPrimitive);
- //if (CollInst && CollInst->GetController())
- //{
- // NSpatialComponent* OtherSpace = Cast<NSpatialComponent>(CollInst->GetController()->GetCollisionOwner());
- // if (OtherSpace)
- // {
- // if (ThisHitRes.HitNormal.y < -0.8f)
- // {
- // ThisPlayer->Base->TryBaseOn(OtherSpace->GetHandle());
- // }
- // }
- //}
- }
- }
- }
- void Player::OnLand(NEntity* OwnerEntity, const NCollisionResult& ThisHitRes, bool bEffectsReady)
- {
- bool bPlayEffects = true;
- CollisionLineDef* TestPrim = Cast<CollisionLineDef>(ThisHitRes.HitPrimitive);
- if (TestPrim)
- {
- if (TestPrim->Type == VTT_NoEffects)
- {
- bPlayEffects = false;
- }
- }
- ThisHitRes, bEffectsReady;
- Player* ThisPlayer = Cast<Player>(OwnerEntity);
- opt_assert(ThisPlayer);
- ThisPlayer->LandedTime = 0.2f;
- if (bPlayEffects)
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("landing.nms", AUDPRI_LANDING, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- {
- ValkEntity* NewEntity = NEntityFactory::BuildEntity<ValkEntity>(NHashedString("Landing.ndd"));
- // Oops, this may still be opted-out!
- if (NewEntity)
- {
- // TODO: Allow the game to make additional updates (e.g., for positioning Valkyrie entities relative to room coordinates).
- NBaseGame::GetInstance()->GamePostBuildEntity(NewEntity);
- NBaseGame::GetInstance()->DynamicEntities.push(NewEntity);
- // I guess update its position to the context's position?
- NSpatialComponent* ContextSpace = Resolve<NSpatialComponent>(ThisPlayer);
- NSpatialComponent* EffectSpace = Resolve<NSpatialComponent>(NewEntity);
- if (ContextSpace && EffectSpace)
- {
- // Don't alter Z.
- EffectSpace->Game_Curr.Position.x = ContextSpace->Game_Curr.Position.x;
- EffectSpace->Game_Curr.Position.y = ContextSpace->Game_Curr.Position.y + 6.0f;
- EffectSpace->Init();
- }
- }
- }
- }
- SpeedrunComponent* Speed = OwnerEntity->GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- // This happens when the player initiated a jump and it was successful.
- // By contrast, OnUnground() happens when the player leaves the ground and loses a jump count, even if it's by walking off a ledge.
- void Player::OnJump(NEntity* OwnerEntity, int JumpNum)
- {
- OwnerEntity;
- // Aaaaaaaand play SOUNDS!!
- if (JumpNum == 0)
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("jump.nms", AUDPRI_JUMP, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- else
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("dbljump.nms", AUDPRI_DBLJUMP, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- SpeedrunComponent* Speed = OwnerEntity->GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- // This happens when the player leaves the ground and loses a jump count, even if it's by walking off a ledge.
- // By contrast, OnJump() happens when the player initiated a jump and it was successful.
- void Player::OnUnground(NEntity* OwnerEntity)
- {
- // This means we either just jumped or we walked off a ledge.
- // If we walked off a ledge (how do we test this? velocity?),
- // set a grace period to allow us to use our first jump.
- OwnerEntity;
- DebugLog("############## OnUnground");
- SpeedrunComponent* Speed = OwnerEntity->GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- void Player::OnWallHug(NEntity* OwnerEntity, const NCollisionResult& ThisHitRes)
- {
- OwnerEntity;
- bool bPlayEffects = true;
- CollisionLineDef* TestPrim = Cast<CollisionLineDef>(ThisHitRes.HitPrimitive);
- if (TestPrim)
- {
- if (TestPrim->Type == VTT_NoEffects)
- {
- bPlayEffects = false;
- }
- }
- if (bPlayEffects)
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("wallhug.nms", AUDPRI_WALLHUG, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- SpeedrunComponent* Speed = OwnerEntity->GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- bool Player::CanWallHug(NEntity* OwnerEntity, const NCollisionResult& ThisHitRes)
- {
- OwnerEntity;
- bool bRetVal = true;
- CollisionLineDef* LineDef = Cast<CollisionLineDef>(ThisHitRes.HitPrimitive);
- if (LineDef && LineDef->Type == VTT_NoClimb)
- {
- bRetVal = false;
- }
- return bRetVal;
- }
- bool Player::BlocksOther(NCollisionInterface* Self, NCollisionInterface* Other)
- {
- Self, Other;
- return false;
- }
- bool Player::PingsOther(NCollisionInterface* Self, NCollisionInterface* Other)
- {
- Self;
- return BlocksOther(Self, Other) || true;
- }
- bool Player::SetParam(NShaderParamMapping* Param, NHashedString ActivePass, NShaderParamInformant* Informant)
- {
- bool RetVal = true;
- MAKESTRING(wvpMat);
- MAKESTRING(uvMat);
- MAKESTRING(AnaglyphDistance);
- MAKESTRING(AnaglyphDistanceOffset);
- MAKESTRING(AnaglyphColor);
- MAKESTRING(AnaglyphSilhFix);
- MAKESTRING(AnaglyphDesat);
- MAKESTRING(AnaglyphGamma);
- if (Param->myParamName == AnaglyphDistance)
- {
- float Depth = 0.0f;
- AnaglyphComponent* AC = Resolve<AnaglyphComponent>(this);
- if (AC) {Depth = AC->GetDepth();}
- Param->SetFloatValue(0.5f * Depth * NBaseGame::GetInstance()->HACK_GetAnaglyphDistance());
- }
- else if (Param->myParamName == AnaglyphDistanceOffset)
- {
- Param->SetFloatValue(NBaseGame::GetInstance()->HACK_GetAnaglyphDistanceOffset());
- }
- else if (Param->myParamName == AnaglyphColor)
- {
- Param->SetVectorValue(NBaseGame::GetInstance()->HACK_GetAnaglyphColor());
- }
- else if (Param->myParamName == AnaglyphSilhFix)
- {
- Param->SetFloatValue(NBaseGame::GetInstance()->HACK_GetAnaglyphSilhFix() ? 1.0f : 0.0f);
- }
- else if (Param->myParamName == AnaglyphDesat)
- {
- Param->SetFloatValue(NBaseGame::GetInstance()->HACK_GetAnaglyphDesat());
- }
- else if (Param->myParamName == AnaglyphGamma)
- {
- Param->SetVectorValue(NBaseGame::GetInstance()->HACK_GetAnaglyphGamma());
- }
- else if (Param->myParamName == wvpMat)
- {
- NVec3 RelativePos = Camera->Camera->getPos();
- Param->SetMatrixValue(Space->GetWorldMatrixQuantized(true, RelativePos) *
- #ifndef _NFML
- CreateTranslationMatrix(NVec3(-0.5f, -0.5f, 0.0f)) *
- #endif
- Camera->GetModifiedViewProj());
- }
- else if (Param->myParamName == uvMat)
- {
- NVec2 AnimPos;
- if (!OVERWORLD_MOTION)
- {
- if (IsDying())
- {
- int Blink = 0;
- if (DeadedTime <= 0.3f)
- {
- Blink = int(DeadedTime * 30.0f) % 2;
- }
- else
- {
- Blink = int(DeadedTime * 15.0f) % 2;
- }
- AnimPos.y = (16.0f / 128.0f) * 0.75f;
- AnimPos.x = (float(Blink) * 16.0f / 128.0f);
- }
- else
- {
- if (OVERWORLD_MOTION || PhysComp->IsGrounded())
- {
- if (LandedTime > 0.0f)
- {
- AnimPos.y = (48.0f / 128.0f) * 0.75f;
- AnimPos.x = (48.0f / 128.0f);
- }
- else
- {
- if ((!OVERWORLD_MOTION && (float)fabs(Space->Game_Curr.Velocity.x) > 0.01f) ||
- (OVERWORLD_MOTION && (float)fabs(Space->Game_Curr.Velocity.lengthSquared2D()) > 0.01f))
- {
- AnimPos.y = (32.0f / 128.0f) * 0.75f;
- AnimPos.x = (16.0f / 128.0f) * float(int(WalkingFrame) % 6);
- }
- else if (bLookingDown)
- {
- AnimPos.x = (16.0f / 128.0f);
- }
- else
- {
- // Idle. Leave zeroed.
- if (IdleTime > 4.0f)
- {
- int IdleFrame = int(IdleTime * 2.0f) % 8;
- if (IdleFrame == 6)
- {
- // Or go to landed:
- AnimPos.y = (48.0f / 128.0f) * 0.75f;
- AnimPos.x = (48.0f / 128.0f);
- }
- else if (IdleFrame % 2 == 0)
- {
- // Or to first walking frame:
- AnimPos.y = (32.0f / 128.0f) * 0.75f;
- AnimPos.x = 0.0f;
- }
- }
- }
- }
- }
- else
- {
- // TODO: Add a WallSliding() function?)
- // (Also TODO: clarify vocabulary. Wall hugging, wall sliding, and wall jumping are three different things.)
- if (PhysComp && PhysComp->IsWallSliding())
- {
- AnimPos.x = (32.0f / 128.0f);
- AnimPos.y = (16.0f / 128.0f) * 0.75f;
- }
- else
- {
- AnimPos.y = (48.0f / 128.0f) * 0.75f;
- float JumpScalar = 0.1f * (Space->Game_Curr.Velocity.y / float(TILE_SIZE));
- float JumpFrame = 0.0f;
- if (JumpScalar < -1.0f)
- {
- JumpFrame = 1.0f;
- }
- else if (JumpScalar > 1.0f)
- {
- JumpFrame = 2.0f;
- }
- AnimPos.x = (16.0f / 128.0f) * JumpFrame;
- }
- }
- }
- if (bFacingLeft)
- {
- AnimPos.y += 0.5f;
- }
- NMat4 TextureMatrix;
- TextureMatrix =
- CreateScaleMatrix(NVec3((16.0f / 128.0f), (16.0f / 128.0f) * 0.75f, 1.0f)) *
- CreateTranslationMatrix(NVec3(AnimPos.x, AnimPos.y, 0.0f));
- Param->SetMatrixValue(TextureMatrix);
- }
- else // OVERWORLD_MOTION
- {
- AnimPos.x = 0.0f;
- if (OverworldFacing.y <= -0.707f) AnimPos.x = 0.75f;
- else if (OverworldFacing.y >= 0.707f) AnimPos.x = 0.0f;
- else if (OverworldFacing.x <= -0.707f) AnimPos.x = 0.5f;
- else if (OverworldFacing.x >= 0.707f) AnimPos.x = 0.25f;
- if (int(OverworldTime * 4.0f) % 2 == 0)
- {
- AnimPos.y += 0.5f;
- }
- NMat4 TextureMatrix;
- TextureMatrix =
- CreateScaleMatrix(NVec3((16.0f / 64.0f), (16.0f / 32.0f), 1.0f)) *
- CreateTranslationMatrix(NVec3(AnimPos.x, AnimPos.y, 0.0f));
- Param->SetMatrixValue(TextureMatrix);
- }
- }
- else
- {
- RetVal = NShaderParamInformant::SetParam(Param, ActivePass, Informant);
- }
- return RetVal;
- }
- void Player::Die()
- {
- if (bVulnerable)
- {
- if (!IsDying())
- {
- DeadedTime = 0.6f;
- SetDeaths(GetDeaths() + 1);
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("death.nms", AUDPRI_DEATH, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- // I guess? I mean these should get repropped when we respawn if we actually want them.
- bLineDefUnderwater = false;
- bLineDefToxic = false;
- // And probably these too?
- //bRegionUnderwater = false;
- //bRegionToxic = false;
- IcyVelocity.x = 0.0f;
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->IncrementDeaths();
- Speed->TryRecordGhostEvent(true);
- }
- }
- }
- }
- void Player::TeleportWith(NEntity* Other)
- {
- // Might be dangerous to transition mid-collision. Hrm.
- // Maybe set a flag saying we want to transition next frame instead?
- opt_assert(Other);
- //TransitionRooms(Other->DestRoom, Other->DestLocation, Space->Game_Curr.Velocity);
- }
- void Player::TransitionRooms(POINT NewRoomCoords, POINT RoomMoveDir, const NVec3& NewPlayerPos, const NVec3& NewPlayerVel, const EdgeTransition& EdgeTrans, bool bAllowCheckpoint)
- {
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- if (EdgeTrans.bWipeTransition &&
- EdgeTrans.bHasMapName &&
- EdgeTrans.bHasMapCoords &&
- EdgeTrans.bHasEntityName)
- {
- if (EdgeTrans.bWipeAudio)
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("footsteps.nms", AUDPRI_BELL /* (120) */, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- ValkyrieGame::GetInstance()->ClearDynamicEntities();
- ValkyrieGame::GetInstance()->ThePlayer->GetComponent<NRenderableComponent>()->SetVisibility(false);
- NSubroutineMgr::GetInstance()->FinishSubroutine(NHashedString("Door Transition"));
- NSubroutineMgr::GetInstance()->RunSubroutine(new DoorTransition(EdgeTrans.MapName, EdgeTrans.MapCoords, EdgeTrans.EntityName, bAllowCheckpoint), NHashedString("Door Transition"), 0);
- }
- else
- {
- //PreTransitionPosition = Space->Game_Curr.Position;
- PreTransitionPosition = Space->Game_Prev.Position;
- bExtendedCamera = EdgeTrans.Type == TT_ScrollCut;//true;
- if (EdgeTrans.bHasMapName)
- {
- // Load that map!
- ValkyrieGame::GetInstance()->LoadMap(EdgeTrans.MapName);
- }
- POINT OrigCoords = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom;
- POINT RemapFixup;
- RemapFixup.x = 0;
- RemapFixup.y = 0;
- if (EdgeTrans.bHasMapCoords)
- {
- // Stomp whatever we expected.
- NewRoomCoords = EdgeTrans.MapCoords;
- // But we'll also need to fix up our EffCoords if we're scrolling...which we won't be. This should be fine.
- //opt_assert(EdgeTrans.Type == TT_JumpCut);
- // Hacky last-minute feature add! Definitely won't break anything! :D
- if (EdgeTrans.Type == TT_ScrollCut)
- {
- ANCHOR;
- RemapFixup.x = NewRoomCoords.x - OrigCoords.x;
- RemapFixup.y = NewRoomCoords.y - OrigCoords.y;
- RemapFixup.x -= RoomMoveDir.x;
- RemapFixup.y -= RoomMoveDir.y;
- }
- }
- // EffCoords is "where the new room thinks we're coming from,"
- // after compensating for scroll regions and maybe scroll cuts to other rooms.
- POINT EffCoords;
- EffCoords.x = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.x;
- EffCoords.y = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.y;
- NVec3 EffPos = Space->Game_Prev.Position;
- // Myeh, whatever.
- // (I shouldn't need this fudge if I use the previous position. What I'm trying to do is figure out which room I'm actually leaving,
- // since the ActiveRoom will be whichever part of the scroll region I first entered and not necessarily the one I'm in now.)
- // (Still need it for crossing back from room to room unless I push the player in a bit more, which I still might.)
- const float FUDGE = 0.01f;
- EffPos.x = Clamp(EffPos.x,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Left + FUDGE,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Right - FUDGE);
- EffPos.y = Clamp(EffPos.y,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Top + FUDGE,
- ValkyrieGame::GetInstance()->TheWorld.CurrentScrollBounds.Bottom - FUDGE);
- int dx = int(floor(EffPos.x / float(GAME_SCREEN_WIDTH)));
- int dy = int(floor(EffPos.y / float(GAME_SCREEN_HEIGHT)));
- EffCoords.x += dx;
- EffCoords.y += dy;
- EffCoords.x += RemapFixup.x;
- EffCoords.y += RemapFixup.y;
- POINT ApparentDelta;
- ApparentDelta.x = NewRoomCoords.x - EffCoords.x;
- ApparentDelta.y = NewRoomCoords.y - EffCoords.y;
- DebugLog(Text(">>>> RT >>>> Clamped position is ( %f, %f ).", EffPos.x, EffPos.y));
- DebugLog(Text(">>>> RT >>>> Offset on current room coords due to position in scroll region is [ %d, %d ].", dx, dy));
- DebugLog(Text(">>>> RT >>>> Current room with offset is [ %d, %d ].", EffCoords, EffCoords));
- DebugLog(Text(">>>> RT >>>> Apparent delta is [ %d, %d ].", ApparentDelta, ApparentDelta));
- Space->Game_Curr.Position = NewPlayerPos;
- Space->Game_Curr.Velocity = NewPlayerVel;
- Space->Game_Curr.Position.z = 0.0f; // Just to be safe.
- Space->Init();
- // Note that MoveDelta doesn't correspond to camera motion because of scroll regions!
- //InitialCamPos.x = float(NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.x - NewRoomCoords.x) * GAME_SCREEN_WIDTH;
- //InitialCamPos.y = float(NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.y - NewRoomCoords.y) * GAME_SCREEN_HEIGHT;
- bool bChangedRooms =
- (NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.x != NewRoomCoords.x ||
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.y != NewRoomCoords.y);
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.x = NewRoomCoords.x;
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.ActiveRoom.y = NewRoomCoords.y;
- NVec3 CamDeltaFixup;
- CamDeltaFixup.x = float((OrigCoords.x - NewRoomCoords.x) * GAME_SCREEN_WIDTH);
- CamDeltaFixup.y = float((OrigCoords.y - NewRoomCoords.y) * GAME_SCREEN_HEIGHT);
- if (EdgeTrans.bHasMapName)
- {
- bChangedRooms = true;
- }
- if (bChangedRooms)
- {
- // Might run into problems if we do the transition (which calls EndCycleMeshes()) without doing this first...
- ValkyrieGame::GetInstance()->TheWorldEntity->CycleMeshes();
- ValkyrieGame::GetInstance()->TheDynWorldEntity->CycleMeshes();
- ValkyrieGame::GetInstance()->GameCamera_Alt->setPos(ValkyrieGame::GetInstance()->GameCamera->getPos());
- NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->CompileRoom();
- // This is kind of a dumb hack, but if we're teleporting to another room or map, we need to get its entities created NOW
- // so that we can find our target.
- if (EdgeTrans.bHasEntityName)
- {
- ValkyrieGame::GetInstance()->PostTransitionCreateEntities(true);
- }
- }
- if (EdgeTrans.bHasEntityName)
- {
- // Find that entity and jump there.
- // (Once the map's compiled and entities exist.)
- for (int i = 0; i < NBaseGame::GetInstance()->DynamicEntities.size(); ++i)
- {
- NNameComponent* EntName = NBaseGame::GetInstance()->DynamicEntities[i]->GetComponent<NNameComponent>();
- if (EntName && EntName->MyName == EdgeTrans.EntityName)
- {
- NSpatialComponent* EntSpace = NBaseGame::GetInstance()->DynamicEntities[i]->GetComponent<NSpatialComponent>();
- if (EntSpace)
- {
- Space->Game_Curr.Position = EntSpace->Game_Curr.Position;
- Space->Game_Curr.Position.z = 0.0f; // derp
- Space->Init();
- // Aaaaand if we've just teleported, try to ground the player.
- // Probably generalize this so I can do it on game start (if I want)
- // or really whenever.
- TryGround();
- }
- }
- }
- }
- else if (EdgeTrans.bHasRoomCoords)
- {
- // Move to those coords.
- }
- // This is a REALLY gross hack, but to suppress a one-frame flicker when going to the overworld, do this.
- // (And hope this won't mess up other overworld transitions!)
- // Actually, maybe I want this for any jump cut. :/
- if (/*OVERWORLD_MOTION &&*/ EdgeTrans.Type == TT_JumpCut)
- {
- // Actually, not sure this is necessary at all, but it doesn't seem to hurt...
- InitCamera();
- //Camera->Camera->setPos(GetCameraPosition(bExtendedCamera, bExtendedCamera));
- }
- NVec3 EffCamDeltaFixup;
- if (ApparentDelta.x == 0)
- {
- EffCamDeltaFixup += (CamDeltaFixup * NVec3(1.0f, 0.0f, 0.0f));
- }
- if (ApparentDelta.y == 0)
- {
- EffCamDeltaFixup += (CamDeltaFixup * NVec3(0.0f, 1.0f, 0.0f));
- }
- Camera->Camera->setPos(Camera->Camera->getPos() + EffCamDeltaFixup);
- // Just in case...
- NSubroutineMgr::GetInstance()->FinishSubroutine(NHashedString("Room Transition"));
- // I guess always do the transition even if we didn't change rooms, just in case we want to do
- // the Zelda "Lost Woods" trick of scrolling back into the room we were just in.
- NSubroutineMgr::GetInstance()->RunSubroutine(new Transition(EdgeTrans.Type, ApparentDelta, EffCamDeltaFixup, bAllowCheckpoint), NHashedString("Room Transition"), 0);
- // Maybe?
- // TODO: Test first to make sure we're not saving on a vertical transition. Or at least not an upward one. Or if we are, save our velocity.
- if (bAllowCheckpoint)
- {
- CheckpointWith(GetHandle(), false/*, true*/);
- }
- }
- }
- //
- //void Player::SaveGame()
- //{
- // //if (!NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->IsYOLOMode())
- // {
- // // No support for anything but an autosave currently.
- // // Not sure if care.
- // char SaveGamePath[MAX_PATH];
- // GetLocalAppDataPath(SaveGamePath, NCore::GetInstance()->GetLocalAppDataPathName(), "Saves" FOLDER_SEPARATOR);
- // strcat_s(SaveGamePath, MAX_PATH, "autosave.vsg");
- //
- //
- // FILE* File;
- // fopen_s(&File, SaveGamePath, "wb");
- //
- //
- //
- // fwrite(&CURRENT_SAVE_FILE_VERSION, sizeof(int), 1, File);
- //
- //
- //
- // SYSTEMTIME LocalTime;
- //
- //#ifdef _PLAT_WIN
- // GetLocalTime(&LocalTime);
- //#else
- // // TODO: NFML TIME. Generalize this conversion (both directions) maybe?
- // std::time_t StdTime = std::time(0);
- // std::tm* StdLocalTime = std::localtime(&StdTime);
- // StdLocalTime;
- //
- // LocalTime.wYear = StdLocalTime->tm_year + 1900;
- // LocalTime.wMonth = StdLocalTime->tm_mon;
- // LocalTime.wDayOfWeek = StdLocalTime->tm_wday;
- // LocalTime.wDay = StdLocalTime->tm_mday;
- // LocalTime.wHour = StdLocalTime->tm_hour;
- // LocalTime.wMinute = StdLocalTime->tm_min;
- // LocalTime.wSecond = StdLocalTime->tm_sec;
- // LocalTime.wMilliseconds = 0;
- //#endif
- //
- // fwrite(&LocalTime, sizeof(SYSTEMTIME), 1, File);
- //
- // NString CampaignFile = NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->TheWorld.CampaignFilename;
- //
- // int CampFileLen = CampaignFile.Length() + 1;
- // fwrite(&CampFileLen, sizeof(int), 1, File);
- // fwrite(*CampaignFile, sizeof(char) * CampFileLen, 1, File);
- //
- //
- //
- // fwrite(&PlayTime, sizeof(float), 1, File);
- // fwrite(&Deaths, sizeof(int), 1, File);
- //
- // int MapStrLen = (int)strlen(RespawnMap.getString()) + 1;
- // fwrite(&MapStrLen, sizeof(int), 1, File);
- // fwrite(RespawnMap.getString(), sizeof(char), MapStrLen, File);
- //
- // fwrite(&RespawnRoom, sizeof(POINT), 1, File);
- // fwrite(&RespawnPoint, sizeof(NVec3), 1, File);
- // //fwrite(&bHasDoubleJump, sizeof(bool), 1, File);
- // //fwrite(&bHasWallJump, sizeof(bool), 1, File);
- //
- // nfclose(File);
- //
- //
- //
- //
- //
- //
- //
- // // Aaaaand spawn the save effect.
- // /*
- // if (NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->SHOW_SAVE_ICON)
- // {
- // Effect* NewEffect = new Effect();
- // NewEffect->Space->Game_Curr.Position = NVec3((float)(CRT_WIDTH) - 16.0f, 16.0f, 0.0f);
- //
- // ((NSprite*)(NewEffect->Sprite->GetRenderableByName()))->LoadTex(NString("savedisk.bmp"), NHashedString("Texture_SaveDisk"));
- //
- // NewEffect->Space->Game_Curr.Scale = NVec3(16.0f, 16.0f, 1.0f);
- //
- // NewEffect->Space->Init();
- //
- // NewEffect->Anim->AnimFrames = 8;
- // NewEffect->Anim->AnimDuration = 0.6f;
- //
- // NBaseGame::GetInstance()->DynamicEntities.push(NewEffect);
- // }
- // */
- // }
- //}
- //
- //void Player::LoadGame()
- //{
- // // Always disable this when loading!!
- // //NBaseGame::GetInstance()->GetGameType<ValkyrieGame>()->SetYOLOMode(false);
- //
- // // No support for anything but an autosave currently.
- // // Not sure if care.
- // char SaveGamePath[MAX_PATH];
- // GetLocalAppDataPath(SaveGamePath, NCore::GetInstance()->GetLocalAppDataPathName(), "Saves" FOLDER_SEPARATOR);
- // strcat_s(SaveGamePath, MAX_PATH, "autosave.vsg");
- //
- // if (FileExists(SaveGamePath))
- // {
- // FILE* File;
- // fopen_s(&File, SaveGamePath, "rb");
- //
- // // IF THIS CHANGES, ValkyrieTitleScreenMenu::GetSaveGameInfo MAY NEED TO CHANGE TOO!!
- //
- //
- //
- // int SaveVersion = 0;
- // fread_s(&SaveVersion, sizeof(int), sizeof(int), 1, File);
- //
- //
- //
- //// if (SaveVersion != CURRENT_SAVE_FILE_VERSION)
- //// {
- //// NMessageBox::Show("Save file version does not match expected value.", "Warning", MBS_Warning);
- //// nfclose(File);
- //// ClearStatsForNewGame(); // I guess?
- //// return;
- //// }
- //
- //
- //
- // SYSTEMTIME LocalTime;
- // fread_s(&LocalTime, sizeof(SYSTEMTIME), sizeof(SYSTEMTIME), 1, File);
- //
- // int CampFileLen = -1;
- // fread_s(&CampFileLen, sizeof(int), sizeof(int), 1, File);
- // opt_assert(CampFileLen >= 0);
- // char* buffer = new char[CampFileLen];
- // fread_s(buffer, sizeof(char) * CampFileLen, sizeof(char), CampFileLen, File);
- // NString CampaignFile = buffer;
- // SafeDeleteArray(buffer);
- //
- //
- //
- // fread_s(&PlayTime, sizeof(float), sizeof(float), 1, File);
- // fread_s(&Deaths, sizeof(int), sizeof(int), 1, File);
- //
- // if (SaveVersion > 2)
- // {
- // int MapStrLen = -1;
- // fread_s(&MapStrLen, sizeof(int), sizeof(int), 1, File);
- // static char MapStrBuffer[256] = {0};
- // fread_s(MapStrBuffer, sizeof(char) * MapStrLen, sizeof(char), MapStrLen, File);
- // RespawnMap = NHashedString(MapStrBuffer);
- // }
- //
- // fread_s(&RespawnRoom, sizeof(POINT), sizeof(POINT), 1, File);
- // fread_s(&RespawnPoint, sizeof(NVec3), sizeof(NVec3), 1, File);
- // //fread_s(&bHasDoubleJump, sizeof(bool), sizeof(bool), 1, File);
- // //fread_s(&bHasWallJump, sizeof(bool), sizeof(bool), 1, File);
- //
- // nfclose(File);
- //
- //
- //
- // SetUpPhysComp();
- // }
- //}
- void Player::ClearAllData()
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- DataComp->Clear();
- }
- MinimapComponent* MiniComp = GetComponent<MinimapComponent>();
- if (MiniComp)
- {
- MiniComp->ClearData();
- }
- // And initialize powerups to suppress missing data asserts.
- SetHasAllPowerups(false);
- // And make sure this default stuff exists too.
- MAKESTRING(CheckpointCampaign);
- MAKESTRING(CheckpointMap);
- MAKESTRING(CheckpointRoomX);
- MAKESTRING(CheckpointRoomY);
- MAKESTRING(CheckpointPositionX);
- MAKESTRING(CheckpointPositionY);
- MAKESTRING(PlayTimeSeconds);
- MAKESTRING(DeathsCount);
- DataComp->CreateMappedValue(CheckpointCampaign);
- DataComp->CreateMappedValue(CheckpointMap);
- DataComp->CreateMappedValue(CheckpointRoomX);
- DataComp->CreateMappedValue(CheckpointRoomY);
- DataComp->CreateMappedValue(CheckpointPositionX);
- DataComp->CreateMappedValue(CheckpointPositionY);
- DataComp->CreateMappedValue(PlayTimeSeconds);
- DataComp->CreateMappedValue(DeathsCount);
- SetCheckpointPosition(NVec2((float)HALF_CRT_WIDTH, (float)HALF_CRT_HEIGHT), false);
- SetCheckpointPosition(NVec2((float)HALF_CRT_WIDTH, (float)HALF_CRT_HEIGHT), true);
- POINT DefRoom;
- DefRoom.x = 0;
- DefRoom.y = 0;
- SetCheckpointRoom(DefRoom, false);
- SetCheckpointMap(gNullStr, false);
- SetCheckpointCampaign(gNullStr, false);
- SetCheckpointRoom(DefRoom, true);
- SetCheckpointMap(gNullStr, true);
- SetCheckpointCampaign(gNullStr, true);
- SetDeaths(0);
- SetPlayTime(0.0f);
- SetEnteredCode(bEnteredCode || GetEnteredCode());
- }
- void Player::SetUpPhysComp()
- {
- if (PhysComp)
- {
- // Does this make sense to generalize for other games?
- // TODO: Make these go through setter functions.
- int CurrMaxJumps = PhysComp->GetMaxJumps();
- PhysComp->SetMaxJumps(HasPowerup(VPU_Boots_DoubleJump) ? 2 : 1);
- PhysComp->SetCanWallJump(HasPowerup(VPU_Gloves_Climbing));
- int JumpsDiff = PhysComp->GetMaxJumps() - CurrMaxJumps;
- for (int i = 0; i < JumpsDiff; ++i)
- {
- PhysComp->IncrementJumpsRemaining();
- }
- }
- }
- bool Player::IsTransitioning()
- {
- MAKESTRINGWITH(RoomTransSubName, "Room Transition");
- MAKESTRINGWITH(DoorTransSubName, "Door Transition");
- return
- NSubroutineMgr::GetInstance()->IsSubroutineRunning(RoomTransSubName) ||
- NSubroutineMgr::GetInstance()->IsSubroutineRunning(DoorTransSubName);
- }
- bool Player::IsIntroShowing()
- {
- MAKESTRINGWITH(SubName, "Intro Splash Cinematic");
- return NSubroutineMgr::GetInstance()->IsSubroutineRunning(SubName);
- }
- bool Player::IsIndisposed()
- {
- return (
- IsDying() ||
- IsTransitioning() ||
- IsIntroShowing() ||
- (NMenuMgr::GetInstance()->IsAnyMenuOpen())
- );
- }
- void Player::InitCamera()
- {
- bool bDummy = false;
- Camera->Camera->setPos((Space->Render_Curr.Position * NVec3(1.0f,1.0f,0.0f)) + NVec3(0,0,-17.0f));
- Camera->Camera->setPos(GetCameraPosition(false, bDummy));
- bExtendedCamera = false;
- }
- void Player::InitUnderwater()
- {
- // See whether we spawned underwater!
- // (Could probably actually use the player's current location instead of these respawn values, but whatever.)
- // SHOULD probably use the player's current location; these values will be out of date when switching maps!!
- //ValkyrieTileType SpawnTile =
- // ValkyrieGame::GetInstance()->TheWorld.GetCellType(
- // GetCheckpointRoom().x, GetCheckpointRoom().y,
- // (int)(GetCheckpointPosition().x / (float)TILE_SIZE),
- // (int)(GetCheckpointPosition().y / (float)TILE_SIZE));
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- ValkyrieTileType SpawnTile =
- ValkyrieGame::GetInstance()->TheWorld.GetCellType(
- TheWorld.ActiveRoom.x, TheWorld.ActiveRoom.y,
- (int)(Space->Game_Curr.Position.x / (float)TILE_SIZE),
- (int)(Space->Game_Curr.Position.y / (float)TILE_SIZE));
- bool bUnderwater = (SpawnTile == VTT_Water || SpawnTile == VTT_Toxic);
- bool bToxic = (SpawnTile == VTT_Toxic);
- SetSwimmingLineDef(bUnderwater, bToxic);
- }
- void Player::SetOverworld(bool bNewOverworld)
- {
- if (bNewOverworld != OVERWORLD_MOTION)
- {
- OVERWORLD_MOTION = bNewOverworld;
- SetOverworldProps();
- }
- }
- void Player::SetOverworldProps()
- {
- if (!OVERWORLD_MOTION)
- {
- Space->Game_Curr.Scale = NVec3(16.0f, 24.0f, 1.0f);
- }
- else
- {
- Space->Game_Curr.Scale = NVec3(16.0f, 16.0f, 1.0f);
- }
- if (!OVERWORLD_MOTION)
- {
- NPhysicsGlobals::SetWorldUp(NVec3(0,-1,0));
- }
- else
- {
- // Gravity is "into the screen" on the overworld.
- NPhysicsGlobals::SetWorldUp(NVec3(0,0,1));
- }
- if (!OVERWORLD_MOTION)
- {
- SetSwimmingProps();
- }
- else
- {
- PhysComp->InitConstants(MOVEMENT_SPEED, NULL, 0, 0.0f, 0.0f, 0.0f);
- }
- // Maybe?
- PhysComp->OnSpawn(false);
- NCollisionBox* Bounds = Cast<NCollisionBox>(Collision->GetPrimitiveByName());
- if (Bounds)
- {
- if (!OVERWORLD_MOTION)
- {
- Bounds->Extents = NVec3(5.0f, 8.0f, 1.0f);
- }
- else
- {
- // Can't make it an even 8 because of whatever.
- //Bounds->Extents = NVec3(7.95f, 7.95f, 1.0f);
- // For tile-at-a-time movement, make this smaller.
- Bounds->Extents = NVec3(4.0f, 4.0f, 1.0f);
- }
- }
- PlayerSprite* TheSprite = ((PlayerSprite*)(Sprite->GetRenderableByName()));
- if (TheSprite)
- {
- if (!OVERWORLD_MOTION)
- {
- TheSprite->SetSprite("capmansheetredux.bmp", NHashedString("Texture_PlayerSprite_Default"));
- }
- else
- {
- TheSprite->SetSprite("capmanmapsheet.bmp", NHashedString("Texture_PlayerSprite_Overworld"));
- }
- }
- OverworldFacing = NVec2(0,1);
- PrevOverworldFacing = OverworldFacing;
- OverworldState = OMS_Idle;
- OverWalk_Duration = 0.25f; // Based on Zelda 2 rates.
- OverWalk_Elapsed = 0.0f;
- if (OVERWORLD_MOTION)
- {
- // I think this is right...
- //InitCamera();
- }
- if (OVERWORLD_MOTION)
- {
- // Set a brief delay to prevent walking right after going to the map.
- OverworldDelay = OVERWORLD_DELAY;
- }
- else
- {
- OverworldDelay = -1.0f;
- }
- if (OVERWORLD_MOTION)
- {
- IcyVelocity.x = 0.0f;
- }
- }
- void Player::SetSwimmingLineDef(bool bSwimming, bool bToxic, bool bEffects, bool bEntering)
- {
- bLineDefUnderwater = bSwimming;
- bLineDefToxic = bSwimming ? bToxic : false;
- SetSwimming(bEffects, bEntering);
- }
- void Player::SetSwimmingRegion(bool bSwimming, bool bToxic)
- {
- bRegionUnderwater = bSwimming;
- bRegionToxic = bSwimming ? bToxic : false;
- SetSwimming();
- }
- void Player::SetSwimming(bool bEffects, bool bEntering)
- {
- bool bSwimming = bLineDefUnderwater || bRegionUnderwater;
- bool bToxic = bLineDefToxic || bRegionToxic;
- if (bSwimming != SWIMMING_MOTION)
- {
- SWIMMING_MOTION = bSwimming;
- SetSwimmingProps();
- if (bEffects)
- {
- PlaySplashEffects(bEntering);
- }
- }
- if ((bSwimming && !HasPowerup(VPU_Suit_Swimming)) ||
- (bToxic && !HasPowerup(VPU_Suit_Toxic)))
- {
- Die();
- }
- }
- void Player::SetSwimmingProps()
- {
- // 1.12x multiplier means jumps now reach:
- // First jump: 4.704
- // Second jump: 3.024
- // Total jump: 7.728
- // That's probably okay?
- // With 1.5x on top of that,
- // First: 7.056
- // Second: 4.536
- // Total: 11.592
- float JumpHeights[NUM_JUMPS] =
- {(4.20f * 8.0f) * ASPECT_RATIO_FIXUP_Y * SIZE_FIXUP_Y,
- (2.70f * 8.0f) * ASPECT_RATIO_FIXUP_Y * SIZE_FIXUP_Y};
- float SwimmingJumpHeights[NUM_JUMPS] =
- {(4.20f * 8.0f) * ASPECT_RATIO_FIXUP_Y * SIZE_FIXUP_Y * 2.0f,
- (2.70f * 8.0f) * ASPECT_RATIO_FIXUP_Y * SIZE_FIXUP_Y * 2.0f};
- float PreChangeVertVel = Space->Game_Curr.Velocity.y;
- float PreChangeTermVel = PhysComp->GetTerminalVelocity();
- if (!OVERWORLD_MOTION)
- {
- if (SWIMMING_MOTION)
- {
- PhysComp->InitConstants(SWIMMING_MOVEMENT_SPEED, SwimmingJumpHeights, NUM_JUMPS, JUMP_TIME * 4.0f, 0.25f, 0.0f);
- }
- else
- {
- PhysComp->InitConstants(MOVEMENT_SPEED, JumpHeights, NUM_JUMPS, JUMP_TIME, 0.5f, 0.0f);
- }
- }
- float PostChangeVertVel = Space->Game_Curr.Velocity.y;
- float PostChangeTermVel = PhysComp->GetTerminalVelocity();
- float NewVertVel = PreChangeVertVel * PostChangeTermVel;
- if (fabs(PreChangeTermVel) > 0.0f)
- {
- NewVertVel = NewVertVel / PreChangeTermVel;
- }
- PostChangeVertVel;
- NewVertVel;
- //if (PreChangeVertVel < 0.0 && NewVertVel < 0.0f && NewVertVel < PreChangeVertVel)
- {
- // Increase speed jumping out of water.
- const float CHANGE_PERCENT = 0.65f;
- Space->Game_Curr.Velocity.y = Lerp(PostChangeVertVel, NewVertVel, CHANGE_PERCENT);
- //Space->Init();
- }
- ANCHOR;
- }
- // Don't actually start playing the tune here.
- // Instead (assuming the song changed), silence the music channel for a brief time, THEN play the song.
- void Player::SetBGMusic(const NString& BGMusicName)
- {
- // TODO: Don't restart the song if we're attempting to play the same one that's currently playing!
- if (BGMusicName != CurrentBGMusicName)
- {
- BGMusicSwitchDelay = BGMUSIC_SWITCH_DELAY;
- CurrentBGMusicName = BGMusicName;
- //ValkyrieGame::GetInstance()->MultiSynth->ClearTunes();
- MAKESTRING(BGMusicTune);
- ValkyrieGame::GetInstance()->MultiSynth->StopTune(BGMusicTune);
- }
- }
- void Player::SetSpeedrun(bool bSpeedrun, bool bSpeedrunActive, NHashedString CourseID)
- {
- bSpeedrun, bSpeedrunActive, CourseID;
- // bSpeedrun controls whether we show the speedrun status menu, the timer, etc.
- // bSpeedrunActive controls whether the timer is running.
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->SetProps(bSpeedrun, bSpeedrunActive, CourseID);
- }
- }
- void Player::SetBuildMinimap(bool bBuildMinimap, const NString& MinimapID)
- {
- bBuildMinimap; // Unused now.
- bBuildMinimap, MinimapID;
- MinimapComponent* MiniComp = GetComponent<MinimapComponent>();
- if (MiniComp)
- {
- if (ValkyrieGame::GetInstance()->TheMinimapBackMesh &&
- ValkyrieGame::GetInstance()->TheMinimapMesh &&
- ValkyrieGame::GetInstance()->TheMinimapIndicatorMesh)
- {
- ValkyrieGame::GetInstance()->TheMinimapBackMesh->visible = false;
- ValkyrieGame::GetInstance()->TheMinimapMesh->visible = false;
- ValkyrieGame::GetInstance()->TheMinimapIndicatorMesh->visible = false;
- ValkyrieGame::GetInstance()->bHasMinimap = false;
- }
- MiniComp->InvalidateID();
- MAKESTRINGWITH(MinimapsDef, "Minimaps.ndd");
- const NDefFileNode& TopNode = NDefMgr::GetInstance()->GetDefMapRef(MinimapsDef);
- TopNode;
- if (!TopNode.bIsDummy)
- {
- MAKESTRING(Collections);
- MAKESTRING(Collection);
- MAKESTRING(ID);
- MAKESTRING(LocFile);
- MAKESTRING(LocSection);
- MAKESTRING(LocKey);
- MAKESTRING(Minimaps);
- MAKESTRING(Minimap);
- MAKESTRING(Name);
- MAKESTRING(CollID);
- MAKESTRING(OX);
- MAKESTRING(OY);
- MAKESTRING(W);
- MAKESTRING(H);
- MAKESTRING(PX);
- MAKESTRING(PY);
- MAKESTRING(Base);
- MAKESTRING(Overlay);
- //MiniComp->MapIDToCollID.clear();
- for (NDefFileNodeIterator It = TopNode.GetChildByName(Collections).IterBegin(Collection); It(); It.Advance())
- {
- // TODO: Load collections
- }
- for (NDefFileNodeIterator It = TopNode.GetChildByName(Minimaps).IterBegin(Minimap); It(); It.Advance())
- {
- if (It.Get().KeyValues.exists(Name) &&
- It.Get().KeyValues[Name] ^ MinimapID)
- {
- //if ((It.Get().KeyValues.exists(Name))
- //{
- // NHashedString(*(It.Get().KeyValues[CollID]))
- // MiniComp->MapIDToCollID[] = ;
- //}
- if (It.Get().KeyValues.exists(OX) &&
- It.Get().KeyValues.exists(OY) &&
- It.Get().KeyValues.exists(Base) &&
- It.Get().KeyValues.exists(Overlay))
- {
- NString BaseBMP = It.Get().KeyValues[Base];
- NString OverlayBMP = It.Get().KeyValues[Overlay];
- int OffsetX = It.Get().KeyValues[OX].GetInt();
- int OffsetY = It.Get().KeyValues[OY].GetInt();
- int Width = -1;
- int Height = -1;
- int PosX = -1;
- int PosY = -1;
- if (It.Get().KeyValues.exists(W) &&
- It.Get().KeyValues.exists(H) &&
- It.Get().KeyValues.exists(PX) &&
- It.Get().KeyValues.exists(PY))
- {
- Width = It.Get().KeyValues[W].GetInt();
- Height = It.Get().KeyValues[H].GetInt();
- PosX = It.Get().KeyValues[PX].GetInt();
- PosY = It.Get().KeyValues[PY].GetInt();
- }
- // TODO: Load collection ID.
- MiniComp->Init(BaseBMP, OverlayBMP, OffsetX, OffsetY, Width, Height, PosX, PosY, NHashedString(*MinimapID));
- if (ValkyrieGame::GetInstance()->TheMinimapBackMesh &&
- ValkyrieGame::GetInstance()->TheMinimapMesh &&
- ValkyrieGame::GetInstance()->TheMinimapIndicatorMesh)
- {
- ValkyrieGame::GetInstance()->TheMinimapBackMesh->visible = ValkyrieGame::GetInstance()->MINIMAP_VISIBLE;
- ValkyrieGame::GetInstance()->TheMinimapMesh->visible = ValkyrieGame::GetInstance()->MINIMAP_VISIBLE;
- ValkyrieGame::GetInstance()->TheMinimapIndicatorMesh->visible = ValkyrieGame::GetInstance()->MINIMAP_VISIBLE;
- ValkyrieGame::GetInstance()->bHasMinimap = true;
- }
- }
- }
- }
- }
- }
- /*
- NString MapName = ValkyrieGame::GetInstance()->TheWorld.CurrentMapName;
- MapName;
- //ValkyrieGame::GetInstance()->TheWorld.ActiveMap;
- POINT Room = ValkyrieGame::GetInstance()->TheWorld.ActiveRoom;
- Room;
- ANCHOR;
- //if (bBuildMinimap)
- {
- // We need to walk the rooms and build a map.
- ANCHOR;
- // Really just a set.
- //NUtilMap<NUtilMap<uint, int>, int> WalkedRooms;
- //RecBuildMinimap(WalkedRooms, Room);
- int MinX = 1000;
- int MaxX = -1000;
- int MinY = 1000;
- int MaxY = -1000;
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- const NUtilMap<NUtilMap<ValkyrieRoom, int>, int>& Rooms = TheWorld.Rooms;
- //for (NUtilMapIter<NUtilMap<uint, int>, int> It1 = WalkedRooms.first(); It1(); It1.next())
- for (NUtilMapIter<NUtilMap<ValkyrieRoom, int>, int> It1 = Rooms.first(); It1(); It1.next())
- {
- MinX = Min(MinX, It1.getKey());
- MaxX = Max(MaxX, It1.getKey());
- for (NUtilMapIter<ValkyrieRoom, int> It2 = (*It1).first(); It2(); It2.next())
- {
- MinY = Min(MinY, It2.getKey());
- MaxY = Max(MaxY, It2.getKey());
- }
- }
- int CenterX = (MinX + MaxX) / 2;
- int CenterY = (MinY + MaxY) / 2;
- int Width = (MaxX - MinX) + 1;
- int Height = (MaxY - MinY) + 1;
- CenterX, CenterY, Width, Height;
- int X1 = -(Width / 2);
- int Y1 = -(Height / 2);
- int X2 = X1 + Width - 1;
- int Y2 = Y1 + Height - 1;
- X1, X2, Y1, Y2;
- NImage MinimapImage;
- NImage GuideImage;
- MinimapImage.init(Width * 4 + 8, Height * 4 + 8, 3);
- GuideImage.init(Width * 8 + 16, Height * 8 + 16, 3);
- opt_assert(Width <= 24);
- opt_assert(Height <= 20);
- for (int x = X1; x <= X2; ++x)
- {
- for (int y = Y1; y <= Y2; ++y)
- {
- //int PixelX1 = (MinimapImage.getWidth() / 2) + (x * 8);
- //int PixelY1 = (MinimapImage.getHeight() / 2) + (y * 8);
- int PixelX1 = ((x - X1) * 8) + 8;
- int PixelY1 = ((y - Y1) * 8) + 8;
- int PixelX2 = PixelX1 + 7;
- int PixelY2 = PixelY1 + 7;
- int RoomX = x - X1 + MinX;
- int RoomY = y - Y1 + MinY;
- RoomX, RoomY;
- if (Rooms.exists(RoomX) &&
- Rooms[RoomX].exists(RoomY))
- {
- //uint Paths = Rooms[RoomX][RoomY];
- for (int px = PixelX1; px <= PixelX2; ++px)
- {
- for (int py = PixelY1; py <= PixelY2; ++py)
- {
- int Count = 0;
- int SolidCount = 0;
- for (int xx = 0; xx < 4; ++xx)
- {
- for (int yy = 0; yy < 4; ++yy)
- {
- Count++;
- int bx = ((px - PixelX1) * 4) + xx;
- int by = ((py - PixelY1) * 4) + yy;
- static NUtilVector<ValkyrieTileType> SolidTiles;
- if (SolidTiles.empty())
- {
- SolidTiles.push(VTT_Solid);
- SolidTiles.push(VTT_Ice);
- SolidTiles.push(VTT_Deadly);
- SolidTiles.push(VTT_NoClimb);
- SolidTiles.push(VTT_NoEffects);
- }
- if (SolidTiles.findFirst(TheWorld.GetCellType(RoomX,RoomY,bx,by)) != -1)
- {
- SolidCount++;
- }
- }
- }
- uchar Brightness = uchar(128.0f * (float(SolidCount) / float(Count)));
- GuideImage.setPixel(px, py, NColor8(Brightness));
- }
- }
- //if ((Paths & HAS_PATH_TOP) == 0)
- {
- for (int px = PixelX1; px <= PixelX2 + 1; ++px)
- {
- //MinimapImage.setPixel(px, PixelY1, NColor8(255));
- }
- }
- //if ((Paths & HAS_PATH_BOTTOM) == 0)
- {
- for (int px = PixelX1; px <= PixelX2 + 1; ++px)
- {
- //MinimapImage.setPixel(px, PixelY2 + 1, NColor8(255));
- }
- }
- //if ((Paths & HAS_PATH_LEFT) == 0)
- {
- for (int py = PixelY1; py <= PixelY2 + 1; ++py)
- {
- //MinimapImage.setPixel(PixelX1, py, NColor8(255));
- }
- }
- //if ((Paths & HAS_PATH_RIGHT) == 0)
- {
- for (int py = PixelY1; py <= PixelY2 + 1; ++py)
- {
- //MinimapImage.setPixel(PixelX2 + 1, py, NColor8(255));
- }
- }
- }
- }
- }
- for (int x = X1; x <= X2; ++x)
- {
- for (int y = Y1; y <= Y2; ++y)
- {
- //int PixelX1 = (MinimapImage.getWidth() / 2) + (x * 8);
- //int PixelY1 = (MinimapImage.getHeight() / 2) + (y * 8);
- int PixelX1 = ((x - X1) * 4) + 4;
- int PixelY1 = ((y - Y1) * 4) + 4;
- int PixelX2 = PixelX1 + 4;
- int PixelY2 = PixelY1 + 4;
- int RoomX = x - X1 + MinX;
- int RoomY = y - Y1 + MinY;
- RoomX, RoomY;
- if (Rooms.exists(RoomX) &&
- Rooms[RoomX].exists(RoomY))
- {
- bool bInSubRegion = false;
- for (int i = 0; i < TheWorld.ScrollRegions.size() && !bInSubRegion; ++i)
- {
- const RECT& Region = TheWorld.ScrollRegions[i].Region;
- if (RoomX >= Region.left &&
- RoomX < Region.right &&
- RoomY >= Region.top &&
- RoomY < Region.bottom)
- {
- bInSubRegion = true;
- }
- }
- if (!bInSubRegion)
- {
- for (int px = PixelX1 + 1; px <= PixelX2 - 1; ++px)
- {
- for (int py = PixelY1 + 1; py <= PixelY2 - 1; ++py)
- {
- MinimapImage.setPixel(px, py, NColor8(0, 120, 248));
- }
- }
- for (int px = PixelX1; px <= PixelX2; ++px)
- {
- MinimapImage.setPixel(px, PixelY1, NColor8(255));
- MinimapImage.setPixel(px, PixelY2, NColor8(255));
- }
- for (int py = PixelY1; py <= PixelY2; ++py)
- {
- MinimapImage.setPixel(PixelX1, py, NColor8(255));
- MinimapImage.setPixel(PixelX2, py, NColor8(255));
- }
- }
- }
- }
- }
- for (int i = 0; i < TheWorld.ScrollRegions.size(); ++i)
- {
- //for (int x = TheWorld.ScrollRegions[i].Region.left; x < TheWorld.ScrollRegions[i].Region.right; ++x)
- //{
- // for (int y = TheWorld.ScrollRegions[i].Region.top; y < TheWorld.ScrollRegions[i].Region.bottom; ++y)
- // {
- // }
- //}
- const RECT& Region = TheWorld.ScrollRegions[i].Region;
- int PixelX1 = ((Region.left - MinX) * 4) + 4;
- int PixelY1 = ((Region.top - MinY) * 4 + 4);
- int PixelX2 = ((Region.right - MinX) * 4) + 4;
- int PixelY2 = ((Region.bottom - MinY) * 4) + 4;
- for (int px = PixelX1 + 1; px <= PixelX2 - 1; ++px)
- {
- for (int py = PixelY1 + 1; py <= PixelY2 - 1; ++py)
- {
- MinimapImage.setPixel(px, py, NColor8(0, 120, 248));
- }
- }
- for (int px = PixelX1; px <= PixelX2; ++px)
- {
- MinimapImage.setPixel(px, PixelY1, NColor8(255));
- MinimapImage.setPixel(px, PixelY2, NColor8(255));
- }
- for (int py = PixelY1; py <= PixelY2; ++py)
- {
- MinimapImage.setPixel(PixelX1, py, NColor8(255));
- MinimapImage.setPixel(PixelX2, py, NColor8(255));
- }
- }
- ANCHOR;
- //MinimapImage.saveBMP(Text("MINIMAP_%s.bmp", MapName));
- //GuideImage.saveBMP(Text("MINIMAP_GUIDE_%s.bmp", MapName));
- ANCHOR;
- }
- //else
- {
- // We want to hide the minimap in this case.
- ANCHOR;
- }
- // Let's try something different.
- {
- }
- */
- }
- void Player::RecBuildMinimap(NUtilMap<NUtilMap<uint, int>, int>& Set, POINT CurRoom)
- {
- if (!Set.exists(CurRoom.x) ||
- !Set[CurRoom.x].exists(CurRoom.y))
- {
- // We haven't added this room yet.
- // See whether a path exists to an adjacent room.
- // Also have to see whether there's an edge remap,
- // whether the adjacent room is part of a scroll region, and so on.
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- if (TheWorld.Rooms.exists(CurRoom.x) &&
- TheWorld.Rooms[CurRoom.x].exists(CurRoom.y))
- {
- uint PATHS = 0;
- Set[CurRoom.x][CurRoom.y] = PATHS;
- const ValkyrieRoom& ThisRoom = TheWorld.Rooms[CurRoom.x][CurRoom.y];
- bool bHasTopPath = false;
- bool bHasBottomPath = false;
- bool bHasLeftPath = false;
- bool bHasRightPath = false;
- static NUtilVector<ValkyrieTileType> PathTypes;
- if (PathTypes.empty())
- {
- PathTypes.push(VTT_None);
- PathTypes.push(VTT_Ledge);
- PathTypes.push(VTT_Water);
- PathTypes.push(VTT_Toxic);
- }
- for (int i = 1; i < TILES_WIDTH - 1; ++i)
- {
- bHasTopPath = bHasTopPath || (PathTypes.findFirst(TheWorld.GetCellType(CurRoom.x, CurRoom.y, i, 0)) != -1);
- bHasBottomPath = bHasBottomPath || (PathTypes.findFirst(TheWorld.GetCellType(CurRoom.x, CurRoom.y, i, TILES_HEIGHT - 1)) != -1);
- }
- for (int i = 1; i < TILES_HEIGHT - 1; ++i)
- {
- bHasLeftPath = bHasLeftPath || (PathTypes.findFirst(TheWorld.GetCellType(CurRoom.x, CurRoom.y, 0, i)) != -1);
- bHasRightPath = bHasRightPath || (PathTypes.findFirst(TheWorld.GetCellType(CurRoom.x, CurRoom.y, TILES_WIDTH - 1, i)) != -1);
- }
- // See whether we have a jump cut or a remap, as this will affect how or whether we recurse.
- // Not yet sure where scroll regions will go.
- if (bHasTopPath)
- {
- bool bRecurse = true;
- POINT RecRoom;
- RecRoom.x = CurRoom.x;
- RecRoom.y = CurRoom.y - 1;
- if (!TheWorld.Rooms.exists(RecRoom.x) || !TheWorld.Rooms[RecRoom.x].exists(RecRoom.y)) {bRecurse = false;}
- if (ThisRoom.Edges[0].bHasMapName && ThisRoom.Edges[0].MapName != TheWorld.ActiveMap) {bRecurse = false;}
- if (ThisRoom.Edges[0].bHasMapCoords) {RecRoom = ThisRoom.Edges[0].MapCoords;}
- if (bRecurse) {RecBuildMinimap(Set, RecRoom); PATHS |= HAS_PATH_TOP;}
- }
- if (bHasBottomPath)
- {
- bool bRecurse = true;
- POINT RecRoom;
- RecRoom.x = CurRoom.x;
- RecRoom.y = CurRoom.y + 1;
- if (!TheWorld.Rooms.exists(RecRoom.x) || !TheWorld.Rooms[RecRoom.x].exists(RecRoom.y)) {bRecurse = false;}
- if (ThisRoom.Edges[1].bHasMapName && ThisRoom.Edges[1].MapName != TheWorld.ActiveMap) {bRecurse = false;}
- if (ThisRoom.Edges[1].bHasMapCoords) {RecRoom = ThisRoom.Edges[1].MapCoords;}
- if (bRecurse) {RecBuildMinimap(Set, RecRoom); PATHS |= HAS_PATH_BOTTOM;}
- }
- if (bHasLeftPath)
- {
- bool bRecurse = true;
- POINT RecRoom;
- RecRoom.x = CurRoom.x - 1;
- RecRoom.y = CurRoom.y;
- if (!TheWorld.Rooms.exists(RecRoom.x) || !TheWorld.Rooms[RecRoom.x].exists(RecRoom.y)) {bRecurse = false;}
- if (ThisRoom.Edges[2].bHasMapName && ThisRoom.Edges[2].MapName != TheWorld.ActiveMap) {bRecurse = false;}
- if (ThisRoom.Edges[2].bHasMapCoords) {RecRoom = ThisRoom.Edges[2].MapCoords;}
- if (bRecurse) {RecBuildMinimap(Set, RecRoom); PATHS |= HAS_PATH_LEFT;}
- }
- if (bHasRightPath)
- {
- bool bRecurse = true;
- POINT RecRoom;
- RecRoom.x = CurRoom.x + 1;
- RecRoom.y = CurRoom.y;
- if (!TheWorld.Rooms.exists(RecRoom.x) || !TheWorld.Rooms[RecRoom.x].exists(RecRoom.y)) {bRecurse = false;}
- if (ThisRoom.Edges[3].bHasMapName && ThisRoom.Edges[3].MapName != TheWorld.ActiveMap) {bRecurse = false;}
- if (ThisRoom.Edges[3].bHasMapCoords) {RecRoom = ThisRoom.Edges[3].MapCoords;}
- if (bRecurse) {RecBuildMinimap(Set, RecRoom); PATHS |= HAS_PATH_RIGHT;}
- }
- Set[CurRoom.x][CurRoom.y] = PATHS;
- }
- }
- }
- void Player::TickCommitBGMusicChange(float DeltaTime)
- {
- if (BGMusicSwitchDelay > 0.0f)
- {
- BGMusicSwitchDelay -= DeltaTime;
- if (BGMusicSwitchDelay <= 0.0f)
- {
- //CurrentBGMusicName = BGMusicSwitchName;
- // At least for starters, we'll clear ALL tunes (including sound effects) when changing BG music.
- // This will likely be crap and not a shipping solution.
- if (CurrentBGMusicName.Length() > 0)
- {
- // TODO: Need to save off the campaign's prefix for use here!
- MAKESTRING(BGMusicTune);
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune(*(ValkyrieGame::GetInstance()->ActiveCampaignPrefix + CurrentBGMusicName), AUDPRI_BGMUSIC, NMS_CHAN_BGMUSIC), BGMusicTune, NMSTU_BGM);
- }
- }
- }
- }
- void Player::SetSprite(const NString& SpriteName)
- {
- PlayerSprite* TheSprite = ((PlayerSprite*)(Sprite->GetRenderableByName()));
- if (TheSprite)
- {
- if (SpriteName.Length() > 0)
- {
- TheSprite->SetSprite(*SpriteName, NHashedString(*(NString("Texture_PlayerSprite_Alternate_") + SpriteName)));
- }
- else
- {
- if (!OVERWORLD_MOTION)
- {
- TheSprite->SetSprite("capmansheetredux.bmp", NHashedString("Texture_PlayerSprite_Default"));
- }
- else
- {
- TheSprite->SetSprite("capmanmapsheet.bmp", NHashedString("Texture_PlayerSprite_Overworld"));
- }
- }
- }
- }
- void Player::SetSafeSpace(bool bSafe)
- {
- bCurrentSafeSpace = bSafe;
- }
- void Player::OnBaseAboutToMove(NEntity* Owner, NEntity* Parent)
- {
- if (Owner && Parent)
- {
- }
- }
- void Player::OnBaseMoved(NEntity* Owner, NEntity* Parent)
- {
- if (Owner && Parent)
- {
- Player* ThePlayer = Cast<Player>(Owner);
- ThePlayer->Camera->Camera->setPos(ThePlayer->GetCameraPosition(ThePlayer->bExtendedCamera, ThePlayer->bExtendedCamera));
- // Should fix the "whoops I rode a donut lift off the screen" bug.
- ThePlayer->CheckTransitionRooms();
- }
- }
- void Player::OnHealthDamaged(NEntity* OwnerEntity, NHandle Causer)
- {
- if (OwnerEntity)
- {
- Player* ThePlayer = Cast<Player>(OwnerEntity);
- ThePlayer->Die();
- }
- }
- bool Player::HasPowerup(ValkPowerups Powerup, bool bOmitSpeedrunPowerups)
- {
- bool bRetVal = false;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- static char NameBuffer[64] = {0};
- sprintf_s(NameBuffer, "Powerup_%08x", (int)Powerup);
- NHashedString PowerupName(NameBuffer);
- if (DataComp)
- {
- if (DataComp->HasValue(PowerupName))
- {
- GenericData PowerupValue;
- if (DataComp->GetValue(PowerupName, PowerupValue))
- {
- if (PowerupValue.Type == GDT_Bool)
- {
- if (PowerupValue.Data.Data_Bool == true)
- {
- bRetVal = true;
- }
- }
- }
- }
- }
- if (!bOmitSpeedrunPowerups)
- {
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->OverridePowerup(bRetVal, Powerup);
- }
- }
- return bRetVal;
- }
- void Player::SetHasPowerup(ValkPowerups Powerup, bool bHas)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- static char NameBuffer[64] = {0};
- sprintf_s(NameBuffer, "Powerup_%08x", (int)Powerup);
- NHashedString PowerupName(NameBuffer);
- if (DataComp)
- {
- GenericData PowerupValue(bHas);
- DataComp->CreateMappedValue(PowerupName);
- DataComp->SetValue(PowerupName, PowerupValue);
- }
- // And fix up the legacy properties until I kill them off...
- if (Powerup == VPU_Boots_DoubleJump)
- {
- //bHasDoubleJump = bHas;
- }
- else if (Powerup == VPU_Gloves_Climbing)
- {
- //bHasWallJump = bHas;
- }
- // TODO: Figure out the appropriate times to do these things.
- SetUpPhysComp();
- if (PhysComp)
- {
- PhysComp->IncrementJumpsRemaining();
- }
- // THIS IS VERY DANGEROUS. IT CAN DELETE STUFF OUT FROM UNDER US.
- //ValkyrieGame::GetInstance()->CompileRoom();
- }
- void Player::SetHasAllPowerups(bool bHas)
- {
- NUtilVector<ValkPowerups> DefPowers;
- DefPowers.push(VPU_Aura_Red);
- DefPowers.push(VPU_Aura_Blue);
- //DefPowers.push(VPU_Aura_Green);
- //DefPowers.push(VPU_Aura_Yellow);
- DefPowers.push(VPU_Boots_HighJump);
- DefPowers.push(VPU_Boots_DoubleJump);
- DefPowers.push(VPU_Boots_Spiked);
- DefPowers.push(VPU_Gloves_Climbing);
- DefPowers.push(VPU_Mask_Hidden);
- DefPowers.push(VPU_Badge_Pass);
- DefPowers.push(VPU_Suit_Swimming);
- DefPowers.push(VPU_Suit_Toxic);
- DefPowers.push(VPU_Key_Master);
- DefPowers.push(VPU_Pass_Arc);
- DefPowers.push(VPU_Pass_Styx);
- DefPowers.push(VPU_Trinket_Necklace);
- for (int i = 0; i < DefPowers.size(); ++i)
- {
- SetHasPowerup(DefPowers[i], bHas);
- }
- }
- void Player::CheckpointWith(NHandle Checkpoint, bool bUseLastSafePlace/*, bool bAllowThumbnail*/)
- {
- bool bIsSelf = (Checkpoint == GetHandle());
- bool bDoWrite = true;
- if (bUseLastSafePlace && bIsSelf)
- {
- if (LastSafePlace.Time > LastCheckpointTime)
- {
- SetCheckpointPosition(LastSafePlace.Position, bIsSelf);
- SetCheckpointCampaign(LastSafePlace.Campaign, bIsSelf);
- SetCheckpointMap(LastSafePlace.Map, bIsSelf);
- SetCheckpointRoom(LastSafePlace.Room, bIsSelf);
- }
- else
- {
- bDoWrite = false;
- }
- }
- else
- {
- NSpatialComponent* OtherSpace = Resolve<NSpatialComponent>(Checkpoint);
- if (Space)
- {
- SetCheckpointPosition(NVec2(OtherSpace->Game_Curr.Position.x, OtherSpace->Game_Curr.Position.y), bIsSelf);
- }
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- SetCheckpointCampaign(TheWorld.ActiveCampaign, bIsSelf);
- SetCheckpointMap(TheWorld.ActiveMap, bIsSelf);
- POINT NewRoom;
- NewRoom.x = TheWorld.ActiveRoom.x;
- NewRoom.y = TheWorld.ActiveRoom.y;
- SetCheckpointRoom(NewRoom, bIsSelf);
- }
- if (!bIsSelf)
- {
- // If we're trying to save at a bell, do a quicksave afterwards. This will also do the actual write to disk.
- CheckpointWith(GetHandle(), false/*, bAllowThumbnail*/);
- bDoWrite = false;
- }
- if (bDoWrite)
- {
- // Save our own data to the serial resource.
- NEntityFactory::SaveEntity(this);
- // Hrm. I need a better plan for these things.
- NEntityFactory::SaveEntity(ValkyrieGame::GetInstance()->TheGroupMgr);
- // TODO: Save ALL dynamic entities!!
- for (int i = 0; i < NBaseGame::GetInstance()->DynamicEntities.size(); ++i)
- {
- NEntityFactory::SaveEntity(NBaseGame::GetInstance()->DynamicEntities[i]);
- }
- //if (bAllowThumbnail)
- //{
- // // Super hacks.
- // if (bUseLastSafePlace)
- // {
- // CaptureThumbnail();
- // }
- // else
- // {
- // QueueThumbnail();
- // }
- //}
- // Do I want to commit changes to disk here?
- // Is there any reason not to?
- // When I end the game, I'll flush any unsaved data and reload from disk.
- char SaveGamePath[MAX_PATH];
- GetLocalAppDataPath(SaveGamePath, ValkyrieGame::GetInstance()->GetLocalAppDataPathName(), "Saves" FOLDER_SEPARATOR);
- strcat_s(SaveGamePath, MAX_PATH, "autosave.nsd");
- NSerialResource::GetInstance()->SaveToDisk(SaveGamePath);
- LastCheckpointTime = NBaseGame::GetInstance()->engAbsTime;
- }
- }
- //void Player::QueueThumbnail()
- //{
- // bCaptureThumbnail = true;
- //}
- //
- //void Player::CaptureThumbnail()
- //{
- // NColor8* CleanBuffer = new NColor8[CRT_WIDTH*CRT_HEIGHT];
- //
- // NColor8* pBuffer = CleanBuffer;
- // for (int y = 0; y < CRT_HEIGHT; ++y)
- // {
- // for (int x = 0; x < CRT_WIDTH; ++x)
- // {
- // *pBuffer = NColor8(0,0,0,255);
- // pBuffer++;
- // }
- // }
- //
- // // Somehow it looks like the pRenderSurface in this RTT can be NULL and that's the cause of the thumbnail crash.
- // // Seems unlikely (because how would the game work at all then), but shrug?
- // if (ValkyrieGame::GetInstance()->CleanFrame &&
- // ValkyrieGame::GetInstance()->CleanFrame->getSurface())
- // {
- // ValkyrieGame::GetInstance()->CleanFrame->CopyToBuffer(CleanBuffer, sizeof(NColor8) * CRT_WIDTH * CRT_HEIGHT);
- // }
- //
- // //MAKESTRINGWITH(QuadPassName, "Composite Pass");
- // //NRenderer::GetInstance()->GetRenderPass(QuadPassName)->targets[0]->CopyToBuffer(CleanBuffer, sizeof(NColor8) * CRT_WIDTH * CRT_HEIGHT);
- //
- // pBuffer = CleanBuffer;
- //#ifndef _NFML
- // for (int y = 0; y < CRT_HEIGHT; ++y)
- //#else
- // for (int y = CRT_HEIGHT - 1; y >=0 ; --y)
- //#endif
- // {
- // for (int x = 0; x < CRT_WIDTH; ++x)
- // {
- // ThumbImgFull.setPixel(x, y, *pBuffer);
- // pBuffer++;
- // }
- // }
- // SafeDeleteArray(CleanBuffer);
- //
- // // Ugh, sure.
- // SaveThumbnail();
- //}
- //
- //void Player::SaveThumbnail()
- //{
- // char ThumbPath[MAX_PATH];
- // GetLocalAppDataPath(ThumbPath, ValkyrieGame::GetInstance()->GetLocalAppDataPathName(), "Saves" FOLDER_SEPARATOR);
- // strcat_s(ThumbPath, MAX_PATH, "autosave.bmp");
- //
- //
- //
- // //int ScaledHeight = int(float(CRT_HEIGHT) * (float(THUMB_SIZE) / float(CRT_WIDTH)));
- // //NBlitter::ScaleDownBlit(ThumbImgSm, ThumbImgFull, 0, (THUMB_SIZE - ScaledHeight) / 2, 0, 0, THUMB_SIZE, ScaledHeight, CRT_WIDTH, CRT_HEIGHT, false, true);
- //
- // //ThumbImgSm.saveBMP(ThumbPath);
- //
- //
- //
- // if (!FileExists(ThumbPath) ||
- // !FileLocked(ThumbPath))
- // {
- // ThumbImgFull.saveBMP(ThumbPath);
- // }
- //}
- void Player::PostApplySerialData()
- {
- GetComponent<NDataComponent>()->SetCallbackOwner(GetHandle());
- GetComponent<NDataComponent>()->SetHasCallback(HACK_HasData);
- GetComponent<NDataComponent>()->SetGetCallback(HACK_GetData);
- GetComponent<NDataComponent>()->SetSetCallback(HACK_SetData);
- GetComponent<NDataComponent>()->SetIncCallback(HACK_IncData);
- GetComponent<NDataComponent>()->SetDecCallback(HACK_DecData);
- SetUpPhysComp();
- // And I guess always apply this after loading...
- SetEnteredCode(bEnteredCode || GetEnteredCode());
- }
- void Player::ApplyCheckpointData()
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- // Probably this doesn't need to do anything now.
- }
- }
- void Player::SetCheckpointPosition(NVec2 Position, bool bQuickSave)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(CheckpointPositionX);
- MAKESTRING(CheckpointPositionY);
- MAKESTRING(CheckpointPositionX_QuickSave);
- MAKESTRING(CheckpointPositionY_QuickSave);
- NHashedString StrX = bQuickSave ? CheckpointPositionX_QuickSave : CheckpointPositionX;
- NHashedString StrY = bQuickSave ? CheckpointPositionY_QuickSave : CheckpointPositionY;
- DataComp->CreateMappedValue(StrX);
- DataComp->CreateMappedValue(StrY);
- DataComp->SetValue(StrX, GenericData(Position.x));
- DataComp->SetValue(StrY, GenericData(Position.y));
- }
- }
- void Player::SetCheckpointRoom(POINT Coords, bool bQuickSave)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(CheckpointRoomX);
- MAKESTRING(CheckpointRoomY);
- MAKESTRING(CheckpointRoomX_QuickSave);
- MAKESTRING(CheckpointRoomY_QuickSave);
- NHashedString StrX = bQuickSave ? CheckpointRoomX_QuickSave : CheckpointRoomX;
- NHashedString StrY = bQuickSave ? CheckpointRoomY_QuickSave : CheckpointRoomY;
- DataComp->CreateMappedValue(StrX);
- DataComp->CreateMappedValue(StrY);
- DataComp->SetValue(StrX, GenericData(Coords.x));
- DataComp->SetValue(StrY, GenericData(Coords.y));
- }
- }
- void Player::SetCheckpointMap(NHashedString MapName, bool bQuickSave)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(CheckpointMap);
- MAKESTRING(CheckpointMap_QuickSave);
- NHashedString Str = bQuickSave ? CheckpointMap_QuickSave : CheckpointMap;
- DataComp->CreateMappedValue(Str);
- DataComp->SetValue(Str, GenericData(MapName));
- }
- }
- void Player::SetCheckpointCampaign(NHashedString CampaignName, bool bQuickSave)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(CheckpointCampaign);
- MAKESTRING(CheckpointCampaign_QuickSave);
- NHashedString Str = bQuickSave ? CheckpointCampaign_QuickSave : CheckpointCampaign;
- DataComp->CreateMappedValue(Str);
- DataComp->SetValue(Str, GenericData(CampaignName));
- }
- }
- void Player::SetDeaths(int Deaths)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(DeathsCount);
- DataComp->CreateMappedValue(DeathsCount);
- DataComp->SetValue(DeathsCount, GenericData(Deaths));
- }
- ValkyrieGame::GetInstance()->CheckAchievements("");
- }
- void Player::SetPlayTime(float PlayTime)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(PlayTimeSeconds);
- DataComp->CreateMappedValue(PlayTimeSeconds);
- DataComp->SetValue(PlayTimeSeconds, GenericData(PlayTime));
- }
- }
- void Player::SetEnteredCode(bool bEnteredCode)
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- MAKESTRING(EnteredCode);
- DataComp->CreateMappedValue(EnteredCode);
- DataComp->SetValue(EnteredCode, GenericData(bEnteredCode));
- }
- ValkyrieGame::GetInstance()->CheckAchievements(NString("AnyCampaign"));
- }
- NVec2 Player::GetCheckpointPosition(bool bQuickSave)
- {
- NVec2 RetVal = NVec2((float)HALF_CRT_WIDTH, (float)HALF_CRT_HEIGHT);
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(CheckpointPositionX);
- MAKESTRING(CheckpointPositionY);
- MAKESTRING(CheckpointPositionX_QuickSave);
- MAKESTRING(CheckpointPositionY_QuickSave);
- NHashedString StrX = bQuickSave ? CheckpointPositionX_QuickSave : CheckpointPositionX;
- NHashedString StrY = bQuickSave ? CheckpointPositionY_QuickSave : CheckpointPositionY;
- if (DataComp->GetValue(StrX, OutData))
- {
- opt_assert(OutData.Type == GDT_Float);
- RetVal.x = OutData.Data.Data_Float;
- }
- if (DataComp->GetValue(StrY, OutData))
- {
- opt_assert(OutData.Type == GDT_Float);
- RetVal.y = OutData.Data.Data_Float;
- }
- }
- return RetVal;
- }
- POINT Player::GetCheckpointRoom(bool bQuickSave)
- {
- POINT RetVal;
- RetVal.x = 0;
- RetVal.y = 0;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(CheckpointRoomX);
- MAKESTRING(CheckpointRoomY);
- MAKESTRING(CheckpointRoomX_QuickSave);
- MAKESTRING(CheckpointRoomY_QuickSave);
- NHashedString StrX = bQuickSave ? CheckpointRoomX_QuickSave : CheckpointRoomX;
- NHashedString StrY = bQuickSave ? CheckpointRoomY_QuickSave : CheckpointRoomY;
- if (DataComp->GetValue(StrX, OutData))
- {
- opt_assert(OutData.Type == GDT_Int);
- RetVal.x = OutData.Data.Data_Int;
- }
- if (DataComp->GetValue(StrY, OutData))
- {
- opt_assert(OutData.Type == GDT_Int);
- RetVal.y = OutData.Data.Data_Int;
- }
- }
- return RetVal;
- }
- NHashedString Player::GetCheckpointMap(bool bQuickSave)
- {
- NHashedString RetVal;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(CheckpointMap);
- MAKESTRING(CheckpointMap_QuickSave);
- NHashedString Str = bQuickSave ? CheckpointMap_QuickSave : CheckpointMap;
- if (DataComp->GetValue(Str, OutData))
- {
- opt_assert(OutData.Type == GDT_HashedString);
- RetVal = OutData.Data.Data_HashedString;
- }
- }
- return RetVal;
- }
- NHashedString Player::GetCheckpointCampaign(bool bQuickSave)
- {
- NHashedString RetVal;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(CheckpointCampaign);
- MAKESTRING(CheckpointCampaign_QuickSave);
- NHashedString Str = bQuickSave ? CheckpointCampaign_QuickSave : CheckpointCampaign;
- if (DataComp->GetValue(Str, OutData))
- {
- opt_assert(OutData.Type == GDT_HashedString);
- RetVal = OutData.Data.Data_HashedString;
- }
- }
- return RetVal;
- }
- int Player::GetDeaths()
- {
- int RetVal = 0;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(DeathsCount);
- if (DataComp->GetValue(DeathsCount, OutData))
- {
- opt_assert(OutData.Type == GDT_Int);
- RetVal = OutData.Data.Data_Int;
- }
- }
- return RetVal;
- }
- float Player::GetPlayTime()
- {
- float RetVal = 0;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(PlayTimeSeconds);
- if (DataComp->GetValue(PlayTimeSeconds, OutData))
- {
- opt_assert(OutData.Type == GDT_Float);
- RetVal = OutData.Data.Data_Float;
- }
- }
- return RetVal;
- }
- bool Player::GetEnteredCode()
- {
- bool RetVal = false;
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- GenericData OutData;
- MAKESTRING(EnteredCode);
- if (DataComp->GetValue(EnteredCode, OutData))
- {
- opt_assert(OutData.Type == GDT_Bool);
- RetVal = OutData.Data.Data_Bool;
- }
- }
- return RetVal;
- }
- void Player::TryGround(float LiftDist, float DropDist)
- {
- if (Space && Collision && !OVERWORLD_MOTION)
- {
- NCore::GetInstance()->DebuggerHook();
- // Lift without regard to collision, probably.
- // Can change this if it causes problems later.
- Space->Game_Curr.Position.y -= LiftDist;
- // Then drop and collide.
- // This does not go through the normal spatial component sweep path.
- {
- static NUtilVector<NCollisionResult> Results;
- Results.setNeverDealloc(true);
- Results.clear();
- NCollisionInterface* Primitive = Collision->GetPrimitiveByName();
- if (Primitive)
- {
- if (!NGameOctree::GetInstance()->Sweep(
- Results, Primitive,
- Space->Game_Curr.Position,
- Space->Game_Curr.Position + NVec3(0, DropDist, 0),
- 0, Collision->GetSweepFilter()))
- {
- // We hit something.
- // Update our position.
- Space->Game_Curr.Position = Results[0].HitPosition;
- Space->Game_Curr.Position.z = 0.0f; // Just to be safe.
- // Suuuuuuuuper hacks.
- if (GetComponent<NPhysicsComponent>())
- {
- GetComponent<NPhysicsComponent>()->OnSpawn(false);
- GetComponent<NPhysicsComponent>()->Land(Results[0]);
- // Apply terminal velocity immediately so we stay grounded.
- Space->Game_Curr.Velocity = NPhysicsGlobals::GetWorldUp() * -PhysComp->GetTerminalVelocity();
- // This initializes acceleration.
- PhysComp->Function2_NeedsName(false);
- }
- // Suppress animation.
- LandedTime = 0.0f;
- }
- else
- {
- // We didn't hit anything.
- // Undo the lift.
- Space->Game_Curr.Position.y += LiftDist;
- }
- }
- }
- Space->Init();
- }
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (Speed)
- {
- Speed->TryRecordGhostEvent(true);
- }
- }
- void Player::TryEnterRoomFromTeleport()
- {
- // Just a random bit of polish.
- // Automate walking and suppress jumping for a short duration. Another bit stolen from Zelda 2.
- if (!OVERWORLD_MOTION)
- {
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- if (Space->Game_Curr.Position.x <= (TheWorld.CurrentScrollBounds.Left) + (TILE_SIZE * 2.0f))
- {
- TeleportEntry_Direction = NVec3(1.0f, 0.0f, 0.0f);
- TeleportEntry_Remaining = TeleportEntry_Duration;
- }
- else if (Space->Game_Curr.Position.x >= (TheWorld.CurrentScrollBounds.Right) - (TILE_SIZE * 2.0f))
- {
- TeleportEntry_Direction = NVec3(-1.0f, 0.0f, 0.0f);
- TeleportEntry_Remaining = TeleportEntry_Duration;
- }
- }
- }
- void Player::ShowStatusScreen()
- {
- NDialogConsumerComponent* MyDialogConsumer = GetComponent<NDialogConsumerComponent>();
- NDialogProviderComponent* MyDialogProvider = GetComponent<NDialogProviderComponent>();
- if (MyDialogConsumer && MyDialogProvider)
- {
- // TODO: AUDIO
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Open);
- ValkyrieGame::GetInstance()->TheGameFont_Screen->LeadingScale = 1.0f;
- MAKESTRING(DialogProvider);
- SpeedrunComponent* Speed = GetComponent<SpeedrunComponent>();
- if (!Speed || !Speed->bOnSpeedrunCourse)
- {
- MyDialogProvider->ClearTree();
- MyDialogProvider->ApplyDefinitionData(StatusProviderFile.Contents.GetChildByName(DialogProvider));
- MyDialogProvider->SetTextSpeed(100000.0f); // Basically immediate.
- MyDialogProvider->SetMaxLines(10); // This is probably the best fit. Actually takes 23 lines, or 184 pixels of about 224 visible (16 above and 24 below).
- MyDialogProvider->SetMinLines(10); // This is probably the best fit. Actually takes 23 lines, or 184 pixels of about 224 visible (16 above and 24 below).
- MyDialogProvider->SetWidth(15);
- }
- else
- {
- MyDialogProvider->ClearTree();
- MyDialogProvider->ApplyDefinitionData(StatusProviderFile_Speedrun.Contents.GetChildByName(DialogProvider));
- MyDialogProvider->SetTextSpeed(100000.0f);
- MyDialogProvider->SetMaxLines(7);
- MyDialogProvider->SetMinLines(7);
- MyDialogProvider->SetWidth(18);
- }
- if (ValkyrieGame::GetInstance()->bHasMinimap)
- {
- //GetComponent<NDialogConsumerComponent>()->SetClosedCallback(OnDialogClosed_ToFullMap);
- }
- MyDialogProvider->Consumer = MyDialogConsumer->GetHandle();
- MyDialogProvider->TryInitFromTemplate();
- MyDialogConsumer->SetProvider(MyDialogProvider);
- }
- }
- void Player::ShowFullMap()
- {
- NDialogConsumerComponent* MyDialogConsumer = GetComponent<NDialogConsumerComponent>();
- NDialogProviderComponent* MyDialogProvider = GetComponent<NDialogProviderComponent>();
- if (MyDialogConsumer && MyDialogProvider)
- {
- // TODO: AUDIO
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Open);
- ValkyrieGame::GetInstance()->TheGameFont_Screen->LeadingScale = 1.0f;
- MAKESTRING(DialogProvider);
- {
- MyDialogProvider->ClearTree();
- MyDialogProvider->ApplyDefinitionData(StatusProviderFile_FullMap.Contents.GetChildByName(DialogProvider));
- MyDialogProvider->SetTextSpeed(100000.0f);
- MyDialogProvider->SetMaxLines(10);
- MyDialogProvider->SetMinLines(10);
- MyDialogProvider->SetWidth(26);
- }
- MyDialogProvider->Consumer = MyDialogConsumer->GetHandle();
- MyDialogProvider->TryInitFromTemplate();
- MyDialogConsumer->SetProvider(MyDialogProvider);
- }
- }
- void Player::OnDialogClosed(NEntity* OwnerEntity)
- {
- OwnerEntity;
- // Always reset this in case the dialog was the status screen.
- ValkyrieGame::GetInstance()->TheGameFont_Screen->LeadingScale = 2.0f;
- // Sure. Whatever.
- // Nah, still exploitable because of status screen.
- //Cast<Player>(OwnerEntity)->CheckpointWith(Cast<Player>(OwnerEntity)->GetHandle());
- ValkyrieGame::GetInstance()->TheFullMapMesh->visible = false;
- ValkyrieGame::GetInstance()->TheFullMapIndicatorMesh->visible = false;
- }
- /*
- void Player::OnDialogClosed_ToFullMap(NEntity* OwnerEntity)
- {
- OwnerEntity->GetComponent<NDialogConsumerComponent>()->SetClosedCallback(OnDialogClosed);
- NDialogConsumerComponent* MyDialogConsumer = OwnerEntity->GetComponent<NDialogConsumerComponent>();
- NDialogProviderComponent* MyDialogProvider = OwnerEntity->GetComponent<NDialogProviderComponent>();
- if (MyDialogConsumer && MyDialogProvider)
- {
- // TODO: AUDIO
- NBaseGame::GetInstance()->PlayDialogAudio(DAC_Open);
- ValkyrieGame::GetInstance()->TheGameFont_Screen->LeadingScale = 1.0f;
- MAKESTRING(DialogProvider);
- {
- MyDialogProvider->ClearTree();
- MyDialogProvider->ApplyDefinitionData(Cast<Player>(OwnerEntity)->StatusProviderFile_FullMap.Contents.GetChildByName(DialogProvider));
- MyDialogProvider->SetTextSpeed(100000.0f);
- MyDialogProvider->SetMaxLines(10);
- MyDialogProvider->SetMinLines(10);
- MyDialogProvider->SetWidth(18);
- }
- MyDialogProvider->Consumer = MyDialogConsumer->GetHandle();
- MyDialogProvider->TryInitFromTemplate();
- MyDialogConsumer->SetProvider(MyDialogProvider);
- }
- }
- */
- void Player::PlaySplashEffects(bool bEntering)
- {
- DebugLog("Playing splash effects.");
- float Offset = bEntering ? -2.0f : 0.0f;
- Offset += 4.0f;
- if (bEntering)
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("splashdown.nms", AUDPRI_LANDING, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- else
- {
- ValkyrieGame::GetInstance()->MultiSynth->PlayTune(NMSTune("splash.nms", AUDPRI_LANDING, NMS_CHAN_SOUNDFX), gNullStr, NMSTU_SFX);
- }
- {
- ValkEntity* NewEntity = NEntityFactory::BuildEntity<ValkEntity>(NHashedString("Splash.ndd"));
- // Oops, this may still be opted-out!
- if (NewEntity)
- {
- // TODO: Allow the game to make additional updates (e.g., for positioning Valkyrie entities relative to room coordinates).
- NBaseGame::GetInstance()->GamePostBuildEntity(NewEntity);
- NBaseGame::GetInstance()->DynamicEntities.push(NewEntity);
- // I guess update its position to the context's position?
- NSpatialComponent* ContextSpace = Resolve<NSpatialComponent>(this);
- NSpatialComponent* EffectSpace = Resolve<NSpatialComponent>(NewEntity);
- if (ContextSpace && EffectSpace)
- {
- // Don't alter Z.
- EffectSpace->Game_Curr.Position.x = ContextSpace->Game_Curr.Position.x;
- EffectSpace->Game_Curr.Position.y = ContextSpace->Game_Curr.Position.y + Offset;
- EffectSpace->Init();
- }
- }
- }
- }
- void Player::MadSwag()
- {
- NDataComponent* DataComp = GetComponent<NDataComponent>();
- if (DataComp)
- {
- DataComp->IncValue(NHashedString("smcubes"), GenericData(200));
- DataComp->IncValue(NHashedString("smcubes_total"), GenericData(200));
- DataComp->IncValue(NHashedString("bgcubes"), GenericData(10));
- }
- }
- void Player::AllowRejump()
- {
- bAllowRejump = true;
- }
- void Player::TryBubble(float DeltaTime)
- {
- if (SWIMMING_MOTION)
- {
- NextBubbleTime -= DeltaTime;
- if (NextBubbleTime <= 0.0f)
- {
- NextBubbleTime = (random_fl() * 2.0f) + 0.5f;
- NSpatialComponent* ContextSpace = Resolve<NSpatialComponent>(this);
- NVec3 SpawnPos = ContextSpace->Game_Curr.Position;
- SpawnPos.y -= 2.0f;
- const ValkyrieWorld& TheWorld = ValkyrieGame::GetInstance()->TheWorld;
- ValkyrieTileType SpawnTile =
- ValkyrieGame::GetInstance()->TheWorld.GetCellType(
- TheWorld.ActiveRoom.x, TheWorld.ActiveRoom.y,
- (int)(SpawnPos.x / (float)TILE_SIZE),
- (int)((SpawnPos.y - 8.0f) / (float)TILE_SIZE)); // Test higher to provide buffer space to float up.
- bool bUnderwater =
- ((SpawnTile == VTT_Water || SpawnTile == VTT_Toxic) ||
- (bRegionUnderwater && (SpawnTile == VTT_None || SpawnTile == VTT_Ledge)));
- if (bUnderwater)
- {
- ValkEntity* NewEntity = NEntityFactory::BuildEntity<ValkEntity>(NHashedString("Bubble.ndd"));
- // Oops, this may still be opted-out!
- if (NewEntity)
- {
- // TODO: Allow the game to make additional updates (e.g., for positioning Valkyrie entities relative to room coordinates).
- NBaseGame::GetInstance()->GamePostBuildEntity(NewEntity);
- NBaseGame::GetInstance()->DynamicEntities.push(NewEntity);
- // I guess update its position to the context's position?
- NSpatialComponent* EffectSpace = Resolve<NSpatialComponent>(NewEntity);
- if (ContextSpace && EffectSpace)
- {
- // Don't alter Z.
- EffectSpace->Game_Curr.Position.x = SpawnPos.x;
- EffectSpace->Game_Curr.Position.y = SpawnPos.y;
- EffectSpace->Init();
- }
- }
- }
- }
- }
- }
- bool Player::HACK_HasData(NHandle CallbackOwner, NHashedString Key)
- {
- bool bRetVal = false;
- SpeedrunComponent* Speed = Resolve<SpeedrunComponent>(CallbackOwner);
- if (Speed)
- {
- bRetVal = Speed->HasData(Key);
- }
- return bRetVal;
- }
- bool Player::HACK_GetData(NHandle CallbackOwner, NHashedString Key, GenericData& OutData)
- {
- bool bRetVal = false;
- SpeedrunComponent* Speed = Resolve<SpeedrunComponent>(CallbackOwner);
- if (Speed)
- {
- bRetVal = Speed->GetData(Key, OutData);
- if (!bRetVal)
- {
- MinimapComponent* Mini = Resolve<MinimapComponent>(CallbackOwner);
- if (Mini)
- {
- MAKESTRING(smcubes_loc_coll);
- MAKESTRING(smcubes_loc_total);
- MAKESTRING(loc_title);
- if (Key == smcubes_loc_coll)
- {
- bRetVal = true;
- //OutData = GenericData(Mini->CurrentDeets.CollectedGems);
- int OutCollectedGems = 0;
- int OutTotalGems = 0;
- Mini->CountGemsInCollection(OutCollectedGems, OutTotalGems, Mini->MapIDToCollID[Mini->LastMap]);
- OutData = GenericData(OutCollectedGems);
- }
- else if (Key == smcubes_loc_total)
- {
- bRetVal = true;
- //OutData = GenericData(Mini->CurrentDeets.TotalGems);
- int OutCollectedGems = 0;
- int OutTotalGems = 0;
- Mini->CountGemsInCollection(OutCollectedGems, OutTotalGems, Mini->MapIDToCollID[Mini->LastMap]);
- OutData = GenericData(OutTotalGems);
- }
- else if (Key == loc_title)
- {
- bRetVal = true;
- MAKESTRINGWITH(LocFile, "ValkyrieGame");
- MAKESTRINGWITH(LocSection, "Collections");
- NHashedString LocKey = Mini->CollIDToLocKey[Mini->MapIDToCollID[Mini->LastMap]];
- NString TitleString = NLocMgr::GetInstance()->GetString(LocFile, LocSection, LocKey);
- opt_assert(TitleString.PercLen() <= 24);
- int NumSpaces = Max(0, (24 - TitleString.PercLen()) / 2);
- for (int i = 0; i < NumSpaces; ++i)
- {
- TitleString = NString(" ") + TitleString;
- }
- OutData = GenericData(TitleString);
- }
- }
- }
- }
- return bRetVal;
- }
- bool Player::HACK_SetData(NHandle CallbackOwner, NHashedString Key, const GenericData& InData)
- {
- bool bRetVal = false;
- SpeedrunComponent* Speed = Resolve<SpeedrunComponent>(CallbackOwner);
- if (Speed)
- {
- bRetVal = Speed->SetData(Key, InData);
- }
- return bRetVal;
- }
- bool Player::HACK_IncData(NHandle CallbackOwner, NHashedString Key, const GenericData& DeltaData)
- {
- bool bRetVal = false;
- SpeedrunComponent* Speed = Resolve<SpeedrunComponent>(CallbackOwner);
- if (Speed)
- {
- bRetVal = Speed->IncData(Key, DeltaData);
- }
- return bRetVal;
- }
- bool Player::HACK_DecData(NHandle CallbackOwner, NHashedString Key, const GenericData& DeltaData)
- {
- bool bRetVal = false;
- SpeedrunComponent* Speed = Resolve<SpeedrunComponent>(CallbackOwner);
- if (Speed)
- {
- bRetVal = Speed->DecData(Key, DeltaData);
- }
- return bRetVal;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement