Type-strict a bunch of arousal things

This commit is contained in:
Jean-Baptiste Emmanuel Zorg 2025-03-29 11:59:52 +01:00
parent 1a31f76f46
commit c024cd9317
9 changed files with 48 additions and 50 deletions
BondageClub
Screens
Character/Preference
Inventory/ItemNipples/LactationPump
Online/ChatRoom
Room/PrivateBed
Scripts

View file

@ -175,7 +175,7 @@ let PreferenceDidAddOldStyleScreens = false;
* @returns {void} - Nothing
*/
function PreferenceLoad() {
PreferenceSubscreen = PreferenceSubscreens.find(s => s.name === "Main");
PreferenceSubscreen = PreferenceSubscreens.find(s => s.name === "Main") ?? null;
// Backward-compatibility: just throw the old-style screens into the mix
if (!PreferenceDidAddOldStyleScreens) {

View file

@ -29,7 +29,7 @@ function AssetsItemNipplesLactationPumpScriptDraw(data) {
const persist = data.PersistentData();
// We do nothing if suction is disabled or if we're rendering someone else
if (!Item.Property.SuctionLevel || !C.IsPlayer()) return;
if (!Item.Property.SuctionLevel || !C.IsPlayer() || !Item.Asset.Group.IsItem()) return;
if (persist.LastSuction === undefined) {
persist.LastSuction = CurrentTime;

View file

@ -1752,7 +1752,7 @@ function ChatRoomStimulationMessage(Action) {
// Increase player arousal to the zone
if (!Player.IsEdged() && arousal < 70 - event.arousal && event.event != "Talk")
ActivityEffectFlat(Player, Player, event.arousal, group.Name, 1);
ActivityEffectFlat(Player, Player, event.arousal, /** @type {AssetGroupItemName} */ (group.Name), 1);
const duration = (Math.random() + event.arousal / 2.4) * 500;
DrawFlashScreen("#FFB0B0", duration, 140);
if (Player.ArousalSettings?.AffectExpression) {

View file

@ -195,7 +195,7 @@ function PrivateBedRun() {
* Starts an arousal action on a character.
* @param {Character} Source - The source character.
* @param {Character} Target - The target character.
* @param {AssetGroup} Group - The zone / group to target.
* @param {AssetItemGroup} Group - The zone / group to target.
* @param {ActivityName} Activity - The activity to do.
* @returns {boolean} - TRUE if the activity could start.
*/
@ -305,6 +305,7 @@ function PrivateBedNPCActivity(Source) {
let ActivityPenis = AssetGetActivity(Target.AssetFamily, Activity.Name + "Penis");
// Selects a random location on the body from available locations
/** @type {AssetGroup[]} */
let GroupList = [];
for (let G of AssetGroup) {
if (PrivateBedGroupActivityIsValid(Source, Target, G, Activity))
@ -316,6 +317,7 @@ function PrivateBedNPCActivity(Source) {
}
if (GroupList.length == 0) return;
let Group = CommonRandomItemFromList(null, GroupList);
if (!Group.IsItem()) return;
// Launches the activity
if (!PrivateBedActivityStart(Source, Target, Group, Activity.Name)) {

View file

@ -82,13 +82,13 @@ function ActivityDictionaryText(KeyWord) {
/**
* Resolve a group name to the correct group for activities
* @param {IAssetFamily} family - The asset family for the named group
* @param {AssetGroupName} groupname - The name of the group to resolve
* @returns {AssetGroup | null} - The resolved group
* @param {AssetGroupItemName} groupname - The name of the group to resolve
* @returns {AssetItemGroup | null} - The resolved group
*/
function ActivityGetGroupOrMirror(family, groupname) {
const group = AssetGroupGet(family, groupname);
const group = /** @type {AssetItemGroup} */ (AssetGroupGet(family, groupname));
if (group && group.MirrorActivitiesFrom != null) {
const mirror = AssetGroupGet(family, group.MirrorActivitiesFrom);
const mirror = /** @type {AssetItemGroup} */ (AssetGroupGet(family, group.MirrorActivitiesFrom));
if (mirror) {
return mirror;
}
@ -110,7 +110,7 @@ function ActivityGetAllMirrorGroups(family, groupName) {
/**
* Check if any activities are possible for a character's given group.
* @param {Character} C - The character on which the check is done
* @param {AssetGroupName} GroupName - The group to check access on
* @param {AssetGroupItemName} GroupName - The group to check access on
* @returns {boolean} Whether any activity is possible
*/
function ActivityPossibleOnGroup(C, GroupName) {
@ -301,7 +301,7 @@ function ActivityGenerateItemActivitiesFromNeed(allowed, acting, acted, needsIte
/**
* Builds the allowed activities on a group given the character's settings.
* @param {Character} character - The character for which to build the activity dialog options
* @param {AssetGroupName} groupname - The group to check
* @param {AssetGroupItemName} groupname - The group to check
* @return {ItemActivity[]} - The list of allowed activities
*/
function ActivityAllowedForGroup(character, groupname) {
@ -367,7 +367,7 @@ function ActivityAllowedForGroup(character, groupname) {
* Returns TRUE if an activity can be done
* @param {Character} C - The character to evaluate
* @param {ActivityName} Activity - The name of the activity
* @param {AssetGroupName} Group - The name of the group
* @param {AssetGroupItemName} Group - The name of the group
* @return {boolean} - TRUE if the activity can be done
*/
function ActivityCanBeDone(C, Activity, Group) {
@ -383,7 +383,7 @@ function ActivityCanBeDone(C, Activity, Group) {
* @param {Character} S - The character performing the activity
* @param {Character} C - The character on which the activity is performed
* @param {ActivityName | Activity} A - The activity performed
* @param {AssetGroupName} Z - The group/zone name where the activity was performed
* @param {AssetGroupItemName} Z - The group/zone name where the activity was performed
* @param {number} [Count=1] - If the activity is done repeatedly, this defines the number of times, the activity is done.
* If you don't want an activity to modify arousal, set this parameter to '0'
* @param {Asset} [Asset] - The asset used to perform the activity
@ -418,7 +418,7 @@ function ActivityEffect(S, C, A, Z, Count, Asset) {
* @param {Character} S - The character performing the activity
* @param {Character} C - The character on which the activity is performed
* @param {number} Amount - The base amount of arousal to add
* @param {AssetGroupName} Z - The group/zone name where the activity was performed
* @param {AssetGroupItemName} Z - The group/zone name where the activity was performed
* @param {number} [Count=1] - If the activity is done repeatedly, this defines the number of times, the activity is done.
* If you don't want an activity to modify arousal, set this parameter to '0'
* @param {Asset} [Asset] - The asset used to perform the activity
@ -471,7 +471,7 @@ function ActivitySetArousal(C, Progress) {
* Sets an activity progress on a timer, activities are capped at MaxProgress
* @param {Character} C - The character for which to set the timer for
* @param {null | Activity} Activity - The activity for which the timer is for
* @param {AssetGroupName | "ActivityOnOther"} Zone - The target zone of the activity
* @param {AssetGroupItemName | "ActivityOnOther"} Zone - The target zone of the activity
* @param {number} Progress - Progress to set
* @param {Asset} [Asset] - The asset used to perform the activity
* @return {void} - Nothing
@ -859,7 +859,7 @@ function ActivityBuildChatTag(character, group, activity, is_label = false) {
* Launches a sexual activity for a character and sends the chatroom message if applicable.
* @param {Character} actor - Character which is performing the activity
* @param {Character} acted - Character on which the activity was triggered
* @param {AssetGroup} targetGroup - The group targetted by the activity
* @param {AssetItemGroup} targetGroup - The group targetted by the activity
* @param {ItemActivity} ItemActivity - The activity performed, with its optional item used
* @param {boolean} sendMessage - Whether to send a message to the chat or not
*/
@ -921,7 +921,7 @@ function ActivityArousalItem(Source, Target, Asset) {
var Activity = AssetGetActivity(Target.AssetFamily, AssetActivity);
if (Source.IsPlayer() && !Target.IsPlayer()) ActivityRunSelf(Source, Target, Activity, Asset.Group);
if (PreferenceArousalAtLeast(Target, "Hybrid") && (Target.IsPlayer() || Target.IsNpc()))
ActivityEffect(Source, Target, AssetActivity, Asset.Group.Name);
ActivityEffect(Source, Target, AssetActivity, /** @type {AssetGroupItemName} */ (Asset.Group.Name));
}
}

View file

@ -1962,12 +1962,14 @@ function CharacterIsEdged(C) {
// Get all zones that allow an orgasm
/** @type {AssetGroupItemName[]} */
let OrgasmZones = [];
for (let Group of AssetGroup)
for (let Group of AssetGroup) {
if (!Group.IsItem()) continue;
if (Group.ArousalZoneID != null) {
let Zone = PreferenceGetArousalZone(C, Group.Name);
if (Zone.Orgasm && (Zone.Factor > 0))
OrgasmZones.push(Zone.Name);
}
}
// Get every vibrating item acting on an orgasm zone
const VibratingItems = C.Appearance

View file

@ -192,7 +192,7 @@ function NPCArousal(C) {
// Go through all zones
for (let Group of AssetGroup)
if (Group.ArousalZoneID != null) {
if (Group.IsItem() && Group.ArousalZoneID != null) {
// Gets the current factors for that charact
let Zone = PreferenceGetArousalZone(C, Group.Name);

View file

@ -584,7 +584,7 @@ function PortalLinkProcessMessage(sender, data) {
return;
}
const group = AssetGroupGet("Female3DCG", /** @type {AssetGroupName} */ (attrTarget.substring("PortalLinkTarget".length)));
if (!group) return;
if (!group || !group.IsItem()) return;
ActivityRun(sender, Player, group, { Activity: act, Item: tablet, Group: tablet.Asset.Group.Name }, false);
builder.focusGroup(group.Name);

View file

@ -72,8 +72,8 @@ function PreferenceSetActivityFactor(C, Type, Self, Factor) {
// Make sure the Activity data is valid
if ((typeof Factor !== "number") || (Factor < 0) || (Factor > 4)) return;
if ((C == null) || (C.ArousalSettings == null)) return;
if ((C.ArousalSettings.Activity == null) || (typeof C.ArousalSettings.Activity !== "string")) C.ArousalSettings.Activity = PreferenceArousalActivityDefaultCompressedString;
if (!CommonIsObject(C.ArousalSettings)) return;
if (!C.ArousalSettings || typeof C.ArousalSettings?.Activity !== "string") C.ArousalSettings.Activity = PreferenceArousalActivityDefaultCompressedString;
while ((C.ArousalSettings.Activity.length < PreferenceArousalActivityDefaultCompressedString.length))
C.ArousalSettings.Activity = C.ArousalSettings.Activity + PreferenceArousalTwoFactorToChar();
@ -106,7 +106,7 @@ function PreferenceSetActivityFactor(C, Type, Self, Factor) {
function PreferenceGetFetishFactor(C, Type) {
// No valid data means no fetish
if ((C == null) || (C.ArousalSettings == null) || (C.ArousalSettings.Fetish == null) || (typeof C.ArousalSettings.Fetish !== "string")) return 2;
if (typeof C.ArousalSettings?.Fetish !== "string") return 2;
// Finds the ID of the fetish specified
let ID = -1;
@ -128,7 +128,7 @@ function PreferenceGetFetishFactor(C, Type) {
* Sets the arousal factor of a fetish for a character
* @param {Character} C - The character to set
* @param {FetishName} Type - The name of the fetish
* @param {ArousalFactor} Type - New arousal factor for that fetish (0 is horrible, 2 is normal, 4 is great)
* @param {ArousalFactor} Factor - New arousal factor for that fetish (0 is horrible, 2 is normal, 4 is great)
* @returns {void} - Nothing
*/
function PreferenceSetFetishFactor(C, Type, Factor) {
@ -181,24 +181,22 @@ function PreferenceArousalTwoFactorToChar(Factor1 = 2, Factor2 = 2) {
* Gets the corresponding arousal zone definition from a player's preferences (if the group's activities are mirrored,
* returns the arousal zone definition for the mirrored group).
* @param {Character} C - The character for whom to get the arousal zone
* @param {AssetGroupName} ZoneName - The name of the zone to get
* @param {AssetGroupItemName} ZoneName - The name of the zone to get
* @returns {null | ArousalZone} - Returns the arousal zone preference object,
* or null if a corresponding zone definition could not be found.
*/
function PreferenceGetArousalZone(C, ZoneName) {
// Make sure the data is valid
if ((C == null) || (C.ArousalSettings == null) || (C.ArousalSettings.Zone == null) || (typeof C.ArousalSettings.Zone !== "string")) return null;
if (typeof C.ArousalSettings?.Zone !== "string") return null;
// Finds the asset group and make sure the string contains it
let Group = AssetGroupGet(C.AssetFamily, ZoneName);
if ((Group.ArousalZoneID == null) || (C.ArousalSettings.Zone.length <= Group.ArousalZoneID)) return null;
if (!Group?.ArousalZoneID || (C.ArousalSettings.Zone.length <= Group.ArousalZoneID)) return null;
let Value = C.ArousalSettings.Zone.charCodeAt(Group.ArousalZoneID) - 100;
return {
// @ts-ignore
Name: ZoneName,
// @ts-ignore
Factor: Value % 10,
Orgasm: (Value >= 10)
};
@ -208,7 +206,7 @@ function PreferenceGetArousalZone(C, ZoneName) {
/**
* Gets the love factor of a zone for the character
* @param {Character} C - The character for whom the love factor of a particular zone should be gotten
* @param {AssetGroupName} ZoneName - The name of the zone to get the love factor for
* @param {AssetGroupItemName} ZoneName - The name of the zone to get the love factor for
* @returns {ArousalFactor} - Returns the love factor of a zone for the character (0 is horrible, 2 is normal, 4 is great)
*/
function PreferenceGetZoneFactor(C, ZoneName) {
@ -223,29 +221,27 @@ function PreferenceGetZoneFactor(C, ZoneName) {
/**
* Sets the love factor for a specific body zone on the player
* @param {Character} C - The character, for whom the love factor of a particular zone should be set
* @param {AssetGroupName} ZoneName - The name of the zone, the factor should be set for
* @param {AssetGroupItemName} ZoneName - The name of the zone, the factor should be set for
* @param {ArousalFactor} Factor - The factor of the zone (0 is horrible, 2 is normal, 4 is great)
* @returns {void} - Nothing
*/
function PreferenceSetZoneFactor(C, ZoneName, Factor) {
// Nothing to do if data is invalid
if ((C == null) || (C.ArousalSettings == null) || (C.ArousalSettings.Zone == null) || (typeof C.ArousalSettings.Zone !== "string")) return;
if (typeof C.ArousalSettings?.Zone !== "string") return;
// Finds the asset group and make sure the string contains it
let Group = AssetGroupGet(C.AssetFamily, ZoneName);
if (!Group) return;
if ((Group.ArousalZoneID == null) || (C.ArousalSettings.Zone.length <= Group.ArousalZoneID)) return;
// Gets the zone object
let Zone = PreferenceGetArousalZone(C, ZoneName);
if (Zone == null) {
Zone = {
// @ts-ignore
Name: ZoneName,
Factor: 2,
Orgasm: false
};
}
let Zone = PreferenceGetArousalZone(C, ZoneName) ?? {
Name: ZoneName,
Factor: 2,
Orgasm: false
};
Zone.Factor = Factor;
// Creates the new char and slides it in the compressed string
@ -256,7 +252,7 @@ function PreferenceSetZoneFactor(C, ZoneName, Factor) {
/**
* Determines, if a player can reach on orgasm from a particular zone
* @param {Character} C - The character whose ability to orgasm we check
* @param {AssetGroupName} ZoneName - The name of the zone to check
* @param {AssetGroupItemName} ZoneName - The name of the zone to check
* @returns {boolean} - Returns true if the zone allows orgasms for a character, false otherwise
*/
function PreferenceGetZoneOrgasm(C, ZoneName) {
@ -278,18 +274,16 @@ function PreferenceSetZoneOrgasm(C, ZoneName, CanOrgasm) {
// Finds the asset group and make sure the string contains it
let Group = AssetGroupGet(C.AssetFamily, ZoneName);
if (!Group) return;
if ((Group.ArousalZoneID == null) || (C.ArousalSettings.Zone.length <= Group.ArousalZoneID)) return;
// Gets the zone object
let Zone = PreferenceGetArousalZone(C, ZoneName);
if (Zone == null) {
Zone = {
// @ts-ignore
Name: ZoneName,
Factor: 2,
Orgasm: false
};
}
let Zone = PreferenceGetArousalZone(C, ZoneName) ?? {
Name: ZoneName,
Factor: 2,
Orgasm: false
};
Zone.Orgasm = CanOrgasm;
// Creates the new char and slides it in the compressed string