Skip to content

Commit

Permalink
Info text window
Browse files Browse the repository at this point in the history
- Added a new info text window.
- With mouse click on the message, the vehicle will be entered.
- While the message is hovered, the vehicle name is displayed.
- Info text are finished/empty/full.
- When the driver is released with a message, then the message is
  displayed until the vehicle is entered by a player.
  • Loading branch information
schwiti6190 committed Mar 10, 2022
1 parent 7be0f28 commit 41a166f
Show file tree
Hide file tree
Showing 38 changed files with 942 additions and 69 deletions.
72 changes: 70 additions & 2 deletions Courseplay.lua
Expand Up @@ -22,6 +22,7 @@ function Courseplay:registerXmlSchema()
self.xmlSchema:register(XMLValueType.STRING, self.baseXmlKey.."#lastVersion")
self.globalSettings:registerXmlSchema(self.xmlSchema, self.xmlKey)
CpBaseHud.registerXmlSchema(self.xmlSchema, self.xmlKey)
CpHudInfoTexts.registerXmlSchema(self.xmlSchema, self.xmlKey)
end

--- Loads data not tied to a savegame.
Expand All @@ -31,6 +32,7 @@ function Courseplay:loadUserSettings()
self:showUserInformation(xmlFile, self.baseXmlKey)
self.globalSettings:loadFromXMLFile(xmlFile, self.xmlKey)
CpBaseHud.loadFromXmlFile(xmlFile, self.xmlKey)
CpHudInfoTexts.loadFromXmlFile(xmlFile, self.xmlKey)
xmlFile:save()
xmlFile:delete()
end
Expand All @@ -42,6 +44,7 @@ function Courseplay:saveUserSettings()
if xmlFile then
self.globalSettings:saveUserSettingsToXmlFile(xmlFile, self.xmlKey)
CpBaseHud.saveToXmlFile(xmlFile, self.xmlKey)
CpHudInfoTexts.saveToXmlFile(xmlFile, self.xmlKey)
if self.currentVersion then
xmlFile:setValue(self.baseXmlKey.."#lastVersion", self.currentVersion)
end
Expand Down Expand Up @@ -127,6 +130,8 @@ function Courseplay:setupGui()
CpGuiUtil.fixInGameMenuPage(courseManagerFrame, "pageCpCourseManager",
{256, 0, 128, 128}, 5, predicateFunc)
CpGuiUtil.fixInGameMenu()
self.infoTextsHud = CpHudInfoTexts()

end

--- Adds cp help info to the in game help menu.
Expand Down Expand Up @@ -159,6 +164,9 @@ end
function Courseplay:draw()
g_devHelper:draw()
CpDebug:draw()
if not g_gui:getIsGuiVisible() then
self.infoTextsHud:draw()
end
end

---@param posX number
Expand All @@ -173,6 +181,7 @@ function Courseplay:mouseEvent(posX, posY, isDown, isUp, button)
if hud then
hud:mouseEvent(posX, posY, isDown, isUp, button)
end
self.infoTextsHud:mouseEvent(posX, posY, isDown, isUp, button)
end
end

Expand Down Expand Up @@ -212,6 +221,64 @@ function Courseplay:load()
g_currentMission.aiMessageManager:registerMessage("ERROR_FULL", AIMessageErrorIsFull)
end

------------------------------------------------------------------------------------------------------------------------
-- Player action events
------------------------------------------------------------------------------------------------------------------------

--- Adds player mouse action event, for global info texts.
function Courseplay.addPlayerActionEvents(mission)
if mission.player then
print("Added player input events")
mission.player.inputInformation.registrationList[InputAction.CP_TOGGLE_MOUSE] = {
text = "",
triggerAlways = false,
triggerDown = false,
eventId = "",
textVisibility = true,
triggerUp = true,
callback = Courseplay.onOpenCloseMouseEvent,
activeType = Player.INPUT_ACTIVE_TYPE.STARTS_DISABLED
}
mission.player.updateActionEvents = Utils.appendedFunction(mission.player.updateActionEvents, Courseplay.updatePlayerActionEvents)
mission.player.removeActionEvents = Utils.prependedFunction(mission.player.removeActionEvents, Courseplay.removePlayerActionEvents)
end
end
FSBaseMission.onStartMission = Utils.appendedFunction(FSBaseMission.onStartMission , Courseplay.addPlayerActionEvents)

