Insanely huge initial commit

This commit is contained in:
2026-02-21 17:04:05 -08:00
parent 9cdd36191a
commit 613d75914a
22525 changed files with 4035207 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ArrowController : MonoBehaviour
{
// Left, down, up, right arrow sprites.
[SerializeField] public Sprite[] arrowSprites;
[SerializeField] public GameObject successObject;
[SerializeField] public GameObject failObject;
[SerializeField] public Image image;
public int key = 0;
public void Init()
{
image.sprite = arrowSprites[key];
}
public void Succeed()
{
GameObject o = Instantiate(successObject);
o.transform.position = transform.position;
o.transform.SetParent(this.transform);
image.color = Color.clear;
}
public void Fail()
{
GameObject o = Instantiate(failObject);
o.transform.position = transform.position;
o.transform.SetParent(this.transform);
image.color = Color.clear;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b3c1cb45c9b13247a4165a9c4bab279
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyLaserController : MonoBehaviour
{
[SerializeField] List<Color> colors;
[SerializeField] float fadeDuration; // seconds per color
int colorIndex = 0;
SpriteRenderer sprite;
float fadeTime = 0;
// Start is called before the first frame update
void Start()
{
sprite = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
sprite.color = Color.Lerp(colors[colorIndex], colors[(colorIndex+1)%colors.Count], fadeTime);
fadeTime += Time.deltaTime / fadeDuration;
if (fadeTime >= 1f) {
colorIndex = (colorIndex + 1) % colors.Count;
fadeTime = 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc4bcf9b6e935734ca56bf737321e78e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 84971b146ad33b84eb945d79a214dce1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using TinySaveAPI;
using System.Threading.Tasks;
// Enum index corresponds with stat index for that character.
public enum Employee {
Elaine,
Irida,
Clem,
Schroder
}
public enum Unlockable {
None,
IridaPlayable,
ClemPlayable,
SchroderPlayable,
Dialogue_Elaine_Voyeurism,
Dialogue_Elaine_Femdom,
Dialogue_Elaine_Foodplay,
Dialogue_Irida_Anal,
Dialogue_Irida_Boobies,
Dialogue_Irida_Oral,
Dialogue_Clem_FFM,
Dialogue_Clem_BadGirl,
Dialogue_Clem_Exploration,
Dialogue_Clem_Confession,
Dialogue_Schroder_Packing,
Dialogue_Schroder_Anal,
Dialogue_Schroder_Lapdance,
Dialogue_Schroder_Dom,
Backrooms,
}
public class EmployeeStats {
// TODO: Add performance-based stats for employees, such as
// Speed - how efficiently they complete timed tasks
// Appeal - affects chance of receiving tasks, and tip percentages
// Specialty - affects the chance and effectiveness of a special buff during gameplay.
// The buff varies by character and might even have different trigger conditions.
// Each employee should build a different amount of these stats per level.
// The starting energy that this employee has at the beginning of each shift.
// Should increase with employee level.
public int maxEnergy { get; set; } = 100;
// RPG-style level and experience. Completing a work day earns each employee EXP,
// depending on how well you did and how much energy they expended.
// The max level is 10.
// TODO: Write a formula for EXP given based on daily performance.
public int level { get; set; } = 1;
public int exp { get; set; } = 0;
// "Love" stat. Increases as you interact with the employee, and at the end of
// any shift based on their performance.
// This is the primary way to unlock sex scenes.
// TODO: Write a formula for interactions and unlock thresholds.
public int affinity { get; set; } = 0;
// Chosen hairstyle for the character.
public int hair { get; set; } = 0;
// Returns true iff the employee leveled up.
public bool GainExp(int newExp) {
exp += newExp;
bool leveledUp = false;
while (level <= expRequirement.Length && exp > expRequirement[level-1]) {
exp -= expRequirement[level - 1];
level += 1;
leveledUp = true;
}
return leveledUp;
}
public static int[] expRequirement = {
25, // to level 2
100,
300,
600,
1000,
1500,
3000,
5000,
10000 // to level 10
};
}
[System.Serializable]
public class GameData {
public int money = 0;
public int day = 1;
public EmployeeStats[] employeeStats = {
// Elaine
new EmployeeStats() {
maxEnergy = 100,
level = 1,
exp = 0,
affinity = 10,
hair = 0,
},
// Irida
new EmployeeStats() {
maxEnergy = 110,
level = 2,
exp = 0,
affinity = 10,
hair = 1,
},
// Clem
new EmployeeStats() {
maxEnergy = 60,
level = 3,
exp = 0,
affinity = -20,
hair = 2,
},
// Schroder
new EmployeeStats() {
maxEnergy = 200,
level = 5,
exp = 0,
affinity = 20,
hair = 3,
},
};
public HashSet<Unlockable> unlocked = new HashSet<Unlockable>() {
Unlockable.ClemPlayable,
Unlockable.IridaPlayable,
Unlockable.SchroderPlayable,
Unlockable.Dialogue_Clem_BadGirl,
};
public HashSet<Dialogue> viewedScenes = new HashSet<Dialogue>();
// Who's displayed in the game's main menu?
public Employee sidePiece = Employee.Elaine;
GameData() {
}
public static bool IsUnlocked(Unlockable u) {
return GLOBAL.unlocked.Contains(u);
}
public static void Unlock(Unlockable u) {
GLOBAL.unlocked.Add(u);
}
public static bool IsPlayerUnlocked(Employee e) {
switch (e) {
case Employee.Elaine:
return true;
case Employee.Irida:
return IsUnlocked(Unlockable.IridaPlayable);
case Employee.Clem:
return IsUnlocked(Unlockable.ClemPlayable);
case Employee.Schroder:
return IsUnlocked(Unlockable.SchroderPlayable);
}
return false;
}
public static EmployeeStats StatsOf(Employee e) {
return GLOBAL.employeeStats[(int)e];
}
public static GameData GLOBAL = new GameData();
public static void Save() {
Debug.Log("GAME SAVE!");
string loc = Application.persistentDataPath + "/save.ihob";
Debug.Log("TODO: Actually save the game");
}
public static bool Load() {
Debug.Log("GAME LOAD!");
string loc = Application.persistentDataPath + "/save.ihob";
if (!File.Exists(loc)) {
return false;
}
Debug.Log("TODO: Actually save the game");
return true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 141bb9a3f666c0042974689b3b6e2320
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,600 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueInteraction
{
// This is the name of whoever's talking.
public string name;
// This is the text being spoken.
public string text;
// Set this when you want completing this interaction to unlock something.
public Unlockable unlock = Unlockable.None;
// Reserved index -1 to mean "do not set".
// See VNObjectController for canonical lists.
public int backgroundIndex { get; set; } = -1;
public int audioClipIndex { get; set; } = -1;
public int musicClipIndex { get; set; } = -1;
public Body body1 { get; set; } = Body.None;
public Expression expression1 { get; set; } = Expression.None;
public int hair1 { get; set; } = 0;
public Effect effect1 { get; set; } = Effect.None;
public Body body2 { get; set; } = Body.None;
public int hair2 { get; set; } = 0;
public Expression expression2 { get; set; } = Expression.None;
public Effect effect2 { get; set; } = Effect.None;
public Body body3 { get; set; } = Body.None;
public int hair3 { get; set; } = 0;
public Expression expression3 { get; set; } = Expression.None;
public Effect effect3 { get; set; } = Effect.None;
public bool removeBody1 { get; set; } = false;
public bool removeBody2 { get; set; } = false;
public bool removeBody3 { get; set; } = false;
public DialogueInteraction(string name,
string text,
Unlockable unlock = Unlockable.None)
{
this.name = name;
this.text = text;
this.unlock = unlock;
}
}
public enum Dialogue
{
None,
// Default greetings when spinning up the Manager.
// One per chosen Side Piece.
Manager_Elaine1,
Manager_Elaine2,
Manager_Elaine3,
Manager_Irida1,
Manager_Irida2,
Manager_Irida3,
Manager_Clem1,
Manager_Clem2,
Manager_Clem3,
Manager_Schroder1,
Manager_Schroder2,
Manager_Schroder3,
Intro,
Unlock_Irida,
Unlock_Clem,
Unlock_Schroder,
Elaine_PentUp,
Elaine_Femdom,
Elaine_Foodplay,
Irida_Anal,
Irida_Boobies,
Irida_Oral,
Clem_Confession,
Clem_BadGirl,
Clem_FFM,
Clem_Exploration,
Schroder_Packing,
Schroder_Anal,
Schroder_Lapdance,
Schroder_Dom
}
public enum Body
{
None,
Elaine_Normal,
Irida_Normal,
Clem_Normal,
Schroder_Normal
}
public enum Expression
{
None,
Elaine_Normal,
Irida_Normal,
Clem_Normal,
Schroder_Normal,
Elaine_Smug,
}
public enum Effect
{
None,
}
public class Description
{
public string name { get; set; }
public string description { get; set; }
public string warnings { get; set; }
}
public class VNData
{
// Manager sets this value before loading SceneViewer.
public static Dialogue NextScene = Dialogue.Manager_Elaine1;
// TODO: Turn this into a set of probability distributions
public static Dictionary<Employee, List<Dialogue>> managerScenes =
new Dictionary<Employee, List<Dialogue>>() {
{ Employee.Elaine, new List<Dialogue>() {
Dialogue.Manager_Elaine1,
Dialogue.Manager_Elaine2,
Dialogue.Manager_Elaine3,
} },
{ Employee.Clem, new List<Dialogue>() {
Dialogue.Manager_Clem1,
Dialogue.Manager_Clem2,
Dialogue.Manager_Clem3,
} },
{ Employee.Irida, new List<Dialogue>() {
Dialogue.Manager_Irida1,
Dialogue.Manager_Irida2,
Dialogue.Manager_Irida3,
} },
{ Employee.Schroder, new List<Dialogue>() {
Dialogue.Manager_Schroder1,
Dialogue.Manager_Schroder2,
Dialogue.Manager_Schroder3,
} },
};
public static Dialogue GetRandomManagerScene(Employee employee)
{
// TODO: Turn this into a set of probability distributions
return managerScenes[employee][Random.Range(0, managerScenes[employee].Count)];
}
// Used to tell which dialogue sequences are unlockable.
// Mapped via DIALOGUE_DESCRIPTIONS.keys() by the Scene Picker to make a list of unlocked dialogues.
public static Dictionary<Dialogue, Unlockable> UNLOCKABLES = new Dictionary<Dialogue, Unlockable>() {
{ Dialogue.Unlock_Irida, Unlockable.IridaPlayable },
{ Dialogue.Unlock_Clem, Unlockable.ClemPlayable },
{ Dialogue.Unlock_Schroder, Unlockable.SchroderPlayable },
{ Dialogue.Elaine_PentUp, Unlockable.Dialogue_Elaine_Voyeurism },
{ Dialogue.Elaine_Femdom, Unlockable.Dialogue_Elaine_Femdom },
{ Dialogue.Elaine_Foodplay, Unlockable.Dialogue_Elaine_Foodplay },
{ Dialogue.Irida_Anal, Unlockable.Dialogue_Irida_Anal },
{ Dialogue.Irida_Boobies, Unlockable.Dialogue_Irida_Boobies },
{ Dialogue.Irida_Oral, Unlockable.Dialogue_Irida_Oral },
{ Dialogue.Clem_BadGirl, Unlockable.Dialogue_Clem_BadGirl },
{ Dialogue.Clem_Confession, Unlockable.Dialogue_Clem_Confession },
{ Dialogue.Clem_FFM, Unlockable.Dialogue_Clem_FFM },
{ Dialogue.Clem_Exploration, Unlockable.Dialogue_Clem_Exploration },
{ Dialogue.Schroder_Packing, Unlockable.Dialogue_Schroder_Packing },
{ Dialogue.Schroder_Anal, Unlockable.Dialogue_Schroder_Anal },
{ Dialogue.Schroder_Lapdance, Unlockable.Dialogue_Schroder_Lapdance },
{ Dialogue.Schroder_Dom, Unlockable.Dialogue_Schroder_Dom },
};
public static Dictionary<Dialogue, Description> DIALOGUE_DESCRIPTIONS = new Dictionary<Dialogue, Description>() {
{ Dialogue.Intro, new Description() {
name = "Intro",
description = "Elaine convinces you to make a dubious life decision." } },
// Unlock sequences.
{ Dialogue.Unlock_Irida, new Description() {
name = "Irida's Intro",
description = "A bombshell beauty suddenly arrives looking for work (and sex)!" } },
{ Dialogue.Unlock_Clem, new Description() {
name = "Clementine's Intro",
description = "What's this kid doing in my office?" } },
{ Dialogue.Unlock_Schroder, new Description() {
name = "Schroder's Intro",
description = "Mysterious, ambiguous, androgynous... whoever they are, their ass is mine!" } },
// Elaine fetish scenes.
{ Dialogue.Elaine_PentUp, new Description() {
name = "(Elaine) Off the Clock",
description = "Elaine gets caught flickin' it after her shift. Care to join?",
warnings = "Voyeurism" } },
{ Dialogue.Elaine_Femdom, new Description() {
name = "(Elaine) Mommy?",
description = "You get piss drunk with Elaine and convince her to be your dom for a night.",
warnings = "BDSM" } },
{ Dialogue.Elaine_Foodplay, new Description() {
name = "(Elaine) The Smorgasboard",
description = "You and Elaine explore some food fetishism!",
warnings = "Feederism, Oral Fixation" } },
// Irida fetish scenes.
{ Dialogue.Irida_Anal, new Description() {
name = "(Irida) Back-end in the Back-room",
description = "Irida challenges you to make her cum from just anal.",
warnings = "Anal" } },
{ Dialogue.Irida_Boobies, new Description() {
name = "(Irida) Boobies!",
description = "You book Irida for a nice long titty fucking session." } },
{ Dialogue.Irida_Oral, new Description() {
name = "(Irida) Sloppy Toppy",
description = "The bar's about to open, but Irida is nowhere to be seen. Where could she possibly be?" } },
// Clementine fetish scenes.
{ Dialogue.Clem_BadGirl, new Description() {
name = "(Clementine) Bad Girl",
description = "Clem gets in trouble over an altercation. It's time to teach her a lesson.",
warnings = "Petite, BDSM" } },
{ Dialogue.Clem_Confession, new Description() {
name = "(Clementine) The Confession",
description = "Clem comes clean about why she's there. And then you come clean all over her face.",
warnings = "Petite, Mental Health" } },
{ Dialogue.Clem_FFM, new Description() {
name = "(Clementine) FFM or FM (F)",
description = "You and Elaine give Clem some \"special training\" to boost her \"performance\".",
warnings = "Petite" } },
{ Dialogue.Clem_Exploration, new Description() {
name = "(Clementine) FFM or FM (F)",
description = "Clem needs help experimenting with her erogeneous zones.",
warnings = "Petite, Extreme Close-up" } },
// Schroder fetish scenes
{ Dialogue.Schroder_Packing, new Description() {
name = "(Schroder) Packing Heat",
description = "Just a simple night of love-making with Schroder." } },
{ Dialogue.Schroder_Anal, new Description() {
name = "(Schroder) The Bet",
description = "Schroder vows to win the Whose-Asshole-Tastes-The-Best competition that they made up.",
warnings = "Anal" } },
{ Dialogue.Schroder_Lapdance, new Description() {
name = "(Schroder) Private Showing",
description = "You book Schroder for a one-on-one sesh." } },
{ Dialogue.Schroder_Dom, new Description() {
name = "(Schroder) Role Reversal",
description = "Have you ever wondered how it feels to suck dick?" } },
};
public static string GetDialogueAssetPackFor(Dialogue d)
{
return "VNAssetPacks/VNA_" + d.ToString();
}
public static Dictionary<Dialogue, List<DialogueInteraction>> DIALOGUE = new Dictionary<Dialogue, List<DialogueInteraction>>() {
// Manager default day-shift quotes.
{ Dialogue.Manager_Elaine1,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "Phew... All in a day's work.") {
body1 = Body.Elaine_Normal,
expression1 = Expression.Elaine_Normal,
hair1 = 0,
},
new DialogueInteraction("Elaine", "Time to close down for the night."),
new DialogueInteraction("Elaine", "Anything you wanna do first?") {
expression1 = Expression.Elaine_Smug
}
}
},
{ Dialogue.Manager_Elaine2,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "Hey buster, I know we're all ripe for rubbin' here...") {
body1 = Body.Elaine_Normal,
expression1 = Expression.Elaine_Normal,
hair1 = 0,
},
new DialogueInteraction("Elaine", "But if you keep oglin', I'm gonna have to start chargin' for looks.") {
expression1 = Expression.Elaine_Smug
},
}
},
{ Dialogue.Manager_Elaine3,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "Let's wrap things up for the day.") {
body1 = Body.Elaine_Normal,
expression1 = Expression.Elaine_Normal,
hair1 = 0,
},
}
},
{ Dialogue.Manager_Clem1,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "Manager_Clem1"),
}
},
{ Dialogue.Manager_Clem2,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "Manager_Clem2"),
}
},
{ Dialogue.Manager_Clem3,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "Manager_Clem3"),
}
},
{ Dialogue.Manager_Irida1,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "Manager_Irida1"),
}
},
{ Dialogue.Manager_Irida2,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "Manager_Irida2"),
}
},
{ Dialogue.Manager_Irida3,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "Manager_Irida3"),
}
},
{ Dialogue.Manager_Schroder1,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "Manager_Schroder1"),
}
},
{ Dialogue.Manager_Schroder2,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "Manager_Schroder2"),
}
},
{ Dialogue.Manager_Schroder3,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "Manager_Schroder3"),
}
},
// Character unlock scenes.
{ Dialogue.Intro,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "(STUB) Game Intro"),
}
},
{ Dialogue.Unlock_Irida,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "(STUB) Irida Unlocked"),
}
},
{ Dialogue.Unlock_Clem,
new List<DialogueInteraction>() {
new DialogueInteraction("Clem", "(STUB) Clem Unlocked"),
}
},
{ Dialogue.Unlock_Schroder,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "(STUB) Schroder Unlocked"),
}
},
{ Dialogue.Elaine_PentUp,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "(STUB) Elaine_PentUp"),
}
},
{ Dialogue.Elaine_Femdom,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "(STUB) Elaine_Femdom"),
}
},
{ Dialogue.Elaine_Foodplay,
new List<DialogueInteraction>() {
new DialogueInteraction("Elaine", "(STUB) Elaine_Voyeurism"),
}
},
{ Dialogue.Irida_Anal,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "(STUB) Irida_Anal"),
}
},
{ Dialogue.Irida_Boobies,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "(STUB) Irida_Boobies"),
}
},
{ Dialogue.Irida_Oral,
new List<DialogueInteraction>() {
new DialogueInteraction("Irida", "(STUB) Irida_Oral"),
}
},
{ Dialogue.Clem_Confession,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "(STUB) Clem_Confession"),
}
},
{ Dialogue.Clem_BadGirl,
new List<DialogueInteraction>() {
new DialogueInteraction("", "(So Clementine's been reported to my office for misconduct.)") {
backgroundIndex = 0,
},
new DialogueInteraction("", "(From what I can tell, she got angry with some rowdy customer.)"),
new DialogueInteraction("", "(One thing lead to another...)"),
new DialogueInteraction("", "...And then you punched him.") {
body1 = Body.Clem_Normal,
expression1 = Expression.Clem_Normal,
hair1 = 2,
backgroundIndex = 1,
},
new DialogueInteraction("Clementine", "Yeah, well, that's what happened."),
new DialogueInteraction("", "Clementine, this shit is racking up our insurance!"),
new DialogueInteraction("", "I'm sure that guy deserved it, but we have security for a reason."),
new DialogueInteraction("Clementine", "(Sigh.)"),
new DialogueInteraction("", "Alright, look. This one's on you."),
new DialogueInteraction("", "You're gonna pay off the claim for that customer. Last I heard was a few hundred for the settlement."),
new DialogueInteraction("Clementine", "Wha- You know I can't afford that shit!") {
// expression1 = Expression.Clem_Angry,
},
new DialogueInteraction("", "Well, neither can I! Everyone's gotta work overtime here to clean up your messes."),
new DialogueInteraction("", "Frankly, you should know better."),
new DialogueInteraction("Clementine", "Yeah, well, sorry.") {
// expression1 = Expression.Clem_Normal,
},
new DialogueInteraction("", "..."),
new DialogueInteraction("", "You don't look very sorry to me."),
new DialogueInteraction("Clementine", "Yeah? And what are you gonna do, daddy? Spank me?") {
// expression1 = Expression.Clem_Angry,
},
new DialogueInteraction("", "Maybe I will. I'm getting sick of taking your crap."),
new DialogueInteraction("", "I don't want to fire you, but if you're gonna stay then you need to learn a lesson or two.") {
// expression1 = Expression.Clem_Surprised,
},
new DialogueInteraction("Clementine", "U-um..."),
new DialogueInteraction("", "So here's the deal.") {
// expression1 = Expression.Clem_Normal,
},
new DialogueInteraction("", "You're gonna get a hard spanking and tell me how sorry you are, and I'll pay for this little \"incident\"."),
new DialogueInteraction("Clementine", "(Growl)") {
// expression1 = Expression.Clem_Angry,
},
new DialogueInteraction("Clementine", "You're a sick freak, you know that?"),
new DialogueInteraction("", "I suppose I should mail you a bill, then?"),
new DialogueInteraction("", "Besides, I heard what you and Elaine were whispering about.") {
// expression1 = Expression.Clem_Sad,
},
new DialogueInteraction("", "You've got a kink for bdsm, don't you?"),
new DialogueInteraction("Clementine", "N-No, that was-...") {
// expression1 = Expression.Clem_Surprised,
},
new DialogueInteraction("", "Am I wrong?"),
new DialogueInteraction("Clementine", "(Sigh.)") {
// expression1 = Expression.Clem_Normal,
},
new DialogueInteraction("Clementine", "Fine. Just spank me and get it over with."),
new DialogueInteraction("Clementine", "But if you tell anyone what we're doing, I'll never forgive you!") {
// expression1 = Expression.Clem_Angry,
},
new DialogueInteraction("", "Yeah, yeah. Shut up and get on the table."),
new DialogueInteraction("", "...") {
removeBody1 = true,
backgroundIndex = 0,
},
new DialogueInteraction("", "....."),
new DialogueInteraction("Clementine", ".......") {
backgroundIndex = 2,
// TODO: Derpy music
},
new DialogueInteraction("Clementine", "W-Why'd you tie me up?!"),
new DialogueInteraction("", "I figured if I'm gonna whack you one, I might as well have some fun with it."),
new DialogueInteraction("", "Besides, this is a fitting look for you."),
new DialogueInteraction("Clementine", "..."),
new DialogueInteraction("Clementine", "Hey... Don't hit me too hard, okay?"),
new DialogueInteraction("", "Are you really in a position to negotiate right now?"),
new DialogueInteraction("Clementine", "Ungh..."),
new DialogueInteraction("", "(Let's get these panties off.)"),
new DialogueInteraction("", "(Yoink.)") {
backgroundIndex = 3,
// TODO: Ruffling sound effect
},
new DialogueInteraction("Clementine", "..."),
new DialogueInteraction("", "(She seems awfully calm given the situation.)"),
new DialogueInteraction("", "(I've got a paddle from the drawer, just waiting for some action.)"),
new DialogueInteraction("", "(Maybe she's used to this kind of thing. I'm not one to pry, so I wouldn't know.)"),
new DialogueInteraction("", "(Anyways... Let's get started.)"),
new DialogueInteraction("", "WHAM!") {
backgroundIndex = 4,
// TODO: Smack sound effect
},
new DialogueInteraction("Clementine", "--!! ...--!!!... --!... --!... ---!!!... --!... --!!... --!!!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("", "(With long deliberate strokes, I lay into Clementine's ass with the paddle.)") {
// TODO: Wordless smacking sound effect
},
new DialogueInteraction("Clementine", "Augh-- FUCK!"),
new DialogueInteraction("", "Damn! Pipe down; they'll hear you outside."),
new DialogueInteraction("Clementine", "Shut the fuck up and hit me!"),
new DialogueInteraction("", "(...)"),
new DialogueInteraction("Clementine", "-#! --##!! --#! -##! --##! -#! -##! ---#!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("Clementine", "Harder!!"),
new DialogueInteraction("", "(Harder, huh?)"),
new DialogueInteraction("", "(I reel back all the way and--)"),
new DialogueInteraction("Clementine", "--A! --AHH! -AGH! --AUH! --HH! --AH! --AHH! -AGH!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("", "(I grip the paddle and go full-force onto her ass.)") {
// TODO: Wordless smacking sound effect
},
new DialogueInteraction("Clementine", "Ooh!! Oh! I'm gonna pee-- Nngh!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("", "(...?)"),
new DialogueInteraction("", "(That's fine, I'll just have her clean it up later.)"),
new DialogueInteraction("Clementine", "--A! --AHH! -AGH! --AUH! --HH! --AH! --AHH! -AGH!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("Clementine", "Wait-wait-wait-wait-wait-WAIT! I--"),
new DialogueInteraction("", "Nope."),
new DialogueInteraction("Clementine", "!!! !!! !!!! !!! !! !!! !!! !!!!!!") {
// TODO: Yelp sound effect
},
new DialogueInteraction("Clementine", "OOUGH!! Unnghhh!!! Ug--") {
// TODO: Yelp sound effect
},
new DialogueInteraction("", "(Clementine lets out an otherworldly noise as she squirts all over my paddle and desk.)"),
new DialogueInteraction("Clementine", "Augh-- ugh... nnn...") {
backgroundIndex = 5,
// TODO: Yelp sound effect
},
new DialogueInteraction("Clementine", "..........") {
// TODO: Breathing sound effect
},
new DialogueInteraction("", "(Clementine seems to be in another world right now.)"),
new DialogueInteraction("", "(As fun as this is, I've got other things to do today.)"),
new DialogueInteraction("", "..."),
new DialogueInteraction("", "So? What do you have to say for yourself?"),
new DialogueInteraction("Clementine", "I--..."),
new DialogueInteraction("Clementine", "I've been a bad girl... I'm sorry..."),
new DialogueInteraction("Clementine", "I'll be good, daddy... I'll be good for you."),
new DialogueInteraction("Clementine", "Promise."),
new DialogueInteraction("", "..."),
new DialogueInteraction("", "Good. You're in the clear for now."),
new DialogueInteraction("", "By the way, I was gonna foot the bill either way. Just thought I'd tease you a little first."),
new DialogueInteraction("Clementine", "....."),
new DialogueInteraction("Clementine", "Hey..."),
new DialogueInteraction("Clementine", "..."),
new DialogueInteraction("Clementine", "Can you spank me more later?"),
new DialogueInteraction("", "Uh--"),
new DialogueInteraction("", "Sure... Sounds like a plan to me. I'll see you back here after some other shift."),
new DialogueInteraction("", "But first..."),
new DialogueInteraction("", "You pissed all over my desk, so get down from there and clean it up."),
new DialogueInteraction("Clementine", "..."),
new DialogueInteraction("Clementine", "Yes, sir..."),
}
},
{ Dialogue.Clem_FFM,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "(STUB) Clem_FFM"),
}
},
{ Dialogue.Clem_Exploration,
new List<DialogueInteraction>() {
new DialogueInteraction("Clementine", "(STUB) Clem_Exploration"),
}
},
{ Dialogue.Schroder_Packing,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "(STUB) Schroder_Packing"),
}
},
{ Dialogue.Schroder_Anal,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "(STUB) Schroder_Anal"),
}
},
{ Dialogue.Schroder_Dom,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "(STUB) Schroder_Dom"),
}
},
{ Dialogue.Schroder_Lapdance,
new List<DialogueInteraction>() {
new DialogueInteraction("Schroder", "(STUB) Schroder_Lapdance"),
}
},
};
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af05fe228e47d7549a340a5ba7f87fe2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;
public class IntroController : MonoBehaviour
{
[SerializeField] List<IntroFadeController> faders;
[SerializeField] string nextSceneName;
// Start is called before the first frame update
void Start()
{
if (faders.Count > 0) {
faders[0].gameObject.SetActive(true);
}
}
// Update is called once per frame
void Update()
{
if (faders.Count == 0) {
SceneManager.LoadScene(nextSceneName, LoadSceneMode.Single);
} else if (!faders[0].gameObject.activeSelf) {
// Start the timer of a new fader.
faders[0].gameObject.SetActive(true);
} else if (faders[0].turnedOff) {
faders[0].gameObject.SetActive(false);
faders.RemoveAt(0);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 914b57c52ccada24691acfd4916b9cde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e891042b4107a274eabfa86658e15fe2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChairController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1198b75c2511bb040b26688ea6c572c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameAudioController : MonoBehaviour {
[SerializeField] public AudioSource sound;
[SerializeField] public AudioClip talentTabOpen;
[SerializeField] public AudioClip talentTabClose;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e9523b6feae576e43a4ccb946d124b16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,459 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
using Com.LuisPedroFonseca.ProCamera2D;
using TMPro;
using UnityEngine.UI;
public enum PatronType {
Default
}
public class Party {
// Gameplay stats.
// Set of patrons to be seated. The size determines eligible tables.
// The type determines what sprites to use.
public List<PatronType> patrons;
// Default amount of time before the party walks out when waiting on something.
public int patience = 5;
// Chance for a party to give a task instead of an order.
public int baseTaskRate = 50;
// Default speed at which a party decides on an order and eats.
public int baseSpeed = 10;
public Party(List<PatronType> patrons, int patience, int baseTaskRate, int baseSpeed) {
this.patrons = patrons;
this.patience = patience;
this.baseTaskRate = baseTaskRate;
this.baseSpeed = baseSpeed;
}
}
public class TalentState {
public int energy { get; set; } = 100;
public int tips { get; set; } = 0;
public int exp { get; set; } = 0;
// Not owned.
public TableController assignedTable { get; set; } = null;
// public StageSlotController assignedStageSlot = null;
// public int assignedBackroom = -1;
// public bool atFrontDesk = false;
}
public class GameStateController : MonoBehaviour {
[SerializeField] TalentListController talentList;
[HideInInspector] GameAudioController audioController;
[HideInInspector] int selectedTab = -1;
[HideInInspector] ProCamera2D proCamera2D;
[HideInInspector] ProCamera2DPanAndZoom proCamera2DPan;
[HideInInspector] ProCamera2DTransitionsFX proCamera2DTransition;
[HideInInspector] Animator expandedCG;
[HideInInspector] SummaryController summaryController;
// List of all tables in the map.
// Used to validate party seating eligibility.
[HideInInspector] private List<TableController> tables = new List<TableController>();
[SerializeField] public List<OrderPlacementController> orderPlacements;
// Game loop stats.
[HideInInspector] public int moneyEarned = 0;
[HideInInspector] public int currentTime = 0;
[HideInInspector] public int patrons = 0;
[HideInInspector] public Queue<Party> frontDeskQueue = new Queue<Party>();
[HideInInspector] public Queue<Order> orderBacklog = new Queue<Order>();
[HideInInspector] public bool gameRunning = false;
// Game init values.
[SerializeField] int secondsPerTick = 10;
[SerializeField] int maxTime = 30;
[SerializeField] int openingHour = 6;
// Game init values (configurable).
// Varies based on progress in the game. Will be loaded dynamically.
// Max number of parties waiting to be seated.
[SerializeField] int queueCapacity = 3;
// Spawn speed of new parties per minute.
[SerializeField] int baseSpawnRate = 1;
// Seconds to wait before spawning the first party.
[SerializeField] int firstSpawnTime = 3;
// EXP earned for completing actions.
// Subject to bonuses based on what the talent does.
[SerializeField] public int baseExp = 5;
// Probability distribution of party size, starting at 1.
// Works the same as the Grand Star item lottery.
// Must add to 100.
[SerializeField] List<int> partySizeDistribution =
new List<int>() { 25, 50, 20, 5 };
// Multiplier distribution to receive different letter grades.
// C, B, A, S, SS. You get an F if you're below the goal.
[SerializeField] public List<float> gradeDistribution =
new List<float>() { 1.0f, 1.5f, 2.0f, 2.5f, 3.0f };
// Goal for the day. You fail and the day resets if you don't hit this goal.
[SerializeField] public int moneyGoal = 100;
// Base multiplier for earned money per patron.
[SerializeField] public float baseMoneyMultiplier = 100.0f;
// Base difficulty for patron patience and tipping.
[SerializeField] public float difficulty = 1.0f;
// Status indicators.
// Not owned.
[SerializeField] public TextMeshProUGUI text_CurrentTime;
[SerializeField] public TextMeshProUGUI text_CurrentMoney;
[SerializeField] public TextMeshProUGUI text_CurrentPatrons;
// Guaranteed waypoints.
// Not owned.
// Backroom is targeted automatically when a talent receives a task.
[HideInInspector] public Transform backroom;
// Bar is targeted with a hotkey (B).
[HideInInspector] public Transform bar;
// Front desk is targeted with a hotkey (F).
[HideInInspector] public Transform frontDesk;
// Dishes can be targeted with a hotkey (D).
[HideInInspector] public Transform dishes;
// Should load from GameData later.
public TalentState[] talentState = {
// Elaine
new TalentState() {
energy = GameData.GLOBAL
.employeeStats[(int)Employee.Elaine].maxEnergy
},
new TalentState() {
energy = GameData.GLOBAL
.employeeStats[(int)Employee.Irida].maxEnergy
},
new TalentState() {
energy = GameData.GLOBAL
.employeeStats[(int)Employee.Clem].maxEnergy
},
new TalentState() {
energy = GameData.GLOBAL
.employeeStats[(int)Employee.Schroder].maxEnergy
},
};
private void EndTimer() {
Debug.Log("TODO: Make all employees stop what they're doing");
gameRunning = false;
summaryController.gameObject.SetActive(true);
summaryController.SetText();
}
IEnumerator GameTimer() {
while (currentTime < maxTime) {
yield return new WaitForSeconds(secondsPerTick);
currentTime += 1;
}
EndTimer();
}
IEnumerator SpawnTimer() {
yield return new WaitForSeconds(firstSpawnTime);
if (frontDeskQueue.Count < queueCapacity) {
NewParty();
}
while (gameRunning) {
yield return new WaitForSeconds(60 / baseSpawnRate);
if (frontDeskQueue.Count < queueCapacity) {
NewParty();
}
}
}
private void StartTimer() {
if (currentTime < maxTime) {
gameRunning = true;
StartCoroutine("GameTimer");
StartCoroutine("SpawnTimer");
}
}
private PatronType GeneratePatron() {
Debug.Log("TODO: Patron type variance");
return PatronType.Default;
}
private void NewParty() {
int lotto = Random.Range(0, 100);
int lottoSum = 0;
int i = 0;
List<PatronType> patrons = new List<PatronType>() {
GeneratePatron()
};
while (i < partySizeDistribution.Count && partySizeDistribution[i] + lottoSum < lotto) {
lottoSum += partySizeDistribution[i];
i += 1;
patrons.Add(GeneratePatron());
}
Debug.Log("TODO: Party stat variance");
frontDeskQueue.Enqueue(new Party(
patrons,
/*patience =*/ 5,
/*baseTaskRate =*/ 10,
/*baseSpeed =*/ 15));
Debug.Log("New Party (" + frontDeskQueue.Count.ToString() + ")");
}
// Start is called before the first frame update
void Start() {
audioController = GetComponent<GameAudioController>();
backroom = GameObject.FindGameObjectWithTag("BackroomWaypoint").transform;
bar = GameObject.FindGameObjectWithTag("BarWaypoint").transform;
frontDesk = GameObject.FindGameObjectWithTag("FrontDeskWaypoint").transform;
dishes = GameObject.FindGameObjectWithTag("DishesWaypoint").transform;
proCamera2D = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<ProCamera2D>();
proCamera2DPan = proCamera2D.GetComponent<ProCamera2DPanAndZoom>();
proCamera2DTransition = proCamera2D.GetComponent<ProCamera2DTransitionsFX>();
expandedCG = GameObject.FindGameObjectWithTag("ExpandedCG").GetComponent<Animator>();
expandedCG.gameObject.SetActive(false);
summaryController = GameObject.FindGameObjectWithTag("Summary").GetComponent<SummaryController>();
summaryController.gameObject.SetActive(false);
proCamera2DTransition.TransitionEnter();
int i = 1;
foreach (GameObject g in GameObject.FindGameObjectsWithTag("Table")) {
TableController table = g.GetComponent<TableController>();
table.tableId = i;
i++;
tables.Add(table);
}
Debug.Log("TODO: Move this to a ready-set-go");
StartTimer();
}
TalentController GetSelectedEmployee() {
GameObject employee = GameObject.FindGameObjectWithTag(((Employee)selectedTab).ToString());
if (employee != null) {
return employee.GetComponent<TalentController>();
}
return null;
}
public void GainExp(Employee e, int amount) {
talentState[(int)e].exp += amount;
}
public void GainTips(Employee e, int amount) {
moneyEarned += amount;
talentState[(int)e].tips += amount;
}
public void GainMoney(int amount) {
moneyEarned += amount;
}
// Attempt to select the [tabIndex]'th Talent.
public void HandleSelect(int tabIndex) {
if (selectedTab == tabIndex) {
// Deselect tab
Debug.Log("Attempting to de-select tab " + tabIndex.ToString());
talentList.setActiveTab(-1);
selectedTab = -1;
audioController.sound.PlayOneShot(
audioController.talentTabClose);
// Return pan to the player.
proCamera2D.RemoveAllCameraTargets();
proCamera2DPan.enabled = true;
} else {
// Select tab
Debug.Log("Attempting to select tab " + tabIndex.ToString());
talentList.setActiveTab(tabIndex);
selectedTab = tabIndex;
audioController.sound.PlayOneShot(
audioController.talentTabOpen);
// Switch target to the newly selected employee if in target mode.
if (proCamera2DPan.enabled == false) {
HandleTargetSelection();
}
}
}
void HandleShowCG() {
if (expandedCG.isActiveAndEnabled) {
talentList.gameObject.SetActive(true);
expandedCG.gameObject.SetActive(false);
Debug.Log("TODO: Stop loop sound for animation");
} else if (selectedTab != -1) {
talentList.gameObject.SetActive(false);
expandedCG.gameObject.SetActive(true);
Debug.Log("TODO: Set animator float for CG of " + ((Employee)selectedTab).ToString());
Debug.Log("TODO: Play loop sound for animation");
}
}
void HandleTargetSelection() {
if (!proCamera2DPan.enabled) {
// Turn off targeting.
proCamera2D.RemoveAllCameraTargets();
proCamera2DPan.enabled = true;
} else if (selectedTab != -1) {
TalentController talent = GetSelectedEmployee();
if (talent != null) {
talent.OnTarget();
// Targeting takes pan away from the player.
proCamera2DPan.enabled = false;
proCamera2D.RemoveAllCameraTargets();
proCamera2D.AddCameraTarget(talent.transform, 1, 1, 1);
}
}
}
// If an employee is selected, have them tend to the table.
public void HandleTableClick(TableController table) {
if (selectedTab != -1 &&
table.waypoint != null) {
// The target employee's name should be the object tag associated with their selection index.
// Elaine = 0, Irida = 1, Clem = 2, Schroder = 3.
TalentController talent = GetSelectedEmployee();
if (talent != null) {
Debug.Log("Queueing " + ((Employee)selectedTab).ToString() + " to a table.");
talent.QueueDestination(table.waypoint, AssignmentType.Table, table);
}
}
}
// If an employee is selected, have them visit this order waypoint.
public void HandleOrderClick(OrderPlacementController order) {
if (selectedTab != -1 &&
order.waypoint != null) {
// The target employee's name should be the object tag associated with their selection index.
// Elaine = 0, Irida = 1, Clem = 2, Schroder = 3.
TalentController talent = GetSelectedEmployee();
if (talent != null) {
Debug.Log("Queueing " + ((Employee)selectedTab).ToString() + " to pick up an order.");
talent.QueueDestination(order.waypoint, AssignmentType.Order, null, order);
}
}
}
private IEnumerator FinishCooking(Order o, float time) {
yield return new WaitForSeconds(time);
bool orderAccepted = false;
foreach (OrderPlacementController placement in orderPlacements) {
if (placement.order == null) {
placement.TakeOrder(o);
orderAccepted = true;
break;
}
}
if (!orderAccepted) {
orderBacklog.Enqueue(o);
}
}
// Starts coroutines to cook a list of orders.
public void Cook(List<Order> orders) {
foreach (Order o in orders) {
Debug.Log("TODO: Cook time based on difficulty");
StartCoroutine(FinishCooking(o, Random.Range(1.0f, 5.0f)));
}
}
// Returns true iff an open table with sufficient capacity is available for seating.
public bool ValidateParty(Party p) {
foreach (TableController t in tables) {
if (t.chairs.Count >= p.patrons.Count && t.party == null) {
return true;
}
}
return false;
}
// Check if the front desk is already occupied.
// If not, attempt to assign the selected talent to the front desk.
void HandleFrontDeskClick() {
if (selectedTab != -1) {
TalentController talent = GetSelectedEmployee();
if (talent != null) {
Debug.Log("Queueing " + ((Employee)selectedTab).ToString() + " to the front desk.");
talent.QueueDestination(frontDesk, AssignmentType.FrontDesk);
}
}
}
// Attempt to assign the selected talent to the bar.
void HandleBarClick() {
if (selectedTab != -1) {
TalentController talent = GetSelectedEmployee();
if (talent != null) {
Debug.Log("Queueing " + ((Employee)selectedTab).ToString() + " to the bar.");
talent.QueueDestination(bar, AssignmentType.Bar);
}
}
}
// Attempt to assign the selected talent to the bar.
void HandleDishesClick() {
if (selectedTab != -1) {
TalentController talent = GetSelectedEmployee();
if (talent != null) {
Debug.Log("Queueing " + ((Employee)selectedTab).ToString() + " to the dishes.");
talent.QueueDestination(dishes, AssignmentType.Dishes);
}
}
}
// Turn a time tick into XX:YY PM/AM.
// Starting time is set by openingHour and each tick is 15 minutes.
// So tick 5 with openingHour 6 is 7:15 PM.
private string BuildTimeString(int time) {
int minute = (time % 4) * 15;
int hour = (time / 4 + openingHour) % 12;
if (hour == 0) hour = 12;
return hour.ToString() + ":"
+ minute.ToString().PadLeft(2, '0')
+ ((hour < openingHour || hour == 12) ? " AM" : " PM");
}
private void LateUpdate() {
text_CurrentTime.SetText(BuildTimeString(currentTime));
text_CurrentMoney.SetText("$" + moneyEarned.ToString());
text_CurrentPatrons.SetText(patrons.ToString());
}
// Update is called once per frame
void Update() {
if (Input.GetKeyDown(KeyCode.Alpha1)) {
HandleSelect(0);
} else if (Input.GetKeyDown(KeyCode.Alpha2)) {
HandleSelect(1);
} else if (Input.GetKeyDown(KeyCode.Alpha3)) {
HandleSelect(2);
} else if (Input.GetKeyDown(KeyCode.Alpha4)) {
HandleSelect(3);
} else if (Input.GetKeyDown(KeyCode.Alpha5)) {
HandleSelect(4);
} else if (Input.GetKeyDown(KeyCode.Alpha6)) {
HandleSelect(5);
} else if (Input.GetKeyDown(KeyCode.E)) {
HandleShowCG();
} else if (Input.GetKeyDown(KeyCode.T)) {
HandleTargetSelection();
} else if (Input.GetKeyDown(KeyCode.F)) {
HandleFrontDeskClick();
} else if (Input.GetKeyDown(KeyCode.B)) {
HandleBarClick();
} else if (Input.GetKeyDown(KeyCode.D)) {
HandleDishesClick();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b294d80dcfa51404aa7d5bfe04b29794
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using TMPro;
public class Order {
public TableController destination;
public Order(TableController destination) {
this.destination = destination;
}
}
public class OrderPlacementController : MonoBehaviour, IPointerClickHandler
{
[SerializeField] public Transform waypoint = null;
[SerializeField] public TextMeshPro debugText = null;
[HideInInspector] public Order order = null;
// Not owned.
[HideInInspector] private GameStateController gameStateController;
public void OnPointerClick(PointerEventData eventData) {
Debug.Log("I'm an order waypoint and you clicked on me!!");
gameStateController.HandleOrderClick(this);
}
// API to take a new order.
public void TakeOrder(Order o) {
Debug.Log("Animation update");
order = o;
}
// Yield the order to a talent, setting it as null for self.
// If an order is in the backlog, it'll be placed immediately at this table.
public Order PickUp() {
Order o = order;
order = null;
if (gameStateController.orderBacklog.Count > 0) {
TakeOrder(gameStateController.orderBacklog.Dequeue());
}
return o;
}
// Start is called before the first frame update
void Start() {
gameStateController = GameObject.FindGameObjectWithTag("GameStateController").GetComponent<GameStateController>();
}
private void LateUpdate() {
if (order != null) {
debugText.SetText(order.destination.tableId.ToString());
} else {
debugText.SetText("");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 209d7b37c6709ec4f884baa2a1809223
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,253 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using Com.LuisPedroFonseca.ProCamera2D;
using UnityEngine.SceneManagement;
public class SummaryController : MonoBehaviour {
[SerializeField] TextMeshProUGUI textPatrons;
[SerializeField] TextMeshProUGUI textMoney;
[SerializeField] TextMeshProUGUI textGrade;
// TODO: TMPros for each talent's summary
[SerializeField] TextMeshProUGUI textElaineXP;
[SerializeField] TextMeshProUGUI textIridaXP;
[SerializeField] TextMeshProUGUI textClemXP;
[SerializeField] TextMeshProUGUI textSchroderXP;
// Not owned.
[HideInInspector] GameStateController gameStateController;
[HideInInspector] ProCamera2DTransitionsFX transition;
// Makes up a grade given the game state.
public string GetGrade() {
Debug.Log("GetGrade not yet implemented");
if (gameStateController.moneyEarned < gameStateController.moneyGoal) {
return "F";
}
string[] grades = { "C", "B", "A", "S", "SS" };
int i = 0;
while (i < grades.Length &&
gameStateController.moneyEarned > gameStateController.moneyGoal * gameStateController.gradeDistribution[i]) {
i++;
}
return grades[i - 1];
}
void Start() {
gameStateController = GameObject.FindGameObjectWithTag("GameStateController").GetComponent<GameStateController>();
transition = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<ProCamera2DTransitionsFX>();
}
public void SetText() {
ProcessAndShowEXP();
textPatrons.SetText(gameStateController.patrons.ToString());
textMoney.SetText(gameStateController.moneyEarned.ToString());
textGrade.SetText(GetGrade());
}
// Update is called once per frame
void Update()
{
}
public void GoToManagement() {
SceneManager.LoadScene("Manager");
}
// For when the player unlocks something that starts with a scene.
public void GoToDialogue() {
SceneManager.LoadScene("SceneViewer");
}
public Dialogue ReturnDialogueIfUnlock(Unlockable u, Dialogue d) {
if (!GameData.IsUnlocked(u)) {
GameData.Unlock(u);
return d;
}
return Dialogue.None;
}
public Dialogue ProcessUnlockables() {
// Character-specific scenes.
if (GameData.StatsOf(Employee.Elaine).level >= 3) {
GameData.Unlock(Unlockable.Dialogue_Elaine_Voyeurism);
}
if (GameData.StatsOf(Employee.Elaine).level >= 6) {
GameData.Unlock(Unlockable.Dialogue_Elaine_Femdom);
}
if (GameData.StatsOf(Employee.Elaine).level >= 9) {
GameData.Unlock(Unlockable.Dialogue_Elaine_Foodplay);
}
if (GameData.IsPlayerUnlocked(Employee.Irida) &&
GameData.StatsOf(Employee.Irida).level >= 4) {
GameData.Unlock(Unlockable.Dialogue_Irida_Anal);
}
if (GameData.IsPlayerUnlocked(Employee.Irida) &&
GameData.StatsOf(Employee.Irida).level >= 6) {
GameData.Unlock(Unlockable.Dialogue_Irida_Boobies);
}
if (GameData.IsPlayerUnlocked(Employee.Irida) &&
GameData.StatsOf(Employee.Irida).level >= 8) {
GameData.Unlock(Unlockable.Dialogue_Irida_Oral);
}
if (GameData.IsPlayerUnlocked(Employee.Clem) &&
GameData.StatsOf(Employee.Clem).level >= 4) {
GameData.Unlock(Unlockable.Dialogue_Clem_FFM);
}
if (GameData.IsPlayerUnlocked(Employee.Clem) &&
GameData.StatsOf(Employee.Clem).level >= 6) {
GameData.Unlock(Unlockable.Dialogue_Clem_Exploration);
}
if (GameData.IsPlayerUnlocked(Employee.Clem) &&
GameData.StatsOf(Employee.Clem).level >= 8) {
GameData.Unlock(Unlockable.Dialogue_Clem_Confession);
}
if (GameData.IsPlayerUnlocked(Employee.Schroder) &&
GameData.StatsOf(Employee.Schroder).level >= 5) {
GameData.Unlock(Unlockable.Dialogue_Schroder_Packing);
}
if (GameData.IsPlayerUnlocked(Employee.Schroder) &&
GameData.StatsOf(Employee.Schroder).level >= 8) {
GameData.Unlock(Unlockable.Dialogue_Schroder_Anal);
}
if (GameData.IsPlayerUnlocked(Employee.Schroder) &&
GameData.StatsOf(Employee.Schroder).level >= 9) {
GameData.Unlock(Unlockable.Dialogue_Schroder_Dom);
}
if (GameData.IsPlayerUnlocked(Employee.Schroder) &&
GameData.StatsOf(Employee.Schroder).level >= 10) {
GameData.Unlock(Unlockable.Dialogue_Schroder_Lapdance);
}
// Backrooms: Unlock all characters
if (GameData.IsUnlocked(Unlockable.IridaPlayable) &&
GameData.IsUnlocked(Unlockable.ClemPlayable) &&
GameData.IsUnlocked(Unlockable.SchroderPlayable)) {
GameData.Unlock(Unlockable.Backrooms);
}
Debug.Log("TODO: Schroder special condition of stripper assignment");
// Irida: Clear 3 days and Elaine level 3+
if (GameData.StatsOf(Employee.Elaine).level >= 3
&& GameData.GLOBAL.day > 3) {
return ReturnDialogueIfUnlock(
Unlockable.IridaPlayable,
Dialogue.Unlock_Irida);
}
// Clem: Clear 8 days and Elaine and Irida level 5+
else if (
GameData.StatsOf(Employee.Elaine).level >= 5
&& GameData.StatsOf(Employee.Irida).level >= 5
&& GameData.GLOBAL.day > 8) {
return ReturnDialogueIfUnlock(
Unlockable.ClemPlayable,
Dialogue.Unlock_Clem);
}
// Schroder: Clear 14 days and Elaine, Irida, Clem level 7+
else if (
GameData.StatsOf(Employee.Elaine).level >= 7
&& GameData.StatsOf(Employee.Irida).level >= 7
&& GameData.StatsOf(Employee.Clem).level >= 7
&& GameData.GLOBAL.day > 14) {
return ReturnDialogueIfUnlock(
Unlockable.SchroderPlayable,
Dialogue.Unlock_Schroder);
}
return Dialogue.None;
}
// Process GameData after completing a day.
private void ProcessAndShowEXP(bool won = true) {
Debug.Log("TODO: Calculate exp gain per employee based on daily activities");
Debug.Log("TODO: Build summary around results of above calculation (pre-calculate)");
int[] previousLevels = {
GameData.StatsOf(Employee.Elaine).level,
GameData.StatsOf(Employee.Irida).level,
GameData.StatsOf(Employee.Clem).level,
GameData.StatsOf(Employee.Schroder).level,
};
int[] previousExp = {
GameData.StatsOf(Employee.Elaine).exp,
GameData.StatsOf(Employee.Irida).exp,
GameData.StatsOf(Employee.Clem).exp,
GameData.StatsOf(Employee.Schroder).exp,
};
Debug.Log("TODO: Implement ability to lose and not gain exp/money/day");
if (won) {
for (int i = 0; i < 4; i++) {
GameData.StatsOf((Employee)i).GainExp(
gameStateController.talentState[i].exp);
}
GameData.GLOBAL.money += gameStateController.moneyEarned;
GameData.GLOBAL.day += 1;
}
Debug.Log("bruh");
textElaineXP.SetText(
"LV" +
previousLevels[0].ToString() + " " +
previousExp[0].ToString() + " / " +
EmployeeStats.expRequirement[previousLevels[0]] + " => " +
GameData.StatsOf(Employee.Elaine).level.ToString() + " " +
GameData.StatsOf(Employee.Elaine).exp.ToString() + " / " +
EmployeeStats.expRequirement[GameData.StatsOf(Employee.Elaine).level]);
if (GameData.IsPlayerUnlocked(Employee.Irida)) {
textIridaXP.SetText(
"LV" +
previousLevels[1].ToString() + " " +
previousExp[1].ToString() + " / " +
EmployeeStats.expRequirement[previousLevels[1]] + " => " +
GameData.StatsOf(Employee.Irida).level.ToString() + " " +
GameData.StatsOf(Employee.Irida).exp.ToString() + " / " +
EmployeeStats.expRequirement[GameData.StatsOf(Employee.Irida).level]);
}
if (GameData.IsPlayerUnlocked(Employee.Clem)) {
textClemXP.SetText(
"LV" +
previousLevels[2].ToString() + " " +
previousExp[2].ToString() + " / " +
EmployeeStats.expRequirement[previousLevels[2]] + " => " +
GameData.StatsOf(Employee.Clem).level.ToString() + " " +
GameData.StatsOf(Employee.Clem).exp.ToString() + " / " +
EmployeeStats.expRequirement[GameData.StatsOf(Employee.Clem).level]);
}
if (GameData.IsPlayerUnlocked(Employee.Schroder)) {
textSchroderXP.SetText(
"LV" +
previousLevels[3].ToString() + " " +
previousExp[3].ToString() + " / " +
EmployeeStats.expRequirement[previousLevels[3]] + " => " +
GameData.StatsOf(Employee.Schroder).level.ToString() + " " +
GameData.StatsOf(Employee.Schroder).exp.ToString() + " / " +
EmployeeStats.expRequirement[GameData.StatsOf(Employee.Schroder).level]);
}
}
public void Continue() {
Dialogue unlockedScene = ProcessUnlockables();
Debug.Log("TODO: Autosave toggle as option");
GameData.Save();
if (unlockedScene != Dialogue.None) {
VNData.NextScene = unlockedScene;
transition.OnTransitionExitEnded = GoToDialogue;
} else {
transition.OnTransitionExitEnded = GoToManagement;
}
transition.TransitionExit();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fbb1bb49c234df44fa5cab5d5cf22b25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,181 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine;
using TMPro;
public enum TableState {
Empty,
Deciding, // Deciding on an order or task
ReadyToOrder, // Actively waiting for an employee
WaitingOnOrder, // Specifically for food
Escorting, // Moving to backroom. Transitions to Empty
Eating, // Transitions to Deciding or Done
WaitingOnCheck, // Interaction takes the check. Transitions to Plates
Plates // The table needs to be bussed. Transitions to Empty
}
public class TableController : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] public int tableId = 0;
[SerializeField] public Transform waypoint;
[SerializeField] public Transform pornModal;
[SerializeField] public Animator pornAnimator;
// Autograb.
[HideInInspector] public List<ChairController> chairs;
[HideInInspector] public float patienceTimeStart = 0.0f;
[HideInInspector] public float maxWait = 30.0f;
// Should increase significantly with tasks.
[HideInInspector] public float tipMultiplier = 0.3f;
[HideInInspector] public List<float> remainingPatience = new List<float>();
// TODO: Implement patron actions, timeouts, etc.
// Not owned.
private GameStateController gameStateController;
[SerializeField] TextMeshPro debugText;
// Gameplay fields.
[HideInInspector] public Party party = null;
[HideInInspector] public TableState state = TableState.Empty;
[HideInInspector] public bool waiting = false;
// Mutex.
[HideInInspector] public bool servicing = false;
public void OnPointerClick(PointerEventData eventData) {
Debug.Log("I'm a table and you clicked on me!!");
gameStateController.HandleTableClick(this);
}
public void OnPointerEnter(PointerEventData eventData) {
Debug.Log("I'm a table and you're hovering on me!");
}
public void OnPointerExit(PointerEventData eventData) {
Debug.Log("I'm a table and you left!");
}
private void StartWait() {
waiting = true;
patienceTimeStart = Time.time;
}
private void EndWait() {
waiting = false;
float waited = 1.0f - (Time.time - patienceTimeStart) / maxWait;
Debug.Log("Table patience remaining on complete: " + waited.ToString());
remainingPatience.Add(waited);
}
private void ResetPatience() {
waiting = false;
remainingPatience.Clear();
}
public int GetPay() {
if (remainingPatience.Count == 0 || party.patrons.Count == 0) {
return 0;
}
Debug.Log("Make dynamic based on other party stats");
float pay = party.patrons.Count
* gameStateController.baseMoneyMultiplier
/ gameStateController.difficulty;
return Mathf.FloorToInt(pay);
}
public int GetTip() {
if (remainingPatience.Count == 0 || party.patrons.Count == 0) {
return 0;
}
float avgPatience = 0.0f;
foreach (float p in remainingPatience) {
avgPatience += Mathf.Max(0.0f, p);
}
avgPatience /= remainingPatience.Count;
Debug.Log("Make dynamic based on party stats");
float pay = party.patrons.Count
* gameStateController.baseMoneyMultiplier
* tipMultiplier
* (1.0f - avgPatience)
/ gameStateController.difficulty;
return Mathf.FloorToInt(pay);
}
public Order GenerateOrder() {
Debug.Log("TODO: Capture event where employee picks up a ticket");
state = TableState.WaitingOnOrder;
EndWait();
StartWait();
return new Order(this);
}
private IEnumerator DecideOnOrder() {
Debug.Log("TODO: Make order time dynamic and based on day's difficulty");
yield return new WaitForSeconds(5);
state = TableState.ReadyToOrder;
StartWait();
}
public void AssignParty(Party p) {
party = p;
state = TableState.Deciding;
remainingPatience.Clear();
Debug.Log("Make maxWait dynamic based on Party and GameState difficulty");
maxWait = 30.0f; // 30 seconds
StartCoroutine("DecideOnOrder");
Debug.Log("TODO: Update chairs after being seated");
}
private IEnumerator FinishEating() {
Debug.Log("TODO: Make order time dynamic and based on day's difficulty");
yield return new WaitForSeconds(5);
state = TableState.WaitingOnCheck;
StartWait();
}
public void StartEating() {
EndWait();
state = TableState.Eating;
StartCoroutine("FinishEating");
Debug.Log("TODO: Update chairs to start eating");
}
public void PickUpCheck() {
EndWait();
state = TableState.Plates;
Debug.Log("TODO: Update chairs to go yay and make money");
}
public void CleanUpDishes() {
Debug.Log("TODO: Implement dishes or empty state depending on backroom vs escort");
state = TableState.Empty;
party = null;
ResetPatience();
}
// Start is called before the first frame update
void Start() {
gameStateController = GameObject.FindGameObjectWithTag("GameStateController").GetComponent<GameStateController>();
chairs = new List<ChairController>(transform.GetComponentsInChildren<ChairController>());
}
// Update is called once per frame
void LateUpdate() {
if (waiting && Time.time - patienceTimeStart > maxWait) {
// Debug.Log("TIME'S OUT, SUCKER");
}
debugText.SetText("Table: " + tableId.ToString()
+ "\nCapacity: " + chairs.Count.ToString()
+ "\nOccupancy: " + ((party == null) ? "0" : party.patrons.Count.ToString())
+ "\nTableState: " + state.ToString()
);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 130fe064c437c88469cbafba08c3bd2a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,372 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public enum AssignmentType {
None,
Table,
Backroom,
FrontDesk,
Bar,
Order,
Dishes
}
// To-do item for an employee. The player queues these up,
// and the employee performs each one best-effort as quickly as they can.
public class Destination {
public Transform waypoint;
public AssignmentType assignmentType;
public TableController assignedTable;
public OrderPlacementController order;
public Destination(Transform waypoint, AssignmentType assignmentType, TableController assignedTable, OrderPlacementController order) {
this.waypoint = waypoint;
this.assignmentType = assignmentType;
this.assignedTable = assignedTable;
this.order = order;
}
}
public class TalentController : MonoBehaviour {
[SerializeField] List<AudioClip> greetings;
[SerializeField] List<AudioClip> comply;
// Prefab to spawn XP/Money text.
[SerializeField] GameObject fadingTextProto;
[HideInInspector] AudioSource audioSource;
[HideInInspector] Animator animator;
// Pathfinding related objects.
[HideInInspector] AIDestinationSetter destination;
[HideInInspector] AILerp aiLerp;
// Not owned.
[HideInInspector] GameStateController gameStateController;
[HideInInspector] bool busy = false;
// The distance at which an employee will stop away from a table, if they're
// walking towards it while it's being serviced by another employee.
[SerializeField] float maxServiceWaitDistance = 4.0f;
// Table service variables.
[SerializeField] TableController assignedTable = null;
[HideInInspector] List<Order> heldTickets = new List<Order>();
[HideInInspector] List<Order> heldFood = new List<Order>();
[HideInInspector] OrderPlacementController assignedOrder = null;
[HideInInspector] bool isAtWaypoint = true;
[HideInInspector] Party seatingParty = null;
[HideInInspector] bool isHoldingPlates = false;
[HideInInspector] AssignmentType assignmentType = AssignmentType.None;
// TOOD: The list of destinations is overrideable by a visit to the Backroom.
[SerializeField] Queue<Destination> todo = new Queue<Destination>();
[SerializeField] Employee employee = Employee.Elaine;
// Start is called before the first frame update
void Start() {
audioSource = GetComponent<AudioSource>();
destination = GetComponent<AIDestinationSetter>();
animator = GetComponent<Animator>();
aiLerp = GetComponent<AILerp>();
gameStateController = GameObject.FindGameObjectWithTag("GameStateController").GetComponent<GameStateController>();
// TODO: Maybe something safer on GetComponent.
if (!GameData.IsPlayerUnlocked(employee)) {
Destroy(gameObject);
}
}
void NewDestination(Transform waypoint,
AssignmentType destinationType = AssignmentType.None,
TableController table = null,
OrderPlacementController order = null) {
destination.target = waypoint;
assignmentType = destinationType;
assignedTable = table;
assignedOrder = order;
isAtWaypoint = false;
busy = true;
}
// Vector push-back a new Destination onto the employee's to-do list.
// They will act upon all destinations, in the order they were enqueued by the player.
public void QueueDestination(Transform waypoint,
AssignmentType destinationType = AssignmentType.None,
TableController table = null,
OrderPlacementController order = null) {
if (todo.Count == 0 && !busy) {
PlayRandomSound(comply);
}
todo.Enqueue(new Destination(waypoint, destinationType, table, order));
}
public void PlayRandomSound(List<AudioClip> sounds) {
if (sounds.Count > 0) {
audioSource.PlayOneShot(sounds[Random.Range(0, sounds.Count)]);
}
}
public void OnTarget() {
PlayRandomSound(greetings);
}
private void GainPay(int amount, int tips) {
Debug.Log("Spawn text with amount + tip amount");
gameStateController.GainMoney(amount);
gameStateController.GainTips(employee, tips);
TextFadeController tfc = Instantiate(fadingTextProto).GetComponent<TextFadeController>();
tfc.transform.position = transform.position;
tfc.baseColor = Color.green;
tfc.text.SetText("+$" + amount.ToString() + " +$" + tips.ToString());
}
private void GainExp(int amount) {
Debug.Log("Spawn text with exp amount");
gameStateController.GainExp(employee, amount);
TextFadeController tfc = Instantiate(fadingTextProto).GetComponent<TextFadeController>();
tfc.transform.position = transform.position;
tfc.baseColor = Color.yellow;
tfc.text.SetText("+" + amount.ToString() + " XP");
}
private IEnumerator PickUpTicket() {
Debug.Log("TODO: Make dynamic based on employee speed");
Debug.Log("TODO: Update animation to having conversation");
Debug.Log("TODO: Implement chance of generating a task instead");
yield return new WaitForSeconds(2);
heldTickets.Add(assignedTable.GenerateOrder());
assignedTable.servicing = false;
assignedTable = null;
GainExp(gameStateController.baseExp);
assignmentType = AssignmentType.None;
busy = false;
}
private IEnumerator DropOffTickets() {
Debug.Log("TODO: Make dynamic based on employee speed");
Debug.Log("TODO: Update animation to dropping off tickets");
yield return new WaitForSeconds(1);
gameStateController.Cook(heldTickets);
heldTickets.Clear();
GainExp(gameStateController.baseExp);
assignmentType = AssignmentType.None;
busy = false;
}
private IEnumerator PickUpFood() {
Debug.Log("TODO: Make dynamic based on employee speed");
Debug.Log("TODO: Update animation to grabbing the order");
yield return new WaitForSeconds(1);
heldFood.Add(assignedOrder.PickUp());
assignedOrder = null;
GainExp(gameStateController.baseExp);
assignmentType = AssignmentType.None;
busy = false;
}
private IEnumerator DropOffFood() {
int i = 0;
bool droppedOff = false;
for (; i < heldFood.Count; i++) {
if (heldFood[i].destination.tableId == assignedTable.tableId) {
Debug.Log("TODO: Make dynamic based on employee speed");
Debug.Log("TODO: Update animation to dropping off food");
yield return new WaitForSeconds(2);
assignedTable.StartEating();
GainExp(gameStateController.baseExp);
droppedOff = true;
break;
}
}
if (droppedOff) {
heldFood.RemoveAt(i);
}
assignedTable.servicing = false;
assignedTable = null;
assignmentType = AssignmentType.None;
busy = false;
}
private IEnumerator PickUpDishes() {
Debug.Log("TODO: Make dynamic based on employee speed");
Debug.Log("TODO: Update animation to picking up dishes");
yield return new WaitForSeconds(2);
isHoldingPlates = true;
assignedTable.CleanUpDishes();
assignedTable.servicing = false;
assignedTable = null;
GainExp(gameStateController.baseExp);
assignmentType = AssignmentType.None;
busy = false;
}
private IEnumerator PickUpCheck() {
Debug.Log("TODO: Yay animation");
yield return new WaitForSeconds(1);
assignedTable.PickUpCheck();
GainExp(gameStateController.baseExp);
GainPay(assignedTable.GetPay(), assignedTable.GetTip());
assignedTable.servicing = false;
assignedTable = null;
assignmentType = AssignmentType.None;
busy = false;
}
void InteractWithTable() {
// Set animation and timeout for corresponding action from possibilities:
// If talent is leading employees, dump them at the table.
// Otherwise:
// TableState.Ready -> Table chooses between a food order and task
// TableState.WaitingOnOrder -> If the employee is holding the table's food, fulfills the order
// TableState.WaitingOnCheck -> Gather the check and empty the table of plates and guests.
assignedTable.servicing = true;
if (seatingParty != null) {
if (assignedTable.party == null && assignedTable.state == TableState.Empty) {
Debug.Log("TODO: Convert to Coroutine to take time seating a party");
assignedTable.AssignParty(seatingParty);
GainExp(gameStateController.baseExp);
seatingParty = null;
}
} else if (assignedTable.state != TableState.Empty) {
switch(assignedTable.state) {
case TableState.WaitingOnOrder:
// Coroutine should set assignedTable.servicing=false, assignedTable=null, assignmentType=None.
if (!isHoldingPlates && seatingParty == null && heldTickets.Count == 0) {
StartCoroutine("DropOffFood");
return;
}
break;
case TableState.WaitingOnCheck:
// Coroutine should set assignedTable.servicing=false, assignedTable=null, assignmentType=None.
StartCoroutine("PickUpCheck");
return;
case TableState.ReadyToOrder:
// Coroutine should set assignedTable.servicing=false, assignedTable=null, assignmentType=None.
if (!isHoldingPlates && seatingParty == null && heldFood.Count == 0) {
StartCoroutine("PickUpTicket");
return;
}
break;
case TableState.Plates:
// Coroutine should set assignedTable.servicing=false, assignedTable=null, assignmentType=None.
if (seatingParty == null && heldFood.Count == 0 && heldTickets.Count == 0) {
StartCoroutine("PickUpDishes");
return;
}
break;
default:
Debug.Log("TODO: Sound for un-interactable table, maybe");
break;
}
}
assignedTable.servicing = false;
assignmentType = AssignmentType.None;
assignedTable = null;
busy = false;
}
void InteractWithBar() {
// Drop off any held tickets from customers.
if (heldTickets.Count > 0) {
StartCoroutine("DropOffTickets");
return;
}
assignmentType = AssignmentType.None;
busy = false;
}
void InteractWithOrder() {
// Pick up an order at the waypoint.
// Should fail if the employee is holding anything other an another order.
if (assignedOrder.order != null && !isHoldingPlates && heldTickets.Count == 0 && seatingParty == null) {
StartCoroutine("PickUpFood");
return;
}
assignmentType = AssignmentType.None;
busy = false;
}
void InteractWithDishes() {
// Drop off any held dishes at the waypoint.
// Does nothing else.
if (isHoldingPlates) {
Debug.Log("TODO: Make a dish noise?");
GainExp(gameStateController.baseExp);
}
isHoldingPlates = false;
busy = false;
}
// If the front desk has a party queued, grab the party.
// Fails if busy or ineligible.
void InteractWithFrontDesk() {
if (isHoldingPlates || heldFood.Count > 0 || heldTickets.Count > 0 || seatingParty != null) {
Debug.Log("TODO: Play sound for failed queue interaction");
} else if (gameStateController.frontDeskQueue.Count == 0) {
Debug.Log("TODO: Play sound for empty queue");
} else {
Debug.Log("TODO: Parameterize front desk interact for particular party");
Party candidateParty = gameStateController.frontDeskQueue.Peek();
if (gameStateController.ValidateParty(candidateParty)) {
seatingParty = gameStateController.frontDeskQueue.Dequeue();
} else {
Debug.Log("TODO: Party grab failure sound");
}
}
busy = false;
}
// Update is called once per frame
void Update()
{
// This is true on the frame at which the employee reaches the waypoint.
if (!isAtWaypoint && aiLerp.reachedDestination) {
isAtWaypoint = true;
if (assignmentType == AssignmentType.Table && assignedTable != null) {
Debug.Log("I reached the table!");
InteractWithTable();
} else if (assignmentType == AssignmentType.Bar) {
Debug.Log("I reached the bar to drop off a ticket!");
InteractWithBar();
} else if (assignmentType == AssignmentType.Order) {
Debug.Log("I reached the bar to pick up an order!");
InteractWithOrder();
} else if (assignmentType == AssignmentType.Dishes) {
Debug.Log("I reached the dishes!");
InteractWithDishes();
} else if (assignmentType == AssignmentType.FrontDesk) {
Debug.Log("I reached the front desk!");
InteractWithFrontDesk();
}
}
// If the employee is available, pop the top of the queue and set it as a destination.
if (!busy && todo.Count > 0) {
Destination dest = todo.Dequeue();
NewDestination(dest.waypoint, dest.assignmentType, dest.assignedTable, dest.order);
}
// If another employee is servicing the assigned table, wait for them to finish.
if (assignedTable != null &&
assignedTable.servicing &&
Vector2.Distance(transform.position, assignedTable.waypoint.transform.position) <= maxServiceWaitDistance) {
aiLerp.canMove = false;
} else {
aiLerp.canMove = true;
}
}
private void LateUpdate() {
if (aiLerp.canMove) {
animator.SetInteger("hSpeed", (int)aiLerp.velocity.x);
animator.SetInteger("vSpeed", (int)aiLerp.velocity.y);
} else {
animator.SetInteger("hSpeed", 0);
animator.SetInteger("vSpeed", 0);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 17314c1a90889c042942aa23b294f835
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TalentListController : MonoBehaviour
{
[SerializeField] List<TalentTabController> talentTabs;
void updateTab(int tabIndex, bool active) {
if (tabIndex < 0 || tabIndex > talentTabs.Count) {
return;
}
if (GameData.IsPlayerUnlocked((Employee)tabIndex)) {
talentTabs[tabIndex].setPanelActive(active);
}
}
public void setActiveTab(int tabIndex) {
for (int i = 0; i < talentTabs.Count; i++) {
updateTab(i, i == tabIndex);
}
}
// Start is called before the first frame update
void Start() {
Debug.Log("TODO: Load a specific set in demo mode regardless of unlock status");
for (int i = 0; i < talentTabs.Count; i++) {
talentTabs[i].gameObject.SetActive(GameData.IsPlayerUnlocked((Employee)i));
}
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55524743610d27d40b6cbc71411bacbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TalentPanelController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8150f5d93e364a42ab7dc29e23e59af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,54 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using TMPro;
public class TalentTabController : MonoBehaviour, IPointerDownHandler
{
[SerializeField] TalentPanelController panel;
[SerializeField] int tabIndex = -1;
[SerializeField] TextMeshProUGUI textName;
[SerializeField] TextMeshProUGUI textEnergy;
[SerializeField] TextMeshProUGUI textStatus;
[SerializeField] TextMeshProUGUI textTips;
[HideInInspector] GameStateController gameStateController;
public void OnPointerDown(PointerEventData eventData) {
gameStateController.HandleSelect(tabIndex);
}
public void setPanelActive(bool active) {
panel.gameObject.SetActive(active);
}
private void Awake() {
// All pop-up panels start inactive.
if (panel) {
panel.gameObject.SetActive(false);
}
}
// Start is called before the first frame update
void Start()
{
gameStateController = GameObject.FindGameObjectWithTag("GameStateController").GetComponent<GameStateController>();
// Load name and level from GameData.
textName.SetText(((Employee)tabIndex).ToString() + " LV" + GameData.GLOBAL.employeeStats[tabIndex].level);
Debug.Log("TODO: Load talent image and whatnot into tab from GameData");
}
private string GetTalentStatus() {
// TODO: Implement from talentState and Talent controller (maybe)
return "Somewhere";
}
private void LateUpdate() {
// Load current stats from TalentState.
textEnergy.SetText(gameStateController.talentState[tabIndex].energy.ToString());
textStatus.SetText(GetTalentStatus());
textTips.SetText("$" + gameStateController.talentState[tabIndex].tips.ToString());
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d421b28363a2eed4988c7725c29d4178
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 542c7cb6002bbe04bb06a0dccefc75d5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine;
using TMPro;
public class IntroFadeController : MonoBehaviour, IPointerDownHandler {
[SerializeField] List<TextMeshProUGUI> text;
[SerializeField] List<Image> images;
[SerializeField] float crossFadeTime = 1.0f;
[SerializeField] float waitTime = 1.5f;
[HideInInspector] bool readyToTurnOff = false;
[HideInInspector] bool turningOff = false;
[HideInInspector] public bool turnedOff = false;
public void OnPointerDown(PointerEventData eventData) {
if (readyToTurnOff && !turningOff) {
foreach (TextMeshProUGUI tmPro in text) {
tmPro.GetComponent<CanvasRenderer>().SetAlpha(1.0f);
tmPro.CrossFadeAlpha(0.0f, crossFadeTime, false);
}
foreach (Image image in images) {
image.GetComponent<CanvasRenderer>().SetAlpha(1.0f);
image.CrossFadeAlpha(0.0f, crossFadeTime, false);
}
turningOff = true;
StartCoroutine("DoNextWait");
}
}
// Start is called before the first frame update
void Awake()
{
readyToTurnOff = false;
foreach (TextMeshProUGUI tmPro in text) {
tmPro.GetComponent<CanvasRenderer>().SetAlpha(0.0f);
tmPro.CrossFadeAlpha(1.0f, crossFadeTime, false);
}
foreach (Image image in images) {
image.GetComponent<CanvasRenderer>().SetAlpha(0.0f);
image.CrossFadeAlpha(1.0f, crossFadeTime, false);
}
StartCoroutine("DoWait");
}
IEnumerator DoWait() {
yield return new WaitForSeconds(waitTime);
readyToTurnOff = true;
}
IEnumerator DoNextWait() {
yield return new WaitForSeconds(crossFadeTime);
turnedOff = true;
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc466df080317d549aece1a4ff7f0fe6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.LuisPedroFonseca.ProCamera2D;
using UnityEngine.SceneManagement;
public class MainMenuController : MonoBehaviour
{
[SerializeField] ProCamera2DTransitionsFX transition;
[SerializeField] RectTransform menuPanel;
void NewGame() {
VNData.NextScene = Dialogue.Intro;
SceneManager.LoadScene("SceneViewer");
}
void Continue() {
Debug.Log("Start Load");
GameData.Load();
Debug.Log("End Load");
SceneManager.LoadScene("Manager");
}
void Quit() {
Application.Quit();
}
void StartTransition() {
Debug.Log("TODO: Make a sound");
transition.TransitionExit();
menuPanel.gameObject.SetActive(false);
}
public void PressedNewGame() {
transition.OnTransitionExitEnded = NewGame;
StartTransition();
}
public void PressedContinue() {
transition.OnTransitionExitEnded = Continue;
StartTransition();
}
public void PressedQuit() {
transition.OnTransitionExitEnded = Quit;
StartTransition();
}
// Start is called before the first frame update
void Start()
{
transition.TransitionEnter();
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 251a7e0adb1dfd14fbaa2ecfbf2c47bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a5f8c199c5426d54eabe2220823050b4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,96 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using Michsky.MUIP;
using TMPro;
using Febucci.UI;
public class DialogueController : MonoBehaviour, IPointerClickHandler {
[SerializeField] TextMeshProUGUI textTMPro;
[SerializeField] TextMeshProUGUI nameTMPro;
[SerializeField] TextAnimatorPlayer typer;
[SerializeField] ButtonManager button;
[SerializeField] RectTransform optionMenu;
[SerializeField] bool clickAnywhere = false;
[SerializeField] VNController vn = null;
[HideInInspector] List<DialogueInteraction> interactions;
[HideInInspector] public int dialogueIndex = 0;
// Whether to use VNData.NextScene or to pick a random Manager scene
// for the given SidePiece.
[SerializeField] bool chooseManagerScene = false;
private void Interact() {
if (dialogueIndex >= interactions.Count && optionMenu != null) {
optionMenu.gameObject.SetActive(true);
return;
}
if (dialogueIndex >= interactions.Count) {
vn.Done();
return;
}
DialogueInteraction d = interactions[dialogueIndex];
if (vn != null) {
vn.Interact(d);
}
nameTMPro.SetText(d.name);
textTMPro.SetText(d.text);
if (d.unlock != Unlockable.None) {
GameData.Unlock(d.unlock);
}
dialogueIndex += 1;
}
public void NextButtonPressed() {
if (typer.textAnimator.allLettersShown) {
if (button.enabled) {
button.enabled = false;
}
Interact();
} else {
typer.SkipTypewriter();
}
}
public void OnPointerClick(PointerEventData eventData) {
if (clickAnywhere) {
NextButtonPressed();
}
}
// Start is called before the first frame update
void Start()
{
if (clickAnywhere) {
button.gameObject.SetActive(false);
} else {
button.enabled = false;
}
if (optionMenu != null) {
optionMenu.gameObject.SetActive(false);
}
if (chooseManagerScene) {
VNData.NextScene = VNData.GetRandomManagerScene(GameData.GLOBAL.sidePiece);
}
// The scene to play is pre-loaded here.
interactions = VNData.DIALOGUE[VNData.NextScene];
GameData.GLOBAL.viewedScenes.Add(VNData.NextScene);
vn.SetUp(VNData.NextScene);
Interact();
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d33d7fc2a127484428ab8e80ea62bd10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,123 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.LuisPedroFonseca.ProCamera2D;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ManagerController : MonoBehaviour {
[SerializeField] ProCamera2DTransitionsFX transition;
[SerializeField] string mainGameSceneName;
[SerializeField] string mainMenuSceneName;
[SerializeField] string sceneViewerSceneName;
[SerializeField] string managerSceneName;
[SerializeField] RectTransform menuBox;
[SerializeField] RectTransform dialogueBox;
[SerializeField] RectTransform optionPicker;
[SerializeField] RectTransform scenePicker;
[SerializeField] RectTransform sidePiecePicker;
[SerializeField] VerticalLayoutGroup scenePickerList;
[SerializeField] RectTransform iridaPickButton;
[SerializeField] RectTransform clemPickButton;
[SerializeField] RectTransform schroderPickButton;
[SerializeField] GameObject ScenePickerButtonProto;
private void Start() {
transition.TransitionEnter();
}
public void SaveButtonPressed() {
Debug.Log("TODO: Autosave toggle as option");
GameData.Save();
Debug.Log("TODO: Play a save noise");
}
public void OptionScenePickerPressed() {
foreach (Transform child in scenePickerList.transform) {
Destroy(child.gameObject);
}
// Get all unlocked scenes.
foreach (Dialogue d in VNData.DIALOGUE_DESCRIPTIONS.Keys) {
if (!VNData.UNLOCKABLES.ContainsKey(d) ||
GameData.IsUnlocked(VNData.UNLOCKABLES[d])) {
ViewSceneButtonController newButton = Instantiate(ScenePickerButtonProto).GetComponent<ViewSceneButtonController>();
newButton.SetUp(d);
newButton.transform.SetParent(scenePickerList.transform);
}
}
scenePicker.gameObject.SetActive(true);
optionPicker.gameObject.SetActive(false);
}
public void OnChangeSidePiecePressed() {
optionPicker.gameObject.SetActive(false);
sidePiecePicker.gameObject.SetActive(true);
iridaPickButton.gameObject.SetActive(GameData.IsPlayerUnlocked(Employee.Irida));
clemPickButton.gameObject.SetActive(GameData.IsPlayerUnlocked(Employee.Clem));
schroderPickButton.gameObject.SetActive(GameData.IsPlayerUnlocked(Employee.Schroder));
}
public void SidePiecePickerBackPressed() {
optionPicker.gameObject.SetActive(true);
sidePiecePicker.gameObject.SetActive(false);
}
public void ScenePickerBackPressed() {
scenePicker.gameObject.SetActive(false);
optionPicker.gameObject.SetActive(true);
}
public void PickSidePiece(int e) {
// Why does Modern UI Pack not support enums?!
GameData.GLOBAL.sidePiece = (Employee)e;
transition.OnTransitionExitEnded = ResetManager;
StartTransition();
}
void MainMenu() {
SceneManager.LoadScene(mainMenuSceneName);
}
void NextDay() {
SceneManager.LoadScene(mainGameSceneName);
}
void ShowVNScene() {
SceneManager.LoadScene(sceneViewerSceneName);
}
void ResetManager() {
SceneManager.LoadScene(managerSceneName);
}
void StartTransition() {
transition.TransitionExit();
menuBox.gameObject.SetActive(false);
dialogueBox.gameObject.SetActive(false);
}
public void SceneViewButtonPressed(Dialogue scene) {
VNData.NextScene = scene;
transition.OnTransitionExitEnded = ShowVNScene;
StartTransition();
Debug.Log("TODO: Make a sound");
}
public void NextDayPressed() {
transition.OnTransitionExitEnded = NextDay;
StartTransition();
Debug.Log("TODO: Make a sound");
}
public void MainMenuPressed() {
Debug.Log("TODO: Maybe add save-first confirmation, or auto-save");
transition.OnTransitionExitEnded = MainMenu;
StartTransition();
Debug.Log("TODO: Make a sound");
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7621006841812f845b79853f76fc080c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class ViewSceneButtonController : MonoBehaviour {
[HideInInspector] public Dialogue scene;
[HideInInspector] public bool isNewScene = false;
[SerializeField] TextMeshProUGUI sceneNameText;
public void SetUp(Dialogue sceneId) {
scene = sceneId;
sceneNameText.SetText(VNData.DIALOGUE_DESCRIPTIONS[sceneId].name);
isNewScene = GameData.GLOBAL.viewedScenes.Contains(sceneId);
}
public void ViewButtonClicked() {
Debug.Log("TODO: Look up and use DIALOGUE_DESCRIPTIONS[scene].warnings");
Debug.Log("TODO: Look up and use DIALOGUE_DESCRIPTIONS[scene].description");
ManagerController manager = GameObject.FindGameObjectWithTag("Manager").GetComponent<ManagerController>();
manager.SceneViewButtonPressed(scene);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 40b4c3e5be8c3e347a555eb8a5641b7d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,180 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StreamController : MonoBehaviour
{
// May be a flatUI arrow or pixel art arrow.
// Pixel art is used in gameplay streams.
// FlatUI arrows are used in cutaway scene streams.
[SerializeField] public GameObject arrowPrefab;
[SerializeField] public AudioClip hitClip;
[SerializeField] public AudioClip missClip;
[SerializeField] public AudioClip winClip;
[SerializeField] public AudioClip loseClip;
[SerializeField] public GameObject arrowGroup;
[SerializeField] public AudioSource audioSource;
[SerializeField] public List<ArrowController> arrows;
[SerializeField] public float resetDelay = 0.5f;
[SerializeField] public bool debug = false;
StreamInfo info;
bool isTicking = false;
float startTime = 0.0f;
int passed = 0;
public class StreamInfo
{
public int numArrows { get; set; }
public float timeLimit { get; set; }
public float startDelay { get; set; }
public float endDelay { get; set; }
// Whether or not to auto-close the Stream after winning or losing.
// Infinite scenes are for special enjoyment events.
public bool infinite { get; set; }
// In sudden death, missing one arrow fails the event even if
// the timer is still running.
public bool suddenDeath { get; set; }
public Sprite beforeBG { get; set; } = null;
public Sprite winBG { get; set; } = null;
public Sprite loseBG { get; set; } = null;
public AudioClip beforeClip { get; set; } = null;
public AudioClip winClip { get; set; } = null;
public AudioClip loseClip { get; set; } = null;
}
public void Init(StreamInfo info, bool wait = true)
{
this.info = info;
passed = 0;
// Calculate int[] keys
for (int i = 0; i < info.numArrows; i++)
{
ArrowController arrow = Instantiate(arrowPrefab).GetComponent<ArrowController>();
arrow.key = Random.Range(0, 4);
arrow.Init();
arrow.transform.parent = arrowGroup.transform;
arrows.Add(arrow);
}
if (wait)
{
Invoke("StartTimer", info.startDelay);
}
}
public void Start()
{
if (debug)
{
Init(new StreamInfo
{
numArrows = 5,
timeLimit = 5.0f,
startDelay = 1.0f,
endDelay = 1.0f,
infinite = true,
suddenDeath = false
});
}
}
public void MakeGlow(int arrowIndex)
{
// TODO: implement (make the arrow at ArrowIndex glow)
// use the shader thing
}
void StartTimer()
{
isTicking = true;
MakeGlow(0);
}
void Reset()
{
foreach (ArrowController arrow in arrows)
{
Destroy(arrow.gameObject);
}
arrows.Clear();
Init(this.info, false);
isTicking = true;
MakeGlow(0);
}
void TryHit(int key)
{
if (passed < info.numArrows)
{
if (arrows[passed].key == key)
{
// You hit the right arrow, move to the next one
audioSource.PlayOneShot(hitClip);
arrows[passed].Succeed();
passed += 1;
} else
{
arrows[passed].Fail();
if (!info.suddenDeath)
{
audioSource.PlayOneShot(missClip);
isTicking = false;
Invoke("Reset", resetDelay);
} else
{
// TODO: do a lose thing
audioSource.PlayOneShot(loseClip);
}
}
if (passed == info.numArrows)
{
// TODO: do a win thing
audioSource.PlayOneShot(winClip);
if (debug)
{
isTicking = false;
Invoke("Reset", resetDelay);
}
} else
{
MakeGlow(passed);
}
}
}
// Update is called once per frame
void Update()
{
// Process key presses if the delay is over
if (isTicking)
{
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
Debug.Log("Left");
TryHit(0);
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
Debug.Log("Down");
TryHit(1);
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
Debug.Log("Up");
TryHit(2);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
Debug.Log("Right");
TryHit(3);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e6792d796628ff4aac782bb7c86e0e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class TextFadeController : MonoBehaviour
{
[SerializeField] public TextMeshPro text;
[SerializeField] float dieTime = 1.0f;
[SerializeField] public Color baseColor = Color.white;
[HideInInspector] float alpha = 1.0f;
[HideInInspector] float startTime = -1.0f;
private void Awake()
{
startTime = Time.time;
}
// Update is called once per frame
void LateUpdate()
{
alpha = Mathf.Max(0.0f, 1.0f - (Time.time - startTime) / dieTime);
text.color = new Color(baseColor.r, baseColor.g, baseColor.b, alpha);
if (alpha == 0.0f) {
Destroy(gameObject);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80f674085ddc54541ae3d2314158e7cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: df380fdb6808fca4bb2668eb8ade4c8c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,152 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using Com.LuisPedroFonseca.ProCamera2D;
public class VNController : MonoBehaviour {
[SerializeField] float bgCrossfadeTime = 0.5f;
[SerializeField] DialogueController dialogueBox;
[SerializeField] VNSpriteController vnSpriteCenter;
[SerializeField] VNSpriteController vnSpriteLeft;
[SerializeField] VNSpriteController vnSpriteRight;
[SerializeField] Image bgBack;
// Used for cross-fading.
[SerializeField] Image bgFront;
[SerializeField] bool LeaveAfterDone = false;
[HideInInspector] VNObjectController vnAssets;
[HideInInspector] AudioSource audioSource;
[HideInInspector] bool isLeaving = false;
[SerializeField] ProCamera2DTransitionsFX transition;
[SerializeField] bool loadExternalAssets = false;
private void Leave() {
SceneManager.LoadScene("Manager");
}
public void Done() {
if (LeaveAfterDone && !isLeaving) {
transition.OnTransitionExitEnded = Leave;
transition.TransitionExit();
isLeaving = true;
}
}
private class SetSpriteOptions {
public Body spriteBody { get; set; } = Body.None;
// Requires spriteBody.
public int spriteHair { get; set; } = 0;
public Expression spriteExpression { get; set; } = Expression.None;
public bool removeSprite { get; set; } = false;
}
private void SetSprite(VNSpriteController spriteController, SetSpriteOptions options) {
int spriteIndex = (int)options.spriteBody - 1;
if (options.spriteBody != Body.None && spriteIndex < vnAssets.sprites.Count) {
spriteController.body.gameObject.SetActive(true);
spriteController.body.sprite = vnAssets.sprites[spriteIndex];
spriteController.hair.gameObject.SetActive(true);
spriteController.hair.sprite = vnAssets.spriteHairs[options.spriteHair];
}
int spriteExpressionIndex = (int)options.spriteExpression - 1;
if (options.spriteExpression != Expression.None && spriteExpressionIndex < vnAssets.spriteExpressions.Count) {
spriteController.expression.gameObject.SetActive(true);
spriteController.expression.sprite = vnAssets.spriteExpressions[spriteExpressionIndex];
}
if (options.removeSprite) {
spriteController.body.gameObject.SetActive(false);
spriteController.hair.gameObject.SetActive(false);
spriteController.expression.gameObject.SetActive(false);
}
Debug.Log("TODO: Effect animation");
}
public void Interact(DialogueInteraction interaction) {
// Cancel any pending crossfades.
if (bgFront != null) {
bgFront.CrossFadeAlpha(1.0f, 0.0f, false);
}
// If there's a new background, fade into it.
if (bgFront != null && bgBack != null && interaction.backgroundIndex > -1) {
if (bgBack.sprite != null) {
bgBack.sprite = bgFront.sprite;
if (interaction.backgroundIndex < vnAssets.backgrounds.Count) {
bgFront.sprite = vnAssets.backgrounds[interaction.backgroundIndex];
bgFront.GetComponent<CanvasRenderer>().SetAlpha(0);
bgFront.CrossFadeAlpha(1.0f, bgCrossfadeTime, false);
Debug.Log(bgFront.color.ToString());
Debug.Log(bgFront.sprite.ToString());
} else {
Debug.LogError("Background index out of range for interaction!");
}
} else {
bgBack.sprite = bgFront.sprite = vnAssets.backgrounds[interaction.backgroundIndex];
bgFront.CrossFadeAlpha(1.0f, 0.0f, false);
}
}
// If there's an audio clip, play it.
if (audioSource != null && interaction.audioClipIndex > -1) {
if (interaction.audioClipIndex < vnAssets.voiceBank.Count) {
audioSource.PlayOneShot(vnAssets.voiceBank[interaction.audioClipIndex]);
} else {
Debug.LogError("AudioClip index out of range for interaction!");
}
}
// If a sprite is defined, set it.
SetSprite(vnSpriteCenter, new SetSpriteOptions() {
spriteBody = interaction.body1,
spriteHair = interaction.hair1,
spriteExpression = interaction.expression1,
removeSprite = interaction.removeBody1,
});
SetSprite(vnSpriteLeft, new SetSpriteOptions() {
spriteBody = interaction.body2,
spriteHair = interaction.hair2,
spriteExpression = interaction.expression2,
removeSprite = interaction.removeBody2,
});
SetSprite(vnSpriteRight, new SetSpriteOptions() {
spriteBody = interaction.body3,
spriteHair = interaction.hair3,
spriteExpression = interaction.expression3,
removeSprite = interaction.removeBody3,
});
// TODO: If there's a music clip, stop the currently running clip and play it.
Debug.Log("TODO: Music change");
}
// Called by DialogueControler to enforce loading before the first Interact.
public void SetUp(Dialogue scene)
{
if (loadExternalAssets) {
vnAssets = Instantiate((GameObject)Resources.Load(VNData.GetDialogueAssetPackFor(scene), typeof(GameObject))).GetComponent<VNObjectController>();
} else {
vnAssets = gameObject.GetComponent<VNObjectController>();
}
audioSource = gameObject.GetComponent<AudioSource>();
if (LeaveAfterDone) {
transition.TransitionEnter();
}
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c2a9e172aa31a2540aec950c37a797b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class VNObjectController : MonoBehaviour
{
[SerializeField] public List<Sprite> backgrounds;
[SerializeField] public List<Sprite> sprites;
[SerializeField] public List<Sprite> spriteExpressions;
[SerializeField] public List<Sprite> spriteHairs;
[SerializeField] public List<Sprite> spriteOverlays;
[SerializeField] public List<AudioClip> voiceBank;
[SerializeField] public List<AudioClip> musicBank;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01274bba8e881e74bbaeb75435b4baae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class VNSpriteController : MonoBehaviour {
[SerializeField] public Image body;
[SerializeField] public Image expression;
[SerializeField] public Image hair;
[SerializeField] public Image effect;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54bb159ea8ec1f24fba4dc1c9395d787
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: