Skip to content

Commit

Permalink
Explosion and selection modifier cheat shortcuts
Browse files Browse the repository at this point in the history
* Added modifier shortcut to include monsters/spiderwebs in selections.
* Added modifier shortcut to include resources/equipment in selections.
* Emerge shortcut can now emerge slimy slugs from holes.
* DestroyAll shortcut now requires edit mode. Default keybind has been changed from [RCtrl]+[RShift]+[D] to [Delete].
* Default keybind for CommandDropLiveDynamite has been changed from [C] to [LShift]+[C].
* Added edit shortcut to toggle a unit's powered state (the old toggle power shortcut was mislabeled), now renamed ToggleSelfPowered.
* Added cheat shortcut to freeze a unit at mousepoint.
* Added cheat shortcut to spawn dynamite at mousepoint, and separate version to immediately explode.
* Added cheat shortcut to spawn a sonic blaster at mousepoint, and separate version to immediately go off.
* Added cheat shortcut to self-destruct all selected units with an explosion (inspired by Kamikaze Raiders).
* Fixed ice cube object not being deleted with parent objects when using DestroyAll.
  • Loading branch information
trigger-segfault committed Aug 26, 2022
1 parent 7cce61a commit cdcefc9
Show file tree
Hide file tree
Showing 12 changed files with 399 additions and 32 deletions.
30 changes: 26 additions & 4 deletions data/Settings/Shortcuts.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Lego* {
IncreaseGameSpeed KEYPAD_9

; Commands selected unit to drop live dynamite.
Debug_CommandDropDynamite !KEY_LEFTSHIFT+!KEY_RIGHTSHIFT+KEY_C
Debug_CommandDropDynamite KEY_LEFTSHIFT+!KEY_RIGHTSHIFT+KEY_C
; Registers selected vehicle for Debug_CommandGetInRegisteredVehicle.
Debug_CommandRegisterVehicle !KEY_LEFTCTRL+!KEY_RIGHTCTRL+KEY_K
; Commands selected unit to get in registered vehicle.
Expand All @@ -186,7 +186,7 @@ Lego* {
Debug_StopRouting KEY_N

; Toggles power Off/On for currently selected building.
Debug_TogglePower KEY_END
Debug_ToggleSelfPowered KEY_END

; Ends current advisor animation.
Debug_EndAdvisorAnim !KEY_LEFTSHIFT+KEY_U
Expand Down Expand Up @@ -242,7 +242,7 @@ Lego* {
; Triggers CrystalFound InfoMessage at block (1,1).
Debug_InterfaceCrystalFoundMessage KEY_LEFTSHIFT+KEY_Y ;KEY_Y

; Emerges level-designated Monster at mousepoint.
; Makes a monster or slug emerge from a valid spawn wall/hole at mousepoint.
Debug_EmergeMonster KEY_E
; ( ! ) Commands selected monster to gather a boulder at the nearest wall.
Debug_CommandGatherBoulder KEY_W
Expand All @@ -257,7 +257,7 @@ Lego* {
TrackUnit KEY_FOUR

; Deletes all selected units.
Debug_DestroyUnits KEY_RIGHTCTRL+KEY_RIGHTSHIFT+KEY_D
Edit_DestroyUnits !KEY_RIGHTSHIFT+KEY_DELETE ;KEY_RIGHTCTRL+KEY_RIGHTSHIFT+KEY_D
; Levels up selected units to max level, and gives selected mini-figures all abilities.
Cheat_MaxOutUnit KEY_RIGHTSHIFT+KEY_M

Expand Down Expand Up @@ -313,6 +313,28 @@ Lego* {
; Strafes (moves) the primary selected unit right in topdown view (while held).
Cheat_TopdownFPStrafeRight KeyBinds::FPStrafeRight

; Hold down while selecting units to include enemy creatures and spider webs.
Edit_SelectMonstersModifier KEY_T
; Hold down while selecting units to include crystals, ore, and equipment.
;; WARNING!! Messing with this is unstable, so expect crashes!
Edit_SelectResourcesModifier KEY_R

; Toggles the power of a building, or the sleeping state of a monster.
Edit_TogglePower KEY_HOME
; Freezes unit at mousepoint in a block of ice for 10 seconds.
Cheat_FreezeUnit KEY_I

; Spawns dynamite at mousepoint and begins the tickdown.
Cheat_PlaceDynamite !KEY_RIGHTSHIFT+KEY_LEFTBRACE
; Spawns dynamite at mousepoint that immediately explodes.
Cheat_PlaceDynamiteInstant KEY_RIGHTSHIFT+KEY_LEFTBRACE
; Spawns a sonic blaster at mousepoint and begins the tickdown.
Cheat_PlaceSonicBlaster !KEY_RIGHTSHIFT+KEY_RIGHTBRACE
; Spawns a sonic blaster at mousepoint that immediately goes off.
Cheat_PlaceSonicBlasterInstant KEY_RIGHTSHIFT+KEY_RIGHTBRACE
; Causes an explosion at the all selected units' positions and kills them in the process.
Cheat_KamikazeUnit KEY_RIGHTSHIFT+KEY_DELETE


; Reloads this configuration file, allowing to change command bindings on the fly.
ReloadKeyBinds KEY_LEFTCTRL+KEY_LEFTSHIFT+KEY_K|KEY_RIGHTCTRL+KEY_RIGHTSHIFT+KEY_K
Expand Down
142 changes: 135 additions & 7 deletions src/openlrr/game/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1251,14 +1251,38 @@ void __cdecl LegoRR::Lego_HandleWorldDebugKeys(sint32 mbx, sint32 mby, LegoObjec
}

/// DEBUG KEYBIND: [End] "Toggles power Off/On for currently selected building."
if (Message_AnyUnitSelected() && Shortcut_IsPressed(ShortcutID::Debug_TogglePower)) {
StatsObject_Debug_ToggleObjectPower(Message_GetPrimarySelectedUnit());
if (Message_AnyUnitSelected() && Shortcut_IsPressed(ShortcutID::Debug_ToggleSelfPowered)) {
StatsObject_Debug_ToggleSelfPowered(Message_GetPrimarySelectedUnit());
}

/// DEBUG KEYBIND: [E] "Makes a monster emerge from a diggable (valid) wall at mousepoint."
/// DEBUG KEYBIND: [E] "Makes a monster or slug emerge from a valid spawn wall/hole at mousepoint."
if (Shortcut_IsPressed(ShortcutID::Debug_EmergeMonster)) {
LegoObject_TryGenerateRMonster(&legoGlobs.rockMonsterData[legoGlobs.currLevel->EmergeCreature],
LegoObject_RockMonster, legoGlobs.currLevel->EmergeCreature, mbx, mby);
// First see if a slughole is at mousepoint, and try to emerge a slug.
LegoObject* emergeObj = nullptr;
LegoObject_Type slugType = LegoObject_None; // dummy inits
LegoObject_ID slugID = LegoObject_ID_Invalid;
ObjectModel* slugModel = nullptr;
// Oh joy, only one legacy level even uses this property, everywhere else, Slug is hardcoded...
if (legoGlobs.currLevel->Slug != LegoObject_ID_Invalid) {
slugType = LegoObject_RockMonster;
slugID = legoGlobs.currLevel->Slug;
slugModel = &legoGlobs.rockMonsterData[legoGlobs.currLevel->Slug];
}
else {
if (!Lego_GetObjectByName("Slug", &slugType, &slugID, &slugModel))
slugID = LegoObject_ID_Invalid;
}
if (slugID != LegoObject_ID_Invalid) {
emergeObj = LegoObject_TryGenerateSlugAtBlock(slugModel,
slugType, slugID,
mbx, mby, 0.0f, false);
}

if (emergeObj == nullptr && legoGlobs.currLevel->EmergeCreature != LegoObject_ID_Invalid) {
// This wasn't a slughole, try to emerge a monster.
LegoObject_TryGenerateRMonster(&legoGlobs.rockMonsterData[legoGlobs.currLevel->EmergeCreature],
LegoObject_RockMonster, legoGlobs.currLevel->EmergeCreature, mbx, mby);
}
}

/// DEBUG KEYBIND: [W] "Performs unknown behaviour with the unfinished 'flood water' surface."
Expand Down Expand Up @@ -1583,7 +1607,7 @@ void __cdecl LegoRR::Lego_HandleWorldDebugKeys(sint32 mbx, sint32 mby, LegoObjec
const bool cryOreExactMousePoint = true;

/// EDIT KEYBIND: NULL "Places one crystal at mousepoint."
if (Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_PlaceCrystal)) {
if (Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_PlaceCrystal) && Level_Block_IsGround(mbx, mby)) {
Point2F wPos2D = { 0.0f }; // dummy init
if (cryOreExactMousePoint) {
Vector3F wPos3D = { 0.0f }; // dummy init
Expand All @@ -1593,7 +1617,7 @@ void __cdecl LegoRR::Lego_HandleWorldDebugKeys(sint32 mbx, sint32 mby, LegoObjec
Level_GenerateCrystal(&mouseBlockPos, 0, (cryOreExactMousePoint ? &wPos2D : nullptr), false);
}
/// EDIT KEYBIND: NULL "Places one ore piece at mousepoint."
if (Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_PlaceOre)) {
if (Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_PlaceOre) && Level_Block_IsGround(mbx, mby)) {
Point2F wPos2D = { 0.0f }; // dummy init
if (cryOreExactMousePoint) {
Vector3F wPos3D = { 0.0f }; // dummy init
Expand All @@ -1612,6 +1636,110 @@ void __cdecl LegoRR::Lego_HandleWorldDebugKeys(sint32 mbx, sint32 mby, LegoObjec
Level_AddOreStored(false, 5);
}

/// DEBUG KEYBIND: NULL "Toggles the power of a building, or the sleeping state of a monster."
if (Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_TogglePower) && Message_AnyUnitSelected()) {
LegoObject_SetPowerOn(Message_GetPrimarySelectedUnit(), (Message_GetPrimarySelectedUnit()->flags3 & LIVEOBJ3_POWEROFF));
}
/// DEBUG KEYBIND: NULL "Freezes unit at mousepoint in a block of ice for 10 seconds."
if (mouseOverObj != nullptr && Shortcut_IsPressed(ShortcutID::Cheat_FreezeUnit)) {
LegoObject_Freeze(mouseOverObj, 10.0f); // Freeze for 10 seconds.
}

const bool placeDynBirdExactMousePoint = true;

/// DEBUG KEYBIND: NULL "Causes an explosion at the all selected units' positions and kills them in the process."
if (Shortcut_IsPressed(ShortcutID::Cheat_KamikazeUnit) && Message_AnyUnitSelected()) {
const uint32 numSelected = Message_GetNumSelectedUnits();
LegoObject** selectedUnits = Message_GetSelectedUnits();

for (uint32 i = 0; i < numSelected; i++) {
LegoObject* unit = selectedUnits[i];

const real32 heading = LegoObject_GetHeading(unit);
Point2F wPos2D = { 0.0f }; // dummy init
LegoObject_GetPosition(unit, &wPos2D.x, &wPos2D.y);
LegoObject* dynamiteObj = LegoObject_CreateInWorld(legoGlobs.contDynamite, LegoObject_Dynamite, (LegoObject_ID)0, 0, wPos2D.x, wPos2D.y, heading);
// Set the dynamite explosion block to invalid coordinates (strangely not -1, -1).
dynamiteObj->targetBlockPos = Point2F { 0.0f, 0.0f };
LegoObject_StartTickDown(dynamiteObj, true);

// No tickdown, explode immediately.
dynamiteObj->health = -1.0f;

if (unit->health >= 0.0f) {
unit->health = -1.0f;
switch (unit->type) {
case LegoObject_Building:
case LegoObject_Vehicle:
case LegoObject_MiniFigure:
// Destroy these object types normally.
unit->health = -1.0f;
break;
case LegoObject_RockMonster:
unit->health = -1.0f;
if (!(StatsObject_GetStatsFlags3(unit) & STATS3_SHOWHEALTHBAR) ||
(StatsObject_GetStatsFlags2(unit) & STATS2_USEHOLES))
{
// Remove unit by force. Either its a unit that doesn't "die",
// or Slimy Slug burrowing is too slow for a kamikaze visual.
unit->flags3 |= LIVEOBJ3_REMOVING;
}
break;
default:
unit->health = -1.0f;
unit->flags3 |= LIVEOBJ3_REMOVING;
break;
}
}
}
}
/// DEBUG KEYBIND: NULL "Spawns dynamite and starts the tickdown."
/// DEBUG KEYBIND: NULL "Spawns dynamite at mousepoint that immediately explodes."
if ((Shortcut_IsPressed(ShortcutID::Cheat_PlaceDynamite) || Shortcut_IsPressed(ShortcutID::Cheat_PlaceDynamiteInstant)) &&
(Level_Block_IsGround(mbx, mby) || Level_Block_IsWall(mbx, mby)))
{
const real32 heading = Gods98::Maths_RandRange(0.0f, M_PI*2.0f);
Point2F wPos2D = { 0.0f }; // dummy init
if (placeDynBirdExactMousePoint) {
Vector3F wPos3D = { 0.0f }; // dummy init
Lego_GetMouseWorldPosition(&wPos3D);
Gods98::Maths_Vector3DMake2D(&wPos2D, &wPos3D);
}
else {
Map3D_BlockToWorldPos(Lego_GetMap(), mbx, mby, &wPos2D.x, &wPos2D.x);
}
LegoObject* dynamiteObj = LegoObject_CreateInWorld(legoGlobs.contDynamite, LegoObject_Dynamite, (LegoObject_ID)0, 0, wPos2D.x, wPos2D.y, heading);
// Set the block this is on, which will be demolished if its a wall.
dynamiteObj->targetBlockPos = Point2F { (real32)mbx, (real32)mby };
LegoObject_StartTickDown(dynamiteObj, true);
if (Shortcut_IsPressed(ShortcutID::Cheat_PlaceDynamiteInstant)) {
// No tickdown, explode immediately.
dynamiteObj->health = -1.0f;
}
}
/// DEBUG KEYBIND: NULL "Spawns Sonic Blaster and starts the tickdown."
/// DEBUG KEYBIND: NULL "Spawns a sonic blaster at mousepoint that immediately goes off."
if ((Shortcut_IsPressed(ShortcutID::Cheat_PlaceSonicBlaster) || Shortcut_IsPressed(ShortcutID::Cheat_PlaceSonicBlasterInstant)) &&
(Level_Block_IsGround(mbx, mby) || Level_Block_IsWall(mbx, mby)))
{
const real32 heading = Gods98::Maths_RandRange(0.0f, M_PI*2.0f);
Point2F wPos2D = { 0.0f }; // dummy init
if (placeDynBirdExactMousePoint) {
Vector3F wPos3D = { 0.0f }; // dummy init
Lego_GetMouseWorldPosition(&wPos3D);
Gods98::Maths_Vector3DMake2D(&wPos2D, &wPos3D);
}
else {
Map3D_BlockToWorldPos(Lego_GetMap(), mbx, mby, &wPos2D.x, &wPos2D.x);
}
LegoObject* oohScaryObj = LegoObject_CreateInWorld(legoGlobs.contOohScary, LegoObject_OohScary, (LegoObject_ID)0, 0, wPos2D.x, wPos2D.y, heading);
LegoObject_StartTickDown(oohScaryObj, true);
if (Shortcut_IsPressed(ShortcutID::Cheat_PlaceSonicBlasterInstant)) {
// No tickdown, go off immediately.
oohScaryObj->health = -1.0f;
}
}


/// DEBUG KEYBIND: [Y] "Triggers the CrystalFound InfoMessage."
if (Shortcut_IsPressed(ShortcutID::Debug_InterfaceCrystalFoundMessage)) {
Expand Down
3 changes: 3 additions & 0 deletions src/openlrr/game/GameCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,9 @@ enum LegoObject_ID : sint32
LegoObject_ID_Pilot = 0,

LegoObject_ID_Count = 15,

// Used to signify that a level has no designated slug, may be used elsewhere.
LegoObject_ID_Invalid = 20,
};
assert_sizeof(LegoObject_ID, 0x4);

Expand Down
2 changes: 1 addition & 1 deletion src/openlrr/game/GameState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ bool32 __cdecl LegoRR::Lego_MainLoop(real32 elapsed)
}
}
/// DEBUG KEYBIND: NULL "Deletes all selected units."
if (Lego_IsAllowDebugKeys() && Shortcut_IsPressed(ShortcutID::Debug_DestroyUnits)) {
if (Lego_IsAllowDebugKeys() && Lego_IsAllowEditMode() && Shortcut_IsPressed(ShortcutID::Edit_DestroyUnits)) {
Message_PostEvent(Message_Debug_DestroyAll, nullptr, MESSAGE_ARGUMENT_NONE, nullptr);
}

Expand Down
15 changes: 13 additions & 2 deletions src/openlrr/game/Shortcuts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool Shortcuts::ShortcutManager::Initialise()

Shortcut_Register(Debug_StopRouting, "KEY_N");

Shortcut_Register(Debug_TogglePower, "KEY_END");
Shortcut_Register(Debug_ToggleSelfPowered, "KEY_END");

Shortcut_Register(Debug_EndAdvisorAnim, "!KEY_LEFTSHIFT+KEY_U");
Shortcut_Register(Debug_BeginAdvisorAnim, "KEY_LEFTSHIFT+KEY_U");
Expand Down Expand Up @@ -140,7 +140,7 @@ bool Shortcuts::ShortcutManager::Initialise()
Shortcut_Register(ChangeViewFP2, "KEY_TWO");
Shortcut_Register(ChangeViewTop, "KEY_THREE");
Shortcut_Register(TrackUnit, "KEY_FOUR");
Shortcut_Register(Debug_DestroyUnits, nullptr);
Shortcut_Register(Edit_DestroyUnits, nullptr);
Shortcut_Register(Cheat_MaxOutUnit, nullptr);

Shortcut_Register(Debug_ToggleUpgradeCarry, "KEY_FIVE");
Expand Down Expand Up @@ -171,6 +171,17 @@ bool Shortcuts::ShortcutManager::Initialise()
Shortcut_Register(Cheat_TopdownFPStrafeLeft, FPStrafeLeft);
Shortcut_Register(Cheat_TopdownFPStrafeRight, FPStrafeRight);

Shortcut_Register(Edit_SelectMonstersModifier, "KEY_T");
Shortcut_Register(Edit_SelectResourcesModifier, "KEY_R");

Shortcut_Register(Edit_TogglePower, nullptr);
Shortcut_Register(Cheat_FreezeUnit, nullptr);
Shortcut_Register(Cheat_PlaceDynamite, nullptr);
Shortcut_Register(Cheat_PlaceDynamiteInstant, nullptr);
Shortcut_Register(Cheat_PlaceSonicBlaster, nullptr);
Shortcut_Register(Cheat_PlaceSonicBlasterInstant, nullptr);
Shortcut_Register(Cheat_KamikazeUnit, nullptr);

Shortcut_Register(ReloadKeyBinds, "KEY_LEFTCTRL+KEY_LEFTSHIFT+KEY_K|KEY_RIGHTCTRL+KEY_RIGHTSHIFT+KEY_K");


Expand Down
26 changes: 23 additions & 3 deletions src/openlrr/game/Shortcuts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ enum ShortcutID
Debug_StopRouting, // [N]

// Toggles power Off/On for currently selected building.
Debug_TogglePower, // [End]
Debug_ToggleSelfPowered, // [End]

// Ends current advisor animation.
Debug_EndAdvisorAnim, // (!LShift)+[U]
Expand Down Expand Up @@ -199,7 +199,7 @@ enum ShortcutID
// Triggers CrystalFound InfoMessage at block (1,1).
Debug_InterfaceCrystalFoundMessage, // [Y]

// Emerges level-designated Monster at mousepoint.
// Makes a monster or slug emerge from a valid spawn wall/hole at mousepoint.
Debug_EmergeMonster, // [E]
// ( ! ) Commands selected monster to gather a boulder at the nearest wall.
Debug_CommandGatherBoulder, // [W]
Expand All @@ -213,7 +213,7 @@ enum ShortcutID
// Tracks the selected unit in the radar.
TrackUnit, // [4]
/// NEW: Deletes all selected units.
Debug_DestroyUnits, // NULL
Edit_DestroyUnits, // NULL
/// NEW: Levels up selected units to max level, and gives selected mini-figures all abilities.
Cheat_MaxOutUnit,

Expand Down Expand Up @@ -270,6 +270,26 @@ enum ShortcutID
/// NEW: Strafes (moves) the primary selected unit right in topdown view (while held).
Cheat_TopdownFPStrafeRight, // [X]

/// NEW: Hold down while selecting units to include enemy creatures.
Edit_SelectMonstersModifier, // [T]
/// NEW: Hold down while selecting units to include crystals and ore.
Edit_SelectResourcesModifier, // [R]

/// NEW: Toggles the power of a building, or the sleeping state of a monster.
Edit_TogglePower,
/// NEW: Freezes unit at mousepoint in a block of ice for 10 seconds.
Cheat_FreezeUnit,

/// NEW: Spawns dynamite at mousepoint and begins the tickdown.
Cheat_PlaceDynamite,
/// NEW: Spawns dynamite at mousepoint that immediately explodes.
Cheat_PlaceDynamiteInstant,
/// NEW: Spawns a sonic blaster at mousepoint and begins the tickdown.
Cheat_PlaceSonicBlaster,
/// NEW: Spawns a sonic blaster at mousepoint that immediately goes off.
Cheat_PlaceSonicBlasterInstant,
/// NEW: Causes an explosion at the all selected units' positions and kills them in the process.
Cheat_KamikazeUnit,


/// NEW: Reloads the configuration file, allowing to change command bindings on the fly.
Expand Down
Loading

0 comments on commit cdcefc9

Please sign in to comment.