--- Open/close mouse in player state.
function Courseplay.onOpenCloseMouseEvent(player)
local showMouseCursor = not g_inputBinding:getShowMouseCursor()
g_inputBinding:setShowMouseCursor(showMouseCursor)
local leftRightRotationEventId = player.inputInformation.registrationList[InputAction.AXIS_LOOK_LEFTRIGHT_PLAYER].eventId
local upDownRotationEventId = player.inputInformation.registrationList[InputAction.AXIS_LOOK_UPDOWN_PLAYER].eventId
g_inputBinding:setActionEventActive(leftRightRotationEventId, not showMouseCursor)
g_inputBinding:setActionEventActive(upDownRotationEventId, not showMouseCursor)
player.wasCpMouseActive = not showMouseCursor
end

--- Enables/disables the player mouse action event, if there are any info texts.
function Courseplay.updatePlayerActionEvents(player)
local eventId = player.inputInformation.registrationList[InputAction.CP_TOGGLE_MOUSE].eventId
g_inputBinding:setActionEventActive(eventId, false)
if not player:hasHandtoolEquipped() then
if g_Courseplay.infoTextsHud:isVisible() then
g_inputBinding:setActionEventActive(eventId, true)
elseif player.wasCpMouseActive then
Courseplay.onOpenCloseMouseEvent(player)
end
end
end

--- Resets the mouse cursor on entering a vehicle for example.
function Courseplay.removePlayerActionEvents(player)
g_inputBinding:setShowMouseCursor(false)
player.wasCpMouseActive = nil
end

------------------------------------------------------------------------------------------------------------------------
-- Commands
------------------------------------------------------------------------------------------------------------------------

function Courseplay:registerConsoleCommands()
addConsoleCommand( 'cpAddMoney', 'adds money', 'addMoney', self)
addConsoleCommand( 'cpRestartSaveGame', 'Load and start a savegame', 'restartSaveGame', self)
Expand Down Expand Up @@ -379,9 +446,10 @@ function Courseplay.register(typeManager)
CpAIWorker.register(typeManager, typeName, typeEntry.specializations)
CpAIFieldWorker.register(typeManager, typeName, typeEntry.specializations)
CpAIBaleFinder.register(typeManager, typeName, typeEntry.specializations)
CpVehicleSettingDisplay.register(typeManager, typeName, typeEntry.specializations)
CpVehicleSettingDisplay.register(typeManager, typeName,typeEntry.specializations)
CpHud.register(typeManager, typeName, typeEntry.specializations)
end
CpInfoTexts.register(typeManager, typeName, typeEntry.specializations)
end
end
TypeManager.finalizeTypes = Utils.prependedFunction(TypeManager.finalizeTypes, Courseplay.register)

Expand Down
2 changes: 1 addition & 1 deletion config/DebugChannels.xml
Expand Up @@ -24,7 +24,7 @@
<DebugChannel active="false" name="DBG_LOAD_UNLOAD" text="load and unload tippers"/>
<DebugChannel active="true" name="DBG_TRAFFIC" text="traffic collision/proximity"/>
<DebugChannel active="true" name="DBG_COURSES" text="course save/load/generation"/>
<DebugChannel active="false" name="DBG_HUD" text="hud action"/>
<DebugChannel active="true" name="DBG_HUD" text="hud action"/>
<DebugChannel active="true" name="DBG_MULTIPLAYER" text="multiplayer"/>
<DebugChannel active="true" name="DBG_IMPLEMENTS" text="implements"/>
<DebugChannel active="false" name="DBG_UNCATEGORIZED" text="other"/>
Expand Down
2 changes: 1 addition & 1 deletion config/GlobalSettingsSetup.xml
Expand Up @@ -30,12 +30,12 @@
<Text>always</Text>
</Texts>
</Setting>

