Futuristic Collar ()

* Futuristic item upgrades

First commit. Roadmap:
-Chastity bra will be a diagnostic item (mostly fluff)
-Chastity belt will have several functions to aid in training
-
-Futuristic items in general will give an error sound effect when a user who cannot unlock the item attempts to access the controls

Changes included in this commit:
-Bra implementation. Now displays heart rate and also a little heart icon when the user is orgasming or when the user is being aroused by an item action
-CommonDraw updated to pass G for size-based modifications
-Dialog added
-Assets added to futuristic bra to allow recoloring the text

* Added access denied effect to the panel gag

* Access denied sound effect

* Added ACCESS DENIED to the other futuristic items

Except the bra, which does not have any actual functionality besides appearance (but it has a fancy animation!)

* AlwaysExtend for all futuristic items as they are bluetooth enabled ^^

* Added ability to close the futuristic bra display + added muzzle gag

These changes should help players that prefer the metal look without too many displays

* Made the visor harder to take off when locked.

Also removed a debug statement in CommonDraw.js

* Added chat room message for trying to access a locked futuristic item

* Access Denied message now remains until the user exits

The load function kept removing the access denied message so now it's just called in the exit function

* Added a null check to prevent crash

* Futuristic Collar

Added a futuristic collar, which has the functionality of allowing a player to quickly lock all items with "Futuristic" or "Interactive" in their name on a player. It only allows players to use the following locks, and only allows the player to lock or unlock the items if they own the locks and could normally lock the player:
 - Metal Padlock
 - Exclusive Padlock
 - 5 Min Padlock
 - Mistress Padlock
 - Lovers Padlock
 - Owner Padlock


This has a dependency on the futuristic item revamp

* Fixed partial locking, other bugs

* Start

* Revert "Start"

This reverts commit 20f4e31f95.

* Added a hydraulic locking sound instead of the default lock/unlock

Recorded it myself so no attribution needed

* Included a new sound for putting the collar on

Also fixed sound effects not playing for others

* Fixed a bug that allowed you to put blocked locks on someone

Co-authored-by: Ben987 <30805159+Ben987@users.noreply.github.com>
This commit is contained in:
Ada18980 2020-10-20 21:50:51 -07:00 committed by GitHub
parent ff00d196b6
commit a1afb1fc63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 241 additions and 3 deletions

View file

@ -788,6 +788,7 @@ ItemNeck,SteelPostureCollar,Steel Collar
ItemNeck,DogCollar,Dog Collar
ItemNeck,SpikeCollar,Spike Collar
ItemNeck,HighCollar,High Collar
ItemNeck,FuturisticCollar,Futuristic Collar
ItemNeck,LeatherChoker,Leather Choker
ItemNeck,PetCollar,Pet Collar
ItemNeck,MaidCollar,Maid Collar

1 Cloth Cloth
788 ItemNeck DogCollar Dog Collar
789 ItemNeck SpikeCollar Spike Collar
790 ItemNeck HighCollar High Collar
791 ItemNeck FuturisticCollar Futuristic Collar
792 ItemNeck LeatherChoker Leather Choker
793 ItemNeck PetCollar Pet Collar
794 ItemNeck MaidCollar Maid Collar

View file

@ -2131,6 +2131,13 @@ var AssetFemale3DCG = [
{ Name: "Rings" }
]
},
{
Name: "FuturisticCollar", Fetish: ["Metal"], Value: 100, Difficulty: 50, Time: 12, Audio: "FuturisticApply", DefaultColor: ["#40812C", "Default"], AllowLock: true, Extended: true,
Layer: [
{ Name: "Display" },
{ Name: "Band" },
]
},
{ Name: "LeatherChoker", Fetish: ["Leather"], Value: 10, Difficulty: 50, Time: 5, AllowLock: true },
{ Name: "PetCollar", Fetish: ["Leather", "Pet"], Value: -1, Difficulty: 50, Time: 5, AllowLock: true },
{ Name: "MaidCollar", Fetish: ["Lingerie"], Value: 30, Difficulty: 50, Time: 5, AllowLock: true },

Binary file not shown.

After

(image error) Size: 2 KiB

Binary file not shown.

After

(image error) Size: 940 B

Binary file not shown.

After

(image error) Size: 443 B

Binary file not shown.

After

(image error) Size: 29 KiB

View file

