Add Peter & Clara afternoon dialogue
[wgj58.git] / wgj58.js
index e034b01a3eeb3155b41d0c874e1150c64147cc79..71b0484725d4b015551a0053e6a9b5cc1d8b3626 100644 (file)
--- a/wgj58.js
+++ b/wgj58.js
@@ -40,10 +40,63 @@ class Dialogue {
 }
 
 class Door extends Phaser.TileSprite {
-       constructor(x, y, name, vector, longpanel) {
+       constructor(x, y, name, rotation, vector, longpanel) {
                super(game, x, y, 64, 64, 'objects');
-               this.tilePosition = new Phaser.Point(-64, -64);
-               console.log("New door:", this);
+               this.name = name;
+               this.longpanel = longpanel;
+               if (!longpanel) {
+                       this.anchor = new Phaser.Point(0.5, 0.5);
+                       this.tilePosition = new Phaser.Point(-64, -64);
+                       this.openvector = Phaser.Point.multiply(vector, new Phaser.Point(56, 56));
+               }
+               else {
+                       this.width *= 2;
+                       this.anchor = new Phaser.Point(0.75, 0.5);
+                       this.tilePosition = new Phaser.Point(0, -64);
+                       this.openvector = Phaser.Point.multiply(vector, new Phaser.Point(116, 116));
+               }
+               if (rotation === undefined) rotation = 0;
+               this.rotation = rotation * (Math.PI / 180);
+               this.closetween = game.add.tween(this).to({ x: this.position.x, y: this.position.y }, 1000, Phaser.Easing.Sinusoidal.InOut, false, 0, 0, false);
+               this.openposition = Phaser.Point.add(this.position, this.openvector);
+               this.opentween = game.add.tween(this).to({ x: this.openposition.x, y: this.openposition.y }, 1000, Phaser.Easing.Sinusoidal.InOut, false, 0, 0, false);
+               this.isOpen = false;
+               game.physics.arcade.enable(this);
+               this.body.immovable = true;
+               this.setBody(rotation);
+       }
+
+       setBody(rotation) {
+               switch(rotation) {
+                       case 0:
+                       case 180:
+                               this.body.setSize(this.width, 10, this.longpanel * (rotation / 180) * 64, 27);
+                               break;
+                       case 90:
+                       case 270:
+                               this.body.setSize(10, this.width, 27 + (this.longpanel * 64), this.longpanel * ((rotation - 270) / 180) * 64);
+                               break;
+                       default:
+                               console.log("Unable to set body due to unknown rotation:", rotation);
+               }
+       }
+
+       open() {
+               if (!this.isOpen) {
+                       this.opentween.start();
+                       this.isOpen = true;
+               }
+       }
+
+       close() {
+               if (this.isOpen) {
+                       this.closetween.start();
+                       this.isOpen = false;
+               }
+       }
+
+       update() {
+               game.debug.body(this);
        }
 }
 
@@ -106,6 +159,8 @@ class Player extends Phaser.Sprite {
        takeMe(npc) {
                this.loadTexture(npc.key);
                npc.kill();
+               this.disguise = npc;
+               logic.gameinterface.dropNoticeTimeout(Phaser.Timer.SECOND * 5, "You are now identified as " + npc.fullname + "!");
        }
 }
 
@@ -117,12 +172,14 @@ class GameNPC extends Phaser.Sprite {
                this.fullname = fullname;
                this.interaction_distance = interaction_distance;
                this.interactable = false;
-               this.talkcount = 0;
+               this.resetTalk();
+               this.happy = false;
        }
 
        kill() {
                super.kill();
                this.exists = false;
+               this.happy = false;                     // Dead people are not happy.
        }
 
        update() {
@@ -137,6 +194,11 @@ class GameNPC extends Phaser.Sprite {
                        logic.player.offerInteraction(null);
                        this.interactable = false;
                }
+               if ((this.teleport_instructions) && (game.physics.arcade.distanceBetween(this, logic.player) > (game.width + 200))) {
+                       this.position = this.teleport_instructions.newPosition;
+                       this.teleport_instructions.callback(this.teleport_instructions.callbackValue);
+                       this.teleport_instructions = null;
+               }
        }
 
        actionTalk() {
@@ -155,6 +217,20 @@ class GameNPC extends Phaser.Sprite {
        endTalk() {
                return true;
        }
+
+       resetTalk() {
+               this.talkcount = 0;
+       }
+
+       makeHappy() {
+               this.happy = true;
+               console.log(this.shortname, "is happy!");
+       }
+
+       offscreenTeleportation(newPosition, callback, callbackValue) {
+               this.teleport_instructions = { newPosition: newPosition, callback: callback, callbackValue: callbackValue };
+               console.log("Offscreen teleport request registered:", this.teleport_instructions);
+       }
 }
 
 class NPC_Clara extends GameNPC {
@@ -169,7 +245,9 @@ class NPC_Clara extends GameNPC {
                                        { actor: logic.player, text: "Well, maybe if we dare to joke about it, it won't happen to us..." },
                                        { actor: this, text: "Wish it worked like that... Is it some superstition like the belief that having an umbrella with you prevents rain?" },
                                        { actor: logic.player, text: "Nah, that actually works; it's not a superstition, but Murphy's Law!" },
-                                       { actor: this, text: "If you say so..." } ] ));
+                                       { actor: this, text: "If you say so..." },
+                                       { actor: this, text: "Anyway, I logged you in and opened the door for you." } ] ));
+                               logic.openDoor("cutedoor");
                                break;
                        case 1:
                                logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "John, have you ever thought about losing your employee card?" },