</SettingSubTitle>
<SettingSubTitle prefix="true" title="userSettings">
<Setting classType="AIParameterBooleanSetting" name="controllerHudSelected" defaultBool="false" onChangeCallback="onHudSelectionChanged" isUserSetting="true"/>
<Setting classType="AIParameterBooleanSetting" name="showsAllActiveCourses" isUserSetting="true"/>
<Setting classType="AIParameterBooleanSetting" name="showActionEventHelp" isUserSetting="true" defaultBool="true" onChangeCallback="onActionEventTextVisibilityChanged"/>
<Setting classType="AIParameterBooleanSetting" name="infoTextHudActive" isUserSetting="true" defaultBool="true"/>
</SettingSubTitle>
<SettingSubTitle prefix="true" title="pathfinder">
<Setting classType="AIParameterSettingList" name="maxDeltaAngleAtGoal" min="5" max="90" incremental="5" default="45"/>
Expand Down
19 changes: 19 additions & 0 deletions config/InfoTexts.xml
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
All info texts need to be placed here.
name: The name for the info text to call it in the lua scripts.
text: The button text shown.
The priority is from top to bottom, which makes the first the highest priority in the hud.
-->

<InfoTexts prefix="CP_infoTexts_">
<InfoText name="IS_STUCK" text="isStuck"/>
<InfoText name="TRAFFIC" text="isInTraffic"/>
<InfoText name="SLOWING_DOWN_FOR_TRAFFIC" text="slowingDownForTraffic"/>

<InfoText name="NEEDS_FILLING" text="needsFilling"/>
<InfoText name="NEEDS_UNLOADING" text="needsUnloading"/>
<InfoText name="WORK_FINISHED" text="workFinished"/>
</InfoTexts>
3 changes: 3 additions & 0 deletions modDesc.xml
Expand Up @@ -114,6 +114,7 @@ Funktionen:
<sourceFile filename="scripts/ai/controllers/StonePickerController.lua"/>
<sourceFile filename="scripts/ai/BaleToCollect.lua"/>
<sourceFile filename="scripts/ai/FillLevelManager.lua"/>
<sourceFile filename="scripts/ai/InfoTextsManager.lua"/>
<sourceFile filename="scripts/ai/PurePursuitController.lua"/>
<sourceFile filename="scripts/ai/VehicleScanner.lua"/>
<sourceFile filename="scripts/ai/WorkWidthUtil.lua"/>
Expand Down Expand Up @@ -147,6 +148,7 @@ Funktionen:
<sourceFile filename="scripts/events/CpJoinEvent.lua"/>
<sourceFile filename="scripts/events/GlobalSettingsEvent.lua"/>
<sourceFile filename="scripts/events/VehicleSettingsEvent.lua"/>
<sourceFile filename="scripts/gui/hud/CpHudInfoTexts.lua"/>
</extraSourceFiles>

<specializations>
Expand All @@ -159,6 +161,7 @@ Funktionen:
<specialization name="cpAIBaleFinder" className="CpAIBaleFinder" filename="scripts/specializations/CpAIBaleFinder.lua"/>
<specialization name="cpVehicleSettingDisplay" className="CpVehicleSettingDisplay" filename="scripts/specializations/CpVehicleSettingDisplay.lua"/>
<specialization name="cpHud" className="CpHud" filename="scripts/specializations/CpHud.lua"/>
<specialization name="cpInfoTexts" className="CpInfoTexts" filename="scripts/specializations/CpInfoTexts.lua"/>
</specializations>

<inputBinding>
Expand Down
31 changes: 21 additions & 10 deletions scripts/ai/AIDriveStrategyCombineCourse.lua
Expand Up @@ -89,6 +89,15 @@ function AIDriveStrategyCombineCourse.new(customMt)
self.chopperCanDischarge = CpTemporaryObject(false)
-- hold the harvester temporarily
self.temporaryHold = CpTemporaryObject(false)

--- Register info texts
self:registerInfoTextForStates(self:getFillLevelInfoText(), {
self.states.WAITING_FOR_UNLOAD_ON_FIELD,
self.states.WAITING_FOR_UNLOAD_AFTER_FIELDWORK_ENDED,
self.states.WAITING_FOR_UNLOAD_AFTER_PULLED_BACK,
self.states.WAITING_FOR_UNLOAD_IN_POCKET
})

