Building a Quest UI [SOLVED!]

Started by deadsuperhero, Wed 15/07/2020 23:01:53

Previous topic - Next topic

deadsuperhero

Edit: This has been solved. Check out the solution!

I'm in the process of building out an adventure RPG in Adventure Game Studio, and over the past few months I've been making some pretty good progress.
Recently, though, I've wanted to implement a quest system, as a sort of visual way to assign things to the player and give them the opportunity to track things they have left to do.

In the process of building this, I've come across a few constaints, and haven't totally worked out the bugs yet. I'd like to touch upon what I've gotten working so far, along with a few ideas I've had.

Creating a Quest
Currently, Quest creation is little more than adding a new String to a ListBox. It looks like this:

Code: ags

function createQuest(const string questTitle,  const string questDesc) {
  questList.AddItem(questTitle);
  qDesc.Text = questDesc;
}


What we end up with looks like this:

https://i.imgur.com/YwdvbGu.png

The Description Problem
Anyone with experience in AGS will immediately realize there's a bit of a problem with doing things this way: the description is not actually being stored! The UI label just gets updated every single time a new quest gets assigned.

I've looked through the forums a couple of times to determine how exactly I'm supposed to update the label upon selecting a particular ListBox element. Thankfully, SelectedIndex is a thing, so we can at the very least update the label based on what the description is, like so...

Code: ags

function questList_OnSelectionChanged(GUIControl *control)
{
  if (questList.Items[questList.SelectedIndex] == "Sample Quest") {
    qDesc.Text = "The interface should update when selecting this";
  }
  
   if (questList.Items[questList.SelectedIndex] == "Get Ready for Work") {
     qDesc.Text = "You need to get ready to go to the office. Don't be late!";
  }

  else {
    qDesc.Text = "No description. Please select a quest.";
  }
}


