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; } } }
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 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; }
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); } }
struct Thing *create_cave_in(struct Coord3d *pos, unsigned short cimodel, unsigned short owner) { struct MagicStats *magstat; struct Dungeon *dungeon; struct Thing *thing; if ( !i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots) ) { ERRORDBG(3,"Cannot create cave in %d for player %d. There are too many things allocated.",(int)cimodel,(int)owner); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots); if (thing->index == 0) { ERRORDBG(3,"Should be able to allocate cave in %d for player %d, but failed.",(int)cimodel,(int)owner); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } thing->class_id = TCls_CaveIn; thing->model = 0; thing->parent_idx = thing->index; memcpy(&thing->mappos,pos,sizeof(struct Coord3d)); thing->owner = owner; thing->creation_turn = game.play_gameturn; magstat = &game.keeper_power_stats[PwrK_CAVEIN]; thing->word_15 = magstat->time; thing->byte_13 = pos->x.stl.num; thing->byte_14 = pos->y.stl.num; thing->byte_17 = cimodel; thing->health = magstat->time; if (owner != game.neutral_player_num) { dungeon = get_dungeon(owner); dungeon->camera_deviate_quake = thing->word_15; } add_thing_to_its_class_list(thing); place_thing_in_mapwho(thing); return thing; }
long tree_to_route(long tag_start_id, long tag_end_id, long *route_pts) { long ipt; if (tag_current != Tags[tag_start_id]) return -1; ipt = copy_tree_to_route(tag_start_id, tag_end_id, route_pts, 3000+1); if (ipt < 0) { erstat_inc(ESE_BadRouteTree); ERRORDBG(6,"route length overflow"); } return ipt; }
struct Thing *create_ambient_sound(const struct Coord3d *pos, ThingModel model, PlayerNumber owner) { struct Thing *thing; if ( !i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots) ) { ERRORDBG(3,"Cannot create ambient sound %d for player %d. There are too many things allocated.",(int)model,(int)owner); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots); if (thing->index == 0) { ERRORDBG(3,"Should be able to allocate ambient sound %d for player %d, but failed.",(int)model,(int)owner); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } thing->class_id = TCls_AmbientSnd; thing->model = model; thing->parent_idx = thing->index; memcpy(&thing->mappos,pos,sizeof(struct Coord3d)); thing->owner = owner; thing->field_4F |= TF4F_DoNotDraw; add_thing_to_its_class_list(thing); return thing; }
/** Sets tags if indices from given border to given tag_id. * * @param tag_id * @param border_pt * @param border_len * @return */ long update_border_tags(long tag_id, long *border_pt, long border_len) { long ipt,n; long iset; iset = 0; for (ipt=0; ipt < border_len; ipt++) { n = border_pt[ipt]; if ((n < 0) || (n >= TREEITEMS_COUNT)) { erstat_inc(ESE_BadRouteTree); continue; } Tags[n] = tag_id; iset++; } tag_current = tag_id; return iset; }
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; }
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; } } }
short good_returns_to_start(struct Thing *thing) { struct Thing *heartng; // Debug code to find incorrect states SYNCDBG(7,"Starting"); 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_returns_to_start(thing); heartng = get_player_soul_container(thing->owner); TRACE_THING(heartng); //TODO CREATURE_AI Heroes don't usually have hearts; maybe they should also go back to hero gates, or any room? if (!setup_person_move_to_coord(thing, &heartng->mappos, NavRtF_Default)) { return 0; } thing->continue_state = CrSt_GoodBackAtStart; return 1; }
/** * Returns a hero gate object to which given hero can navigate. * @todo CREATURE_AI It returns first hero door found, not the best one. * Maybe it should find the one he will reach faster, or at least a random one? * @param herotng The hero to be able to make it to gate. * @return The gate thing, or invalid thing. */ struct Thing *find_hero_door_hero_can_navigate_to(struct Thing *herotng) { struct Thing *thing; unsigned long k; int i; k = 0; const struct StructureList *slist; slist = get_list_for_thing_class(TCls_Object); i = slist->index; while (i != 0) { thing = thing_get(i); if (thing_is_invalid(thing)) { ERRORLOG("Jump to invalid thing detected"); break; } i = thing->next_of_class; // Per thing code if (object_is_hero_gate(thing)) { if (creature_can_navigate_to_with_storage(herotng, &thing->mappos, NavRtF_Default)) { return thing; } } // Per thing code ends k++; if (k > slist->count) { ERRORLOG("Infinite loop detected when sweeping things list"); erstat_inc(ESE_InfChainTngPerClass); break; } } return NULL; }
void god_lightning_choose_next_creature(struct Thing *shotng) { SYNCDBG(16,"Starting for %s index %d owner %d",thing_model_name(shotng),(int)shotng->index,(int)shotng->owner); //_DK_god_lightning_choose_next_creature(shotng); return; long best_dist; struct Thing *best_thing; best_dist = LONG_MAX; best_thing = INVALID_THING; unsigned long k; int i; const struct StructureList *slist; slist = get_list_for_thing_class(TCls_Creature); k = 0; i = slist->index; while (i != 0) { struct Thing *thing; thing = thing_get(i); if (thing_is_invalid(thing)) { ERRORLOG("Jump to invalid thing detected"); break; } i = thing->next_of_class; // Per-thing code //TODO use hit_type instead of hard coded conditions if ((shotng->owner != thing->owner) && !thing_is_picked_up(thing) && !creature_is_being_unconscious(thing) && !creature_is_dying(thing)) { long dist; dist = get_2d_distance(&shotng->mappos, &thing->mappos); if (dist < best_dist) { const struct MagicStats *pwrdynst; pwrdynst = get_power_dynamic_stats(PwrK_LIGHTNING); int spell_lev; spell_lev = shotng->shot.byte_19; if (spell_lev > SPELL_MAX_LEVEL) spell_lev = SPELL_MAX_LEVEL; if (subtile_coord(pwrdynst->strength[spell_lev],0) > dist) { if (line_of_sight_2d(&shotng->mappos, &thing->mappos)) { best_dist = dist; best_thing = thing; } } } } // Per-thing code ends k++; if (k > slist->count) { ERRORLOG("Infinite loop detected when sweeping things list"); erstat_inc(ESE_InfChainTngPerClass); break; } } SYNCDBG(8,"The best target for %s index %d owner %d is %s index %d owner %d", thing_model_name(shotng),(int)shotng->index,(int)shotng->owner, thing_model_name(best_thing),(int)best_thing->index,(int)best_thing->owner); if (!thing_is_invalid(best_thing)) { shotng->shot.target_idx = best_thing->index; } else { shotng->shot.target_idx = 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; }
struct Thing *create_trap(struct Coord3d *pos, ThingModel trpkind, PlayerNumber plyr_idx) { SYNCDBG(7,"Starting"); struct TrapStats *trapstat; trapstat = &trap_stats[trpkind]; if (!i_can_allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots)) { ERRORDBG(3,"Cannot create trap %s for player %d. There are too many things allocated.",trap_code_name(trpkind),(int)plyr_idx); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } struct InitLight ilght; LbMemorySet(&ilght, 0, sizeof(struct InitLight)); struct Thing *thing; thing = allocate_free_thing_structure(FTAF_FreeEffectIfNoSlots); if (thing->index == 0) { ERRORDBG(3,"Should be able to allocate trap %s for player %d, but failed.",trap_code_name(trpkind),(int)plyr_idx); erstat_inc(ESE_NoFreeThings); return INVALID_THING; } thing->class_id = TCls_Trap; thing->model = trpkind; thing->mappos.x.val = pos->x.val; thing->mappos.y.val = pos->y.val; thing->mappos.z.val = pos->z.val; thing->next_on_mapblk = 0; thing->parent_idx = thing->index; thing->owner = plyr_idx; char start_frame; if (trapstat->field_13) { start_frame = -1; } else { start_frame = 0; } set_thing_draw(thing, trapstat->field_4, trapstat->field_D, trapstat->field_8, trapstat->field_C, start_frame, 2); if (trapstat->field_11) { thing->field_4F |= 0x02; } else { thing->field_4F &= ~0x02; } if (trapstat->field_C) { thing->field_4F |= 0x40; } else { thing->field_4F &= ~0x40; } thing->clipbox_size_xy = trapstat->size_xy; thing->clipbox_size_yz = trapstat->field_16; thing->solid_size_xy = trapstat->size_xy; thing->field_5C = trapstat->field_16; thing->creation_turn = game.play_gameturn; thing->health = trapstat->field_0; thing->field_4F &= ~0x10; thing->field_4F |= 0x20; thing->byte_13 = 0; thing->long_14 = game.play_gameturn; if (trapstat->field_1C != 0) { 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_0 = trapstat->field_1C; ilght.field_2 = trapstat->field_1E; ilght.is_dynamic = 1; ilght.field_3 = trapstat->field_1F; thing->light_id = light_create_light(&ilght); if (thing->light_id <= 0) { SYNCDBG(8,"Cannot allocate dynamic light to %s.",thing_model_name(thing)); } } add_thing_to_its_class_list(thing); place_thing_in_mapwho(thing); return thing; }