@ -155,6 +155,8 @@ ItemArmsChains,Chains
ItemArmsChainsSuspension,Suspension Chain
ItemNeckHighCollarLeather,Leather
ItemNeckHighCollarRings,Rings
ItemNeckFuturisticCollarBand,Band
ItemNeckFuturisticCollarDisplay,Display
ItemNeckOrnateCollarCollar,Collar
ItemNeckOrnateCollarGem,Gems
ItemNeckAccessoriesCustomCollarTagTag,Tag

1 ClothStudentOutfit3White Shirt
155 ItemArmsChainsSuspension Suspension Chain
156 ItemNeckHighCollarLeather Leather
157 ItemNeckHighCollarRings Rings
158 ItemNeckFuturisticCollarBand Band
159 ItemNeckFuturisticCollarDisplay Display
160 ItemNeckOrnateCollarCollar Collar
161 ItemNeckOrnateCollarGem Gems
162 ItemNeckAccessoriesCustomCollarTagTag Tag

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -613,7 +613,20 @@ FuturisticPanelGagMouthSetBall,,,SourceCharacter configures DestinationCharacter
FuturisticPanelGagMouthSetPlug,,,SourceCharacter configures DestinationCharacter gag to dildo mode.,,
DildoPlugGagMouthSetPlug,,,SourceCharacter plugs up DestinationCharacter mouth with the dildo plug.,,
DildoPlugGagMouthSetOpen,,,SourceCharacter pulls out DestinationCharacter dildo plug from her gag.,,
FuturisticCollarTriggerLockdown,,,SourceCharacter feels her bindings tightening around her body with a hiss as they lock themselves automatically.,,
FuturisticCollarTriggerUnlock,,,SourceCharacter feels her bindings release her with a hiss.,,
FuturisticCollarOptions,,,Current Status:,,
FuturisticCollarOptionsNoLocks,,,Unlocked,,
FuturisticCollarOptionsPartialLocks,,,Partially Locked,,
FuturisticCollarOptionsFullyLocked,,,Fully Locked,,
FuturisticCollarOptionsNoItems,,,No Futuristic Items Worn,,
FuturisticCollarLockMetal,,,Lock Metal,,
FuturisticCollarLockExclusive,,,Lock Exclusive,,
FuturisticCollarLockTimer,,,Lock 5 Minutes,,
FuturisticCollarLockMistress,,,Lock Mistress,,
FuturisticCollarLockLover,,,Lock Lovers,,
FuturisticCollarLockOwner,,,Lock Owner,,
FuturisticCollarUnlock,,,Unlock,,
FuturisticHeelsType,,,Select heel mode,,
FuturisticHeelsTypeShoes,,,Heels Retracted,,
FuturisticHeelsTypeHeel,,,Heels Extended,,
@ -622,7 +635,6 @@ FuturisticHeelsSetHeel,,,SourceCharacter extends the heels on DestinationCharact
FuturisticPanelGagMouthSetPadded,,,SourceCharacter configures DestinationCharacter gag to padded mode.,,
FuturisticPanelGagMouthSetBall,,,SourceCharacter configures DestinationCharacter gag to ball mode.,,
FuturisticPanelGagMouthSetPlug,,,SourceCharacter configures DestinationCharacter gag to dildo mode.,,
FuturisticBraPlayerDesc,,,Diagnostics for wearer,,
FuturisticBraPlayerTemp,,,Current Body Temp:,,
FuturisticBraPlayerTempC,,,°C,,
@ -638,7 +650,6 @@ FuturisticBraPlayerSolid,,,Cover Display,,
FuturisticBraPlayerShow,,,Show Display,,
InventoryItemBreastFuturisticBraSetSolid,,,SourceCharacter covers the display on DestinationCharacter bra.,,
InventoryItemBreastFuturisticBraSetShow,,,SourceCharacter opens up the display on DestinationCharacter bra.,,
FuturisticBraPlayerHeartRateBPM,,,BPM,,
CupholderGagOptions,,,Cup interactions,,
CupholderGagTipOverCup,,,Tip over,,

Can't render this file because it has a wrong number of fields in line 373.

View file