Unfortunately, this is kind of unwieldy, and goes against the principle of DRY (Don't Repeat Yourself) in programming. It might not be a problem if I only have a dozen or so quests, but it doesn't exactly scale up if I want a game with 60+ quests or something. It also kind of goes against the initial function pattern I was hoping to follow.

Another headache that I've noticed is that SelectedIndex appears to only work on matching results against an exact title. One thing I'd love to figure out is whether or not it's possible to use some other kind of value, like an ID or something. My thought is that, if I could somehow store the description somewhere, and associate that with the title, I might be able to update certain elements through that association.

A Possible Solution - Structs!
So, I've been banging my head against the wall, trying to figure out how to store Quests as a type of Script Object that can be referenced in the UI. I came across the AGS Documentation on Structs, and it almost seems perfect...

So, in the global script header, I defined my Quest struct like so:

Code: ags

struct Quest {
  String title;
  String desc;
  int ID;
  bool complete;
  import function Create(int questID, const string questTitle, const string questDesc);
};


I also have this function in the Global Script:

Code: ags

function Quest::Create(int questID, const string questTitle, const string questDesc) {
  this.title = questTitle;
  this.desc = questDesc;
  this.ID = questID;
  this.complete = false;
  questList.AddItem(this.title);
}


The editor compiles with no problems, and this seems to be a semantically better way to generate quests. Now, whenever I try to create a new quest, I define an ID, the title, and the description, and it should get added to the Quest UI.

Let's try this with a Sample Quest...

Code: ags

  // Generate fake quest
 Quest.Create(1,  "Sample Quest", "The interface should update when selecting this");


This is unfortunately where I hit my first serious snag with Structs. Upon attempting to compile, the editor gives me an error:

Code: ags

GlobalScript.asc(198): Error (line 198): must have an instance of the struct to access a non-static member


At this point, I'm not really sure about what I need to do to move forward. This is the first time I've tried to work with Structs, and it's not 100% clear how I'm supposed to make them accessible to global or local scripts. Unfortunately, many of the examples I've seen of Structs being used are fairly abstract, or fit use-cases that are put together quite differently.

Goals and Questions
Ideally, what I'd like to do is successfully generate a Quest struct, and update the Quest UI so that the ListBox gets populated and the Label gets changed in a more efficient way.
Here are my questions on "How do I...?"


  • What am I doing wrong in creating the struct from the function?
  • Can SelectedIndex use something other than the Quest Title for setting the label? Such as an ID?
  • If I have to use the Quest Title for SelectedIndex, how might I be able to parse out other values of an existing Quest struct and update the UI accordingly?
  • Given that ListBox has a relatively limited API, is there a way to include sprites inside of the ListBox to represent completion state?
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Update: I managed to wrap my head around the first problem with Structs. It turns out that I needed to define an instance for my quest creation function to work.

So now, the Header looks like this:

Code: ags

struct Quest {
  String title;
  String desc;
  int ID;
  bool complete;
  import function Create(int questID, const string questTitle, const string questDesc);
};

import Quest playerQuests;


And the Global Script has this at the top:

Code: ags

Quest playerQuests;
export playerQuests;


Meaning that I can now call the creation function like so:

Code: ags

playerQuests.Create(2,  "Get Ready for Work", "You need to get ready to go to the office. Don't be late!");


While the naming convention could probably be cleaned up a bit  :tongue:, I'm relatively happy to see that the result matches exactly what I was doing before, but now I can create the struct and theoretically access it.

The new question now is, how do I reference values stored in the struct to update my GUI label?
The fediverse needs great indie game developers! Find me there!

Khris

You need to create an array of struct instances:

Code: ags
// header
import Quest quest[60];

// main script
Quest quest[60]; // quest[0], quest[1], ..., quest[59]
export quest;

(import and export lines are only required if you want to access your quest array from other scripts, like room scripts)

Now you can call  quest[0].Create(...);


On to SelectedIndex: the quest array stores quest data, now you need an active_quest array:
(this array allows a) an arbitrary order of active quests b) doesn't have holes, if quests 1 and 3 are active but 2 isn't)
Code: ags
int active_quest[60]; // create 60 integer slots
int active_quests = 0;  // stores amount of active quests and also first free slot

// adding quest #3 as first active quest:
active_quest[active_quests] = 3;
active_quests++;

// OnSelectionChanged
  qDesc.Text = quest[active_quest[questList.SelectedIndex]].desc;

The way this works:  questList.SelectedIndex  is 0, so  active_quest[questList.SelectedIndex]  is 3
and  quest[active_quest[questList.SelectedIndex]] is therefore  quest[3]


Listbox doesn't support sprites; you need to either draw the GUI yourself or use buttons to display images

deadsuperhero

Woah, nice! I'll give that a stab and report back!  :cheesy:
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Okay, I've implemented everything, unfortunately the game now crashes when clicking on Quests in the UI.

Code: ags
Error: Null string supplied to CheckForTranslations


I'm maybe getting the impression that perhaps the active_quest variable isn't actually touching the struct itself, which is what I need to access.
Maybe it's not a bad idea to set a quest as active upon creation?
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Okay, I got it! It's a bit hacky for now, but the creation function looks like this:

Code: ags

function Epic::Create(int questID,  const string questTitle, const string questDesc) {
  this.title = questTitle;
  this.desc = questDesc;
  this.complete = false;
  this.ID = questID;
  questList.AddItem(this.title);
  active_quest[active_quests] = questID;
  active_quests++;
}


It's a little hacky, because unfortunately quest creation now looks like this:

Code: ags
Quest[2].Create(2,  "Get Ready for Work", "You need to get ready to go to the office. Don't be late!");


But it's something I can live with for now.  :wink:
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Okay, this has been really fruitful! I guess the last thing at this point: I have a secondary listbox that contains Tasks. A Task Struct looks like this:

Code: ags

struct Task {
  String desc;
  int ID;
  bool complete;
  import function Create(int questID,  const string taskDesc);
};


