# Upgrade Guide

## General Instructions

Key notes on upgrading existing mod for the CET 1.14+:

* Don't use `Game` object and any game types before `onInit`.
* Don't use `GetMod()` before `onInit`.
* Don't pass excessive params to game functions. If the max number of params is 3, then passing 4 params will result in an error.
* Update `Observe()` / `Override()` handlers so they accept `self` as the first param. Previously, some observers lacked the `self` param:

```lua
Observe("PlayerPuppet", "OnAction", function(self, action)
    -- First param self is required now
end)
```

* If your mod stores player reference then unset it when game session ends.&#x20;
  * An unreleased reference can lead to bugs such as disappearing footsteps.
  * Accessing `Game.GetPlayer()` in `onUpdate` will not cause the issue.
  * This can be achieved using next snippet or with `GameSession` / `GameUI` libs:

```lua
Observe("QuestTrackerGameController", "OnUninitialize", function()
    if Game.GetPlayer() == nil then
        Mod.Player = nil -- var containing a reference to the player 
    end
end)
```

* Use corresponding getters for game systems instead of `GetSingleton()`. For example, `Game.GetTeleportationFacility()` instead of  `GetSingleton('gameTeleportationFacility')`.

## New Script API

New scripting capabilities were introduced in CET 1.14 to make it more convenient and simple:

* All game classes are directly accessible by name. For example, `entEntityId`, `PlayerPuppet`.
* All game enums are directly accessible by name. For example, `gamedataStatType.BaseDamage`, `gameGameVersion.Current`.
* Classes can also be accessed by their aliases from redscript. For example, `WeaponObject` instead of `gameweaponObject`.
* Classes have the conventional `.new()` constructor. For example, `MappinData.new()`.
* A constructor can take an array of properties to create and initialize an object in a single statement. For example, `EntityID.new({ hash = 12345 })`.
* Static methods are accessible from classes using the dot. For example, `ScriptedPuppet.IsDefeated(npc)`.
* A static method can be called from an instance if the first parameter is of the same type. For example, `vec4:Length()` instead of `Vector4.Length(vec4)`.
* The overloaded function is resolved based on passed parameters when called by its short name. For example, `StatusEffectHelper.HasStatusEffect(target, gamedataStatusEffectType.Overheat)`.
* Partial `Variant` type support. `ToVariant()` and `FromVariant()` are only applicable to classes.

### Backward Compatibility

All new scripting features are optional. You're not required to rewrite an existing mod using these features.

### Redscript Similarity

The new API allows code that is also valid redscript or very close to its redscript counterpart. Thus, it simplifies the research and the transition to / from the redscript.

For example, this line looks exactly the same in Lua and in the redscript:

```lua
RPGManager.CreateStatModifier(gamedataStatType.BaseDamage, gameStatModifierType.Additive, 50)
```

### Examples

**Constructing objects**

Old API:

```lua
local mappinData = NewObject("gamemappinsMappinData")
mappinData.mappinType = TweakDBID.new("Mappins.DefaultStaticMappin")
mappinData.variant = Enum.new("gamedataMappinVariant", "FastTravelVariant")
mappinData.visibleThroughWalls = true
```

New API:

```lua
local mappinData = MappinData.new()
mappinData.mappinType = "Mappins.DefaultStaticMappin"
mappinData.variant = gamedataMappinVariant.FastTravelVariant
mappinData.visibleThroughWalls = true
```

**Constructor with initialization**

Old API:

```lua
function getStash()
    local stashId = NewObject("entEntityID")
    stashId.hash = 16570246047455160070ULL

    return Game.FindEntityByID(stashId)
end
```

New API:

```lua
function getStash()
    return Game.FindEntityByID(EntityID.new({ hash = 16570246047455160070ULL }))
end
```

**Scripted static call**

Old API:

```lua
Game["PreventionSystem::ShowMessage;GameInstanceStringFloat"]("Message", 5.0)
```

New API:

```lua
PreventionSystem.ShowMessage("Message", 5.0)
```

**Shorthand static call**

Old API:

```lua
Observe("PlayerPuppet", "OnAction", function(action)
    -- Option 1 --
    print(GetSingleton("gameinputScriptListenerAction"):GetName(action))
    -- Option 2 --
    print(action:GetName(action))   
end)
```

New API:

```lua
Observe("PlayerPuppet", "OnAction", function(action)
    -- Option 1 --
    print(ListenerAction.GetName(action))
    -- Option 2 --
    print(action:GetName())   
end)
```

**Working with enums**

Old API:

```lua
print(Enum.new('gameGameVersion', 'Current') == Enum.new('gameGameVersion', 'CP77_GoldMaster'))
print(Enum.new('gameGameVersion', 'Current') == Enum.new('gameGameVersion', 'CP77_Patch_1_2_Hotfix2'))
```

New API:

```lua
print(gameGameVersion.Current == gameGameVersion.CP77_GoldMaster)
print(gameGameVersion.Current == gameGameVersion.CP77_Patch_1_2_Hotfix2)
```

**Variants**

```lua
local message = SimpleScreenMessage.new()
message.message = "Test"
message.isShown = true

local blackboardDefs = Game.GetAllBlackboardDefs()
local blackboardUI = Game.GetBlackboardSystem():Get(blackboardDefs.UI_Notifications)
blackboardUI:SetVariant(
    blackboardDefs.UI_Notifications.OnscreenMessage, 
    ToVariant(message), 
    true
)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.redmodding.org/cyber-engine-tweaks/upgrade-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
