Skip to content

Commit 55fbce4

Browse files
committed
Enhance grapple flight physics and max shoot distance
Introduces a maximum shooting distance, stopping the grapple hook if it doesn't attach within this range. Applies full rope physics simulation during the hook's flight phase, leading to more realistic rope behavior before attachment. If the player moves away while the airborne hook is at its maximum extension, the player is now pulled to maintain rope tension. Consolidates and refines the logic for handling rope length limits.
1 parent 169cb05 commit 55fbce4

File tree

3 files changed

+69
-32
lines changed

3 files changed

+69
-32
lines changed

Data/Base.rte/Devices/Tools/GrappleGun/Grapple.lua

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function Create(self)
2222

2323
self.fireVel = 40 -- This immediately overwrites the .ini FireVel
2424
self.maxLineLength = 400 -- Shorter rope for faster gameplay
25+
self.maxShootDistance = self.maxLineLength * 0.95 -- 95% of maxLineLength (5% less shooting distance)
2526
self.setLineLength = 0
2627
self.lineStrength = 10000 -- EXTREMELY HIGH force threshold - virtually unbreakable (was 120)
2728

@@ -134,17 +135,30 @@ function Update(self)
134135
self.lineLength = self.lineVec.Magnitude
135136
self.currentLineLength = self.lineLength
136137

138+
-- Check if we\'ve reached the maximum shooting distance during flight
139+
if self.lineLength >= self.maxShootDistance then
140+
-- Stop the claw at max shooting distance but keep it in flight mode
141+
local maxShootVec = self.lineVec:SetMagnitude(self.maxShootDistance)
142+
self.Pos = self.parent.Pos + maxShootVec
143+
self.Vel = Vector(0, 0) -- Stop the claw
144+
self.currentLineLength = self.maxShootDistance
145+
self.limitReached = true
146+
-- Keep actionMode = 1 (flight) so it can still detect collisions
147+
self.clickSound:Play(self.parent.Pos)
148+
end
149+
137150
-- Update rope anchor points directly for flight mode
138151
self.apx[0] = self.parent.Pos.X
139152
self.apy[0] = self.parent.Pos.Y
140153
self.apx[self.currentSegments] = self.Pos.X
141154
self.apy[self.currentSegments] = self.Pos.Y
142155

143156
-- Set all lastX/lastY positions to prevent velocity inheritance from previous mode
144-
for i = 0, self.currentSegments do
145-
self.lastX[i] = self.apx[i]
146-
self.lastY[i] = self.apy[i]
147-
end
157+
-- Commenting out this loop allows for rope physics during flight
158+
-- for i = 0, self.currentSegments do
159+
-- self.lastX[i] = self.apx[i]
160+
-- self.lastY[i] = self.apy[i]
161+
-- end
148162
end
149163

150164
-- Calculate optimal number of segments based on rope length using our module function
@@ -161,28 +175,22 @@ function Update(self)
161175
-- Proper rope physics simulation using the RopePhysics module
162176
local endPos = self.Pos
163177

164-
-- Choose physics simulation based on rope mode
165-
if self.actionMode == 1 then
166-
-- Flight mode - keep rope tight and straight
167-
RopePhysics.updateRopeFlightPath(self)
168-
else
169-
-- Attached mode - run full physics simulation
170-
RopePhysics.updateRopePhysics(self, startPos, endPos, self.currentLineLength)
171-
172-
-- Apply constraints and check for rope breaking (extremely high threshold)
173-
local ropeBreaks = RopePhysics.applyRopeConstraints(self, self.currentLineLength)
174-
if ropeBreaks or self.shouldBreak then
175-
-- Rope snapped due to EXTREME tension (500% stretch)
176-
self.ToDelete = true
177-
if self.parent and self.parent:IsPlayerControlled() then
178-
-- Add screen shake and sound effect when rope breaks
179-
FrameMan:SetScreenScrollSpeed(10.0) -- More dramatic shake for extreme break
180-
if self.returnSound then
181-
self.returnSound:Play(self.parent.Pos)
182-
end
178+
-- Use full rope physics simulation for both flight and attached modes
179+
RopePhysics.updateRopePhysics(self, startPos, endPos, self.currentLineLength)
180+
181+
-- Apply constraints and check for rope breaking (extremely high threshold)
182+
local ropeBreaks = RopePhysics.applyRopeConstraints(self, self.currentLineLength)
183+
if ropeBreaks or self.shouldBreak then
184+
-- Rope snapped due to EXTREME tension (500% stretch)
185+
self.ToDelete = true
186+
if self.parent and self.parent:IsPlayerControlled() then
187+
-- Add screen shake and sound effect when rope breaks
188+
FrameMan:SetScreenScrollSpeed(10.0) -- More dramatic shake for extreme break
189+
if self.returnSound then
190+
self.returnSound:Play(self.parent.Pos)
183191
end
184-
return -- Exit early since rope is breaking
185192
end
193+
return -- Exit early since rope is breaking
186194
end
187195