The associated Task creation function looks like this:

Code: ags

function Task::Create(int questID,  const string taskDesc) {
  this.desc = taskDesc;
  this.ID = questID;
  this.complete = false;
  subTasks.AddItem(this.desc);
}


Tasks get added to a secondary ListBox in the UI called subTasks. How can I change the content of this ListBox when selecting its corresponding Quest?
The Task Struct does accept a questID parameter just like Quests do... I was hoping perhaps there was a way to associate one struct to the other this way, but it's not completely clear how the subTasks ListBox might get updated accordingly.
The fediverse needs great indie game developers! Find me there!

deadsuperhero

#7
I apologize if my multiple posts on this thread have been disruptive; this is largely serving as an internal monologue as I stumble through ideas of how to do this.

For updating the list of subTasks, the best I can figure is that I'll need to:

1. derive the quest ID from the currently selected quest.
2. Look up which Task structs have a matching quest ID in them
3. Clear the list so that there's nothing on it.
4. Repopulate the List with relevant Task items

I may just bang my head against the wall some more tonight and give up, but I'll probably have something put together tomorrow.

Deriving the ID, Spitting Out Values

So, for the first experiment, I tried to pluck out the ID by running a check: if the existing selection's title matches with an existing Quest struct, spit out relevant details about what's stored in that particular quest struct.

Code: ags


function questList_OnSelectionChanged(GUIControl *control)
{
  // Dummy function for deriving values from selection
  String current_selection = quest[active_quest[questList.SelectedIndex]].title;
  int list_id = quest[active_quest[questList.SelectedIndex]].ID;
  int struct_id = quest[list_id].ID;
  
  // If the current selection matches a Struct that has this title, tell us some stuff.
  if (current_selection == quest[struct_id].title) {
    Display("This matches an existing Quest struct!");
    String name = String.Format("%s",  quest[struct_id].title);
    String splain = String.Format("%s", quest[struct_id].desc);
    bool status = quest[struct_id].complete;
    String fin = String.Format("%d", status);
    Display("%s is the quest", name);
    Display("%d is the ID", struct_id);
    Display("Description: %s", splain);
    Display("Completion status: %s", fin);
  }
  
  // Existing function to adjust the label
  qDesc.Text = quest[active_quest[questList.SelectedIndex]].desc;
}}



So, this part of the debugging script mostly works...if I click on a Sample Quest with a questID of 1, the script will spit out the Title of Sample Quest, an associated description, an ID of 1, and a Completion Status of 0.

Here's the part where everything goes to hell: Let's say that I complete a quest, removing it from the list. Somehow, suddenly, the items that came after the Sample Quest now suffer from an off-by-one error, meaning that the second entry returns the output of what should've come before it.

It seems that somehow, the struct_id value is still somehow dependent on the list's position integer. I was hoping that putting together struct_id would be a way to work around this, but here we are...

I might have to try constructing this another way...
The fediverse needs great indie game developers! Find me there!

Khris

#8
This:
Code: ags
  int struct_id = quest[list_id].ID;

seems unnecessary, list_id should already be the struct_id you're looking for.

Your points 1-4 look exactly right, that's how I'd do it, here's the basic idea:
Code: ags
  int quest_id = quest[active_quest[questList.SelectedIndex]].ID;

  // TODO: clear subTasks 

  for (int i = 0; i < tasks_count; i++) {
    if (task[i].questID == quest_id) subTasks.AddItem(task[i].desc);
  }

deadsuperhero

Yeah, for some reason I was worried that the list_id was actually just reflecting the integer of the list position, and that I needed to further derive the actual ID stored inside of the struct for that. Removing a quest from the list causes subsequent quests coming after it to spit everything out for a prior entry.

I'll putz around in the morning and see what comes of this.  :wink:
The fediverse needs great indie game developers! Find me there!

deadsuperhero