@ -0,0 +1,211 @@
"use strict";
// Loads the item extension properties
function InventoryItemNeckFuturisticCollarLoad() {
var C = (Player.FocusGroup != null) ? Player : CurrentCharacter;
if (!InventoryItemMouthFuturisticPanelGagValidate(C)) {
InventoryItemMouthFuturisticPanelGagLoadAccessDenied()
}
}
// Draw the item extension screen
function InventoryItemNeckFuturisticCollarDraw() {
var C = (Player.FocusGroup != null) ? Player : CurrentCharacter;
if (!InventoryItemMouthFuturisticPanelGagValidate(C)) {
InventoryItemMouthFuturisticPanelGagDrawAccessDenied()
} else {
DrawRect(1387, 225, 225, 275, "white");
DrawImageResize("Assets/" + DialogFocusItem.Asset.Group.Family + "/" + DialogFocusItem.Asset.Group.Name + "/Preview/" + DialogFocusItem.Asset.Name + ".png", 1389, 227, 221, 221);
DrawTextFit(DialogFocusItem.Asset.Description, 1500, 475, 221, "black");
var FuturisticCollarStatus = "NoItems"
var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C)
var FuturisticCollarItemsUnlockable = InventoryItemNeckFuturisticCollarGetItems(C, true)
var lockedItems = 0
for (let I = 0; I < FuturisticCollarItems.length; I++) {
if (InventoryGetLock(FuturisticCollarItems[I])) {
lockedItems += 1
}
}
if (FuturisticCollarItems.length > 0) {
if (lockedItems == 0) FuturisticCollarStatus = "NoLocks"
else if (lockedItems < FuturisticCollarItems.length) FuturisticCollarStatus = "PartialLocks"
else if (lockedItems == FuturisticCollarItems.length) FuturisticCollarStatus = "FullyLocked"
}
DrawText(DialogFind(Player, "FuturisticCollarOptions" + FuturisticCollarStatus), 1500, 600, "White", "Gray");
if (FuturisticCollarItems.length > 0 && lockedItems < FuturisticCollarItems.length) {
if (InventoryItemNeckFuturisticCollarCanLock(C, "MetalPadlock", "ItemMisc")) DrawButton(1250, 650, 200, 55, DialogFind(Player, "FuturisticCollarLockMetal"), "White");
if (InventoryItemNeckFuturisticCollarCanLock(C, "ExclusivePadlock", "ItemMisc")) DrawButton(1550, 650, 200, 55, DialogFind(Player, "FuturisticCollarLockExclusive"), "White");
if (InventoryItemNeckFuturisticCollarCanLock(C, "TimerPadlock", "ItemMisc")) DrawButton(1250, 710, 200, 55, DialogFind(Player, "FuturisticCollarLockTimer"), "White");
if (InventoryItemNeckFuturisticCollarCanLock(C, "MistressPadlock", "ItemMisc")) DrawButton(1550, 710, 200, 55, DialogFind(Player, "FuturisticCollarLockMistress"), "White");
if (InventoryItemNeckFuturisticCollarCanLock(C, "LoversPadlock", "ItemMisc")) DrawButton(1250, 770, 200, 55, DialogFind(Player, "FuturisticCollarLockLover"), "White");
if (InventoryItemNeckFuturisticCollarCanLock(C, "OwnerPadlock", "ItemMisc")) DrawButton(1550, 770, 200, 55, DialogFind(Player, "FuturisticCollarLockOwner"), "White");
}
if (FuturisticCollarItemsUnlockable.length > 0) {
DrawButton(1400, 880, 200, 55, DialogFind(Player, "FuturisticCollarUnlock"), "White");
}
}
}
function InventoryItemNeckFuturisticCollarExit() {
InventoryItemMouthFuturisticPanelGagExitAccessDenied()
}
// Catches the item extension clicks
function InventoryItemNeckFuturisticCollarClick() {
var C = (Player.FocusGroup != null) ? Player : CurrentCharacter;
if (!InventoryItemMouthFuturisticPanelGagValidate(C)) {
InventoryItemMouthFuturisticPanelGagClickAccessDenied()
} else {
if ((MouseX >= 1885) && (MouseX <= 1975) && (MouseY >= 25) && (MouseY <= 110)) InventoryItemNeckFuturisticCollarExit();
else {
var FuturisticCollarItems = InventoryItemNeckFuturisticCollarGetItems(C)
var FuturisticCollarItemsUnlockable = InventoryItemNeckFuturisticCollarGetItems(C, true)
var lockedItems = 0
for (let I = 0; I < FuturisticCollarItems.length; I++) {
if (InventoryGetLock(FuturisticCollarItems[I])) {
lockedItems += 1
}
}
var CollarAction = 0 // 0 - nothing, 1 - Lock, 2 - Unlock
if (FuturisticCollarItems.length > 0 ) {
if (lockedItems < FuturisticCollarItems.length) {
if (MouseIn(1250, 650, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "MetalPadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "MetalPadlock"); CollarAction = 1}
else if (MouseIn(1550, 650, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "ExclusivePadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "ExclusivePadlock"); CollarAction = 1}
else if (MouseIn(1250, 710, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "TimerPadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "TimerPadlock"); CollarAction = 1}
else if (MouseIn(1550, 710, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "MistressPadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "MistressPadlock"); CollarAction = 1}
else if (MouseIn(1250, 770, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "LoversPadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "LoversPadlock"); CollarAction = 1}
else if (MouseIn(1550, 770, 200, 55) && InventoryItemNeckFuturisticCollarCanLock(C, "OwnerPadlock", "ItemMisc")) { InventoryItemNeckFuturisticCollarLockdown(C, "OwnerPadlock"); CollarAction = 1}
}
}
if (MouseIn(1400, 880, 200, 55) && FuturisticCollarItemsUnlockable.length > 0) { InventoryItemNeckFuturisticCollarUnlock(C); CollarAction = 2}
if (CollarAction > 0) {
InventoryItemNeckFuturisticCollarExit();
/*var vol = 1
if (Player.AudioSettings && Player.AudioSettings.Volume) {
vol = Player.AudioSettings.Volume
}
if (CollarAction == 1)
AudioPlayInstantSound("Audio/HydraulicLock.mp3", vol)
else
AudioPlayInstantSound("Audio/HydraulicUnlock.mp3", vol)*/
}
}
}
}
function InventoryItemNeckFuturisticCollarCanLock(C, LockType) {
InventoryAvailable(Player, LockType, "ItemMisc")
var LockItem = null
// First, we check if the inventory already exists, exit if it's the case
for (let I = 0; I < C.Inventory.length; I++)
if ((C.Inventory[I].Name == LockType) && (C.Inventory[I].Group == "ItemMisc")) {
LockItem = C.Inventory[I]
break;
}
if (LockItem && !(InventoryIsPermissionBlocked(C, LockType, "ItemMisc") || !InventoryCheckLimitedPermission(C, LockItem))) {
// Make sure we do not add owner/lover only items for invalid characters, owner/lover locks can be applied on the player by the player for self-bondage
if (LockItem.Asset.OwnerOnly && !C.IsOwnedByPlayer())
if ((C.ID != 0) || ((C.Owner == "") && (C.Ownership == null)) || ((C.ID == 0) && LogQuery("BlockOwnerLockSelf", "OwnerRule")))
return false;
if (LockItem.Asset.LoverOnly && !C.IsLoverOfPlayer())
if ((C.ID != 0) || (C.Lovership.length == 0) || ((C.ID == 0) && C.GetLoversNumbers(true).length == 0))
return false;
return true
}
return false
}
function InventoryItemNeckFuturisticCollarGetItems(C, OnlyUnlockable) {
var ItemList = []
for (let E = C.Appearance.length - 1; E >= 0; E--)
if (((C.Appearance[E].Asset.Name.indexOf("Futuristic") >= 0 || C.Appearance[E].Asset.Name.indexOf("Interactive") >= 0) && C.Appearance[E].Asset.Group.Name != "ItemNeck") &&
(C.Appearance[E].Asset.AllowLock)
&& (!OnlyUnlockable || (InventoryGetLock(C.Appearance[E]) != null && InventoryItemHasEffect(C.Appearance[E], "Lock", true) && DialogCanUnlock(C, C.Appearance[E])))) {
ItemList.push(C.Appearance[E])
}
return ItemList
}
function InventoryItemNeckFuturisticCollarValidate(C, Option) {
return InventoryItemMouthFuturisticPanelGagValidate(C, Option)
}
function InventoryItemNeckFuturisticCollarLockdown(C, LockType) {
for (let E = C.Appearance.length - 1; E >= 0; E--)
if (((C.Appearance[E].Asset.Name.indexOf("Futuristic") >= 0 || C.Appearance[E].Asset.Name.indexOf("Interactive") >= 0) && C.Appearance[E].Asset.Group.Name != "ItemNeck") &&
(C.Appearance[E].Asset.AllowLock && InventoryGetLock(C.Appearance[E]) == null)) {
InventoryLock(C, C.Appearance[E], LockType, Player.MemberNumber);
var Lock = InventoryGetLock(C.Appearance[E])
}
ChatRoomCharacterUpdate(C);
CharacterRefresh(C, true);
if (CurrentScreen == "ChatRoom") {
var Message;
var Dictionary = [
{ Tag: "SourceCharacter", Text: Player.Name, MemberNumber: Player.MemberNumber },
{ Tag: "DestinationCharacter", Text: C.Name, MemberNumber: C.MemberNumber },
];
Message = "FuturisticCollarTriggerLockdown";
ServerSend("ChatRoomChat", { Content: Message, Type: "Action", Dictionary });
}
//ServerSend("ChatRoomChat", { Content: " feels her bindings tightening around her body with a hiss as they lock themselves automatically.", Type: "Emote" });
}
function InventoryItemNeckFuturisticCollarUnlock(C) {
for (let E = C.Appearance.length - 1; E >= 0; E--)
if (((C.Appearance[E].Asset.Name.indexOf("Futuristic") >= 0 || C.Appearance[E].Asset.Name.indexOf("Interactive") >= 0) && C.Appearance[E].Asset.Group.Name != "ItemNeck") &&
(InventoryGetLock(C.Appearance[E]) != null && InventoryItemHasEffect(C.Appearance[E], "Lock", true) && DialogCanUnlock(C, C.Appearance[E]))) {
InventoryUnlock(C, C.Appearance[E])
}
ChatRoomCharacterUpdate(C);
CharacterRefresh(C, true);
if (CurrentScreen == "ChatRoom") {
var Message;
var Dictionary = [
{ Tag: "SourceCharacter", Text: Player.Name, MemberNumber: Player.MemberNumber },
{ Tag: "DestinationCharacter", Text: C.Name, MemberNumber: C.MemberNumber },
];
Message = "FuturisticCollarTriggerUnlock";
ServerSend("ChatRoomChat", { Content: Message, Type: "Action", Dictionary });
}
//if (CurrentScreen == "ChatRoom")
// ServerSend("ChatRoomChat", { Content: " 's bindings unlock with a hiss.", Type: "Emote" });
}

View file

@ -9,6 +9,9 @@ var AudioList = [
{ Name: "ChainLong", File: "ChainLong" },
{ Name: "ChainShort", File: "ChainShort" },
{ Name: "CuffsMetal", File: "CuffsMetal" },
{ Name: "FuturisticApply", File: "FuturisticApply" },
{ Name: "HydraulicLock", File: "HydraulicLock" },
{ Name: "HydraulicUnlock", File: "HydraulicUnlock" },
{ Name: "Deflation", File: "Deflation" },
{ Name: "DuctTape", File: "DuctTape18" },
{ Name: "Inflation", File: "Inflation" },
@ -37,6 +40,8 @@ var AudioActions = [
{ Action: "TimerRelease", Sound: "Unlock" },
{ Action: "ActionUnlock", Sound: "Unlock" },
{ Action: "ActionUnlockAndRemove", Sound: "Unlock" },
{ Action: "FuturisticCollarTriggerLockdown", Sound: "HydraulicLock" },
{ Action: "FuturisticCollarTriggerUnlock", Sound: "HydraulicUnlock" },
{ Action: "ActionLock", GetAudioInfo: AudioPlayAssetSound },
{
IsAction: (data) => ["ActionUse", "ActionSwap"].includes(data.Content) && data.Sender !== Player.MemberNumber,

View file

@ -169,6 +169,7 @@
<script src="Screens/Inventory/ItemMouth/PlugGag/PlugGag.js"></script>
<script src="Screens/Inventory/ItemMouth/FuturisticPanelGag/FuturisticPanelGag.js"></script>
<script src="Screens/Inventory/ItemMouth/FuturisticHarnessPanelGag/FuturisticHarnessPanelGag.js"></script>
<script src="Screens/Inventory/ItemNeck/FuturisticCollar/FuturisticCollar.js"></script>
<script src="Screens/Inventory/ItemMouth/DildoPlugGag/DildoPlugGag.js"></script>
<script src="Screens/Inventory/ItemHands/SpankingToys/SpankingToy.js"></script>
<script src="Screens/Inventory/ItemTorso/HempRopeHarness/HempRopeHarness.js"></script>