short creature_drop_body_in_prison(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    struct Thing *dragtng;
    dragtng = thing_get(cctrl->dragtng_idx);
    if (!thing_exists(dragtng) || !creature_is_being_unconscious(dragtng)) {
        set_start_state(thing);
        return 0;
    }
    if (!subtile_is_room(thing->mappos.x.stl.num, thing->mappos.y.stl.num)) {
        set_start_state(thing);
        return 0;
    }
    struct Room *room;
    room = get_room_thing_is_on(thing);
    if ((room->owner != thing->owner) || (room->kind != RoK_PRISON)) {
        set_start_state(thing);
        return 0;
    }
    make_creature_conscious(dragtng);
    initialise_thing_state(dragtng, CrSt_CreatureArrivedAtPrison);
    struct CreatureControl *dragctrl;
    dragctrl = creature_control_get_from_thing(dragtng);
    dragctrl->flgfield_1 |= CCFlg_NoCompControl;
    set_start_state(thing);
    return 1;

}
short at_guard_post_room(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Room *room;
    cctrl = creature_control_get_from_thing(thing);
    cctrl->target_room_id = 0;
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, get_room_for_job(Job_GUARD), thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(thing),(int)thing->index);
        set_start_state(thing);
        return 0;
    }
    if (!add_creature_to_work_room(thing, room, Job_GUARD))
    {
        set_start_state(thing);
        return 0;
    }
    internal_set_thing_state(thing, get_continue_state_for_job(Job_GUARD));
    if (!person_get_somewhere_adjacent_in_room(thing, room, &cctrl->moveto_pos))
    {
        cctrl->moveto_pos.x.val = thing->mappos.x.val;
        cctrl->moveto_pos.y.val = thing->mappos.y.val;
        cctrl->moveto_pos.z.val = thing->mappos.z.val;
    }
    return 1;
}
/**
 * Does a step of being imprisoned.
 * Informs if the imprisoning cycle should end.
 * @param thing
 */