So, I've almost got it working now, but with one caveat: the first quest can add and remove quests without any problem, but any subsequent quest never gets the task added, despite the system confirming it exists in the relevant struct.

Global Creation Function:
Code: ags

function Quest::Create(int questID,  const string questTitle, const string questDesc) {
  this.title = questTitle;
  this.desc = questDesc;
  this.complete = false;
  this.ID = questID;
  questList.AddItem(this.title);
  active_quest[active_quests] = this.ID;
  active_quests++;
}

function Task::Create(int questID,  const string taskDesc) {
  this.desc = taskDesc;
  this.parent = questID;
  this.complete = false;
  if (this.parent == quest[this.parent].ID && this.complete == false) {
      subTasks.AddItem(this.desc);
    }
  quest[this.parent].children ++; // Tell the parent quest how many tasks it has
}


Global Header Declarations:
Code: ags

struct Quest {
  String title;
  String desc;
  int ID;
  int children;
  bool complete;
  bool active;
  import function Create(int questID, const string questTitle, const string questDesc);
  import function Complete();
};

struct Task {
  String desc;
  int parent;
  bool complete;
  import function Create(int questID,  const string taskDesc);
  import function Complete();
  int count;
};

import Quest quest[60];
import Task task[100];


GUI Function:

Code: ags

unction questList_OnSelectionChanged(GUIControl *control)
{
  // Dummy function for deriving values from selection
 int quest_id = quest[active_quest[questList.SelectedIndex]].ID;
 int task_count = quest[quest_id].children;
  }
  
  //Adjust Label
  qDesc.Text = quest[active_quest[questList.SelectedIndex]].desc;
  
  
  // Clear the List
 subTasks.Clear();
  
  
  // Populate the List with just the relevant Tasks.
  for (int i = 0; i < task_count; i++) {
    if (task[i].parent == quest[quest_id].ID && task[i].complete == false) {
      subTasks.AddItem(task[i].desc);
    }
  }
  
}


The problem is this: if I create a second quest and a task for that second quest, it briefly shows up appended to the first quest's tasks in the UI:

Creating tasks for first quest:
Code: ags

 quest[0].Create(0,  "Get Ready for Work", "You need to get ready to go to the office. Don't be late!");
 task[0].Create(0, "Get Dressed");
 task[1].Create(0, "Eat Breakfast");
 task[2].Create(0, "Drink Coffee");


Creating tasks for second quest:
Code: ags

   quest[1].Create(1,  "Second Quest", "It's time to start the second adventure!");
   task[4].Create(1,  "Do the first action of the second quest.");


Additionally, "Completing" the first quest causes an off-by-one error with the second quest, where the values being returned are the details of the first quest.
I think now that the problem might have something to do with how the activequest is being declared: currently, it's declared in the create function for every single quest.
The fediverse needs great indie game developers! Find me there!

Khris

One thing that might cause issues:
ints that aren't initialized to any value start out being 0, and your code skips creating  task[3]  which means  task[3].parent  is 0, i.e. the ID of the first quest.

deadsuperhero

It's a good thought, but unfortunately no dice.

One thought is that maybe new tasks are somehow getting pinned to whatever quest is highlighted at the top of the ListBox. Weird thought, but maybe the creation call for tasks doesn't need to actually add the item to the ListBox at all?

My gut says that maybe this is what is happening: the task gets added to the highlighted active quest. Then, my validation check to see if the IDs match removes it from the listBox, because of course it doesn't match (my latest version of the population code has a second if statement using a NOT operator). Only, because I've done this, there's now no task to actually append to the correct quest.

One fun part of programming is realizing how many potential edge cases a seemingly simple idea misses.  :wink:
The fediverse needs great indie game developers! Find me there!

deadsuperhero

I'm back from the abyss! I was away at Air Force Basic Training for the last few months, but I have some time now to pick this up again.