188196
-- Special handling for attached targets (MO grabbing)
@@ -237,16 +245,15 @@ function Update(self)
237245
self.setLineLength = self.currentLineLength
238246
end
239247

240-
-- Single length limit check - removed redundant checkLineLengthUpdate call
248+
-- Single length limit check - now handled during flight phase
241249
if self.currentLineLength > self.maxLineLength then
242250
self.currentLineLength = self.maxLineLength
243251
self.setLineLength = self.maxLineLength
244-
if not self.limitReached then
245-
self.limitReached = true
246-
self.clickSound:Play(self.parent.Pos)
247-
end
252+
-- limitReached is now set during flight phase
248253
else
249-
self.limitReached = false
254+
if self.actionMode > 1 then -- Only reset limit flag when attached, not during flight
255+
self.limitReached = false
256+
end
250257
end
251258

252259
if self.parentGun and self.parentGun.ID ~= rte.NoMOID then

Data/Base.rte/Devices/Tools/GrappleGun/Scripts/RopePhysics.lua

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,8 @@ function RopePhysics.applyRopeConstraints(grappleInstance, currentTotalCableLeng
307307
local constraintDirection = ropeVector:SetMagnitude(1)
308308

309309
-- Check if hook is anchored (attached to terrain or MO)
310-
if grappleInstance.actionMode >= 2 then
310+
-- if grappleInstance.actionMode >= 2 then -- Original condition
311+
if grappleInstance.actionMode == 2 then -- Changed: Actor anchored to claw only in mode 2
311312
-- Hook is anchored - apply PROPER SWINGING CONSTRAINT
312313
-- This allows free tangential movement (swinging) while constraining radial movement
313314

@@ -351,8 +352,25 @@ function RopePhysics.applyRopeConstraints(grappleInstance, currentTotalCableLeng
351352
grappleInstance.apx[0] = grappleInstance.parent.Pos.X
352353
grappleInstance.apy[0] = grappleInstance.parent.Pos.Y
353354
end
355+
elseif grappleInstance.actionMode == 1 then -- Added: Claw anchored to actor in mode 1
356+
-- Hook is in flight, anchor it to the player
357+
local correctionVector = constraintDirection * excessDistance
358+
-- Move the player instead of the hook
359+
grappleInstance.parent.Pos = grappleInstance.parent.Pos + correctionVector
360+
-- Update rope anchor to match corrected player position
361+
grappleInstance.apx[0] = grappleInstance.parent.Pos.X
362+
grappleInstance.apy[0] = grappleInstance.parent.Pos.Y
363+
364+
-- Clear any tension forces since rope is not under tension
365+
grappleInstance.ropeTensionForce = nil
366+
grappleInstance.ropeTensionDirection = nil
367+
368+
-- Recalculate after constraint
369+
playerPos = grappleInstance.parent.Pos -- update playerPos for subsequent calculations
370+
ropeVector = SceneMan:ShortestDistance(playerPos, hookPos, grappleInstance.mapWrapsX)
371+
totalRopeDistance = ropeVector.Magnitude
354372
else
355-
-- Hook is in flight - we can move it to maintain rope length
373+
-- Hook is in flight - we can move it to maintain rope length (default case)
356374
local correctionVector = constraintDirection * excessDistance
357375
grappleInstance.apx[segments] = grappleInstance.apx[segments] - correctionVector.X
358376
grappleInstance.apy[segments] = grappleInstance.apy[segments] - correctionVector.Y

Data/Base.rte/Devices/Tools/GrappleGun/Scripts/RopeStateManager.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ function RopeStateManager.checkAttachmentCollisions(grappleInstance)
6464
grappleInstance.Vel = Vector() -- Stop the hook
6565
grappleInstance.PinStrength = 1000
6666
grappleInstance.Frame = 1 -- Change appearance
67+
68+
-- Reset rope physics initialization when transitioning from flight to attached
69+
grappleInstance.ropePhysicsInitialized = false
70+
grappleInstance.limitReached = false -- Reset limit when attaching
6771
end
6872

6973
return stateChanged
@@ -72,6 +76,14 @@ end
7276
-- Handle exceeding maximum length - SIMPLIFIED VERSION
7377
-- Main length control is now centralized in Grapple.lua
7478
function RopeStateManager.checkLengthLimit(grappleInstance)
79+
-- During flight, the claw automatically stops at max rope length
80+
-- This function now mainly handles attached mode length limits
81+
if grappleInstance.actionMode == 1 then
82+
-- Flight mode - length limit is handled in main Grapple.lua Update function
83+
return grappleInstance.limitReached
84+
end
85+
86+
-- Attached mode - check if rope is at maximum length
7587
if grappleInstance.lineLength > grappleInstance.maxLineLength then
7688
if grappleInstance.limitReached == false then
7789
grappleInstance.limitReached = true

0 commit comments

Comments
 (0)