New Theresa NPC joins MagicSchoolFindsAround bringing a new Seraph wing asset with it | by Felix & Rosa & Tifa

This commit is contained in:
Feldob66 2026-03-29 20:27:58 +00:00 committed by BondageProjects
parent 2b08771a5f
commit 993593b586
63 changed files with 1211 additions and 234 deletions

View file

@ -6889,6 +6889,19 @@ WingsDragonWingsSpread,Spread
WingsDragonWingsFolded,Folded
WingsDragonWingsBound,Bound
WingsDragonWingsSelect,Select the state
WingsSeraphWingsSelectBase,Toggle Wings
WingsSeraphWingsSelectWing1,Wing 1
WingsSeraphWingsSelectWing2,Wing 2
WingsSeraphWingsSelectWing3,Wing 3
WingsSeraphWingsModuleWing1,Wing 1
WingsSeraphWingsModuleWing2,Wing 2
WingsSeraphWingsModuleWing3,Wing 3
WingsSeraphWingsOptionshow10,Show
WingsSeraphWingsOptionshow11,Hide
WingsSeraphWingsOptionshow20,Show
WingsSeraphWingsOptionshow21,Hide
WingsSeraphWingsOptionshow30,Show
WingsSeraphWingsOptionshow31,Hide
YourRoom,<i>Your private room</i>
ZipBondageZipFeetFull,Full Binding
ZipBondageZipFeetLight,Light Binding

Can't render this file because it is too large.

View file

@ -171,3 +171,6 @@ ShoesZipperLeatherBootsLeft,Left
ShoesZipperLeatherBootsRight,Right
TailStrapsKitsuneTailStrapsTails,Tails
TailStrapsKitsuneTailStrapsTips,Tips
WingsSeraphWingsBases,Bases
WingsSeraphWingsTips,Tips
WingsSeraphWingsWings,Wings
1 BraLeatherBunnyHollowBraBody Body
171 ShoesZipperLeatherBootsRight Right
172 TailStrapsKitsuneTailStrapsTails Tails
173 TailStrapsKitsuneTailStrapsTips Tips
174 WingsSeraphWingsBases Bases
175 WingsSeraphWingsTips Tips
176 WingsSeraphWingsWings Wings

View file

@ -2048,3 +2048,4 @@ Wings,SuccubusFeather,Succubus Feather
Wings,SuccubusWings,Succubus Wings
Wings,DragonWings,Dragon Wings
Wings,Wing1,Low Bat Wings
Wings,SeraphWings,Seraph Wings

1 AnkletLeft Anklet (Left)
2048 Wings SuccubusWings Succubus Wings
2049 Wings DragonWings Dragon Wings
2050 Wings Wing1 Low Bat Wings
2051 Wings SeraphWings Seraph Wings

View file

