1

I'm working on a game in which, when the player talks to an npc with a quest, one of for dialogues is shown, based on what a string made in the main scene is set to. The string can be:

  • inactive: is set to this be default, the player hasn't talked to the quest npc yet
  • active: after talking to the quest npc for the first time, ensuring they get context
  • found: is set once the player finds all the items needed to complete the quest, talking to the quest npc makes dialogue that tells of completing the quest
  • complete: is set when the quest is finished, after the items have been delivered

Here is the code I use for changing a quest's status, this bit taken from a quest about gathering medical supplies:

 if (this.talkCount == 2){
        doctorQuest = "active";
    }

    if (this.has("medBag") && this.has("stephascope") && this.has("shot") && doctorQuest == "active"){
        doctorQuest = "found";
    }

    if (this.talkCount >= 4 && doctorQuest == "found"){
        doctorQuest = "complete";
    }   

And this code is what makes this.talkCount go up, triggered when trying to talk to a character named Curie, but its the same for other quest npcs:

if ((this.checkCollision(this.p1, this.curie) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
        this.talkCount = this.talkCount + 1;
        this.talking = !this.talking;
    }

And here is the code that sets the dialogue based on what the quest status is set to:

if (this.talking == true){
        if (this.checkCollision(this.p1, this.curie)) {
            if (doctorQuest == "inactive") {
                this.line1.setText('Peef: Hey Curie. You and the cells still trying to become doctors?');
                this.line2.setText('Curie: We sure are, Peef! We just need a few more supplies. We will be the best healers ever!');
            }
            else if (doctorQuest == "active"){
                this.line1.setText('Curie: Have you found the supplies yet. I would look myself, but I struggle to move around.');
                this.line2.setText('Peef: Its understandable for a plushie bottle of covid vaccine. But you have great friends in a pair of red and white blood cells.');
            }
            else if (doctorQuest == "found"){
                this.line1.setText('Curie: You got everything?! Thank you Peef! Dreams are coming true!');
                this.line2.setText('Peef: Nice to see you so happy. Good luck doctors.');
            }
            else if (doctorQuest == "complete"){
                this.line1.setText('Curie: Hey Peef. Need a check up? I am happy help.');
                this.line2.setText('Peef: I feel just fine, thank you. But you really do sound like a doctor, Curie.');
            }
        }
        
        if (this.keyA.isDown || this.keyD.isDown) {
            this.p1.setVelocityX(0);
        }
        if(this.p1.body.touching.down && Phaser.Input.Keyboard.JustDown(this.keyW)) {
            this.p1.body.setVelocityY(0);
        }

    }

    if (this.talking == false){
        this.line1.setText('');
        this.line2.setText('');
    }

I'm having trouble with the code that sets the quest status, in this case the string named doctorQuest, to complete. In its current state, it has a chance of skipping the dialogue that plays if doctorQuest is set to found. It does this if the player talks to the npc twice already.

I've already tried altering what talkCount needs to be to trigger the if statement, but it ultimately has the same problem, if the player talks to the npc too many times, they will end up skipping the dialogue that plays when doctorQuest is set to found.

So, I need a different trigger to set doctorQuest to complete, but I'm struggling to come u with anything. Anyone have a suggestion?

If it helps, I'm using Phaser 3 is VSCode employing arcade physics.

Edit: I admit this looks desperate and maybe a bit stupid, but incase it helps anyone: here's the code of the whole file:

   class BathRoom extends Phaser.Scene {
    constructor() {
        super('bathRoom');
    }

    preload() {

        this.load.image('bathroom', "assets/bathroom.png");
        this.load.image('testGround', "assets/testGround.png");
        this.load.image('couchCushion', "assets/couchCushion.png");
        this.load.image('bathroomSink', "assets/bathroomSink.png");
        this.load.image('bathroomTub', "assets/bathroomTub.png");
        this.load.spritesheet('PeefSide', "assets/PeefSide.png", { frameWidth: 50, frameHeight: 60, startFrame: 0, endFrame: 7 });
        this.load.image('curie', "assets/curie.png");
        this.load.image('celly', "assets/celly.png");
        this.load.image('bloody', "assets/bloody.png");
        this.load.image('clearDoor', "assets/clearDoor.png");
        this.load.image('testItem', "assets/testItem.png");

    }

    create() {

        let width = config.width;
        let height = config.height;
        this.physics.world.gravity.y = 1000;

        this.keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
        this.keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
        this.keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);

        this.keyR = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.R); this.keyT = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
        this.keyG = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.G);
        this.keyV = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.V);

        this.bg = this.add.tileSprite(0, 0, game.config.width, game.config.height, 'bathroom').setOrigin(0, 0);

        this.ground = this.physics.add.sprite(800, 864, 'testGround');
        this.ground.body.immovable = true;
        this.ground.body.allowGravity = false;

        this.platforms = this.add.group();

        this.sink = this.physics.add.sprite(376, 721, 'bathroomSink');
        this.sink.body.immovable = true;
        this.sink.body.allowGravity = false;

        this.tub = this.physics.add.sprite(1252, 750, 'bathroomTub');
        this.tub.body.immovable = true;
        this.tub.body.allowGravity = false;

        this.doorLeft = this.physics.add.sprite(14.5, 735, 'clearDoor');
        this.doorLeft.body.immovable = true;
        this.doorLeft.body.allowGravity = false;

        // characters

        this.curie = this.physics.add.sprite(570, 741, 'curie');
        this.curie.body.immovable = true;
        this.curie.body.allowGravity = false;

        this.bloody = this.physics.add.sprite(500, 741, 'bloody');
        this.bloody.body.immovable = true;
        this.bloody.body.allowGravity = false;

        this.celly = this.physics.add.sprite(640, 741, 'celly');
        this.celly.body.immovable = true;
        this.celly.body.allowGravity = false;

        this.talkCount = 0;

        this.p1 = this.physics.add.sprite(55, 730, 'PeefSide');
        this.p1.setCollideWorldBounds(true);
        this.p1.setFlip(true, false);

        this.physics.add.collider(this.p1, this.ground);
        this.physics.add.collider(this.p1, this.platforms);

        this.line1 = this.add.text(880, 790, ' ', { font: '20px Futura', fill: '#FFFFFF' }).setOrigin(0.5);
        this.line2 = this.add.text(880, 840, ' ', { font: '20px Futura', fill: '#FFFFFF' }).setOrigin(0.5);

        this.talking = false;

        this.anims.create({
            key: 'walk',
            frames: this.anims.generateFrameNumbers('PeefSide', { start: 0, end: 7, first: 0 }),
            frameRate: 10,
            repeat: -1
        });

        this.anims.create({
            key: 'idle',
            frames: [{ key: 'PeefSide', frame: 0 }],
        });

    }

    update() {

        if (this.keyA.isDown && this.talking == false) {
            this.p1.setVelocityX(-270);
            this.p1.setFlip(true, false);
            this.p1.anims.play('walk', true);
        }
        else if (this.keyD.isDown && this.talking == false) {
            this.p1.setVelocityX(270);
            this.p1.resetFlip();
            this.p1.anims.play('walk', true);
        }
        else {
            this.p1.setVelocityX(0);
            this.p1.anims.play('idle', true);
        }

        if (this.p1.body.touching.down && Phaser.Input.Keyboard.JustDown(this.keyW) && this.talking == false) {
            this.p1.body.setVelocityY(-500);
        }

        if (this.checkCollision(this.p1, this.doorLeft)) {
            this.p1.x = 55;
            this.scene.switch('hallWay');
        }

        if (this.talkCount == 2) {
            doctorQuest = "active";
        }

        if (this.has("medBag") && this.has("stephascope") && this.has("shot") && doctorQuest == "active") {
            doctorQuest = "found";
        }

        if (this.talkCount >= 4 && doctorQuest == "found") {
            doctorQuest = "complete";
        }

        if (Phaser.Input.Keyboard.JustDown(this.keyG)) {
            console.log(this.p1.x + " " + this.p1.y);

        }

        if (Phaser.Input.Keyboard.JustDown(this.keyG)) {
            console.log(this.talking);

        }

        if ((this.checkCollision(this.p1, this.curie) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
            this.talkCount = this.talkCount + 1;
            this.talking = !this.talking;
        }

        if ((this.checkCollision(this.p1, this.celly) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
            this.talkCount = this.talkCount + 1;
            this.talking = !this.talking;
        }

        if ((this.checkCollision(this.p1, this.bloody) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
            this.talkCount = this.talkCount + 1;
            this.talking = !this.talking;
        }

        if ((this.checkCollision(this.p1, this.sink) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
            this.talking = !this.talking;
        }

        if ((this.checkCollision(this.p1, this.tub) && Phaser.Input.Keyboard.JustDown(this.keyT))) {
            this.talking = !this.talking;
        }

        if (this.talking == true) {
            if (this.checkCollision(this.p1, this.bloody)) {
                if (doctorQuest == "inactive") {
                    this.line1.setText('Bloody: Hey Peef. Guess what? We are so close to reaching are dream of medicine practice. We just need a little more supplies.');
                    this.line2.setText('Peef: I have been happy to support your dream. And I am happy to help to.');
                }
                else if (doctorQuest == "active") {
                    this.line1.setText('Peef: I gotta ask, how are you gonna be doctors when only Celly has arms?.');
                    this.line2.setText('Bloody: Celly says she will do most of the hand work, but we are all ready to do what we can.');
                }
                else if (doctorQuest == "found") {
                    this.line1.setText('Bloody: Thanks for the help. We will be helping everyone in the house soon enough.');
                    this.line2.setText('Peef: Have fun living the dream, doctors.');
                }
                else if (doctorQuest == "complete") {
                    this.line1.setText('Peef: Hey Bloody. How is being a doctor working out?');
                    this.line2.setText('Bloody: Pretty good. Celly has to help me put it on, but I am getting really good at using the stephascope.');
                }
            }
            if (this.checkCollision(this.p1, this.curie)) {
                if (doctorQuest == "inactive") {
                    this.line1.setText('Peef: Hey Curie. You and the cells still trying to become doctors?');
                    this.line2.setText('Curie: We sure are, Peef! We just need a few more supplies. We will be the best healers ever!');
                }
                else if (doctorQuest == "active") {
                    this.line1.setText('Curie: Have you found the supplies yet. I would look myself, but I struggle to move around.');
                    this.line2.setText('Peef: Its understandable for a plushie bottle of covid vaccine. But you have great friends in a pair of red and white blood cells.');
                }
                else if (doctorQuest == "found") {
                    this.line1.setText('Curie: You got everything?! Thank you Peef! Dreams are coming true!');
                    this.line2.setText('Peef: Nice to see you so happy. Good luck doctors.');
                }
                else if (doctorQuest == "complete") {
                    this.line1.setText('Curie: Hey Peef. Need a check up? I am happy help.');
                    this.line2.setText('Peef: I feel just fine, thank you. But you really do sound like a doctor, Curie.');
                }
            }
            if (this.checkCollision(this.p1, this.celly)) {
                if (doctorQuest == "inactive") {
                    this.line1.setText('Peef: Hey Celly. I here you guys are getting close to becoming doctors.');
                    this.line2.setText('Celly: Yeah. We just need a med bag, a seringe, and a stephascope. Then we can set up shop.');
                }
                else if (doctorQuest == "active") {
                    this.line1.setText('Peef: What do you guys need to set up your doctors office?');
                    this.line2.setText('Celly: Standard doctor equipment. A med bag, a stephascope, and seringe, better known as a shot.');
                }
                else if (doctorQuest == "found") {
                    this.line1.setText('Celly: Thats everything we need. Now we can set up our office.');
                    this.line2.setText('Peef: Plushies of a red blood cell, white blood cell, and a bottle of Covid vaccine working as doctors. Sure to be a success.');
                }
                else if (doctorQuest == "complete") {
                    this.line1.setText('Celly: I do the lifting, while Curie and Bloody handle diagnosis and comfort patients. We are the perfect team.');
                    this.line2.setText('Peef: Glad to know you guys have a great working relationship.');
                }
            }

            if (this.checkCollision(this.p1, this.sink)) {
                this.line1.setText('Peef: Its the sink. Even the biggest of us are too small reach it.');
                this.line2.setText('');
            }

            if (this.checkCollision(this.p1, this.tub)) {
                this.line1.setText('Peef: Its the bath tub. Though only stuffed animal sea creatures can stand getting wet, almost everyone has ideas for it.');
                this.line2.setText('');
            }

            if (this.keyA.isDown || this.keyD.isDown) {
                this.p1.setVelocityX(0);
            }
            if (this.p1.body.touching.down && Phaser.Input.Keyboard.JustDown(this.keyW)) {
                this.p1.body.setVelocityY(0);
            }


        }

        if (this.talking == false) {
            this.line1.setText('');
            this.line2.setText('');
        }

    }

    checkCollision(a, b) {
        // simple AABB checking
        if ((a.x < b.x + b.width &&
            a.x + a.width > b.x &&
            a.y < b.y + b.height &&
            a.height + a.y > b.y)) {
            return true;
        }
        else {
            return false;
        }
    }

    collect(item) {
        this.space = 0;
        while (this.space < 10) {
            if (inventory[this.space] == null) {
                inventory[this.space] == item;
                break;
            }
            else {
                this.space += 1;
            }
        }
    }

    has(item) {
        this.space = 0;
        this.result = false
        while (this.space < inventory.length) {
            if (inventory[this.space] == item) {
                this.result = true;
                break;
            }
            else {
                this.space += 1;
            }
        }
        return this.result;
    }

    takeOut(item) {
        this.space = 0;
        while (this.space < 10) {
            if (inventory[this.space] == item) {
                inventory[this.space] == null;
                break;
            }
            else {
                this.space += 1;
            }
        }
    }

}
winner_joiner
  • 12,173
  • 4
  • 36
  • 61
EmptyStone
  • 235
  • 1
  • 7

1 Answers1

0

Why are you using this.talkCount == 2 to check if they talked twice I would simply remove this lines:

if (this.talkCount == 2){
    doctorQuest = "active";
}

And simply add modify the interactive state, like this:

if (this.checkCollision(this.p1, this.curie)) {
    if (doctorQuest == "inactive") {
        this.line1.setText('Peef: Hey Curie. You and the cells still trying to become doctors?');
        this.line2.setText('Curie: We sure are, Peef! We just need a few more supplies. We will be the best healers ever!');
        doctorQuest = "active";
    }
    ...
 } 

Tipp: If you are planing alot of quests, I would recommend looking into Quest plugins like this one (it has a good documenation). I made a small demo, explaining it abit, for a SO-Question, in no time.

Update:
This is not a fix, but this will help make the code better, and help solve the problems, since currently many checks are performed in the the update function, every tick(that is in my opinion the main reason for the issues)

Well honestly you could fix it somehow, but I might be better to refactor the whole update function.

Here somethings you should consider changing:

  1. collision detection: if you are using physics, use it. Instead of checking collisions yourself in the update function:

     if (this.checkCollision(this.p1, this.bloody))
    

    configure an collide / overlap handler in the create function:

     this.physics.add.collide(this.p1, this.bloody, this.handleCollision, null, this);
    

    Checkout the documentation for details

  2. Input handling: except from the movement you could put keyboard interaction in there own event callbacks. So Instead of this code in the update function:

    if ((this.checkCollision(this.p1, this.tub) && Phaser.Input.Keyboard.JustDown(this.keyT))) 
    

    You can create an input handler in the create function, like this:

    this.input.keyboard.on('keyup-T', this.handleTalking, this);
    
     // ... the function would than look like this
     handleTalking(){
        if((this.checkCollision(this.p1, this.tub)){
            ...
        }
        ...
     }
    
  3. keep your if block tight and use else if, when possible, to avoid strange edge case like in:

     if (this.checkCollision(this.p1, this.bloody)) {
         ...
     } else if (this.checkCollision(this.p1, this.curie)) {
         ...
     }
     ...
    
  4. keep function short: extract not releated code into own functions. Instead of:

     if (this.checkCollision(this.p1, this.bloody)) {
         if (doctorQuest == "inactive") {
             ...
         }
         ...
     } else if (this.checkCollision(this.p1, this.curie)) {
         if (doctorQuest == "inactive") {
             ...
         }
         ...
     }
    

    extract the logic, like this:

     if (this.checkCollision(this.p1, this.bloody)) {
         this.handleBloodyQuest();
     } else if (this.checkCollision(this.p1, this.curie)) {
         this.handleCurieQuest();
     }
    

Just to name a few points. All this will improve your code, the performance and it's readability, and probably even fix your main issue.

winner_joiner
  • 12,173
  • 4
  • 36
  • 61
  • I did try something similar, but unfortunately the code would immediately switch to the text for doctorQuest == "active". That's why I went with the talkCount in the first place. – EmptyStone Jul 03 '23 at 05:29
  • Yes because You would also have to set `this.talking = false;`, but since I don't know your code I can't tell if that would disrupt something else. – winner_joiner Jul 03 '23 at 05:52
  • Hey, I think I found a solution. it pretty much involves changing if (this.talkCount >= 4 && doctorQuest == "found"){ doctorQuest = "complete"; } – EmptyStone Jul 04 '23 at 20:26
  • To if (this.talking == false && this.finished == true){ sewQuest = "complete"; } – EmptyStone Jul 04 '23 at 20:26
  • and adding this.finished = true; to the found dialogue area. – EmptyStone Jul 04 '23 at 20:27