diff options
Diffstat (limited to 'engines/glk/adrift/sctasks.cpp')
-rw-r--r-- | engines/glk/adrift/sctasks.cpp | 2237 |
1 files changed, 1060 insertions, 1177 deletions
diff --git a/engines/glk/adrift/sctasks.cpp b/engines/glk/adrift/sctasks.cpp index 4ced0c5099..8273affef6 100644 --- a/engines/glk/adrift/sctasks.cpp +++ b/engines/glk/adrift/sctasks.cpp @@ -57,43 +57,38 @@ static sc_bool task_trace = FALSE; * hints. */ static const sc_char * -task_get_hint_common (sc_gameref_t game, sc_int task, const sc_char *hint) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *retval; - - /* Look up and return the requested hint string. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = hint; - retval = prop_get_string (bundle, "S<-sis", vt_key); - return retval; +task_get_hint_common(sc_gameref_t game, sc_int task, const sc_char *hint) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *retval; + + /* Look up and return the requested hint string. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = hint; + retval = prop_get_string(bundle, "S<-sis", vt_key); + return retval; } const sc_char * -task_get_hint_question (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Question"); +task_get_hint_question(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Question"); } const sc_char * -task_get_hint_subtle (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Hint1"); +task_get_hint_subtle(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Hint1"); } const sc_char * -task_get_hint_unsubtle (sc_gameref_t game, sc_int task) -{ - return task_get_hint_common (game, task, "Hint2"); +task_get_hint_unsubtle(sc_gameref_t game, sc_int task) { + return task_get_hint_common(game, task, "Hint2"); } sc_bool -task_has_hints (sc_gameref_t game, sc_int task) -{ - /* A non-empty question implies hints available. */ - return !sc_strempty (task_get_hint_question (game, task)); +task_has_hints(sc_gameref_t game, sc_int task) { + /* A non-empty question implies hints available. */ + return !sc_strempty(task_get_hint_question(game, task)); } @@ -104,72 +99,68 @@ task_has_hints (sc_gameref_t game, sc_int task) * is runnable in the given direction. */ sc_bool -task_can_run_task_directional (sc_gameref_t game, - sc_int task, sc_bool forwards) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type; - - /* If already run, non-repeatable tasks are not re-runnable forwards. */ - if (forwards && gs_task_done (game, task)) - { - sc_bool repeatable; - const sc_char *repeattext; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Repeatable"; - repeatable = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!repeatable) - return FALSE; - - vt_key[2].string = "RepeatText"; - repeattext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (repeattext)) - return FALSE; - } - - /* If checking for reverse, test the reversibility flag. */ - if (!forwards) - { - sc_bool reversible; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Reversible"; - reversible = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!reversible) - return FALSE; - } - - /* Check room list for the task and return it. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Where"; - vt_key[3].string = "Type"; - type = prop_get_integer (bundle, "I<-siss", vt_key); - switch (type) - { - case ROOMLIST_NO_ROOMS: - return FALSE; - case ROOMLIST_ALL_ROOMS: - return TRUE; - - case ROOMLIST_ONE_ROOM: - vt_key[3].string = "Room"; - return prop_get_integer (bundle, - "I<-siss", vt_key) == gs_playerroom (game); - - case ROOMLIST_SOME_ROOMS: - vt_key[3].string = "Rooms"; - vt_key[4].integer = gs_playerroom (game); - return prop_get_boolean (bundle, "B<-sissi", vt_key); - - default: - sc_fatal ("task_can_run_task_directional: invalid type, %ld\n", type); - return FALSE; - } +task_can_run_task_directional(sc_gameref_t game, + sc_int task, sc_bool forwards) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type; + + /* If already run, non-repeatable tasks are not re-runnable forwards. */ + if (forwards && gs_task_done(game, task)) { + sc_bool repeatable; + const sc_char *repeattext; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Repeatable"; + repeatable = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!repeatable) + return FALSE; + + vt_key[2].string = "RepeatText"; + repeattext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(repeattext)) + return FALSE; + } + + /* If checking for reverse, test the reversibility flag. */ + if (!forwards) { + sc_bool reversible; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Reversible"; + reversible = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!reversible) + return FALSE; + } + + /* Check room list for the task and return it. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Where"; + vt_key[3].string = "Type"; + type = prop_get_integer(bundle, "I<-siss", vt_key); + switch (type) { + case ROOMLIST_NO_ROOMS: + return FALSE; + case ROOMLIST_ALL_ROOMS: + return TRUE; + + case ROOMLIST_ONE_ROOM: + vt_key[3].string = "Room"; + return prop_get_integer(bundle, + "I<-siss", vt_key) == gs_playerroom(game); + + case ROOMLIST_SOME_ROOMS: + vt_key[3].string = "Rooms"; + vt_key[4].integer = gs_playerroom(game); + return prop_get_boolean(bundle, "B<-sissi", vt_key); + + default: + sc_fatal("task_can_run_task_directional: invalid type, %ld\n", type); + return FALSE; + } } @@ -179,15 +170,14 @@ task_can_run_task_directional (sc_gameref_t game, * Returns TRUE if the task can be run in either direction. */ sc_bool -task_can_run_task (sc_gameref_t game, sc_int task) -{ - /* - * Testing reversible tasks first may be a little more efficient if they - * aren't common in games. There is, though, probably a little bit of - * redundant work going on here. - */ - return task_can_run_task_directional (game, task, FALSE) - || task_can_run_task_directional (game, task, TRUE); +task_can_run_task(sc_gameref_t game, sc_int task) { + /* + * Testing reversible tasks first may be a little more efficient if they + * aren't common in games. There is, though, probably a little bit of + * redundant work going on here. + */ + return task_can_run_task_directional(game, task, FALSE) + || task_can_run_task_directional(game, task, TRUE); } @@ -197,114 +187,102 @@ task_can_run_task (sc_gameref_t game, sc_int task) * Move an object to a place. */ static void -task_move_object (sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - - /* Select action depending on var2. */ - switch (var2) - { - case 0: /* To room */ - if (var3 == 0) - { - if (task_trace) - sc_trace ("Task: moving object %ld to hidden\n", object); - - gs_object_make_hidden (game, object); - } - else - { - if (task_trace) - { - sc_trace ("Task: moving object %ld to room %ld\n", - object, var3 - 1); - } - - if (var3 == 0) - gs_object_player_get (game, object); - else - gs_object_to_room (game, object, var3 - 1); - } - break; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving object %ld to random room in group %ld\n", - object, var3); - } - - gs_object_to_room (game, object, - lib_random_roomgroup_member (game, var3)); - break; - - case 2: /* Into object */ - if (task_trace) - sc_trace ("Task: moving object %ld into %ld\n", object, var3); - - gs_object_move_into (game, object, obj_container_object (game, var3)); - break; - - case 3: /* Onto object */ - if (task_trace) - sc_trace ("Task: moving object %ld onto %ld\n", object, var3); - - gs_object_move_onto (game, object, obj_surface_object (game, var3)); - break; - - case 4: /* Held by */ - if (task_trace) - sc_trace ("Task: moving object %ld to held by %ld\n", object, var3); - - if (var3 == 0) /* Player */ - gs_object_player_get (game, object); - else if (var3 == 1) /* Ref character */ - gs_object_npc_get (game, object, var_get_ref_character (vars)); - else /* NPC id */ - gs_object_npc_get (game, object, var3 - 2); - break; - - case 5: /* Worn by */ - if (task_trace) - sc_trace ("Task: moving object %ld to worn by %ld\n", object, var3); - - if (var3 == 0) /* Player */ - gs_object_player_wear (game, object); - else if (var3 == 1) /* Ref character */ - gs_object_npc_wear (game, object, var_get_ref_character (vars)); - else /* NPC id */ - gs_object_npc_wear (game, object, var3 - 2); - break; - - case 6: /* Same room as */ - { - sc_int room, npc; - - if (task_trace) - { - sc_trace ("Task: moving object %ld to same room as %ld\n", - object, var3); - } - - if (var3 == 0) /* Player */ - room = gs_playerroom (game); - else if (var3 == 1) /* Ref character */ - { - npc = var_get_ref_character (vars); - room = gs_npc_location (game, npc) - 1; - } - else /* NPC id */ - { - npc = var3 - 2; - room = gs_npc_location (game, npc) - 1; - } - gs_object_to_room (game, object, room); - break; - } - - default: - sc_fatal ("task_move_object: unknown move type, %ld\n", var2); - } +task_move_object(sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + + /* Select action depending on var2. */ + switch (var2) { + case 0: /* To room */ + if (var3 == 0) { + if (task_trace) + sc_trace("Task: moving object %ld to hidden\n", object); + + gs_object_make_hidden(game, object); + } else { + if (task_trace) { + sc_trace("Task: moving object %ld to room %ld\n", + object, var3 - 1); + } + + if (var3 == 0) + gs_object_player_get(game, object); + else + gs_object_to_room(game, object, var3 - 1); + } + break; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving object %ld to random room in group %ld\n", + object, var3); + } + + gs_object_to_room(game, object, + lib_random_roomgroup_member(game, var3)); + break; + + case 2: /* Into object */ + if (task_trace) + sc_trace("Task: moving object %ld into %ld\n", object, var3); + + gs_object_move_into(game, object, obj_container_object(game, var3)); + break; + + case 3: /* Onto object */ + if (task_trace) + sc_trace("Task: moving object %ld onto %ld\n", object, var3); + + gs_object_move_onto(game, object, obj_surface_object(game, var3)); + break; + + case 4: /* Held by */ + if (task_trace) + sc_trace("Task: moving object %ld to held by %ld\n", object, var3); + + if (var3 == 0) /* Player */ + gs_object_player_get(game, object); + else if (var3 == 1) /* Ref character */ + gs_object_npc_get(game, object, var_get_ref_character(vars)); + else /* NPC id */ + gs_object_npc_get(game, object, var3 - 2); + break; + + case 5: /* Worn by */ + if (task_trace) + sc_trace("Task: moving object %ld to worn by %ld\n", object, var3); + + if (var3 == 0) /* Player */ + gs_object_player_wear(game, object); + else if (var3 == 1) /* Ref character */ + gs_object_npc_wear(game, object, var_get_ref_character(vars)); + else /* NPC id */ + gs_object_npc_wear(game, object, var3 - 2); + break; + + case 6: { /* Same room as */ + sc_int room, npc; + + if (task_trace) { + sc_trace("Task: moving object %ld to same room as %ld\n", + object, var3); + } + + if (var3 == 0) /* Player */ + room = gs_playerroom(game); + else if (var3 == 1) { /* Ref character */ + npc = var_get_ref_character(vars); + room = gs_npc_location(game, npc) - 1; + } else { /* NPC id */ + npc = var3 - 2; + room = gs_npc_location(game, npc) - 1; + } + gs_object_to_room(game, object, room); + break; + } + + default: + sc_fatal("task_move_object: unknown move type, %ld\n", var2); + } } @@ -314,41 +292,37 @@ task_move_object (sc_gameref_t game, sc_int object, sc_int var2, sc_int var3) * Demultiplex an object move action and execute it. */ static void -task_run_move_object_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int object; - - /* Select depending on value in var1. */ - switch (var1) - { - case 0: /* All held */ - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_HELD_PLAYER) - task_move_object (game, object, var2, var3); - } - break; - - case 1: /* All worn */ - for (object = 0; object < gs_object_count (game); object++) - { - if (gs_object_position (game, object) == OBJ_WORN_PLAYER) - task_move_object (game, object, var2, var3); - } - break; - - case 2: /* Ref object */ - object = var_get_ref_object (vars); - task_move_object (game, object, var2, var3); - break; - - default: /* Dynamic object */ - object = obj_dynamic_object (game, var1 - 3); - task_move_object (game, object, var2, var3); - break; - } +task_run_move_object_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int object; + + /* Select depending on value in var1. */ + switch (var1) { + case 0: /* All held */ + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_HELD_PLAYER) + task_move_object(game, object, var2, var3); + } + break; + + case 1: /* All worn */ + for (object = 0; object < gs_object_count(game); object++) { + if (gs_object_position(game, object) == OBJ_WORN_PLAYER) + task_move_object(game, object, var2, var3); + } + break; + + case 2: /* Ref object */ + object = var_get_ref_object(vars); + task_move_object(game, object, var2, var3); + break; + + default: /* Dynamic object */ + object = obj_dynamic_object(game, var1 - 3); + task_move_object(game, object, var2, var3); + break; + } } @@ -358,21 +332,20 @@ task_run_move_object_action (sc_gameref_t game, * Move an NPC to a given room. */ static void -task_move_npc_to_room (sc_gameref_t game, sc_int npc, sc_int room) -{ - if (task_trace) - sc_trace ("Task: moving NPC %ld to room %ld\n", npc, room); - - /* Update the NPC's state. */ - if (room < gs_room_count (game)) - gs_set_npc_location (game, npc, room + 1); - else - gs_set_npc_location (game, npc, - lib_random_roomgroup_member (game, - room - gs_room_count (game)) + 1); - - gs_set_npc_parent (game, npc, -1); - gs_set_npc_position (game, npc, 0); +task_move_npc_to_room(sc_gameref_t game, sc_int npc, sc_int room) { + if (task_trace) + sc_trace("Task: moving NPC %ld to room %ld\n", npc, room); + + /* Update the NPC's state. */ + if (room < gs_room_count(game)) + gs_set_npc_location(game, npc, room + 1); + else + gs_set_npc_location(game, npc, + lib_random_roomgroup_member(game, + room - gs_room_count(game)) + 1); + + gs_set_npc_parent(game, npc, -1); + gs_set_npc_position(game, npc, 0); } @@ -382,164 +355,149 @@ task_move_npc_to_room (sc_gameref_t game, sc_int npc, sc_int room) * Move player or NPC. */ static void -task_run_move_npc_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3) -{ - const sc_var_setref_t vars = gs_get_vars (game); - sc_int npc, room, ref_npc = -1; - - /* Player or NPC? */ - if (var1 == 0) - { - /* Player -- decide where to move player to. */ - switch (var2) - { - case 0: /* To room */ - gs_move_player_to_room (game, var3); - return; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving player to random room in group %ld\n", - var3); - } - - gs_move_player_to_room (game, - lib_random_roomgroup_member (game, var3)); - return; - - case 2: /* To same room as... */ - switch (var3) - { - case 0: /* ...player! */ - return; - case 1: /* ...referenced NPC */ - npc = var_get_ref_character (vars); - break; - default: /* ...specified NPC */ - npc = var3 - 2; - break; - } - - if (task_trace) - sc_trace ("Task: moving player to same room as NPC %ld\n", npc); - - room = gs_npc_location (game, npc) - 1; - if (room < 0) - { - if (task_trace) - sc_trace ("Task: silently suppressed player move to hidden\n"); - } - else - gs_move_player_to_room (game, room); - return; - - case 3: /* To standing on */ - gs_set_playerposition (game, 0); - gs_set_playerparent (game, obj_standable_object (game, var3 - 1)); - return; - - case 4: /* To sitting on */ - gs_set_playerposition (game, 1); - gs_set_playerparent (game, obj_standable_object (game, var3 - 1)); - return; - - case 5: /* To lying on */ - gs_set_playerposition (game, 2); - gs_set_playerparent (game, obj_lieable_object (game, var3 - 1)); - return; - - default: - sc_fatal ("task_run_move_npc_action:" - " unknown player move type, %ld\n", var2); - return; - } - } - else - { - /* NPC -- first find which NPC to move about. */ - if (var1 == 1) - npc = var_get_ref_character (vars); - else - npc = var1 - 2; - - /* Decide where to move the NPC to. */ - switch (var2) - { - case 0: /* To room */ - task_move_npc_to_room (game, npc, var3 - 1); - return; - - case 1: /* To roomgroup part */ - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to random room in group %ld\n", - npc, var3); - } - - task_move_npc_to_room (game, npc, - lib_random_roomgroup_member (game, var3)); - return; - - case 2: /* To same room as... */ - switch (var3) - { - case 0: /* ...player */ - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to same room as player\n", - npc); - } - - task_move_npc_to_room (game, npc, gs_playerroom (game)); - break; - case 1: /* ...referenced NPC */ - ref_npc = var_get_ref_character (vars); - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to" - " same room as referenced NPC %ld\n", npc, ref_npc); - } - - room = gs_npc_location (game, ref_npc) - 1; - task_move_npc_to_room (game, npc, room); - break; - default: /* ...specified NPC */ - ref_npc = var3 - 2; - if (task_trace) - { - sc_trace ("Task: moving NPC %ld to" - " same room as NPC %ld\n", npc, ref_npc); - } - - room = gs_npc_location (game, ref_npc) - 1; - task_move_npc_to_room (game, npc, room); - break; - } - return; - - case 3: /* To standing on */ - gs_set_npc_position (game, npc, 0); - gs_set_npc_parent (game, npc, obj_standable_object (game, var3)); - return; - - case 4: /* To sitting on */ - gs_set_npc_position (game, npc, 1); - gs_set_npc_parent (game, npc, obj_standable_object (game, var3)); - return; - - case 5: /* To lying on */ - gs_set_npc_position (game, npc, 2); - gs_set_npc_parent (game, npc, obj_lieable_object (game, var3)); - return; - - default: - sc_fatal ("task_run_move_npc_action:" - " unknown NPC move type, %ld\n", var2); - return; - } - } +task_run_move_npc_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3) { + const sc_var_setref_t vars = gs_get_vars(game); + sc_int npc, room, ref_npc = -1; + + /* Player or NPC? */ + if (var1 == 0) { + /* Player -- decide where to move player to. */ + switch (var2) { + case 0: /* To room */ + gs_move_player_to_room(game, var3); + return; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving player to random room in group %ld\n", + var3); + } + + gs_move_player_to_room(game, + lib_random_roomgroup_member(game, var3)); + return; + + case 2: /* To same room as... */ + switch (var3) { + case 0: /* ...player! */ + return; + case 1: /* ...referenced NPC */ + npc = var_get_ref_character(vars); + break; + default: /* ...specified NPC */ + npc = var3 - 2; + break; + } + + if (task_trace) + sc_trace("Task: moving player to same room as NPC %ld\n", npc); + + room = gs_npc_location(game, npc) - 1; + if (room < 0) { + if (task_trace) + sc_trace("Task: silently suppressed player move to hidden\n"); + } else + gs_move_player_to_room(game, room); + return; + + case 3: /* To standing on */ + gs_set_playerposition(game, 0); + gs_set_playerparent(game, obj_standable_object(game, var3 - 1)); + return; + + case 4: /* To sitting on */ + gs_set_playerposition(game, 1); + gs_set_playerparent(game, obj_standable_object(game, var3 - 1)); + return; + + case 5: /* To lying on */ + gs_set_playerposition(game, 2); + gs_set_playerparent(game, obj_lieable_object(game, var3 - 1)); + return; + + default: + sc_fatal("task_run_move_npc_action:" + " unknown player move type, %ld\n", var2); + return; + } + } else { + /* NPC -- first find which NPC to move about. */ + if (var1 == 1) + npc = var_get_ref_character(vars); + else + npc = var1 - 2; + + /* Decide where to move the NPC to. */ + switch (var2) { + case 0: /* To room */ + task_move_npc_to_room(game, npc, var3 - 1); + return; + + case 1: /* To roomgroup part */ + if (task_trace) { + sc_trace("Task: moving NPC %ld to random room in group %ld\n", + npc, var3); + } + + task_move_npc_to_room(game, npc, + lib_random_roomgroup_member(game, var3)); + return; + + case 2: /* To same room as... */ + switch (var3) { + case 0: /* ...player */ + if (task_trace) { + sc_trace("Task: moving NPC %ld to same room as player\n", + npc); + } + + task_move_npc_to_room(game, npc, gs_playerroom(game)); + break; + case 1: /* ...referenced NPC */ + ref_npc = var_get_ref_character(vars); + if (task_trace) { + sc_trace("Task: moving NPC %ld to" + " same room as referenced NPC %ld\n", npc, ref_npc); + } + + room = gs_npc_location(game, ref_npc) - 1; + task_move_npc_to_room(game, npc, room); + break; + default: /* ...specified NPC */ + ref_npc = var3 - 2; + if (task_trace) { + sc_trace("Task: moving NPC %ld to" + " same room as NPC %ld\n", npc, ref_npc); + } + + room = gs_npc_location(game, ref_npc) - 1; + task_move_npc_to_room(game, npc, room); + break; + } + return; + + case 3: /* To standing on */ + gs_set_npc_position(game, npc, 0); + gs_set_npc_parent(game, npc, obj_standable_object(game, var3)); + return; + + case 4: /* To sitting on */ + gs_set_npc_position(game, npc, 1); + gs_set_npc_parent(game, npc, obj_standable_object(game, var3)); + return; + + case 5: /* To lying on */ + gs_set_npc_position(game, npc, 2); + gs_set_npc_parent(game, npc, obj_lieable_object(game, var3)); + return; + + default: + sc_fatal("task_run_move_npc_action:" + " unknown NPC move type, %ld\n", var2); + return; + } + } } @@ -549,59 +507,51 @@ task_run_move_npc_action (sc_gameref_t game, * Change the status of an object. */ static void -task_run_change_object_status (sc_gameref_t game, sc_int var1, sc_int var2) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int object, openable, lockable; - - if (task_trace) - { - sc_trace ("Task: setting status of stateful object %ld to %ld\n", - var1, var2); - } - - /* Identify the target object. */ - object = obj_stateful_object (game, var1); - - /* See if openable. */ - vt_key[0].string = "Objects"; - vt_key[1].integer = object; - vt_key[2].string = "Openable"; - openable = prop_get_integer (bundle, "I<-sis", vt_key); - if (openable > 0) - { - /* See if lockable. */ - vt_key[2].string = "Key"; - lockable = prop_get_integer (bundle, "I<-sis", vt_key); - if (lockable >= 0) - { - /* Lockable. */ - if (var2 <= 2) - gs_set_object_openness (game, object, var2 + 5); - else - gs_set_object_state (game, object, var2 - 2); - } - else - { - /* Not lockable, though openable. */ - if (var2 <= 1) - gs_set_object_openness (game, object, var2 + 5); - else - gs_set_object_state (game, object, var2 - 1); - } - } - else - /* Not openable. */ - gs_set_object_state (game, object, var2 + 1); - - if (task_trace) - { - sc_trace ("Task: openness of object %ld is now %ld\n", - object, gs_object_openness (game, object)); - sc_trace ("Task: state of object %ld is now %ld\n", - object, gs_object_state (game, object)); - } +task_run_change_object_status(sc_gameref_t game, sc_int var1, sc_int var2) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int object, openable, lockable; + + if (task_trace) { + sc_trace("Task: setting status of stateful object %ld to %ld\n", + var1, var2); + } + + /* Identify the target object. */ + object = obj_stateful_object(game, var1); + + /* See if openable. */ + vt_key[0].string = "Objects"; + vt_key[1].integer = object; + vt_key[2].string = "Openable"; + openable = prop_get_integer(bundle, "I<-sis", vt_key); + if (openable > 0) { + /* See if lockable. */ + vt_key[2].string = "Key"; + lockable = prop_get_integer(bundle, "I<-sis", vt_key); + if (lockable >= 0) { + /* Lockable. */ + if (var2 <= 2) + gs_set_object_openness(game, object, var2 + 5); + else + gs_set_object_state(game, object, var2 - 2); + } else { + /* Not lockable, though openable. */ + if (var2 <= 1) + gs_set_object_openness(game, object, var2 + 5); + else + gs_set_object_state(game, object, var2 - 1); + } + } else + /* Not openable. */ + gs_set_object_state(game, object, var2 + 1); + + if (task_trace) { + sc_trace("Task: openness of object %ld is now %ld\n", + object, gs_object_openness(game, object)); + sc_trace("Task: state of object %ld is now %ld\n", + object, gs_object_state(game, object)); + } } @@ -611,164 +561,151 @@ task_run_change_object_status (sc_gameref_t game, sc_int var1, sc_int var2) * Change a variable's value in inscrutable ways. */ static void -task_run_change_variable_action (sc_gameref_t game, - sc_int var1, sc_int var2, sc_int var3, - const sc_char *expr, sc_int var5) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - const sc_var_setref_t vars = gs_get_vars (game); - sc_vartype_t vt_key[3]; - const sc_char *name, *string; - sc_char *mutable_string; - sc_int type, value; - - /* - * At this point, we need to checkpoint the filter. We're about to change - * a variable value, so interpolating here before doing that ensures that - * any currently buffered text gets the values that were set when the text - * was buffered. - */ - pf_checkpoint (filter, vars, bundle); - - /* Get the name and type of the variable being addressed. */ - vt_key[0].string = "Variables"; - vt_key[1].integer = var1; - vt_key[2].string = "Name"; - name = prop_get_string (bundle, "S<-sis", vt_key); - vt_key[2].string = "Type"; - type = prop_get_integer (bundle, "I<-sis", vt_key); - - /* Select first based on variable type. */ - switch (type) - { - case TAFVAR_NUMERIC: /* Integer */ - - /* Select again based on action type. */ - switch (var2) - { - case 0: /* Var = */ - if (task_trace) - sc_trace ("Task: variable %ld (%s) = %ld\n", var1, name, var3); - - var_put_integer (vars, name, var3); - return; - - case 1: /* Var += */ - if (task_trace) - sc_trace ("Task: variable %ld (%s) += %ld\n", var1, name, var3); - - value = var_get_integer (vars, name) + var3; - var_put_integer (vars, name, value); - return; - - case 2: /* Var = rnd(range) */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = random(%ld,%ld)\n", - var1, name, var3, var5); - } - - value = sc_randomint (var3, var5); - var_put_integer (vars, name, value); - return; - - case 3: /* Var += rnd(range) */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) += random(%ld,%ld)\n", - var1, name, var3, var5); - } - - value = var_get_integer (vars, name) + sc_randomint (var3, var5); - var_put_integer (vars, name, value); - return; - - case 4: /* Var = ref */ - value = var_get_ref_number (vars); - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = ref, %ld\n", - var1, name, value); - } - - var_put_integer (vars, name, value); - return; - - case 5: /* Var = expr */ - if (!expr_eval_numeric_expression (expr, vars, &value)) - { - sc_error ("task_run_change_variable_action:" - " invalid expression, %s\n", expr); - value = 0; - } - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = %s, %ld\n", - var1, name, expr, value); - } - - var_put_integer (vars, name, value); - return; - - default: - sc_fatal ("task_run_change_variable_action:" - " unknown integer change type, %ld\n", var2); - } - - case TAFVAR_STRING: /* String */ - - /* Select again based on action type. */ - switch (var2) - { - case 0: /* Var = text literal */ - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = \"%s\"\n", - var1, name, expr); - } - - var_put_string (vars, name, expr); - return; - - case 1: /* Var = ref */ - string = var_get_ref_text (vars); - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = ref, \"%s\"\n", - var1, name, string); - } - - var_put_string (vars, name, string); - return; - - case 2: /* Var = expr */ - if (!expr_eval_string_expression (expr, vars, &mutable_string)) - { - sc_error ("task_run_change_variable_action:" - " invalid string expression, %s\n", expr); - mutable_string = (sc_char *)sc_malloc (strlen ("[expr error]") + 1); - strcpy (mutable_string, "[expr error]"); - } - if (task_trace) - { - sc_trace ("Task: variable %ld (%s) = %s, %s\n", - var1, name, expr, mutable_string); - } - - var_put_string (vars, name, mutable_string); - sc_free (mutable_string); - return; - - default: - sc_fatal ("task_run_change_variable_action:" - " unknown string change type, %ld\n", var2); - } - - default: - sc_fatal ("task_run_change_variable_action:" - " invalid variable type, %ld\n", type); - } +task_run_change_variable_action(sc_gameref_t game, + sc_int var1, sc_int var2, sc_int var3, + const sc_char *expr, sc_int var5) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + const sc_var_setref_t vars = gs_get_vars(game); + sc_vartype_t vt_key[3]; + const sc_char *name, *string; + sc_char *mutable_string; + sc_int type, value; + + /* + * At this point, we need to checkpoint the filter. We're about to change + * a variable value, so interpolating here before doing that ensures that + * any currently buffered text gets the values that were set when the text + * was buffered. + */ + pf_checkpoint(filter, vars, bundle); + + /* Get the name and type of the variable being addressed. */ + vt_key[0].string = "Variables"; + vt_key[1].integer = var1; + vt_key[2].string = "Name"; + name = prop_get_string(bundle, "S<-sis", vt_key); + vt_key[2].string = "Type"; + type = prop_get_integer(bundle, "I<-sis", vt_key); + + /* Select first based on variable type. */ + switch (type) { + case TAFVAR_NUMERIC: /* Integer */ + + /* Select again based on action type. */ + switch (var2) { + case 0: /* Var = */ + if (task_trace) + sc_trace("Task: variable %ld (%s) = %ld\n", var1, name, var3); + + var_put_integer(vars, name, var3); + return; + + case 1: /* Var += */ + if (task_trace) + sc_trace("Task: variable %ld (%s) += %ld\n", var1, name, var3); + + value = var_get_integer(vars, name) + var3; + var_put_integer(vars, name, value); + return; + + case 2: /* Var = rnd(range) */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) = random(%ld,%ld)\n", + var1, name, var3, var5); + } + + value = sc_randomint(var3, var5); + var_put_integer(vars, name, value); + return; + + case 3: /* Var += rnd(range) */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) += random(%ld,%ld)\n", + var1, name, var3, var5); + } + + value = var_get_integer(vars, name) + sc_randomint(var3, var5); + var_put_integer(vars, name, value); + return; + + case 4: /* Var = ref */ + value = var_get_ref_number(vars); + if (task_trace) { + sc_trace("Task: variable %ld (%s) = ref, %ld\n", + var1, name, value); + } + + var_put_integer(vars, name, value); + return; + + case 5: /* Var = expr */ + if (!expr_eval_numeric_expression(expr, vars, &value)) { + sc_error("task_run_change_variable_action:" + " invalid expression, %s\n", expr); + value = 0; + } + if (task_trace) { + sc_trace("Task: variable %ld (%s) = %s, %ld\n", + var1, name, expr, value); + } + + var_put_integer(vars, name, value); + return; + + default: + sc_fatal("task_run_change_variable_action:" + " unknown integer change type, %ld\n", var2); + } + + case TAFVAR_STRING: /* String */ + + /* Select again based on action type. */ + switch (var2) { + case 0: /* Var = text literal */ + if (task_trace) { + sc_trace("Task: variable %ld (%s) = \"%s\"\n", + var1, name, expr); + } + + var_put_string(vars, name, expr); + return; + + case 1: /* Var = ref */ + string = var_get_ref_text(vars); + if (task_trace) { + sc_trace("Task: variable %ld (%s) = ref, \"%s\"\n", + var1, name, string); + } + + var_put_string(vars, name, string); + return; + + case 2: /* Var = expr */ + if (!expr_eval_string_expression(expr, vars, &mutable_string)) { + sc_error("task_run_change_variable_action:" + " invalid string expression, %s\n", expr); + mutable_string = (sc_char *)sc_malloc(strlen("[expr error]") + 1); + strcpy(mutable_string, "[expr error]"); + } + if (task_trace) { + sc_trace("Task: variable %ld (%s) = %s, %s\n", + var1, name, expr, mutable_string); + } + + var_put_string(vars, name, mutable_string); + sc_free(mutable_string); + return; + + default: + sc_fatal("task_run_change_variable_action:" + " unknown string change type, %ld\n", var2); + } + + default: + sc_fatal("task_run_change_variable_action:" + " invalid variable type, %ld\n", type); + } } @@ -778,64 +715,56 @@ task_run_change_variable_action (sc_gameref_t game, * Change game score. */ static void -task_run_change_score_action (sc_gameref_t game, sc_int task, sc_int var1) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - - /* Increasing or decreasing the score? */ - if (var1 > 0) - { - sc_bool increase_score; - - /* See if this task is already scored. */ - increase_score = !gs_task_scored (game, task); - if (!increase_score) - { - sc_vartype_t vt_key[3]; - sc_int version; - - if (task_trace) - sc_trace ("Task: already scored task %ld\n", var1); - - /* Version 3.8 games permit tasks to rescore. */ - vt_key[0].string = "Version"; - version = prop_get_integer (bundle, "I<-s", vt_key); - if (version == TAF_VERSION_380) - { - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "SingleScore"; - increase_score = !prop_get_boolean (bundle, "B<-sis", vt_key); - - if (increase_score) - { - if (task_trace) - sc_trace ("Task: rescoring version 3.8 task anyway\n"); - } - } - } - - /* - * Increase the score if not yet scored or a version 3.8 multiple - * scoring task, and note as a scored task. - */ - if (increase_score) - { - if (task_trace) - sc_trace ("Task: increased score by %ld\n", var1); - - game->score += var1; - gs_set_task_scored (game, task, TRUE); - } - } - else if (var1 < 0) - { - /* Decrease the score. */ - if (task_trace) - sc_trace ("Task: decreased score by %ld\n", -(var1)); - - game->score += var1; - } +task_run_change_score_action(sc_gameref_t game, sc_int task, sc_int var1) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + + /* Increasing or decreasing the score? */ + if (var1 > 0) { + sc_bool increase_score; + + /* See if this task is already scored. */ + increase_score = !gs_task_scored(game, task); + if (!increase_score) { + sc_vartype_t vt_key[3]; + sc_int version; + + if (task_trace) + sc_trace("Task: already scored task %ld\n", var1); + + /* Version 3.8 games permit tasks to rescore. */ + vt_key[0].string = "Version"; + version = prop_get_integer(bundle, "I<-s", vt_key); + if (version == TAF_VERSION_380) { + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "SingleScore"; + increase_score = !prop_get_boolean(bundle, "B<-sis", vt_key); + + if (increase_score) { + if (task_trace) + sc_trace("Task: rescoring version 3.8 task anyway\n"); + } + } + } + + /* + * Increase the score if not yet scored or a version 3.8 multiple + * scoring task, and note as a scored task. + */ + if (increase_score) { + if (task_trace) + sc_trace("Task: increased score by %ld\n", var1); + + game->score += var1; + gs_set_task_scored(game, task, TRUE); + } + } else if (var1 < 0) { + /* Decrease the score. */ + if (task_trace) + sc_trace("Task: decreased score by %ld\n", -(var1)); + + game->score += var1; + } } @@ -845,36 +774,29 @@ task_run_change_score_action (sc_gameref_t game, sc_int task, sc_int var1) * Redirect to another task. */ static sc_bool -task_run_set_task_action (sc_gameref_t game, sc_int var1, sc_int var2) -{ - sc_bool status = FALSE; - - /* Select based on var1. */ - if (var1 == 0) - { - /* Redirect forwards. */ - if (task_can_run_task_directional (game, var2, TRUE)) - { - if (task_trace) - sc_trace ("Task: redirecting to task %ld\n", var2); - - status = task_run_task (game, var2, TRUE); - } - else - { - if (task_trace) - sc_trace ("Task: can't redirect to task %ld\n", var2); - } - } - else - { - /* Undo task. */ - gs_set_task_done (game, var2, FALSE); - if (task_trace) - sc_trace ("Task: reversing task %ld\n", var2); - } - - return status; +task_run_set_task_action(sc_gameref_t game, sc_int var1, sc_int var2) { + sc_bool status = FALSE; + + /* Select based on var1. */ + if (var1 == 0) { + /* Redirect forwards. */ + if (task_can_run_task_directional(game, var2, TRUE)) { + if (task_trace) + sc_trace("Task: redirecting to task %ld\n", var2); + + status = task_run_task(game, var2, TRUE); + } else { + if (task_trace) + sc_trace("Task: can't redirect to task %ld\n", var2); + } + } else { + /* Undo task. */ + gs_set_task_done(game, var2, FALSE); + if (task_trace) + sc_trace("Task: reversing task %ld\n", var2); + } + + return status; } @@ -884,65 +806,60 @@ task_run_set_task_action (sc_gameref_t game, sc_int var1, sc_int var2) * End of game task action. */ static sc_bool -task_run_end_game_action (sc_gameref_t game, sc_int var1) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_bool status = FALSE; - - /* Print a message based on var1. */ - switch (var1) - { - case 0: - { - sc_vartype_t vt_key[2]; - const sc_char *wintext; - - /* Get game WinText. */ - vt_key[0].string = "Header"; - vt_key[1].string = "WinText"; - wintext = prop_get_string (bundle, "S<-ss", vt_key); - - /* Print WinText, if any defined, otherwise a default. */ - if (!sc_strempty (wintext)) - { - pf_buffer_string (filter, wintext); - pf_buffer_character (filter, '\n'); - } - else - pf_buffer_string (filter, "Congratulations!\n"); - - /* Handle any associated WinRes resource. */ - vt_key[0].string = "Globals"; - vt_key[1].string = "WinRes"; - res_handle_resource (game, "ss", vt_key); - - status = TRUE; - break; - } - - case 1: - pf_buffer_string (filter, "Better luck next time.\n"); - status = TRUE; - break; - - case 2: - pf_buffer_string (filter, "I'm afraid you are dead!\n"); - status = TRUE; - break; - - case 3: - break; - - default: - sc_fatal ("task_run_end_game_action: invalid type, %ld\n", var1); - } - - /* Stop the game, and note that it's not resumeable. */ - game->is_running = FALSE; - game->has_completed = TRUE; - - return status; +task_run_end_game_action(sc_gameref_t game, sc_int var1) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_bool status = FALSE; + + /* Print a message based on var1. */ + switch (var1) { + case 0: { + sc_vartype_t vt_key[2]; + const sc_char *wintext; + + /* Get game WinText. */ + vt_key[0].string = "Header"; + vt_key[1].string = "WinText"; + wintext = prop_get_string(bundle, "S<-ss", vt_key); + + /* Print WinText, if any defined, otherwise a default. */ + if (!sc_strempty(wintext)) { + pf_buffer_string(filter, wintext); + pf_buffer_character(filter, '\n'); + } else + pf_buffer_string(filter, "Congratulations!\n"); + + /* Handle any associated WinRes resource. */ + vt_key[0].string = "Globals"; + vt_key[1].string = "WinRes"; + res_handle_resource(game, "ss", vt_key); + + status = TRUE; + break; + } + + case 1: + pf_buffer_string(filter, "Better luck next time.\n"); + status = TRUE; + break; + + case 2: + pf_buffer_string(filter, "I'm afraid you are dead!\n"); + status = TRUE; + break; + + case 3: + break; + + default: + sc_fatal("task_run_end_game_action: invalid type, %ld\n", var1); + } + + /* Stop the game, and note that it's not resumeable. */ + game->is_running = FALSE; + game->has_completed = TRUE; + + return status; } @@ -952,95 +869,93 @@ task_run_end_game_action (sc_gameref_t game, sc_int var1) * Demultiplexer for task actions. */ static sc_bool -task_run_task_action (sc_gameref_t game, sc_int task, sc_int action) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[5]; - sc_int type, var1, var2, var3, var5; - const sc_char *expr; - sc_bool status = FALSE; - - /* Get the task action type. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Actions"; - vt_key[3].integer = action; - vt_key[4].string = "Type"; - type = prop_get_integer (bundle, "I<-sisis", vt_key); - - /* Demultiplex depending on type. */ - switch (type) - { - case 0: /* Move object. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_move_object_action (game, var1, var2, var3); - break; - - case 1: /* Move player/NPC. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_move_npc_action (game, var1, var2, var3); - break; - - case 2: /* Change object status. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_object_status (game, var1, var2); - break; - - case 3: /* Change variable. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var3"; - var3 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Expr"; - expr = prop_get_string (bundle, "S<-sisis", vt_key); - vt_key[4].string = "Var5"; - var5 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_variable_action (game, var1, var2, var3, expr, var5); - break; - - case 4: /* Change score. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - task_run_change_score_action (game, task, var1); - break; - - case 5: /* Execute/unset task. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - vt_key[4].string = "Var2"; - var2 = prop_get_integer (bundle, "I<-sisis", vt_key); - status = task_run_set_task_action (game, var1, var2); - break; - - case 6: /* End game. */ - vt_key[4].string = "Var1"; - var1 = prop_get_integer (bundle, "I<-sisis", vt_key); - status = task_run_end_game_action (game, var1); - break; - - case 7: /* Battle options, ignored for now... */ - break; - - default: - sc_fatal ("task_run_task_action: unknown action type %ld\n", type); - } - - return status; +task_run_task_action(sc_gameref_t game, sc_int task, sc_int action) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[5]; + sc_int type, var1, var2, var3, var5; + const sc_char *expr; + sc_bool status = FALSE; + + /* Get the task action type. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Actions"; + vt_key[3].integer = action; + vt_key[4].string = "Type"; + type = prop_get_integer(bundle, "I<-sisis", vt_key); + + /* Demultiplex depending on type. */ + switch (type) { + case 0: /* Move object. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_move_object_action(game, var1, var2, var3); + break; + + case 1: /* Move player/NPC. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_move_npc_action(game, var1, var2, var3); + break; + + case 2: /* Change object status. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_object_status(game, var1, var2); + break; + + case 3: /* Change variable. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var3"; + var3 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Expr"; + expr = prop_get_string(bundle, "S<-sisis", vt_key); + vt_key[4].string = "Var5"; + var5 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_variable_action(game, var1, var2, var3, expr, var5); + break; + + case 4: /* Change score. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + task_run_change_score_action(game, task, var1); + break; + + case 5: /* Execute/unset task. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + vt_key[4].string = "Var2"; + var2 = prop_get_integer(bundle, "I<-sisis", vt_key); + status = task_run_set_task_action(game, var1, var2); + break; + + case 6: /* End game. */ + vt_key[4].string = "Var1"; + var1 = prop_get_integer(bundle, "I<-sisis", vt_key); + status = task_run_end_game_action(game, var1); + break; + + case 7: /* Battle options, ignored for now... */ + break; + + default: + sc_fatal("task_run_task_action: unknown action type %ld\n", type); + } + + return status; } @@ -1052,68 +967,62 @@ task_run_task_action (sc_gameref_t game, sc_int task, sc_int action) * returned TRUE. */ static sc_bool -task_run_task_actions (sc_gameref_t game, sc_int task) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - sc_int action_count, action; - sc_bool status, muted; - - /* Get the count of task actions. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Actions"; - action_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - if (action_count > 0) - { - if (task_trace) - { - sc_trace ("Task: task %ld running %ld action%s\n", - task, action_count, action_count == 1 ? "" : "s"); - } - } - - /* - * Run all task actions, capturing any TRUE status returned. If any task - * ends the game, run the remaining tasks silently. - * - * This seems a little counterintuitive; a more conventional thing would be - * to just exit the actions loop early. However, Adrift appears to plough - * on, and there may be an action that changes the score in here somewhere, - * so we'll do the same. - */ - status = FALSE; - muted = FALSE; - for (action = 0; action < action_count; action++) - { - sc_bool was_running; - - was_running = game->is_running; - status |= task_run_task_action (game, task, action); - - /* Did this action end the game? */ - if (was_running && !game->is_running) - { - if (task_trace) - { - sc_trace ("Task: task %ld action %ld ended game\n", - task, action); - } - - /* Mute the filter, and note that we did it, but continue. */ - pf_mute (filter); - muted = TRUE; - } - } - - /* If this stack frame muted the filter, un-mute it now. */ - if (muted) - pf_clear_mute (filter); - - /* Return TRUE if any task action returned TRUE. */ - return status; +task_run_task_actions(sc_gameref_t game, sc_int task) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + sc_int action_count, action; + sc_bool status, muted; + + /* Get the count of task actions. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Actions"; + action_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + if (action_count > 0) { + if (task_trace) { + sc_trace("Task: task %ld running %ld action%s\n", + task, action_count, action_count == 1 ? "" : "s"); + } + } + + /* + * Run all task actions, capturing any TRUE status returned. If any task + * ends the game, run the remaining tasks silently. + * + * This seems a little counterintuitive; a more conventional thing would be + * to just exit the actions loop early. However, Adrift appears to plough + * on, and there may be an action that changes the score in here somewhere, + * so we'll do the same. + */ + status = FALSE; + muted = FALSE; + for (action = 0; action < action_count; action++) { + sc_bool was_running; + + was_running = game->is_running; + status |= task_run_task_action(game, task, action); + + /* Did this action end the game? */ + if (was_running && !game->is_running) { + if (task_trace) { + sc_trace("Task: task %ld action %ld ended game\n", + task, action); + } + + /* Mute the filter, and note that we did it, but continue. */ + pf_mute(filter); + muted = TRUE; + } + } + + /* If this stack frame muted the filter, un-mute it now. */ + if (muted) + pf_clear_mute(filter); + + /* Return TRUE if any task action returned TRUE. */ + return status; } @@ -1123,29 +1032,27 @@ task_run_task_actions (sc_gameref_t game, sc_int task) * Start NPC walks based on alerts. */ static void -task_start_npc_walks (sc_gameref_t game, sc_int task) -{ - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[4]; - sc_int alert_count, alert; - - /* Get a count of NPC walk alerts. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "NPCWalkAlert"; - alert_count = prop_get_child_count (bundle, "I<-sis", vt_key); - - /* Check alerts, and start any walks that need starting. */ - for (alert = 0; alert < alert_count; alert += 2) - { - sc_int npc, walk; - - vt_key[3].integer = alert; - npc = prop_get_integer (bundle, "I<-sisi", vt_key); - vt_key[3].integer = alert + 1; - walk = prop_get_integer (bundle, "I<-sisi", vt_key); - npc_start_npc_walk (game, npc, walk); - } +task_start_npc_walks(sc_gameref_t game, sc_int task) { + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[4]; + sc_int alert_count, alert; + + /* Get a count of NPC walk alerts. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "NPCWalkAlert"; + alert_count = prop_get_child_count(bundle, "I<-sis", vt_key); + + /* Check alerts, and start any walks that need starting. */ + for (alert = 0; alert < alert_count; alert += 2) { + sc_int npc, walk; + + vt_key[3].integer = alert; + npc = prop_get_integer(bundle, "I<-sisi", vt_key); + vt_key[3].integer = alert + 1; + walk = prop_get_integer(bundle, "I<-sisi", vt_key); + npc_start_npc_walk(game, npc, walk); + } } @@ -1158,166 +1065,151 @@ task_start_npc_walks (sc_gameref_t game, sc_int task) * done. */ static sc_bool -task_run_task_unrestricted (sc_gameref_t game, sc_int task, sc_bool forwards) -{ - const sc_filterref_t filter = gs_get_filter (game); - const sc_prop_setref_t bundle = gs_get_bundle (game); - sc_vartype_t vt_key[3]; - const sc_char *completetext, *additionalmessage; - sc_int action_count, showroomdesc; - sc_bool status; - - /* Start considering task output tracking. */ - status = FALSE; - - /* - * If reversing, print any reverse message for the task, and undo the task, - * then return. - */ - if (!forwards) - { - const sc_char *reversemessage; - - /* If not yet done, we can hardly reverse it. */ - if (gs_task_done (game, task)) - { - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "ReverseMessage"; - reversemessage = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (reversemessage)) - { - pf_buffer_string (filter, reversemessage); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Undo the task. */ - gs_set_task_done (game, task, FALSE); - } - - /* Return status of undo. */ - return status; - } - - /* See if we are trying to repeat a task that's not repeatable. */ - if (gs_task_done (game, task)) - { - sc_bool repeatable; - - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "Repeatable"; - repeatable = prop_get_boolean (bundle, "B<-sis", vt_key); - if (!repeatable) - { - const sc_char *repeattext; - - vt_key[2].string = "RepeatText"; - repeattext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (repeattext)) - { - if (task_trace) - { - sc_trace ("Task:" - " trying to repeat completed action, aborting\n"); - } - - pf_buffer_string (filter, repeattext); - pf_buffer_character (filter, '\n'); - status |= TRUE; - return status; - } - - /* - * Task done, yet not repeatable, so don't consider this case - * handled. - */ - return status; - } - } - - /* Mark the task as done. */ - gs_set_task_done (game, task, TRUE); - - /* Print any task completion text. */ - vt_key[0].string = "Tasks"; - vt_key[1].integer = task; - vt_key[2].string = "CompleteText"; - completetext = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (completetext)) - { - pf_buffer_string (filter, completetext); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Handle any task completion resource. */ - vt_key[2].string = "Res"; - res_handle_resource (game, "sis", vt_key); - - /* - * Things get slightly tricky here. We need to filter the completion text - * for the task using any final variable values generated or modified by - * task actions, but other task text, run by actions, according to the - * variable value in effect when it runs. - * - * To do this, we take a local copy of the filter's current buffer at this - * point, remove it from the filter, run task actions with checkpointing, - * then prepend it back into the filter after all the actions are done. - * - * As an optimization, we can avoid doing this if there are no task actions. - */ - vt_key[2].string = "Actions"; - action_count = prop_get_child_count (bundle, "I<-sis", vt_key); - if (action_count > 0) - { - sc_char *buffer; - - /* - * Take ownership of the current filter buffer text, then start NPC - * walks based on alerts, and run any and all task actions. Note that - * the buffer transferred out of the filter may be NULL if there is no - * text currently in the filter. - */ - buffer = pf_transfer_buffer (filter); - task_start_npc_walks (game, task); - status |= task_run_task_actions (game, task); - - /* Prepend the saved buffer data back onto the front of the filter. */ - if (buffer) - { - pf_prepend_string (filter, buffer); - sc_free (buffer); - } - } - else - { - /* Start NPC walks only; there are no task actions. */ - task_start_npc_walks (game, task); - } - - /* Append any room description and additional message for the task. */ - vt_key[2].string = "ShowRoomDesc"; - showroomdesc = prop_get_integer (bundle, "I<-sis", vt_key); - if (showroomdesc != 0) - { - lib_print_room_name (game, showroomdesc - 1); - lib_print_room_description (game, showroomdesc - 1); - status |= TRUE; - } - - vt_key[2].string = "AdditionalMessage"; - additionalmessage = prop_get_string (bundle, "S<-sis", vt_key); - if (!sc_strempty (additionalmessage)) - { - pf_buffer_string (filter, additionalmessage); - pf_buffer_character (filter, '\n'); - status |= TRUE; - } - - /* Return status -- TRUE if matched and we output something. */ - return status; +task_run_task_unrestricted(sc_gameref_t game, sc_int task, sc_bool forwards) { + const sc_filterref_t filter = gs_get_filter(game); + const sc_prop_setref_t bundle = gs_get_bundle(game); + sc_vartype_t vt_key[3]; + const sc_char *completetext, *additionalmessage; + sc_int action_count, showroomdesc; + sc_bool status; + + /* Start considering task output tracking. */ + status = FALSE; + + /* + * If reversing, print any reverse message for the task, and undo the task, + * then return. + */ + if (!forwards) { + const sc_char *reversemessage; + + /* If not yet done, we can hardly reverse it. */ + if (gs_task_done(game, task)) { + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "ReverseMessage"; + reversemessage = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(reversemessage)) { + pf_buffer_string(filter, reversemessage); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Undo the task. */ + gs_set_task_done(game, task, FALSE); + } + + /* Return status of undo. */ + return status; + } + + /* See if we are trying to repeat a task that's not repeatable. */ + if (gs_task_done(game, task)) { + sc_bool repeatable; + + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "Repeatable"; + repeatable = prop_get_boolean(bundle, "B<-sis", vt_key); + if (!repeatable) { + const sc_char *repeattext; + + vt_key[2].string = "RepeatText"; + repeattext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(repeattext)) { + if (task_trace) { + sc_trace("Task:" + " trying to repeat completed action, aborting\n"); + } + + pf_buffer_string(filter, repeattext); + pf_buffer_character(filter, '\n'); + status |= TRUE; + return status; + } + + /* + * Task done, yet not repeatable, so don't consider this case + * handled. + */ + return status; + } + } + + /* Mark the task as done. */ + gs_set_task_done(game, task, TRUE); + + /* Print any task completion text. */ + vt_key[0].string = "Tasks"; + vt_key[1].integer = task; + vt_key[2].string = "CompleteText"; + completetext = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(completetext)) { + pf_buffer_string(filter, completetext); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Handle any task completion resource. */ + vt_key[2].string = "Res"; + res_handle_resource(game, "sis", vt_key); + + /* + * Things get slightly tricky here. We need to filter the completion text + * for the task using any final variable values generated or modified by + * task actions, but other task text, run by actions, according to the + * variable value in effect when it runs. + * + * To do this, we take a local copy of the filter's current buffer at this + * point, remove it from the filter, run task actions with checkpointing, + * then prepend it back into the filter after all the actions are done. + * + * As an optimization, we can avoid doing this if there are no task actions. + */ + vt_key[2].string = "Actions"; + action_count = prop_get_child_count(bundle, "I<-sis", vt_key); + if (action_count > 0) { + sc_char *buffer; + + /* + * Take ownership of the current filter buffer text, then start NPC + * walks based on alerts, and run any and all task actions. Note that + * the buffer transferred out of the filter may be NULL if there is no + * text currently in the filter. + */ + buffer = pf_transfer_buffer(filter); + task_start_npc_walks(game, task); + status |= task_run_task_actions(game, task); + + /* Prepend the saved buffer data back onto the front of the filter. */ + if (buffer) { + pf_prepend_string(filter, buffer); + sc_free(buffer); + } + } else { + /* Start NPC walks only; there are no task actions. */ + task_start_npc_walks(game, task); + } + + /* Append any room description and additional message for the task. */ + vt_key[2].string = "ShowRoomDesc"; + showroomdesc = prop_get_integer(bundle, "I<-sis", vt_key); + if (showroomdesc != 0) { + lib_print_room_name(game, showroomdesc - 1); + lib_print_room_description(game, showroomdesc - 1); + status |= TRUE; + } + + vt_key[2].string = "AdditionalMessage"; + additionalmessage = prop_get_string(bundle, "S<-sis", vt_key); + if (!sc_strempty(additionalmessage)) { + pf_buffer_string(filter, additionalmessage); + pf_buffer_character(filter, '\n'); + status |= TRUE; + } + + /* Return status -- TRUE if matched and we output something. */ + return status; } @@ -1330,72 +1222,64 @@ task_run_task_unrestricted (sc_gameref_t game, sc_int task, sc_bool forwards) * the call depth. */ sc_bool -task_run_task (sc_gameref_t game, sc_int task, sc_bool forwards) -{ - static sc_int recursion_depth = 0; - - const sc_filterref_t filter = gs_get_filter (game); - const sc_char *fail_message; - sc_bool restrictions_passed, status; - - if (task_trace) - { - sc_trace ("Task: running task %ld %s, depth %ld\n", - task, forwards ? "forwards" : "backwards", recursion_depth); - } - - /* Check restrictions. */ - if (!restr_eval_task_restrictions (game, task, - &restrictions_passed, &fail_message)) - { - sc_error ("task_run_task: restrictions error, %ld\n", task); - return FALSE; - } - if (!restrictions_passed) - { - if (task_trace) - { - sc_trace ("Task: restrictions failed, task %s\n", - fail_message ? "failed" : "aborted"); - } - - if (fail_message) - { - /* - * Print a message, and return TRUE since we can consider this task - * "done" (more accurately, we've output text, so the task command - * searching in the main run loop can exit...). - */ - pf_buffer_string (filter, fail_message); - pf_buffer_character (filter, '\n'); - return TRUE; - } - - /* Task not done; look for more possibilities. */ - return FALSE; - } - - /* Check for infinite recursion. */ - if (recursion_depth > TASK_MAXIMUM_RECURSION) - { - sc_error ("task_run_task: maximum recursion depth exceeded --" - " game task loop?\n"); - return FALSE; - } - - /* Increment depth, run the task, then decrement depth. */ - recursion_depth++; - status = task_run_task_unrestricted (game, task, forwards); - recursion_depth--; - - if (task_trace) - { - sc_trace ("Task: task %ld finished, return %s, depth %ld\n", - task, status ? "true" : "false", recursion_depth); - } - - /* Return the task's status. */ - return status; +task_run_task(sc_gameref_t game, sc_int task, sc_bool forwards) { + static sc_int recursion_depth = 0; + + const sc_filterref_t filter = gs_get_filter(game); + const sc_char *fail_message; + sc_bool restrictions_passed, status; + + if (task_trace) { + sc_trace("Task: running task %ld %s, depth %ld\n", + task, forwards ? "forwards" : "backwards", recursion_depth); + } + + /* Check restrictions. */ + if (!restr_eval_task_restrictions(game, task, + &restrictions_passed, &fail_message)) { + sc_error("task_run_task: restrictions error, %ld\n", task); + return FALSE; + } + if (!restrictions_passed) { + if (task_trace) { + sc_trace("Task: restrictions failed, task %s\n", + fail_message ? "failed" : "aborted"); + } + + if (fail_message) { + /* + * Print a message, and return TRUE since we can consider this task + * "done" (more accurately, we've output text, so the task command + * searching in the main run loop can exit...). + */ + pf_buffer_string(filter, fail_message); + pf_buffer_character(filter, '\n'); + return TRUE; + } + + /* Task not done; look for more possibilities. */ + return FALSE; + } + + /* Check for infinite recursion. */ + if (recursion_depth > TASK_MAXIMUM_RECURSION) { + sc_error("task_run_task: maximum recursion depth exceeded --" + " game task loop?\n"); + return FALSE; + } + + /* Increment depth, run the task, then decrement depth. */ + recursion_depth++; + status = task_run_task_unrestricted(game, task, forwards); + recursion_depth--; + + if (task_trace) { + sc_trace("Task: task %ld finished, return %s, depth %ld\n", + task, status ? "true" : "false", recursion_depth); + } + + /* Return the task's status. */ + return status; } @@ -1405,9 +1289,8 @@ task_run_task (sc_gameref_t game, sc_int task, sc_bool forwards) * Set task tracing on/off. */ void -task_debug_trace (sc_bool flag) -{ - task_trace = flag; +task_debug_trace(sc_bool flag) { + task_trace = flag; } } // End of namespace Adrift |