return self
end

Expand Down Expand Up @@ -244,7 +253,6 @@ function AIDriveStrategyCombineCourse:driveUnloadOnField()
-- reset offset to return to the original up/down row after we unloaded in the pocket
self.aiOffsetX = 0

self:clearInfoText(self:getFillLevelInfoText())
-- wait a bit after the unload finished to give a chance to the unloader to move away
self.stateBeforeWaitingForUnloaderToLeave = self.unloadState
self.unloadState = self.states.WAITING_FOR_UNLOADER_TO_LEAVE
Expand All @@ -257,7 +265,6 @@ function AIDriveStrategyCombineCourse:driveUnloadOnField()
if g_updateLoopIndex % 5 == 0 then --small delay, to make sure no more fillLevel change is happening
if not self:isFull() and not self:shouldStopForUnloading() then
self:debug('not full anymore, can continue working')
-- TODO_22 self:clearInfoText(self:getFillLevelInfoText())
self:changeToFieldWork()
end
end
Expand All @@ -281,7 +288,6 @@ function AIDriveStrategyCombineCourse:driveUnloadOnField()
--- Makes sure the cotton harvester gets release at the end of the course.
--- TODO: Unload the unfinished bale from the cotton harvester.
if fillLevel < 0.01 or self:isCottonHarvester() then
self:clearInfoText(self:getFillLevelInfoText())
self:debug('Unloading finished after fieldwork ended, end course')
AIDriveStrategyCombineCourse.superClass().finishFieldWork(self)
else
Expand Down Expand Up @@ -400,7 +406,6 @@ function AIDriveStrategyCombineCourse:onWaypointPassed(ix, course)
self.unloadInPocketIx and ix == self.unloadInPocketIx then
-- we are making a pocket and reached the waypoint where we are going to stop and wait for unload
self:debug('Waiting for unload in the pocket')
self:setInfoText(self:getFillLevelInfoText())
self.unloadState = self.states.WAITING_FOR_UNLOAD_IN_POCKET
end

Expand Down Expand Up @@ -437,7 +442,6 @@ function AIDriveStrategyCombineCourse:onLastWaypointPassed()
-- pulled back, now wait for unload
self.unloadState = self.states.WAITING_FOR_UNLOAD_AFTER_PULLED_BACK
self:debug('Pulled back, now wait for unload')
self:setInfoText(self:getFillLevelInfoText())
elseif self.unloadState == self.states.DRIVING_TO_SELF_UNLOAD then
self:debug('Self unloading point reached, fill level %.1f, waiting for unload to start to start.', fillLevel)
self.unloadState = self.states.SELF_UNLOADING_WAITING_FOR_DISCHARGE
Expand All @@ -456,7 +460,6 @@ function AIDriveStrategyCombineCourse:onLastWaypointPassed()
self.ppc:setShortLookaheadDistance()
self:disableCollisionDetection()
else
self:setInfoText(self:getFillLevelInfoText())
-- let AutoDrive know we are done and can unload
self:debug('Fieldwork done, fill level is %.1f, now waiting to be unloaded.', fillLevel)
self.state = self.states.UNLOADING_ON_FIELD
Expand Down Expand Up @@ -1954,7 +1957,15 @@ function AIDriveStrategyCombineCourse:getWorkingToolPositionsSetting()
return setting:getHasMoveablePipe() and setting:hasValidToolPositions() and setting
end

