feat. Lewdgambler Palaace demo

This commit is contained in:
vash-the-vet 2022-01-11 19:39:38 +02:00
parent d590640912
commit 45363c15f1
21 changed files with 1181 additions and 88 deletions

Binary file not shown.

After

(image error) Size: 871 KiB

Binary file not shown.

After

(image error) Size: 676 KiB

Binary file not shown.

After

(image error) Size: 127 KiB

Binary file not shown.

After

(image error) Size: 2.5 KiB

View file

@ -272,25 +272,25 @@ function GamblingSimpleDiceController(SimpleDiceState) {
if (GamblingPlayerDice > GamblingNpcDice) {
GamblingFirstSub.AllowItem = true;
GamblingFirstSub.Stage = 81;
}
}
if (GamblingPlayerDice < GamblingNpcDice) {
GamblingFirstSub.AllowItem = false;
GamblingFirstSub.Stage = 82;
}
}
if (GamblingPlayerDice == GamblingNpcDice) {
GamblingFirstSub.AllowItem = false;
GamblingFirstSub.Stage = 83;
}
}
} else if (SimpleDiceState == "win") {
GamblingFirstSub.Stage = 0;
ReputationProgress("Gambling", 1);
GamblingFirstSub.Stage = 0;
ReputationProgress("Gambling", 1);
} else if (SimpleDiceState == "lost") {
InventoryWearRandom(Player, "ItemArms");
GamblingFirstSub.Stage = 0;
InventoryWearRandom(Player, "ItemArms");
GamblingFirstSub.Stage = 0;
} else if (SimpleDiceState == "equal") {
InventoryRemove(Player, "ItemArms");
InventoryRemove(GamblingFirstSub, "ItemArms");
GamblingFirstSub.Stage = 0;
InventoryRemove(Player, "ItemArms");
InventoryRemove(GamblingFirstSub, "ItemArms");
GamblingFirstSub.Stage = 0;
}
}
@ -437,7 +437,7 @@ function GamblingTwentyOneController(TwentyOneState) {
GamblingFirstSub.AllowItem = true;
GamblingFirstSub.Stage = 0;
ReputationProgress("Gambling", 3);
}
}
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
@ -455,7 +455,7 @@ function GamblingTwentyOneController(TwentyOneState) {
GamblingFirstSub.Appearance = GamblingAppearanceFirst.slice();
CharacterRefresh(GamblingFirstSub);
GamblingFirstSub.Stage = 0;
}
}
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
@ -472,75 +472,75 @@ function GamblingTwentyOneController(TwentyOneState) {
* @param {"new" | "fox" | "hunter" | "NextDice" | "player_fox_win" | "player_fox_lost" | "player_hunter_lost" | "player_hunter_win"} FoxState - The current state of the game
*/
function GamblingFoxController(FoxState) {
if (FoxState == "new") {
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = true;
} else if (FoxState == "fox") {
GamblingPlayerIsFox = true;
GamblingPlayerDice = Math.floor(Math.random() * 6) + 1;
GamblingPlayerDiceStack[GamblingPlayerDiceStack.length] = GamblingPlayerDice;
GamblingMoneyBet = 5;
if (FoxState == "new") {
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = true;
} else if (FoxState == "fox") {
GamblingPlayerIsFox = true;
GamblingPlayerDice = Math.floor(Math.random() * 6) + 1;
GamblingPlayerDiceStack[GamblingPlayerDiceStack.length] = GamblingPlayerDice;
GamblingMoneyBet = 5;
GamblingSecondSub.Stage = 101;
} else if (FoxState == "hunter") {
GamblingPlayerIsFox = false;
GamblingMoneyBet = 5;
CharacterChangeMoney(Player, GamblingMoneyBet * -1);
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
GamblingSecondSub.Stage = 101;
} else if (FoxState == "NextDice") {
GamblingPlayerDice = Math.floor(Math.random() * 6) + 1;
GamblingPlayerDiceStack[GamblingPlayerDiceStack.length] = GamblingPlayerDice;
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
if (GamblingPlayerIsFox && GamblingDiceStackSum(GamblingPlayerDiceStack) >= 30) {
//player has won
GamblingSecondSub.Stage = 102;
} else if (!GamblingPlayerIsFox && GamblingDiceStackSum(GamblingNpcDiceStack) >= 30) {
//npc has won
GamblingSecondSub.Stage = 103;
} else if (GamblingPlayerIsFox && (GamblingDiceStackSum(GamblingPlayerDiceStack) <= GamblingDiceStackSum(GamblingNpcDiceStack))) {
//npc has won
GamblingSecondSub.Stage = 104;
} else if (!GamblingPlayerIsFox && (GamblingDiceStackSum(GamblingNpcDiceStack) <= GamblingDiceStackSum(GamblingPlayerDiceStack))) {
//player has won
GamblingSecondSub.Stage = 105;
} else {
//next dice
GamblingSecondSub.Stage = 101;
} else if (FoxState == "hunter") {
GamblingPlayerIsFox = false;
GamblingMoneyBet = 5;
CharacterChangeMoney(Player, GamblingMoneyBet * -1);
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
GamblingSecondSub.Stage = 101;
} else if (FoxState == "NextDice") {
GamblingPlayerDice = Math.floor(Math.random() * 6) + 1;
GamblingPlayerDiceStack[GamblingPlayerDiceStack.length] = GamblingPlayerDice;
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
if (GamblingPlayerIsFox && GamblingDiceStackSum(GamblingPlayerDiceStack) >= 30) {
//player has won
GamblingSecondSub.Stage = 102;
} else if (!GamblingPlayerIsFox && GamblingDiceStackSum(GamblingNpcDiceStack) >= 30) {
//npc has won
GamblingSecondSub.Stage = 103;
} else if (GamblingPlayerIsFox && (GamblingDiceStackSum(GamblingPlayerDiceStack) <= GamblingDiceStackSum(GamblingNpcDiceStack))) {
//npc has won
GamblingSecondSub.Stage = 104;
} else if (!GamblingPlayerIsFox && (GamblingDiceStackSum(GamblingNpcDiceStack) <= GamblingDiceStackSum(GamblingPlayerDiceStack))) {
//player has won
GamblingSecondSub.Stage = 105;
} else {
//next dice
GamblingSecondSub.Stage = 101;
}
} else if (FoxState == "player_fox_win") {
GamblingSecondSub.AllowItem = false;
GamblingSecondSub.CurrentDialog = GamblingSecondSub.CurrentDialog.replace("REPLACEMONEY", GamblingMoneyBet.toString());
CharacterChangeMoney(Player, GamblingMoneyBet);
ReputationProgress("Gambling", 2);
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_fox_lost") {
GamblingSecondSub.AllowItem = false;
InventoryWearRandom(Player, "ItemLegs");
InventoryWearRandom(Player, "ItemFeet");
InventoryWearRandom(Player, "ItemArms");
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_hunter_win") {
InventoryWearRandom(GamblingSecondSub, "ItemArms");
GamblingSecondSub.AllowItem = true;
GamblingSecondSub.CurrentDialog = GamblingSecondSub.CurrentDialog.replace("REPLACEMONEY", GamblingMoneyBet.toString());
CharacterChangeMoney(Player, GamblingMoneyBet);
ReputationProgress("Gambling", 1);
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_hunter_lost") {
GamblingSecondSub.AllowItem = false;
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
}
} else if (FoxState == "player_fox_win") {
GamblingSecondSub.AllowItem = false;
GamblingSecondSub.CurrentDialog = GamblingSecondSub.CurrentDialog.replace("REPLACEMONEY", GamblingMoneyBet.toString());
CharacterChangeMoney(Player, GamblingMoneyBet);
ReputationProgress("Gambling", 2);
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_fox_lost") {
GamblingSecondSub.AllowItem = false;
InventoryWearRandom(Player, "ItemLegs");
InventoryWearRandom(Player, "ItemFeet");
InventoryWearRandom(Player, "ItemArms");
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_hunter_win") {
InventoryWearRandom(GamblingSecondSub, "ItemArms");
GamblingSecondSub.AllowItem = true;
GamblingSecondSub.CurrentDialog = GamblingSecondSub.CurrentDialog.replace("REPLACEMONEY", GamblingMoneyBet.toString());
CharacterChangeMoney(Player, GamblingMoneyBet);
ReputationProgress("Gambling", 1);
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
} else if (FoxState == "player_hunter_lost") {
GamblingSecondSub.AllowItem = false;
GamblingPlayerDiceStack = [];
GamblingNpcDiceStack = [];
GamblingShowMoney = false;
}
}
/**
@ -672,9 +672,9 @@ function GamblingDaredSixController(DaredSixState) {
}
} else if (DaredSixState == "fin") {
do {
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
GamblingMoneyBet++;
GamblingNpcDice = Math.floor(Math.random() * 6) + 1;
GamblingNpcDiceStack[GamblingNpcDiceStack.length] = GamblingNpcDice;
GamblingMoneyBet++;
} while (GamblingDiceStackSum(GamblingNpcDiceStack) <= GamblingDiceStackSum(GamblingPlayerDiceStack) && GamblingNpcDice != 6 );
if (GamblingNpcDice == 6)
{

View file

@ -0,0 +1,20 @@
0,0,,"Greetings miss. Welcome to Mistress Lewdgambler Palace! Please, come closer. I have to check your member card before you can enter.",,
0,20,What is this place?,"So youre a newcomer? Okay then, I will give you a quick tour. This is a closed gambling facility for people who are involved in domination relationships. You can play with other visitors, making a bets for money or bondage treats.",,
0,900,Here it is,--- > (checks the card and lets you in),GoToHall(),MembershipStatus(1)
0,0,What is a member card?,"This is a pass that proofs your membership status. It is required to enter a Palace. We want to make sure that our guest wont be disturbed by narrow persons or vanillas, if you know what I mean.",,MembershipStatus()
0,10,I dont have any cards,There is an option to buy one. But I need to do some background check first. What is your name again?,,MembershipStatus()
10,11,Im DialogPlayerName,"Good. Give me a moment. … I see, youre from the Bondage Club right?",,
11,12,I am.,Great then. 50$ is a price for a membership status. You will get an entry card signed by Mistress Lewdgambler personally.,,
12,900,Deal (pay 50$),Congratulations! Here is your pass and welcome to Lewdgamer Palace. Enjoy.,BuyMembership(),HasMoneyForMembership()
12,999,"That is too much, I don't have that money.","Sorry to say that, but I cant let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!",,
12,999,That is too much for a door pay.,"Sorry to say that, but I cant let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!",,
11,999,What is Bondage Club?,"Oh, my apologies. I believe some confusion have place in our data. Sorry to say that, but I cant let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!",,
999,0,(Leave),,DialogLeave();,
900,0,Thanks,,DialogLeave();,
20,21,(Next),To get in you also need to have a membership card.,,
21,0,Got it.,"Now please, present your member card. I have plenty of people waiting.",,
0,30,Is there an option to get in without a card?,Owners can take their slaves inside for free with some conditions. So if youre owned by some Palace member then lucky you.,,MembershipStatus()
30,31,(Next),(giggles) Anyway slaves are not allowed to gamble at Palace. However any other way to have fun is allowed.,,
31,31,What are conditions for a slave?,"Pacified, collared, leashed, with strict hand restrains.",,
31,0,Got it.,"Now please, present your member card. I have plenty of people waiting.",,
0,0,(Leave),,DialogLeave();,
1 0 0 Greetings miss. Welcome to Mistress Lewdgambler Palace! Please, come closer. I have to check your member card before you can enter.
2 0 20 What is this place? So you’re a newcomer? Okay then, I will give you a quick tour. This is a closed gambling facility for people who are involved in domination relationships. You can play with other visitors, making a bets for money or bondage treats.
3 0 900 Here it is --- > (checks the card and lets you in) GoToHall() MembershipStatus(1)
4 0 0 What is a member card? This is a pass that proofs your membership status. It is required to enter a Palace. We want to make sure that our guest won’t be disturbed by narrow persons or vanillas, if you know what I mean. MembershipStatus()
5 0 10 I don’t have any cards There is an option to buy one. But I need to do some background check first. What is your name again? MembershipStatus()
6 10 11 I’m DialogPlayerName Good. Give me a moment. … I see, you’re from the Bondage Club right?
7 11 12 I am. Great then. 50$ is a price for a membership status. You will get an entry card signed by Mistress Lewdgambler personally.
8 12 900 Deal (pay 50$) Congratulations! Here is your pass and welcome to Lewdgamer Palace. Enjoy. BuyMembership() HasMoneyForMembership()
9 12 999 That is too much, I don't have that money. Sorry to say that, but I can’t let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!
10 12 999 That is too much for a door pay. Sorry to say that, but I can’t let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!
11 11 999 What is Bondage Club? Oh, my apologies. I believe some confusion have place in our data. Sorry to say that, but I can’t let you in. This is some kind of closed facility and we do care of our guests comfort. Now I will ask you to leave. Good bye!
12 999 0 (Leave) DialogLeave();
13 900 0 Thanks DialogLeave();
14 20 21 (Next) To get in you also need to have a membership card.
15 21 0 Got it. Now please, present your member card. I have plenty of people waiting.
16 0 30 Is there an option to get in without a card? Owners can take their slaves inside for free with some conditions. So if you’re owned by some Palace member then lucky you. MembershipStatus()
17 30 31 (Next) (giggles) Anyway slaves are not allowed to gamble at Palace. However any other way to have fun is allowed.
18 31 31 What are conditions for a slave? Pacified, collared, leashed, with strict hand restrains.
19 31 0 Got it. Now please, present your member card. I have plenty of people waiting.
20 0 0 (Leave) DialogLeave();

View file

@ -0,0 +1,63 @@
'use strict';
(function _() {
const {
integrateRoomToWorld,
setPlayerGameData,
readPlayerGameData,
} = __vash_utils;
let securityGuy = null;
const MEMBERSHIP_PRICE = 50;
const MEMBERSHIP_PROPERTY_KEY = 'Lewdgambler.isMember';
const Background = 'LewdgamblerEntrance';
const Load = () => {
// Default load
if (securityGuy == null) {
securityGuy = CharacterLoadNPC('NPC_Lewdgambler_Security');
securityGuy.Name = 'Security';
CharacterNaked(securityGuy);
InventoryWear(securityGuy, 'CorsetShirt', 'Cloth', 'Default');
InventoryWear(securityGuy, 'ShortPencilSkirt', 'ClothLower', 'Default');
InventoryWear(securityGuy, 'Pantyhose1', 'Socks', 'Default');
InventoryWear(securityGuy, 'GarterBelt2', 'Garters', 'Default');
InventoryWear(securityGuy, 'Heels3', 'Shoes', '#202020');
}
};
const Run = () => {
DrawCharacter(securityGuy, 750, 0, 1);
DrawCharacter(Player, 250, 0, 1);
if (Player.CanWalk()) DrawButton(1885, 25, 90, 90, '', 'White', 'Icons/Exit.png', TextGet("Leave"));
};
const Click = () => {
if (MouseIn(250, 0, 500, 1000)) CharacterSetCurrent(Player);
if (MouseIn(750, 0, 500, 1000)) CharacterSetCurrent(securityGuy);
if (MouseIn(1885, 25, 90, 90) && Player.CanWalk()) CommonSetScreen('Room', 'MainHall');
};
const MembershipStatus = (requestedStatus) => {
const result = readPlayerGameData(MEMBERSHIP_PROPERTY_KEY) == requestedStatus;
return result;
};
const HasMoneyForMembership = () =>
Player.Money >= MEMBERSHIP_PRICE;
const BuyMembership = () => {
if (HasMoneyForMembership()) {
CharacterChangeMoney(Player, -MEMBERSHIP_PRICE);
setPlayerGameData('Lewdgambler.isMember', '1');
}
};
const GoToHall = () =>
CommonSetScreen('Room', 'LewdgamblerGameBiddingDuel');
// CommonSetScreen('Room', 'LewdgamblerHall');
integrateRoomToWorld('LewdgamblerEntrance', {
Background, Load, Run, Click, BuyMembership, MembershipStatus, HasMoneyForMembership, GoToHall,
});
})();

View file

@ -0,0 +1 @@
Leave,"Leave"
1 Leave Leave

Binary file not shown.

After

(image error) Size: 17 KiB

View file

@ -0,0 +1,4 @@
0,0,,"Oh dear! Looks like you lost it all. Such a poor girl.",,
0,1,"(Mumble in the gag.)","Oh stop it. Keep those noises for the visitors, I'll just take your money and will go rob someone else. Guards, take her away!"
1,2,"(Struggle in your restraints.)","[You lost this game completely. Opponent takes all money and leave you restrained to the will of Palace security.]"
2,0,"(Submit to guards.)",,"HandleLostGame()"
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,2 @@
0,0,,"[You won! (+50$)]"
0,0,"Yay!",,"HandleWonGame()"
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,345 @@
'use strict';
(function _() {
const {
integrateRoomToWorld,
pipe,
} = __vash_utils;
const {
INITIAL_STATE,
BID_ZONE,
STAGE,
addBid,
bidForOther,
canAddBid,
canRemoveBid,
removeBid,
setPileSize,
setStage,
switchStageAfterBids,
applyOtherDecision,
roundEnd,
restrain,
escape,
hasWinner,
} = __lewdgambler_biddingGame;
let opponentGuy = null;
const Background = 'LewdgamblerRoomGameTable';
const PILE_SIZE = 25;
const lockWithTimer = (character, groupName) => {
const currentItem = InventoryGet(character, groupName);
if (!currentItem.Property || !currentItem.Property.LockedBy) {
InventoryLock(character, currentItem, {
Asset: AssetGet("Female3DCG", "ItemMisc", "TimerPadlock"),
});
}
};
const releaseCharacter = (character) => {
InventoryRemove(character, 'ItemFeet');
InventoryRemove(character, 'ItemBoots');
InventoryRemove(character, 'ItemArms');
InventoryRemove(character, 'ItemHands');
InventoryRemove(character, 'ItemMouth');
InventoryRemove(character, 'ItemMouth2');
InventoryRemove(character, 'ItemHead');
};
const applyEndgameStateTransition = (state, updatedState) => {
const isWinningTransition = !hasWinner(state) && hasWinner(updatedState);
if (!isWinningTransition) return;
if (updatedState.stage === STAGE.PLAYER_LOST) {
CharacterSetCurrent(opponentGuy);
CharacterLoadCSVDialog(opponentGuy, 'Screens/Room/LewdgamblerGameBiddingDuel/Dialog_NPC_LewdgamblerBiddingGame_Loose');
releaseCharacter(opponentGuy);
}
if (updatedState.stage === STAGE.PLAYER_WON) {
CharacterSetCurrent(opponentGuy);
CharacterLoadCSVDialog(opponentGuy, 'Screens/Room/LewdgamblerGameBiddingDuel/Dialog_NPC_LewdgamblerBiddingGame_Win');
releaseCharacter(Player);
}
};
const applyRestrains = (character, restrains) => {
if (restrains[BID_ZONE.LEGS] > 0) {
InventoryWear(character, 'Irish8Cuffs', 'ItemFeet');
} else {
InventoryRemove(character, 'ItemFeet');
}
if (restrains[BID_ZONE.LEGS] > 1) {
InventoryWear(character, 'BalletWedges', 'ItemBoots');
} else {
InventoryRemove(character, 'ItemBoots');
}
if (restrains[BID_ZONE.LEGS] > 2) {
lockWithTimer(character, 'ItemFeet');
lockWithTimer(character, 'ItemBoots');
} else {
InventoryUnlock(character, 'ItemFeet');
InventoryUnlock(character, 'ItemBoots');
}
if (restrains[BID_ZONE.HANDS] > 0) {
InventoryWear(character, 'CollarCuffs', 'ItemArms');
} else {
InventoryRemove(character, 'ItemArms');
}
if (restrains[BID_ZONE.HANDS] > 1) {
lockWithTimer(character, 'ItemArms');
} else {
InventoryUnlock(character, 'ItemArms');
}
if (restrains[BID_ZONE.HANDS] > 2) {
InventoryWear(character, 'PolishedMittens', 'ItemHands');
} else {
InventoryRemove(character, 'ItemHands');
}
if (restrains[BID_ZONE.HEAD] > 0) {
InventoryWear(character, 'ClothGag', 'ItemMouth');
} else {
InventoryRemove(character, 'ItemMouth');
}
if (restrains[BID_ZONE.HEAD] > 1) {
InventoryWear(character, 'MuzzleGag', 'ItemMouth2');
} else {
InventoryRemove(character, 'ItemMouth2');
}
if (restrains[BID_ZONE.HEAD] > 2) {
InventoryWear(character, 'LeatherBlindfold', 'ItemHead');
} else {
InventoryRemove(character, 'ItemHead');
}
};
let gameState = INITIAL_STATE;
const check = selector => selector(gameState);
const setState = update => {
const updatedState = update(gameState);
applyRestrains(Player, updatedState.ownRestrains);
applyRestrains(opponentGuy, updatedState.otherRestrains);
applyEndgameStateTransition(gameState, updatedState);
gameState = updatedState;
};
const DrawCasinoButton = (top, left, w, h, text, hint) => {
const hintText = hint ? TextGet(hint) : null;
return DrawButton(top, left, w, h, text.toString(), '#61a66f', '', hintText, false, 'White', '#53885d');
};
const Load = () => {
if (opponentGuy == null) {
opponentGuy = CharacterLoadNPC('');
}
setState(() => INITIAL_STATE);
setState(setStage(STAGE.ROUND_START));
setState(setPileSize(PILE_SIZE));
};
const renderOwnBidValue = value => {
if (gameState.stage === STAGE.ROUND_START) return '-';
return value;
};
const renderOpponentBidValue = value => {
if (gameState.stage === STAGE.ROUND_START) return '-';
if (gameState.stage === STAGE.BIDDING) return '?';
return value;
};
const renderOpponentBubble = text => {
DrawImage("Screens/" + CurrentModule + "/" + CurrentScreen + "/Bubble.png", 1500, 16);
DrawText(text, 1725, 53, "Black", "Gray");
};
const Run = () => {
const {
otherBids,
otherPale,
ownBids,
ownPale,
stage,
winnerPale,
} = gameState;
// characters preview
DrawCharacter(opponentGuy, 1500, 75, 0.9);
DrawCharacter(Player, 50, 75, 0.9);
// Bidding labels
DrawTextFit(`${Player.Name} (${ownPale}$)`, 750, 295, 150, 'White', 'Black');
DrawTextFit(`${opponentGuy.Name} (${otherPale}$)`, 750, 600, 150, 'White', 'Black');
DrawTextFit('Head', 900, 80, 150, 'White', 'Black');
DrawTextFit('Hands', 1075, 80, 150, 'White', 'Black');
DrawTextFit('Feet', 1250, 80, 150, 'White', 'Black');
// Player bidding zone
DrawCasinoButton(855, 250, 90, 90, renderOwnBidValue(ownBids[BID_ZONE.HEAD]));
DrawCasinoButton(1030, 250, 90, 90, renderOwnBidValue(ownBids[BID_ZONE.HANDS]));
DrawCasinoButton(1205, 250, 90, 90, renderOwnBidValue(ownBids[BID_ZONE.LEGS]));
// Opponent bidding zone
DrawCasinoButton(855, 555, 90, 90, renderOpponentBidValue(otherBids[BID_ZONE.HEAD]));
DrawCasinoButton(1030, 555, 90, 90, renderOpponentBidValue(otherBids[BID_ZONE.HANDS]));
DrawCasinoButton(1205, 555, 90, 90, renderOpponentBidValue(otherBids[BID_ZONE.LEGS]));
// Player bid controls for bidding stage
if (stage === STAGE.BIDDING) {
if (check(canAddBid)) DrawCasinoButton(855, 140, 90, 90, '+', "AddHead");
if (check(canRemoveBid(BID_ZONE.HEAD))) DrawCasinoButton(855, 360, 90, 90, '-', "RemoveHead");
if (check(canAddBid)) DrawCasinoButton(1030, 140, 90, 90, '+', "AddHands");
if (check(canRemoveBid(BID_ZONE.HANDS))) DrawCasinoButton(1030, 360, 90, 90, '-', "RemoveHands");
if (check(canAddBid)) DrawCasinoButton(1205, 140, 90, 90, '+', "AddFeet");
if (check(canRemoveBid(BID_ZONE.LEGS))) DrawCasinoButton(1205, 360, 90, 90, '-', "RemoveFeet");
}
// Winner's pale nocice
DrawTextFit(`Winner gains additional (${winnerPale}$)`, 875, 750, 400, 'White', 'Black');
// Generic actions zone
if (stage === STAGE.BIDDING) {
renderOpponentBubble('I\'m done. Your move?');
DrawButton(1010, 850, 200, 90, 'Confirm', 'White', '', TextGet("ConfirmBidding"));
}
if (stage === STAGE.ROUND_START) {
renderOpponentBubble('Scared, you chicken?');
DrawButton(1010, 850, 200, 90, 'Go on', 'White', '', TextGet("StartRound"));
if (Player.CanWalk()) DrawButton(790, 850, 200, 90, 'Leave', 'White', '', TextGet("Leave"));
}
if (stage === STAGE.WIN_DECISION) {
renderOpponentBubble('The round is yours');
// Release actions zone
DrawButton(75, 140, 400, 90, 'Release head', 'White', '', '');
DrawButton(75, 250, 400, 90, 'Release hands', 'White', '', '');
DrawButton(75, 360, 400, 90, 'Release feet', 'White', '', '');
// Restrain actions zone
DrawButton(1525, 140, 400, 90, 'Restrain head', 'White', '', '');
DrawButton(1525, 250, 400, 90, 'Restrain hands', 'White', '', '');
DrawButton(1525, 360, 400, 90, 'Restrain feet', 'White', '', '');
}
if (stage === STAGE.LOOSE_ACCEPTANCE) {
renderOpponentBubble('Looser, huh.');
DrawButton(75, 690, 400, 90, 'Do your job...', 'White', '', '');
}
};
const Click = () => {
const {
stage,
} = gameState;
if (stage === STAGE.BIDDING) {
// bids controls
if (MouseIn(855, 140, 90, 90) && check(canAddBid)) setState(addBid(BID_ZONE.HEAD));
if (MouseIn(855, 360, 90, 90) && check(canRemoveBid(BID_ZONE.HEAD))) setState(removeBid(BID_ZONE.HEAD));
if (MouseIn(1030, 140, 90, 90) && check(canAddBid)) setState(addBid(BID_ZONE.HANDS));
if (MouseIn(1030, 360, 90, 90) && check(canRemoveBid(BID_ZONE.HANDS))) setState(removeBid(BID_ZONE.HANDS));
if (MouseIn(1205, 140, 90, 90) && check(canAddBid)) setState(addBid(BID_ZONE.LEGS));
if (MouseIn(1205, 360, 90, 90) && check(canRemoveBid(BID_ZONE.LEGS))) setState(removeBid(BID_ZONE.LEGS));
// proceed buttons
if (MouseIn(1010, 850, 200, 90)) {
// cheat should go here
// setState(setStage(STAGE.CHEAT_DECISION));
setState(switchStageAfterBids);
}
}
if (stage === STAGE.ROUND_START) {
// leave button
if (MouseIn(790, 850, 200, 90)) {
if (Player.CanWalk()) CommonSetScreen('Room', 'MainHall');
}
// proceed buttons
if (MouseIn(1010, 850, 200, 90)) {
setState(bidForOther);
setState(setStage(STAGE.BIDDING));
}
}
if (stage === STAGE.LOOSE_ACCEPTANCE) {
// loose acceptance buttons
if (MouseIn(75, 690, 400, 90)) {
setState(pipe(
applyOtherDecision,
roundEnd,
));
}
}
if (stage === STAGE.WIN_DECISION) {
// release buttons
if (MouseIn(75, 140, 400, 90)) {
setState(pipe(
escape(BID_ZONE.HEAD),
roundEnd,
));
}
if (MouseIn(75, 250, 400, 90)) {
setState(pipe(
escape(BID_ZONE.HANDS),
roundEnd,
));
}
if (MouseIn(75, 360, 400, 90)) {
setState(pipe(
escape(BID_ZONE.LEGS),
roundEnd,
));
}
// restrain buttons
if (MouseIn(1525, 140, 400, 90)) {
setState(pipe(
restrain(BID_ZONE.HEAD),
roundEnd,
));
}
if (MouseIn(1525, 250, 400, 90)) {
setState(pipe(
restrain(BID_ZONE.HANDS),
roundEnd,
));
}
if (MouseIn(1525, 360, 400, 90)) {
setState(pipe(
restrain(BID_ZONE.LEGS),
roundEnd,
));
}
}
};
const HandleLostGame = () => {
// change to moving to casino hall so maids can't reach you
CommonSetScreen('Room', 'MainHall');
CharacterChangeMoney(Player, -PILE_SIZE);
DialogLeave();
};
const HandleWonGame = () => {
CommonSetScreen('Room', 'MainHall');
CharacterChangeMoney(Player, PILE_SIZE * 2);
DialogLeave();
};
integrateRoomToWorld('LewdgamblerGameBiddingDuel', {
Background, Load, Run, Click, HandleLostGame, HandleWonGame,
});
})();

View file

@ -0,0 +1,520 @@
"use strict";
/* eslint-disable semi */
window.__lewdgambler_biddingGame = (function _() {
const {
pipe,
complement,
sum,
anyPass,
} = __vash_utils;
const STAGE = {
INITIAL: 'INITIAL',
ROUND_START: 'ROUND_START',
BIDDING: 'BIDDING',
CHEAT_DECISION: 'CHEAT_DECISION',
WIN_DECISION: 'WIN_DECISION',
LOOSE_ACCEPTANCE: 'LOOSE_ACCEPTANCE',
PLAYER_WON: 'PLAYER_WON',
PLAYER_LOST: 'PLAYER_LOST',
}
const CHEAT_CHANCE = 0.15
const BLUFF_CHANCE = 0.15
const MAX_RESTRAIN_LEVEL = 3
const RESTRAIN = {
HEAD_STUFFING: 'stuffing',
HEAD_CLEAVE: 'cleave',
HEAD_BLINDFOLD: 'blindfold',
FEET_TIED: 'tied-feet',
FEET_BOOTS: 'boots',
FEET_LOCKED: 'locked-feet',
HANDS_HANDCUFFS: 'handcuffs',
HANDS_TIED_BEHIND: 'armbinder',
HANDS_MITTENS: 'mittens',
}
const BID_ZONE = {
HEAD: 'head',
HANDS: 'hands',
LEGS: 'legs',
}
const DECISION = {
CHEAT_SKIP: 'CHEAT_SKIP',
CHEAT_HANDS: 'CHEAT_HANDS',
CHEAT_HEAD: 'CHEAT_HEAD',
CHEAT_FEET: 'CHEAT_FEET',
ESCAPE_HANDS: 'ESCAPE_HANDS',
ESCAPE_HEAD: 'ESCAPE_HEAD',
ESCAPE_FEET: 'ESCAPE_FEET',
RESTRAIN_HANDS: 'RESTRAIN_HANDS',
RESTRAIN_HEAD: 'RESTRAIN_HEAD',
RESTRAIN_FEET: 'RESTRAIN_FEET',
}
const RESTRAIN_STATS = {
[RESTRAIN.HEAD_STUFFING]: {
zone: BID_ZONE.HEAD,
level: 1,
},
[RESTRAIN.HEAD_CLEAVE]: {
zone: BID_ZONE.HEAD,
level: 2,
},
[RESTRAIN.HEAD_BLINDFOLD]: {
zone: BID_ZONE.HEAD,
level: 3,
},
[RESTRAIN.FEET_TIED]: {
zone: BID_ZONE.LEGS,
level: 1,
},
[RESTRAIN.FEET_BOOTS]: {
zone: BID_ZONE.LEGS,
level: 2,
},
[RESTRAIN.FEET_LOCKED]: {
zone: BID_ZONE.LEGS,
level: 3,
},
[RESTRAIN.HANDS_HANDCUFFS]: {
zone: BID_ZONE.HANDS,
level: 1,
},
[RESTRAIN.HANDS_TIED_BEHIND]: {
zone: BID_ZONE.HANDS,
level: 2,
},
[RESTRAIN.HANDS_MITTENS]: {
zone: BID_ZONE.HANDS,
level: 3,
},
}
const BID_STATUS = {
WIN: 'win',
LOOSE: 'loose',
DRAW: 'draw',
}
const INITIAL_STATE = {
ownPale: 0,
winnerPale: 0,
otherPale: 0,
stage: STAGE.INITIAL,
ownRestrains: {
[BID_ZONE.HEAD]: 0,
[BID_ZONE.HANDS]: 0,
[BID_ZONE.LEGS]: 1,
},
otherRestrains: {
[BID_ZONE.HEAD]: 0,
[BID_ZONE.HANDS]: 0,
[BID_ZONE.LEGS]: 1,
},
ownBids: {
[BID_ZONE.HEAD]: 0,
[BID_ZONE.HANDS]: 0,
[BID_ZONE.LEGS]: 0,
},
otherBids: {
[BID_ZONE.HEAD]: 0,
[BID_ZONE.HANDS]: 0,
[BID_ZONE.LEGS]: 0,
},
}
const randomInt = (min, max) =>
Math.floor(Math.random() * (max + 1 - min) + min)
const checkRestrain = restrainName => restrains => {
const { zone, level } = (RESTRAIN_STATS[restrainName] || {})
return (restrains[zone] || 0) >= level
}
const hasRestrain = restrainName => state =>
checkRestrain(restrainName)(state.ownRestrains);
const hasRestrains = restrains => state =>
restrains.some(restrainName => hasRestrain(restrainName)(state))
const hasOtherRestrain = restrainName => state =>
checkRestrain(restrainName)(state.otherRestrains);
const hasOtherRestrains = restrains => state =>
restrains.some(restrainName => hasOtherRestrain(restrainName)(state))
// @TODO: add some intelligence here
const rollBid = pale => {
const max = Math.floor(pale / 3)
return {
[BID_ZONE.HEAD]: randomInt(0, max),
[BID_ZONE.HANDS]: randomInt(0, max),
[BID_ZONE.LEGS]: randomInt(0, max),
}
}
const bidsTotal = bids => sum(Object.values(bids))
const canRestrain = zone => state => (state.otherRestrains[zone] || 0) < MAX_RESTRAIN_LEVEL
const canOtherRestrain = zone => state => (state.ownRestrains[zone] || 0) < MAX_RESTRAIN_LEVEL
const canEscape = zone => state => {
if (zone === BID_ZONE.LEGS && hasRestrains([RESTRAIN.FEET_LOCKED])(state)) {
return false
}
return state.ownRestrains[zone] > 0
}
const canOtherEscape = zone => state => {
if (zone === BID_ZONE.LEGS && hasOtherRestrains([RESTRAIN.FEET_LOCKED])(state)) {
return false
}
return state.otherRestrains[zone] > 0
}
const canLeave = complement(hasRestrains([RESTRAIN.FEET_TIED]))
const canCheat = complement(hasRestrains([RESTRAIN.HANDS_HANDCUFFS]))
const canBluff = complement(hasRestrains([RESTRAIN.HEAD_STUFFING]))
const canRemoveBid = zone => state => state.ownBids[zone] > 0
const canAddBid = state => state.ownPale - bidsTotal(state.ownBids) > 0
const isWinner = hasOtherRestrains([RESTRAIN.HEAD_BLINDFOLD, RESTRAIN.HANDS_MITTENS])
const isLooser = hasRestrains([RESTRAIN.HEAD_BLINDFOLD, RESTRAIN.HANDS_MITTENS])
const hasWinner = anyPass([isWinner, isLooser])
const dropBids = state => ({
...state,
ownBids: { [BID_ZONE.HEAD]: 0, [BID_ZONE.HANDS]: 0, [BID_ZONE.LEGS]: 0 },
otherBids: { [BID_ZONE.HEAD]: 0, [BID_ZONE.HANDS]: 0, [BID_ZONE.LEGS]: 0 },
})
const bidForOther = state => ({
...state,
otherBids: rollBid(state.otherPale),
})
const addBid = zone => state => ({
...state,
ownBids: {
...state.ownBids,
[zone]: state.ownBids[zone] + 1,
},
})
const removeBid = zone => state => ({
...state,
ownBids: {
...state.ownBids,
[zone]: state.ownBids[zone] - 1,
},
})
const cheat = zone => state => {
const cheatSucceed = Math.random() < CHEAT_CHANCE
if (!cheatSucceed) {
return state
}
const ownZoneBid = state.ownBids[zone]
const otherZoneBid = state.otherBids[zone]
const diff = otherZoneBid - ownZoneBid
const ownBidSum = bidsTotal(state.ownBids)
const addedBid = Math.min(state.ownPale - ownBidSum, diff + 1)
return {
...state,
ownBids: {
...state.ownBids,
[zone]: ownZoneBid + addedBid,
},
}
}
const bluff = zone => state => {
const bluffSucceed = Math.random() < BLUFF_CHANCE
if (!bluffSucceed) {
return state
}
const currentBid = state.otherBids
const paleLeft = state.otherPale - bidsTotal(state.otherBids)
const addedBid = randomInt(0, paleLeft)
return {
...state,
otherBids: {
...state.otherBids,
[zone]: currentBid + addedBid,
},
}
}
const compareBids = zone => state => {
const ownBid = state.ownBids[zone]
const otherBid = state.otherBids[zone]
if (ownBid === otherBid) return BID_STATUS.DRAW
if (ownBid > otherBid) return BID_STATUS.WIN
return BID_STATUS.LOOSE
}
const getBidsStatuses = state => ({
[BID_ZONE.HEAD]: compareBids(BID_ZONE.HEAD)(state),
[BID_ZONE.HANDS]: compareBids(BID_ZONE.HANDS)(state),
[BID_ZONE.LEGS]: compareBids(BID_ZONE.LEGS)(state),
})
const getBidRoundStatus = state => {
const statuses = getBidsStatuses(state)
const winsAmount = Object.values(statuses)
.filter(x => x === BID_STATUS.WIN).length
const lossesAmount = Object.values(statuses)
.filter(x => x === BID_STATUS.LOOSE).length
if (winsAmount > lossesAmount) {
return BID_STATUS.WIN
} else if (winsAmount < lossesAmount) {
return BID_STATUS.LOOSE
}
return BID_STATUS.DRAW
}
const applyZoneBid = zone => state => {
const ownBid = state.ownBids[zone]
const otherBid = state.otherBids[zone]
const zoneStatus = compareBids(zone)(state)
switch (zoneStatus) {
case BID_STATUS.DRAW: {
return {
...state,
ownPale: Math.max(0, state.ownPale - ownBid),
otherPale: Math.max(0, state.otherPale - otherBid),
winnerPale: state.winnerPale + otherBid + ownBid,
}
}
case BID_STATUS.WIN: {
return {
...state,
ownPale: Math.max(0, state.ownPale - ownBid),
otherPale: Math.max(0, state.otherPale - otherBid + ownBid),
winnerPale: state.winnerPale + otherBid,
}
}
case BID_STATUS.LOOSE: {
return {
...state,
ownPale: Math.max(0, state.ownPale - ownBid + otherBid),
otherPale: Math.max(0, state.otherPale - otherBid),
winnerPale: state.winnerPale + ownBid,
}
}
default: return state
}
}
const recalculatePales = state => Object.values(BID_ZONE)
.reduce((acc, zone) => applyZoneBid(zone)(acc), state)
const applyBids = pipe(
recalculatePales,
dropBids,
)
const restrain = zone => state => ({
...state,
otherRestrains: {
...state.otherRestrains,
[zone]: state.otherRestrains[zone] + 1,
},
})
const otherRestrain = zone => state => ({
...state,
ownRestrains: {
...state.ownRestrains,
[zone]: state.ownRestrains[zone] + 1,
},
})
const escape = zone => state => ({
...state,
ownRestrains: {
...state.ownRestrains,
[zone]: state.ownRestrains[zone] - 1,
},
})
const otherEscape = zone => state => ({
...state,
otherRestrains: {
...state.otherRestrains,
[zone]: state.otherRestrains[zone] - 1,
},
})
const rollLooseDecision = state => {
const bidsStatus = getBidsStatuses(state)
const wins = {
[BID_ZONE.HANDS]: bidsStatus[BID_ZONE.HANDS] === BID_STATUS.LOOSE,
[BID_ZONE.HEAD]: bidsStatus[BID_ZONE.HEAD] === BID_STATUS.LOOSE,
[BID_ZONE.LEGS]: bidsStatus[BID_ZONE.LEGS] === BID_STATUS.LOOSE,
}
const options = [
wins[BID_ZONE.HANDS]
&& canOtherEscape(BID_ZONE.HANDS)(state)
&& DECISION.ESCAPE_HANDS,
wins[BID_ZONE.HEAD]
&& canOtherEscape(BID_ZONE.HEAD)(state)
&& DECISION.ESCAPE_HEAD,
wins[BID_ZONE.LEGS]
&& canOtherEscape(BID_ZONE.LEGS)(state)
&& DECISION.ESCAPE_FEET,
wins[BID_ZONE.HANDS]
&& canOtherRestrain(BID_ZONE.HANDS)(state)
&& DECISION.RESTRAIN_HANDS,
wins[BID_ZONE.HEAD]
&& canOtherRestrain(BID_ZONE.HEAD)(state)
&& DECISION.RESTRAIN_HEAD,
wins[BID_ZONE.LEGS]
&& canOtherRestrain(BID_ZONE.LEGS)(state)
&& DECISION.RESTRAIN_FEET,
].filter(Boolean)
const decisionIndex = randomInt(0, options.length - 1)
return options[decisionIndex]
}
const getCheatDecisions = state => canCheat(state)
? [DECISION.CHEAT_HANDS, DECISION.CHEAT_HEAD, DECISION.CHEAT_FEET, DECISION.CHEAT_SKIP]
: [DECISION.CHEAT_SKIP]
const getWinDecisions = state => {
const bidsStatus = getBidsStatuses(state)
const wins = {
[BID_ZONE.HANDS]: bidsStatus[BID_ZONE.HANDS] === BID_STATUS.WIN,
[BID_ZONE.HEAD]: bidsStatus[BID_ZONE.HEAD] === BID_STATUS.WIN,
[BID_ZONE.LEGS]: bidsStatus[BID_ZONE.LEGS] === BID_STATUS.WIN,
}
return [
wins[BID_ZONE.HANDS]
&& canEscape(BID_ZONE.HANDS)(state)
&& DECISION.ESCAPE_HANDS,
wins[BID_ZONE.HEAD]
&& canEscape(BID_ZONE.HEAD)(state)
&& DECISION.ESCAPE_HEAD,
wins[BID_ZONE.LEGS]
&& canEscape(BID_ZONE.LEGS)(state)
&& DECISION.ESCAPE_FEET,
wins[BID_ZONE.HANDS]
&& canRestrain(BID_ZONE.HANDS)(state)
&& DECISION.RESTRAIN_HANDS,
wins[BID_ZONE.HEAD]
&& canRestrain(BID_ZONE.HEAD)(state)
&& DECISION.RESTRAIN_HEAD,
wins[BID_ZONE.LEGS]
&& canRestrain(BID_ZONE.LEGS)(state)
&& DECISION.RESTRAIN_FEET,
].filter(Boolean)
}
const setStage = stage => state => ({ ...state, stage })
const setPileSize = pileSize => state => ({
...state,
ownPale: pileSize,
otherPale: pileSize,
})
const switchStageAfterBids = state => {
const roundStatus = getBidRoundStatus(state)
const newStage = roundStatus === BID_STATUS.DRAW
? STAGE.ROUND_START
: roundStatus === BID_STATUS.WIN
? STAGE.WIN_DECISION
: STAGE.LOOSE_ACCEPTANCE
return setStage(newStage)(state)
}
const applyOwnDecision = decision => state => {
switch (decision) {
case DECISION.RESTRAIN_HEAD:
return restrain(BID_ZONE.HEAD)(state)
case DECISION.RESTRAIN_HANDS:
return restrain(BID_ZONE.HANDS)(state)
case DECISION.RESTRAIN_FEET:
return restrain(BID_ZONE.LEGS)(state)
case DECISION.ESCAPE_HEAD:
return escape(BID_ZONE.HEAD)(state)
case DECISION.ESCAPE_HANDS:
return escape(BID_ZONE.HANDS)(state)
case DECISION.ESCAPE_FEET:
return escape(BID_ZONE.LEGS)(state)
default: return state
}
}
const applyOtherDecision = state => {
const decision = rollLooseDecision(state)
switch (decision) {
case DECISION.RESTRAIN_HEAD:
return otherRestrain(BID_ZONE.HEAD)(state)
case DECISION.RESTRAIN_HANDS:
return otherRestrain(BID_ZONE.HANDS)(state)
case DECISION.RESTRAIN_FEET:
return otherRestrain(BID_ZONE.LEGS)(state)
case DECISION.ESCAPE_HEAD:
return otherEscape(BID_ZONE.HEAD)(state)
case DECISION.ESCAPE_HANDS:
return otherEscape(BID_ZONE.HANDS)(state)
case DECISION.ESCAPE_FEET:
return otherEscape(BID_ZONE.LEGS)(state)
default: return state
}
}
const roundEnd = state => {
const newStage = isWinner(state)
? STAGE.PLAYER_WON
: isLooser(state)
? STAGE.PLAYER_LOST
: STAGE.ROUND_START
return pipe(
setStage(newStage),
applyBids,
)(state)
}
return {
BID_ZONE,
DECISION,
INITIAL_STATE,
RESTRAIN,
STAGE,
addBid,
applyBids,
applyOtherDecision,
applyOwnDecision,
bidForOther,
bluff,
canAddBid,
canBluff,
canLeave,
canRemoveBid,
cheat,
escape,
getBidRoundStatus,
getCheatDecisions,
getWinDecisions,
removeBid,
restrain,
roundEnd,
setPileSize,
setStage,
switchStageAfterBids,
checkRestrain,
hasWinner,
}
})();

View file

@ -0,0 +1,62 @@
'use strict';
(function _() {
const {
integrateRoomToWorld,
setPlayerGameData,
readPlayerGameData,
} = __vash_utils;
let hostessGuy = null;
const MEMBERSHIP_PRICE = 50;
const MEMBERSHIP_PROPERTY_KEY = 'Lewdgambler.isMember';
const Background = 'LewdgamblerHall';
const Load = () => {
// Default load
if (hostessGuy == null) {
hostessGuy = CharacterLoadNPC('NPC_Lewdgambler_Hostess');
hostessGuy.Name = 'Hostess girl';
CharacterNaked(hostessGuy);
InventoryWear(hostessGuy, 'CorsetShirt', 'Cloth', 'Default');
InventoryWear(hostessGuy, 'ShortPencilSkirt', 'ClothLower', 'Default');
InventoryWear(hostessGuy, 'Pantyhose1', 'Socks', 'Default');
InventoryWear(hostessGuy, 'GarterBelt2', 'Garters', 'Default');
InventoryWear(hostessGuy, 'Heels3', 'Shoes', '#202020');
}
};
const Run = () => {
DrawCharacter(hostessGuy, 750, 0, 1);
DrawCharacter(Player, 250, 0, 1);
if (Player.CanWalk()) DrawButton(1885, 25, 90, 90, '', 'White', 'Icons/Exit.png', TextGet("Leave"));
};
const Click = () => {
if (MouseIn(250, 0, 500, 1000)) CharacterSetCurrent(Player);
if (MouseIn(750, 0, 500, 1000)) CharacterSetCurrent(hostessGuy);
if (MouseIn(1885, 25, 90, 90) && Player.CanWalk()) CommonSetScreen('Room', 'MainHall');
};
const MembershipStatus = (requestedStatus) => {
const result = readPlayerGameData(MEMBERSHIP_PROPERTY_KEY) == requestedStatus;
return result;
};
const HasMoneyForMembership = () =>
Player.Money >= MEMBERSHIP_PRICE;
const BuyMembership = () => {
if (HasMoneyForMembership()) {
CharacterChangeMoney(Player, -MEMBERSHIP_PRICE);
setPlayerGameData('Lewdgambler.isMember', '1');
}
};
const GoToHall = () =>
CommonSetScreen('Room', 'LewdgamblerHall');
integrateRoomToWorld('LewdgamblerHall', {
Background, Load, Run, Click, BuyMembership, MembershipStatus, HasMoneyForMembership, GoToHall,
});
})();

View file

@ -0,0 +1 @@
Leave,"Leave"
1 Leave Leave

View file

@ -239,6 +239,7 @@ function MainHallRun() {
DrawButton(1885, 505, 90, 90, "", "White", "Icons/Cell.png", TextGet("Cell"));
// Asylum, College & LARP battles
DrawButton(1525, 625, 90, 90, "", "White", "Icons/Lewdgambler.png", TextGet("Lewdgambler"));
if (!ManagementIsClubSlave()) DrawButton(1645, 625, 90, 90, "", "White", "Icons/Battle.png", TextGet("LARPBattle"));
if (!ManagementIsClubSlave()) DrawButton(1765, 625, 90, 90, "", "White", "Icons/College.png", TextGet("College"));
DrawButton(1885, 625, 90, 90, "", "White", "Icons/Asylum.png", TextGet("Asylum"));
@ -389,6 +390,8 @@ function MainHallClick() {
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 505) && (MouseY < 595)) MainHallWalk("Cell");
// Asylum & College
// if ((MouseX >= 1525) && (MouseX < 1615) && (MouseY >= 625) && (MouseY < 715)) MainHallWalk("LewdgamblerEntrance");
if ((MouseX >= 1525) && (MouseX < 1615) && (MouseY >= 625) && (MouseY < 715)) MainHallWalk("LewdgamblerGameBiddingDuel");
if ((MouseX >= 1645) && (MouseX < 1735) && (MouseY >= 625) && (MouseY < 715) && !ManagementIsClubSlave()) MainHallWalk("LARP");
if ((MouseX >= 1765) && (MouseX < 1855) && (MouseY >= 625) && (MouseY < 715) && !ManagementIsClubSlave()) MainHallWalk("CollegeEntrance");
if ((MouseX >= 1885) && (MouseX < 1975) && (MouseY >= 625) && (MouseY < 715)) MainHallWalk("AsylumEntrance");

View file

@ -16,6 +16,7 @@ Appearance,Change Appearance,
Cell,Timer Cell,
SlaveMarket,Slave Market,
LookForTrouble,Look for Trouble,
Lewdgambler, Lewdgambler Palace,
Asylum,Asylum,
College,Visit the College,
LARPBattle,LARP Battles,

1 SyncWithServer Synchronizing with server, please wait...
16 Cell Timer Cell
17 SlaveMarket Slave Market
18 LookForTrouble Look for Trouble
19 Lewdgambler Lewdgambler Palace
20 Asylum Asylum
21 College Visit the College
22 LARPBattle LARP Battles

View file

@ -0,0 +1,61 @@
"use strict";
window.__vash_utils = (function _() {
const randomInt = (min, max) =>
Math.floor(Math.random() * (max + 1 - min) + min);
const integrateRoomToWorld = (roomName, props) => {
Object.entries(props).forEach(([prop, value]) => {
const key = `${roomName}${prop}`;
if (window[key] !== undefined) {
console.warn(`Attempt to override window property "${key}" while integrating room "${roomName}"`);
} else {
window[key] = value;
}
});
};
const setPlayerGameData = (path, value) => {
const pathChains = path.split('.');
if (!Player.Game) {
Player.Game = {};
}
let pointer = Player.Game;
while (pathChains.length > 1) {
const key = pathChains.shift();
if (!pointer[key]) pointer[key] = {};
pointer = pointer[key];
}
pointer[pathChains[0]] = value;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
};
const readPlayerGameData = (path) => {
const pathChains = path.split('.');
if (!Player.Game) {
Player.Game = {};
}
return pathChains.reduce((pointer, key) => pointer && pointer[key], Player.Game);
};
const getRandomItem = (array) => {
const index = randomInt(0, array.length - 1);
return array[index];
};
const sum = list => list.reduce((a, i) => a + i, 0);
const complement = predicate => (...props) => !predicate(...props);
const pipe = (...funcs) => argument => funcs.reduce((arg, func) => func(arg), argument);
const anyPass = (predicates) => (...props) => predicates.some(p => p(...props));
return {
integrateRoomToWorld,
setPlayerGameData,
readPlayerGameData,
getRandomItem,
sum,
complement,
pipe,
anyPass,
};
})();

View file

@ -954,35 +954,41 @@ function DrawText(Text, X, Y, Color, BackColor) {
* @param {number} Width - Width of the component
* @param {number} Height - Height of the component
* @param {string} Label - Text to display in the button
* @param {string} Color - Color of the component
* @param {string} BackgroundColor - Color of the component
* @param {string} [Image] - URL of the image to draw inside the button, if applicable
* @param {string} [HoveringText] - Text of the tooltip, if applicable
* @param {boolean} [Disabled] - Disables the hovering options if set to true
* @param {string} [TextColor] - Foreground Color of the component
* @param {string} [HoverColor] - Hovered state color of the component
* @returns {void} - Nothing
*/
function DrawButton(Left, Top, Width, Height, Label, Color, Image, HoveringText, Disabled) {
function DrawButton(Left, Top, Width, Height, Label, BackgroundColor, Image, HoveringText, Disabled, TextColor, HoverColor) {
if (ControllerActive == true) {
setButton(Left, Top);
}
const foregroundColor = TextColor || "black";
const accentColor = HoverColor || "Cyan";
const isHovered = (MouseX >= Left) && (MouseX <= Left + Width) && (MouseY >= Top) && (MouseY <= Top + Height);
const hoverEnabled = HoveringText != null;
// Draw the button rectangle (makes the background color cyan if the mouse is over it)
MainCanvas.beginPath();
MainCanvas.rect(Left, Top, Width, Height);
MainCanvas.fillStyle = ((MouseX >= Left) && (MouseX <= Left + Width) && (MouseY >= Top) && (MouseY <= Top + Height) && !CommonIsMobile && !Disabled) ? "Cyan" : Color;
MainCanvas.fillStyle = (isHovered && hoverEnabled && !CommonIsMobile && !Disabled) ? accentColor : BackgroundColor;
MainCanvas.fillRect(Left, Top, Width, Height);
MainCanvas.fill();
MainCanvas.lineWidth = 2;
MainCanvas.strokeStyle = 'black';
MainCanvas.strokeStyle = foregroundColor;
MainCanvas.stroke();
MainCanvas.closePath();
// Draw the text or image
DrawTextFit(Label, Left + Width / 2, Top + (Height / 2) + 1, Width - 4, "black");
DrawTextFit(Label, Left + Width / 2, Top + (Height / 2) + 1, Width - 4, foregroundColor);
if ((Image != null) && (Image != "")) DrawImage(Image, Left + 2, Top + 2);
// Draw the hovering text
if ((HoveringText != null) && (MouseX >= Left) && (MouseX <= Left + Width) && (MouseY >= Top) && (MouseY <= Top + Height) && !CommonIsMobile) {
if (hoverEnabled && isHovered && !CommonIsMobile) {
DrawHoverElements.push(() => DrawButtonHover(Left, Top, Width, Height, HoveringText));
}
}

View file

@ -78,6 +78,7 @@
<script src="Screens/Character/Title/Title.js"></script>
<script src="Screens/Character/BackgroundSelection/BackgroundSelection.js"></script>
<script src="Screens/Character/Relog/Relog.js"></script>
<script src="Screens/Room/utils.js"></script>
<script src="Screens/Room/MainHall/MainHall.js"></script>
<script src="Screens/Room/Shop/Shop.js"></script>
<script src="Screens/Room/Introduction/Introduction.js"></script>
@ -122,6 +123,9 @@
<script src="Screens/Room/Nursery/Nursery.js"></script>
<script src="Screens/Room/Cafe/Cafe.js"></script>
<script src="Screens/Room/Arcade/Arcade.js"></script>
<script src="Screens/Room/LewdgamblerEntrance/LewdgamblerEntrance.js"></script>
<script src="Screens/Room/LewdgamblerGameBiddingDuel/core.js"></script>
<script src="Screens/Room/LewdgamblerGameBiddingDuel/LewdgamblerGameBiddingDuel.js"></script>
<script src="Screens/MiniGame/HorseWalk/HorseWalk.js"></script>
<script src="Screens/MiniGame/GetUp/GetUp.js"></script>
<script src="Screens/MiniGame/Kidnap/Kidnap.js"></script>