예제 #1
0
void increase_level(struct PlayerInfo *player)
{
    struct Dungeon *dungeon;
    struct CreatureControl *cctrl;
    struct Thing *thing;
    unsigned long k;
    int i;
    dungeon = get_dungeon(player->id_number);
    // Increase level of normal creatures
    k = 0;
    i = dungeon->creatr_list_start;
    while (i != 0)
    {
        thing = thing_get(i);
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
          ERRORLOG("Jump to invalid creature detected");
          break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        creature_increase_level(thing);
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            erstat_inc(ESE_InfChainTngPerOwner);
            break;
        }
    }
    // Increase level of special workers
    k = 0;
    i = dungeon->digger_list_start;
    while (i != 0)
    {
        thing = thing_get(i);
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
          ERRORLOG("Jump to invalid creature detected");
          break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        creature_increase_level(thing);
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
          ERRORLOG("Infinite loop detected when sweeping creatures list");
          erstat_inc(ESE_InfChainTngPerOwner);
          break;
        }
    }
}
예제 #2
0
TbBool setup_person_move_close_to_position(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags)
{
    struct CreatureControl *cctrl;
    struct Coord3d trgpos;
    struct Coord3d navpos;
    SYNCDBG(18,"Moving %s index %d to (%d,%d)",thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y);
    trgpos.x.val = subtile_coord_center(stl_x);
    trgpos.y.val = subtile_coord_center(stl_y);
    trgpos.z.val = thing->mappos.z.val;
    cctrl = creature_control_get_from_thing(thing);
    if (creature_control_invalid(cctrl))
    {
        WARNLOG("Tried to move invalid creature to (%d,%d)",(int)stl_x,(int)stl_y);
        return false;
    }
    get_nearest_navigable_point_for_thing(thing, &trgpos, &navpos, flags);
    if (!creature_can_navigate_to_with_storage(thing, &navpos, flags))
    {
        SYNCDBG(19,"The %s cannot reach subtile (%d,%d)",thing_model_name(thing),(int)stl_x,(int)stl_y);
        return false;
    }
    cctrl->move_flags = flags;
    internal_set_thing_state(thing, CrSt_MoveToPosition);
    cctrl->moveto_pos.x.val = navpos.x.val;
    cctrl->moveto_pos.y.val = navpos.y.val;
    cctrl->moveto_pos.z.val = navpos.z.val;
    return true;
}
예제 #3
0
TbBool setup_person_move_to_position_f(struct Thing *thing, MapSubtlCoord stl_x, MapSubtlCoord stl_y, NaviRouteFlags flags, const char *func_name)
{
    struct CreatureControl *cctrl;
    struct Coord3d locpos;
    SYNCDBG(18,"%s: Moving %s index %d to (%d,%d)",func_name,thing_model_name(thing),(int)thing->index,(int)stl_x,(int)stl_y);
    TRACE_THING(thing);
    locpos.x.val = subtile_coord_center(stl_x);
    locpos.y.val = subtile_coord_center(stl_y);
    locpos.z.val = thing->mappos.z.val;
    locpos.z.val = get_thing_height_at(thing, &locpos);
    cctrl = creature_control_get_from_thing(thing);
    if (creature_control_invalid(cctrl))
    {
        WARNLOG("%s: Tried to move invalid creature to (%d,%d)",func_name,(int)stl_x,(int)stl_y);
        return false;
    }
    if (thing_in_wall_at(thing, &locpos))
    {
        SYNCDBG(16,"%s: The %s would be trapped in wall at (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y);
        return false;
    }
    if (!creature_can_navigate_to_with_storage_f(thing, &locpos, flags, func_name))
    {
        SYNCDBG(19,"%s: The %s cannot reach subtile (%d,%d)",func_name,thing_model_name(thing),(int)stl_x,(int)stl_y);
        return false;
    }
    cctrl->move_flags = flags;
    internal_set_thing_state(thing, CrSt_MoveToPosition);
    cctrl->moveto_pos.x.val = locpos.x.val;
    cctrl->moveto_pos.y.val = locpos.y.val;
    cctrl->moveto_pos.z.val = locpos.z.val;
    SYNCDBG(19,"%s: Done",func_name);
    return true;
}
예제 #4
0
TbBool creature_control_exists(const struct CreatureControl *cctrl)
{
  if (creature_control_invalid(cctrl))
      return false;
  if ((cctrl->flgfield_1 & CCFlg_Exists) == 0)
      return false;
  return true;
}
예제 #5
0
TbBool creature_instance_is_available(const struct Thing *thing, CrInstance inst_id)
{
    struct CreatureControl *cctrl;
    TRACE_THING(thing);
    cctrl = creature_control_get_from_thing(thing);
    if (creature_control_invalid(cctrl))
        return false;
    return cctrl->instance_available[inst_id];
}
예제 #6
0
void delete_all_control_structures(void)
{
    long i;
    struct CreatureControl *cctrl;
    for (i=1; i < CREATURES_COUNT; i++)
    {
      cctrl = creature_control_get(i);
      if (!creature_control_invalid(cctrl))
      {
        if ((cctrl->flgfield_1 & CCFlg_Exists) != 0)
          delete_control_structure(cctrl);
      }
    }
}
예제 #7
0
TbBool set_creature_assigned_job(struct Thing *thing, CreatureJob new_job)
{
    struct CreatureControl *cctrl;
    TRACE_THING(thing);
    cctrl = creature_control_get_from_thing(thing);
    if (creature_control_invalid(cctrl))
    {
        ERRORLOG("The %s index %d has invalid control",thing_model_name(thing),(int)thing->index);
        return false;
    }
    cctrl->job_assigned = new_job;
    SYNCLOG("Assigned job %s for %s index %d owner %d",creature_job_code_name(new_job),thing_model_name(thing),(int)thing->index,(int)thing->owner);
    return true;
}
예제 #8
0
long i_can_allocate_free_control_structure(void)
{
  struct CreatureControl *cctrl;
  long i;
  for (i=1; i < CREATURES_COUNT; i++)
  {
    cctrl = game.persons.cctrl_lookup[i];
    if (!creature_control_invalid(cctrl))
    {
        if ((cctrl->flgfield_1 & CCFlg_Exists) == 0)
            return i;
    }
  }
  return 0;
}
예제 #9
0
TbBool action_point_is_creature_from_list_within(const struct ActionPoint *apt, long first_thing_idx)
{
    unsigned long k;
    int i;
    SYNCDBG(8,"Starting");
    k = 0;
    i = first_thing_idx;
    while (i != 0)
    {
        struct Thing *thing;
        thing = thing_get(i);
        TRACE_THING(thing);
        struct CreatureControl *cctrl;
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        // Range of 0 means activate when on the same subtile
        if (apt->range <= 0)
        {
            if ((apt->mappos.x.stl.num == thing->mappos.x.stl.num)
             && (apt->mappos.y.stl.num == thing->mappos.y.stl.num)) {
                return true;
            }
        } else
        {
            long dist;
            dist = get_distance_xy(thing->mappos.x.val, thing->mappos.y.val, apt->mappos.x.val, apt->mappos.y.val);
            if (apt->range > dist) {
                return true;
            }
        }
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            break;
        }
    }
    return false;
}
예제 #10
0
struct Thing *computer_check_creatures_in_room_for_accelerate(struct Computer2 *comp, struct Room *room)
{
    struct Dungeon *dungeon;
    struct StateInfo *stati;
    struct CreatureControl *cctrl;
    struct Thing *thing;
    unsigned long k;
    long i,n;
    dungeon = comp->dungeon;
    i = room->creatures_list;
    k = 0;
    while (i != 0)
    {
      thing = thing_get(i);
      cctrl = creature_control_get_from_thing(thing);
      if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
      {
        ERRORLOG("Jump to invalid creature %ld detected",i);
        break;
      }
      i = cctrl->next_in_room;
      // Per creature code
      if (!thing_affected_by_spell(thing, SplK_Speed))
      {
          n = get_creature_state_besides_move(thing);
          stati = get_thing_state_info_num(n);
          if (stati->state_type == 1)
          {
              if (try_game_action(comp, dungeon->owner, GA_UsePwrSpeedUp, SPELL_MAX_LEVEL, 0, 0, thing->index, 0) > Lb_OK)
              {
                  return thing;
              }
          }
      }
      // Per creature code ends
      k++;
      if (k > THINGS_COUNT)
      {
        ERRORLOG("Infinite loop detected when sweeping things list");
        break;
      }
    }
    return INVALID_THING;
}
예제 #11
0
void delete_thing_structure_f(struct Thing *thing, long a2, const char *func_name)
{
    TRACE_THING(thing);
    if ((thing->alloc_flags & TAlF_InDungeonList) != 0) {
        remove_first_creature(thing);
    }
    if (!a2)
    {
        if (thing->light_id != 0) {
            light_delete_light(thing->light_id);
            thing->light_id = 0;
        }
    }
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    if (!creature_control_invalid(cctrl))
    {
        if ( !a2 )
        {
            remove_creature_lair(thing);
            if (creature_is_group_member(thing)) {
                remove_creature_from_group(thing);
            }
        }
        delete_control_structure(cctrl);
    }
    if (thing->snd_emitter_id != 0) {
        S3DDestroySoundEmitterAndSamples(thing->snd_emitter_id);
        thing->snd_emitter_id = 0;
    }
    remove_thing_from_its_class_list(thing);
    remove_thing_from_mapwho(thing);
    if (thing->index > 0) {
        game.free_things_start_index--;
        game.free_things[game.free_things_start_index] = thing->index;
    } else {
#if (BFDEBUG_LEVEL > 0)
        ERRORMSG("%s: Performed deleting of thing with bad index %d!",func_name,(int)thing->index);
#endif
    }
    LbMemorySet(thing, 0, sizeof(struct Thing));
}
예제 #12
0
struct CreatureControl *allocate_free_control_structure(void)
{
    struct CreatureControl *cctrl;
    long i;
    for (i=1; i < CREATURES_COUNT; i++)
    {
      cctrl = game.persons.cctrl_lookup[i];
      if (!creature_control_invalid(cctrl))
      {
          if ((cctrl->flgfield_1 & CCFlg_Exists) == 0)
          {
              LbMemorySet(cctrl, 0, sizeof(struct CreatureControl));
              cctrl->flgfield_1 |= CCFlg_Exists;
              cctrl->index = i;
              return cctrl;
          }
      }
    }
    return NULL;
}
예제 #13
0
long get_wanderer_possible_targets_count_in_list(long first_thing_idx, struct Thing *wanderer)
{
    struct CreatureControl *cctrl;
    struct Thing *thing;
    long victims_count;
    unsigned long k;
    long i;
    victims_count = 0;
    // Get the amount of possible targets
    k = 0;
    i = first_thing_idx;
    while (i != 0)
    {
        thing = thing_get(i);
        TRACE_THING(thing);
        cctrl = creature_control_get_from_thing(thing);
        if (creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        if (!thing_is_picked_up(thing) && !creature_is_kept_in_custody_by_enemy(thing))
        {
            // Don't check for being navigable - it's too CPU-expensive to check all creatures
            //if ( creature_can_navigate_to(wanderer, &thing->mappos, NavTF_Default) )
            {
                victims_count++;
            }
        }
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            break;
        }
    }
    return victims_count;
}
예제 #14
0
void multiply_creatures_in_dungeon_list(struct Dungeon *dungeon, long list_start)
{
    struct Thing *thing;
    struct Thing *tncopy;
    struct CreatureControl *cctrl;
    unsigned long k;
    int i;
    k = 0;
    i = list_start;
    while (i != 0)
    {
        thing = thing_get(i);
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        tncopy = create_creature(&thing->mappos, thing->model, dungeon->owner);
        if (thing_is_invalid(tncopy))
        {
            WARNLOG("Can't create a copy of creature");
            break;
        }
        set_creature_level(tncopy, cctrl->explevel);
        tncopy->health = thing->health;
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            erstat_inc(ESE_InfChainTngPerOwner);
            break;
        }
    }
}
예제 #15
0
struct Thing * find_imp_for_pickup(struct Computer2 *comp, MapSubtlCoord stl_x, MapSubtlCoord stl_y)
{
    struct Dungeon *dungeon;
    int pick1_dist;
    struct Thing *pick1_tng;
    int pick2_dist;
    struct Thing *pick2_tng;
    //return _DK_find_imp_for_pickup(comp, stl_x, stl_y);
    dungeon = comp->dungeon;
    pick1_dist = INT_MAX;
    pick2_dist = INT_MAX;
    pick2_tng = INVALID_THING;
    pick1_tng = INVALID_THING;
    long i;
    unsigned long k;
    k = 0;
    i = dungeon->digger_list_start;
    while (i != 0)
    {
        struct Thing *thing;
        struct CreatureControl *cctrl;
        thing = thing_get(i);
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
          ERRORLOG("Jump to invalid creature detected");
          break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        if (cctrl->combat_flags == 0)
        {
            if (!creature_is_being_unconscious(thing) && !creature_affected_by_spell(thing, SplK_Chicken))
            {
                if (!creature_is_being_dropped(thing) && can_thing_be_picked_up_by_player(thing, dungeon->owner))
                {
                    MapSubtlDelta dist;
                    long state_type;
                    dist = abs(stl_x - (MapSubtlDelta)thing->mappos.x.stl.num) + abs(stl_y - (MapSubtlDelta)thing->mappos.y.stl.num);
                    state_type = get_creature_state_type(thing);
                    if (state_type == CrStTyp_Work)
                    {
                        if (dist < pick1_dist)
                        {
                            pick1_dist = dist;
                            pick1_tng = thing;
                        }
                    }
                    else
                    {
                        if (dist < pick2_dist)
                        {
                            pick2_dist = dist;
                            pick2_tng = thing;
                        }
                    }
                }
            }
        }
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
          ERRORLOG("Infinite loop detected when sweeping creatures list");
          break;
        }
    }
    if (!thing_is_invalid(pick2_tng)) {
        return pick2_tng;
    } else {
        return pick1_tng;
    }
}
예제 #16
0
short creature_being_scavenged(struct Thing *creatng)
{
    //return _DK_creature_being_scavenged(creatng);
    struct Thing *fellowtng;
    struct Dungeon *dungeon;
    SYNCDBG(8,"Starting");
    //return _DK_make_all_players_creatures_angry(plyr_idx);
    dungeon = get_players_num_dungeon(creatng->owner);
    fellowtng = INVALID_THING;
    if (dungeon->num_active_creatrs <= 1)
    {
        SYNCDBG(19,"No other creatures");
        return 0;
    }
    int n;
    n = ACTION_RANDOM(dungeon->num_active_creatrs-1);
    unsigned long k;
    int i;
    k = 0;
    i = dungeon->creatr_list_start;
    while (i != 0)
    {
        struct Thing *thing;
        thing = thing_get(i);
        TRACE_THING(thing);
        struct CreatureControl *cctrl;
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        if ((n <= 0) && (thing->index != creatng->index)) {
            fellowtng = thing;
            break;
        }
        n--;
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            break;
        }
    }
    if (thing_is_invalid(fellowtng))
    {
        SYNCDBG(19,"Cannot get creature");
        return 0;
    }
    if (setup_person_move_to_coord(creatng, &fellowtng->mappos, NavRtF_Default) <= 0)
    {
        SYNCDBG(19,"Cannot move to coord");
        return 0;
    }
    creatng->continue_state = CrSt_CreatureBeingScavenged;
    if (!S3DEmitterIsPlayingSample(creatng->snd_emitter_id, 156, 0))
        thing_play_sample(creatng, 156, NORMAL_PITCH, 0, 3, 1, 2, FULL_LOUDNESS);
    SYNCDBG(19,"Finished");
    return 1;
}
예제 #17
0
TbBool wander_to_specific_possible_target_in_list(long first_thing_idx, struct Thing *wanderer, long specific_target)
{
    struct CreatureControl *cctrl;
    struct Thing *thing;
    long target_match;
    long matched_thing_idx;
    unsigned long k;
    long i;
    target_match = specific_target;
    // Find the target
    k = 0;
    i = first_thing_idx;
    matched_thing_idx = i;
    while (i != 0)
    {
        thing = thing_get(i);
        TRACE_THING(thing);
        cctrl = creature_control_get_from_thing(thing);
        if (creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        if (!thing_is_picked_up(thing) && !creature_is_kept_in_custody_by_enemy(thing))
        {
            // If it's not the one we want, continue sweeping
            if (target_match > 0)
            {
                target_match--;
                // Store the last unmatched thing, so we know where to stop when wrapped
                matched_thing_idx = thing->index;
            } else
            // If it is the one, try moving to it
            if (setup_person_move_to_coord(wanderer, &thing->mappos, NavRtF_Default))
            {
                SYNCDBG(8,"The %s wanders towards %s",thing_model_name(wanderer),thing_model_name(thing));
                return true;
            }
            // If we've got the right creature, but moving failed for some reason, try next one.
        }
        // Wrap to first thing if reached end of list.
        if (i == 0) {
            i = first_thing_idx;
            if (target_match != 0)
                WARNLOG("Wrapping to start of the list shouldn't occur before target_match reaches 0!");
        }
        // When wrapped, process things only to the start index
        if (i == matched_thing_idx)
            break;
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            break;
        }
    }
    return false;
}
예제 #18
0
short good_doing_nothing(struct Thing *creatng)
{
    struct CreatureControl *cctrl;
    struct PlayerInfo *player;
    long nturns;
    PlayerNumber target_plyr_idx;
    //return _DK_good_doing_nothing(creatng);
    SYNCDBG(18,"Starting");
    TRACE_THING(creatng);
    // Debug code to find incorrect states
    if (!is_hero_thing(creatng))
    {
        ERRORLOG("Non hero %s index %d owned by player %d - reset",
            thing_model_name(creatng),(int)creatng->index,(int)creatng->owner);
        set_start_state(creatng);
        return 0;
    }
    cctrl = creature_control_get_from_thing(creatng);
    if (creature_control_invalid(cctrl))
    {
        ERRORLOG("Invalid creature control; no action");
        return 0;
    }
    // Respect the idle time - just wander around some time
    nturns = game.play_gameturn - cctrl->idle.start_gameturn;
    if (nturns <= 1) {
        return 1;
    }
    // Do some wandering also if can't find any task to do
    if (cctrl->field_5 > (long)game.play_gameturn)
    {
        if (creature_choose_random_destination_on_valid_adjacent_slab(creatng)) {
            creatng->continue_state = CrSt_GoodDoingNothing;
        }
        return 1;
    }
    // Done wandering - find a target player
    target_plyr_idx = cctrl->party.target_plyr_idx;
    if (target_plyr_idx != -1)
    {
        player = get_player(target_plyr_idx);
        if (player_invalid(player))
        {
            ERRORLOG("Invalid target player in %s index %d owned by player %d - reset",
                thing_model_name(creatng),(int)creatng->index,(int)creatng->owner);
            cctrl->party.target_plyr_idx = -1;
            return 0;
        }
        if (player->victory_state != VicS_LostLevel)
        {
            nturns = game.play_gameturn - cctrl->long_91;
            if (nturns > 400)
            {
                // Go to the previously chosen dungeon
                if (!creature_can_get_to_dungeon(creatng,target_plyr_idx))
                {
                    // Cannot get to the originally selected dungeon - reset it
                    cctrl->party.target_plyr_idx = -1;
                }
            } else
            if (nturns >= 0)
            {
                // Waiting - move around a bit
                if (creature_choose_random_destination_on_valid_adjacent_slab(creatng))
                {
                    creatng->continue_state = CrSt_GoodDoingNothing;
                    return 0;
                }
            } else
            {
                // Value lower than 0 would mean it is invalid
                WARNLOG("Invalid wait time detected for %s, value %ld",thing_model_name(creatng),(long)cctrl->long_91);
                cctrl->long_91 = 0;
            }
        } else
        {
            // The player we've chosen has lost - we'll have to find other target
            cctrl->party.target_plyr_idx = -1;
        }
    }
    target_plyr_idx = cctrl->party.target_plyr_idx;
    if (target_plyr_idx == -1)
    {
        nturns = game.play_gameturn - cctrl->long_91;
        if (nturns > 400)
        {
            cctrl->long_91 = game.play_gameturn;
            cctrl->byte_8C = 1;
        }
        nturns = game.play_gameturn - cctrl->long_8D;
        if (nturns > 64)
        {
            cctrl->long_8D = game.play_gameturn;
            cctrl->party.target_plyr_idx = good_find_enemy_dungeon(creatng);
        }
        target_plyr_idx = cctrl->party.target_plyr_idx;
        if (target_plyr_idx == -1)
        {
            SYNCDBG(4,"No enemy dungeon to perform %s index %d task",
                thing_model_name(creatng),(int)creatng->index);
            if (creature_choose_random_destination_on_valid_adjacent_slab(creatng))
            {
                creatng->continue_state = CrSt_GoodDoingNothing;
                return 1;
            }
            cctrl->field_5 = game.play_gameturn + 16;
        }
        return 1;
    }
    if (good_creature_setup_task_in_dungeon(creatng, target_plyr_idx)) {
        return 1;
    }
    // If there are problems with the task, do a break before re-trying
    cctrl->field_5 = game.play_gameturn + 200;
    return 0;
}
예제 #19
0
TbBool steal_hero(struct PlayerInfo *player, struct Coord3d *pos)
{
    //TODO CONFIG creature models dependency; put them in config files
    static ThingModel skip_steal_models[] = {6, 7};
    static ThingModel prefer_steal_models[] = {3, 12};
    struct Thing *herotng;
    herotng = INVALID_THING;
    int heronum;
    struct Dungeon *herodngn;
    struct CreatureControl *cctrl;
    unsigned long k;
    int i;
    SYNCDBG(8,"Starting");
    herodngn = get_players_num_dungeon(game.hero_player_num);
    k = 0;
    if (herodngn->num_active_creatrs > 0) {
        heronum = ACTION_RANDOM(herodngn->num_active_creatrs);
        i = herodngn->creatr_list_start;
        SYNCDBG(4,"Selecting random creature %d out of %d heroes",(int)heronum,(int)herodngn->num_active_creatrs);
    } else {
        heronum = 0;
        i = 0;
        SYNCDBG(4,"No heroes on map, skipping selection");
    }
    while (i != 0)
    {
        struct Thing *thing;
        thing = thing_get(i);
        TRACE_THING(thing);
        cctrl = creature_control_get_from_thing(thing);
        if (thing_is_invalid(thing) || creature_control_invalid(cctrl))
        {
            ERRORLOG("Jump to invalid creature detected");
            break;
        }
        i = cctrl->players_next_creature_idx;
        // Thing list loop body
        TbBool heroallow;
        heroallow = true;
        ThingModel skipidx;
        for (skipidx=0; skipidx < sizeof(skip_steal_models)/sizeof(skip_steal_models[0]); skipidx++)
        {
            if (thing->model == skip_steal_models[skipidx]) {
                heroallow = false;
            }
        }
        if (heroallow) {
            herotng = thing;
        }
        // If we've reached requested hero number, return either current hero on previously selected one
        if ((heronum <= 0) && thing_is_creature(herotng)) {
            break;
        }
        heronum--;
        if (i == 0) {
            i = herodngn->creatr_list_start;
        }
        // Thing list loop body ends
        k++;
        if (k > CREATURES_COUNT)
        {
            ERRORLOG("Infinite loop detected when sweeping creatures list");
            erstat_inc(ESE_InfChainTngPerOwner);
            break;
        }
    }
    if (!thing_is_invalid(herotng))
    {
        move_thing_in_map(herotng, pos);
        change_creature_owner(herotng, player->id_number);
        SYNCDBG(3,"Converted %s to owner %d",thing_model_name(herotng),(int)player->id_number);
    }
    else
    {
        i = ACTION_RANDOM(sizeof(prefer_steal_models)/sizeof(prefer_steal_models[0]));
        struct Thing *creatng;
        creatng = create_creature(pos, prefer_steal_models[i], player->id_number);
        if (thing_is_invalid(creatng))
            return false;
        SYNCDBG(3,"Created %s owner %d",thing_model_name(creatng),(int)player->id_number);
    }
    return true;
}