void process_disease(struct Thing *creatng) { SYNCDBG(18,"Starting"); //_DK_process_disease(thing); struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); if (!creature_affected_by_spell(creatng, SplK_Disease)) { return; } if (ACTION_RANDOM(100) < game.disease_transfer_percentage) { SubtlCodedCoords stl_num; long n; stl_num = get_subtile_number(creatng->mappos.x.stl.num,creatng->mappos.y.stl.num); for (n=0; n < AROUND_MAP_LENGTH; n++) { struct Thing *thing; struct Map *mapblk; unsigned long k; long i; mapblk = get_map_block_at_pos(stl_num+around_map[n]); k = 0; i = get_mapwho_thing_index(mapblk); while (i != 0) { thing = thing_get(i); if (thing_is_invalid(thing)) { WARNLOG("Jump out of things array"); break; } i = thing->next_on_mapblk; // Per thing code if (thing_is_creature(thing) && ((get_creature_model_flags(thing) & CMF_IsSpecDigger) == 0) && (thing->owner != cctrl->disease_caster_plyridx) && !creature_affected_by_spell(thing, SplK_Disease)) { struct CreatureControl *tngcctrl; tngcctrl = creature_control_get_from_thing(thing); apply_spell_effect_to_thing(thing, SplK_Disease, cctrl->explevel); tngcctrl->disease_caster_plyridx = cctrl->disease_caster_plyridx; } // Per thing code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping things list"); erstat_inc(ESE_InfChainTngPerMapWho); break_mapwho_infinite_chain(mapblk); break; } } } } if (((game.play_gameturn - cctrl->disease_start_turn) % game.disease_lose_health_time) == 0) { apply_damage_to_thing_and_display_health(creatng, game.disease_lose_percentage_health * cctrl->max_health / 100, DmgT_Biological, cctrl->disease_caster_plyridx); } }
TbBool can_thing_be_possessed(const struct Thing *thing, PlayerNumber plyr_idx) { //return _DK_can_thing_be_possessed(thing, plyr_idx); if (thing->owner != plyr_idx) return false; if (thing_is_creature(thing)) { if (thing_is_picked_up(thing)) { return false; } if ((thing->active_state == CrSt_CreatureUnconscious) || creature_affected_by_spell(thing, SplK_Teleport)) { return false; } if (creature_is_being_sacrificed(thing) || creature_is_being_summoned(thing)) { return false; } if (creature_is_kept_in_custody_by_enemy(thing)) { return false; } return true; } if (thing_is_object(thing)) { if (object_is_mature_food(thing)) { return true; } return false; } return false; }
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; }
void update_creature_graphic_tint(struct Thing *thing) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(thing); if (creature_affected_by_spell(thing, SplK_Freeze)) { tint_thing(thing, colours[4][4][15], 1); } else if (((cctrl->combat_flags & CmbtF_Melee) == 0) && ((cctrl->combat_flags & CmbtF_Ranged) == 0)) { untint_thing(thing); } else if ((game.play_gameturn % 3) == 0) { untint_thing(thing); } else { switch (thing->owner) { case 0: tint_thing(thing, colours[15][0][0], 1); break; case 1: tint_thing(thing, colours[0][0][15], 1); break; case 2: tint_thing(thing, colours[0][15][0], 1); break; case 3: tint_thing(thing, colours[13][13][2], 1); break; default: untint_thing(thing); break; } } }
/** Returns if a creature can do specific job at given map position. * * @param creatng The creature which is planned for the job. * @param stl_x Target map position, x coord. * @param stl_y Target map position, y coord. * @param new_job Job selection with single job flag set. * @return True if the creature can do the job specified, false otherwise. * @see creature_can_do_job_for_player() similar function for use when only target player is known */ TbBool creature_can_do_job_near_position(struct Thing *creatng, MapSubtlCoord stl_x, MapSubtlCoord stl_y, CreatureJob new_job, unsigned long flags) { struct CreatureControl *cctrl; cctrl = creature_control_get_from_thing(creatng); SYNCDBG(6,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); struct CreatureStats *crstat; crstat = creature_stats_get_from_thing(creatng); if (creature_will_reject_job(creatng, new_job)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; in not-do-jobs list",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_SetStateOnFail) != 0) { anger_apply_anger_to_creature(creatng, crstat->annoy_will_not_do_job, AngR_Other, 1); external_set_thing_state(creatng, CrSt_CreatureMoan); cctrl->field_282 = 50; } return false; } // Don't allow creatures changed to chickens to have any job assigned, besides those specifically marked if (creature_affected_by_spell(creatng, SplK_Chicken) && ((get_flags_for_job(new_job) & JoKF_AllowChickenized) == 0)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; under chicken spell",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // Check if the job is related to correct map place (room,slab) if (!is_correct_position_to_perform_job(creatng, stl_x, stl_y, new_job)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; not correct place for job",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } struct CreatureJobConfig *jobcfg; jobcfg = get_config_for_job(new_job); if (jobcfg->func_cord_check == NULL) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; job has no coord check function",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } if (!jobcfg->func_cord_check(creatng, stl_x, stl_y, new_job, flags)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; coord check not passed",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // If other tests pass, check if related room (if is needed) has capacity to be used for that job if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { struct Room *room; room = subtile_room_get(stl_x, stl_y); if (!room_has_enough_free_capacity_for_creature(room, creatng)) { SYNCDBG(3,"Cannot assign %s at (%d,%d) for %s index %d owner %d; not enough room capacity",creature_job_code_name(new_job),(int)stl_x,(int)stl_y,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(room->kind); if (is_my_player_number(room->owner) && (roomst->msg_too_small > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_too_small); } } return false; } } return true; }
/** Returns if a creature can do specific job for the player. * * @param creatng The creature which is planned for the job. * @param plyr_idx Player for whom the job is to be done. * @param new_job Job selection with single job flag set. * @param flags Function behavior adjustment flags. * @return True if the creature can do the job specified, false otherwise. * @note this should be used instead of person_will_do_job_for_room() * @note this function will never change state of the input thing, even if appropriate flags are set * @see creature_can_do_job_near_position() similar function for use when target position is known */ TbBool creature_can_do_job_for_player(const struct Thing *creatng, PlayerNumber plyr_idx, CreatureJob new_job, unsigned long flags) { SYNCDBG(16,"Starting for %s (owner %d) and job %s",thing_model_name(creatng),(int)creatng->owner,creature_job_code_name(new_job)); if (creature_will_reject_job(creatng, new_job)) { SYNCDBG(13,"Cannot assign %s for %s index %d owner %d; in not do jobs list",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } if (!is_correct_owner_to_perform_job(creatng, plyr_idx, new_job)) { SYNCDBG(13,"Cannot assign %s for %s index %d owner %d; not correct owner for job",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // Don't allow creatures changed to chickens to have any job assigned, besides those specifically marked if (creature_affected_by_spell(creatng, SplK_Chicken) && ((get_flags_for_job(new_job) & JoKF_AllowChickenized) == 0)) { SYNCDBG(13,"Cannot assign %s for %s index %d owner %d; under chicken spell",creature_job_code_name(new_job),thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); return false; } // Check if the job is related to correct player struct CreatureJobConfig *jobcfg; jobcfg = get_config_for_job(new_job); if (jobcfg->func_plyr_check == NULL) { return false; } if (!jobcfg->func_plyr_check(creatng, plyr_idx, new_job)) { return false; } RoomKind job_rkind; job_rkind = get_room_for_job(new_job); if (job_rkind != RoK_NONE) { if (!player_has_room(plyr_idx, job_rkind)) { SYNCDBG(3,"Cannot assign %s in player %d room for %s index %d owner %d; no required room built",creature_job_code_name(new_job),(int)plyr_idx,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(get_room_for_job(new_job)); if (is_my_player_number(plyr_idx) && (roomst->msg_needed > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_needed); } } return false; } if ((get_flags_for_job(new_job) & JoKF_NeedsCapacity) != 0) { struct Room *room; room = find_room_with_spare_capacity(plyr_idx, job_rkind, 1); if (room_is_invalid(room)) { SYNCDBG(3,"Cannot assign %s in player %d room for %s index %d owner %d; not enough room capacity",creature_job_code_name(new_job),(int)plyr_idx,thing_model_name(creatng),(int)creatng->index,(int)creatng->owner); if ((flags & JobChk_PlayMsgOnFail) != 0) { const struct RoomConfigStats *roomst; roomst = get_room_kind_stats(get_room_for_job(new_job)); if (is_my_player_number(plyr_idx) && (roomst->msg_too_small > 0)) { output_message_room_related_from_computer_or_player_action(roomst->msg_too_small); } } return false; } } } return true; }
struct Thing *find_prisoner_for_thing(struct Thing *creatng) { struct CreatureControl *cctrl; struct Thing *thing; unsigned long k; long i; TRACE_THING(creatng); struct Room *room; room = INVALID_ROOM; if (!is_neutral_thing(creatng)) { room = find_nearest_room_for_thing_with_used_capacity(creatng, creatng->owner, RoK_PRISON, NavRtF_Default, 1); } if (room_exists(room)) { i = room->creatures_list; } else { i = 0; } struct Thing *out_creatng; long out_delay; out_creatng = INVALID_THING; out_delay = LONG_MAX; k = 0; while (i != 0) { thing = thing_get(i); TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); if (!creature_control_exists(cctrl)) { ERRORLOG("Jump to invalid creature %ld detected",i); break; } i = cctrl->next_in_room; // Per creature code long dist, durt; dist = get_2d_box_distance(&creatng->mappos, &thing->mappos); if (out_delay < 0) { // If we have a victim which isn't frozen, accept only other unfrozen creatures if ((dist <= LONG_MAX) && !creature_affected_by_spell(thing, SplK_Freeze)) { out_creatng = thing; out_delay = -1; } } else if (creature_affected_by_spell(thing, SplK_Freeze)) { // If the victim is frozen, select one which will unfreeze sooner durt = get_spell_duration_left_on_thing(thing, SplK_Freeze); if ((durt > 0) && (out_delay > durt)) { out_creatng = thing; out_delay = durt; } } else { // Found first unfrozen victim - change out_delay to mark thet we no longer want frozen ones out_creatng = thing; out_delay = -1; } // Per creature code ends k++; if (k > THINGS_COUNT) { ERRORLOG("Infinite loop detected when sweeping creatures list"); break; } } return out_creatng; }
void update_creature_graphic_anim(struct Thing *thing) { struct CreatureControl *cctrl; struct CreatureStats *crstat; long i; TRACE_THING(thing); cctrl = creature_control_get_from_thing(thing); crstat = creature_stats_get_from_thing(thing); if ((thing->field_50 & 0x01) != 0) { thing->field_50 &= ~0x01; } else if ((thing->active_state == CrSt_CreatureHeroEntering) && (cctrl->countdown_282 >= 0)) { thing->field_4F |= TF4F_Unknown01; } else if (!creature_affected_by_spell(thing, SplK_Chicken)) { if (cctrl->instance_id != CrInst_NULL) { if (cctrl->instance_id == CrInst_TORTURED) { thing->field_4F &= ~(TF4F_Unknown20|TF4F_Unknown10); } struct InstanceInfo *inst_inf; inst_inf = creature_instance_info_get(cctrl->instance_id); update_creature_anim(thing, cctrl->instance_anim_step_turns, inst_inf->graphics_idx); } else if ((cctrl->field_B1 != 0) || creature_is_dying(thing) || creature_affected_by_spell(thing, SplK_Freeze)) { update_creature_anim(thing, 256, 8); } else if ((cctrl->stateblock_flags & CCSpl_ChickenRel) != 0) { update_creature_anim(thing, 256, 0); } else if (thing->active_state == CrSt_CreatureSlapCowers) { update_creature_anim(thing, 256, 10); } else if ((thing->active_state == CrSt_CreaturePiss) || (thing->active_state == CrSt_CreatureRoar)) { update_creature_anim(thing, 128, 4); } else if (thing->active_state == CrSt_CreatureUnconscious) { update_creature_anim(thing, 64, 16); thing->field_4F |= TF4F_Unknown40; } else if (thing->active_state == CrSt_CreatureSleep) { thing->field_4F &= ~(TF4F_Unknown20|TF4F_Unknown10); update_creature_anim(thing, 128, 12); } else if (cctrl->field_9 == 0) { update_creature_anim(thing, 256, 0); } else if (thing->field_60 < thing->mappos.z.val) { update_creature_anim(thing, 256, 0); } else if ((cctrl->dragtng_idx != 0) && (thing_get(cctrl->dragtng_idx)->state_flags & TF1_IsDragged1)) { i = (((long)cctrl->field_9) << 8) / (crstat->walking_anim_speed+1); update_creature_anim(thing, i, 2); } else if (creatures[thing->model].field_6 == 4) { update_creature_anim(thing, 256, 1); } else { i = (((long)cctrl->field_9) << 8) / (crstat->walking_anim_speed+1); if (!update_creature_anim(thing, i, 1)) { thing->field_3E = i; } } } else { thing->field_4F &= ~0x30; if (cctrl->field_9 == 0) { update_creature_anim_td(thing, 256, 820); } else if (thing->field_60 < thing->mappos.z.val) { update_creature_anim_td(thing, 256, 820); } else if (creatures[thing->model].field_6 == 4) { update_creature_anim_td(thing, 256, 819); } else { i = (((long)cctrl->field_9) << 8) / (crstat->walking_anim_speed+1); if (!update_creature_anim_td(thing, i, 819)) { thing->field_3E = i; } } } }
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; } }