dfhack/plugins/ruby/unit.rb

174 lines
6.6 KiB
Ruby

2012-04-26 11:38:15 -06:00
module DFHack
2012-06-24 09:30:26 -06:00
class << self
# return an Unit
# with no arg, return currently selected unit in df UI ('v' or 'k' menu)
# with numeric arg, search unit by unit.id
# with an argument that respond to x/y/z (eg cursor), find first unit at this position
def unit_find(what=:selected, y=nil, z=nil)
2012-06-24 09:30:26 -06:00
if what == :selected
case curview._rtti_classname
when :viewscreen_itemst
ref = curview.entry_ref[curview.cursor_pos]
ref.unit_tg if ref.kind_of?(GeneralRefUnit)
when :viewscreen_unitlistst
v = curview
2012-09-26 10:13:01 -06:00
v.units[v.page][v.cursor_pos[v.page]]
when :viewscreen_petst
v = curview
case v.mode
when :List
v.animal[v.cursor].unit if !v.is_vermin[v.cursor]
when :SelectTrainer
v.trainer_unit[v.trainer_cursor]
end
2012-11-16 09:39:08 -07:00
when :viewscreen_dwarfmodest
case ui.main.mode
when :ViewUnits
# nobody selected => idx == 0
v = world.units.active[ui_selected_unit]
v if v and v.pos.z == cursor.z
when :LookAround
k = ui_look_list.items[ui_look_cursor]
k.unit if k.type == :Unit
else
ui.follow_unit_tg if ui.follow_unit != -1
end
2012-11-16 09:39:08 -07:00
when :viewscreen_dungeonmodest
case ui_advmode.menu
when :Default
world.units.active[0]
else
unit_find(cursor) # XXX
end
when :viewscreen_dungeon_monsterstatusst
curview.unit
2012-06-24 09:30:26 -06:00
end
elsif what.kind_of?(Integer)
# search by id
return world.units.all.binsearch(what) if not z
# search by coords
x = what
world.units.all.find { |u| u.pos.x == x and u.pos.y == y and u.pos.z == z }
2012-06-24 09:30:26 -06:00
elsif what.respond_to?(:x) or what.respond_to?(:pos)
world.units.all.find { |u| same_pos?(what, u) }
else
raise "what what?"
end
end
2012-04-26 11:38:15 -06:00
2012-06-24 09:30:26 -06:00
# returns an Array of all units that are current fort citizen (dwarves, on map, not hostile)
def unit_citizens
world.units.active.find_all { |u|
unit_iscitizen(u)
2012-06-24 09:30:26 -06:00
}
end
2012-04-26 11:38:15 -06:00
2012-12-06 03:00:19 -07:00
def unit_testflagcurse(u, flag)
return false if u.curse.rem_tags1.send(flag)
return true if u.curse.add_tags1.send(flag)
return false if u.caste < 0
u.race_tg.caste[u.caste].flags[flag]
end
def unit_isfortmember(u)
# RE from viewscreen_unitlistst ctor
return false if df.gamemode != :DWARF or
u.mood == :Berserk or
unit_testflagcurse(u, :CRAZED) or
unit_testflagcurse(u, :OPPOSED_TO_LIFE) or
u.enemy.undead or
2012-12-06 03:00:19 -07:00
u.flags3.ghostly or
u.flags1.marauder or u.flags1.active_invader or u.flags1.invader_origin or
u.flags1.forest or
u.flags1.merchant or u.flags1.diplomat
return true if u.flags1.tame
return false if u.flags2.underworld or u.flags2.resident or
u.flags2.visitor_uninvited or u.flags2.visitor or
u.civ_id == -1 or
u.civ_id != df.ui.civ_id
true
end
# return the page in viewscreen_unitlist where the unit would appear
def unit_category(u)
return if u.flags1.left or u.flags1.incoming
# return if hostile & unit_invisible(u) (hidden_in_ambush or caged+mapblock.hidden or caged+holder.ambush
return :Dead if u.flags1.dead
return :Dead if u.flags3.ghostly # hostile ?
return :Others if !unit_isfortmember(u)
casteflags = u.race_tg.caste[u.caste].flags if u.caste >= 0
return :Livestock if casteflags and (casteflags[:PET] or casteflags[:PET_EXOTIC])
return :Citizens if unit_testflagcurse(u, :CAN_SPEAK)
:Livestock
# some other stuff with ui.race_id ? (jobs only?)
end
2012-09-26 10:13:01 -06:00
def unit_iscitizen(u)
2012-12-06 03:00:19 -07:00
unit_category(u) == :Citizens
end
def unit_ishostile(u)
unit_category(u) == :Others and
# TODO
true
end
# merchant: df.ui.caravans.find { |cv| cv.entity == u.civ_id }
# diplomat: df.ui.dip_meeting_info.find { |m| m.diplomat_id == u.hist_figure_id or m.diplomat_id2 == u.hist_figure_id }
2012-06-24 09:30:26 -06:00
# list workers (citizen, not crazy / child / inmood / noble)
def unit_workers
world.units.active.find_all { |u|
unit_isworker(u)
2012-06-24 09:30:26 -06:00
}
end
2012-04-26 11:38:15 -06:00
def unit_isworker(u)
unit_iscitizen(u) and
u.mood == :None and
u.profession != :CHILD and
u.profession != :BABY and
# TODO MENIAL_WORK_EXEMPTION_SPOUSE
!unit_entitypositions(u).find { |pos| pos.flags[:MENIAL_WORK_EXEMPTION] }
end
2012-06-24 09:30:26 -06:00
# list currently idle workers
def unit_idlers
world.units.active.find_all { |u|
unit_isidler(u)
2012-06-24 09:30:26 -06:00
}
end
def unit_isidler(u)
unit_isworker(u) and
# current_job includes eat/drink/sleep/pickupequip
!u.job.current_job and
# filter 'attend meeting'
not u.specific_refs.find { |s| s.type == :ACTIVITY } and
# filter soldiers (TODO check schedule)
u.military.squad_id == -1 and
# filter 'on break'
not u.status.misc_traits.find { |t| t.id == :OnBreak }
end
2012-06-24 09:30:26 -06:00
def unit_entitypositions(unit)
list = []
return list if not hf = unit.hist_figure_tg
2012-06-24 09:30:26 -06:00
hf.entity_links.each { |el|
next if el._rtti_classname != :histfig_entity_link_positionst
next if not ent = el.entity_tg
2012-06-24 09:30:26 -06:00
next if not pa = ent.positions.assignments.binsearch(el.assignment_id)
next if not pos = ent.positions.own.binsearch(pa.position_id)
list << pos
}
list
end
end
class LanguageName
def to_s(english=false)
df.translate_name(self, english)
end
end
2012-04-26 11:38:15 -06:00
end