diff --git a/library/lua/script-manager.lua b/library/lua/script-manager.lua index c2647fbe2d..57edc0d61a 100644 --- a/library/lua/script-manager.lua +++ b/library/lua/script-manager.lua @@ -88,28 +88,60 @@ local INSTALLED_MODS_PATH = 'data/installed_mods/' -- changes to the files) local MOD_PATH_ROOTS = {WORKSHOP_MODS_PATH, MODS_PATH, INSTALLED_MODS_PATH} -local function get_mod_id_and_version(path) +local function get_mod_info(path) local idfile = path .. '/info.txt' local ok, lines = pcall(io.lines, idfile) if not ok then return end - local id, version + local id, numerical_version, name, steam_id, display_version for line in lines do if not id then _,_,id = line:find('^%[ID:([^%]]+)%]') end - if not version then + if not numerical_version then -- note this doesn't include the closing brace since some people put -- non-number characters in here, and DF only reads the leading digits -- as the numeric version - _,_,version = line:find('^%[NUMERIC_VERSION:(%d+)') + _,_,numerical_version = line:find('^%[NUMERIC_VERSION:(%d+)') end + if not display_version then + if line:find('^%[DISPLAYED_VERSION:') then display_version = line:sub(20,-2) end + end + if not name then + _,_,name = line:find('^%[NAME:([^%]]+)%]') + end + if not steam_id then + _,_,steam_id = line:find('^%[STEAM_FILE_ID:(%d+)') + end + -- note that we do *not* want to break out of this loop early since -- lines has to hit EOF to close the file end - return id, version + return { + id=id, + numerical_version=numerical_version, + name=name, + steam_id=steam_id, + display_version=display_version, + } +end + +function getAllModsInfo(include_vanilla, mods, mod_paths) + for _,path in ipairs(df.global.world.object_loader.object_load_order_src_dir) do + path = tostring(path.value) + if not include_vanilla then + -- skip vanilla "mods" + if not path:startswith(INSTALLED_MODS_PATH) then goto continue end + end + local info = get_mod_info(path) + if info == nil then goto continue end + if not info.id or not info.numerical_version then goto continue end + mods[info.id]= {handled=true, name=info.name, version=info.display_version, steam_id=info.steam_id} + add_mod_paths(mod_paths, info.id, path, '.') + ::continue:: + end end -local function add_mod_paths(mod_paths, id, base_path, subdir) +function add_mod_paths(mod_paths, id, base_path, subdir) local sep = base_path:endswith('/') and '' or '/' local path = ('%s%s%s'):format(base_path, sep, subdir) if dfhack.filesystem.isdir(path) then @@ -128,7 +160,7 @@ function get_mod_paths(installed_subdir, active_subdir) path = tostring(path.value) -- skip vanilla "mods" if not path:startswith(INSTALLED_MODS_PATH) then goto continue end - local id = get_mod_id_and_version(path) + local id = get_mod_info(path).id if not id then goto continue end mods[id] = {handled=true} if active_subdir then @@ -145,7 +177,9 @@ function get_mod_paths(installed_subdir, active_subdir) if not files then goto skip_path_root end for _,f in ipairs(files) do if not f.isdir then goto continue end - local id, version = get_mod_id_and_version(f.path) + local info = get_mod_info(f.path) + if info == nil then goto continue end + local id, version = info.id,info.numerical_version if not id or not version then goto continue end local mod = ensure_key(mods, id) if mod.handled then goto continue end diff --git a/plugins/spectate.cpp b/plugins/spectate.cpp index 54bd4944a0..1e3042c360 100644 --- a/plugins/spectate.cpp +++ b/plugins/spectate.cpp @@ -43,6 +43,7 @@ static uint32_t next_cycle_unpaused_ms = 0; // threshold for the next cycle static const size_t MAX_HISTORY = 200; static const float CITIZEN_COMBAT_PREFERRED_WEIGHT = 25.0f; +static const float NICKNAMED_CITIZEN_PREFERRED_WEIGHT = 15.0f; static const float OTHER_COMBAT_PREFERRED_WEIGHT = 10.0f; static const float JOB_WEIGHT = 5.0f; static const float OTHER_WEIGHT = 1.0f; @@ -71,6 +72,7 @@ static struct Configuration { bool include_wildlife; bool prefer_conflict; bool prefer_new_arrivals; + bool prefer_nicknamed; int32_t follow_ms; void reset() { @@ -82,6 +84,7 @@ static struct Configuration { include_wildlife = false; prefer_conflict = true; prefer_new_arrivals = true; + prefer_nicknamed = true; follow_ms = 10000; } } config; @@ -436,6 +439,7 @@ static bool is_in_combat(df::unit *unit) { static void get_dwarf_buckets(color_ostream &out, vector &citizen_combat_units, vector &other_combat_units, + vector &nicknamed_units, vector &job_units, vector &other_units) { @@ -452,11 +456,13 @@ static void get_dwarf_buckets(color_ostream &out, continue; if (is_in_combat(unit)) { - TRACE(cycle,out).print("unit %d is in combat: %s\n", unit->id, DF2CONSOLE(Units::getReadableName(unit)).c_str()); + TRACE(cycle, out).print("unit %d is in combat: %s\n", unit->id, DF2CONSOLE(Units::getReadableName(unit)).c_str()); if (Units::isCitizen(unit, true) || Units::isResident(unit, true)) citizen_combat_units.push_back(unit); else other_combat_units.push_back(unit); + } else if (!unit->name.nickname.empty()) { + nicknamed_units.push_back(unit); } else if (unit->job.current_job && !boring_jobs.contains(unit->job.current_job->job_type)) { job_units.push_back(unit); } else { @@ -510,9 +516,10 @@ static void follow_a_dwarf(color_ostream &out) { vector citizen_combat_units; vector other_combat_units; + vector nicknamed_units; vector job_units; vector other_units; - get_dwarf_buckets(out, citizen_combat_units, other_combat_units, job_units, other_units); + get_dwarf_buckets(out, citizen_combat_units, other_combat_units, nicknamed_units, job_units, other_units); set_next_cycle_unpaused_ms(out, !citizen_combat_units.empty()); @@ -523,6 +530,7 @@ static void follow_a_dwarf(color_ostream &out) { intervals.push_back(0); add_bucket(citizen_combat_units, units, intervals, weights, config.prefer_conflict ? CITIZEN_COMBAT_PREFERRED_WEIGHT : JOB_WEIGHT); add_bucket(other_combat_units, units, intervals, weights, config.prefer_conflict ? OTHER_COMBAT_PREFERRED_WEIGHT : JOB_WEIGHT); + add_bucket(nicknamed_units, units, intervals, weights, config.prefer_nicknamed ? NICKNAMED_CITIZEN_PREFERRED_WEIGHT : OTHER_WEIGHT); add_bucket(job_units, units, intervals, weights, JOB_WEIGHT); add_bucket(other_units, units, intervals, weights, OTHER_WEIGHT); @@ -538,6 +546,7 @@ static void follow_a_dwarf(color_ostream &out) { if (debug_cycle.isEnabled(DebugCategory::LDEBUG)) { DUMP_BUCKET(citizen_combat_units); DUMP_BUCKET(other_combat_units); + DUMP_BUCKET(nicknamed_units); DUMP_BUCKET(job_units); DUMP_BUCKET(other_units); DUMP_FLOAT_VECTOR(intervals); @@ -575,6 +584,8 @@ static void spectate_setSetting(color_ostream &out, string name, int val) { config.prefer_conflict = val; } else if (name == "prefer-new-arrivals") { config.prefer_new_arrivals = val; + } else if (name == "prefer-nicknamed") { + config.prefer_nicknamed = val; } else if (name == "follow-seconds") { if (val <= 0) { WARN(control,out).print("follow-seconds must be a positive integer\n"); diff --git a/plugins/stonesense b/plugins/stonesense index d65c4ac560..acc24a37f1 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit d65c4ac560264c4a0d69a802bc31b636c3da55fc +Subproject commit acc24a37f15dc00f2ecb4d149b5c5a3a509b2ced diff --git a/scripts b/scripts index 3220332217..03bcb0c8d7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 322033221745e9cbf537d59152138df385c505b7 +Subproject commit 03bcb0c8d7f370b64e9a002e16d5f2e82213c89b