1 var game
= new Phaser
.Game(800, 600, Phaser
.AUTO
, '', { preload: function() { this.state
.add('GamePlay', GamePlay
, true); } });
5 const PLAYER_SPEED
= 200;
6 const WAIT_MENUSTEP
= 100;
9 const MENUITEM_TALK
= 0;
10 const MENUITEM_LEAVE
= 1;
11 const MENUITEM_TAKE
= 2;
13 const GUI_MENUITEM_DISTANCE
= 20;
15 window
.addEventListener("keydown", function(e
) {
16 // Prevent default browser action for arrows and spacebar
17 if([32, 37, 38, 39, 40].indexOf(e
.keyCode
) > -1) {
22 function hasTimePassed(time
, delay
) {
23 return (game
.time
.now
- time
) > delay
;
27 // dialogue is array of {actor, text} records.
28 constructor(dialogue
) {
29 this.dialogue
= dialogue
;
34 return this.dialogue
[this.state
];
42 class Door
extends Phaser
.TileSprite
{
43 constructor(x
, y
, name
, rotation
, vector
, longpanel
) {
44 super(game
, x
, y
, 64, 64, 'objects');
46 this.longpanel
= longpanel
;
48 this.anchor
= new Phaser
.Point(0.5, 0.5);
49 this.tilePosition
= new Phaser
.Point(-64, -64);
50 this.openvector
= Phaser
.Point
.multiply(vector
, new Phaser
.Point(56, 56));
54 this.anchor
= new Phaser
.Point(0.75, 0.5);
55 this.tilePosition
= new Phaser
.Point(0, -64);
56 this.openvector
= Phaser
.Point
.multiply(vector
, new Phaser
.Point(116, 116));
58 if (rotation
=== undefined) rotation
= 0;
59 this.rotation
= rotation
* (Math
.PI
/ 180);
60 this.closetween
= game
.add
.tween(this).to({ x
: this.position
.x
, y
: this.position
.y
}, 1000, Phaser
.Easing
.Sinusoidal
.InOut
, false, 0, 0, false);
61 this.openposition
= Phaser
.Point
.add(this.position
, this.openvector
);
62 this.opentween
= game
.add
.tween(this).to({ x
: this.openposition
.x
, y
: this.openposition
.y
}, 1000, Phaser
.Easing
.Sinusoidal
.InOut
, false, 0, 0, false);
64 game
.physics
.arcade
.enable(this);
65 this.body
.immovable
= true;
66 this.setBody(rotation
);
73 this.body
.setSize(this.width
, 10, this.longpanel
* (rotation
/ 180) * 64, 27);
77 this.body
.setSize(10, this.width
, 27 + (this.longpanel
* 64), this.longpanel
* ((rotation
- 270) / 180) * 64);
80 console
.log("Unable to set body due to unknown rotation:", rotation
);
86 this.opentween
.start();
93 this.closetween
.start();
99 game
.debug
.body(this);
103 class Player
extends Phaser
.Sprite
{
105 super(game
, x
, y
, 'player');
106 this.y
-= this.height
;
107 this.shortname
= "John";
108 this.fullname
= "John Evals";
109 this.offerInteraction(null);
114 game
.physics
.arcade
.enable(this);
115 this.body
.bounce
.y
= 0.2;
116 this.body
.bounce
.x
= 0.2;
117 this.body
.collideWorldBounds
= true;
121 if ((this.alive
) && (!this.freezed
))
123 if (cursors
.left
.isDown
)
125 this.body
.velocity
.x
= -PLAYER_SPEED
;
127 else if (cursors
.right
.isDown
)
129 this.body
.velocity
.x
= PLAYER_SPEED
;
131 if (cursors
.up
.isDown
)
133 this.body
.velocity
.y
= -PLAYER_SPEED
;
135 else if (cursors
.down
.isDown
)
137 this.body
.velocity
.y
= PLAYER_SPEED
;
143 this.body
.velocity
.x
= this.body
.velocity
.y
= 0;
152 this.freezed
= false;
155 offerInteraction(npc
) {
156 this.interactablenpc
= npc
;
160 this.loadTexture(npc
.key
);
163 logic
.gameinterface
.dropNoticeTimeout(Phaser
.Timer
.SECOND
* 5, "You are now identified as " + npc
.fullname
+ "!");
167 class GameNPC
extends Phaser
.Sprite
{
168 constructor(x
, y
, key
, shortname
, fullname
, interaction_distance
) {
169 super(game
, x
, y
, key
);
170 this.y
-= this.height
;
171 this.shortname
= shortname
;
172 this.fullname
= fullname
;
173 this.interaction_distance
= interaction_distance
;
174 this.interactable
= false;
182 this.happy
= false; // Dead people are not happy.
187 if ((!this.interactable
) && (game
.physics
.arcade
.distanceBetween(this, logic
.player
) < this.interaction_distance
)) {
188 logic
.gameinterface
.dropNotice("(ENTER) Interact with " + this.shortname
+ "!");
189 logic
.player
.offerInteraction(this);
190 this.interactable
= true;
192 else if ((this.interactable
) && (game
.physics
.arcade
.distanceBetween(this, logic
.player
) > this.interaction_distance
)) {
193 logic
.gameinterface
.clearNotice();
194 logic
.player
.offerInteraction(null);
195 this.interactable
= false;
197 if ((this.teleport_instructions
) && (game
.physics
.arcade
.distanceBetween(this, logic
.player
) > (game
.width
+ 200))) {
198 this.position
= this.teleport_instructions
.newPosition
;
199 this.teleport_instructions
.callback(this.teleport_instructions
.callbackValue
);
200 this.teleport_instructions
= null;
212 logic
.player
.offerInteraction(null);
213 logic
.player
.takeMe(this);
223 console
.log(this.shortname
, "is happy!");
226 offscreenTeleportation(newPosition
, callback
, callbackValue
) {
227 this.teleport_instructions
= { newPosition
: newPosition
, callback
: callback
, callbackValue
: callbackValue
};
228 console
.log("Offscreen teleport request registered:", this.teleport_instructions
);
232 class NPC_Clara
extends GameNPC
{
234 switch (this.talkcount
) {
236 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "What a morning..." },
237 { actor
: logic
.player
, text
: "Hi Clara! What happened?" },
238 { actor
: this, text
: "No one cares to tell. I just know that I have to log on people manually, as the access control system doesn't work properly." },
239 { actor
: logic
.player
, text
: "Hmm... I'll look into it. Maybe it's just that everyone is fired." },
240 { actor
: this, text
: "Haha! Wouldn't joke about this, though, due to the recent layoffs." },
241 { actor
: logic
.player
, text
: "Well, maybe if we dare to joke about it, it won't happen to us..." },
242 { actor
: this, text
: "Wish it worked like that... Is it some superstition like the belief that having an umbrella with you prevents rain?" },
243 { actor
: logic
.player
, text
: "Nah, that actually works; it's not a superstition, but Murphy's Law!" },
244 { actor
: this, text
: "If you say so..." },
245 { actor
: this, text
: "Anyway, I logged you in and opened the door for you." } ] ));
246 logic
.openDoor("cutedoor");
249 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "John, have you ever thought about losing your employee card?" },
250 { actor
: logic
.player
, text
: "Yeah, you'd just get a new one." },
251 { actor
: this, text
: "You don't understand me, John!" },
252 { actor
: this, text
: "..." },
253 { actor
: this, text
: "I mean... Losing it for real..." },
254 { actor
: this, text
: "Doesn't it feel like it's the culmination of your being?" },
255 { actor
: this, text
: "If I had no card, would I still exist?" },
256 { actor
: logic
.player
, text
: "..." },
257 { actor
: logic
.player
, text
: "You sound very philosophical today." } ] ));
262 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Would you like to hear a random fun fact?" },
263 { actor
: logic
.player
, text
: "Of course!" },
264 { actor
: this, text
: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s," },
265 { actor
: this, text
: "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap" },
266 { actor
: this, text
: "into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem" },
267 { actor
: this, text
: "Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." },
268 { actor
: logic
.player
, text
: "That's very interesting, I didn't know that!" },
269 { actor
: logic
.player
, text
: "Thanks for sharing, Clara!" } ] ));
272 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Would you like to hear a random fun fact?" },
273 { actor
: logic
.player
, text
: "Of course!..." },
274 { actor
: logic
.player
, text
: "But first..." },
275 { actor
: this, text
: "What is it?" },
276 { actor
: logic
.player
, text
: "..." },
277 { actor
: logic
.player
, text
: "Never mind, go on with what you wanted to say." },
278 { actor
: this, text
: "Lorem Ipsum is simply dummy text of the printing and typesetting industry..." },
279 { actor
: logic
.player
, text
: "I knew that already..." },
280 { actor
: logic
.player
, text
: "But..." },
281 { actor
: logic
.player
, text
: "Would you go out on a date with me?" },
282 { actor
: this, text
: "..." },
283 { actor
: this, text
: "No." } ] ));
286 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "..." } ] ));
292 logic
.gameinterface
.dropNotice(this.shortname
+ ": Have a great day, John!");
296 logic
.openDoor("cutedoor");
297 return super.actionTake();
301 return (this.talkcount
< 6);
305 class NPC_Carlos
extends GameNPC
{
307 if (logic
.clara
.alive
) {
308 switch (this.talkcount
) {
310 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Good morning, Carlos! What's up?" },
311 { actor
: this, text
: "Hey, John! Not too much, I'm just trying to sell some shit to this new client." },
312 { actor
: logic
.player
, text
: "And so? Is it hard to convince them?" },
313 { actor
: this, text
: "Of course, they don't want to buy. It's shit." },
314 { actor
: this, text
: "I mean, who would want to buy shit?" },
315 { actor
: logic
.player
, text
: "Yeah. Relatable... But why are you trying to sell shit? I mean, why not one of our cutting edge technologies?" },
316 { actor
: this, text
: "They couldn't afford it." },
317 { actor
: logic
.player
, text
: "Then why are you trying to sell them... anything at all? They'd better off with a cheaper company." },
318 { actor
: this, text
: "Company policies. Plus the management instructed me to sell to them, no matter what." },
319 { actor
: logic
.player
, text
: "That sucks... Well... good luck!" },
320 { actor
: this, text
: "Thanks..." } ] ));
321 logic
.closeDoor("cutedoor");
322 logic
.openDoor("carlosdoor");
325 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." },
326 { actor
: this, text
: "These layoffs are terrifying. They let go of anyone for even the slightest mistake." },
327 { actor
: logic
.player
, text
: "But it's not a mistake when our client doesn't buy something they don't need." },
328 { actor
: this, text
: "Tell this to my boss..." } ] ));
331 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." },
332 { actor
: this, text
: "..." },
333 { 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..." },
334 { 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." },
335 { actor
: this, text
: "So I thought I could grow my own pig in the garden from pig seeds!" },
336 { actor
: logic
.player
, text
: "Interesting. Where are you going with this?" },
337 { actor
: this, text
: "I don't know... sometimes I feel like I'd rather sell pig semen to our clients, heh!" },
338 { actor
: this, text
: "Uhm..." },
339 { actor
: this, text
: "Totally don't tell this to Saiki!" } ] ));
340 this.pigsemen
= true;
343 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Weren't you heading to the IT department to the right?" },
344 { actor
: this, text
: "You know... the green department which looks way better than blue!" },
345 { actor
: this, text
: "..." },
346 { actor
: this, text
: "Damn, why do I have to work in blue? I just feel... so blue about it." } ] ));
349 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." },
350 { actor
: this, text
: "You're so lucky that you can work with her every day!" } ] ));
353 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Guess you'll stay here then. It's cool, you're great company anyway." } ] ));
357 switch (this.talkcount
) {
359 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Good morning, Carlos!" },
360 { actor
: this, text
: "Whoa, Clara! You have changed so much! I barely recognize you. What's up?" },
361 { actor
: logic
.player
, text
: "I need to talk to Saiki at the IT department, but... my card doesn't allow me to enter there." },
362 { actor
: this, text
: "Well... I can certainly help you with that..." },
363 { actor
: this, text
: "..." } ] ));
366 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Carlos. You promised to help me." },
367 { actor
: this, text
: "Uhm... It's just... Please give me 5 mins to finish this e-mail." },
368 { actor
: logic
.player
, text
: "I don't have much time, Carlos." },
369 { 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." },
370 { actor
: logic
.player
, text
: "..." } ] ));
373 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Time is up, Carlos!" },
374 { actor
: this, text
: "Please give me just another min." },
375 { actor
: logic
.player
, text
: "Fine. Please just give me your card and I'll help myself!" },
376 { actor
: this, text
: "But... you know that company policies forbid that, Clara! Please just be a little more patient!" },
377 { actor
: logic
.player
, text
: "You will give me your card now or you will regret!" },
378 { actor
: this, text
: "...?" },
379 { actor
: this, text
: "You're not gonna treat me like this. Forget it!" },
380 { actor
: logic
.player
, text
: "You'll not work here tomorrow." } ] ));
383 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "..." } ] ));
390 if (logic
.clara
.alive
) {
391 logic
.gameinterface
.dropNotice(this.shortname
+ ": Bye, John! Pass on my greetings to Saiki!");
396 logic
.closeDoor("cutedoor");
397 logic
.openDoor("carlosdoor");
398 return super.actionTake();
402 return (logic
.clara
.alive
) || (this.talkcount
< 3);
406 class NPC_Saiki
extends GameNPC
{
408 if (logic
.carlos
.alive
) {
409 switch (this.talkcount
) {
411 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Hi Saiki!" },
412 { actor
: this, text
: "Hi John! Glad you arrived, here's some work for you!" },
413 { actor
: logic
.player
, text
: "Awesome! What is it?" },
414 { actor
: this, text
: "Haha, joking! Actually, our queue is suspiciously empty for today." },
415 { actor
: logic
.player
, text
: "Yeah... That's really suspicious!" },
416 { actor
: logic
.player
, text
: "Maybe I can get home today in time?" },
417 { actor
: this, text
: "You mean, you wouldn't spend the mandatory free extra working hours?" },
418 { 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?" },
419 { actor
: this, text
: "*Whispers with wink.* I hope you get my sarcasm." },
420 { actor
: logic
.player
, text
: "Haha! I always get it, Saiki!" } ] ));
421 logic
.closeDoor("carlosdoor");
422 logic
.openDoor("saikidoor");
423 logic
.openDoor("peterdoor");
426 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." },
427 { actor
: this, text
: "Clara has to enter people manually." },
428 { actor
: logic
.player
, text
: "Yeah, I'll definitely check that." } ] ));
431 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "So... what's up with the trash can?" },
432 { actor
: this, text
: "I'm always up for such deep conversation" },
433 { actor
: this, text
: "about trash cans." },
434 { 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." },
435 { 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." },
436 { actor
: logic
.player
, text
: "Hmm... Maybe it's too much to ask. Can we take one from another department?" },
437 { actor
: this, text
: "No, everyone holds on to their trash cans." },
438 { actor
: logic
.player
, text
: "You certainly did your research." },
439 { actor
: this, text
: "Of course. It's an important subject." } ] ));
442 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "My parents named me after a Japanese rock singer." },
443 { actor
: logic
.player
, text
: "Cool! Which band?" },
444 { 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." } ] ));
447 if ((logic
.carlos
.pigsemen
) && (this.talkcount
== 4)) {
448 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?" },
449 { actor
: this, text
: "Hmm..." },
450 { actor
: this, text
: "I guess it didn't work." },
451 { actor
: this, text
: "So do you want to know what I think about this?" },
452 { actor
: this, text
: "..." },
453 { actor
: this, text
: "IT'S BRILLIANT!!!" },
454 { actor
: this, text
: "You know, it really sparkled my artistic vision! Now I must draw a pig with its legs rooted into the ground!" },
455 { actor
: logic
.player
, text
: "That's gross. Poor pig." },
456 { 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." },
457 { actor
: logic
.player
, text
: "You have a point." },
458 { 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." } ] ));
459 this.offscreenTeleportation(new Phaser
.Point(logic
.carlos
.x
, logic
.carlos
.y
+ 64), this.tpDone
, this);
462 if (Phaser
.Math
.random() < 0.5) {
463 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!" } ] ));
466 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." } ] ));
472 switch (this.talkcount
) {
474 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "I love you, Saiki!" },
475 { actor
: this, text
: "Hi Carlos..." },
476 { actor
: logic
.player
, text
: "I'm infatuated by the mere thought of you." },
477 { actor
: this, text
: "Well... it sounds pretty much creepy." },
478 { actor
: logic
.player
, text
: "Will you go out on a date with me?" },
479 { actor
: this, text
: "..." },
480 { actor
: this, text
: "Sorry to hurt your feelings, but... even though I like you... Your sudden, unprecedented confession makes me scared." },
481 { actor
: this, text
: "Especially with that facial expression." },
482 { actor
: this, text
: "I mean... you're not even joking." },
483 { actor
: this, text
: "So sorry... I won't date you." } ] ));
486 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "I thought I could impress you." },
487 { actor
: this, text
: "I'm sorry." } ] ));
490 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "You will give me your card." },
491 { actor
: this, text
: "Geez, what for? Go back to your department and work!" },
492 { actor
: logic
.player
, text
: "I need it." },
493 { actor
: this, text
: "..." } ] ));
496 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Don't you have anything better to do, Carlos?" } ] ));
503 if (logic
.carlos
.alive
) {
504 logic
.gameinterface
.dropNotice(this.shortname
+ ": It was nice talking to you!");
509 logic
.closeDoor("carlosdoor");
510 logic
.openDoor("saikidoor");
511 logic
.openDoor("peterdoor");
513 return super.actionTake();
517 return (logic
.carlos
.alive
);
521 console
.log("Woot-woot! Teleport complete:", value
);
523 logic
.carlos
.makeHappy();
524 // FIXME: Need to find a prettier way than this.
525 logic
.carlos
.update = function() { }; // Disable Carlos' interaction. (Saiki will talk for him.)
529 class NPC_Peter
extends GameNPC
{
531 if (logic
.saiki
.alive
) {
532 switch (this.talkcount
) {
534 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Hi Peter! What's up?" },
535 { actor
: this, text
: "Hi John! Bianca has locked herself in the large meeting room." },
536 { actor
: logic
.player
, text
: "Why would she do that?" },
537 { actor
: this, text
: "I have no idea." },
538 { 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." },
539 { actor
: logic
.player
, text
: "That was rude. I think you should care more about your colleagues." },
540 { actor
: this, text
: "Ahh... You're right. I didn't mean it. I'm just so frustrated about all the shit going on here." } ] ));
541 logic
.closeDoor("saikidoor");
542 logic
.openDoor("peterdoor");
543 logic
.openDoor("biancadoor");
546 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." } ] ));
549 if ((logic
.clara
.talkcount
>= 5) && (this.talkcount
== 2)) {
550 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Do you know Clara from the Reception?" },
551 { actor
: this, text
: "Of course I do." },
552 { actor
: logic
.player
, text
: "I think she's mad at me..." },
553 { actor
: this, text
: "Why would she?" },
554 { actor
: logic
.player
, text
: "I kind of... asked her out." },
555 { actor
: logic
.player
, text
: "She said no." },
556 { actor
: this, text
: "What the heck, dude?" },
557 { actor
: this, text
: "..." },
558 { actor
: this, text
: "You should know it's against the company etiquette..." },
559 { actor
: this, text
: "Regardless, I don't think she's really mad. You're a cool guy." },
560 { 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." } ] ));
561 this.offscreenTeleportation(new Phaser
.Point(logic
.clara
.x
- 160, logic
.clara
.y
), this.tpDone
, this);
564 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "I'm kind of busy, man." } ] ));
569 switch (this.talkcount
) {
571 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "What a wonderful day, Peter!" },
572 { actor
: this, text
: "Yikes! Saiki! You scared me!" },
573 { actor
: logic
.player
, text
: "I didn't even say \"boo\"." },
574 { actor
: this, text
: "Are you OK? You look horrible! You should really see a doctor." },
575 { actor
: logic
.player
, text
: "I'm fine, Peter. And you?" },
576 { actor
: this, text
: "No... Not at all." },
577 { actor
: logic
.player
, text
: "I'm sorry to hear that..." } ] ));
580 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "Don't come closer to me!" },
581 { actor
: logic
.player
, text
: "Why?" },
582 { actor
: this, text
: "I don't mean to offend you, but... you really creep me out..." },
583 { actor
: logic
.player
, text
: "Why do you say that?" },
584 { actor
: this, text
: "I honestly can't tell what's wrong with you, but... you look like that ghost girl from The Ring!" } ] ));
587 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Now that was pretty much racist..." },
588 { 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?" },
589 { actor
: this, text
: "Geez... that's not even a Japanese movie! And the actress is American..." },
590 { actor
: logic
.player
, text
: "The original movie is Japanese." },
591 { actor
: this, text
: "I don't care... Just... keep distance, please!" } ] ));
594 if (Phaser
.Math
.random() < 0.5) {
595 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "STAY AWAY FROM ME!" } ] ));
598 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "DON'T COME ANY CLOSER!" } ] ));
606 logic
.closeDoor("saikidoor");
607 logic
.openDoor("peterdoor");
608 logic
.openDoor("biancadoor");
609 return super.actionTake();
613 return (logic
.saiki
.alive
) && (this.talkcount
< 3);
617 console
.log("Woot-woot! Teleport complete:", value
);
619 logic
.clara
.makeHappy();
620 // FIXME: Need to find a prettier way than this.
621 logic
.clara
.update = function() { }; // Disable Clara's interaction. (Peter will talk for him.)
625 class NPC_Bianca
extends GameNPC
{
627 if (logic
.peter
.alive
) {
628 switch (this.talkcount
) {
630 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "... Hi Bianca!" },
631 { actor
: this, text
: "... Hello John!" },
632 { actor
: logic
.player
, text
: "So I've been told, you've been spending most of the day in this meeting room..." },
633 { actor
: this, text
: "Yeah?" },
634 { actor
: logic
.player
, text
: "... Your colleagues want to hold a meeting in this room and you're blocking it." },
635 { actor
: this, text
: "Hmm... Kind of that's the point... There is no need for that meeting." },
636 { actor
: logic
.player
, text
: "May I know why?" },
637 { 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." },
638 { actor
: this, text
: "But today morning, I received a list with about 50% of the employees... Many of them are great friends of mine..." },
639 { 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." },
640 { actor
: logic
.player
, text
: "That's rough. Does this company even need people?" },
641 { actor
: this, text
: "..." } ] ));
642 logic
.openDoor("cutedoor");
643 logic
.closeDoor("peterdoor");
646 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "Bianca... Am I on that list?" },
647 { actor
: this, text
: "Yes, John." },
648 { actor
: this, text
: "Well, I'll try to convince them to keep you and many other great folks from the list." },
649 { 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." },
650 { actor
: logic
.player
, text
: "Thank you very much... I'll see what I can do." } ] ));
653 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." },
654 { actor
: this, text
: "I know. It's just part of my work..." },
655 { 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." },
656 { actor
: this, text
: "... I feel like I'm growing distant from the company." },
657 { 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." },
658 { actor
: logic
.player
, text
: "Yeah, you should definitely not talk about it to others... I mean, maybe only those you deeply trust." },
659 { actor
: this, text
: "I don't care anymore..." },
660 { actor
: logic
.player
, text
: "Fine." },
661 { actor
: logic
.player
, text
: "See... probably there is no need for such drama. Maybe it's for the best for everyone." },
662 { actor
: logic
.player
, text
: "... After all, there IS life beyond the company..." },
663 { actor
: this, text
: "You think so?..." },
664 { actor
: this, text
: "Hmm..." },
665 { actor
: this, text
: "I never thought about it for a long time..." },
666 { actor
: logic
.player
, text
: "There are plenty of other opportunities for us! Everything will be fine!" },
667 { actor
: this, text
: "..." },
668 { actor
: this, text
: "Thank you. This helped me to regain a bit of my composure..." },
669 { actor
: logic
.player
, text
: "You're welcome." } ] ));
673 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." } ] ));
677 switch (this.talkcount
) {
679 logic
.gameinterface
.talk(new Dialogue( [ { actor
: logic
.player
, text
: "..." },
680 { actor
: this, text
: "... So you came for me too." },
681 { actor
: this, text
: "..." },
682 { actor
: this, text
: "I know what you are..." },
683 { actor
: this, text
: "..." },
684 { actor
: this, text
: "Let's get over with." },
685 { actor
: logic
.player
, text
: "..." } ] ));
688 logic
.gameinterface
.talk(new Dialogue( [ { actor
: this, text
: "What are you waiting for?" } ] ));
696 logic
.gameinterface
.dropNotice(this.shortname
+ ": Thank you. I'll go back to work soon.");
701 // All doors open for you if you have all the cards.
702 logic
.openDoor("cutedoor");
703 logic
.openDoor("carlosdoor");
704 logic
.openDoor("saikidoor");
705 return super.actionTake();
710 class GameInterface
extends Phaser
.Group
{
711 constructor(game
, parent
) {
712 super(game
, parent
, 'GUI', false, false, 0);
713 this.back_notice
= new Phaser
.Graphics(game
, 0, game
.height
- 50);
714 this.back_notice
.beginFill(0x000000);
715 this.back_notice
.drawRect(0, 0, game
.width
, 30);
716 this.back_notice
.endFill();
717 this.add(this.back_notice
);
718 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' });
719 this.add(this.text_notice
);
722 this.back_menu
= new Phaser
.Graphics(game
, 150, (game
.height
/ 2) + 40);
723 this.back_menu
.beginFill(0x000000);
724 this.back_menu
.drawRect(0, 0, 155, 105);
725 this.back_menu
.endFill();
726 this.back_menu
.lineStyle(3, Phaser
.Color
.YELLOW
, 1);
727 this.back_menu
.moveTo(10, 35);
728 this.back_menu
.lineTo(this.back_menu
.width
- 10, 35);
729 this.add(this.back_menu
);
730 var style
= { align
: 'left', fill
: 'yellow', font
: 'Ubuntu Mono', fontSize
: 22, fontWeight
: 'bold' };
731 this.text_menutitle
= new Phaser
.Text(game
, this.back_menu
.x
, this.back_menu
.y
, null, style
);
732 this.text_menutitle
.anchor
.setTo(-0.2, -0.2);
733 style
= { align
: 'left', fill
: 'white', font
: 'Ubuntu Mono', fontSize
: 18, fontWeight
: 'bold' };
734 this.text_menuitem_Talk
= new Phaser
.Text(game
, this.back_menu
.x
+ 35, this.back_menu
.y
+ 40, "Talk", style
);
735 this.text_menuitem_Leave
= new Phaser
.Text(game
, this.back_menu
.x
+ 35, this.text_menuitem_Talk
.y
+ GUI_MENUITEM_DISTANCE
, "Leave", style
);
736 this.text_menuitem_Take
= new Phaser
.Text(game
, this.back_menu
.x
+ 35, this.text_menuitem_Leave
.y
+ GUI_MENUITEM_DISTANCE
, "Take ID", style
);
737 style
.fill
= 'yellow';
738 this.text_menucursor
= new Phaser
.Text(game
, this.back_menu
.x
+ 15, this.text_menuitem_Talk
.y
, "→", style
);
739 this.add(this.text_menutitle
);
740 this.add(this.text_menuitem_Talk
);
741 this.add(this.text_menuitem_Leave
);
742 this.add(this.text_menuitem_Take
);
743 this.add(this.text_menucursor
);
745 this.last_menustep
= 0;
747 this.back_talk
= new Phaser
.Graphics(game
, 100, game
.height
- 120);
748 this.back_talk
.beginFill(0x000000);
749 this.back_talk
.drawRect(0, 0, game
.width
- 200, 105);
750 this.back_talk
.endFill();
751 this.back_talk
.lineStyle(3, Phaser
.Color
.YELLOW
, 1);
752 this.back_talk
.moveTo(10, 35);
753 this.back_talk
.lineTo(this.back_talk
.width
- 10, 35);
754 this.add(this.back_talk
);
755 style
= { align
: 'left', fill
: 'yellow', font
: 'Ubuntu Mono', fontSize
: 22, fontWeight
: 'bold' };
756 this.text_talktitle
= new Phaser
.Text(game
, this.back_talk
.x
+ 15, this.back_talk
.y
+ 6, null, style
);
757 //this.text_talktitle.anchor.setTo(-0.2, -0.2);
758 this.add(this.text_talktitle
);
759 this.strikethrough_talktitle
= new Phaser
.Graphics(game
, this.back_talk
.x
, this.back_talk
.y
);
760 this.strikethrough_talktitle
.lineStyle(3, Phaser
.Color
.RED
, 1);
761 this.strikethrough_talktitle
.moveTo(12, 20);
762 this.strikethrough_talktitle
.lineTo(67, 20);
763 this.add(this.strikethrough_talktitle
);
764 style
= { align
: 'left', fill
: 'white', font
: 'Ubuntu Mono', fontSize
: 18, fontWeight
: 'bold' };
765 this.text_talk
= new Phaser
.Text(game
, this.back_talk
.x
+ 35, this.back_talk
.y
+ 40, null, style
);
766 this.text_talk
.wordWrap
= true;
767 this.text_talk
.wordWrapWidth
= this.back_talk
.width
- 70;
768 this.text_talk
.lineSpacing
= -5;
769 this.add(this.text_talk
);
775 this.text_notice
.text
= text
;
776 this.back_notice
.visible
= true;
777 this.text_notice
.visible
= true;
780 dropNoticeTimeout(timeout
, text
) {
781 this.dropNotice(text
);
782 game
.time
.events
.add(timeout
, this.clearNotice
, this);
786 this.back_notice
.visible
= false;
787 this.text_notice
.visible
= false;
794 this.text_menutitle
.text
= npc
.shortname
;
795 this.back_menu
.visible
= true;
796 this.text_menutitle
.visible
= true;
797 this.text_menuitem_Talk
.visible
= true;
798 this.text_menuitem_Leave
.visible
= true;
799 this.text_menuitem_Take
.visible
= true;
800 this.currentmenuitem
= MENUITEM_TALK
;
801 this.actualizeCursorPosition();
802 this.text_menucursor
.visible
= true;
803 this.last_menustep
= game
.time
.now
;
808 this.back_menu
.visible
= false;
809 this.text_menutitle
.visible
= false;
810 this.text_menuitem_Talk
.visible
= false;
811 this.text_menuitem_Leave
.visible
= false;
812 this.text_menuitem_Take
.visible
= false;
813 this.text_menucursor
.visible
= false;
819 this.dialogue
= dialogue
;
821 this.back_talk
.visible
= true;
822 this.text_talktitle
.visible
= true;
823 this.text_talk
.visible
= true;
828 this.dialogue
= null;
829 this.back_talk
.visible
= false;
830 this.text_talktitle
.visible
= false;
831 this.strikethrough_talktitle
.visible
= false;
832 this.text_talk
.visible
= false;
836 console
.log(this.dialogue
);
837 console
.log(this.dialogue
.actual());
838 var actualdialogue
= this.dialogue
.actual();
839 if (actualdialogue
) {
840 if (actualdialogue
.actor
.disguise
) {
841 this.text_talktitle
.text
= actualdialogue
.actor
.shortname
+ " " + actualdialogue
.actor
.disguise
.shortname
;
842 this.strikethrough_talktitle
.visible
= true;
845 this.text_talktitle
.text
= actualdialogue
.actor
.shortname
;
846 this.strikethrough_talktitle
.visible
= false;
848 this.text_talk
.text
= actualdialogue
.text
;
849 this.dialogue
.advance();
855 this.last_talk
= game
.time
.now
;
858 actualizeCursorPosition() {
859 this.text_menucursor
.y
= this.text_menuitem_Talk
.y
+ (this.currentmenuitem
* GUI_MENUITEM_DISTANCE
);
863 if ((this.inMenu
) && (hasTimePassed(this.last_menustep
, WAIT_MENUSTEP
))) {
864 if (cursors
.up
.isDown
)
866 this.currentmenuitem
--;
867 if (this.currentmenuitem
< MENUITEM_TALK
) this.currentmenuitem
= MENUITEM_TAKE
;
868 this.actualizeCursorPosition();
870 else if (cursors
.down
.isDown
)
872 this.currentmenuitem
++;
873 if (this.currentmenuitem
> MENUITEM_TAKE
) this.currentmenuitem
= MENUITEM_TALK
;
874 this.actualizeCursorPosition();
876 if (game
.input
.keyboard
.isDown(Phaser
.Keyboard
.ENTER
)) {
877 logic
.callMenu(this.currentmenuitem
);
879 this.last_menustep
= game
.time
.now
;
881 if ((this.inTalk
) && (game
.input
.keyboard
.isDown(Phaser
.Keyboard
.ENTER
)) && (hasTimePassed(this.last_talk
, WAIT_TALK
))) {
890 this.player
= this.clara
= this.carlos
= this.saiki
= this.peter
= this.bianca
= null;
891 this.gameinterface
= new GameInterface(game
, game
.stage
);
892 //this.doors = game.add.group(game.world, "doors");
893 this.last_menuselect
= 0;
896 createObject(object
) {
897 switch (object
.type
) {
898 case 'spawnpoint': this.createCharacter(object
); break;
899 case 'door': this.createDoor(object
); break;
900 case '': console
.error("Object type is empty:", object
); break;
901 default: console
.error("Unknown object type:", object
);
905 createCharacter(object
) {
907 switch (object
.name
) {
909 newChar
= new Player(object
.x
, object
.y
, 'player');
910 this.player
= newChar
;
911 this.player
.enablePhysics();
912 game
.camera
.follow(this.player
);
915 newChar
= new NPC_Clara(object
.x
, object
.y
, 'clara', "Clara", "Clara Tnavelerri", 200);
916 this.clara
= newChar
;
919 newChar
= new NPC_Carlos(object
.x
, object
.y
, 'carlos', "Carlos", "Carlos Elbacalper", 150);
920 this.carlos
= newChar
;
923 newChar
= new NPC_Saiki(object
.x
, object
.y
, 'saiki', "Saiki", "Saiki Ytpme", 150);
924 this.saiki
= newChar
;
927 newChar
= new NPC_Peter(object
.x
, object
.y
, 'peter', "Peter", "Peter Tluaf", 225);
928 this.peter
= newChar
;
931 newChar
= new NPC_Bianca(object
.x
, object
.y
, 'bianca', "Bianca", "Bianca Gnihton", 150);
932 this.bianca
= newChar
;
935 console
.error("Unknown character:", object
);
937 newChar
.name
= object
.name
;
938 game
.add
.existing(newChar
);
939 console
.log(newChar
);
943 /* Calculate movement vector and correct position (32 = half tile width/height). */
945 switch (object.rotation) {
947 case 0: vector = new Phaser.Point( -1, 0); object.x += 32; object.y -= 32; break;
948 case 90: vector = new Phaser.Point( 0, -1); object.x += 32; object.y += 32; break;
949 case 180: vector = new Phaser.Point( 1, 0); object.x -= 32; object.y += 32; break;
950 case 270: vector = new Phaser.Point( 0, 1); object.x -= 32; object.y -= 32; break;
951 default: console.error("Invalid rotation:", object.rotation);
953 this.doors.add(new Door(object.x, object.y, object.name, object.rotation, vector, object.properties.longpanel));
957 console.log("Menu callback received:", menuitem);
958 this.last_menuselect = game.time.now;
959 this.gameinterface.leaveMenu();
962 this.player.interactablenpc.actionTalk();
965 this.player.interactablenpc.actionLeave();
966 this.player.unfreeze();
969 if (this.player.interactablenpc.actionTake())
970 this.player.unfreeze();
976 if (this.player.interactablenpc) {
977 if (this.player.interactablenpc.endTalk()) {
978 this.gameinterface.npcMenu(this.player.interactablenpc);
981 this.player.unfreeze();
982 this.last_menuselect = game.time.now;
988 this.doors.children.forEach(function(o) { if (o.name == doorname) o.open(); });
991 closeDoor(doorname) {
992 this.doors.children.forEach(function(o) { if (o.name == doorname) o.close(); });
996 return (this.clara.happy) && (this.carlos.happy) && (this.saiki.happy);
1000 if ((game.input.keyboard.isDown(Phaser.Keyboard.ENTER)) && (hasTimePassed(this.last_menuselect, WAIT_MENUSTEP))) {
1001 if ((this.player.interactablenpc) && (this.player.interactablenpc.interactable) && (!this.gameinterface.inMenu) && (!this.gameinterface.inTalk)) {
1002 console.log("Starting interaction with", this.player.interactablenpc.fullname);
1003 this.player.freeze();
1004 this.gameinterface.npcMenu(this.player.interactablenpc);
1011 class GamePlay extends Phaser.State {
1016 logic = new GameLogic();
1017 game.world.updateOnlyExistingChildren = true;
1018 game.state.add('GameOver', GameOver, false);
1024 game.load.image('player', 'john.png');
1025 game.load.image('clara', 'clara.png');
1026 game.load.image('carlos', 'carlos.png');
1027 game.load.image('saiki', 'saiki.png');
1028 game.load.image('peter', 'peter.png');
1029 game.load.image('bianca', 'bianca.png');
1030 game.load.image('tileset', 'tileset.png');
1031 game.load.image('objects', 'objects.png');
1032 game.load.tilemap('gamemap', 'tilemap.json', null, Phaser.Tilemap.TILED_JSON);
1038 game.world.setBounds(0, 0, 800, 600);
1039 game.stage.backgroundColor = '#000000';
1040 game.physics.startSystem(Phaser.Physics.ARCADE);
1041 console.log("Debug enabled:", !game.debug.isDisabled);
1043 var map = game.add.tilemap('gamemap');
1044 map.addTilesetImage('tileset', 'tileset');
1045 map.addTilesetImage('objects', 'objects');
1046 var layer_floor = map.createLayer('floor');
1047 layer_floor.resizeWorld();
1048 this.layer_walls = map.createLayer('walls');
1049 map.setCollisionBetween(1, 100, true, this.layer_walls);
1050 this.layer_furniture = map.createLayer('furniture');
1051 map.setCollisionBetween(1, 100, true, this.layer_furniture);
1053 // FIXME: Don't create a group here like this, it's too ugly! Now I have it here due to the display order.
1054 logic.doors = game.add.group(game.world, "doors");
1056 map.objects['objects'].forEach(function(o) { logic.createObject(o); });
1057 console.log(map.objects);
1059 cursors = game.input.keyboard.createCursorKeys();
1066 game.physics.arcade.collide(logic.player, this.layer_walls);
1067 game.physics.arcade.collide(logic.player, this.layer_furniture);
1068 game.physics.arcade.collide(logic.player, logic.doors);
1074 class GameOver extends Phaser.State {
1078 console.log("Entered GameOver state.");
1079 game.stage.removeChildren(1);
1080 game.camera.follow(logic.player);
1081 logic.player.freeze();
1083 var g = game.add.group(game.stage, "GAMEOVER");
1084 this.back_gameover = new Phaser.Graphics(game, 100, game.height / 2 - 200);
1085 this.back_gameover.beginFill(0x000000);
1086 this.back_gameover.drawRect(0, 0, game.width - 200, 400);
1087 this.back_gameover.endFill();
1088 this.back_gameover.lineStyle(3, Phaser.Color.YELLOW, 1);
1089 this.back_gameover.moveTo(10, 35);
1090 this.back_gameover.lineTo(this.back_gameover.width - 10, 35);
1091 g.add(this.back_gameover);
1092 var style = { align: 'left', fill: 'yellow', font: 'Ubuntu Mono', fontSize: 22, fontWeight: 'bold' };
1093 this.text_title = new Phaser.Text(game, this.back_gameover.x + 15, this.back_gameover.y + 6, "ABRUPT GAME OVER", style);
1094 g.add(this.text_title);
1095 style = { align: 'left', fill: 'white', font: 'Ubuntu Mono', fontSize: 18, fontWeight: 'bold' };
1096 this.text_gameover = new Phaser.Text(game, this.back_gameover.x + 35, this.back_gameover.y + 60, null, style);
1097 this.text_gameover.wordWrap = true;
1098 this.text_gameover.wordWrapWidth = this.back_gameover.width - 70;
1099 this.text_gameover.lineSpacing = -5;
1100 g.add(this.text_gameover);
1102 this.text_gameover.text = this.assess();
1107 if (logic.checkAllHappy()) {
1108 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.";
1110 else if (logic.player.disguise) {
1111 this.text_gameover.style.fill = 'red';
1112 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.";
1115 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.";