CrCheckRet process_prison_function(struct Thing *creatng)
{
  struct Room *room;
  room = get_room_creature_works_in(creatng);
  if (!room_still_valid_as_type_for_thing(room, RoK_PRISON, creatng))
  {
      WARNLOG("Room %s owned by player %d is bad work place for %s index %d owner %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner);
      set_start_state(creatng);
      return CrCkRet_Continue;
  }
  process_creature_hunger(creatng);
  if ( process_prisoner_skelification(creatng,room) )
    return CrCkRet_Deleted;
  struct CreatureControl *cctrl;
  cctrl = creature_control_get_from_thing(creatng);
  if ((cctrl->instance_id == CrInst_NULL) && process_prison_food(creatng, room) )
    return CrCkRet_Continue;
  // Breaking from jail is only possible once per some amount of turns
  if ((game.play_gameturn % gameadd.time_between_prison_break) == 0)
  {
      if (jailbreak_possible(room, creatng->owner))
      {
          if (is_my_player_number(room->owner))
              output_message(SMsg_PrisonersEscaping, 40, true);
          else if (is_my_player_number(room->owner))
              output_message(SMsg_CreatrFreedPrison, 40, true);
          set_start_state(creatng);
          return CrCkRet_Continue;
      }
  }
  return CrCkRet_Available;
}
short creature_hero_entering(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    TRACE_THING(thing);
    //return _DK_creature_hero_entering(thing);
    cctrl = creature_control_get_from_thing(thing);
    if (cctrl->field_282 > 0)
    {
        cctrl->field_282--;
        return CrStRet_Unchanged;
    }
    if (cctrl->field_282 == 0)
    {
        thing->mappos.z.val = get_ceiling_height(&thing->mappos) - (long)thing->field_58 - 1;
        cctrl->field_282--;
        return CrStRet_Modified;
    }
    if ( thing_touching_floor(thing) || (((thing->movement_flags & TMvF_Flying) != 0) && thing_touching_flight_altitude(thing)))
    {
        set_start_state(thing);
        return CrStRet_ResetOk;
    }
    if (cctrl->field_282 < -500)
    {
        set_start_state(thing);
        return CrStRet_ResetFail;
    }
    cctrl->field_282--;
    return CrStRet_Modified;
}
CrStateRet creature_at_changed_lair(struct Thing *creatng)
{
    struct Room *room;
    TRACE_THING(creatng);
    //return _DK_creature_at_changed_lair(thing);
    if (!thing_is_on_own_room_tile(creatng))
    {
        set_start_state(creatng);
        return CrStRet_ResetFail;
    }
    room = get_room_thing_is_on(creatng);
    if (!room_initially_valid_as_type_for_thing(room, RoK_LAIR, creatng))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng));
        set_start_state(creatng);
        return CrStRet_ResetFail;
    }
    if (!creature_add_lair_to_room(creatng, room)) {
        internal_set_thing_state(creatng, CrSt_CreatureChooseRoomForLairSite);
        return CrStRet_Modified;
    }
    // All done - finish the state
    set_start_state(creatng);
    return CrStRet_ResetOk;
}
CrCheckRet process_scavenge_function(struct Thing *calltng)
{
    SYNCDBG(18,"Starting for %s owner %d",thing_model_name(calltng),(int)calltng->owner);
    //return _DK_process_scavenge_function(thing);
    struct CreatureControl *callctrl;
    callctrl = creature_control_get_from_thing(calltng);
    struct Dungeon *calldngn;
    struct Room *room;
    calldngn = get_dungeon(calltng->owner);
    room = get_room_creature_works_in(calltng);
    if ( !room_still_valid_as_type_for_thing(room, RoK_SCAVENGER, calltng) )
    {
        WARNLOG("Room %s owned by player %d is bad work place for %s owned by played %d",room_code_name(room->kind),(int)room->owner,thing_model_name(calltng),(int)calltng->owner);
        set_start_state(calltng);
        return CrCkRet_Continue;
    }
    struct CreatureStats *crstat;
    crstat = creature_stats_get_from_thing(calltng);
    if (!player_can_afford_to_scavenge_creature(calltng))
    {
        if (is_my_player_number(calltng->owner))
            output_message(SMsg_NoGoldToScavenge, 500, 1);
        set_start_state(calltng);
        return CrCkRet_Continue;
    }
    if (calldngn->scavenge_counters_turn != game.play_gameturn)
    {
        reset_scavenge_counts(calldngn);
    }
    long work_value;
    work_value = compute_creature_work_value(crstat->scavenge_value*256, room->efficiency, callctrl->explevel);
    work_value = process_work_speed_on_work_value(calltng, work_value);
    SYNCDBG(9,"The %s index %d owner %d produced %d scavenge points",thing_model_name(calltng),(int)calltng->index,(int)calltng->owner,(int)work_value);
    struct Thing *scavtng;
    scavtng = get_scavenger_target(calltng);
    if (!thing_is_invalid(scavtng))
    {
        process_scavenge_creature_from_level(scavtng, calltng, work_value);
    } else
    if (can_scavenge_creature_from_pool(calldngn, calltng->model))
    {
        process_scavenge_creature_from_pool(calltng, work_value);
    } else
    {
        if (crstat->entrance_force) {
          calldngn->field_1485++;
        }
        return 0;
    }
    callctrl->field_82++;
    if (callctrl->field_82 > game.scavenge_cost_frequency)
    {
        callctrl->field_82 -= game.scavenge_cost_frequency;
        if (take_money_from_dungeon(calltng->owner, crstat->scavenger_cost, 1) < 0) {
            ERRORLOG("Cannot take %d gold from dungeon %d",(int)crstat->scavenger_cost,(int)calltng->owner);
        }
        create_price_effect(&calltng->mappos, calltng->owner, crstat->scavenger_cost);
    }
    return 0;
}
short at_scavenger_room(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct CreatureStats *crstat;
    struct Dungeon *dungeon;
    struct Room *room;
    //return _DK_at_scavenger_room(thing);
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, RoK_SCAVENGER, thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(thing),(int)thing->index);
        set_start_state(thing);
        return 0;
    }
    cctrl = creature_control_get_from_thing(thing);
    crstat = creature_stats_get_from_thing(thing);
    dungeon = get_dungeon(thing->owner);
    if (crstat->scavenger_cost >= dungeon->total_money_owned)
    {
        if (is_my_player_number(thing->owner))
            output_message(SMsg_NoGoldToScavenge, MESSAGE_DELAY_TREASURY, true);
        set_start_state(thing);
        return 0;
    }
    if (!add_creature_to_work_room(thing, room))
    {
        set_start_state(thing);
        return 0;
    }
    internal_set_thing_state(thing, CrSt_Scavengering);
    cctrl->field_82 = 0;
    return 1;
}
CrStateRet creature_in_prison(struct Thing *thing)
{
    struct Room *room;
    TRACE_THING(thing);
    room = get_room_thing_is_on(thing);
    if (creature_work_in_room_no_longer_possible(room, RoK_PRISON, thing))
    {
        remove_creature_from_work_room(thing);
        set_start_state(thing);
        return CrStRet_ResetFail;
    }
    if (room->used_capacity > room->total_capacity)
    {
        output_message_room_related_from_computer_or_player_action(room->owner, room->kind, OMsg_RoomTooSmall);
        set_start_state(thing);
        return CrStRet_ResetOk;
    }
    switch (process_prison_function(thing))
    {
    case CrCkRet_Deleted:
        return CrStRet_Deleted;
    case CrCkRet_Available:
        process_prison_visuals(thing, room);
        return CrStRet_Modified;
    default:
        return CrStRet_ResetOk;
    }
}
Exemple #9
0
short at_workshop_room(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Room *room;
    //return _DK_at_workshop_room(thing);
    cctrl = creature_control_get_from_thing(thing);
    cctrl->target_room_id = 0;
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, RoK_WORKSHOP, thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(thing));
        set_start_state(thing);
        return 0;
    }
    if (room->total_capacity <= room->used_capacity)
    {
        set_start_state(thing);
        return 0;
    }
    if ( !add_creature_to_work_room(thing, room) )
    {
        set_start_state(thing);
        return 0;
    }
    internal_set_thing_state(thing, CrSt_Manufacturing);
    setup_move_to_new_workshop_position(thing, room, 1);
    return 1;
}
short creature_sleep(struct Thing *thing)
{
    //return _DK_creature_sleep(thing);
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    if ((cctrl->slap_turns > 0) || !creature_will_sleep(thing)) {
        set_start_state(thing);
        return 0;
    }
    struct Room *room;
    room = get_room_thing_is_on(thing);
    if (room_is_invalid(room) || (room->kind != RoK_LAIR)
        || (cctrl->lair_room_id != room->index) || (room->owner != thing->owner)) {
        set_start_state(thing);
        return 0;
    }
    thing->movement_flags &= ~0x0020;
    struct CreatureStats *crstat;
    crstat = creature_stats_get_from_thing(thing);
    if (((game.play_gameturn + thing->index) % game.recovery_frequency) == 0)
    {
        HitPoints recover;
        recover = compute_creature_max_health(crstat->sleep_recovery, cctrl->explevel);
        apply_health_to_thing_and_display_health(thing, recover);
    }
    anger_set_creature_anger(thing, 0, AngR_NoLair);
    anger_apply_anger_to_creature(thing, crstat->annoy_sleeping, AngR_Other, 1);
    if (cctrl->field_82 > 0) {
        cctrl->field_82--;
    }
    if (((game.play_gameturn + thing->index) & 0x3F) == 0)
    {
        if (ACTION_RANDOM(100) < 5) {
            struct Dungeon *dungeon;
            dungeon = get_dungeon(thing->owner);
            dungeon->lvstats.backs_stabbed++;
        }
    }
    if (crstat->sleep_exp_slab != SlbT_ROCK)
    {
        if (creature_can_gain_experience(thing) && room_has_slab_adjacent(room, crstat->sleep_exp_slab))
        {
            cctrl->exp_points += crstat->sleep_experience;
            check_experience_upgrade(thing);
        }
    }
    {
        HitPoints health_max;
        health_max = compute_creature_max_health(crstat->health, cctrl->explevel);
        if ((crstat->heal_threshold * health_max / 256 <= thing->health) && (!cctrl->field_82))
        {
            set_start_state(thing);
            return 1;
        }
    }
    process_lair_enemy(thing, room);
    return 0;
}
short good_attack_room(struct Thing *thing)
{
    // Debug code to find incorrect states
    if (!is_hero_thing(thing))
    {
        ERRORLOG("Non hero %s index %d owner %d - reset",thing_model_name(thing),(int)thing->index,(int)thing->owner);
        set_start_state(thing);
        return 0;
    }
    //return _DK_good_attack_room(thing);
    MapSlabCoord base_slb_x,base_slb_y;
    base_slb_x = subtile_slab_fast(thing->mappos.x.stl.num);
    base_slb_y = subtile_slab_fast(thing->mappos.y.stl.num);
    struct Room *room;
    room = slab_room_get(base_slb_x, base_slb_y);
    // If the current tile can be destroyed
    if (room_exists(room) && (room->owner != thing->owner) && !room_cannot_vandalise(room->kind))
    {
        struct CreatureControl *cctrl;
        cctrl = creature_control_get_from_thing(thing);
        if (cctrl->instance_id == CrInst_NULL)
        {
            set_creature_instance(thing, CrInst_ATTACK_ROOM_SLAB, 1, 0, 0);
            MapCoord ev_coord_x,ev_coord_y;
            ev_coord_x = subtile_coord_center(room->central_stl_x);
            ev_coord_y = subtile_coord_center(room->central_stl_y);
            event_create_event_or_update_nearby_existing_event(ev_coord_x, ev_coord_y, EvKind_RoomUnderAttack, room->owner, 0);
            if (is_my_player_number(room->owner))
                output_message(SMsg_EnemyDestroyRooms, MESSAGE_DELAY_FIGHT, true);
        }
        return 1;
    }
    // Otherwise, search around for a tile to destroy
    long m,n;
    m = ACTION_RANDOM(SMALL_AROUND_SLAB_LENGTH);
    for (n=0; n < SMALL_AROUND_SLAB_LENGTH; n++)
    {
        MapSlabCoord slb_x,slb_y;
        slb_x = base_slb_x + (long)small_around[m].delta_x;
        slb_y = base_slb_y + (long)small_around[m].delta_y;
        room = slab_room_get(slb_x, slb_y);
        if (room_exists(room) && (room->owner != thing->owner))
        {
            if (setup_person_move_to_position(thing, slb_x, slb_y, NavRtF_Default))
            {
                thing->continue_state = CrSt_GoodAttackRoom1;
                return 1;
            }
        }
        m = (m+1) % SMALL_AROUND_SLAB_LENGTH;
    }
    set_start_state(thing);
    return 0;
}
TbBool prison_convert_creature_to_skeleton(struct Room *room, struct Thing *thing)
{
    struct Dungeon *dungeon;
    struct CreatureControl *cctrl;
    struct Thing *crthing;
    long crmodel;
    cctrl = creature_control_get_from_thing(thing);
    crmodel = get_room_create_creature_model(room->kind); // That normally returns skeleton breed
    crthing = create_creature(&thing->mappos, crmodel, room->owner);
    if (thing_is_invalid(crthing))
    {
        ERRORLOG("Couldn't create creature %s in prison", creature_code_name(crmodel));
        return false;
    }
    init_creature_level(crthing, cctrl->explevel);
    set_start_state(crthing);
    if (creature_model_bleeds(thing->model))
      create_effect_around_thing(thing, TngEff_Unknown10);
    kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects);
    dungeon = get_dungeon(room->owner);
    if (!dungeon_invalid(dungeon)) {
        dungeon->lvstats.skeletons_raised++;
    }
    return true;
}
short move_to_position(struct Thing *creatng)
{
    CreatureStateCheck callback;
    struct CreatureControl *cctrl;
    struct StateInfo *stati;
    long move_result;
    CrCheckRet state_check;
    long speed;
    TRACE_THING(creatng);
    cctrl = creature_control_get_from_thing(creatng);
    speed = get_creature_speed(creatng);
    SYNCDBG(18,"Starting to move %s index %d into (%d,%d)",thing_model_name(creatng),(int)creatng->index,(int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num);
    // Try teleporting the creature
    if (creature_move_to_using_teleport(creatng, &cctrl->moveto_pos, speed)) {
        SYNCDBG(8,"Teleporting %s index %d owner %d into (%d,%d) for %s",thing_model_name(creatng),(int)creatng->index,(int)creatng->owner,
            (int)cctrl->moveto_pos.x.stl.num,(int)cctrl->moveto_pos.y.stl.num,creature_state_code_name(creatng->continue_state));
        return 1;
    }
    move_result = creature_move_to(creatng, &cctrl->moveto_pos, speed, cctrl->move_flags, 0);
    state_check = CrCkRet_Available;
    stati = get_thing_continue_state_info(creatng);
    if (!state_info_invalid(stati))
    {
        callback = stati->move_check;
        if (callback != NULL)
        {
            SYNCDBG(18,"Doing move check callback for continue state %s",creature_state_code_name(creatng->continue_state));
            state_check = callback(creatng);
        }
    }
    if (state_check == CrCkRet_Available)
    {
        // If moving was successful
        if (move_result == 1) {
            // Back to "main state"
            internal_set_thing_state(creatng, creatng->continue_state);
            return CrStRet_Modified;
        }
        // If moving failed, do a reset
        if (move_result == -1) {
            CrtrStateId cntstat;
            cntstat = creatng->continue_state;
            internal_set_thing_state(creatng, cntstat);
            set_start_state(creatng);
            SYNCDBG(8,"Couldn't move %s to place required for state %s; reset to state %s",thing_model_name(creatng),creature_state_code_name(cntstat),creatrtng_actstate_name(creatng));
            return CrStRet_ResetOk;
        }
        // If continuing the job, check for job stress
        process_job_stress_and_going_postal(creatng);
    }
    switch (state_check)
    {
    case CrCkRet_Deleted:
        return CrStRet_Deleted;
    case CrCkRet_Available:
        return CrStRet_Modified;
    default:
        return CrStRet_ResetOk;
    }
}
CrStateRet guarding(struct Thing *thing)
{
    struct Room *room;
    TRACE_THING(thing);
    room = get_room_thing_is_on(thing);
    if (creature_job_in_room_no_longer_possible(room, Job_GUARD, thing))
    {
        remove_creature_from_work_room(thing);
        set_start_state(thing);
        return CrStRet_ResetFail;
    }
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    if (creature_move_to(thing, &cctrl->moveto_pos, cctrl->max_speed, 0, 0) == 0)
    {
        return CrStRet_Unchanged;
    }
    if (!person_get_somewhere_adjacent_in_room(thing, room, &cctrl->moveto_pos))
    {
        cctrl->moveto_pos.x.val = thing->mappos.x.val;
        cctrl->moveto_pos.y.val = thing->mappos.y.val;
        cctrl->moveto_pos.z.val = thing->mappos.z.val;
    }
    return CrStRet_Modified;
}
short good_drops_gold(struct Thing *thing)
{
    // Debug code to find incorrect states
    if (!is_hero_thing(thing))
    {
        ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner);
        set_start_state(thing);
        erstat_inc(ESE_BadCreatrState);
        return 0;
    }
    //return _DK_good_drops_gold(thing);
    GoldAmount amount;
    amount = game.pot_of_gold_holds;
    if (thing->creature.gold_carried <= game.pot_of_gold_holds)
        amount = thing->creature.gold_carried;
    struct Thing *gldtng;
    gldtng = create_object(&thing->mappos, 6, thing->owner, -1);
    if (thing_is_invalid(gldtng)) {
        return 0;
    }
    gldtng->valuable.gold_stored = amount;
    thing->creature.gold_carried -= amount;
    // Update size of the gold object
    add_gold_to_pile(gldtng, 0);
    internal_set_thing_state(thing, CrSt_GoodBackAtStart);
    return 1;
}
short good_leave_through_exit_door(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Thing *tmptng;
    // Debug code to find incorrect states
    if (!is_hero_thing(thing))
    {
        ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner);
        set_start_state(thing);
        erstat_inc(ESE_BadCreatrState);
        return false;
    }
    //return _DK_good_leave_through_exit_door(thing);
    tmptng = find_base_thing_on_mapwho(TCls_Object, 49, thing->mappos.x.stl.num, thing->mappos.y.stl.num);
    if (thing_is_invalid(tmptng))
    {
        return 0;
    }
    cctrl = creature_control_get_from_thing(thing);
    thing->creature.gold_carried = 0;
    cctrl->field_282 = game.hero_door_wait_time;
    cctrl->byte_8A = tmptng->creation_turn;
    place_thing_in_creature_controlled_limbo(thing);
    internal_set_thing_state(thing, CrSt_GoodWaitInExitDoor);
    return 1;
}
short creature_freeze_prisonors(struct Thing *creatng)
{
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(creatng);
    if (cctrl->instance_id != CrInst_NULL) {
        return 1;
    }
    if (!creature_instance_has_reset(creatng, CrInst_FREEZE))
    {
        if (creature_choose_random_destination_on_valid_adjacent_slab(creatng)) {
            creatng->continue_state = CrSt_CreatureFreezePrisoners;
        }
        return 1;
    }
    struct Thing *victng;
    victng = find_prisoner_for_thing(creatng);
    if (thing_is_invalid(victng)) {
        set_start_state(creatng);
        return 0;
    }
    long dist;
    dist = get_combat_distance(creatng, victng);
    if (dist < 156) {
        creature_retreat_from_combat(creatng, victng, CrSt_CreatureFreezePrisoners, 0);
    } else
    if ((dist <= 2048) && (creature_can_see_combat_path(creatng, victng, dist) > AttckT_Unset))
    {
        set_creature_instance(creatng, CrInst_FREEZE, 1, victng->index, 0);
    } else
    {
        creature_move_to(creatng, &victng->mappos, cctrl->max_speed, 0, 0);
    }
    return 1;

}
struct Thing *create_and_control_creature_as_controller(struct PlayerInfo *player, long breed, struct Coord3d *pos)
{
    struct CreatureStats *crstat;
    struct CreatureControl *cctrl;
    struct Dungeon *dungeon;
    struct Thing *thing;
    struct Camera *cam;
    struct InitLight ilght;
    SYNCDBG(6,"Request for model %ld at (%d,%d,%d)",breed,(int)pos->x.val,(int)pos->y.val,(int)pos->z.val);
    //return _DK_create_and_control_creature_as_controller(player, a2, pos);
    thing = create_creature(pos, breed, player->id_number);
    if (thing_is_invalid(thing))
      return INVALID_THING;
    dungeon = get_dungeon(thing->owner);
    dungeon->num_active_creatrs--;
    dungeon->owned_creatures_of_model[thing->model]--;
    if (is_my_player(player))
    {
        toggle_status_menu(0);
        turn_off_roaming_menus();
    }
    cam = player->acamera;
    player->controlled_thing_idx = thing->index;
    player->field_31 = thing->creation_turn;
    player->field_4B5 = cam->field_6;
    thing->alloc_flags |= TAlF_IsControlled;
    thing->field_4F |= 0x01;
    cctrl = creature_control_get_from_thing(thing);
    cctrl->flgfield_2 |= 0x02;
    cctrl->max_speed = calculate_correct_creature_maxspeed(thing);
    set_player_mode(player, PVT_CreatureContrl);
    set_start_state(thing);
    // Preparing light object
    LbMemorySet(&ilght, 0, sizeof(struct InitLight));
    ilght.mappos.x.val = thing->mappos.x.val;
    ilght.mappos.y.val = thing->mappos.y.val;
    ilght.mappos.z.val = thing->mappos.z.val;
    ilght.field_2 = 36;
    ilght.field_3 = 1;
    ilght.is_dynamic = 1;
    ilght.field_0 = 2560;
    thing->light_id = light_create_light(&ilght);
    if (thing->light_id != 0)
    {
        light_set_light_never_cache(thing->light_id);
    } else
    {
        ERRORLOG("Cannot allocate light to new hero");
    }
    if (is_my_player_number(thing->owner))
    {
        if (thing->class_id == TCls_Creature)
        {
            crstat = creature_stats_get_from_thing(thing);
            setup_eye_lens(crstat->eye_effect);
        }
    }
    return thing;
}
Exemple #19
0
short manufacturing(struct Thing *creatng)
{
    struct Room *room;
    //return _DK_manufacturing(creatng);
    TRACE_THING(creatng);
    room = get_room_thing_is_on(creatng);
    if (creature_work_in_room_no_longer_possible(room, RoK_WORKSHOP, creatng))
    {
        remove_creature_from_work_room(creatng);
        set_start_state(creatng);
        return CrStRet_ResetFail;
    }
    if (room->used_capacity > room->total_capacity)
    {
        if (is_my_player_number(creatng->owner))
            output_message(SMsg_WorkshopTooSmall, 500, true);
        remove_creature_from_work_room(creatng);
        set_start_state(creatng);
        return CrStRet_ResetOk;
    }
    struct Dungeon *dungeon;
    dungeon = get_dungeon(creatng->owner);
    if (dungeon->manufacture_class)
    {
        struct CreatureControl *cctrl;
        struct CreatureStats *crstat;
        cctrl = creature_control_get_from_thing(creatng);
        crstat = creature_stats_get_from_thing(creatng);
        long work_value;
        work_value = compute_creature_work_value(crstat->manufacture_value*256, room->efficiency, cctrl->explevel);
        work_value = process_work_speed_on_work_value(creatng, work_value);
        SYNCDBG(9,"The %s index %d produced %d manufacture points",thing_model_name(creatng),(int)creatng->index,(int)work_value);
        dungeon->manufacture_progress += work_value;
        dungeon->field_1181 += work_value;
    } else
    {
        WARNDBG(9,"The %s index %d owner %d is manufacturing nothing",thing_model_name(creatng),(int)creatng->index,(int)creatng->owner);
        // This may be cause by a creature taking up place in workshop where crate should be created; the creature should take a break
        if (room->used_capacity >= room->total_capacity) {
            external_set_thing_state(creatng, CrSt_CreatureGoingHomeToSleep);
            return CrStRet_Modified;
        }
    }
    process_creature_in_workshop(creatng, room);
    return CrStRet_Modified;
}
short at_lair_to_sleep(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Thing *lairtng;
    struct Room *room;
    TRACE_THING(thing);
    //return _DK_at_lair_to_sleep(thing);
    cctrl = creature_control_get_from_thing(thing);
    lairtng = thing_get(cctrl->lairtng_idx);
    TRACE_THING(lairtng);
    cctrl->target_room_id = 0;
    if (thing_is_invalid(lairtng) || (cctrl->slap_turns != 0))
    {
        set_start_state(thing);
        return 0;
    }
    if (!creature_will_sleep(thing))
    {
        set_start_state(thing);
        return 0;
    }
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, RoK_LAIR, thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(thing));
        set_start_state(thing);
        return 0;
    }
    if ((cctrl->lair_room_id != room->index))
    {
        set_start_state(thing);
        return 0;
    }
    if ( !creature_turn_to_face_angle(thing, lairtng->field_52) )
    {
        internal_set_thing_state(thing, CrSt_CreatureSleep);
        cctrl->field_82 = 200;
        thing->movement_flags &= ~TMvF_Flying;
    }
    process_lair_enemy(thing, room);
    return 1;
}
short at_research_room(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Dungeon *dungeon;
    struct Room *room;
    cctrl = creature_control_get_from_thing(thing);
    cctrl->target_room_id = 0;
    dungeon = get_dungeon(thing->owner);
    if (!creature_can_do_research(thing))
    {
        if (!is_neutral_thing(thing) && (dungeon->current_research_idx < 0))
        {
            if (is_my_player_number(dungeon->owner))
                output_message(SMsg_NoMoreReseach, 500, true);
        }
        set_start_state(thing);
        return 0;
    }
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, RoK_LIBRARY, thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(thing),(int)thing->index);
        set_start_state(thing);
        return 0;
    }
    if (!add_creature_to_work_room(thing, room))
    {
        set_start_state(thing);
        return 0;
    }
    if (!setup_random_head_for_room(thing, room, NavRtF_Default))
    {
        ERRORLOG("The %s index %d can not move in research room", thing_model_name(thing),(int)thing->index);
        remove_creature_from_work_room(thing);
        set_start_state(thing);
        return 0;
    }
    thing->continue_state = CrSt_Researching;
    cctrl->field_82 = 0;
    cctrl->byte_9A = 3;
    return 1;
}
CrStateRet creature_at_new_lair(struct Thing *creatng)
{
    struct Room *room;
    TRACE_THING(creatng);
    //return _DK_creature_at_new_lair(thing);
    room = get_room_thing_is_on(creatng);
    if ( !room_still_valid_as_type_for_thing(room, RoK_LAIR, creatng) )
    {
        WARNLOG("Room %s owned by player %d is bad work place for %s owned by played %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->owner);
        set_start_state(creatng);
        return CrStRet_ResetFail;
    }
    if (!creature_add_lair_to_room(creatng, room))
    {
        internal_set_thing_state(creatng, CrSt_CreatureChooseRoomForLairSite);
        return CrStRet_Modified;
    }
    set_start_state(creatng);
    return CrStRet_ResetOk;
}
Exemple #23
0
short at_training_room(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct CreatureStats *crstat;
    struct Dungeon *dungeon;
    struct Room *room;
    //return _DK_at_training_room(thing);
    cctrl = creature_control_get_from_thing(thing);
    cctrl->target_room_id = 0;
    if (!creature_can_be_trained(thing))
    {
        SYNCDBG(9,"Ending training of %s level %d; creature is not trainable",thing_model_name(thing),(int)cctrl->explevel);
        set_start_state(thing);
        return 0;
    }
    crstat = creature_stats_get_from_thing(thing);
    dungeon = get_dungeon(thing->owner);
    if (dungeon->total_money_owned < crstat->training_cost)
    {
        if (is_my_player_number(thing->owner))
            output_message(SMsg_NoGoldToTrain, MESSAGE_DELAY_TREASURY, true);
        set_start_state(thing);
        return 0;
    }
    room = get_room_thing_is_on(thing);
    if (!room_initially_valid_as_type_for_thing(room, RoK_TRAINING, thing))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s",room_code_name(room->kind),(int)room->owner,thing_model_name(thing));
        set_start_state(thing);
        return 0;
    }
    if ( !add_creature_to_work_room(thing, room) )
    {
        set_start_state(thing);
        return 0;
    }
    internal_set_thing_state(thing, CrSt_Training);
    setup_move_to_new_training_position(thing, room, 1);
    cctrl->field_82 = 0;
    return 1;
}
short good_wait_in_exit_door(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    struct Thing *tmptng;
    // Debug code to find incorrect states
    if (!is_hero_thing(thing))
    {
        ERRORLOG("Non hero thing %s index %d, owner %d - reset",
            thing_model_name(thing), (int)thing->index, (int)thing->owner);
        set_start_state(thing);
        erstat_inc(ESE_BadCreatrState);
        return 0;
    }
    //return _DK_good_wait_in_exit_door(thing);
    cctrl = creature_control_get_from_thing(thing);
    if (cctrl->field_282 <= 0)
        return 0;
    cctrl->field_282--;
    if (cctrl->field_282 == 0)
    {
        tmptng = find_base_thing_on_mapwho(TCls_Object, 49, thing->mappos.x.stl.num, thing->mappos.y.stl.num);
        if (!thing_is_invalid(tmptng))
        {
            if (cctrl->byte_8A == tmptng->creation_turn)
            {
                remove_thing_from_creature_controlled_limbo(thing);
                set_start_state(thing);
                return 1;
            }
        }
        thing->creature.gold_carried = 0;
        tmptng = thing_get(cctrl->dragtng_idx);
        TRACE_THING(tmptng);
        if (!thing_is_invalid(tmptng))
        {
            delete_thing_structure(tmptng, 0);
        }
        kill_creature(thing, INVALID_THING, -1, CrDed_NoEffects|CrDed_NotReallyDying);
    }
    return 0;
}
short good_back_at_start(struct Thing *thing)
{
    // Debug code to find incorrect states
    if (!is_hero_thing(thing))
    {
        ERRORLOG("Non hero thing %ld, %s, owner %ld - reset",(long)thing->index,thing_model_name(thing),(long)thing->owner);
        set_start_state(thing);
        return false;
    }
    //return _DK_good_back_at_start(thing);
    if (thing->creature.gold_carried <= 0)
    {
        set_start_state(thing);
        return 1;
    }
    SubtlCodedCoords stl_num;
    long m,n;
    stl_num = get_subtile_number(thing->mappos.x.stl.num,thing->mappos.y.stl.num);
    m = ACTION_RANDOM(AROUND_MAP_LENGTH);
    for (n=0; n < AROUND_MAP_LENGTH; n++)
    {
        struct Map *mapblk;
        mapblk = get_map_block_at_pos(stl_num+around_map[m]);
        // Per-block code
        if ((mapblk->flags & MapFlg_IsTall) == 0)
        {
            MapSubtlCoord stl_x, stl_y;
            stl_x = stl_num_decode_x(stl_num+around_map[m]);
            stl_y = stl_num_decode_y(stl_num+around_map[m]);
            if (setup_person_move_to_position(thing, stl_x, stl_y, NavRtF_Default)) {
                thing->continue_state = CrSt_GoodDropsGold;
                return 1;
            }
        }
        // Per-block code ends
        m = (m + 1) % AROUND_MAP_LENGTH;
    }
    set_start_state(thing);
    return 1;

}
short creature_choose_room_for_lair_site(struct Thing *thing)
{
    TRACE_THING(thing);
    //return _DK_creature_choose_room_for_lair_site(thing);
    struct Room *room;
    room = get_best_new_lair_for_creature(thing);
    if (room_is_invalid(room))
    {
        update_cannot_find_room_wth_spare_capacity_event(thing->owner, thing, RoK_LAIR);
        set_start_state(thing);
        return 0;
    }
    if (!setup_head_for_random_unused_lair_slab(thing, room))
    {
        ERRORLOG("Chosen lair is not valid, internal inconsistency.");
        set_start_state(thing);
        return 0;
    }
    thing->continue_state = CrSt_CreatureAtNewLair;
    return 1;
}
void creature_stop_affected_by_call_to_arms(struct Thing *thing)
{
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(thing);
    cctrl->spell_flags &= ~CSAfF_CalledToArms;
    if (!thing_is_picked_up(thing) && !creature_is_being_unconscious(thing))
    {
        if (creature_is_called_to_arms(thing)) {
            set_start_state(thing);
        }
    }
}
short at_barrack_room(struct Thing *creatng)
{
    struct Room *room;
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(creatng);
    cctrl->target_room_id = 0;
    room = get_room_thing_is_on(creatng);
    if (!room_initially_valid_as_type_for_thing(room, RoK_BARRACKS, creatng))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->index);
        set_start_state(creatng);
        return 0;
    }
    if (!add_creature_to_work_room(creatng, room))
    {
        set_start_state(creatng);
        return 0;
    }
    internal_set_thing_state(creatng, CrSt_Barracking);
    return 1;
}
short creature_arrived_at_prison(struct Thing *creatng)
{
    struct CreatureControl *cctrl;
    struct Room *room;
    TRACE_THING(creatng);
    cctrl = creature_control_get_from_thing(creatng);
    cctrl->target_room_id = 0;
    room = get_room_thing_is_on(creatng);
    if (!room_initially_valid_as_type_for_thing(room, RoK_PRISON, creatng))
    {
        WARNLOG("Room %s owned by player %d is invalid for %s index %d",room_code_name(room->kind),(int)room->owner,thing_model_name(creatng),(int)creatng->index);
        set_start_state(creatng);
        return 0;
    }
    if (!add_creature_to_work_room(creatng, room))
    {
        output_message_room_related_from_computer_or_player_action(room->owner, room->kind, OMsg_RoomTooSmall);
        cctrl->flgfield_1 &= ~CCFlg_NoCompControl;
        set_start_state(creatng);
        return 0;
    }
    cctrl->field_82 = game.play_gameturn;
    cctrl->flgfield_1 |= CCFlg_NoCompControl;
    internal_set_thing_state(creatng, CrSt_CreatureInPrison);
    if (creature_affected_by_spell(creatng, SplK_Speed)) {
        terminate_thing_spell_effect(creatng, SplK_Speed);
    }
    if (creature_affected_by_spell(creatng, SplK_Invisibility)) {
        terminate_thing_spell_effect(creatng, SplK_Invisibility);
    }
    if (creatng->light_id != 0) {
        light_delete_light(creatng->light_id);
        creatng->light_id = 0;
    }
    return 1;

}
/**
 * Does a step of researching.
 * Informs if the research cycle should end.
 * @param thing
 */