@ -12866,7 +12866,15 @@ var AssetFemale3DCG = [
Spread: 0,
},
Priority: 12,
DefaultColor: ["#351C1C", "#351C1C", "#1C1111", "#1C1111", "#170E0E", "#170E0E", "#000000"],
DefaultColor: [
"#351C1C",
"#351C1C",
"#1C1111",
"#1C1111",
"#170E0E",
"#170E0E",
"#000000",
],
Layer: [
{
Name: "UpperSocks",
@ -24120,6 +24128,499 @@ var AssetFemale3DCG = [
License: "CC BY-SA-NC 4.0",
},
},
{
Name: "SeraphWings",
InventoryID: 2302,
DefaultColor: [],
Value: -1,
BodyCosplay: true,
PoseMapping: {
...AssetPoseMapping.Wings,
AllFours: "AllFours",
Hogtied: "AllFours",
},
Layer: [
{
Name: "Base1",
ColorGroup: "Bases",
Left: {
[PoseType.DEFAULT]: 101,
AllFours: 140,
Hogtied: 140,
},
Top: {
[PoseType.DEFAULT]: 175,
AllFours: 60,
Hogtied: 60,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show1: 0 },
},
{
Name: "Base2",
ColorGroup: "Bases",
Left: {
[PoseType.DEFAULT]: 97,
AllFours: 130,
Hogtied: 130,
},
Top: {
[PoseType.DEFAULT]: 243,
AllFours: 28,
Hogtied: 28,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show2: 0 },
},
{
Name: "Base3",
ColorGroup: "Bases",
Left: {
[PoseType.DEFAULT]: 89,
AllFours: 145,
Hogtied: 145,
},
Top: {
[PoseType.DEFAULT]: 379,
AllFours: 30,
Hogtied: 30,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show3: 0 },
},
{
Name: "WingBase1",
ColorGroup: "Wings",
Priority: 50,
Left: {
[PoseType.DEFAULT]: 28,
AllFours: 40,
Hogtied: 40,
},
Top: {
[PoseType.DEFAULT]: 170,
AllFours: 50,
Hogtied: 50,
},
PoseMapping: {
OverTheHead: PoseType.HIDE,
Yoked: PoseType.HIDE,
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase1Extra1",
CopyLayerColor: "WingBase1",
Left: 28,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: "OverTheHead",
Yoked: PoseType.HIDE,
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase1Extra2",
CopyLayerColor: "WingBase1",
Priority: 54,
Left: 28,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: "OverTheHead",
Yoked: "OverTheHead",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase1Extra3",
CopyLayerColor: "WingBase1",
Priority: 54,
Left: 28,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase2",
ColorGroup: "Wings",
Priority: 50,
Left: {
[PoseType.DEFAULT]: 308,
AllFours: 260,
Hogtied: 260,
},
Top: {
[PoseType.DEFAULT]: 170,
AllFours: 50,
Hogtied: 50,
},
PoseMapping: {
OverTheHead: PoseType.HIDE,
Yoked: PoseType.HIDE,
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase2Extra1",
CopyLayerColor: "WingBase2",
Left: 308,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: "OverTheHead",
Yoked: PoseType.HIDE,
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase2Extra2",
CopyLayerColor: "WingBase2",
Priority: 54,
Left: 308,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: "OverTheHead",
Yoked: "OverTheHead",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase2Extra3",
CopyLayerColor: "WingBase2",
Priority: 54,
Left: 308,
Top: 170,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingBase3",
ColorGroup: "Wings",
Priority: 49,
Left: {
[PoseType.DEFAULT]: 1,
AllFours: 34,
Hogtied: 34,
},
Top: {
[PoseType.DEFAULT]: 238,
AllFours: 27,
Hogtied: 27,
},
PoseMapping: {
Yoked: PoseType.HIDE,
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase3Extra1",
CopyLayerColor: "WingBase3",
Left: 1,
Top: 238,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase3Extra2",
CopyLayerColor: "WingBase3",
Priority: 52,
Left: 1,
Top: 238,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase4",
ColorGroup: "Wings",
Priority: 49,
Left: {
[PoseType.DEFAULT]: 267,
AllFours: 260,
Hogtied: 260,
},
Top: {
[PoseType.DEFAULT]: 240,
AllFours: 30,
Hogtied: 30,
},
PoseMapping: {
Yoked: PoseType.HIDE,
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase4Extra1",
CopyLayerColor: "WingBase4",
Left: 267,
Top: 240,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase4Extra2",
CopyLayerColor: "WingBase4",
Priority: 52,
Left: 267,
Top: 240,
PoseMapping: {
AllFours: PoseType.HIDE,
BackBoxTie: PoseType.HIDE,
BackCuffs: PoseType.HIDE,
BackElbowTouch: PoseType.HIDE,
BaseUpper: PoseType.HIDE,
Hogtied: PoseType.HIDE,
OverTheHead: PoseType.HIDE,
Yoked: "Yoked",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingBase5",
ColorGroup: "Wings",
Priority: 48,
Left: {
[PoseType.DEFAULT]: 22,
AllFours: 58,
Hogtied: 58,
},
Top: {
[PoseType.DEFAULT]: 375,
AllFours: 28,
Hogtied: 28,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show3: 0 },
},
{
Name: "WingBase6",
ColorGroup: "Wings",
Priority: 48,
Left: {
[PoseType.DEFAULT]: 292,
AllFours: 260,
Hogtied: 260,
},
Top: {
[PoseType.DEFAULT]: 375,
AllFours: 30,
Hogtied: 30,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show3: 0 },
},
{
Name: "WingTip1",
ColorGroup: "Tips",
Priority: 55,
Left: {
[PoseType.DEFAULT]: 28,
AllFours: 40,
Hogtied: 40,
},
Top: {
[PoseType.DEFAULT]: 260,
AllFours: 130,
Hogtied: 130,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingTip2",
ColorGroup: "Tips",
Priority: 55,
Left: {
[PoseType.DEFAULT]: 259,
AllFours: 341,
Hogtied: 341,
},
Top: {
[PoseType.DEFAULT]: 266,
AllFours: 140,
Hogtied: 140,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show1: 0 },
},
{
Name: "WingTip3",
ColorGroup: "Tips",
Priority: 53,
Left: {
[PoseType.DEFAULT]: 0,
AllFours: 34,
Hogtied: 34,
},
Top: {
[PoseType.DEFAULT]: 376,
AllFours: 131,
Hogtied: 131,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingTip4",
ColorGroup: "Tips",
Priority: 53,
Left: {
[PoseType.DEFAULT]: 204,
AllFours: 336,
Hogtied: 336,
},
Top: {
[PoseType.DEFAULT]: 364,
AllFours: 134,
Hogtied: 134,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show2: 0 },
},
{
Name: "WingTip5",
ColorGroup: "Tips",
Priority: 51,
Left: {
[PoseType.DEFAULT]: 22,
AllFours: 55,
Hogtied: 55,
},
Top: {
[PoseType.DEFAULT]: 491,
AllFours: 130,
Hogtied: 130,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show3: 0 },
},
{
Name: "WingTip6",
ColorGroup: "Tips",
Priority: 51,
Left: {
[PoseType.DEFAULT]: 232,
AllFours: 330,
Hogtied: 330,
},
Top: {
[PoseType.DEFAULT]: 499,
AllFours: 132,
Hogtied: 132,
},
PoseMapping: {
AllFours: "AllFours",
Hogtied: "AllFours",
},
AllowTypes: { show3: 0 },
},
],
},
],
Color: [
"Default",

View file

@ -22177,6 +22177,38 @@ var AssetFemale3DCGExtended = {
},
],
}, // SteampunkWings
SeraphWings: {
Archetype: ExtendedArchetype.MODULAR,
Modules: [
{
Name: "Wing1",
Key: "show1",
DrawImages: false,
Options: [
{}, //show1_0 - Show
{}, //show1_1 - Hide
],
},
{
Name: "Wing2",
Key: "show2",
DrawImages: false,
Options: [
{}, //show2_0 - Show
{}, //show2_1 - Hide
],
},
{
Name: "Wing3",
Key: "show3",
DrawImages: false,
Options: [
{}, //show3_0 - Show
{}, //show3_1 - Hide
],
},
],
}, // SeraphWings
DragonWings: {
Archetype: ExtendedArchetype.TYPED,
DrawImages: true,

View file

@ -407,7 +407,7 @@ interface AssetGroupDefinitionBase extends AssetCommonPropertiesGroupAsset, Asse
MirrorActivitiesFrom?: AssetGroupItemName;
/**
* The group actually recieving arousal events
* The group actually receiving arousal events
*
* Used to proxy around a group that does not have activities
* enabled (and thus arousal settings.
@ -939,7 +939,7 @@ interface ExtendedItemConfig<OptionType extends ExtendedItemOption> {
/** A record containing various dialog keys used by the extended item screen */
DialogPrefix?: ExtendedItemCapsDialog<any, OptionType>;
/**
* A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* A record containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
@ -1140,7 +1140,7 @@ interface TypedItemConfig extends ExtendedItemConfig<TypedItemOption> {
*/
ChangeWhenLocked?: boolean;
/**
* A recond containing functions that are run on load, click, draw, exit, validate and publishaction,
* A record containing functions that are run on load, click, draw, exit, validate and publishaction,
* with the original archetype function and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/
@ -1195,7 +1195,7 @@ interface ModularItemConfig extends ExtendedItemConfig<ModularItemOption> {
Chat?: string | ExtendedItemChatCallback<ModularItemOption>;
};
/**
* A recond containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* A record containing functions that are run on load, click, draw, exit, and validate, with the original archetype function
* and parameters passed on to them. If undefined, these are ignored.
* Note that scripthook functions must be loaded before `Female3DCGExtended.js` in `index.html`.
*/

View file

@ -3684,3 +3684,18 @@ WingsDragonWingsBuckles,Binding buckles
WingsDragonWingsStraps,Binding straps
WingsWing1WingBone,Wing Bone
WingsWing1WingMembrane,Wing Membrane
WingsSeraphWingsBase1,Base1
WingsSeraphWingsBase2,Base2
WingsSeraphWingsBase3,Base3
WingsSeraphWingsWingBase1,Wing Base1
WingsSeraphWingsWingBase2,Wing Base2
WingsSeraphWingsWingBase3,Wing Base3
WingsSeraphWingsWingBase4,Wing Base4
WingsSeraphWingsWingBase5,Wing Base5
WingsSeraphWingsWingBase6,Wing Base6
WingsSeraphWingsWingTip1,Wing Tip1
WingsSeraphWingsWingTip2,Wing Tip2
WingsSeraphWingsWingTip3,Wing Tip3
WingsSeraphWingsWingTip4,Wing Tip4
WingsSeraphWingsWingTip5,Wing Tip5
WingsSeraphWingsWingTip6,Wing Tip6

1 BodyUpperLarge Body
3684 WingsDragonWingsStraps Binding straps
3685 WingsWing1WingBone Wing Bone
3686 WingsWing1WingMembrane Wing Membrane
3687 WingsSeraphWingsBase1 Base1
3688 WingsSeraphWingsBase2 Base2
3689 WingsSeraphWingsBase3 Base3
3690 WingsSeraphWingsWingBase1 Wing Base1
3691 WingsSeraphWingsWingBase2 Wing Base2
3692 WingsSeraphWingsWingBase3 Wing Base3
3693 WingsSeraphWingsWingBase4 Wing Base4
3694 WingsSeraphWingsWingBase5 Wing Base5
3695 WingsSeraphWingsWingBase6 Wing Base6
3696 WingsSeraphWingsWingTip1 Wing Tip1
3697 WingsSeraphWingsWingTip2 Wing Tip2
3698 WingsSeraphWingsWingTip3 Wing Tip3
3699 WingsSeraphWingsWingTip4 Wing Tip4
3700 WingsSeraphWingsWingTip5 Wing Tip5
3701 WingsSeraphWingsWingTip6 Wing Tip6

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -3,7 +3,7 @@ ClubCardVictory,0,,"Good work~ you have potential to be a great player, enjoy yo
ClubCardDefeat,,,Now time for my reward: [~More Coming Soon~],,
BattleSuccess,70,,"(She looks at you with hate in her eyes, but you can feel some weakness behind her bravado)",,
BattleFail,70,,Now time for my reward~,,
CompleteQuestRelief,,,"Finally! I can feel the essence you gathered. Good Work~ ",,
CompleteQuestRelief,,,"Finally! I can feel the essence you gathered. Good work~ ",,
0,,,(Her predatory gaze locks onto you as her nine tails swaying lazily behind her.) “Welcome~”,,
0,5,Who are you?,"(She smiles softly, though something dangerous lurks behind it.) “My name is Daji. Im a kitsune… and Ive been waiting for someone like you~”",,
0,30,Do you play club cards?,I enjoy them~ but if you want to play be ready~ I always play for something ,,
@ -11,21 +11,21 @@ CompleteQuestRelief,,,"Finally! I can feel the essence you gathered. Good Work~
5,10,What you want from me?,"“I have a task just for you.” (A glint of hunger flickers in her eyes.) “Collect the essence of nine students and bring it to me.”",,
10,15,And what's in it for me?,I will grand you some of kitsune powers,,
10,20,Forget it,You will regret this! (She gets ready to fight.),,
15,95,I will do it,Good~ then I will wait for you here.,StartQuest(),
15,95,I will do it,Good~ then I will wait for you here.,KitsuneStartQuest(),
15,20,Forget it,"(Her ears flatten, power crackling around her.) “Oh… you stupid little thing.”",,
20,90,(Run away),"Oh, you came back?",RunAway()
20,,(Fight her),,MagicBattleStart()
30,35,What are the stakes?,"If you win I will give you a card, but if you lose... I will tie you up and enjoy myself~",,
30,35,What are the stakes?,"If you win I will give you a card, but if you lose I will tie you up and enjoy myself~",,
35,,Let's play.,,ClubCardStart()
35,0,I dont want to risk,Shame~,,
70,110,(Reach for her power),"(You sense the weakness she hides and reach for it. Slowly, irresistibly, her power flows into you. She resists, but it is in vain. At last, she lies spent on the ground… and her power is yours.) [(~Kitsune tails unlocked~)]",GiveTails(),
70,110,(Reach for her power),"(You sense the weakness she hides and reach for it. Slowly, irresistibly, her power flows into you. She resists, but it is in vain. At last, she lies spent on the ground… and her power is yours.) [(~Kitsune tails unlocked~)]",GiveTails(),
90,,(Fight her),"(Her ears flatten, power crackling around her.) “Oh… you stupid little thing.”",MagicBattleStart(),
90,95,Wait! I want to work with you!,"(She smiles, clearly pleased.) “I knew youd make the right decision~”",StartQuest(),
95,100,How I'm supposed to do this?,"Go back to school, after you defeat students, when they are bound and helpless, use this spell. (She teaches you a spell to drain essence)",StartQuest(),"QuestStarted()"
100,,(Leave for School),"How long I need to wait? You are still missing LEFTDEFEATCOUNT students to defeat!!!",RunAway(),"!QuestCompleted()"
100,105,I did it!,"“Good work~” (A soft pink fog envelops you as she leans closer, her lips brushing your skin.) “Come… I will share secrets of my power~” (You hear her whisper and everything goes dark)",,"QuestCompleted()"
90,95,Wait! I want to work with you!,"(She smiles, clearly pleased.) “I knew youd make the right decision~”",KitsuneStartQuest(),
95,100,How I'm supposed to do this?,"Go back to school, after you defeat students, when they are bound and helpless, use this spell. (She teaches you a spell to drain essence)",KitsuneStartQuest(),"KitsuneQuestStarted()"
100,,(Leave for School),"How long I need to wait? You are still missing LEFTDEFEATCOUNT students to defeat!!!",RunAway(),"!KitsuneQuestCompleted()"
100,105,I did it!,"“Good work~” (A soft pink fog envelops you as she leans closer, her lips brushing your skin.) “Come… I will share secrets of my power~” (You hear her whisper and everything goes dark)",,"KitsuneQuestCompleted()"
105,130,(You look around), Daji is nowhere to be seen. Youre alone… yet you can feel your new power dwelling inside… and ready to be unleashed… [(~Kitsune tails unlocked~)],KitsuneDisappear(),
110,0,(Leave with your new powers),,RunAwayEnd()
105,130,(You look around), Daji is nowhere to be seen. Youre alone… yet you can feel your new power dwelling inside... and ready to be unleashed... [(~Kitsune tails unlocked~)],HideNPC(),
130,0,(Leave with your new powers),,RunAwayEnd()
200,210,(Struggle and test your bondage.),(She smiles and removes your gag.) You're cute when you struggle. I won't let you go that easily.,UngagPlayer(0),
200,210,(Bow your head and whimper silently.),(She smirks and removes your gag.) Such a cute subbie in bondage. I won't let you go easily.,UngagPlayer(-3),
@ -49,7 +49,7 @@ SpellHogtie,,I need to master that spell.,,LoserSpell(0),
SpellHogtie,,This is tight!,,LoserSpell(0),
SpellHogtie,,(Struggle playfully.),,LoserSpell(0),
SpellReleaseHogtieIntro,,,"(After many incantations, she successfully releases you from your hogtie, using her magic.)",,
SpellReleaseHogtie,,Thanks... I guess.,,LoserSpell(0),
SpellReleaseHogtie,,Thanks I guess.,,LoserSpell(0),
SpellReleaseHogtie,,Will you release me now?,,LoserSpell(0),
SpellFlyingHogtieIntro,,,"(She summons the spirits of bondage. You slowly start to move in the air in your hogtie. Going up and down, floating and helpless.)",,
SpellFlyingHogtie,,Weeeeeeeee!,,LoserSpell(0),

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

View file

@ -0,0 +1,38 @@
PlayerGagged,,,"(She smiles as she sees you gagged) My my, it seems like you had some fun dear. Mhm! But I can't understand you like this",,
TooRude,,,Seems like you're not as nice as I thought!,
TooRudeRepeat,,,Seems like you don't even learn from your previous mistakes,
0,,,"(As you stroll through the garden, a woman appears and waves at you)",,!TheresaQuestStarted()
0,,,"Don't know what to do? oh you silly, go to Maid Quarters and offer your help with chores, help with 6 rescue missions and return to me",,TheresaQuestIsOngoing()
0,,,"(On the place where the nun was, an angel now stands, looking at you)",,TheresaQuestCompleted()
0,5,Let me try again,"Alright, let's see if you improved…~",,TheresaBeenRudeBefore()
0,5,(Walk to the woman.),"Hello there dear, I am Theresa. So very nice to meet you!",,TheresaFirstMet()
0,22,"I've helped someone!","Oh, I'm glad to hear that. But a little birdie tells me there's still REMAINING people to help!",,TheresaQuestIsOngoing()
0,30,(You walk to the new girl.),"Oh welcome there cutie, you did what I asked?",,TheresaQuestCompleted()
0,100,"Hello? Theresa?","Oh! Welcome back DialogPlayerName, how have you been~ I hope you're enjoying my gift~",,TheresaTimerUp()
0,100,Where have you been?,,TheresaGiveBadWordPoint(""100""),TheresaTimerUp()
0,,(Leave her.),,DialogLeave(),
5,10,"Hello, nice to meet you too.","Hehe, you seem really sweet. I have a small favor to ask… and there might be something in it for you.",,
5,10,Why do you look so strange?,"I do? I'm from... somewhere far away... but since we met here, can you help me with something?",TheresaGiveBadWordPoint(""5""),
5,,"Nevermind, bye. (Leave her.)",,DialogLeave(),
10,20,"Sure, what would the favor be?",Can you help six people for me? I got lost in here and my time ran out so would you be so kind?,TheresaStartQuest(),
10,11,"Sounds suspicious, what do I get?","What is suspicious about helping others? And why should I spoil the fun! So… will you help me or not?",TheresaGiveBadWordPoint(""10""),
11,20,Okay I will help you.,"Okay then come back after you helped six different people, I heard the maids are always searching for helping hands~",TheresaStartQuest(),
11,12,"No, I only help when I know what is in it for me.",And I should spoil the mystery?,TheresaGiveBadWordPoint(""15""),
12,20,So how can I help you?,"Okay then come back after you helped six different people, I heard the maids always search for helping hands~",TheresaStartQuest(""bad""),
12,20,"Okay, Okay, what do you need?","Could you help six different people out, I heard the maids are always looking for some helping hands~",TheresaStartQuest(),
20,21,On my way,"Thank you so much! I'll be waiting for you here.",
21,22,"(You sigh) Okay, I guess I'll be back soon…","Thank you for your time!",
22,0,(You leave),(Leave.),DialogLeave(),
30,33,I like to help where I can.,"You did well! I am proud of you, let me reward you… (A bright light shines from above, bathing you in. You feel a warm power grow in you). You deserve this gift.",TheresaGiveGift(),
30,33,Wait… Who are you?,"I am still Theresa. You did well! I am proud of you, (She smiles and you recognise that smile, its really Theresa!)",TheresaGiveGift(),
33,34,What happened?,"You proven worthy to see my true form, but my time is short, please accept your gift ( A bright light shines upon you, you close your eyes enjoying the warmth gently enveloping you, it feels almost like a tender hug)"
34,35,(Open your eyes),"(You look around but Theresa is nowhere to be seen, you are alone but her warmth is still with you. You have a feeling you will be seeing her again)",HideTheresa(),
35,100,(Leave with your new gift.),,DialogLeave(),
100,,,I may have another task for you [~More Coming Soon~],,
LandingPage,DestinationPage,ButtonText,NpcAnswer,CommandToHappen(),PrerequisiteCheck()
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -1,23 +1,39 @@
"use strict";
var MagicSchoolFindsAroundBackground = "ForestPath";
var MagicSchoolFindsAroundBackground = "Castle";
/** @type {"" | "Garden" | "Forest"} */
var MagicSchoolFindsAroundArea = "";
/** @type {NPCCharacter} */
// This cursed thing is because I can't use @ts-expect-error here, as non-strict TS flags it
// but not doing that causes 30 strictness errors
var MagicSchoolFindsAroundKitsune = /** @type {NPCCharacter} */ (/** @type {unknown} */ (null));
var MagicSchoolFindsAroundKitsune = /** @type {never} */ (null);
/** @type {NPCCharacter} */
var MagicSchoolFindsAroundTheresa = /** @type {never} */ (null);
var MagicSchoolFindsAroundSpellCount = 0;
var MagicSchoolFindsAroundLastSpell = "";
/** @type {MagicSchoolSpell | undefined} */
var MagicSchoolFindsAroundLastSpell;
//Angel Nun variables
var AngelNunOutfit = "";
var CurrentAngelNunName = "Therese";
var CurrentAngelNunStage = "0";
/** @satisfies {Record<string, RectTuple>} */
var MagicSchoolFindsAroundButtons = ({
exit: [1885, 25, 90, 90],
profile: [1885, 145, 90, 90],
goToGarden: [1885, 265, 90, 90],
goToForest: [1885, 385, 90, 90],
soloCharacter: [750, 0, 500, 1000],
dualCharacterFirst: [500, 0, 500, 1000],
dualCharacterSecond: [1000, 0, 500, 1000],
});
/**
* Uncompress a string containing an appearance, then applies that appearance data to the NPC
* @param {NPCCharacter} C - The NPC character that loads its new appearance
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundPrepareFoundNPC(C) {
function MagicSchoolFindsAroundDressUpKitsune(C) {
CharacterNaked(C, false);
CharacterRelease(C, false);
// BASE APPEARANCE
InventoryWear(C, "EchoV2", "BodyStyle", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Eyebrows1", "Eyebrows", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "NoEars", "Head", undefined, undefined, undefined, undefined, false);
@ -79,21 +95,120 @@ function MagicSchoolFindsAroundPrepareFoundNPC(C) {
CharacterRefresh(C);
}
/**
* Uncompress a string containing an appearance, then applies that appearance data to the NPC
* @param {NPCCharacter} C - The NPC character that loads its new appearance
* @param {"Angel" | "Nun"} outfit - The outfit to use
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundDressUpTheresa(C, outfit) {
CharacterNaked(C, false);
CharacterRelease(C, false);
switch (outfit) {
case "Angel": {
InventoryWear(C, "Original", "BodyStyle", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Eyebrows1", "Eyebrows", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Default", "Head", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Normal", "BodyLower", "White", undefined, undefined, undefined, false);
InventoryWear(C, "XLarge", "BodyUpper", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "H0900", "Height", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Regular", "Mouth", ["#A68096", "Default"], undefined, undefined, undefined, false);
InventoryWear(C, "HairBack80", "HairBack", ["#DCBB19", "#7486C7", "#3D3D81", "#524ABB"], undefined, undefined, undefined, false);
InventoryWear(C, "HairFront64", "HairFront", ["#DCBB19", "#67B3B1"], undefined, undefined, undefined, false);
InventoryWear(C, "Eyes11", "Eyes", ["#7EDBE3"], undefined, undefined, undefined, false);
InventoryWear(C, "Eyes11", "Eyes2", ["#3645BA"], undefined, undefined, undefined, false);
// Angel accessories and clothing
InventoryWear(C, "Panties14", "Panties", ["#CBE9E6"], undefined, undefined, undefined, false);
InventoryWear(C, "SleevelessSlimLatexLeotard", "Bra", ["#A4A4A4"], undefined, undefined, undefined, false);
InventoryWear(C, "RuffledSkirt", "ClothLower", ["#898989"], undefined, undefined, undefined, false);
InventoryWear(C, "Stockings2", "Socks", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "SeraphWings", "Wings", ["#868383", "#868383", "#868383", "#868383", "#868383", "#868383", "#868383", "#868383", "#868383", "#969797", "#969797", "#969797", "#969797", "#969797", "#969797"], undefined, undefined, undefined, false);
InventoryWear(C, "ShoulderlessTop", "Cloth", ["#828282"], undefined, undefined, undefined, false);
InventoryWear(C, "TightCorset", "Corset", ["#D9D9D9", "#ADADAD"], undefined, undefined, undefined, false);
InventoryWear(C, "FaceScars", "BodyMarkings", ["#EEE08C"], undefined, undefined, undefined, false);
InventoryWear(C, "BodyChainNecklace", "Necklace", ["#D2B51A", "#D2B51A"], undefined, undefined, undefined, false);
InventoryWear(C, "WitchShawl", "ClothAccessory", ["#B0B5FF", "#B0B5FF", "#B0B5FF", "#B0B5FF", "#B0B5FF", "#B0B5FF", "#B0B5FF"], undefined, undefined, undefined, false);
// HALO
const halo = InventoryWear(C, "Halo", "HairAccessory1", ["#FDF8EE", "#FFEB87", "#FFD800"], undefined, undefined, undefined, false);
if (halo) {
halo.Property ??= {};
Object.assign(halo.Property, { Opacity: 0.85});
}
break;
}
case "Nun": {
InventoryWear(C, "EchoV2", "BodyStyle", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Eyebrows1", "Eyebrows", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Default", "Head", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Normal", "BodyLower", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Large", "BodyUpper", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "H0940", "Height", undefined, undefined, undefined, undefined, false);
InventoryWear(C, "Regular", "Mouth", ["#BE737E", "Default"], undefined, undefined, undefined, false);
InventoryWear(C, "HairBack76b", "HairBack", ["#5A1D1D"], undefined, undefined, undefined, false);
InventoryWear(C, "HairFront25", "HairFront", ["#5A1D1D"], undefined, undefined, undefined, false);
InventoryWear(C, "Eyes11", "Eyes", ["#7EDBE3"], undefined, undefined, undefined, false);
InventoryWear(C, "Eyes11", "Eyes2", ["#3645BA"], undefined, undefined, undefined, false);
// Angel accessories and clothing
InventoryWear(C, "StringPasty1", "Panties", ["#181818"], undefined, undefined, undefined, false);
InventoryWear(C, "StrapBra", "Bra", ["#2B2B2B"], undefined, undefined, undefined, false);
InventoryWear(C, "LongFishnets", "Socks", ["#121212"], undefined, undefined, undefined, false);
InventoryWear(C, "Socks5", "SocksLeft", ["#222222"], undefined, undefined, undefined, false);
InventoryWear(C, "Socks5", "SocksRight", ["#222222"], undefined, undefined, undefined, false);
InventoryWear(C, "NunRobes", "Cloth", ["#494949", "Default", "Default", "#424242"], undefined, undefined, undefined, false);
InventoryWear(C, "Corset1", "Corset", ["#1C1C1C"], undefined, undefined, undefined, false);
InventoryWear(C, "Glitter", "Mask", ["#E3C6B6", "#E3C6B6"], undefined, undefined, undefined, false);
InventoryWear(C, "AnkleStrapShoes", "Shoes", ["#381717"], undefined, undefined, undefined, false);
InventoryWear(C, "NunVeil", "Hat", ["Default", "#343434", "#515151"], undefined, undefined, undefined, false);
InventoryWear(C, "Gloves2", "Gloves", ["#222222"], undefined, undefined, undefined, false);
InventoryWear(C, "Wings", "EyeShadow", ["#919F9E", "#131313"], undefined, undefined, undefined, false);
// JEWEL
const jewel = InventoryWear(C, "JewelrySet", "Jewelry", ["#908B3A", "#908B3A", "#908B3A"], undefined, undefined, undefined, false);
if (jewel) {
jewel.Property ??= {};
Object.assign(jewel.Property, { TypeRecord: {e: 3, a: 3, n: 0, f: 0} });
}
}
}
CharacterRefresh(C);
}
// #region Screen management
/**
* Loads the magic school finds around screen and the NPC
* @type {ScreenLoadHandler}
*/
async function MagicSchoolFindsAroundLoad() {
if (MagicSchoolFindsAroundKitsune == null) {
// Load Kitsune NPC and prepare her appearance
MagicSchoolFindsAroundKitsune = CharacterLoadNPC("NPC_MagicSchoolFindsAround_Kitsune");
MagicSchoolFindsAroundPrepareFoundNPC(MagicSchoolFindsAroundKitsune);
MagicSchoolFindsAroundDressUpKitsune(MagicSchoolFindsAroundKitsune);
// FIXME: janky wait to make sure the dialog's done loading
await CommonWaitFor(() => MagicSchoolFindsAroundKitsune.Dialog.length !== 0);
MagicSchoolFindsAroundKitsune.LabelColor = "#4E1313";
MagicSchoolFindsAroundKitsune.AllowItem = false;
MagicSchoolFindsAroundKitsune.Name = "Daji";
MagicSchoolFindsAroundKitsune.Stage = "0";
delete MagicSchoolFindsAroundKitsune.FixedImage;
MagicSchoolFindsAroundKitsuneQuestUpdate();
}
MagicSchoolLaboratoryKitsuneQuestUpdate();
if (MagicSchoolFindsAroundTheresa == null) {
MagicSchoolFindsAroundTheresa = CharacterLoadNPC("NPC_MagicSchoolFindsAround_Theresa");
// FIXME: janky wait to make sure the dialog's done loading
await CommonWaitFor(() => MagicSchoolFindsAroundTheresa.Dialog.length !== 0);
MagicSchoolFindsAroundTheresa.LabelColor = "#5FEBE8";
MagicSchoolFindsAroundTheresa.AllowItem = false;
}
MagicSchoolFindsAroundTheresaQuestUpdate();
}
/**
@ -101,11 +216,51 @@ async function MagicSchoolFindsAroundLoad() {
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundRun() {
// Draw the background and the characters
DrawCharacter(Player, 500, 0, 1);
DrawCharacter(MagicSchoolFindsAroundKitsune, 1000, 0, 1);
DrawButton(1885, 25, 90, 90, "", Player.CanWalk() ? "White" : "Pink", "Icons/Exit.png", TextGet("Exit"));
DrawButton(1885, 145, 90, 90, "", "White", "Icons/Character.png", TextGet("Profile"));
if (MagicSchoolFindsAroundArea === "") {
/** @type {RectTuple} */
const introRect = [100, 800, 1782, 200];
DrawTextWrap(TextGet("ScreenIntro"), ...(RectGetFrame(RectOffset(RectMakeRect(...introRect), 2, 2))), "Black");
DrawTextWrap(TextGet("ScreenIntro"), ...introRect, "White");
}
DrawButton(...MagicSchoolFindsAroundButtons.exit, "", Player.CanWalk() ? "White" : "Pink", "Icons/Exit.png", TextGet("Exit"));
DrawButton(...MagicSchoolFindsAroundButtons.profile, "", "White", "Icons/Character.png", TextGet("Profile"));
if (MagicSchoolFindsAroundArea === "") {
DrawButton(...MagicSchoolFindsAroundButtons.goToGarden, "", "White", "Icons/Flower.png", TextGet("GoToGarden"));
DrawButton(...MagicSchoolFindsAroundButtons.goToForest, "", "White", "Icons/Tree.png", TextGet("GoToForest"));
} else if (MagicSchoolFindsAroundArea == "Forest") {
if (MagicSchoolFindsAroundKitsune) {
DrawCharacter(Player, ...RectGetOrigin(MagicSchoolFindsAroundButtons.dualCharacterFirst), 1);
DrawCharacter(MagicSchoolFindsAroundKitsune, ...RectGetOrigin(MagicSchoolFindsAroundButtons.dualCharacterSecond), 1);
}
} else if (MagicSchoolFindsAroundArea == "Garden") {
if (MagicSchoolFindsAroundTheresa && !MagicSchoolFindsAroundTheresaVanished()) {
DrawCharacter(Player, ...RectGetOrigin(MagicSchoolFindsAroundButtons.dualCharacterFirst), 1);
DrawCharacter(MagicSchoolFindsAroundTheresa, ...RectGetOrigin(MagicSchoolFindsAroundButtons.dualCharacterSecond), 1);
} else {
DrawCharacter(Player, ...RectGetOrigin(MagicSchoolFindsAroundButtons.soloCharacter), 1);
}
}
}
/**
*
* @param {"" | "Forest" | "Garden"} screenName
*/
function MagicSchoolFindsAroundChangeScreen(screenName) {
MagicSchoolFindsAroundArea = screenName;
if (MagicSchoolFindsAroundArea == "Forest") {
MagicSchoolFindsAroundBackground = "ForestPath";
if (MagicSchoolFindsAroundKitsune) {
CharacterSetCurrent(MagicSchoolFindsAroundKitsune);
}
} else if (MagicSchoolFindsAroundArea == "Garden") {
MagicSchoolFindsAroundBackground = "Garden1";
if (MagicSchoolFindsAroundTheresa && !MagicSchoolFindsAroundTheresaVanished()) {
CharacterSetCurrent(MagicSchoolFindsAroundTheresa);
}
} else {
MagicSchoolFindsAroundBackground = "Castle";
}
}
/**
@ -113,26 +268,205 @@ function MagicSchoolFindsAroundRun() {
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundClick() {
if (MouseIn(...MagicSchoolFindsAroundButtons.exit) && Player.CanWalk()) {
if (MagicSchoolFindsAroundArea !== "") {
MagicSchoolFindsAroundChangeScreen("");
} else {
CommonSetScreen("Room", "MagicSchoolLaboratory");
}
}
if (MouseIn(...MagicSchoolFindsAroundButtons.profile)) {
InformationSheetLoadCharacter(Player);
}
if (MagicSchoolFindsAroundArea === "") {
if (MouseIn(...MagicSchoolFindsAroundButtons.goToGarden)) {
MagicSchoolFindsAroundChangeScreen("Garden");
return;
}
if (MouseIn(...MagicSchoolFindsAroundButtons.goToForest)) {
MagicSchoolFindsAroundChangeScreen("Forest");
MagicSchoolFindsAroundKitsuneQuestUpdate();
return;
}
}
// Check for clicks on the characters
if (MouseIn(500, 0, 500, 1000)) CharacterSetCurrent(Player);
if (MouseIn(1000, 0, 500, 1000)) CharacterSetCurrent(MagicSchoolFindsAroundKitsune,);
if (MouseIn(1885, 25, 90, 90) && Player.CanWalk()) CommonSetScreen("Room", "MagicSchoolLaboratory");
if (MouseIn(1885, 145, 90, 90)) InformationSheetLoadCharacter(Player);
if (MagicSchoolFindsAroundArea === "") {
if (MouseIn(...MagicSchoolFindsAroundButtons.soloCharacter)) {
CharacterSetCurrent(Player);
}
} else if (MagicSchoolFindsAroundArea === "Forest") {
if (MouseIn(...MagicSchoolFindsAroundButtons.dualCharacterFirst)) {
CharacterSetCurrent(Player);
}
if (MouseIn(...MagicSchoolFindsAroundButtons.dualCharacterSecond)) {
CharacterSetCurrent(MagicSchoolFindsAroundKitsune);
}
} else if (MagicSchoolFindsAroundArea === "Garden") {
if (MagicSchoolFindsAroundTheresaVanished()) {
if (MouseIn(...MagicSchoolFindsAroundButtons.soloCharacter)) {
CharacterSetCurrent(Player);
}
} else {
if (MouseIn(...MagicSchoolFindsAroundButtons.dualCharacterFirst)) {
CharacterSetCurrent(Player);
}
if (MouseIn(...MagicSchoolFindsAroundButtons.dualCharacterSecond)) {
CharacterSetCurrent(MagicSchoolFindsAroundTheresa);
}
}
}
}
// #endregion
// #region Shared
/**
* Sets a boolean flag on the player to indicate they have learned about the prizes
* Returns the fully initialized and validated parameters for the FindsAround game
* @returns {Required<GameMagicSchoolFindsAroundParameters>} - Nothing
*/
function MagicSchoolFindsAroundGetData() {
if (!CommonIsObject(Player.Game.MagicSchoolFindsAround)) Player.Game.MagicSchoolFindsAround = {};
const data = /** @type {Required<GameMagicSchoolFindsAroundParameters>} */ (Player.Game.MagicSchoolFindsAround);
data.KitsuneQuestProgress = CommonClamp(data.KitsuneQuestProgress ?? -1, -1, 9);
data.TheresaQuestProgress = CommonClamp(data.TheresaQuestProgress ?? -1, -1, 6);
data.TheresaBadWords = data.TheresaBadWords ?? [];
data.TheresaHideUntil = data.TheresaHideUntil ?? 0;
return data;
}
/**
* Gives the player the reward tails
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundLearnAboutPrizes() {}
function MagicSchoolFindsAroundGiveTails() {
InventoryAdd(Player, "KitsuneTailStraps", "TailStraps");
}
/**
* Gives the player the reward wings
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundGiveWings() {
InventoryAdd(Player, "SeraphWings", "Wings");
}
/**
* Triggered when the player lost and get untied by the Kitsune, can affect reputation
* @param {string} RepChange
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundReleasePlayer(RepChange) {
DialogChangeReputation("Dominant", CommonParseInt(RepChange) ?? 0);
CharacterRelease(Player);
}
/**
* Returns the player in the main hall in her current bondage
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundPlayerMainHall() {
DialogLeave();
CommonSetScreen("Room", "MainHall");
}
// #endregion
// #region Kitsune
/**
* Starts the quest to gather essences for Kitsune
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundKitsuneStartQuest() {
const data = MagicSchoolFindsAroundGetData();
data.KitsuneQuestProgress = 0;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
MagicSchoolFindsAroundKitsuneQuestUpdate();
}
/**
* Return the current progress of the Kitsune quest
* @returns {number}
*/
function MagicSchoolFindsAroundKitsuneGetQuestProgress() {
const data = MagicSchoolFindsAroundGetData();
return data.KitsuneQuestProgress ?? -1;
}
/**
* Is the Kitsune quest in-progress?
* @returns {boolean} - True if in progress
*/
function MagicSchoolFindsAroundKitsuneQuestStarted() {
return MagicSchoolFindsAroundKitsuneGetQuestProgress() >= 0;
}
/**
* Is the Kitsune quest complete?
* @returns {boolean} - True if completed
*/
function MagicSchoolFindsAroundKitsuneQuestCompleted() {
return MagicSchoolFindsAroundKitsuneGetQuestProgress() >= 9;
}
/**
* Magic School Finds Around Kitsune Quest in progress?
* True if started but not completed (08)
* @returns {boolean}
*/
function DialogKitsuneQuestInProgress() {
const p = MagicSchoolFindsAroundKitsuneGetQuestProgress();
return p >= 0 && p < 9;
}
/**
* Give player essence from defeated student
* @param {string} Amount - The amount of essence to give
* @returns {void} - Nothing
*/
function DialogKitsuneGiveEssence(Amount) {
if (!CurrentCharacter) return;
DialogRemove();
PoseSetActive(CurrentCharacter, 'Kneel');
const data = MagicSchoolFindsAroundGetData();
data.KitsuneQuestProgress += CommonParseInt(Amount) ?? 0;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
MagicSchoolFindsAroundKitsuneQuestUpdate();
}
function MagicSchoolFindsAroundKitsuneDisappear() {
DialogHideNPC(MagicSchoolFindsAroundKitsune);
MagicSchoolFindsAroundGiveTails();
}
/**
* Update the Kitsune NPC's quest status as it progresses
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundKitsuneQuestUpdate() {
if (MagicSchoolFindsAroundKitsune == null) return;
if (!MagicSchoolFindsAroundKitsuneQuestStarted()) return;
let Defeats = MagicSchoolFindsAroundKitsuneGetQuestProgress();
// Quest already started, so set the state directly
if (Defeats !== -1) MagicSchoolFindsAroundKitsune.Stage = "100";
if (Defeats < 0) Defeats = 0;
let MissingDefeats = 9 - Defeats;
if (MissingDefeats !== 0) {
MagicSchoolFindsAroundKitsune.CurrentDialog = DialogFind(MagicSchoolFindsAroundKitsune, "100").replace("LEFTDEFEATCOUNT", MissingDefeats.toString());
} else {
MagicSchoolFindsAroundKitsune.CurrentDialog = DialogFind(MagicSchoolFindsAroundKitsune, "CompleteQuestRelief");
}
}
/**
* Starts a magic battle with the Kitsune NPC
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundMagicBattleStart() {
MagicBattleStart(MagicSchoolFindsAroundKitsune,9,MagicSchoolLaboratoryBackground,"MagicSchoolFindsAroundKitsuneMagicBattleEnd");
MagicBattleStart(MagicSchoolFindsAroundKitsune, 9, MagicSchoolLaboratoryBackground, "MagicSchoolFindsAroundKitsuneMagicBattleEnd");
}
/**
@ -172,10 +506,11 @@ function MagicSchoolFindsAroundClubCardStart() {
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundClubCardEnd() {
CommonSetScreen("Room", "MagicSchoolFindsAround");
CharacterSetCurrent(MagicSchoolFindsAroundKitsune);
if (!CurrentCharacter) return;
CurrentCharacter.CurrentDialog = DialogFind(CurrentCharacter, MiniGameVictory ? "ClubCardVictory" : "ClubCardDefeat");
CommonSetScreen("Room", "MagicSchoolFindsAround").then(() => {
CharacterSetCurrent(MagicSchoolFindsAroundKitsune);
if (!CurrentCharacter) return;
CurrentCharacter.CurrentDialog = DialogFind(CurrentCharacter, MiniGameVictory ? "ClubCardVictory" : "ClubCardDefeat");
});
}
/**
@ -193,8 +528,7 @@ function MagicSchoolFindsAroundRunAway() {
*/
function MagicSchoolFindsAroundRunAwayEnd() {
DialogLeave();
MagicSchoolFindsAroundKitsune.Name = "Daji";
delete MagicSchoolFindsAroundKitsune.FixedImage;
DialogRevealNPC(MagicSchoolFindsAroundKitsune);
CharacterRelease(MagicSchoolFindsAroundKitsune);
PoseSetActive(MagicSchoolFindsAroundKitsune, 'BaseLower');
MagicSchoolFindsAroundGiveTails();
@ -207,69 +541,6 @@ function MagicSchoolFindsAroundRunAwayEnd() {
CommonSetScreen("Room", "MagicSchoolLaboratory");
}
/**
* Starts the quest to gather essences
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundStartQuest() {
const data = MagicSchoolFindsAroundGetData();
data.KitsuneQuestProgress = 0;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
}
/**
* Return the current progress of the quest
* @returns {number}
*/
function MagicSchoolFindsAroundKitsuneGetQuestProgress() {
const data = MagicSchoolFindsAroundGetData();
return data.KitsuneQuestProgress ?? -1;
}
/**
* Quest in-progress?
* @returns {boolean} - True if in progress
*/
function MagicSchoolFindsAroundQuestStarted() {
return MagicSchoolFindsAroundKitsuneGetQuestProgress() >= 0;
}
/**
* Quest completed?
* @returns {boolean} - True if completed
*/
function MagicSchoolFindsAroundQuestCompleted() {
return MagicSchoolFindsAroundKitsuneGetQuestProgress() >= 9;
}
/**
* Returns the fully initialized and validated parameters for the FindsAround game
* @returns {Required<GameMagicSchoolFindsAroundParameters>} - Nothing
*/
function MagicSchoolFindsAroundGetData() {
if (!CommonIsObject(Player.Game.MagicSchoolFindsAround)) Player.Game.MagicSchoolFindsAround = {};
const data = /** @type {Required<GameMagicSchoolFindsAroundParameters>} */ (Player.Game.MagicSchoolFindsAround);
data.KitsuneQuestProgress = CommonClamp(data.KitsuneQuestProgress ?? -1, -1, 9);
return data;
}
/**
* Gives the player the reward tails
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundGiveTails() {
InventoryAdd(Player, "KitsuneTailStraps", "TailStraps");
}
/** Hide the NPC
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundHideNPC() {
MagicSchoolFindsAroundGiveTails();
MagicSchoolFindsAroundKitsune.Name = "";
MagicSchoolFindsAroundKitsune.FixedImage = "Screens/Room/MovieStudio/Empty.png";
}
/**
* Triggered when the player lost and get ungagged by the Kitsune, can affect reputation
* @param {string} RepChange
@ -299,129 +570,153 @@ function MagicSchoolFindsAroundLoserSpell(RepChange) {
return;
}
// Finds a valid spell based on the player current predicament. Some spells can only be done by specific houses.
let Spell = "";
while (Spell == "") {
Spell = CommonRandomItemFromList(MagicSchoolFindsAroundLastSpell, ["Hogtie", "ReleaseHogtie", "FlyingHogtie", "Arousal", "Tickle", "Pain", "SwitchRope", "SwitchChain", "Fail", "Tight"]);
if ((Spell == "Hogtie") && Player.PoseMapping.BodyFull === "Hogtied") Spell = "";
if ((Spell == "ReleaseHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = "";
if ((Spell == "FlyingHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = "";
if ((Spell == "SwitchRope") && ((InventoryGet(Player, "ItemArms")?.Asset.Name == "HempRope") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = "";
if ((Spell == "SwitchChain") && ((InventoryGet(Player, "ItemArms")?.Asset.Name == "Chains") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = "";
if ((Spell == "Arousal") && (MagicSchoolFindsAroundKitsune.House != "Maiestas")) Spell = "";
if ((Spell == "FlyingHogtie") && (MagicSchoolFindsAroundKitsune.House != "Vincula")) Spell = "";
if ((Spell == "Tickle") && (MagicSchoolFindsAroundKitsune.House != "Amplector")) Spell = "";
if ((Spell == "Pain") && (MagicSchoolFindsAroundKitsune.House != "Corporis")) Spell = "";
}
// Applies the spell effect
if (Spell == "Arousal") { CharacterSetFacialExpression(Player, "Blush", "High", 8); CharacterSetFacialExpression(Player, "Eyes", "Horny", 8); }
if (Spell == "Tickle") { CharacterSetFacialExpression(Player, "Blush", "Medium", 8); CharacterSetFacialExpression(Player, "Eyes", "Surprised", 8); }
if (Spell == "Pain") { CharacterSetFacialExpression(Player, "Blush", "Medium", 8); CharacterSetFacialExpression(Player, "Eyes", "Closed", 8); }
if (Spell == "Tight") { CharacterSetFacialExpression(Player, "Blush", "Low", 8); CharacterSetFacialExpression(Player, "Eyes", "Closed", 8); }
if (Spell == "Fail") { CharacterSetFacialExpression(MagicSchoolFindsAroundKitsune, "Blush", "Medium", 8); CharacterSetFacialExpression(MagicSchoolFindsAroundKitsune, "Eyes", "Angry", 8); }
if (Spell == "FlyingHogtie") {
const item = InventoryGet(Player, "ItemArms");
if (item) {
TypedItemSetOptionByName(Player, item, "SuspensionHogtied");
const Height = 0.67 * Math.random();
item.Property ??= {};
item.Property.OverrideHeight = {
Height: Height * (Pose.find(p => p.Name === "Hogtied")?.OverrideHeight?.Height ?? 1),
HeightRatioProportion: Height,
Priority: 0,
};
}
CharacterSetFacialExpression(Player, "Blush", "High", 8);
CharacterSetFacialExpression(Player, "Eyes", "Surprised", 8);
}
if (Spell == "Hogtie") {
TypedItemSetOptionByName(Player, "ItemArms", "Hogtied");
}
if (Spell == "ReleaseHogtie") {
TypedItemSetOptionByName(Player, "ItemArms", "Basic");
}
if (Spell == "SwitchRope") {
if (InventoryGet(Player, "ItemLegs") != null) InventoryWear(Player, "HempRope", "ItemLegs");
if (InventoryGet(Player, "ItemFeet") != null) InventoryWear(Player, "HempRope", "ItemFeet");
if (InventoryGet(Player, "ItemTorso") != null) InventoryWear(Player, "HempRopeHarness", "ItemTorso");
if (InventoryGet(Player, "ItemArms") != null) InventoryWear(Player, "HempRope", "ItemArms");
}
if (Spell == "SwitchChain") {
if (InventoryGet(Player, "ItemLegs") != null) InventoryWear(Player, "Chains", "ItemLegs");
if (InventoryGet(Player, "ItemFeet") != null) InventoryWear(Player, "Chains", "ItemFeet");
if (InventoryGet(Player, "ItemTorso") != null) InventoryWear(Player, "CrotchChain", "ItemTorso");
if (InventoryGet(Player, "ItemArms") != null) InventoryWear(Player, "Chains", "ItemArms");
}
if ((Spell == "FlyingHogtie") || (Spell == "Hogtie") || (Spell == "ReleaseHogtie") || (Spell == "SwitchRope") || (Spell == "SwitchChain")) CharacterRefresh(Player);
const Spell = MagicSchoolLaboratoryApplyRandomSpellEffects(MagicSchoolFindsAroundKitsune, MagicSchoolFindsAroundLastSpell);
// Shows the spell dialog
MagicSchoolFindsAroundLastSpell = Spell;
MagicSchoolFindsAroundKitsune.Stage = "Spell" + Spell;
MagicSchoolFindsAroundSpellCount++;
MagicSchoolFindsAroundKitsune.CurrentDialog = DialogFind(MagicSchoolFindsAroundKitsune, "Spell" + Spell + "Intro");
}
// #endregion Kitsune
// #region Theresa
/**
* Triggered when the player lost and get untied by the Kitsune, can affect reputation
* @param {string} RepChange
* Starts the quest to gather essences for Theresa
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundReleasePlayer(RepChange) {
DialogChangeReputation("Dominant", CommonParseInt(RepChange) ?? 0);
CharacterRelease(Player);
function MagicSchoolFindsAroundTheresaStartQuest() {
const data = MagicSchoolFindsAroundGetData();
if (data.TheresaTooRude && data.TheresaBadWords.length >= 3 ) {
MagicSchoolFindsAroundTheresa.Stage = "0";
MagicSchoolFindsAroundTheresa.CurrentDialog = DialogFind(MagicSchoolFindsAroundTheresa, "TooRudeRepeat");
data.TheresaBadWords = [];
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
return;
}
if (data.TheresaBadWords.length >= 3) {
MagicSchoolFindsAroundTheresa.Stage = "0";
MagicSchoolFindsAroundTheresa.CurrentDialog = DialogFind(MagicSchoolFindsAroundTheresa, "TooRude");
data.TheresaTooRude = true;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
return;
}
data.TheresaQuestProgress = 0;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
MagicSchoolFindsAroundTheresaQuestUpdate();
}
/**
* Returns the player in the main hall in her current bondage
* Return the current progress of the Theresa quest
* @returns {number}
*/
function MagicSchoolFindsAroundTheresaGetQuestProgress() {
const data = MagicSchoolFindsAroundGetData();
return data.TheresaQuestProgress;
}
/** Whether the Theresa quest has started */
function MagicSchoolFindsAroundTheresaQuestStarted() { return MagicSchoolFindsAroundTheresaGetQuestProgress() !== -1; }
/** Whether the Theresa quest is ongoing */
function MagicSchoolFindsAroundTheresaQuestIsOngoing() { return MagicSchoolFindsAroundTheresaQuestStarted() && !MagicSchoolFindsAroundTheresaQuestCompleted(); }
/** Whether the Theresa quest is complete and can be rewarded */
function MagicSchoolFindsAroundTheresaQuestCompleted() { return MagicSchoolFindsAroundTheresaGetQuestProgress() >= 6; }
/** Whether it's the first time we meet Theresa */
function MagicSchoolFindsAroundTheresaFirstMet() { return !MagicSchoolFindsAroundTheresaQuestStarted() && !MagicSchoolFindsAroundTheresaBeenRudeBefore(); }
/** Whether we've been rude to Theresa already */
function MagicSchoolFindsAroundTheresaBeenRudeBefore() { return MagicSchoolFindsAroundGetData().TheresaTooRude && !MagicSchoolFindsAroundTheresaQuestStarted(); }
/** Whether we've been rude to Theresa already */
function MagicSchoolFindsAroundTheresaVanished() { return CurrentTime < MagicSchoolFindsAroundGetData().TheresaHideUntil; }
/** Whether the player owns the reward */
function MagicSchoolFindsAroundTheresaTimerUp() {
const data = MagicSchoolFindsAroundGetData();
return data.TheresaHideUntil !== 0 && CurrentTime >= data.TheresaHideUntil;
}
/**
* Update the Theresa NPC's quest status as it progresses
* @returns {void} - Nothing
*/
function MagicSchoolFindsAroundPlayerMainHall() {
DialogLeave();
CommonSetScreen("Room", "MainHall");
}
/**
* Magic School Finds Around Kitsune Quest in progress?
* True if started but not completed (08)
* @returns {boolean}
*/
function DialogKitsuneQuestInProgress() {
const p = MagicSchoolFindsAroundKitsuneGetQuestProgress();
return p >= 0 && p < 9;
}
/**
* Update the Kitsune NPC's quest status as it progresses
* @returns {void} - Nothing
*/
function MagicSchoolLaboratoryKitsuneQuestUpdate() {
if (MagicSchoolFindsAroundKitsune == null) return;
if (!MagicSchoolFindsAroundQuestStarted()) return;
let Defeats = MagicSchoolFindsAroundKitsuneGetQuestProgress();
// Quest already started, so set the state directly
if (Defeats !== -1) MagicSchoolFindsAroundKitsune.Stage = "100";
if (Defeats < 0) Defeats = 0;
let MissingDefeats = 9 - Defeats;
if (MissingDefeats !== 0) {
MagicSchoolFindsAroundKitsune.CurrentDialog = DialogFind(MagicSchoolFindsAroundKitsune, "100").replace("LEFTDEFEATCOUNT", MissingDefeats.toString());
function MagicSchoolFindsAroundTheresaQuestUpdate() {
if (MagicSchoolFindsAroundTheresa == null) return;
if (MagicSchoolFindsAroundTheresaQuestIsOngoing()) {
let helped = MagicSchoolFindsAroundTheresaGetQuestProgress();
if (helped < 0) helped = 0;
let remaining = 6 - helped;
const line = MagicSchoolFindsAroundTheresa.Dialog.find(({Stage, NextStage}) => Stage === "0" && NextStage === "22");
if (!line) {
console.error("failed to locate line");
} else {
line.Result = line.Result.replace(/(REMAINING|\d+)/, remaining.toString());
}
}
if (MagicSchoolFindsAroundTheresaTimerUp()) {
if (MagicSchoolFindsAroundTheresaVanished()) {
DialogHideNPC(MagicSchoolFindsAroundTheresa);
} else {
if (MagicSchoolFindsAroundTheresaGetQuestProgress() >= 6) {
DialogRevealNPC(MagicSchoolFindsAroundTheresa);
MagicSchoolFindsAroundDressUpTheresa(MagicSchoolFindsAroundTheresa, "Angel");
MagicSchoolFindsAroundTheresa.Name = "Theresa";
} else {
DialogRevealNPC(MagicSchoolFindsAroundTheresa);
MagicSchoolFindsAroundDressUpTheresa(MagicSchoolFindsAroundTheresa, "Nun");
MagicSchoolFindsAroundTheresa.Name = "Theresa";
}
}
} else if (MagicSchoolFindsAroundTheresaQuestCompleted()) {
MagicSchoolFindsAroundDressUpTheresa(MagicSchoolFindsAroundTheresa, "Angel");
if (MagicSchoolFindsAroundTheresa.Stage == "0") {
MagicSchoolFindsAroundTheresa.Name = "Angel";
} else {
MagicSchoolFindsAroundTheresa.Name = "Theresa";
}
} else {
MagicSchoolFindsAroundKitsune.CurrentDialog = DialogFind(MagicSchoolFindsAroundKitsune, "CompleteQuestRelief");
MagicSchoolFindsAroundDressUpTheresa(MagicSchoolFindsAroundTheresa, "Nun");
MagicSchoolFindsAroundTheresa.Name = "Theresa";
}
}
/**
* Give player essence from defeated student
* Give player essence from rescued person
* @param {string} Amount - The amount of essence to give
* @returns {void} - Nothing
*/
function DialogKitsuneGiveEssence(Amount) {
function DialogTheresaGiveEssence(Amount) {
if (!CurrentCharacter) return;
if (!MagicSchoolFindsAroundTheresaQuestIsOngoing()) return;
DialogRemove();
PoseSetActive(CurrentCharacter, 'Kneel');
const data = MagicSchoolFindsAroundGetData();
data.KitsuneQuestProgress += CommonParseInt(Amount) ?? 0;
data.TheresaQuestProgress += CommonParseInt(Amount) ?? 0;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
MagicSchoolFindsAroundTheresaQuestUpdate();
}
/**
* @param {string} stage
*/
function MagicSchoolFindsAroundTheresaGiveBadWordPoint(stage) {
const data = MagicSchoolFindsAroundGetData();
if (!data.TheresaBadWords.includes(stage)) {
data.TheresaBadWords.push(stage);
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
}
}
function MagicSchoolFindsAroundTheresaGiveGift() {
MagicSchoolFindsAroundGiveWings();
DrawFlashScreen("#FFFFFF", 2000, 300);
MagicSchoolFindsAroundTheresa.Name = "Theresa";
}
function MagicSchoolFindsAroundHideTheresa() {
DialogHideNPC(MagicSchoolFindsAroundTheresa);
const data = MagicSchoolFindsAroundGetData();
// Hide for 42 hours
data.TheresaHideUntil = CurrentTime + 42 * 60 * 60 * 1000;
data.TheresaQuestProgress = 7;
ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
MagicSchoolLaboratoryKitsuneQuestUpdate();
}

View file

@ -1,2 +1,5 @@
Exit,Back to the Magic School
Profile,Your Profile
ScreenIntro,"You leave the school and fresh air hits your face. You take a look around; there are many interesting places around. Close to the school you see a garden filled with flowers, and a bit further away you can see a forest brimming with magic."
GoToGarden,Check out the garden
GoToForest,Walk to the forest

1 Exit Back to the Magic School
2 Profile Your Profile
3 ScreenIntro You leave the school and fresh air hits your face. You take a look around; there are many interesting places around. Close to the school you see a garden filled with flowers, and a bit further away you can see a forest brimming with magic.
4 GoToGarden Check out the garden
5 GoToForest Walk to the forest

View file

@ -6,7 +6,8 @@ var MagicSchoolLaboratoryTeacher = null;
/** @type {null | NPCCharacter} */
var MagicSchoolLaboratoryStudent = null;
var MagicSchoolLaboratoryBattleWage = "";
var MagicSchoolLaboratoryLastSpell = "";
/** @type {MagicSchoolSpell | undefined} */
var MagicSchoolLaboratoryLastSpell;
var MagicSchoolLaboratorySpellCount = 0;
/**
@ -98,7 +99,7 @@ function MagicSchoolLaboratoryRun() {
DrawButton(1885, 145, 90, 90, "", "White", "Icons/Character.png", TextGet("Profile"));
if (!MagicSchoolLaboratoryInHouse("")) DrawButton(1885, 265, 90, 90, "", "White", "Icons/Wardrobe.png", TextGet("Dress"));
if (!MagicSchoolLaboratoryInHouse("")) DrawButton(1885, 385, 90, 90, "", "White", "Icons/Explore.png", TextGet("Explore"));
if (!MagicSchoolLaboratoryInHouse("")) DrawButton(1885, 505, 90, 90, "", "White", "Icons/Tree.png", TextGet("ExploreAround"));
if (!MagicSchoolLaboratoryInHouse("")) DrawButton(1885, 505, 90, 90, "", "White", "Icons/Castle.png", TextGet("ExploreAround"));
if (!MagicSchoolLaboratoryInHouse("")) DrawButton(1885, 625, 90, 90, "", "White", "Icons/Kidnap.png", TextGet("Escape"));
}
@ -442,34 +443,46 @@ function MagicSchoolLaboratoryReleasePlayer(RepChange) {
}
/**
* When the player lost a battle and the student tests a spell on her
* @returns {void} - Nothing
* @param {NPCCharacter} npc
*/
function MagicSchoolLaboratoryLoserSpell(RepChange) {
// If we must change the player dom/sub reputation
if ((RepChange != "") && (RepChange != "0")) DialogChangeReputation("Dominant", parseInt(RepChange));
// After many spells, the event ends CHANGE TO 5
if (MagicSchoolLaboratorySpellCount >= 5) {
MagicSchoolLaboratoryStudent.Stage = "240";
MagicSchoolLaboratoryStudent.CurrentDialog = DialogFind(MagicSchoolLaboratoryStudent, "SpellEnd");
return;
function MagicSchoolLaboratoryGetAllSpellsForNpc(npc) {
/** @type {MagicSchoolSpell[]} */
const allCommonSpells = ["Hogtie", "ReleaseHogtie", "SwitchRope", "SwitchChain", "Fail", "Tight"];
switch (npc.House) {
case "Maiestas":
allCommonSpells.push("Arousal");
break;
case "Vincula":
allCommonSpells.push("FlyingHogtie");
break;
case "Amplector":
allCommonSpells.push("Tickle");
break;
case "Corporis":
allCommonSpells.push("Pain");
break;
}
return allCommonSpells;
}
/**
* @param {NPCCharacter} npc
* @param {MagicSchoolSpell | undefined} lastSpell
*/
function MagicSchoolLaboratoryApplyRandomSpellEffects(npc, lastSpell) {
const allSpells = MagicSchoolLaboratoryGetAllSpellsForNpc(npc);
// Finds a valid spell based on the player current predicament. Some spells can only be done by specific houses.
let Spell = "";
while (Spell == "") {
Spell = CommonRandomItemFromList(MagicSchoolLaboratoryLastSpell, ["Hogtie", "ReleaseHogtie", "FlyingHogtie", "Arousal", "Tickle", "Pain", "SwitchRope", "SwitchChain", "Fail", "Tight"]);
if ((Spell == "Hogtie") && Player.PoseMapping.BodyFull === "Hogtied") Spell = "";
if ((Spell == "ReleaseHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = "";
if ((Spell == "FlyingHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = "";
if ((Spell == "SwitchRope") && ((InventoryGet(Player, "ItemArms").Asset.Name == "HempRope") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = "";
if ((Spell == "SwitchChain") && ((InventoryGet(Player, "ItemArms").Asset.Name == "Chains") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = "";
if ((Spell == "Arousal") && (MagicSchoolLaboratoryStudent.House != "Maiestas")) Spell = "";
if ((Spell == "FlyingHogtie") && (MagicSchoolLaboratoryStudent.House != "Vincula")) Spell = "";
if ((Spell == "Tickle") && (MagicSchoolLaboratoryStudent.House != "Amplector")) Spell = "";
if ((Spell == "Pain") && (MagicSchoolLaboratoryStudent.House != "Corporis")) Spell = "";
/** @type {MagicSchoolSpell | undefined} */
let Spell;
while (!Spell) {
Spell = CommonRandomItemFromList(lastSpell, allSpells);
if ((Spell == "Hogtie") && Player.PoseMapping.BodyFull === "Hogtied") Spell = undefined;
if ((Spell == "ReleaseHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = undefined;
if ((Spell == "FlyingHogtie") && Player.PoseMapping.BodyFull !== "Hogtied") Spell = undefined;
if ((Spell == "SwitchRope") && ((InventoryGet(Player, "ItemArms").Asset.Name == "HempRope") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = undefined;
if ((Spell == "SwitchChain") && ((InventoryGet(Player, "ItemArms").Asset.Name == "Chains") || Player.PoseMapping.BodyFull === "Hogtied")) Spell = undefined;
}
// Applies the spell effect
@ -477,7 +490,7 @@ function MagicSchoolLaboratoryLoserSpell(RepChange) {
if (Spell == "Tickle") { CharacterSetFacialExpression(Player, "Blush", "Medium", 8); CharacterSetFacialExpression(Player, "Eyes", "Surprised", 8); }
if (Spell == "Pain") { CharacterSetFacialExpression(Player, "Blush", "Medium", 8); CharacterSetFacialExpression(Player, "Eyes", "Closed", 8); }
if (Spell == "Tight") { CharacterSetFacialExpression(Player, "Blush", "Low", 8); CharacterSetFacialExpression(Player, "Eyes", "Closed", 8); }
if (Spell == "Fail") { CharacterSetFacialExpression(MagicSchoolLaboratoryStudent, "Blush", "Medium", 8); CharacterSetFacialExpression(MagicSchoolLaboratoryStudent, "Eyes", "Angry", 8); }
if (Spell == "Fail") { CharacterSetFacialExpression(npc, "Blush", "Medium", 8); CharacterSetFacialExpression(npc, "Eyes", "Angry", 8); }
if (Spell == "FlyingHogtie") {
const item = InventoryGet(Player, "ItemArms");
TypedItemSetOptionByName(Player, item, "SuspensionHogtied");
@ -508,14 +521,35 @@ function MagicSchoolLaboratoryLoserSpell(RepChange) {
if (InventoryGet(Player, "ItemTorso") != null) InventoryWear(Player, "CrotchChain", "ItemTorso");
if (InventoryGet(Player, "ItemArms") != null) InventoryWear(Player, "Chains", "ItemArms");
}
if ((Spell == "FlyingHogtie") || (Spell == "Hogtie") || (Spell == "ReleaseHogtie") || (Spell == "SwitchRope") || (Spell == "SwitchChain")) CharacterRefresh(Player);
if ((Spell == "FlyingHogtie") || (Spell == "Hogtie") || (Spell == "ReleaseHogtie") || (Spell == "SwitchRope") || (Spell == "SwitchChain")) {
CharacterRefresh(Player);
}
return Spell;
}
/**
* When the player lost a battle and the student tests a spell on her
* @returns {void} - Nothing
*/
function MagicSchoolLaboratoryLoserSpell(RepChange) {
// If we must change the player dom/sub reputation
if ((RepChange != "") && (RepChange != "0")) DialogChangeReputation("Dominant", parseInt(RepChange));
// After many spells, the event ends CHANGE TO 5
if (MagicSchoolLaboratorySpellCount >= 5) {
MagicSchoolLaboratoryStudent.Stage = "240";
MagicSchoolLaboratoryStudent.CurrentDialog = DialogFind(MagicSchoolLaboratoryStudent, "SpellEnd");
return;
}
const Spell = MagicSchoolLaboratoryApplyRandomSpellEffects(MagicSchoolLaboratoryStudent, MagicSchoolLaboratoryLastSpell);
// Shows the spell dialog
MagicSchoolLaboratoryLastSpell = Spell;
MagicSchoolLaboratoryStudent.Stage = "Spell" + Spell;
MagicSchoolLaboratorySpellCount++;
MagicSchoolLaboratoryStudent.CurrentDialog = DialogFind(MagicSchoolLaboratoryStudent, "Spell" + Spell + "Intro");
}
/**

View file

@ -462,6 +462,7 @@ function MaidQuartersRescuePay() {
MaidQuartersMaid.CurrentDialog = MaidQuartersMaid.CurrentDialog.replace("REPLACEMONEY", M.toString());
CharacterChangeMoney(Player, M);
IntroductionJobProgress("SubMaid");
DialogTheresaGiveEssence("1");
}
/**

View file

@ -5893,3 +5893,25 @@ function DialogKeyDown(event) {
function DialogMouseDown(event) {
if (CurrentCharacter) StruggleMouseDown(event);
}
/**
* Make an NPC invisible
* @param {NPCCharacter} npc
* @returns {void} - Nothing
*/
function DialogHideNPC(npc) {
npc.SavedName = npc.Name;
npc.Name = "";
npc.FixedImage = "Screens/Room/MovieStudio/Empty.png";
}
/**
* Make an NPC invisible
* @param {NPCCharacter} npc
* @returns {void} - Nothing
*/
function DialogRevealNPC(npc) {
npc.Name = npc.SavedName;
delete npc.SavedName;
delete npc.FixedImage;
}

View file

@ -1924,6 +1924,15 @@ function RectGetFrame(rect) {
return [rect.x, rect.y, rect.w, rect.h];
}
/**
* Get the rect's origin point
* @param {Rect | RectTuple} rect
* @return {[x: number, y: number]}
*/
function RectGetOrigin(rect) {
return Array.isArray(rect) ? [rect[0], rect[1]] : [rect.x, rect.y];
}
/**
* Offsets a rect by the given amount
* @param {Rect} rect

View file

@ -754,8 +754,6 @@ type BackgroundTag =
"Club" | "College" | "Regular house" | "Dungeon" | "Asylum" | "Pandora" | "Club Cards"
;
type MagicSchoolHouse = "Maiestas" | "Vincula" | "Amplector" | "Corporis";
interface ModuleScreens {
Character:
| "Appearance"
@ -2209,6 +2207,7 @@ interface NPCCharacter extends Character {
Event?: NPCEvent[];
Affection?: number;
Domination?: number;
SavedName?: string;
}
/** Movie Studio */
@ -3978,7 +3977,11 @@ interface GamePrisonParameters {
}
interface GameMagicSchoolFindsAroundParameters {
KitsuneQuestProgress?: number;
KitsuneQuestProgress?: number;
TheresaQuestProgress?: number;
TheresaBadWords?: string[];
TheresaTooRude?: boolean;
TheresaHideUntil?: number;
}
//#endregion
@ -4031,6 +4034,13 @@ interface GameGGTSParameters {
// #endregion
// #region Magic Battle & School stuff
type MagicSchoolHouse = "Maiestas" | "Vincula" | "Amplector" | "Corporis";
type MagicSchoolSpell = "Hogtie" | "ReleaseHogtie" | "FlyingHogtie" | "Arousal" | "Tickle" | "Pain" | "SwitchRope" | "SwitchChain" | "Fail" | "Tight";
// #endregion
// #region Audio
type AudioSoundEffect = [string, number];