I'm still having some challenges with this code. I've managed to clean up a lot of things, but there are two outstanding problems:

1. The "phantom task" issue still happens. No matter what I do, tasks for the secondary quest never show up, despite my counter indicating that
2. If I mark a Quest as "Completed", any Tasks that aren't complete end up getting appended to whatever the next active Quest is.

The biggest wall I seem to be running into is that of associating objects in one array to objects in another array. With regards to the second problem, it would seem straightforward that I could somehow set a boolean state on child objects associated with a parent. However, the process of trying to write some kind of query that can properly crawl from parent to child feels pretty much impossible.

I thought maybe one solution would be to nest arrays inside of a struct in some fashion. It'd be gross, but if I could get an array containing a list of task IDs...it wouldn't be impossible to parse out, because some kind of hierarchy exists to map tasks to a quest. Unfortunately, I can't figure out for the life of me how that might work.
The fediverse needs great indie game developers! Find me there!

deadsuperhero

#14
Okay, I think I've gotten to the root of the phantom task issue now!  :cheesy: (It's not solved yet, but after extensive testing and hacking around, I think I understand the problem).

First off, here's the code of what I have so far.

Code: ags

// Initialize some variables
Quest quest[60];
export quest;
Task task[100];
export task;

int task_counter = -1;
int quest_counter = -1;
int active_quest[60];
int active_quests = 0;

// Creation Functions

function Quest::Create(const string questTitle, const string questDesc) {
  this.title = questTitle;
  this.desc = questDesc;
  this.complete = false;
  questList.AddItem(this.title);
  // Generate an ID using a counter function. Basically, we guess what the array should be based on what the counter says. 
  // We start from an index of -1, because the actual index starts from 0.
  quest_counter +=1;
  this.ID = quest_counter;
  // Set the quest as Active
  active_quest[active_quests] = this.ID;
  active_quests++;
}

function Task::Create(int questID,  const string taskDesc) {
  this.desc = taskDesc;
  this.parent = questID;
  this.complete = false;
  quest[this.parent].children ++;
  task_counter +=1;
  this.ID = task_counter;
}

// Completion Functions

 function Task::Complete() {
  this.complete = true;
}

function Quest::Complete() {
  this.complete = true;
  int q = questList.ItemCount;
  while (q > 0) {
    q--;
    if (questList.Items[q] == this.title) {
      questList.RemoveItem(q);
    }
  }
}

// Update Tasks in the GUI (called later on)