CrCheckRet process_research_function(struct Thing *creatng)
{
    struct Dungeon *dungeon;
    struct Room *room;
    dungeon = get_dungeon(creatng->owner);
    if (dungeon_invalid(dungeon)) {
        SYNCDBG(9,"The %s index %d cannot work as player %d has no dungeon",
            thing_model_name(creatng), (int)creatng->index, (int)creatng->owner);
        set_start_state(creatng);
        return CrCkRet_Continue;
    }
    if (!creature_can_do_research(creatng)) {
        set_start_state(creatng);
        return CrCkRet_Continue;
    }
    room = get_room_creature_works_in(creatng);
    if ( !room_still_valid_as_type_for_thing(room, RoK_LIBRARY, creatng) ) {
        WARNLOG("Room %s owned by player %d is bad work place for %s index %d owner %d",
            room_code_name(room->kind), (int)room->owner, thing_model_name(creatng),(int)creatng->index,(int)creatng->owner);
        set_start_state(creatng);
        return CrCkRet_Continue;
    }
    long work_value;
    struct CreatureControl *cctrl;
    cctrl = creature_control_get_from_thing(creatng);
    struct CreatureStats *crstat;
    crstat = creature_stats_get_from_thing(creatng);
    work_value = compute_creature_work_value(crstat->research_value*256, room->efficiency, cctrl->explevel);
    work_value = process_work_speed_on_work_value(creatng, work_value);
    SYNCDBG(19,"The %s index %d produced %d research points",thing_model_name(creatng),(int)creatng->index,(int)work_value);
    dungeon->total_research_points += work_value;
    dungeon->research_progress += work_value;
    //TODO CREATURE_JOBS going postal should be possible for all jobs, not only research
    process_job_stress_and_going_postal(creatng, room);
    return CrCkRet_Available;
}