-- TODO_22
function AIDriveStrategyCombineCourse:setInfoText(text)
self:debug(text)
end
------------------------------------------------------------------------------------------------------------------------
--- Info texts, makes sure the unloadState also gets checked.
---------------------------------------------------------------------------------------------------------------------------
function AIDriveStrategyCombineCourse:updateInfoTexts()
for infoText, states in pairs(self.registeredInfoTexts) do
if states[self.state] or states[self.unloadState] then
self.vehicle:setCpInfoTextActive(infoText)
else
self.vehicle:resetCpActiveInfoText(infoText)
end
end
end
43 changes: 31 additions & 12 deletions scripts/ai/AIDriveStrategyCourse.lua
Expand Up @@ -32,7 +32,6 @@ AIDriveStrategyCourse.myStates = {
--- Implement controller events.
AIDriveStrategyCourse.onRaisingEvent = "onRaising"
AIDriveStrategyCourse.onLoweringEvent = "onLowering"
AIDriveStrategyCourse.onFinishedEvent = "onFinished"
AIDriveStrategyCourse.updateEvent = "update"

function AIDriveStrategyCourse.new(customMt)
Expand All @@ -44,6 +43,7 @@ function AIDriveStrategyCourse.new(customMt)
self:initStates(AIDriveStrategyCourse.myStates)
---@type ImplementController[]
self.controllers = {}
self.registeredInfoTexts = {}
return self
end

Expand Down Expand Up @@ -81,9 +81,9 @@ function AIDriveStrategyCourse:error(...)
CpUtil.infoVehicle(self.vehicle, self:getStateAsString() .. ': ' .. string.format(...))
end

-- TODO_22
function AIDriveStrategyCourse:setInfoText(text)
self:debug(text)
self:debug("set info text: %s",tostring(text))
self.vehicle:setCpInfoTextActive(text)
end

function AIDriveStrategyCourse:setAIVehicle(vehicle, jobParameters)
Expand Down Expand Up @@ -279,6 +279,7 @@ end
function AIDriveStrategyCourse:update()
self.ppc:update()
self:updatePathfinding()
self:updateInfoTexts()
end

function AIDriveStrategyCourse:getDriveData(dt, vX, vY, vZ)
Expand Down Expand Up @@ -346,16 +347,13 @@ end

--- @param msgReference string as defined in globalInfoText.msgReference
function AIDriveStrategyCourse:clearInfoText(msgReference)
-- TODO_22
if msgReference then
self:debug('clearInfoText: %s', msgReference)
self.vehicle:resetCpActiveInfoText(msgReference)
end
end

function AIDriveStrategyCourse:getFillLevelInfoText()
-- TODO_22
self:debug('getFillLevelInfoText')
return 'getFillLevelInfoText'
return InfoTextManager.NEEDS_UNLOADING
end

-----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -443,8 +441,29 @@ function AIDriveStrategyCourse:isCloseToCourseStart(distance)
return self.course:getDistanceFromFirstWaypoint(self.ppc:getCurrentWaypointIx()) < distance
end

--- Event raised when the drive is finished.
--- This gets called in the :stopCurrentAIJob(), as the giants code might stop the driver and not the active strategy.
function AIDriveStrategyCourse:onFinished()
self:raiseControllerEvent(self.onFinishedEvent)
------------------------------------------------------------------------------------------------------------------------
--- Info texts
---------------------------------------------------------------------------------------------------------------------------

--- Registers info texts for specific states.
---@param infoText CpInfoTextElement
---@param states table
function AIDriveStrategyCourse:registerInfoTextForStates(infoText, states)
if self.registeredInfoTexts[infoText] == nil then
self.registeredInfoTexts[infoText] = {}
end
for i, state in pairs(states) do
self.registeredInfoTexts[infoText][state] = true
end
end

--- Enables/disables based on the state.
function AIDriveStrategyCourse:updateInfoTexts()
for infoText, states in pairs(self.registeredInfoTexts) do
if states[self.state] then
self:setInfoText(infoText)
else
self:clearInfoText(infoText)
end
end
end
1 change: 1 addition & 0 deletions scripts/ai/AIDriveStrategyFieldWorkCourse.lua
Expand Up @@ -191,6 +191,7 @@ function AIDriveStrategyFieldWorkCourse:getDriveData(dt, vX, vY, vZ)
self:limitSpeed()
-- keep away from others working on the same course
self:setMaxSpeed(self.fieldWorkerProximityController:getMaxSpeed(self.settings.convoyDistance:getValue(), self.maxSpeed))

return gx, gz, moveForwards, self.maxSpeed, 100
end

Expand Down

0 comments on commit 41a166f

Please sign in to comment.