function updateTasks(int quest_id, int task_count) {
// First, clear out the task list completely
 if (subTasks.ItemCount > 0) {
      subTasks.Clear(); // for now, we'll just destroy the task upon completion until we have a better way to update ListBox
    }

// Populate the List with just the relevant Tasks.
  for (int i = 0; i < task_count; i++) {
    if ((task[i].parent == quest_id) && (task[i].complete == false)) {
      subTasks.AddItem(task[i].desc);
    }
}

// Quest GUI Functions
function questList_OnSelectionChanged(GUIControl *control)
{
 int quest_id = quest[active_quest[questList.SelectedIndex]].ID;
 int task_count = quest[quest_id].children;
 String splain = String.Format("%s", quest[quest_id].desc);
  
  //Adjust Label
  qDesc.Text = splain;
  
  
  // Update Listed Tasks
  updateTasks(quest_id, task_count);
  
}



So, this almost, ALMOST works! The problem I'm up against now: it seems that the quest_id in the GUI never increments above 0 when it comes to rendering the subTasks list. In other words, Tasks only show up for the first quest, but nothing after that. I have no idea why this is, or how I might go about fixing it. I'm almost convinced it has something to do with this block:

Code: ags

// Populate the List with just the relevant Tasks.
  for (int i = 0; i < task_count; i++) {
    if ((task[i].parent == quest_id) && (task[i].complete == false)) {
      subTasks.AddItem(task[i].desc);
    }
}


It seems like maybe the "i" variable is getting parsed as zero when
Code: ags
task[i].parent
is called. I'm still noodling on how to work around this...
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Hey, so just wanted to bring this to a close - I ended up solving this today! I've been messing with Structs a lot for a different game, and the solution of associating things together ended up being a lot simpler than I was initially giving credit.

TL;DR - The Quest system I was trying to build failed because it was trying to use some kind of ID as a reference point to look up related tasks, but everything was convoluted and built on some very silly assumptions of how best to generate Struct objects and parse through them.

Here's a breakdown of what my system actually does now:

First - I found it much easier to create Struct objects as a separate function not related at all to the Struct object itself. Instead, just get a count of all Quests and Tasks in the game, and increment that number to determine the ID of the next one.

Code: ags

function createQuest(String questTitle,  String questDesc) {
    // Currently refactoring, might not work
  int i = questCount;
  quest[i].title = questTitle;
  quest[i].desc = questDesc;
  quest[i].complete = false;
  questList.AddItem(quest[i].title);
  questCount++;
}

function createTask(String pq, String taskDesc) {
  int i = taskCount;
  task[i].desc = taskDesc;
  task[i].parentQuest = pq;
  task[i].complete = false;
  taskCount++;
}


What I was trying to do before for Struct object generation was super unwieldy. Here's a before and after comparison:

Before:
Code: ags

// Create a Quest
quest[1].Create("Get Ready for Work", "You need to get ready to go to the office. Don't be late!");

// Assign three Tasks to Quest 1
task[0].Create(1`, "Get Dressed");
task[1].Create(1, "Eat Breakfast");
task[2].Create(1, "Drink Coffee");


After:
Code: ags

// Create a Quest
createQuest("Get Ready for Work", "You need to get ready to go to the office. Don't be late!");

// Assign three Tasks to Quest 1
createTask("Get Ready for Work", "Get Dressed");
createTask("Get Ready for Work", "Eat Breakfast");
createTask("Get Ready for Work", "Drink Coffee");


The great thing now is that, the new way of doing things doesn't care about IDs - they're unimportant. Quest names in this system are unique enough, and are what I'm using to do all the lookup logic! AGS literally doesn't care.


Code: ags

// Refreshing the Quest List, which is called every time the Quest UI is invoked.
function refreshQuests() {
  // Refresh the List of Quests
  if (questList.ItemCount > 0) {
    questList.Clear();
  }
  
  // Add Completed Quests
    for (int i = 0; i < questCount; i++) {
      if (quest[i].complete == false) {
         questList.AddItem(quest[i].title);
      }
  }
  
  // Set the Selected Index
  int comboIndex = questList.SelectedIndex + completedQuests;
  
  // Refresh the tasks for good measure
  lookupTasks(quest[comboIndex].title);
  

// Refreshing the Task List, technically this shows up higher in the script so that the prior function can call it.
function lookupTasks(String questTitle) {
  
    // Refresh the Task List
    if (subTasks.ItemCount > 0) {
      subTasks.Clear();
    }
    
    // List all of the Tasks the game knows about
    for (int i = 0; i < taskCount; i++) {
      if ((task[i].parentQuest == questTitle) && (task[i].complete == false)) {
      subTasks.AddItem(task[i].desc);
    }
  }
}



A few weird things I had to do to cover my butt:

Whenever the Quest UI is invoked, it needs to be told to select the topmost item on the Quest list, in order to pull in the Task items associated with a quest.

Code: ags

function btnQuests_OnClick(GUIControl *control, MouseButton button)
{
  int comboIndex = questList.SelectedIndex + completedQuests;
  if (questList.ItemCount > 0) { // Game crashes if it tries to do all this stuff with no quests in the system, so this loop is an extra bit of protection
    refreshQuests();
    qDesc.Text = quest[comboIndex].desc; // Sets the description of the Current Text
    gQuests.Visible = true;
  }
  else {
    Display("You have no quests.");
  }
}


Whenever a selection on the Quest list gets updated, I have to dynamically change everything:

Code: ags

function questList_OnSelectionChanged(GUIControl *control)
{
 int comboIndex = questList.SelectedIndex + completedQuests;
 String selectedQuest = quest[comboIndex].title;
 String selectedDesc = quest[comboIndex].desc;
  
  // Check the quest details
  lookupQuest(selectedQuest);
  
  //Adjust Label
  qDesc.Text = selectedDesc;
  
  
  // Update Listed Tasks
  lookupTasks(selectedQuest);
  
}


Finally, I had to do one really weird thing to account for Completed quests that no longer show up in the UI:

Code: ags

function completeQuest(String questTitle) {


  // Mark all matching tasks as Complete
  for (int i = 0; i < questCount; i++) {
    if ((quest[i].title == questTitle) && (quest[i].complete == false)) {
       quest[i].complete = true;
       completedQuests++; // Increment this so that other quests still properly align with the index
    }
  }

// Mark all matching tasks as Complete
  for (int i = 0; i < taskCount; i++) {
    if ((task[i].parentQuest == questTitle) && (task[i].complete == false)) {
      task[i].complete = true;
    }
  }
  
}


The last part is really important, and addresses the Phantom Task issue from before: when you remove an item from a ListBox, the index for each item in that ListBox changes. If you have a Quest called "Go to Work" with an ID of 0, and a Quest called "Go Home" with an ID of 1, and then mark "Go to Work" as Complete...the selected Index value of "Go Home" is 0 on the ListBox, which will confuse all of the fancy lookup scripts that we've put together. This is gross, and sucks, but the solution is basically to adjust the index value to compensate for the amount of quests that are now marked as Completed.

So, basically, that's it! I apologize for the eyebleed here. In the future, I'd like to offer some kind of template that makes this all super easy, so that other AGS devs can have fun building their own quests with it.
The fediverse needs great indie game developers! Find me there!

eminigalaxy

Hey sorry to bother but saw this and was wondering if you ever did end up making a template for the quest UI?  :-D
I never rlly know what I'm doing but that's life. || WIP: Dilvemma

Khris

emini: try sending him a PM maybe :)

Re the code, this:
Code: ags
// Create a Quest
createQuest("Get Ready for Work", "You need to get ready to go to the office. Don't be late!");

// Assign three Tasks to Quest 1
createTask("Get Ready for Work", "Get Dressed");
createTask("Get Ready for Work", "Eat Breakfast");
createTask("Get Ready for Work", "Drink Coffee");
seems pretty redundant, I'd store the quest name in a temporary variable and use that to assign the tasks.

deadsuperhero

Quote from: Khris on Fri 17/03/2023 08:54:44emini: try sending him a PM maybe :)

Re the code, this:
Code: ags
// Create a Quest
createQuest("Get Ready for Work", "You need to get ready to go to the office. Don't be late!");

// Assign three Tasks to Quest 1
createTask("Get Ready for Work", "Get Dressed");
createTask("Get Ready for Work", "Eat Breakfast");
createTask("Get Ready for Work", "Drink Coffee");
seems pretty redundant, I'd store the quest name in a temporary variable and use that to assign the tasks.

Yeah, that's pretty good feedback. Right now, Tasks and Quests are created by two separate functions for two separate structs, and related to one another by the Quest name.

I guess you could wrap them in another function and pass through Tasks and Quests at the same time, but you'd still have to use the method I illustrated to assign subsequent Tasks to an existing Quest later on.
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Quote from: eminigalaxy on Fri 17/03/2023 00:15:30Hey sorry to bother but saw this and was wondering if you ever did end up making a template for the quest UI?  :-D

Not yet, but I could probably knock something together this weekend.
The fediverse needs great indie game developers! Find me there!

SMF spam blocked by CleanTalk