@@ -218,11 +296,548 @@ class NPC_Clara extends GameNPC {
                logic.gameinterface.dropNotice(this.shortname + ": Have a great day, John!");
        }
 
+       actionTake() {
+               logic.openDoor("cutedoor");
+               return super.actionTake();
+       }
+
        endTalk() {
                return (this.talkcount < 6);
        }
 }
 
+class NPC_Carlos extends GameNPC {
+       actionTalk() {
+               if (logic.clara.alive) {
+                       if (logic.saiki.talkcount == 0) {
+                               switch (this.talkcount) {
+                                       case 0:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Good morning, Carlos! What's up?" },
+                                                       { actor: this, text: "Hey, John! Not too much, I'm just trying to sell some shit to this new client." },
+                                                       { actor: logic.player, text: "And so? Is it hard to convince them?" },
+                                                       { actor: this, text: "Of course, they don't want to buy. It's shit." },
+                                                       { actor: this, text: "I mean, who would want to buy shit?" },
+                                                       { actor: logic.player, text: "Yeah. Relatable... But why are you trying to sell shit? I mean, why not one of our cutting edge technologies?" },
+                                                       { actor: this, text: "They couldn't afford it." },
+                                                       { actor: logic.player, text: "Then why are you trying to sell them... anything at all? They'd better off with a cheaper company." },
+                                                       { actor: this, text: "Company policies. Plus the management instructed me to sell to them, no matter what." },
+                                                       { actor: logic.player, text: "That sucks... Well... good luck!" },
+                                                       { actor: this, text: "Thanks..." } ] ));
+                                               logic.closeDoor("cutedoor");
+                                               logic.openDoor("carlosdoor");
+                                               break;
+                                       case 1:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "*Sigh.* I'll probably not work here for long, if I can't sell this shit to the customer." },
+                                                       { actor: this, text: "These layoffs are terrifying. They let go of anyone for even the slightest mistake." },
+                                                       { actor: logic.player, text: "But it's not a mistake when our client doesn't buy something they don't need." },
+                                                       { actor: this, text: "Tell this to my boss..." } ] ));
+                                               break;
+                                       case 2:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "You know, generally, I think it sucks being a child. One thing I miss though, if you're a child, you're allowed to be silly." },
+                                                       { actor: this, text: "..." },
+                                                       { actor: this, text: "For example, when my Dad told me that semen is the seed of animals, I theoretized, if I'd bury some pig semen in the garden, a pig would grow out of it..." },
+                                                       { actor: this, text: "I was totally fascinated by the thought, because I really wanted to have a pet pig, but Dad wouldn't let me have one." },
+                                                       { actor: this, text: "So I thought I could grow my own pig in the garden from pig seeds!" },
+                                                       { actor: logic.player, text: "Interesting. Where are you going with this?" },
+                                                       { actor: this, text: "I don't know... sometimes I feel like I'd rather sell pig semen to our clients, heh!" },
+                                                       { actor: this, text: "Uhm..." },
+                                                       { actor: this, text: "Totally don't tell this to Saiki!" } ] ));
+                                               this.pigsemen = true;
+                                               break;
+                                       case 3:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Weren't you heading to the IT department to the right?" },
+                                                       { actor: this, text: "You know... the green department which looks way better than blue!" },
+                                                       { actor: this, text: "..." },
+                                                       { actor: this, text: "Damn, why do I have to work in blue? I just feel... so blue about it." } ] ));
+                                               break;
+                                       case 4:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Weren't you heading to the conveniently green department to the right? I guess Saiki is waiting for you." },
+                                                       { actor: this, text: "You're so lucky that you can work with her every day!" } ] ));
+                                               break;
+                                       default:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Guess you'll stay here then. It's cool, you're great company anyway." } ] ));
+                               }
+                       }
+                       else {
+                               switch (this.talkcount) {
+                                       case 0:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Phew... long shift, I gotta go!" },
+                                                       { actor: this, text: "Why are you still here? I mean, you engineers stay here 'til late at night. Why don't you just go home at 4 pm?" },
+                                                       { actor: this, text: "This is why I can never ask out Saiki... She always works for so long..." },
+                                                       { actor: logic.player, text: "We tend to have lots of work with impossible deadlines..." },
+                                                       { actor: this, text: "I bet you get lots of money for the overtimes!" },
+                                                       { actor: logic.player, text: "No, we don't get paid for overtimes." },
+                                                       { actor: this, text: "... Then why do you stay beyond the office hours?" },
+                                                       { actor: logic.player, text: "Otherwise we're fired. That's the deal. Either we work 2 extra hours or we get replaced." },
+                                                       { actor: this, text: "Wow... and I thought we have a shortage on engineers..." } ] ));
+                                               break;
+                                       case 1:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "And how's the business going? Did you manage to shell the shit?" },
+                                                       { actor: this, text: "In a heartbeat! Now they're buying so much shit that I'm afraid we don't have enough assholes to produce that quantity." },
+                                                       { actor: this, text: "Be prepared for another month of overtimes. This deal will be huge!" },
+                                                       { actor: logic.player, text: "Well done, man!" } ] ));
+                                               break;
+                                       default:
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "I really want to leave now." } ] ));
+                                               this.offscreenTeleportation(new Phaser.Point(0, 0), this.tpDone, this);
+                               }
+                       }
+               }
+               else {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Good morning, Carlos!" },
+                                               { actor: this, text: "Whoa, Clara! You have changed so much! I barely recognize you. What's up?" },
+                                               { actor: logic.player, text: "I need to talk to Saiki at the IT department, but... my card doesn't allow me to enter there." },
+                                               { actor: this, text: "Well... I can certainly help you with that..." },
+                                               { actor: this, text: "..." } ] ));
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Carlos. You promised to help me." },
+                                               { actor: this, text: "Uhm... It's just... Please give me 5 mins to finish this e-mail." },
+                                               { actor: logic.player, text: "I don't have much time, Carlos." },
+                                               { actor: this, text: "See, it's just 5 mins, please be patient. I have a chocolate bar in the fridge. I give it to you. Feel free to have it meanwhile." },
+                                               { actor: logic.player, text: "..." } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Time is up, Carlos!" },
+                                               { actor: this, text: "Please give me just another min." },
+                                               { actor: logic.player, text: "Fine. Please just give me your card and I'll help myself!" },
+                                               { actor: this, text: "But... you know that company policies forbid that, Clara! Please just be a little more patient!" },
+                                               { actor: logic.player, text: "You will give me your card now or you will regret!" },
+                                               { actor: this, text: "...?" },
+                                               { actor: this, text: "You're not gonna treat me like this. Forget it!" },
+                                               { actor: logic.player, text: "You'll not work here tomorrow." } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "..." } ] ));
+                       }
+               }
+               super.actionTalk();
+       }
+
+       actionLeave() {
+               if ((logic.clara.alive) && (logic.saiki.talkcount == 0)) {
+                       logic.gameinterface.dropNotice(this.shortname + ": Bye, John! Pass on my greetings to Saiki!");
+               }
+       }
+
+       actionTake() {
+               logic.closeDoor("cutedoor");
+               logic.openDoor("carlosdoor");
+               return super.actionTake();
+       }
+
+       endTalk() {
+               return ((logic.clara.alive) && (logic.saiki.talkcount == 0)) || (this.talkcount < 3);
+       }
+
+       tpDone(value) {
+               console.log("Woot-woot! Teleport complete:", value);
+               value.visible = false;
+       }
+}
+
+class NPC_Saiki extends GameNPC {
+       actionTalk() {
+               /* If Saiki is happy, she's already teleported to Carlos. */
+               if (!this.happy)
+                       this.actionTalk_morning();
+               else
+                       this.actionTalk_afternoon();
+       }
+
+       actionTalk_morning() {
+               if (logic.carlos.alive) {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Hi Saiki!" },
+                                               { actor: this, text: "Hi John! Glad you arrived, here's some work for you!" },
+                                               { actor: logic.player, text: "Awesome! What is it?" },
+                                               { actor: this, text: "Haha, joking! Actually, our queue is suspiciously empty for today." },
+                                               { actor: logic.player, text: "Yeah... That's really suspicious!" },
+                                               { actor: logic.player, text: "Maybe I can get home today in time?" },
+                                               { actor: this, text: "You mean, you wouldn't spend the mandatory free extra working hours?" },
+                                               { actor: this, text: "You steal from the company! The company needs your unpaid hours of work! Otherwise, how would we finance the trash can I ordered for the department?" },
+                                               { actor: this, text: "*Whispers with wink.* I hope you get my sarcasm." },
+                                               { actor: logic.player, text: "Haha! I always get it, Saiki!" } ] ));
+                                       logic.closeDoor("carlosdoor");
+                                       logic.openDoor("saikidoor");
+                                       logic.openDoor("peterdoor");
+                                       logic.carlos.resetTalk();
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Now that I think about it, there's still one thing. You could look into why the access control system is acting so funny today." },
+                                               { actor: this, text: "Clara has to enter people manually." },
+                                               { actor: logic.player, text: "Yeah, I'll definitely check that." } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "So... what's up with the trash can?" },
+                                               { actor: this, text: "I'm always up for such deep conversation" },
+                                               { actor: this, text: "about trash cans." },
+                                               { actor: this, text: "While we only have one trash can, other departments seem to be abundant of them. And ours is always filled. So I requested an additional trash can." },
+                                               { actor: this, text: "Now the ticket is in PENDING status. The latest work note is from two months ago, telling there is no budget at the moment." },
+                                               { actor: logic.player, text: "Hmm... Maybe it's too much to ask. Can we take one from another department?" },
+                                               { actor: this, text: "No, everyone holds on to their trash cans." },
+                                               { actor: logic.player, text: "You certainly did your research." },
+                                               { actor: this, text: "Of course. It's an important subject." } ] ));
+                                       break;
+                               case 3:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "My parents named me after a Japanese rock singer." },
+                                               { actor: logic.player, text: "Cool! Which band?" },
+                                               { actor: this, text: "I don't remember the band name. But the particular singer has a blue rose in her hair most of the time." } ] ));
+                                       break;
+                               default:
+                                       if ((logic.carlos.pigsemen) && (this.talkcount == 4)) {
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Did you know that Carlos thought he can grow a pig by burying pig semen in the ground? What do you think about this?" },
+                                                       { actor: this, text: "Hmm..." },
+                                                       { actor: this, text: "I guess it didn't work." },
+                                                       { actor: this, text: "So do you want to know what I think about this?" },
+                                                       { actor: this, text: "..." },
+                                                       { actor: this, text: "IT'S BRILLIANT!!!" },
+                                                       { actor: this, text: "You know, it really sparkled my artistic vision! Now I must draw a pig with its legs rooted into the ground!" },
+                                                       { actor: logic.player, text: "That's gross. Poor pig." },
+                                                       { actor: this, text: "Indeed. But this is the point. He's stuck in one place, cannot move. Like you in life. So you feel sympathy for him." },
+                                                       { actor: logic.player, text: "You have a point." },
+                                                       { actor: this, text: "I think I'll catch Carlos and talk to him. I always liked that guy but I didn't know he's such imaginative." } ] ));
+                                               this.offscreenTeleportation(new Phaser.Point(logic.carlos.x, logic.carlos.y + 64), this.tpDone, this);
+                                       }
+                                       else {
+                                               if (Phaser.Math.random() < 0.5) {
+                                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "I've found an orchestrated rendition of „Potential for Anything”. You'll have to check it out, it's breathtaking!" } ] ));
+                                               }
+                                               else {
+                                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "I don't like that our department is green. The blue one, where Carlos works, looks much better." } ] ));
+                                               }
+                                       }
+                       }
+               }
+               else {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "I love you, Saiki!" },
+                                               { actor: this, text: "Hi Carlos..." },
+                                               { actor: logic.player, text: "I'm infatuated by the mere thought of you." },
+                                               { actor: this, text: "Well... it sounds pretty much creepy." },
+                                               { actor: logic.player, text: "Will you go out on a date with me?" },
+                                               { actor: this, text: "..." },
+                                               { actor: this, text: "Sorry to hurt your feelings, but... even though I like you... Your sudden, unprecedented confession makes me scared." },
+                                               { actor: this, text: "Especially with that facial expression." },
+                                               { actor: this, text: "I mean... you're not even joking." },
+                                               { actor: this, text: "So sorry... I won't date you." } ] ));
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "I thought I could impress you." },
+                                               { actor: this, text: "I'm sorry." } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "You will give me your card." },
+                                               { actor: this, text: "Geez, what for? Go back to your department and work!" },
+                                               { actor: logic.player, text: "I need it." },
+                                               { actor: this, text: "..." } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Don't you have anything better to do, Carlos?" } ] ));
+                       }
+               }
+               super.actionTalk();
+       }
+
+       actionTalk_afternoon() {
+               if (logic.peter.alive) {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Oh, hi John!" },
+                                               { actor: logic.carlos, text: "Hey John! Thanks for telling my secret to Saiki..." },
+                                               { actor: logic.player, text: "Really sorry man, but it was so funny!" },
+                                               { actor: logic.carlos, text: "Are you kidding me? It's the best thing you could have ever done!" },
+                                               { actor: this, text: "Yeah, I couldn't resist to come over here to talk about it, haha!" },
+                                               { actor: logic.carlos, text: "And we talked about lots of other stuff too..." },
+                                               { actor: this, text: "WE ASKED EACH OTHER OUT ON A DATE!!!" },
+                                               { actor: logic.carlos, text: "Yeah, Saiki finds gender equality so important that she had to take the role of the initiator, just in the right moment when I asked her out." },
+                                               { actor: this, text: "Oh, shut up! xD" },
+                                               { actor: logic.player, text: "Awesome, I'm so happy for you guys!" },
+                                               { actor: logic.player, text: "... Don't mean to ruin the fun, but have you finished with your work?" },
+                                               { actor: logic.carlos, text: "Who cares? It waits. I can totally sell the shit tomorrow." },
+                                               { actor: this, text: "Yeah, I'll commit my patch tomorrow morning. We definitely deserve some fun!" },
+                                               { actor: logic.player, text: "You say it right! Bye then." } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Have a great evening, guys!" } ] ));
+                       }
+               }
+               else {
+                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Oh... hi Peter!..." },
+                               { actor: this, text: "I wanted to talk to Carlos..." },
+                               { actor: this, text: "Where is he? I mean, he often leaves early, but..." },
+                               { actor: this, text: "I can't explain why, but somehow I have a very bad feeling about this. " },
+                               { actor: logic.player, text: "..." } ] ));
+               }
+               super.actionTalk();
+       }
+
+       actionLeave() {
+               if (logic.carlos.alive) {
+                       logic.gameinterface.dropNotice(this.shortname + ": It was nice talking to you!");
+               }
+       }
+
+       actionTake() {
+               logic.closeDoor("carlosdoor");
+               logic.openDoor("saikidoor");
+               logic.openDoor("peterdoor");
+               logic.carlos.kill();
+               return super.actionTake();
+       }
+
+       endTalk() {
+               return (logic.carlos.alive) && (!this.happy);
+       }
+
+       tpDone(value) {
+               console.log("Woot-woot! Teleport complete:", value);
+               value.makeHappy();
+               value.resetTalk();
+               logic.carlos.makeHappy();
+               // FIXME: Need to find a prettier way than this.
+               logic.carlos.update = function() { };           // Disable Carlos' interaction. (Saiki will talk for him.)
+       }
+}
+
+class NPC_Peter extends GameNPC {
+       actionTalk() {
+               /* If Peter is happy, she's already teleported to Clara. */
+               if (!this.happy)
+                       this.actionTalk_morning();
+               else
+                       this.actionTalk_afternoon();
+       }
+
+       actionTalk_morning() {
+               if (logic.saiki.alive) {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Hi Peter! What's up?" },
+                                               { actor: this, text: "Hi John! Bianca has locked herself in the large meeting room." },
+                                               { actor: logic.player, text: "Why would she do that?" },
+                                               { actor: this, text: "I have no idea." },
+                                               { actor: this, text: "Normally, I would give a fuck about what she's doing and her problems, but I want to hold a meeting in an hour." },
+                                               { actor: logic.player, text: "That was rude. I think you should care more about your colleagues." },
+                                               { actor: this, text: "Ahh... You're right. I didn't mean it. I'm just so frustrated about all the shit going on here." } ] ));
+                                       logic.closeDoor("saikidoor");
+                                       logic.openDoor("peterdoor");
+                                       logic.openDoor("biancadoor");
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "See... Would you talk to Bianca? We don't understand each other pretty well. That's why I'd rather wouldn't make a shot." } ] ));
+                                       break;
+                               default:
+                                       if ((logic.clara.talkcount >= 5) && (this.talkcount == 2)) {
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Do you know Clara from the Reception?" },
+                                                       { actor: this, text: "Of course I do." },
+                                                       { actor: logic.player, text: "I think she's mad at me..." },
+                                                       { actor: this, text: "Why would she?" },
+                                                       { actor: logic.player, text: "I kind of... asked her out." },
+                                                       { actor: logic.player, text: "She said no." },
+                                                       { actor: this, text: "What the heck, dude?" },
+                                                       { actor: this, text: "..." },
+                                                       { actor: this, text: "You should know it's against the company etiquette..." },
+                                                       { actor: this, text: "Regardless, I don't think she's really mad. You're a cool guy." },
+                                                       { actor: logic.player, text: "I hope this will be sorted out... I totally accept her answer, but I wouldn't like her to have negative feelings towards me." } ] ));
+                                               this.offscreenTeleportation(new Phaser.Point(logic.clara.x - 160, logic.clara.y), this.tpDone, this);
+                                       }
+                                       else {
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "I'm kind of busy, man." } ] ));
+                                       }
+                       }
+               }
+               else {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "What a wonderful day, Peter!" },
+                                               { actor: this, text: "Yikes! Saiki! You scared me!" },
+                                               { actor: logic.player, text: "I didn't even say \"boo\"." },
+                                               { actor: this, text: "Are you OK? You look horrible! You should really see a doctor." },
+                                               { actor: logic.player, text: "I'm fine, Peter. And you?" },
+                                               { actor: this, text: "No... Not at all." },
+                                               { actor: logic.player, text: "I'm sorry to hear that..." } ] ));
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Don't come closer to me!" },
+                                               { actor: logic.player, text: "Why?" },
+                                               { actor: this, text: "I don't mean to offend you, but... you really creep me out..." },
+                                               { actor: logic.player, text: "Why do you say that?" },
+                                               { actor: this, text: "I honestly can't tell what's wrong with you, but... you look like that ghost girl from The Ring!" } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Now that was pretty much racist..." },
+                                               { actor: logic.player, text: "Just because I have a Japanese name and long black hair, that makes me immediately look like the Japanese girl from Ring when I'm sick?" },
+                                               { actor: this, text: "Geez... that's not even a Japanese movie! And the actress is American..." },
+                                               { actor: logic.player, text: "The original movie is Japanese." },
+                                               { actor: this, text: "I don't care... Just... keep distance, please!" } ] ));
+                                       break;
+                               default:
+                                       if (Phaser.Math.random() < 0.5) {
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "STAY AWAY FROM ME!" } ] ));
+                                       }
+                                       else {
+                                               logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "DON'T COME ANY CLOSER!" } ] ));
+                                       }
+                       }
+               }
+               super.actionTalk();
+       }
+
+       actionTalk_afternoon () {
+               if (logic.bianca.alive) {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Hey John!" },
+                                               { actor: logic.player, text: "Hey, what's up?" },
+                                               { actor: this, text: "I just asked Clara out on a date!" },
+                                               { actor: logic.clara, text: "Shhhsh, don't brag about it! I'm a person, not a prize." },
+                                               { actor: this, text: "Sorry..." },
+                                               { actor: logic.clara, text: "It's OK... Uhm... Sorry, John... I always liked Peter... but when you asked me out, I felt intimidated and a little uncomfortable." } ] ));
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "I'm sorry, Clara, I didn't mean to be inappropriate... situations like this are always so complicated..." },
+                                               { actor: logic.clara, text: "Never mind, John. I didn't handle it properly either. Apology accepted." },
+                                               { actor: this, text: "Everyone's happy, I guess." },
+                                               { actor: logic.player, text: "Not really. Maybe I'm gonna be fired." },
+                                               { actor: this, text: "Haha, you're a joker!" } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "*Whispers.* Khm, no offense, but it would be nice if you excused yourself and leave. You know how it is..." } ] ));
+                                       break;
+                               case 3:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Oh, time goes so fast... I have to go. Bye!" } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "..." } ] ));
+                       }
+               }
+               else {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "..." },
+                                               { actor: logic.clara, text: "..." },
+                                               { actor: logic.player, text: "Hey there!... Uhm... Don't you have anything better to do?" },
+                                               { actor: this, text: "Yeah, I would totally have if you weren't been blocking the meeting room!" } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Get back to work! Don't make me say it again!" } ] ));
+                       }
+               }
+               super.actionTalk();
+       }
+
+       actionTake() {
+               logic.closeDoor("saikidoor");
+               logic.openDoor("peterdoor");
+               logic.openDoor("biancadoor");
+               logic.carlos.kill();
+               if (logic.saiki.talkcount > 0) logic.saiki.kill();
+               return super.actionTake();
+       }
+
+       endTalk() {
+               return (logic.saiki.alive) && (this.talkcount < 3) && (!this.happy);
+       }
+
+       tpDone(value) {
+               console.log("Woot-woot! Teleport complete:", value);
+               value.makeHappy();
+               value.resetTalk();
+               logic.clara.makeHappy();
+               // FIXME: Need to find a prettier way than this.
+               logic.clara.update = function() { };            // Disable Clara's interaction. (Peter will talk for him.)
+       }
+}
+
+class NPC_Bianca extends GameNPC {
+       actionTalk() {
+               if (logic.peter.alive) {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "... Hi Bianca!" },
+                                               { actor: this, text: "... Hello John!" },
+                                               { actor: logic.player, text: "So I've been told, you've been spending most of the day in this meeting room..." },
+                                               { actor: this, text: "Yeah?" },
+                                               { actor: logic.player, text: "... Your colleagues want to hold a meeting in this room and you're blocking it." },
+                                               { actor: this, text: "Hmm... Kind of that's the point... There is no need for that meeting." },
+                                               { actor: logic.player, text: "May I know why?" },
+                                               { actor: this, text: "You must have heard about the layoffs. We weren't happy with that, but it was inevitable to meet the productivity requirements." },
+                                               { actor: this, text: "But today morning, I received a list with about 50% of the employees... Many of them are great friends of mine..." },
+                                               { actor: this, text: "We were like a big family here and we're torn apart like this... The worst is that I have to tell the news to all of them." },
+                                               { actor: logic.player, text: "That's rough. Does this company even need people?" },
+                                               { actor: this, text: "..." } ] ));
+                                       logic.openDoor("cutedoor");
+                                       logic.closeDoor("peterdoor");
+                                       break;
+                               case 1:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "Bianca... Am I on that list?" },
+                                               { actor: this, text: "Yes, John." },
+                                               { actor: this, text: "Well, I'll try to convince them to keep you and many other great folks from the list." },
+                                               { actor: this, text: "But... I can't promise anything. Also, it would help your case a lot if you made some notable work today, so I could mention it as your recent achievement." },
+                                               { actor: logic.player, text: "Thank you very much... I'll see what I can do." } ] ));
+                                       break;
+                               case 2:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "You seem to be somehow blaming yourself. It's not your fault. You're just doing your job." },
+                                               { actor: this, text: "I know. It's just part of my work..." },
+                                               { actor: this, text: "But if you have to sweep out such a great volume of people within such a short time... It does take its toll on the person." },
+                                               { actor: this, text: "... I feel like I'm growing distant from the company." },
+                                               { actor: this, text: "I mean... probably it's heresy to say that, but I feel I can less and less identify with the company's values." },
+                                               { actor: logic.player, text: "Yeah, you should definitely not talk about it to others... I mean, maybe only those you deeply trust." },
+                                               { actor: this, text: "I don't care anymore..." },
+                                               { actor: logic.player, text: "Fine." },
+                                               { actor: logic.player, text: "See... probably there is no need for such drama. Maybe it's for the best for everyone." },
+                                               { actor: logic.player, text: "... After all, there IS life beyond the company..." },
+                                               { actor: this, text: "You think so?..." },
+                                               { actor: this, text: "Hmm..." },
+                                               { actor: this, text: "I never thought about it for a long time..." },
+                                               { actor: logic.player, text: "There are plenty of other opportunities for us! Everything will be fine!" },
+                                               { actor: this, text: "..." },
+                                               { actor: this, text: "Thank you. This helped me to regain a bit of my composure..." },
+                                               { actor: logic.player, text: "You're welcome." } ] ));
+                                       this.makeHappy();
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "Thank you. I'll go back to work soon. Just give some more minutes of alone time." } ] ));
+                       }
+               }
+               else {
+                       switch (this.talkcount) {
+                               case 0:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: logic.player, text: "..." },
+                                               { actor: this, text: "... So you came for me too." },
+                                               { actor: this, text: "..." },
+                                               { actor: this, text: "I know what you are..." },
+                                               { actor: this, text: "..." },
+                                               { actor: this, text: "Let's get over with." },
+                                               { actor: logic.player, text: "..." } ] ));
+                                       break;
+                               default:
+                                       logic.gameinterface.talk(new Dialogue( [ { actor: this, text: "What are you waiting for?" } ] ));
+                       }
+               }
+               super.actionTalk();
+       }
+
+       actionLeave() {
+               if (this.happy) {
+                       logic.gameinterface.dropNotice(this.shortname + ": Thank you. I'll go back to work soon.");
+               }
+       }
+
+       actionTake() {
+               // All doors open for you if you have all the cards.
+               logic.openDoor("cutedoor");
+               logic.openDoor("carlosdoor");
+               logic.openDoor("saikidoor");
+               return super.actionTake();
+       }
+}
+
 
 class GameInterface extends Phaser.Group {
        constructor(game, parent) {
@@ -232,8 +847,7 @@ class GameInterface extends Phaser.Group {
                this.back_notice.drawRect(0, 0, game.width, 30);
                this.back_notice.endFill();
                this.add(this.back_notice);
-               this.text_notice = new Phaser.Text(game, 0, this.back_notice.y, null, { align: 'left', fill: 'white', font: 'Ubuntu Mono', fontSize: 18, fontWeight: 'bold' });
-               this.text_notice.anchor.setTo(-0.5, -0.2);
+               this.text_notice = new Phaser.Text(game, 125, this.back_notice.y + 5, null, { align: 'left', fill: 'white', font: 'Ubuntu Mono', fontSize: 18, fontWeight: 'bold' });
                this.add(this.text_notice);
                this.clearNotice();
 
@@ -271,9 +885,14 @@ class GameInterface extends Phaser.Group {
                this.back_talk.lineTo(this.back_talk.width - 10, 35);
                this.add(this.back_talk);
                style = { align: 'left', fill: 'yellow', font: 'Ubuntu Mono', fontSize: 22, fontWeight: 'bold' };
-               this.text_talktitle = new Phaser.Text(game, this.back_talk.x, this.back_talk.y, null, style);
-               this.text_talktitle.anchor.setTo(-0.2, -0.2);
+               this.text_talktitle = new Phaser.Text(game, this.back_talk.x + 15, this.back_talk.y + 6, null, style);
+               //this.text_talktitle.anchor.setTo(-0.2, -0.2);
                this.add(this.text_talktitle);
+               this.strikethrough_talktitle = new Phaser.Graphics(game, this.back_talk.x, this.back_talk.y);
+               this.strikethrough_talktitle.lineStyle(3, Phaser.Color.RED, 1);
+               this.strikethrough_talktitle.moveTo(12, 20);
+               this.strikethrough_talktitle.lineTo(67, 20);
+               this.add(this.strikethrough_talktitle);
                style = { align: 'left', fill: 'white', font: 'Ubuntu Mono', fontSize: 18, fontWeight: 'bold' };
                this.text_talk = new Phaser.Text(game, this.back_talk.x + 35, this.back_talk.y + 40, null, style);
                this.text_talk.wordWrap = true;
@@ -290,6 +909,11 @@ class GameInterface extends Phaser.Group {
                this.text_notice.visible = true;
        }
 
+       dropNoticeTimeout(timeout, text) {
+               this.dropNotice(text);
+               game.time.events.add(timeout, this.clearNotice, this);
+       }
+
        clearNotice() {
                this.back_notice.visible = false;
                this.text_notice.visible = false;
@@ -336,6 +960,7 @@ class GameInterface extends Phaser.Group {
                this.dialogue = null;
                this.back_talk.visible = false;
                this.text_talktitle.visible = false;
+               this.strikethrough_talktitle.visible = false;
                this.text_talk.visible = false;
        }
 
@@ -344,7 +969,14 @@ class GameInterface extends Phaser.Group {
                console.log(this.dialogue.actual());
                var actualdialogue = this.dialogue.actual();
                if (actualdialogue) {
-                       this.text_talktitle.text = actualdialogue.actor.shortname;
+                       if (actualdialogue.actor.disguise) {
+                               this.text_talktitle.text = actualdialogue.actor.shortname + " " + actualdialogue.actor.disguise.shortname;
+                               this.strikethrough_talktitle.visible = true;
+                       }
+                       else {
+                               this.text_talktitle.text = actualdialogue.actor.shortname;
+                               this.strikethrough_talktitle.visible = false;
+                       }
                        this.text_talk.text = actualdialogue.text;
                        this.dialogue.advance();
                }
@@ -415,6 +1047,22 @@ class GameLogic {
                                newChar = new NPC_Clara(object.x, object.y, 'clara', "Clara", "Clara Tnavelerri", 200);
                                this.clara = newChar;
                                break;
+                       case 'carlos':
+                               newChar = new NPC_Carlos(object.x, object.y, 'carlos', "Carlos", "Carlos Elbacalper", 150);
+                               this.carlos = newChar;
+                               break;
+                       case 'saiki':
+                               newChar = new NPC_Saiki(object.x, object.y, 'saiki', "Saiki", "Saiki Ytpme", 150);
+                               this.saiki = newChar;
+                               break;
+                       case 'peter':
+                               newChar = new NPC_Peter(object.x, object.y, 'peter', "Peter", "Peter Tluaf", 225);
+                               this.peter = newChar;
+                               break;
+                       case 'bianca':
+                               newChar = new NPC_Bianca(object.x, object.y, 'bianca', "Bianca", "Bianca Gnihton", 150);
+                               this.bianca = newChar;
+                               break;
                        default:
                                console.error("Unknown character:", object);
                }
@@ -424,16 +1072,17 @@ class GameLogic {
        }
 
        createDoor(object) {
+               /* Calculate movement vector and correct position (32 = half tile width/height). */
                var vector;
                switch (object.rotation) {
                        case undefined:
-                       case 0:         vector = new Phaser.Point( -1,  0); break;
-                       case 90:        vector = new Phaser.Point(  0, -1); break;
-                       case 180:       vector = new Phaser.Point(  1,  0); break;
-                       case 270:       vector = new Phaser.Point(  0,  1); break;
+                       case 0:         vector = new Phaser.Point( -1,  0); object.x += 32; object.y -= 32; break;
+                       case 90:        vector = new Phaser.Point(  0, -1); object.x += 32; object.y += 32; break;
+                       case 180:       vector = new Phaser.Point(  1,  0); object.x -= 32; object.y += 32; break;
+                       case 270:       vector = new Phaser.Point(  0,  1); object.x -= 32; object.y -= 32; break;
                        default:        console.error("Invalid rotation:", object.rotation);
                }
-               this.doors.add(new Door(object.x, object.y, object.name, vector, object.properties.longpanel));
+               this.doors.add(new Door(object.x, object.y, object.name, object.rotation, vector, object.properties.longpanel));
        }
 
        callMenu(menuitem) {
@@ -467,6 +1116,18 @@ class GameLogic {
                }
        }
 
+       openDoor(doorname) {
+               this.doors.children.forEach(function(o) { if (o.name == doorname) o.open(); });
+       }
+
+       closeDoor(doorname) {
+               this.doors.children.forEach(function(o) { if (o.name == doorname) o.close(); });
+       }
+
+       checkAllHappy() {
+               return (this.clara.happy) && (this.carlos.happy) && (this.saiki.happy);
+       }
+
        update() {
                if ((game.input.keyboard.isDown(Phaser.Keyboard.ENTER)) && (hasTimePassed(this.last_menuselect, WAIT_MENUSTEP))) {
                        if ((this.player.interactablenpc) && (this.player.interactablenpc.interactable) && (!this.gameinterface.inMenu) && (!this.gameinterface.inTalk)) {
@@ -486,7 +1147,7 @@ class GamePlay extends Phaser.State {
                super();
                logic = new GameLogic();
                game.world.updateOnlyExistingChildren = true;
-               //game.state.add('GameOver', GameOver, false);
+               game.state.add('GameOver', GameOver, false);
 
        }
 
@@ -494,7 +1155,10 @@ class GamePlay extends Phaser.State {
 
                game.load.image('player', 'john.png');
                game.load.image('clara', 'clara.png');
+               game.load.image('carlos', 'carlos.png');
                game.load.image('saiki', 'saiki.png');
+               game.load.image('peter', 'peter.png');
+               game.load.image('bianca', 'bianca.png');
                game.load.image('tileset', 'tileset.png');
                game.load.image('objects', 'objects.png');
                game.load.tilemap('gamemap', 'tilemap.json', null, Phaser.Tilemap.TILED_JSON);
@@ -506,6 +1170,7 @@ class GamePlay extends Phaser.State {
                game.world.setBounds(0, 0, 800, 600);
                game.stage.backgroundColor = '#000000';
                game.physics.startSystem(Phaser.Physics.ARCADE);
+               console.log("Debug enabled:", !game.debug.isDisabled);
 
                var map = game.add.tilemap('gamemap');
                map.addTilesetImage('tileset', 'tileset');
@@ -532,7 +1197,55 @@ class GamePlay extends Phaser.State {
 
                game.physics.arcade.collide(logic.player, this.layer_walls);
                game.physics.arcade.collide(logic.player, this.layer_furniture);
+               game.physics.arcade.collide(logic.player, logic.doors);
                logic.update();
 
        }
 }
+
+class GameOver extends Phaser.State {
+
+       create() {
+
+               console.log("Entered GameOver state.");
+               game.stage.removeChildren(1);
+               game.camera.follow(logic.player);
+               logic.player.freeze();
+
+               var g = game.add.group(game.stage, "GAMEOVER");
+               this.back_gameover = new Phaser.Graphics(game, 100, game.height / 2 - 200);
+               this.back_gameover.beginFill(0x000000);
+               this.back_gameover.drawRect(0, 0, game.width - 200, 400);
+               this.back_gameover.endFill();
+               this.back_gameover.lineStyle(3, Phaser.Color.YELLOW, 1);
+               this.back_gameover.moveTo(10, 35);
+               this.back_gameover.lineTo(this.back_gameover.width - 10, 35);
+               g.add(this.back_gameover);
+               var style = { align: 'left', fill: 'yellow', font: 'Ubuntu Mono', fontSize: 22, fontWeight: 'bold' };
+               this.text_title = new Phaser.Text(game, this.back_gameover.x + 15, this.back_gameover.y + 6, "ABRUPT GAME OVER", style);
+               g.add(this.text_title);
+               style = { align: 'left', fill: 'white', font: 'Ubuntu Mono', fontSize: 18, fontWeight: 'bold' };
+               this.text_gameover = new Phaser.Text(game, this.back_gameover.x + 35, this.back_gameover.y + 60, null, style);
+               this.text_gameover.wordWrap = true;
+               this.text_gameover.wordWrapWidth = this.back_gameover.width - 70;
+               this.text_gameover.lineSpacing = -5;
+               g.add(this.text_gameover);
+
+               this.text_gameover.text = this.assess();
+
+       }
+
+       assess() {
+               if (logic.checkAllHappy()) {
+                       return "You listened to all of your colleagues' and affected them to make their day a little better. Next day, the company fired Clara, Carlos, Saiki, and you, to comply with its productivity requirements. The company's internal code demand unconditional and illimitable loyalty from employees to maximize productivity. This includes requisites for employees not to exercise human qualities or express personal needs within and outside the corporate environment. The company has determined that neither of the mentioned people complied to these guidelines, due to the amount of socialization they pursued during the work day.\n\nIronically, the layoffs turned everyone's life for the better.";
+               }
+               else if (logic.player.disguise) {
+                       this.text_gameover.style.fill = 'red';
+                       return "You went on your day to accomplish your tasks without caring about anyone. Where are your colleagues now? Clara, Carlos, Saiki? You don't know. But you don't even care. You have never seen them after they served your needs.\n\nNext day, the company promoted you for your effectiveness and loyalty.";
+               }
+               else {
+                       return "The company is concerned that you may develop other needs (like wanting to pursue hobbies, spend time with friends and family) those compete for the time you devote for your job. The company reminds you that they demand your entire being to exclusively serve the company's interests. Socializing with your colleagues outside the dedicated team building occasions may hurt your performance. To comply with the productivity requirements, the company has terminated your employment.\n\nClara, Carlos, Saiki are still loyal employees of the company. Probably you could have done something different to find a better outcome.";
+               }
+       }
+
+}