# Achieve with Reference

**URL:** <https://forum.choiceofgames.com/t/achieve-with-reference/157882>\
**Category:** Game Development\
**Tags:** coder\
**Created:** [August 17, 2024, 3:54am UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882 "2024-08-17T03:54:54Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Cory\_Caron](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cory_caron/32/233921_2.png) [@Cory\_Caron](https://forum.choiceofgames.com/u/Cory_Caron)\
**Post date:** [August 17, 2024, 3:54am UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/1 "2024-08-17T03:54:54Z")

</div>

Does anyone know if there is a way to use the achieve command with references?  
For context, I have an “easy mode” option that allows players to retry combat if they die, but disables achievements for the rest of that playthrough.  
I was hoping to pipe it through a subroutine to make life easier, but I get an error message.

```choicescript
*label award_achievement
*params achievement_id
*if ((easy_mode) and not(player_alive))
    *comment no achievement
*else
    *achieve {achievement_id}
*return

```

![image](https://global.discourse-cdn.com/choiceofgames/original/3X/a/f/af566929ec2ca253579cdca95aba132d0663562b.png)

I’ve put all kinds of utils like increasing numeric stats inside of a “utils” scene for similar types of things.  
For example, I have a “Notify Stats” option which is used in my increase stats subroutine, if the player sets it to false, they don’t see the stat changes.

```choicescript
*label increase_stat
*params stat_id stat_increase stat_name
*set {stat_id} +{stat_increase}
*if (stat_name = "")
    *set stat_name stat_id
*if (notify_stats)
    $!{stat_name} +${stat_increase}
    *line_break
*return

```

---

<div class="post-metadata">

**Author:** ![Kotosinica](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/kotosinica/32/145626_2.png) [@Kotosinica](https://forum.choiceofgames.com/u/Kotosinica)\
**Post date:** [August 17, 2024, 10:26am UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/2 "2024-08-17T10:26:14Z")

</div>

It appears you haven’t defined your achievements properly. If I understand correctly, \*params create temporary variables, so in your second subroutine, \*params create temporary vars stat\_id and stat\_increase, sets them based on the data in \*gosub command and the subroutine works properly. In your first subroutine, \*params creates a temporary achievement\_id variable, but achievements by their nature aren’t temporary variables, they have to be declared in startup file, so \*achieve command can’t use that temp variable achievement\_id, instead goes to the startup to find an achievement called achievement\_id, and fails.

You should [declare achievements](https://choicescriptdev.fandom.com/wiki/Achievement#Declaring_Achievements) individually and deal with them as they appear in the plot. If a player character can die often, you can create a subroutine to revive them and send them to the fight again.

```choicescript
*if health <= 0
  Everything goes dark.
  *gosub check_revival
  *if player_alive
    On the brink of death, you find your inner strength and continue to fight the dastardly reptile.
    *goto dragon_fight
  *else
    You've died from a terminal case of being squashed by a dragon.
    *ending
*elseif dragon_health <= 0
  Congratulations, you've defeated the dragon!
  *if easy_mode = false
    *achieve defeat_dragon
  *goto victory
*else
  You are still fighting the dragon.
  *goto fight_dragon

*label check_revival
*if easy_mode
  *set health 100
  *set player_alive true
  *return
*else
  Do you wish to switch to easy mode to continue the fight (disables achievements for the rest of the game)?
    *choice
      #Yes, revive me and let me retry!
        *set health 100
        *set player_alive true
        *set easy_mode true
        *return
      #No, I accept my fate!
        So be it.
        *set player_alive false
        *return

```

That’s if you want the player to be able to switch to the easy difficulty later in the game. If you only allow the player to choose difficulty mode in the beginning, the subroutine for revival will be different. Just don’t use \*params command to define achievements.

---

<div class="post-metadata">

**Author:** ![cup\_half\_empty](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cup_half_empty/32/273983_2.png) [@cup\_half\_empty](https://forum.choiceofgames.com/u/cup_half_empty)\
**Post date:** [August 17, 2024, 11:49am UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/3 "2024-08-17T11:49:16Z")

</div>

ChoiceScript is quirky on the edges and inconsistent in its design. What you are trying to do is unfortunately impossible. I can think of two workarounds.

The simplest, but it uses the `*script` command:

```chociescript
*label award_achievement
*params achievement_id
*if (not(easy_mode) and player_alive)
    *script window.stats.scene.achieve(window.stats.scene.temps.achievement_id)
*return

```

Note that I inverted the conditional to make it simpler.

* * *

The second solution is to have a utility scene only for handling achievements. You use the reference id in the `*goto` command instead of the `*achieve` command. Unfortunately, you’ll have to write a label for each achievement.

```choicescript
== startup.txt ==

*achievement diplomatic visible 100 Peacekeeper
    Resolve at least 5 conflicts through diplomatic and non-violent means to earn this achievement.
    At times, a word can be mightier than a sword.

```

```choicescript
== utils_achieve.txt ==

*label award_achievement
*params achievement_id
*if (not(easy_mode) and player_alive)
    *goto {achievement_id}
*return

*label diplomatic
*achieve diplomatic
*return

```

---

<div class="post-metadata">

**Author:** ![Cory\_Caron](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cory_caron/32/233921_2.png) [@Cory\_Caron](https://forum.choiceofgames.com/u/Cory_Caron)\
**Post date:** [August 17, 2024, 1:32pm UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/4 "2024-08-17T13:32:31Z")

</div>

> [@Kotosinica](#):
>
> It appears you haven’t defined your achievements properly. If I understand correctly, \*params create temporary variables, so in your second subroutine, \*params create temporary vars stat\_id and stat\_increase, sets them based on the data in \*gosub command and the subroutine works properly. In your first subroutine, \*params creates a temporary achievement\_id variable, but achievements by their nature aren’t temporary variables, they have to be declared in startup file, so \*achieve command can’t use that temp variable achievement\_id, instead goes to the startup to find an achievement called achievement\_id, and fails.

I did actually declare them in the startup, the achievement\_id is just used to pass the id of the achievement through.  
If you look at the increase\_stat subroutine, I use the same method to pass through the id of a variable, then use the set command to increase it’s value based on the id provided.

> [@cup\_half\_empty](#):
>
> The simplest, but it uses the `*script` command:

I figured I could do it with script, but I’m trying to avoid using it. Part of the fun of learning a new programming language to me is figuring out what I can do with it, and what the limitations are.

> [@cup\_half\_empty](#):
>
> The second solution is to have a utility scene only for handling achievements. You use the reference id in the `*goto` command instead of the `*achieve` command. Unfortunately, you’ll have to write a label for each achievement.

I was hoping to avoid typing them all out. (Cause I’m lazy.)  
But I guess I’ll have to do something like this:

```choicescript
*label award_achievement
*params achievement_id
*if ((easy_mode) and not(player_alive))
    *return
*if (achievement_id = "dragonslayer")
    *achieve dragonslayer
*elseif (achievement_id = "druid")
    *achieve druid
*elseif (achievement_id = "merchantile")
    *achieve merchantile
*else
    *comment invalid achievement
*return

```

It will just return immediately if they are on easy mode and are not alive (died), but otherwise continue and award the achievement.  
Another nice feature would be a switch-case block, but that’s also my laziness talking.

---

<div class="post-metadata">

**Author:** ![cup\_half\_empty](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cup_half_empty/32/273983_2.png) [@cup\_half\_empty](https://forum.choiceofgames.com/u/cup_half_empty)\
**Post date:** [August 17, 2024, 1:54pm UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/5 "2024-08-17T13:54:51Z")

</div>

Yes, that’s better than my suggestion. 😁 Plenty of things missing from ChoiceScript, like a simple loop syntax. 🤷‍♂️

---

<div class="post-metadata">

**Author:** ![Kotosinica](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/kotosinica/32/145626_2.png) [@Kotosinica](https://forum.choiceofgames.com/u/Kotosinica)\
**Post date:** [August 17, 2024, 2:07pm UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/6 "2024-08-17T14:07:37Z")

</div>

> [@Cory\_Caron](#):
>
> I did actually declare them in the startup, the achievement\_id is just used to pass the id of the achievement through.

I was wrong then. Anyway, it appears \*achieve command tries to work with {achieve\_id} achievement insead of whatever value assigned to achievement\_id variable.

However, I don’t see how

```choicescript
*gosub award_achievement diplomacy

*label diplomacy
Long subroutine with achievements.

```

is shorter and easier than

```choicescript
*if not easy_mode
  *achieve diplomacy

```

---

<div class="post-metadata">

**Author:** ![Cory\_Caron](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cory_caron/32/233921_2.png) [@Cory\_Caron](https://forum.choiceofgames.com/u/Cory_Caron)\
**Post date:** [August 17, 2024, 2:09pm UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/7 "2024-08-17T14:09:58Z")

</div>

Loops would certainly be nice, but at least you can code them relatively easily with something like this:

```choicescript
*label loop_start
*temp count 0
*label loop_body
*if (count < 10)
    Looped.
    *set count +1
    *goto loop_body
*else
    Finished looping.
    *return

```

I’d wager making a pull request on the repo in github is unlikely to lead anywhere?

---

<div class="post-metadata">

**Author:** ![Cory\_Caron](https://sea3.discourse-cdn.com/choiceofgames/user_avatar/forum.choiceofgames.com/cory_caron/32/233921_2.png) [@Cory\_Caron](https://forum.choiceofgames.com/u/Cory_Caron)\
**Post date:** [August 17, 2024, 2:13pm UTC](https://forum.choiceofgames.com/t/achieve-with-reference/157882/8 "2024-08-17T14:13:26Z")

</div>

The main reason for using the util subroutine is that I don’t need to copy paste the if condition every time.  
The reason for not wanting to do that is what if I decide to change the condition?  
All of a sudden I need to find every place where I used it and update the code.  
By using a subroutine, I only update it in one place and everything fixes itself.
