diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..75e7a15 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# IDE0290: Use primary constructor +csharp_style_prefer_primary_constructors = false diff --git a/.gitattributes b/.gitattributes index bdb0cab..1ff0c42 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,17 +1,63 @@ -# Auto detect text files and perform LF normalization +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### * text=auto -# Custom for Visual Studio -*.cs diff=csharp +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp -# Standard to msysgit -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index a9f9c14..3dd1246 100644 --- a/.gitignore +++ b/.gitignore @@ -1,51 +1,262 @@ -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -**/bin -**/obj -**/.vs - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# ========================= -# Operating System Files -# ========================= - -# OSX -# ========================= - -.DS_Store -.AppleDouble -.LSOverride - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk -*.txt -Source/BetterAnimalsTab/obj/Debug/BetterAnimalsTab.pdb -*.cache -*.pxd +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc +1.5/Assemblies/0Harmony.dll diff --git a/1.1/Assemblies/Numbers.dll b/1.1/Assemblies/Numbers.dll new file mode 100644 index 0000000..771b61e Binary files /dev/null and b/1.1/Assemblies/Numbers.dll differ diff --git a/1.1/Defs/MainTabDefs/kNumbers.xml b/1.1/Defs/MainTabDefs/kNumbers.xml new file mode 100644 index 0000000..5809ee8 --- /dev/null +++ b/1.1/Defs/MainTabDefs/kNumbers.xml @@ -0,0 +1,13 @@ + + + + + kNumbersOverviewTab + + See every possible stat on every colonist or prisoner in a single table. + Numbers.MainTabWindow_Numbers + 20 + Z + + + \ No newline at end of file diff --git a/1.1/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/1.1/Defs/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..fe1b4d6 --- /dev/null +++ b/1.1/Defs/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,275 @@ + + + + + + + Numbers_Age + Numbers.PawnColumnWorker_Age + true + + + + + Numbers_AnimalEggProgress + Numbers.PawnColumnWorker_AnimalEggProgress + true + + + + + Numbers_Milkfullness + Numbers.PawnColumnWorker_AnimalMilkFullness + true + + + + + Numbers_AnimalWoolGrowth + Numbers.PawnColumnWorker_AnimalWoolGrowth + true + + + + + Numbers_LeatherType + Numbers.PawnColumnWorker_LeatherType + true + + + + + Numbers_Race + Numbers.PawnColumnWorker_Race + true + + + + + Numbers_Backstory + Numbers.PawnColumnWorker_Backstory + true + + + + + Numbers_Psyfocus + Numbers.PawnColumnWorker_Psyfocus + true + + +
  • + + + + + Numbers_Entropy + Numbers.PawnColumnWorker_Entropy + true + + +
  • + + + + + Numbers_PsylinkLevel + Numbers.PawnColumnWorker_PsylinkLevel + true + + +
  • + + + + + Numbers_Equipment + Numbers.PawnColumnWorker_Equipment + true + + + + + Numbers_Inventory + Numbers.PawnColumnWorker_Inventory + true + + + + + Numbers_InventoryDropAll + Numbers.PawnColumnWorker_InventoryDropAll + true + + + + + Numbers_JobCurrent + Numbers.PawnColumnWorker_JobCurrent + true + + + + + Numbers_JobQueued + Numbers.PawnColumnWorker_JobQueued + true + + + + + Numbers_MentalState + Numbers.PawnColumnWorker_MentalState + true + + + + + Numbers_PrisonerInteraction + Numbers.PawnColumnWorker_PrisonerInteraction + true + true + + + + + Numbers_PrisonerRecruitmentDifficulty + Numbers.PawnColumnWorker_PrisonerRecruitmentDifficulty + true + + + + + Numbers_PrisonerResistance + Numbers.PawnColumnWorker_PrisonerResistance + true + + + + + Numbers_Pain + Numbers.PawnColumnWorker_Pain + true + + + + + Numbers_Bleedrate + Numbers.PawnColumnWorker_Bleedrate + true + + + + + Numbers_NeedsTreatment + Numbers.PawnColumnWorker_NeedsTreatment + true + + + + + Numbers_Operations + Numbers.PawnColumnWorker_OperationDropDown + true + + + + + Numbers_Forbidden + Numbers.PawnColumnWorker_Forbidden + true + + true + + + + Numbers_Inspiration + Numbers.PawnColumnWorker_Inspiration + true + + + + + Numbers_DiseaseProgress + Numbers.PawnColumnWorker_DiseaseProgression + true + + Disease immunity margin + 80 + + + + Numbers_ManhunterOnTameFailChance + Numbers.PawnColumnWorker_ManhunterOnTameFailChance + true + Revenge chance on tame fail + UI/Icons/Animal/Predator + 45 + + + + Numbers_Wildness + Numbers.PawnColumnWorker_AnimalWildness + true + + + + + Numbers_TameChance + Numbers.PawnColumnWorker_TameChance + true + + + + + Numbers_SelfTend + Numbers.PawnColumnWorker_SelfTend + true + true + Self-tend + UI/Icons/Trainables/Rescue + 45 + + + + Numbers_HediffList + Numbers.PawnColumnWorker_AllHediffs + true + UI/Buttons/DevRoot/ToggleTweak + Hediffs + 45 + + + + Numbers_Faction + Numbers.PawnColumnWorker_Faction + true + + + + + Numbers_AnimalFilthRate + Numbers.PawnColumnWorker_AnimalFilthRate + true + + + + + Numbers_Meditation + Numbers.PawnColumnWorker_Meditation + true + + +
  • + + + + + Numbers_Areas + Numbers.PawnColumnWorker_AllowedAreaWithMassAssign + true + + 350 + + + diff --git a/1.1/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml b/1.1/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml new file mode 100644 index 0000000..c1439f5 --- /dev/null +++ b/1.1/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml @@ -0,0 +1,85 @@ + + + + + EquipmentBearers + +
  • Numbers_Equipment
  • + + + + + LivingThings + +
  • Numbers_Age
  • +
  • Numbers_MentalState
  • +
  • Numbers_JobCurrent
  • +
  • Numbers_JobQueued
  • +
  • Numbers_HediffList
  • +
  • Numbers_InventoryDropAll
  • +
    +
    + + + Prisoners + +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerRecruitmentDifficulty
  • +
  • Numbers_PrisonerResistance
  • +
  • FoodRestriction
  • +
  • Numbers_Inventory
  • +
    +
    + + + Animals + +
  • Numbers_Milkfullness
  • +
  • Numbers_AnimalWoolGrowth
  • +
  • Numbers_AnimalEggProgress
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_Inventory
  • +
  • Numbers_LeatherType
  • +
  • Numbers_AnimalFilthRate
  • +
  • Numbers_Areas
  • + +
    +
    + + + MainTable + +
  • Numbers_Inspiration
  • +
  • Numbers_Inventory
  • +
  • Numbers_SelfTend
  • +
  • Numbers_Meditation
  • +
  • Numbers_Psyfocus
  • +
  • Numbers_Entropy
  • +
  • Numbers_PsylinkLevel
  • +
  • Numbers_Areas
  • + +
    +
    + + + WildAnimals + +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_LeatherType
  • +
  • Numbers_ManhunterOnTameFailChance
  • + +
    +
    + + + DeadThings + +
  • Numbers_Forbidden
  • +
  • Numbers_LeatherType
  • +
    +
    + + +
    \ No newline at end of file diff --git a/1.1/Defs/PawnTableDef/Numbers_PawnTableDef.xml b/1.1/Defs/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..b88de36 --- /dev/null +++ b/1.1/Defs/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,277 @@ + + + + + Numbers_MainTable + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Backstory
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_SkillDef_Construction
  • +
  • MedicalCare
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Patient
  • +
  • Numbers_Operations
  • +
  • Numbers_Inspiration
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Enemies + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_Pain
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Prisoners + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_MarketValue
  • +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerRecruitmentDifficulty
  • +
  • Numbers_PrisonerResistance
  • +
  • Numbers_MentalState
  • +
  • MedicalCare
  • +
  • FoodRestriction
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Corpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_Guests + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • + +
    + +
  • + true +
  • +
    +
    + + + Numbers_Animals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • Pregnant
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • FollowDrafted
  • +
  • FollowFieldwork
  • +
  • GapTiny
  • +
  • Master
  • +
  • Bond
  • +
  • Slaughter
  • +
  • Numbers_AnimalFilthRate
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Numbers_Areas
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WildAnimals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • Hunt
  • +
  • Tame
  • +
  • GapTiny
  • +
  • ManhunterOnDamageChance
  • +
  • Numbers_ManhunterOnTameFailChance
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Predator
  • +
  • Info
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_AnimalCorpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_CombatPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_Bleedrate
  • +
  • Numbers_Pain
  • +
  • Numbers_JobCurrent
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WorkTabPlusPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_WorkSpeedGlobal
  • +
  • WorkPriority_Patient
  • +
  • Numbers_NeedsTreatment
  • +
  • WorkPriority_Doctor
  • +
  • Numbers_RimWorld_StatDef_MedicalTendQuality
  • +
  • WorkPriority_PatientBedRest
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Warden
  • +
  • Numbers_RimWorld_StatDef_NegotiationAbility
  • +
  • WorkPriority_Handling
  • +
  • Numbers_RimWorld_StatDef_TameAnimalChance
  • +
  • WorkPriority_Cooking
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChance
  • +
  • WorkPriority_Hunting
  • +
  • Numbers_RimWorld_StatDef_HuntingStealth
  • +
  • WorkPriority_Construction
  • +
  • Numbers_RimWorld_StatDef_ConstructSuccessChance
  • +
  • WorkPriority_Growing
  • +
  • Numbers_RimWorld_StatDef_PlantWorkSpeed
  • +
  • WorkPriority_Mining
  • +
  • Numbers_RimWorld_StatDef_MiningSpeed
  • +
  • WorkPriority_PlantCutting
  • +
  • Numbers_RimWorld_StatDef_PlantHarvestYield
  • +
  • WorkPriority_Research
  • +
  • Numbers_RimWorld_StatDef_ResearchSpeed
  • +
  • Numbers_RimWorld_StatDef_GeneralLaborSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_ColonistNeedsPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Rest
  • +
  • Numbers_RimWorld_NeedDef_Beauty
  • +
  • Numbers_RimWorld_NeedDef_Comfort
  • +
  • Numbers_RimWorld_NeedDef_Outdoors
  • +
    + +
  • + true +
  • +
    +
    + +
    \ No newline at end of file diff --git a/1.3/Assemblies/Numbers.dll b/1.3/Assemblies/Numbers.dll new file mode 100644 index 0000000..c836a06 Binary files /dev/null and b/1.3/Assemblies/Numbers.dll differ diff --git a/1.3/Defs/MainTabDefs/kNumbers.xml b/1.3/Defs/MainTabDefs/kNumbers.xml new file mode 100644 index 0000000..5809ee8 --- /dev/null +++ b/1.3/Defs/MainTabDefs/kNumbers.xml @@ -0,0 +1,13 @@ + + + + + kNumbersOverviewTab + + See every possible stat on every colonist or prisoner in a single table. + Numbers.MainTabWindow_Numbers + 20 + Z + + + \ No newline at end of file diff --git a/1.3/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/1.3/Defs/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..0558e23 --- /dev/null +++ b/1.3/Defs/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,286 @@ + + + + + + + Numbers_Age + Numbers.PawnColumnWorker_Age + true + + + + + Numbers_AnimalEggProgress + Numbers.PawnColumnWorker_AnimalEggProgress + true + + + + + Numbers_Milkfullness + Numbers.PawnColumnWorker_AnimalMilkFullness + true + + + + + Numbers_AnimalWoolGrowth + Numbers.PawnColumnWorker_AnimalWoolGrowth + true + + + + + Numbers_LeatherType + Numbers.PawnColumnWorker_LeatherType + true + + + + + Numbers_Race + Numbers.PawnColumnWorker_Race + true + + + + + Numbers_Backstory + Numbers.PawnColumnWorker_Backstory + true + + + + + Numbers_Psyfocus + Numbers.PawnColumnWorker_Psyfocus + true + + +
  • + + + + + Numbers_Entropy + Numbers.PawnColumnWorker_Entropy + true + + +
  • + + + + + Numbers_PsylinkLevel + Numbers.PawnColumnWorker_PsylinkLevel + true + + +
  • + + + + + Numbers_Equipment + Numbers.PawnColumnWorker_Equipment + true + + + + + Numbers_Inventory + Numbers.PawnColumnWorker_Inventory + true + + + + + Numbers_InventoryDropAll + Numbers.PawnColumnWorker_InventoryDropAll + true + + + + + Numbers_JobCurrent + Numbers.PawnColumnWorker_JobCurrent + true + + + + + Numbers_JobQueued + Numbers.PawnColumnWorker_JobQueued + true + + + + + Numbers_MentalState + Numbers.PawnColumnWorker_MentalState + true + + + + + Numbers_PrisonerInteraction + Numbers.PawnColumnWorker_PrisonerInteraction + true + true + + + + + Numbers_PrisonerResistance + Numbers.PawnColumnWorker_PrisonerResistance + true + + + + + Numbers_Pain + Numbers.PawnColumnWorker_Pain + true + + + + + Numbers_Bleedrate + Numbers.PawnColumnWorker_Bleedrate + true + + + + + Numbers_NeedsTreatment + Numbers.PawnColumnWorker_NeedsTreatment + true + + + + + Numbers_Operations + Numbers.PawnColumnWorker_OperationDropDown + true + + + + + Numbers_Forbidden + Numbers.PawnColumnWorker_Forbidden + true + + true + + + + Numbers_Inspiration + Numbers.PawnColumnWorker_Inspiration + true + + + + + Numbers_DiseaseProgress + Numbers.PawnColumnWorker_DiseaseProgression + true + + Disease immunity margin + 80 + + + + Numbers_ManhunterOnTameFailChance + Numbers.PawnColumnWorker_ManhunterOnTameFailChance + true + Revenge chance on tame fail + UI/Icons/Animal/Predator + 45 + + + + Numbers_Wildness + Numbers.PawnColumnWorker_AnimalWildness + true + + + + + Numbers_TameChance + Numbers.PawnColumnWorker_TameChance + true + + + + + Numbers_SelfTend + Numbers.PawnColumnWorker_SelfTend + true + true + Self-tend + UI/Icons/Trainables/Rescue + 45 + + + + Numbers_HediffList + Numbers.PawnColumnWorker_AllHediffs + true + UI/Buttons/DevRoot/ToggleTweak + Hediffs + 45 + + + + Numbers_HediffBadList + Numbers.PawnColumnWorker_HediffIsBad + true + UI/Buttons/DevRoot/ToggleTweak + Bad hediffs + 45 + + + + Numbers_Faction + Numbers.PawnColumnWorker_Faction + true + + + + + Numbers_AnimalFilthRate + Numbers.PawnColumnWorker_AnimalFilthRate + true + + + + + Numbers_Meditation + Numbers.PawnColumnWorker_Meditation + true + + +
  • + + + + + Numbers_Areas + Numbers.PawnColumnWorker_AllowedAreaWithMassAssign + true + + 350 + + + + Numbers_Traits + Numbers.PawnColumnWorker_Trait + true + Traits + + 350 + + + diff --git a/1.3/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml b/1.3/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml new file mode 100644 index 0000000..6ecca42 --- /dev/null +++ b/1.3/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml @@ -0,0 +1,86 @@ + + + + + EquipmentBearers + +
  • Numbers_Equipment
  • +
  • Numbers_Meditation
  • +
  • Numbers_Traits
  • + + + + + LivingThings + +
  • Numbers_Age
  • +
  • Numbers_MentalState
  • +
  • Numbers_JobCurrent
  • +
  • Numbers_JobQueued
  • +
  • Numbers_HediffList
  • +
  • Numbers_HediffBadList
  • +
  • Numbers_InventoryDropAll
  • +
    +
    + + + Prisoners + +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • FoodRestriction
  • +
  • Numbers_Inventory
  • +
    +
    + + + Animals + +
  • Numbers_Milkfullness
  • +
  • Numbers_AnimalWoolGrowth
  • +
  • Numbers_AnimalEggProgress
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_Inventory
  • +
  • Numbers_LeatherType
  • +
  • Numbers_AnimalFilthRate
  • +
  • Numbers_Areas
  • + +
    +
    + + + MainTable + +
  • Numbers_Inspiration
  • +
  • Numbers_Inventory
  • +
  • Numbers_SelfTend
  • +
  • Numbers_Psyfocus
  • +
  • Numbers_Entropy
  • +
  • Numbers_PsylinkLevel
  • +
  • Numbers_Areas
  • + +
    +
    + + + WildAnimals + +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_LeatherType
  • +
  • Numbers_ManhunterOnTameFailChance
  • + +
    +
    + + + DeadThings + +
  • Numbers_Forbidden
  • +
  • Numbers_LeatherType
  • +
    +
    + + +
    \ No newline at end of file diff --git a/1.3/Defs/PawnTableDef/Numbers_PawnTableDef.xml b/1.3/Defs/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..189d6cf --- /dev/null +++ b/1.3/Defs/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,276 @@ + + + + + Numbers_MainTable + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Backstory
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_SkillDef_Construction
  • +
  • MedicalCare
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Patient
  • +
  • Numbers_Operations
  • +
  • Numbers_Inspiration
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Enemies + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_Pain
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Prisoners + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_MarketValue
  • +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • Numbers_MentalState
  • +
  • MedicalCare
  • +
  • FoodRestriction
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Corpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_Guests + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • + +
    + +
  • + true +
  • +
    +
    + + + Numbers_Animals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • Pregnant
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • FollowDrafted
  • +
  • FollowFieldwork
  • +
  • GapTiny
  • +
  • Master
  • +
  • Bond
  • +
  • Slaughter
  • +
  • Numbers_AnimalFilthRate
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Numbers_Areas
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WildAnimals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • Hunt
  • +
  • Tame
  • +
  • GapTiny
  • +
  • ManhunterOnDamageChance
  • +
  • Numbers_ManhunterOnTameFailChance
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Predator
  • +
  • Info
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_AnimalCorpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_CombatPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_Bleedrate
  • +
  • Numbers_Pain
  • +
  • Numbers_JobCurrent
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WorkTabPlusPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_WorkSpeedGlobal
  • +
  • WorkPriority_Patient
  • +
  • Numbers_NeedsTreatment
  • +
  • WorkPriority_Doctor
  • +
  • Numbers_RimWorld_StatDef_MedicalTendQuality
  • +
  • WorkPriority_PatientBedRest
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Warden
  • +
  • Numbers_RimWorld_StatDef_NegotiationAbility
  • +
  • WorkPriority_Handling
  • +
  • Numbers_RimWorld_StatDef_TameAnimalChance
  • +
  • WorkPriority_Cooking
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChance
  • +
  • WorkPriority_Hunting
  • +
  • Numbers_RimWorld_StatDef_HuntingStealth
  • +
  • WorkPriority_Construction
  • +
  • Numbers_RimWorld_StatDef_ConstructSuccessChance
  • +
  • WorkPriority_Growing
  • +
  • Numbers_RimWorld_StatDef_PlantWorkSpeed
  • +
  • WorkPriority_Mining
  • +
  • Numbers_RimWorld_StatDef_MiningSpeed
  • +
  • WorkPriority_PlantCutting
  • +
  • Numbers_RimWorld_StatDef_PlantHarvestYield
  • +
  • WorkPriority_Research
  • +
  • Numbers_RimWorld_StatDef_ResearchSpeed
  • +
  • Numbers_RimWorld_StatDef_GeneralLaborSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_ColonistNeedsPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Rest
  • +
  • Numbers_RimWorld_NeedDef_Beauty
  • +
  • Numbers_RimWorld_NeedDef_Comfort
  • +
  • Numbers_RimWorld_NeedDef_Outdoors
  • +
    + +
  • + true +
  • +
    +
    + +
    \ No newline at end of file diff --git a/1.4/Assemblies/0Harmony.dll b/1.4/Assemblies/0Harmony.dll new file mode 100644 index 0000000..e182535 Binary files /dev/null and b/1.4/Assemblies/0Harmony.dll differ diff --git a/1.4/Assemblies/Numbers.dll b/1.4/Assemblies/Numbers.dll new file mode 100644 index 0000000..2d5a821 Binary files /dev/null and b/1.4/Assemblies/Numbers.dll differ diff --git a/1.4/Defs/MainTabDefs/kNumbers.xml b/1.4/Defs/MainTabDefs/kNumbers.xml new file mode 100644 index 0000000..5809ee8 --- /dev/null +++ b/1.4/Defs/MainTabDefs/kNumbers.xml @@ -0,0 +1,13 @@ + + + + + kNumbersOverviewTab + + See every possible stat on every colonist or prisoner in a single table. + Numbers.MainTabWindow_Numbers + 20 + Z + + + \ No newline at end of file diff --git a/1.4/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/1.4/Defs/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..8b6da03 --- /dev/null +++ b/1.4/Defs/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,361 @@ + + + + + + + Numbers_Age + Numbers.PawnColumnWorker_Age + true + + + + + Numbers_AnimalEggProgress + Numbers.PawnColumnWorker_AnimalEggProgress + true + + + + + Numbers_Milkfullness + Numbers.PawnColumnWorker_AnimalMilkFullness + true + + + + + Numbers_AnimalWoolGrowth + Numbers.PawnColumnWorker_AnimalWoolGrowth + true + + + + + Numbers_LeatherType + Numbers.PawnColumnWorker_LeatherType + true + + + + + Numbers_Race + Numbers.PawnColumnWorker_Race + true + + + + + Numbers_Backstory + Numbers.PawnColumnWorker_Backstory + true + + + + + Numbers_Psyfocus + Numbers.PawnColumnWorker_Psyfocus + true + + +
  • + + + + + Numbers_Entropy + Numbers.PawnColumnWorker_Entropy + true + + +
  • + + + + + Numbers_PsylinkLevel + Numbers.PawnColumnWorker_PsylinkLevel + true + + +
  • + + + + + Numbers_Equipment + Numbers.PawnColumnWorker_Equipment + true + + + + + Numbers_Inventory + Numbers.PawnColumnWorker_Inventory + true + + + + + Numbers_InventoryDropAll + Numbers.PawnColumnWorker_InventoryDropAll + true + + + + + Numbers_JobCurrent + Numbers.PawnColumnWorker_JobCurrent + true + + + + + Numbers_JobQueued + Numbers.PawnColumnWorker_JobQueued + true + + + + + Numbers_MentalState + Numbers.PawnColumnWorker_MentalState + true + + + + + Numbers_PrisonerInteraction + Numbers.PawnColumnWorker_PrisonerInteraction + true + true + + + + + Numbers_PrisonerResistance + Numbers.PawnColumnWorker_PrisonerResistance + true + + + + + Numbers_Pain + Numbers.PawnColumnWorker_Pain + true + + + + + Numbers_Bleedrate + Numbers.PawnColumnWorker_Bleedrate + true + + + + + Numbers_NeedsTreatment + Numbers.PawnColumnWorker_NeedsTreatment + true + + + + + Numbers_Operations + Numbers.PawnColumnWorker_OperationDropDown + true + + + + + Numbers_Forbidden + Numbers.PawnColumnWorker_Forbidden + true + + true + + + + Numbers_Inspiration + Numbers.PawnColumnWorker_Inspiration + true + + + + + Numbers_DiseaseProgress + Numbers.PawnColumnWorker_DiseaseProgression + true + + Disease immunity margin + 80 + + + + Numbers_Wildness + Numbers.PawnColumnWorker_AnimalWildness + true + + + + + Numbers_TameChance + Numbers.PawnColumnWorker_TameChance + true + + + + + Numbers_SelfTend + Numbers.PawnColumnWorker_SelfTend + true + true + Self-tend + UI/Icons/Trainables/Rescue + 45 + + + + Numbers_HediffList + Numbers.PawnColumnWorker_AllHediffs + true + UI/Buttons/DevRoot/ToggleTweak + Hediffs + 45 + + + + Numbers_HediffBadList + Numbers.PawnColumnWorker_HediffIsBad + true + UI/Buttons/DevRoot/ToggleTweak + Bad hediffs + 45 + + + + Numbers_Faction + Numbers.PawnColumnWorker_Faction + true + + + + + Numbers_AnimalFilthRate + Numbers.PawnColumnWorker_AnimalFilthRate + true + + + + + Numbers_Meditation + Numbers.PawnColumnWorker_Meditation + true + + +
  • + + + + + Numbers_Areas + Numbers.PawnColumnWorker_AllowedAreaWithMassAssign + true + + 350 + + + + Numbers_Traits + Numbers.PawnColumnWorker_Trait + true + Traits + + 350 + + + + Numbers_Bandwidth + Numbers.PawnColumnWorker_Bandwidth + true + Bandwidth + + +
  • + + 200 + + + + Numbers_Endogenes + Numbers.PawnColumnWorker_Endogenes + true + Germline genes + + +
  • + + 350 + + + + Numbers_Xenogenes + Numbers.PawnColumnWorker_Xenogenes + true + Xenogenes + + +
  • + + 350 + + + + Numbers_GenesRegrowTime + Numbers.PawnColumnWorker_GenesRegrowTime + true + Genes Regrowing + + +
  • + + 80 + + + + Numbers_Guilt + Numbers.PawnColumnWorker_Guilt + true + Guilt + + 50 + + + + Numbers_Ideology + Numbers.PawnColumnWorker_Ideology + true + Ideology and certainty + + +
  • + + 200 + + + + Numbers_Strip + Numbers.PawnColumnWorker_Strip + Strip + + 50 + + + + Numbers_Recruitable + Numbers.PawnColumnWorker_Recruitable + + 50 + + + \ No newline at end of file diff --git a/1.4/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml b/1.4/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml new file mode 100644 index 0000000..6addce9 --- /dev/null +++ b/1.4/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml @@ -0,0 +1,93 @@ + + + + + EquipmentBearers + +
  • Numbers_Equipment
  • +
  • Numbers_Meditation
  • +
  • Numbers_Traits
  • +
  • Numbers_Strip
  • + + + + + LivingThings + +
  • Numbers_Age
  • +
  • Numbers_MentalState
  • +
  • Numbers_JobCurrent
  • +
  • Numbers_JobQueued
  • +
  • Numbers_HediffList
  • +
  • Numbers_HediffBadList
  • +
  • Numbers_InventoryDropAll
  • +
  • Numbers_Ideology
  • +
  • Numbers_Xenogenes
  • +
  • Numbers_Endogenes
  • +
  • Numbers_GenesRegrowTime
  • +
    +
    + + + Prisoners + +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • FoodRestriction
  • +
  • Numbers_Inventory
  • +
  • Numbers_Guilt
  • +
  • Numbers_Recruitable
  • +
    +
    + + + Animals + +
  • Numbers_Milkfullness
  • +
  • Numbers_AnimalWoolGrowth
  • +
  • Numbers_AnimalEggProgress
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_Inventory
  • +
  • Numbers_LeatherType
  • +
  • Numbers_AnimalFilthRate
  • +
  • Numbers_Areas
  • + +
    +
    + + + MainTable + +
  • Numbers_Inspiration
  • +
  • Numbers_Inventory
  • +
  • Numbers_SelfTend
  • +
  • Numbers_Psyfocus
  • +
  • Numbers_Entropy
  • +
  • Numbers_PsylinkLevel
  • +
  • Numbers_Areas
  • +
  • Numbers_Bandwidth
  • + +
    +
    + + + WildAnimals + +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_LeatherType
  • + +
    +
    + + + DeadThings + +
  • Numbers_Forbidden
  • +
  • Numbers_LeatherType
  • +
    +
    + + +
    \ No newline at end of file diff --git a/1.4/Defs/PawnTableDef/Numbers_PawnTableDef.xml b/1.4/Defs/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..5402ce4 --- /dev/null +++ b/1.4/Defs/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,277 @@ + + + + + Numbers_MainTable + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Backstory
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_SkillDef_Construction
  • +
  • MedicalCare
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Patient
  • +
  • Numbers_Operations
  • +
  • Numbers_Inspiration
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Enemies + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_Pain
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Prisoners + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_MarketValue
  • +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • Numbers_Recruitable
  • +
  • Numbers_MentalState
  • +
  • MedicalCare
  • +
  • FoodRestriction
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Corpses + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_Guests + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • + +
    + +
  • + true +
  • +
    +
    + + + Numbers_Animals + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Gender
  • +
  • LifeStage
  • +
  • Pregnant
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • FollowDrafted
  • +
  • FollowFieldwork
  • +
  • GapTiny
  • +
  • Master
  • +
  • Bond
  • +
  • Slaughter
  • +
  • Numbers_AnimalFilthRate
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Numbers_Areas
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WildAnimals + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Gender
  • +
  • LifeStage
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • Hunt
  • +
  • Tame
  • +
  • GapTiny
  • +
  • ManhunterOnDamageChance
  • +
  • ManhunterOnTameFailChance
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Predator
  • +
  • Info
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_AnimalCorpses + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_CombatPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_Bleedrate
  • +
  • Numbers_Pain
  • +
  • Numbers_JobCurrent
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WorkTabPlusPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_WorkSpeedGlobal
  • +
  • WorkPriority_Patient
  • +
  • Numbers_NeedsTreatment
  • +
  • WorkPriority_Doctor
  • +
  • Numbers_RimWorld_StatDef_MedicalTendQuality
  • +
  • WorkPriority_PatientBedRest
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Warden
  • +
  • Numbers_RimWorld_StatDef_NegotiationAbility
  • +
  • WorkPriority_Handling
  • +
  • Numbers_RimWorld_StatDef_TameAnimalChance
  • +
  • WorkPriority_Cooking
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChance
  • +
  • WorkPriority_Hunting
  • +
  • Numbers_RimWorld_StatDef_HuntingStealth
  • +
  • WorkPriority_Construction
  • +
  • Numbers_RimWorld_StatDef_ConstructSuccessChance
  • +
  • WorkPriority_Growing
  • +
  • Numbers_RimWorld_StatDef_PlantWorkSpeed
  • +
  • WorkPriority_Mining
  • +
  • Numbers_RimWorld_StatDef_MiningSpeed
  • +
  • WorkPriority_PlantCutting
  • +
  • Numbers_RimWorld_StatDef_PlantHarvestYield
  • +
  • WorkPriority_Research
  • +
  • Numbers_RimWorld_StatDef_ResearchSpeed
  • +
  • Numbers_RimWorld_StatDef_GeneralLaborSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_ColonistNeedsPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Rest
  • +
  • Numbers_RimWorld_NeedDef_Beauty
  • +
  • Numbers_RimWorld_NeedDef_Comfort
  • +
  • Numbers_RimWorld_NeedDef_Outdoors
  • +
    + +
  • + true +
  • +
    +
    + +
    \ No newline at end of file diff --git a/1.5/Assemblies/Numbers.dll b/1.5/Assemblies/Numbers.dll new file mode 100644 index 0000000..6b20635 Binary files /dev/null and b/1.5/Assemblies/Numbers.dll differ diff --git a/1.5/Defs/MainTabDefs/kNumbers.xml b/1.5/Defs/MainTabDefs/kNumbers.xml new file mode 100644 index 0000000..5809ee8 --- /dev/null +++ b/1.5/Defs/MainTabDefs/kNumbers.xml @@ -0,0 +1,13 @@ + + + + + kNumbersOverviewTab + + See every possible stat on every colonist or prisoner in a single table. + Numbers.MainTabWindow_Numbers + 20 + Z + + + \ No newline at end of file diff --git a/1.5/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/1.5/Defs/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..704e060 --- /dev/null +++ b/1.5/Defs/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,381 @@ + + + + + + + Numbers_Age + Numbers.PawnColumnWorker_Age + true + + + + + Numbers_AnimalEggProgress + Numbers.PawnColumnWorker_AnimalEggProgress + true + + + + + Numbers_Milkfullness + Numbers.PawnColumnWorker_AnimalMilkFullness + true + + + + + Numbers_AnimalWoolGrowth + Numbers.PawnColumnWorker_AnimalWoolGrowth + true + + + + + Numbers_LeatherType + Numbers.PawnColumnWorker_LeatherType + true + + + + + Numbers_Race + Numbers.PawnColumnWorker_Race + true + + + + + Numbers_Backstory + Numbers.PawnColumnWorker_Backstory + true + + + + + Numbers_Psyfocus + Numbers.PawnColumnWorker_Psyfocus + true + + +
  • + + + + + Numbers_Entropy + Numbers.PawnColumnWorker_Entropy + true + + +
  • + + + + + Numbers_PsylinkLevel + Numbers.PawnColumnWorker_PsylinkLevel + true + + +
  • + + + + + Numbers_Equipment + Numbers.PawnColumnWorker_Equipment + true + + + + + Numbers_Inventory + Numbers.PawnColumnWorker_Inventory + true + + + + + Numbers_InventoryDropAll + Numbers.PawnColumnWorker_InventoryDropAll + true + + + + + Numbers_JobCurrent + Numbers.PawnColumnWorker_JobCurrent + true + + + + + Numbers_JobQueued + Numbers.PawnColumnWorker_JobQueued + true + + + + + Numbers_MentalState + Numbers.PawnColumnWorker_MentalState + true + + + + + Numbers_PrisonerInteraction + Numbers.PawnColumnWorker_PrisonerInteraction + true + true + + + + + Numbers_PrisonerResistance + Numbers.PawnColumnWorker_PrisonerResistance + true + + + + + Numbers_Pain + Numbers.PawnColumnWorker_Pain + true + + + + + Numbers_Bleedrate + Numbers.PawnColumnWorker_Bleedrate + true + + + + + Numbers_NeedsTreatment + Numbers.PawnColumnWorker_NeedsTreatment + true + + + + + Numbers_Operations + Numbers.PawnColumnWorker_OperationDropDown + true + + + + + Numbers_Forbidden + Numbers.PawnColumnWorker_Forbidden + true + + true + + + + Numbers_Inspiration + Numbers.PawnColumnWorker_Inspiration + true + + + + + Numbers_DiseaseProgress + Numbers.PawnColumnWorker_DiseaseProgression + true + + Disease immunity margin + 80 + + + + Numbers_Wildness + Numbers.PawnColumnWorker_AnimalWildness + true + + + + + Numbers_TameChance + Numbers.PawnColumnWorker_TameChance + true + + + + + Numbers_SelfTend + Numbers.PawnColumnWorker_SelfTend + true + true + Self-tend + UI/Icons/Trainables/Rescue + 45 + + + + Numbers_HediffList + Numbers.PawnColumnWorker_AllHediffs + true + UI/Buttons/DevRoot/ToggleTweak + Hediffs + 45 + + + + Numbers_HediffBadList + Numbers.PawnColumnWorker_HediffIsBad + true + UI/Buttons/DevRoot/ToggleTweak + Bad hediffs + 45 + + + + Numbers_Faction + Numbers.PawnColumnWorker_Faction + true + + + + + Numbers_AnimalFilthRate + Numbers.PawnColumnWorker_AnimalFilthRate + true + + + + + Numbers_Meditation + Numbers.PawnColumnWorker_Meditation + true + + +
  • + + + + + Numbers_Areas + Numbers.PawnColumnWorker_AllowedAreaWithMassAssign + true + + 350 + + + + Numbers_Traits + Numbers.PawnColumnWorker_Trait + true + Traits + + 350 + + + + Numbers_Bandwidth + Numbers.PawnColumnWorker_Bandwidth + true + Bandwidth + + +
  • + + 200 + + + + Numbers_Endogenes + Numbers.PawnColumnWorker_Endogenes + true + Germline genes + + +
  • + + 350 + + + + Numbers_Xenogenes + Numbers.PawnColumnWorker_Xenogenes + true + Xenogenes + + +
  • + + 350 + + + + Numbers_GenesRegrowTime + Numbers.PawnColumnWorker_GenesRegrowTime + true + Genes Regrowing + + +
  • + + 80 + + + + Numbers_Guilt + Numbers.PawnColumnWorker_Guilt + true + Guilt + + 50 + + + + Numbers_Ideology + Numbers.PawnColumnWorker_Ideology + true + Ideology and certainty + + +
  • + + 200 + + + + Numbers_Will + Numbers.PawnColumnWorker_Will + true + + +
  • + + 50 + + + + Numbers_FoodConsumption + Numbers.PawnColumnWorker_FoodConsumption + true + Food consumption + + 80 + + + + Numbers_Strip + Numbers.PawnColumnWorker_Strip + Strip + + 50 + + + + Numbers_Recruitable + Numbers.PawnColumnWorker_Recruitable + + 50 + + + \ No newline at end of file diff --git a/1.5/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml b/1.5/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml new file mode 100644 index 0000000..182633f --- /dev/null +++ b/1.5/Defs/PawnColumnOptionDef/Numbers_PawnColumnOptionDef.xml @@ -0,0 +1,96 @@ + + + + + EquipmentBearers + +
  • Numbers_Equipment
  • +
  • Numbers_Meditation
  • +
  • Numbers_Traits
  • +
  • Numbers_Strip
  • + + + + + LivingThings + +
  • Numbers_Age
  • +
  • Numbers_MentalState
  • +
  • Numbers_JobCurrent
  • +
  • Numbers_JobQueued
  • +
  • Numbers_HediffList
  • +
  • Numbers_HediffBadList
  • +
  • Numbers_InventoryDropAll
  • +
  • Numbers_Ideology
  • +
  • Numbers_Xenogenes
  • +
  • Xenotype
  • +
  • Numbers_Endogenes
  • +
  • Numbers_GenesRegrowTime
  • +
  • Numbers_FoodConsumption
  • +
    +
    + + + Prisoners + +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • FoodRestriction
  • +
  • Numbers_Inventory
  • +
  • Numbers_Guilt
  • +
  • Numbers_Recruitable
  • +
  • Numbers_Will
  • +
    +
    + + + Animals + +
  • Numbers_Milkfullness
  • +
  • Numbers_AnimalWoolGrowth
  • +
  • Numbers_AnimalEggProgress
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_Inventory
  • +
  • Numbers_LeatherType
  • +
  • Numbers_AnimalFilthRate
  • +
  • Numbers_Areas
  • + +
    +
    + + + MainTable + +
  • Numbers_Inspiration
  • +
  • Numbers_Inventory
  • +
  • Numbers_SelfTend
  • +
  • Numbers_Psyfocus
  • +
  • Numbers_Entropy
  • +
  • Numbers_PsylinkLevel
  • +
  • Numbers_Areas
  • +
  • Numbers_Bandwidth
  • + +
    +
    + + + WildAnimals + +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Numbers_LeatherType
  • + +
    +
    + + + DeadThings + +
  • Numbers_Forbidden
  • +
  • Numbers_LeatherType
  • +
    +
    + + +
    \ No newline at end of file diff --git a/1.5/Defs/PawnTableDef/Numbers_PawnTableDef.xml b/1.5/Defs/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..5af3ca8 --- /dev/null +++ b/1.5/Defs/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,279 @@ + + + + + Numbers_MainTable + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Backstory
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_SkillDef_Construction
  • +
  • MedicalCare
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Patient
  • +
  • Numbers_Operations
  • +
  • Numbers_Inspiration
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Enemies + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_Pain
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
    + +
  • + true +
  • +
    + 1148 +
    + + + Numbers_Prisoners + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_MarketValue
  • +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerResistance
  • +
  • Numbers_Will
  • +
  • Numbers_Recruitable
  • +
  • Numbers_MentalState
  • +
  • MedicalCare
  • +
  • FoodRestriction
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Corpses + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_Guests + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_Equipment
  • + +
    + +
  • + true +
  • +
    +
    + + + Numbers_Animals + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Gender
  • +
  • LifeStage
  • +
  • Pregnant
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • FollowDrafted
  • +
  • FollowFieldwork
  • +
  • GapTiny
  • +
  • Master
  • +
  • Bond
  • +
  • Slaughter
  • +
  • Numbers_AnimalFilthRate
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Numbers_Areas
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WildAnimals + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Gender
  • +
  • LifeStage
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • Hunt
  • +
  • Tame
  • +
  • GapTiny
  • +
  • ManhunterOnDamageChance
  • +
  • ManhunterOnTameFailChance
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Predator
  • +
  • Info
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
  • Numbers_FoodConsumption
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_AnimalCorpses + + Numbers.PawnTable_NumbersMain + +
  • LabelWithIcon
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_LeatherType
  • +
    + +
  • + true + true +
  • +
    + 700 +
    + + + Numbers_CombatPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_Bleedrate
  • +
  • Numbers_Pain
  • +
  • Numbers_JobCurrent
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WorkTabPlusPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_StatDef_WorkSpeedGlobal
  • +
  • WorkPriority_Patient
  • +
  • Numbers_NeedsTreatment
  • +
  • WorkPriority_Doctor
  • +
  • Numbers_RimWorld_StatDef_MedicalTendQuality
  • +
  • WorkPriority_PatientBedRest
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Warden
  • +
  • Numbers_RimWorld_StatDef_NegotiationAbility
  • +
  • WorkPriority_Handling
  • +
  • Numbers_RimWorld_StatDef_TameAnimalChance
  • +
  • WorkPriority_Cooking
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChance
  • +
  • WorkPriority_Hunting
  • +
  • Numbers_RimWorld_StatDef_HuntingStealth
  • +
  • WorkPriority_Construction
  • +
  • Numbers_RimWorld_StatDef_ConstructSuccessChance
  • +
  • WorkPriority_Growing
  • +
  • Numbers_RimWorld_StatDef_PlantWorkSpeed
  • +
  • WorkPriority_Mining
  • +
  • Numbers_RimWorld_StatDef_MiningSpeed
  • +
  • WorkPriority_PlantCutting
  • +
  • Numbers_RimWorld_StatDef_PlantHarvestYield
  • +
  • WorkPriority_Research
  • +
  • Numbers_RimWorld_StatDef_ResearchSpeed
  • +
  • Numbers_RimWorld_StatDef_GeneralLaborSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_ColonistNeedsPreset + + Numbers.PawnTable_NumbersMain + +
  • LabelShortWithIcon
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Rest
  • +
  • Numbers_RimWorld_NeedDef_Beauty
  • +
  • Numbers_RimWorld_NeedDef_Comfort
  • +
  • Numbers_RimWorld_NeedDef_Outdoors
  • +
    + +
  • + true +
  • +
    +
    + +
    \ No newline at end of file diff --git a/About/About.xml b/About/About.xml index 5530c5e..e6413a1 100644 --- a/About/About.xml +++ b/About/About.xml @@ -1,10 +1,24 @@ - Numbers - koisama - http://steamcommunity.com/sharedfiles/filedetails/?id=939597551 - 0.18.1712 - -Adds a customizable general overview tab, allowing you to see any stats on all your colonists or prisoners in a single window. - + Numbers + Mehni + https://github.com/Mehni/kNumbers + Mehni.Numbers + +
  • + brrainz.harmony + Harmony + steam://url/CommunityFilePage/2009463077 + https://github.com/pardeike/HarmonyRimWorld/releases/latest +
  • +
    + +
  • 1.0
  • +
  • 1.1
  • +
  • 1.2
  • +
  • 1.3
  • +
  • 1.4
  • +
  • 1.5
  • +
    + Adds a customizable general overview tab, allowing you to see any stats on all your colonists or prisoners in a single window. Original by koisama. Updated, expanded and maintained by Mehni.
    \ No newline at end of file diff --git a/About/PublishedFileId.txt b/About/PublishedFileId.txt new file mode 100644 index 0000000..2530495 --- /dev/null +++ b/About/PublishedFileId.txt @@ -0,0 +1 @@ +1414302321 \ No newline at end of file diff --git a/About/preview.png b/About/preview.png new file mode 100644 index 0000000..9a6a2c6 Binary files /dev/null and b/About/preview.png differ diff --git a/Assemblies/0Harmony.dll b/Assemblies/0Harmony.dll new file mode 100644 index 0000000..6c0dd94 Binary files /dev/null and b/Assemblies/0Harmony.dll differ diff --git a/Assemblies/Numbers.dll b/Assemblies/Numbers.dll new file mode 100644 index 0000000..085e386 Binary files /dev/null and b/Assemblies/Numbers.dll differ diff --git a/Assemblies/RWNumbers.dll b/Assemblies/RWNumbers.dll deleted file mode 100644 index 0dade6e..0000000 Binary files a/Assemblies/RWNumbers.dll and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 5ac0e4c..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,60 +0,0 @@ -# CHANGELOG - -## 0.6.3 -Fixed https://github.com/koisama/kNumbers/issues/21 - - probably related: fixed animals, corpses, enemies and other tabs not displaying contents sometimes -Implemented https://github.com/koisama/kNumbers/issues/19 - - press alt to select colonist without camera jump -Implemented https://github.com/koisama/kNumbers/issues/18 - - press shift and click to select multiple colonists - -## 0.6.1 -Merged capacities patch - works just like medical info -Merged Spanish translation -Merged Russian translation - -## 0.6.0 -Updated to A16 (0.16.1393) - -## 0.5.2 -Updated to A15b (0.15.1280) -Added drug needs -Added mental state (other) - -## 0.5.1 -Fixed need bar overflowing -Built against 0.14.1238, also works on steam 0.14.1241 - -## 0.5.0 -Updated to A14 (0.14.1234) - -## 0.4.4-A13 -Fixed the tab sometimes not loading saved layouts -Added "age" column definition - -## 0.4.3.1-A13 -Fixed current job text not fitting the column -Minor GUI improvements - -## 0.4.3-A13 -Fixed a crash under Linux -Added "current job" column definition -Minor GUI improvements - tab will now occupy all available horizontal space and display line count, stats are now alphabetically sorted - -## 0.4.1-A13 -Updated to A13 -Added new categories: Guests, Corpses, Animal Corpses - -## 0.3-A12d -Settings (chosen columns) are now stored in a save. - -## 0.2.1-A12d: -Added a tooltip for displayed equipment - -## 0.2-A12d: -Added prisoner interaction and food, medical care level controls -Added equipment column -Various bugfixes - -## 0.1-A12d: -Initial release diff --git a/Defs/MainTabDefs/kNumbers.xml b/Defs/MainTabDefs/kNumbers.xml index e2bbbe2..5809ee8 100644 --- a/Defs/MainTabDefs/kNumbers.xml +++ b/Defs/MainTabDefs/kNumbers.xml @@ -5,8 +5,9 @@ kNumbersOverviewTab See every possible stat on every colonist or prisoner in a single table. - kNumbers.MainTabWindow_Numbers + Numbers.MainTabWindow_Numbers 20 + Z - + \ No newline at end of file diff --git a/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/Defs/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..d79cd4d --- /dev/null +++ b/Defs/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,206 @@ + + + + + + + Numbers_Age + Numbers.PawnColumnWorker_Age + true + + + + + Numbers_AnimalEggProgress + Numbers.PawnColumnWorker_AnimalEggProgress + true + + + + + Numbers_Milkfullness + Numbers.PawnColumnWorker_AnimalMilkFullness + true + + + + + Numbers_AnimalWoolGrowth + Numbers.PawnColumnWorker_AnimalWoolGrowth + true + + + + + Numbers_Race + Numbers.PawnColumnWorker_Race + true + + + + + Numbers_Backstory + Numbers.PawnColumnWorker_Backstory + true + + + + + Numbers_Equipment + Numbers.PawnColumnWorker_Equipment + true + + + + + Numbers_Inventory + Numbers.PawnColumnWorker_Inventory + true + + + + + Numbers_JobCurrent + Numbers.PawnColumnWorker_JobCurrent + true + + + + + Numbers_JobQueued + Numbers.PawnColumnWorker_JobQueued + true + + + + + Numbers_MentalState + Numbers.PawnColumnWorker_MentalState + true + + + + + Numbers_PrisonerInteraction + Numbers.PawnColumnWorker_PrisonerInteraction + true + true + + + + + Numbers_PrisonerRecruitmentDifficulty + Numbers.PawnColumnWorker_PrisonerRecruitmentDifficulty + true + + + + + Numbers_PrisonerResistance + Numbers.PawnColumnWorker_PrisonerResistance + true + + + + + Numbers_Pain + Numbers.PawnColumnWorker_Pain + true + + + + + Numbers_Bleedrate + Numbers.PawnColumnWorker_Bleedrate + true + + + + + Numbers_NeedsTreatment + Numbers.PawnColumnWorker_NeedsTreatment + true + + + + + Numbers_Operations + Numbers.PawnColumnWorker_OperationDropDown + true + + + + + Numbers_Forbidden + Numbers.PawnColumnWorker_Forbidden + true + + true + + + + Numbers_Inspiration + Numbers.PawnColumnWorker_Inspiration + true + + + + + Numbers_DiseaseProgress + Numbers.PawnColumnWorker_DiseaseProgression + true + + Disease immunity margin + 80 + + + + Numbers_ManhunterOnTameFailChance + Numbers.PawnColumnWorker_ManhunterOnTameFailChance + true + Revenge chance on tame fail + UI/Icons/Animal/Predator + 45 + + + + Numbers_Wildness + Numbers.PawnColumnWorker_AnimalWildness + true + + + + + Numbers_TameChance + Numbers.PawnColumnWorker_TameChance + true + + + + + Numbers_SelfTend + Numbers.PawnColumnWorker_SelfTend + true + true + Self-tend + UI/Icons/Trainables/Rescue + 45 + + + + Numbers_HediffList + Numbers.PawnColumnWorker_AllHediffs + true + UI/Buttons/DevRoot/ToggleTweak + Hediffs + 45 + + + + Numbers_Faction + Numbers.PawnColumnWorker_Faction + true + + + + \ No newline at end of file diff --git a/Defs/PawnTableDef/Numbers_PawnTableDef.xml b/Defs/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..1b53959 --- /dev/null +++ b/Defs/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,274 @@ + + + + + Numbers_MainTable + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Backstory
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_SkillDef_Construction
  • +
  • MedicalCare
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Patient
  • +
  • Numbers_Operations
  • +
  • Numbers_Inspiration
  • +
    + +
  • + true +
  • +
    + 1032 +
    + + + Numbers_Enemies + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_Pain
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Prisoners + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_MarketValue
  • +
  • Numbers_PrisonerInteraction
  • +
  • Numbers_PrisonerRecruitmentDifficulty
  • +
  • Numbers_PrisonerResistance
  • +
  • Numbers_MentalState
  • +
  • MedicalCare
  • +
  • FoodRestriction
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_Corpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 600 +
    + + + Numbers_Guests + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Equipment
  • + +
    + +
  • + true +
  • +
    +
    + + + Numbers_Animals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • Pregnant
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • FollowDrafted
  • +
  • FollowFieldwork
  • +
  • GapTiny
  • +
  • Master
  • +
  • Bond
  • +
  • Slaughter
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Numbers_Areas
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WildAnimals + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Gender
  • +
  • LifeStage
  • +
  • GapTiny
  • +
  • GapTiny
  • +
  • Hunt
  • +
  • Tame
  • +
  • GapTiny
  • +
  • ManhunterOnDamageChance
  • +
  • Numbers_ManhunterOnTameFailChance
  • +
  • Numbers_Wildness
  • +
  • Numbers_TameChance
  • +
  • Predator
  • +
  • Info
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_AnimalCorpses + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_Forbidden
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChanceFixedHuman
  • +
  • Numbers_RimWorld_StatDef_MeatAmount
  • +
  • Numbers_RimWorld_StatDef_LeatherAmount
  • +
    + +
  • + true + true +
  • +
    + 600 +
    + + + Numbers_CombatPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_AimingDelayFactor
  • +
  • Numbers_Equipment
  • +
  • Numbers_RimWorld_StatDef_ShootingAccuracyPawn
  • +
  • Numbers_RimWorld_RecordDef_Kills
  • +
  • Numbers_RimWorld_StatDef_MoveSpeed
  • +
  • Numbers_RimWorld_StatDef_MeleeDPS
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_Bleedrate
  • +
  • Numbers_Pain
  • +
  • Numbers_JobCurrent
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_WorkTabPlusPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_StatDef_WorkSpeedGlobal
  • +
  • WorkPriority_Patient
  • +
  • Numbers_NeedsTreatment
  • +
  • WorkPriority_Doctor
  • +
  • Numbers_RimWorld_StatDef_MedicalTendQuality
  • +
  • WorkPriority_PatientBedRest
  • +
  • Numbers_DiseaseProgress
  • +
  • WorkPriority_Warden
  • +
  • Numbers_RimWorld_StatDef_NegotiationAbility
  • +
  • WorkPriority_Handling
  • +
  • Numbers_RimWorld_StatDef_TameAnimalChance
  • +
  • WorkPriority_Cooking
  • +
  • Numbers_RimWorld_StatDef_FoodPoisonChance
  • +
  • WorkPriority_Hunting
  • +
  • Numbers_RimWorld_StatDef_HuntingStealth
  • +
  • WorkPriority_Construction
  • +
  • Numbers_RimWorld_StatDef_ConstructSuccessChance
  • +
  • WorkPriority_Growing
  • +
  • Numbers_RimWorld_StatDef_PlantWorkSpeed
  • +
  • WorkPriority_Mining
  • +
  • Numbers_RimWorld_StatDef_MiningSpeed
  • +
  • WorkPriority_PlantCutting
  • +
  • Numbers_RimWorld_StatDef_PlantHarvestYield
  • +
  • WorkPriority_Smithing
  • +
  • Numbers_RimWorld_StatDef_SmithingSpeed
  • +
  • WorkPriority_Research
  • +
  • Numbers_RimWorld_StatDef_ResearchSpeed
  • +
    + +
  • + true +
  • +
    +
    + + + Numbers_ColonistNeedsPreset + + Numbers.PawnTable_NumbersMain + +
  • Label
  • +
  • Numbers_RimWorld_NeedDef_Mood
  • +
  • Numbers_RimWorld_NeedDef_Food
  • +
  • Numbers_RimWorld_NeedDef_Rest
  • +
  • Numbers_RimWorld_NeedDef_Beauty
  • +
  • Numbers_RimWorld_NeedDef_Comfort
  • +
  • Numbers_RimWorld_NeedDef_Outdoors
  • +
    + +
  • + true +
  • +
    +
    + +
    \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..41a9585 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Mehni. With acknowledgement of the original idea and first implementation of Numbers by koisama as found on https://github.com/koisama/kNumbers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml b/Languages/ChineseSimplified/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml new file mode 100644 index 0000000..6355f15 --- /dev/null +++ b/Languages/ChineseSimplified/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml @@ -0,0 +1,9 @@ + + + + + + 切换数值标签 + + + \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/MainTabDef/kNumbers.xml b/Languages/ChineseSimplified/DefInjected/MainButtonDef/kNumbers.xml similarity index 75% rename from Languages/ChineseSimplified/DefInjected/MainTabDef/kNumbers.xml rename to Languages/ChineseSimplified/DefInjected/MainButtonDef/kNumbers.xml index c3346c6..614f0ff 100644 --- a/Languages/ChineseSimplified/DefInjected/MainTabDef/kNumbers.xml +++ b/Languages/ChineseSimplified/DefInjected/MainButtonDef/kNumbers.xml @@ -1,8 +1,8 @@ - - - - 数值 - - 查看每个殖民者与囚犯的属性。 - - + + + + 数值 + 查看每个殖民者与囚犯的属性。 + + + \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml b/Languages/ChineseSimplified/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..1bc8881 --- /dev/null +++ b/Languages/ChineseSimplified/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,28 @@ + + + + + + 年龄 + 产蛋进度 + 产奶进度 + 毛发生长进度 + 种族 + 标题 + 装备 + 当前工作 + 等待处理 + 精神状况 + 囚犯互动 + 招募难度 + 招募抵抗 + 疼痛 + 失血速率 + 需要治疗 + 手术 + 禁止 + 灵感 + 免疫裕度 + + + \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml b/Languages/ChineseSimplified/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..2bf6094 --- /dev/null +++ b/Languages/ChineseSimplified/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,16 @@ + + + + 殖民者 + 敌人 + 囚犯 + 尸体 + 访客 + 动物 + 野生动物 + 动物尸体 + 战斗 + 工作 + + + \ No newline at end of file diff --git a/Languages/ChineseSimplified/Keyed/Keys.xml b/Languages/ChineseSimplified/Keyed/Keys.xml index 1114073..351e4f7 100644 --- a/Languages/ChineseSimplified/Keyed/Keys.xml +++ b/Languages/ChineseSimplified/Keyed/Keys.xml @@ -1,33 +1,34 @@ - - - - 属性 - 名称 - 行数 - 点击切换对象类型。 - 点击以{0}进行排序。 - 右键点击删除列。 - 添加统计 - 添加技能 - 添加需求 - 添加其他 - 预设 - - 当前工作 - 装备 - 囚犯互动 - 狱卒该如何看待这名囚犯。 - 医疗保健 - 年龄 - 精神状态 - - 殖民者 - 敌人 - 囚犯 - 访客 - 动物 - 野生动物 - 尸体 - 动物尸体 - - + + + + 数值概览 + 行数 + 点击选择 pawn 的类型。 + 右键点击来移除列。 + 预设 + + + 载入 {0} 预设 + 医疗 + 战斗 + 工作 + 殖民者需求 + + 设置为默认 + 设置现在的布局为当前 pawn ({0})的默认布局,新建的殖民地将使用这样的布局。可以在MOD选项中删除。(菜单 => 选项 => Mod选项 => Numbers)。 + 当前的 pawn 没有保存的默认设置。 + 载入默认设置 + + 显示那些通常会被隐藏的需求和工作。 + 数值MOD有所有野生动物标签MOD的功能,我想用数值MOD取代野生动物MOD。 + 允许数值MOD使用的最大屏幕垂直空间。 + 鼠标左键点击pawn列表来选取他们。(以前的改为Alt加左键) + 使选取方式非常直观。按Esc键关闭窗口\n\nShift加左键:多选。\n双击使镜头中心对准目标。\n右键选择单个pawn。 \nAlt加左键将关闭窗口并查看单个pawn的情况。 \n注意:此种选择方式应用于所有有关Pawn的tab,而不仅仅是数值tab。 + 高亮被选取的pawn。 + 注意:此种选择方式应用于所有有关Pawn的tab,而不仅仅是数值tab。 + + 载入布局存档 + 没有布局存档 + 保存当前布局 + + \ No newline at end of file diff --git a/Languages/ChineseTraditional/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml b/Languages/ChineseTraditional/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml new file mode 100644 index 0000000..31bb220 --- /dev/null +++ b/Languages/ChineseTraditional/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml @@ -0,0 +1,4 @@ + + + 切換數字標籤 + diff --git a/Languages/ChineseTraditional/DefInjected/MainButtonDef/kNumbers.xml b/Languages/ChineseTraditional/DefInjected/MainButtonDef/kNumbers.xml new file mode 100644 index 0000000..c23f743 --- /dev/null +++ b/Languages/ChineseTraditional/DefInjected/MainButtonDef/kNumbers.xml @@ -0,0 +1,5 @@ + + + Numbers + 在單一表格中查看每個殖民者或囚犯的所有可能狀態。 + diff --git a/Languages/ChineseTraditional/DefInjected/MainTabDef/kNumbers.xml b/Languages/ChineseTraditional/DefInjected/MainTabDef/kNumbers.xml deleted file mode 100644 index a952d57..0000000 --- a/Languages/ChineseTraditional/DefInjected/MainTabDef/kNumbers.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - 數值 - - 查看每個殖民者與囚犯的屬性。 - - diff --git a/Languages/ChineseTraditional/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml b/Languages/ChineseTraditional/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..9a896da --- /dev/null +++ b/Languages/ChineseTraditional/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,63 @@ + + + 年齡 + 產蛋進度 + 產奶進度 + 產毛進度 + 種族 + 背景 + 裝備 + 物品 + 目前工作 + 排程工作 + 心理狀態 + 囚犯互動 + 招募難度 + 反抗 + 痛苦 + 出血率 + 需要治療 + 手術 + 禁止 + 靈感 + 免疫程度 + 免疫程度 + 訓服失敗反擊機率 + 野性 + 訓服機率 + 自我照顧 + 心理變化 + 派系 + + 排泄 + 活動區 + 頻寬 + 頻寬 + 種系基因 + 種系基因 + 神經熱 + 基因再生 + 基因再生 + 有罪 + 有罪 + 身體狀態(負面) + 身體狀態(全部) + 理念 + 理念 + 丟棄攜帶物品 + 皮革 + 冥想類型 + 靈能 + 靈能等級 + 可招募 + 脫下衣物 + 脫下衣物 + + + 特性 + 特性 + + 異種基因 + 異種基因 + + diff --git a/Languages/ChineseTraditional/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml b/Languages/ChineseTraditional/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..59f58cf --- /dev/null +++ b/Languages/ChineseTraditional/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,14 @@ + + + 殖民者 + 敵人 + 囚犯 + 屍體 + 訪客 + 動物 + 野生動物 + 動物屍體 + 戰鬥 + 工作 + 預設殖民者需求 + diff --git a/Languages/ChineseTraditional/Keyed/Keys.xml b/Languages/ChineseTraditional/Keyed/Keys.xml index 4209de2..eea6b2d 100644 --- a/Languages/ChineseTraditional/Keyed/Keys.xml +++ b/Languages/ChineseTraditional/Keyed/Keys.xml @@ -1,33 +1,30 @@ - + - - 屬性 - 名稱 - 行數 - 點擊切換對象類型。 - 點擊以{0}進行排序。 - 右鍵點擊刪除列。 - 添加統計 - 添加技能 - 添加需求 - 添加其他 + 數字概觀 + 數量 + 點擊選擇單位類型。 + 點擊右鍵移除欄位,拖曳以移動。 預設 - - 當前工作 - 裝備 - 囚犯互動 - 獄卒該如何看待這名囚犯。 - 醫療保健 - 年齡 - 精神狀態 - - 殖民者 - 敵人 - 囚犯 - 訪客 - 動物 - 野生動物 - 屍體 - 動物屍體 - + 載入 {0} 預設 + 醫療 + 戰鬥 + 工作 + 殖民者需求 + 靈能 + 設定預設檢視 + 將目前的檢視設為此類型檢視的預設值({0})。\n\n然後此檢視將用於新殖民地。\n\n可以在mod設定中刪除:\n[選單] => [選項] => [模組設定] => [Numbers]。 + 對於目前檢視的小人類型,沒有儲存的預設值。 + 載入預設 + 顯示即使在通常隱藏的需求和工作。 + 取代內建的「野生動物」選單 + 取代內建的「動物」選單 + 最大高度相對於您的螢幕尺寸的數字視窗。 + 滑鼠點擊在單位上選擇它們(Alt-點擊) + 應該像任何其他選擇一樣直覺地表現。按Esc鍵關閉標籤視窗。\n\nShift鍵點擊以選擇/取消選擇多個。雙擊以將相機置中。按右鍵選擇單個卒子。Alt點擊關閉視窗,選擇並轉到該個卒子。注意:適用於*所有*PawnTables,而不僅僅是數字。 + 高亮選擇的目標。 + 適用於*所有*的PawnTables,而不僅僅是數字。 + 使用小字體作為標題(實驗性) + 載入已儲存的設置 + 沒有已儲存的設置 + 儲存目前設置 diff --git a/Languages/English/Keyed/Keys.xml b/Languages/English/Keyed/Keys.xml index 4dc1978..31f9b40 100644 --- a/Languages/English/Keyed/Keys.xml +++ b/Languages/English/Keyed/Keys.xml @@ -2,33 +2,37 @@ Numbers overview - Name Row Count - Click to select object type. - Click to sort by {0}. - Right click to remove column. - Add stat - Add skill - Add need - Add capacity - Add other + Click to select pawn type. + Right click to remove column. Click and drag to move. Presets - - Current Job - Equipment - Prisoner Interaction - How should wardens treat this prisoner. - Medical Care - Age - Mental State - - Colonists - Enemies - Prisoners - Guests - Animals - Wild Animals - Corpses - Animal Corpses + + + Load {0} preset + medical + combat + worktab plus + colonist needs + psycasting + + Set current view as default + Set the current view as the default for this type of view ({0}).\n\nThis view will then be used for new colonies.\n\nCan be deleted in the mod settings:\n [Menu] => [Options] => [Mod settings] => [Numbers]. + There are no defaults stored for the currently viewed pawn type. + Load default view + + Show needs and jobs even where it would normally be hidden. + Numbers is everything I ever wanted from the Wildlife tab and I want it to take over. + Numbers is everything I ever wanted from the Animal tab as well and I want it to take over. + Maximum height of the Numbers window relative to your screensize. + Mouse clicks in pawn tables select them. (Alt-click to work as before) + Should behave intuitively like any other selection. Press Esc to close the tab window.\n\nShift-click to select/deselect multiple. Double click to center camera. Right-click to select a single pawn. Alt-click to close window, select and go to that one pawn. Note: Applies to *all* PawnTables, not just Numbers. + Highlight selected pawns. + Note: Applies to *all* PawnTables, not just Numbers. + Use tiny font for headers (experimental) + Reset tables to default columns. + + Load saved view + Nothing saved + Save current view \ No newline at end of file diff --git a/Languages/German/DefInjected/MainTabDefs/kNumbers.xml b/Languages/German/DefInjected/MainTabDefs/kNumbers.xml new file mode 100644 index 0000000..2f28156 --- /dev/null +++ b/Languages/German/DefInjected/MainTabDefs/kNumbers.xml @@ -0,0 +1,13 @@ + + + + + kNumbersOverviewTab + + Sehen Sie alle möglichen Angaben zu jedem Kolonisten oder Gefangenen in einer einzigen Tabelle. + Numbers.MainTabWindow_Numbers + 20 + Z + + + \ No newline at end of file diff --git a/Languages/German/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml b/Languages/German/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..d8c604f --- /dev/null +++ b/Languages/German/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,35 @@ + + + + + + Alter + Fortschritt der Eier + Milchfülle + Wollwachstum + Rasse + Bezeichnung + Ausrütsung + Inventar + Aktueller Job + Job in Warteschleife + Mentaler Zustand + Gefangenen-Interaktion + Schwierigkeit der Rekrutierung + Verbleibender Widerstand + Schmerz + Blutungsrate + Benötigt Behandlung + Operationen + Verboten + Inspiration + Krankheitsfortschritt + Wildheit + Zähm Chance + Selbsthilfe + Gesundheitsdifferenz (vom Normalzustand) + Fraktionen + Verschmutzungsgrad + Fokus + + \ No newline at end of file diff --git a/Languages/German/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml b/Languages/German/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..753fe97 --- /dev/null +++ b/Languages/German/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,16 @@ + + + + Kolonisten + Feinde + Gefangene + Leichen + Gäste + Tiere + Wildtiere + Tierleichen + Kampfvoreinstellung + Arbeits Tab+ Voreinstellung + Kolonistenbedürfnisse + + \ No newline at end of file diff --git a/Languages/German/Keyed/Keys.xml b/Languages/German/Keyed/Keys.xml new file mode 100644 index 0000000..8e80380 --- /dev/null +++ b/Languages/German/Keyed/Keys.xml @@ -0,0 +1,35 @@ + + + + Zahlen Übersicht + Anzahl + Klicke um einen Kolonisten auszuwählen. + Rechtsklick, um Spalte zu entfernen. Klicke und ziehe zum Verschieben. + Voreinstellungen + + + Voreinstellung {0} laden + Medizinisch + Kampf + Arbeits TAB+ + Bedarf der Kolonisten + + Aktuelle Ansicht als Standard festlegen + Legen Sie die aktuelle Ansicht als Standard für diese Art der Ansicht fest ({0}).\n\nDiese Ansicht wird dann für neue Kolonien verwendet.\n\nKann in den Mod-Einstellungen gelöscht werden:\n [Menu] => [Options] => [Mod-Einstellungen] => [Numbers]. + Es gibt keine Standardwerte für den aktuell ausgewählten Kolonisten-Typ. + Standardansicht laden + + Zeige Bedürfnisse und Jobs auch dort, wo es normalerweise ausgeblendet wird. + Numbers ist alles, was ich jemals vom Tierwelt-TAB gewollt habe und ich möchte, dass es die Kontrolle übernimmt. + Numbers ist alles, was ich je vom Animal-TAB gewünscht habe und ich möchte, dass es die Kontrolle übernimmt. + Maximale Höhe des "Numbers" Fensters relativ zur Bildschirmgröße. + Mausklicks in den Kolonisten TAB´s, wählt sie aus. (Alt-Klicken um wie zuvor zu arbeiten) + Sollte sich intuitiv wie jede andere Auswahl verhalten. Drücken Sie Esc, um das Tabfenster zu schließen.\n\nShift-Klick um Mehrfachauswahl auszuwählen/abzuwählen. Doppelklick um die Kamera zu zentrieren. Rechtsklick, um einen einzelnen Kolonisten auszuwählen. Alt-Klick, um Fenster zu schließen, wähle aus und springe zu diesem Kolonisten. Hinweis: Gilt für *alle* Kolonisten TAB´s, nicht nur "Numbers". + Ausgewählte Kolonisten hervorheben. + Hinweis: Gilt für *alle* Kolonisten TAB´s, nicht nur "Numbers". + + Lade gespeicherte Ansicht + Nichts gespeichert + Speichere aktuelle Ansicht + + diff --git a/Languages/Russian/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml b/Languages/Russian/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml new file mode 100644 index 0000000..c16cd3e --- /dev/null +++ b/Languages/Russian/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml @@ -0,0 +1,9 @@ + + + + + + Переключить вкладку Numbers + + + \ No newline at end of file diff --git a/Languages/Russian/DefInjected/MainButtonDef/kNumbers.xml b/Languages/Russian/DefInjected/MainButtonDef/kNumbers.xml new file mode 100644 index 0000000..29c319b --- /dev/null +++ b/Languages/Russian/DefInjected/MainButtonDef/kNumbers.xml @@ -0,0 +1,8 @@ + + + + Цифры + Просмотреть все возможные показатели каждого колониста или других в одной таблице. + + + \ No newline at end of file diff --git a/Languages/Russian/DefInjected/MainTabDef/MainTabs.xml b/Languages/Russian/DefInjected/MainTabDef/MainTabs.xml deleted file mode 100644 index 2e7c80c..0000000 --- a/Languages/Russian/DefInjected/MainTabDef/MainTabs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - цифры - Посмотреть любую доступную статистику по колонистам или заключенным. - - diff --git a/Languages/Russian/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml b/Languages/Russian/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..060509f --- /dev/null +++ b/Languages/Russian/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,38 @@ + + + + + + Возраст + Прогресс яиц + Прогресс молока + Прогресс шерсти + Раса + Предыстория + Cнаряжение + Инвентарь + Текущая работа + Запланированная работа + Психическое состояние + Взаимодействие с заключенными + Сложность вербовки + Сопротивление + Боль + Кровотечение + Необходимо лечение + Операции + Запрещенное + Вдохновение + + Прогресс заболевания + Прогресс заболевания + + Шанс на неудачное приручение + Дикость + Шанс приручения + Самолечение + Бионика/Травмы + Фракция + + + \ No newline at end of file diff --git a/Languages/Russian/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml b/Languages/Russian/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..ac7c7bb --- /dev/null +++ b/Languages/Russian/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,16 @@ + + + + Колонисты + Враги + Заключенные + Трупы + Гости + Животные + Дикие животные + Трупы животных + Наборы снаряжения + Работа + + + + \ No newline at end of file diff --git a/Languages/Russian/Keyed/Keys.xml b/Languages/Russian/Keyed/Keys.xml index 1b2f8e5..737d8cb 100644 --- a/Languages/Russian/Keyed/Keys.xml +++ b/Languages/Russian/Keyed/Keys.xml @@ -1,33 +1,36 @@ - Цифры - Имя - Число строк - Нажмите для выбора. - Нажмите для сортировки по {0}. - ПКМ для удаления колонки. - Добавить стат - Добавить умение - Добавить потребность - Добавить другое - Преднастройки - - Текущая работа - Снаряжение - Отношение к заключенному - Как относится к этому заключенному - Лекарства - Возраст - Психика - - Колонисты - Враги - Заключенные - Гости - Животные - Дикие животные - Трупы - Трупы животных + Numbers overview + Количество строк + Нажмите, чтобы выбрать тип пешки. + Щелкните правой кнопкой, чтобы удалить столбец. Зажмите левую кнопку и перетащите для перемещения. + Шаблоны - + + Загрузить {0} шаблон + медицинский + боевой + работа + + потребности колониста + + Установить текущий шаблон по умолчанию + Установите текущий шаблон по умолчанию для этого типа вида ({0}).\n\nЭтот вид будет использоваться для новых колоний.\n\nМожно удалить в настройках мода:\n [Меню] => [Настройки] => [Настройки модов] => [Numbers]. + Для просматриваемого в настоящее время типа пешки по умолчанию нет сохраненных значений. + Загрузить шаблон по умолчанию + + Показать потребности и работы, даже там, где они обычно скрыты. + Скрыть вкладку "Фауна" (мода "Numbers" достаточно для моих целей). + Скрыть вкладку "Питомцы" (мода "Numbers" достаточно для моих целей). + Максимальная высота окна "Numbers" привязана к размеру вашего экрана. + Клик в таблице выбирает пешку (Alt-клик работает, как и раньше) + Должен вести себя интуитивно, как и любой другой выбор. Нажмите клавишу Esc, чтобы закрыть окно вкладок.\n\nШифт-клик чтобы выбрать/отменить выбор нескольких. Двойной клик чтобы сфокусировать камеру на пешке. Правый-клик чтобы выбрать одну пешку. Alt-клик чтобы закрыть окно и перейти к пешке. Примечание: применяется ко всем таблицам существ, не только к Numbers. + Подсветить выбранных пешек. + Примечание: применяется ко всем таблицам существ, не только к Numbers. + Использовать крошечный шрифт для заголовков (экспериментальный) + + Загрузить сохраненный шаблон + Нету сохраненных шаблонов + Сохранить текущий шаблон + + \ No newline at end of file diff --git a/Languages/Spanish/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml b/Languages/Spanish/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml new file mode 100644 index 0000000..68c932e --- /dev/null +++ b/Languages/Spanish/DefInjected/KeyBindingDef/KeyBindings_Add_MainTab.xml @@ -0,0 +1,9 @@ + + + + + + Pestaña de Datos + + + \ No newline at end of file diff --git a/Languages/Spanish/DefInjected/MainButtonDef/kNumbers.xml b/Languages/Spanish/DefInjected/MainButtonDef/kNumbers.xml new file mode 100644 index 0000000..ea38586 --- /dev/null +++ b/Languages/Spanish/DefInjected/MainButtonDef/kNumbers.xml @@ -0,0 +1,8 @@ + + + + Datos + Vea todas las estadísticas posibles de cada colono o prisionero en una sola tabla. + + + \ No newline at end of file diff --git a/Languages/Spanish/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml b/Languages/Spanish/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml new file mode 100644 index 0000000..cfd0064 --- /dev/null +++ b/Languages/Spanish/DefInjected/PawnColumnDef/PawnColumns_Numbers.xml @@ -0,0 +1,38 @@ + + + + + + Edad + Progreso del huevo + Proceso de la leche + Crecimiento de la lana + Raza + Título + Equipo + Inventario + Trabajo actual + Trabajo en cola + Estado mental + Interacción prisionero + Dificultad de reclutamiento + Resistencia restante + Dolor + Tasa de sangrado + Necesita tratamiento + Operaciones + Prohibido + Inspiración + + Margen de inmunidad de la enfermedad + Margen de inmunidad de la enfermedad + + Porcentaje de venganza en doma fallida + Ferocidad + Oportunidad + Autosuficiente + Estado físico + Facción + + + \ No newline at end of file diff --git a/Languages/Spanish/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml b/Languages/Spanish/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml new file mode 100644 index 0000000..2690584 --- /dev/null +++ b/Languages/Spanish/DefInjected/PawnTableDef/Numbers_PawnTableDef.xml @@ -0,0 +1,17 @@ + + + + Colonos + Enemigos + Prisoneros + Cadáveres + Invitados + Animales + Animales salvajes + Cadáveres de animales + combate + WorkTab plus + necesidades del colono + + + \ No newline at end of file diff --git a/Languages/Spanish/Keyed/Keys.xml b/Languages/Spanish/Keyed/Keys.xml index 370884d..8e2a8a7 100644 --- a/Languages/Spanish/Keyed/Keys.xml +++ b/Languages/Spanish/Keyed/Keys.xml @@ -1,33 +1,37 @@ - + - Numbers overview - Nombre + Resumen de Datos Número de filas - Haga clic para seleccionar el tipo de objeto. - Haga clic para ordenar por {0}. - Haga clic derecho para eliminar la columna. - Añadir estadística - Añadir habilidad - Añadir necesidad - Añadir otro tipo - Preestablecido + Haga clic para seleccionar el tipo de peón. + Haga clic derecho para eliminar la columna. Haz clic y arrastra para moverte. + Configurar - Trabajo actual - Equipo - Interacción con los prisioneros - Cómo deben los guardias tratar a este prisionero. - Asistencia Médica - Edad - Estado Mental + + Cargar {0} configuración + médica + combate + worktab plus + necesidades del colono + Psico-foco - Colonos - Enemigos - Prisioneros - Invitados - Animales - Animales Salvajes - Cadáveres - Cadáveres de Animales + Establecer vista actual como predeterminada + Establezca la vista actual como predeterminada para este tipo de vista ({0}).\n\nEsta vista se utilizará para nuevas colonias.\n\nSe puede eliminar en la configuración de mod:\n [Menu] => [Opciones] => [Mod configuración] => [Datos]. + No hay valores predeterminados almacenados para el tipo de peón visto actualmente. + Cargar vista predeterminada - + Mostrar necesidades y trabajos incluso donde normalmente estaría oculto. + Numbers es todo lo que siempre quise de la pestaña de Vida Silvestre y quiero que se haga cargo. + Numbers es todo lo que siempre quise de la pestaña Animal y quiero que se haga cargo. + Altura máxima de la ventana Números en relación con el tamaño de su pantalla. + Los clics del mouse en las tablas de empeño los seleccionan. (Alt-clic para trabajar como antes) + Debe comportarse intuitivamente como cualquier otra selección. Presione Esc para cerrar la ventana de pestañas.\n\nShift-clic para seleccionar / deseleccionar múltiples. Haga doble clic para centrar la cámara. Haga clic derecho para seleccionar un solo peón. Alt-clic para cerrar la ventana, seleccionar e ir a ese peón. Nota: Se aplica a * todos * PawnTables, no solo a los números. + Resalta los peones seleccionados. + Nota: Se aplica a * todos * PawnTables, no solo a los números. + Usar una fuente diminuta para los encabezados (experimental) + + Cargar vista guardada + Nada salvado + Guardar vista actual + + \ No newline at end of file diff --git a/Numbers.sln b/Numbers.sln new file mode 100644 index 0000000..fef13f7 --- /dev/null +++ b/Numbers.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numbers", "Numbers\Numbers.csproj", "{BA30D06A-3EAF-4302-8FD2-9C6A9BD177C4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7F2E9F8A-0D2C-42B5-AB83-91851FEA7215}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA30D06A-3EAF-4302-8FD2-9C6A9BD177C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA30D06A-3EAF-4302-8FD2-9C6A9BD177C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA30D06A-3EAF-4302-8FD2-9C6A9BD177C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA30D06A-3EAF-4302-8FD2-9C6A9BD177C4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D8A5575F-E628-421F-B9ED-730E5483CB9D} + EndGlobalSection +EndGlobal diff --git a/Numbers/DefModExtension_NeedsBioTech.cs b/Numbers/DefModExtension_NeedsBioTech.cs new file mode 100644 index 0000000..b46d832 --- /dev/null +++ b/Numbers/DefModExtension_NeedsBioTech.cs @@ -0,0 +1,9 @@ +namespace Numbers +{ + using Verse; + + public class DefModExtension_NeedsBioTech : DefModExtension + { + //nothing needed, just a tag + } +} diff --git a/Numbers/DefModExtension_NeedsIdeology.cs b/Numbers/DefModExtension_NeedsIdeology.cs new file mode 100644 index 0000000..fe23149 --- /dev/null +++ b/Numbers/DefModExtension_NeedsIdeology.cs @@ -0,0 +1,9 @@ +namespace Numbers +{ + using Verse; + + public class DefModExtension_NeedsIdeology : DefModExtension + { + + } +} diff --git a/Numbers/DefModExtension_NeedsRoyalty.cs b/Numbers/DefModExtension_NeedsRoyalty.cs new file mode 100644 index 0000000..0c54635 --- /dev/null +++ b/Numbers/DefModExtension_NeedsRoyalty.cs @@ -0,0 +1,9 @@ +namespace Numbers +{ + using Verse; + + public class DefModExtension_NeedsRoyalty : DefModExtension + { + //nothing needed, just a tag + } +} diff --git a/Numbers/DefModExtension_PawnColumnDefs.cs b/Numbers/DefModExtension_PawnColumnDefs.cs new file mode 100644 index 0000000..14cec46 --- /dev/null +++ b/Numbers/DefModExtension_PawnColumnDefs.cs @@ -0,0 +1,15 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class DefModExtension_PawnColumnDefs : DefModExtension + { + public RecordDef record; + public PawnCapacityDef capacity; + public NeedDef need; + public StatDef stat; + public SkillDef skill; + public AbilityDef ability; + } +} diff --git a/Numbers/DefModExtension_PawnTableDefs.cs b/Numbers/DefModExtension_PawnTableDefs.cs new file mode 100644 index 0000000..1b359c2 --- /dev/null +++ b/Numbers/DefModExtension_PawnTableDefs.cs @@ -0,0 +1,12 @@ +namespace Numbers +{ + using Verse; + + public class DefModExtension_PawnTableDefs : DefModExtension + { + public bool Corpse = false; + public bool Humanlike; + public bool Animallike = false; + } +} + diff --git a/Numbers/Dialog_IHaveToCreateAnEntireFuckingDialogForANOKAYBUTTONFFS.cs b/Numbers/Dialog_IHaveToCreateAnEntireFuckingDialogForANOKAYBUTTONFFS.cs new file mode 100644 index 0000000..b2297b6 --- /dev/null +++ b/Numbers/Dialog_IHaveToCreateAnEntireFuckingDialogForANOKAYBUTTONFFS.cs @@ -0,0 +1,39 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class Dialog_IHaveToCreateAnEntireFuckingDialogForAGODDAMNOKAYBUTTONFFS : Dialog_Rename + { + private readonly PawnTableDef pawnTableDef; + + public Dialog_IHaveToCreateAnEntireFuckingDialogForAGODDAMNOKAYBUTTONFFS(PawnTableDef pawnTableDef) : base(null) + { + this.pawnTableDef = pawnTableDef; + curName = pawnTableDef.label; + } + + protected override AcceptanceReport NameIsValid(string name) + { + AcceptanceReport result = base.NameIsValid(name); + if (!result.Accepted) + { + return result; + } + if (!new System.Text.RegularExpressions.Regex("^[a-zA-Z0-9\\-_]*$").IsMatch(name)) //sanitize user input + { + return "Should only contain letters, numbers, underscores, or dashes"; + } + return true; + } + + protected override void OnRenamed(string name) + { + pawnTableDef.label = curName; + + string pawnTableDeftoSave = HorribleStringParsersForSaving.TurnPawnTableDefIntoCommaDelimitedString(pawnTableDef); + + LoadedModManager.GetMod().GetSettings().StoreNewPawnTableDef(pawnTableDeftoSave); + } + } +} diff --git a/Numbers/HorribleStringParsersForSaving.cs b/Numbers/HorribleStringParsersForSaving.cs new file mode 100644 index 0000000..4d21eb8 --- /dev/null +++ b/Numbers/HorribleStringParsersForSaving.cs @@ -0,0 +1,51 @@ +namespace Numbers +{ + using System.Linq; + using System.Text; + using RimWorld; + using Verse; + + public static class HorribleStringParsersForSaving + { + public static string TurnPawnTableDefIntoCommaDelimitedString(PawnTableDef table, bool asDefault = false) + { + string label = asDefault ? "Default" : table.label; + + return string.Join(",", [table.defName, label, TurnPawnTableColumnsIntoCommaDelimitedString(table)]); + } + + public static string CreateDefNameFromType(Def def) + => "Numbers_" + def.GetType().ToString().Replace('.', '_') + "_" + def.defName; + + private static string TurnPawnTableColumnsIntoCommaDelimitedString(PawnTableDef table) + { + StringBuilder stringBuilder = new(); + foreach (var item in table.columns) + { + stringBuilder.Append(item.defName); + stringBuilder.Append(','); + } + return stringBuilder.ToString(); + } + + public static PawnTableDef TurnCommaDelimitedStringIntoPawnTableDef(string ptd) + { + string[] pawnTableDef = ptd.Split(','); + + PawnTableDef reconstructedPCD = DefDatabase.GetNamedSilentFail(pawnTableDef[0]); + + if (reconstructedPCD != null) + { + reconstructedPCD.columns.Clear(); + for (int i = 2; i < pawnTableDef.Length; i++) + { + PawnColumnDef pcd = DefDatabase.GetNamedSilentFail(pawnTableDef[i]); + if (pcd != null) + reconstructedPCD.columns.Add(pcd); + } + return reconstructedPCD; + } + return WorldComponent_Numbers.PrimaryFilter.First().Key; + } + } +} diff --git a/Numbers/MainTabWindow_Numbers.cs b/Numbers/MainTabWindow_Numbers.cs new file mode 100644 index 0000000..d8f3a83 --- /dev/null +++ b/Numbers/MainTabWindow_Numbers.cs @@ -0,0 +1,272 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using RimWorld; + using RimWorld.Planet; + using UnityEngine; + using Verse; + + public class MainTabWindow_Numbers : MainTabWindow_PawnTable + { + public const float buttonWidth = 110f; + public const float buttonHeight = 35f; + public const float buttonGap = 4f; + public const float extraTopSpace = 83f; + + public static List> filterValidator = [Find.World.GetComponent().primaryFilter.Value]; + + private readonly IEnumerable pawnHumanlikeStatDef; + private readonly IEnumerable pawnAnimalStatDef; + private readonly IEnumerable corpseStatDef; + private readonly IEnumerable pawnHumanlikeNeedDef; + private readonly IEnumerable pawnAnimalNeedDef; + + private readonly MethodInfo StatsToDraw; + + public readonly OptionsMaker optionsMaker; + + //Code style: Use GetNamedSilentFail in cases where there is null-handling, so any columns that get run through TryGetBestPawnColumnDefLabel() or AddPawnColumnAtBestPositionAndRefresh() can silently fail. + //Use GetNamed anywhere a null column would throw a null ref. + private static readonly string workTabName = DefDatabase.GetNamed("Work").ShortenedLabelCap; + + private IEnumerable StatDefs => PawnTableDef.Ext().Corpse ? corpseStatDef : + PawnTableDef.Ext().Animallike ? pawnAnimalStatDef : pawnHumanlikeStatDef; + + private IEnumerable NeedDefs => PawnTableDef.Ext().Animallike ? pawnAnimalNeedDef : pawnHumanlikeNeedDef; + + private IEnumerable HealthStats => + [ + DefDatabase.GetNamedSilentFail("Numbers_HediffList"), + DefDatabase.GetNamedSilentFail("Numbers_HediffBadList"), + DefDatabase.GetNamedSilentFail("Numbers_Pain"), + DefDatabase.GetNamedSilentFail("Numbers_Bleedrate"), + DefDatabase.GetNamedSilentFail("Numbers_NeedsTreatment"), + DefDatabase.GetNamedSilentFail("Numbers_DiseaseProgress") + ]; + + //ctor to populate lists. + public MainTabWindow_Numbers() + { + optionsMaker = new OptionsMaker(this); + + StatsToDraw = typeof(StatsReportUtility).GetMethod("StatsToDraw", + BindingFlags.NonPublic | BindingFlags.Static | + BindingFlags.InvokeMethod, null, + [typeof(Thing)], null); + + if (StatsToDraw == null) + Log.Error("ReflectionTypeLoadException in Numbers: statsToDraw was null. Please contact mod author."); + + pawnHumanlikeNeedDef ??= GetHumanLikeNeedDef(); + + pawnHumanlikeStatDef ??= GetHumanLikeStatDefs(); + + if (pawnAnimalNeedDef == null || pawnAnimalStatDef == null || corpseStatDef == null) + { + var statDefs = PopulateLists(); + pawnAnimalStatDef = statDefs.pawnAnimalStatDef; + pawnAnimalNeedDef = statDefs.pawnAnimalNeedDef; + corpseStatDef = statDefs.corpseStatDef; + } + + PawnTableDef defaultTable = WorldComponent_Numbers.PrimaryFilter.First().Key; + if (Find.World.GetComponent().sessionTable.TryGetValue(defaultTable, out List list)) + { + list.RemoveAll(x => x == null); + pawnTableDef.columns = list; + } + + UpdateFilter(); + } + + protected internal PawnTableDef pawnTableDef = NumbersDefOf.Numbers_MainTable; + + protected override PawnTableDef PawnTableDef => pawnTableDef; + + protected override IEnumerable Pawns + { + get + { + var corpseList = Find.CurrentMap.listerThings.ThingsInGroup(ThingRequestGroup.Corpse).Cast(); + + foreach (Corpse corpse in corpseList) + { + if (filterValidator.All(validator => validator(corpse.InnerPawn))) + yield return corpse.InnerPawn; + } + + foreach (Pawn pawn in Find.CurrentMap.mapPawns.AllPawnsSpawned) + { + if (filterValidator.All(validator => validator(pawn))) + yield return pawn; + } + } + } + + protected override float ExtraTopSpace => extraTopSpace; + + public override void DoWindowContents(Rect rect) + { + float x = 0f; + Text.Font = GameFont.Small; + + // row count: + Rect thingCount = new(3f, 40f, 200f, 30f); + Widgets.Label(thingCount, "koisama.Numbers.Count".Translate() + ": " + Pawns.Count()); + + //pawn selector + Rect sourceButton = new(x, 0f, buttonWidth, buttonHeight); + DoButton(PawnTableDef.label, optionsMaker.PawnSelector(), ref x); + TooltipHandler.TipRegion(sourceButton, new TipSignal("koisama.Numbers.ClickToToggle".Translate(), sourceButton.GetHashCode())); + + //stats + DoButton("TabStats".Translate(), optionsMaker.OptionsMakerForGenericDef(StatDefs), ref x); + + //worktypes + if (PawnTableDef == NumbersDefOf.Numbers_MainTable) + { + DoButton(workTabName, optionsMaker.FloatMenuOptionsFor(DefDatabase.AllDefsListForReading.Where(pcd => pcd.workType != null).Reverse()), ref x); + } + + //skills + if (new[] { NumbersDefOf.Numbers_Enemies, NumbersDefOf.Numbers_Prisoners, NumbersDefOf.Numbers_MainTable, NumbersDefOf.Numbers_Guests }.Contains(PawnTableDef)) + { + DoButton("Skills".Translate(), optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading), ref x); + } + + //needs btn (for living things) + if (!new[] { NumbersDefOf.Numbers_AnimalCorpses, NumbersDefOf.Numbers_Corpses }.Contains(PawnTableDef)) + { + DoButton("TabNeeds".Translate(), optionsMaker.OptionsMakerForGenericDef(NeedDefs), ref x); + } + + //cap btn (for living things) + if (!new[] { NumbersDefOf.Numbers_AnimalCorpses, NumbersDefOf.Numbers_Corpses }.Contains(PawnTableDef)) + { + List optionalList = []; + + if (new[] { NumbersDefOf.Numbers_MainTable, NumbersDefOf.Numbers_Prisoners, NumbersDefOf.Numbers_Animals }.Contains(PawnTableDef)) + { + optionalList.Add(DefDatabase.GetNamedSilentFail("MedicalCare")); + optionalList.Add(DefDatabase.GetNamedSilentFail("Numbers_Operations")); + + if (PawnTableDef == NumbersDefOf.Numbers_MainTable) + optionalList.Add(DefDatabase.GetNamedSilentFail("Numbers_SelfTend")); + } + + optionalList.AddRange(HealthStats); + + var tmp = optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading) + .Concat(optionsMaker.FloatMenuOptionsFor(optionalList)); + + DoButton("TabHealth".Translate(), tmp.ToList(), ref x); + } + + //abilities btn + var abilities = optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading.OrderBy(y => y.label)); + if (abilities.Count > 0) + { + DoButton("Abilities".Translate(), abilities, ref x); + } + + //records btn + DoButton("TabRecords".Translate(), optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading), ref x); + + //other btn + DoButton("MiscRecordsCategory".Translate(), optionsMaker.OtherOptionsMaker(), ref x); + + //presets button + float startPositionOfPresetsButton = Mathf.Max(rect.xMax - buttonWidth - Margin, x); + Rect addPresetBtn = new(startPositionOfPresetsButton, 0f, buttonWidth, buttonHeight); + if (Widgets.ButtonText(addPresetBtn, "koisama.Numbers.SetPresetLabel".Translate())) + { + Find.WindowStack.Add(new FloatMenu(optionsMaker.PresetOptionsMaker())); + } + + base.DoWindowContents(rect); + } + + void DoButton(string label, List list, ref float x) + { + Rect addColumnButton = new(x, 0f, buttonWidth, buttonHeight); + if (Widgets.ButtonText(addColumnButton, label)) + { + Find.WindowStack.Add(new FloatMenu(list)); + } + x += buttonWidth + buttonGap; + } + + public override void PostOpen() + { + UpdateFilter(); + base.PostOpen(); + Find.World.renderer.wantedMode = WorldRenderMode.None; + } + + public void RefreshAndStoreSessionInWorldComp() + { + SetDirty(); + Notify_ResolutionChanged(); + Find.World.GetComponent().sessionTable[PawnTableDef] = PawnTableDef.columns; + } + + public void UpdateFilter() + { + filterValidator.Clear(); + filterValidator.Insert(0, WorldComponent_Numbers.PrimaryFilter[PawnTableDef]); + } + + private (List pawnAnimalNeedDef, List pawnAnimalStatDef, List corpseStatDef) PopulateLists() + { + PawnGenerationRequest request = new(PawnKindDefOf.Thrumbo, Faction.OfPirates, forceNoIdeo: true, forceGenerateNewPawn: true); + Pawn tmpPawn = PawnGenerator.GeneratePawn(request); + + var pawnAnimalNeedDef = tmpPawn.needs.AllNeeds.Where(x => x.def.showOnNeedList).Select(x => x.def).ToList(); + + var animalStatDef = ((IEnumerable)StatsToDraw?.Invoke(null, new[] { tmpPawn })) ?? []; + + var pawnAnimalStatDef = animalStatDef + .Where(s => s.stat != null && s.ShouldDisplay() && s.stat.Worker != null) + .Select(s => s.stat) + .OrderBy(stat => stat.LabelCap.Resolve()).ToList(); + + Corpse corpse = (Corpse)ThingMaker.MakeThing(tmpPawn.RaceProps.corpseDef); + corpse.InnerPawn = tmpPawn; + + var deadAnimalStatDef = ((IEnumerable)StatsToDraw?.Invoke(null, new[] { corpse })) ?? []; + + var corpseStatDef = deadAnimalStatDef + .Concat(tmpPawn.def.SpecialDisplayStats(StatRequest.For(tmpPawn))) + .Where(s => s.stat != null && s.ShouldDisplay() && s.stat.Worker != null) + .Select(s => s.stat) + .OrderBy(stat => stat.LabelCap.Resolve()).ToList(); + + tmpPawn.Destroy(DestroyMode.KillFinalize); + corpse.Destroy(); + + return (pawnAnimalNeedDef, pawnAnimalStatDef, corpseStatDef); + } + + private IEnumerable GetHumanLikeNeedDef() => DefDatabase.AllDefsListForReading.Except(Numbers.DummyNeed); + + private List GetHumanLikeStatDefs() + { + PawnGenerationRequest request = new(PawnKindDefOf.AncientSoldier, Faction.OfAncients, forceNoIdeo: true, forceGenerateNewPawn: true); + Pawn tmpPawn = PawnGenerator.GeneratePawn(request); + + var source = ((IEnumerable)StatsToDraw?.Invoke(null, new[] { tmpPawn })) ?? []; + + var pawnHumanlikeStatDef = source + .Concat(tmpPawn.def.SpecialDisplayStats(StatRequest.For(tmpPawn))) + .Where(s => s.stat != null && s.ShouldDisplay() && s.stat.Worker != null) + .Select(s => s.stat); + + tmpPawn.Destroy(DestroyMode.KillFinalize); + + return [.. pawnHumanlikeStatDef.OrderBy(stat => stat.LabelCap.Resolve())]; + } + } +} diff --git a/Numbers/MainTabWindow_NumbersAnimals.cs b/Numbers/MainTabWindow_NumbersAnimals.cs new file mode 100644 index 0000000..719eaa9 --- /dev/null +++ b/Numbers/MainTabWindow_NumbersAnimals.cs @@ -0,0 +1,24 @@ +namespace Numbers +{ + using System.Collections.Generic; + using RimWorld; + using Verse; + + public class MainTabWindow_NumbersAnimals : MainTabWindow_Numbers + { + public override void PostOpen() + { + pawnTableDef = NumbersDefOf.Numbers_Animals; + + if (Find.World.GetComponent().sessionTable + .TryGetValue(pawnTableDef, out List listPawnColumDef)) + { + pawnTableDef.columns = listPawnColumDef; + } + + UpdateFilter(); + Notify_ResolutionChanged(); + base.PostOpen(); + } + } +} \ No newline at end of file diff --git a/Numbers/MainTabWindow_NumbersWildLife.cs b/Numbers/MainTabWindow_NumbersWildLife.cs new file mode 100644 index 0000000..c7bbb1d --- /dev/null +++ b/Numbers/MainTabWindow_NumbersWildLife.cs @@ -0,0 +1,24 @@ +namespace Numbers +{ + using System.Collections.Generic; + using RimWorld; + using Verse; + + public class MainTabWindow_NumbersWildLife : MainTabWindow_Numbers + { + public override void PostOpen() + { + pawnTableDef = NumbersDefOf.Numbers_WildAnimals; + + if (Find.World.GetComponent().sessionTable + .TryGetValue(pawnTableDef, out List listPawnColumDef)) + { + pawnTableDef.columns = listPawnColumDef; + } + + UpdateFilter(); + Notify_ResolutionChanged(); + base.PostOpen(); + } + } +} \ No newline at end of file diff --git a/Numbers/Numbers.cs b/Numbers/Numbers.cs new file mode 100644 index 0000000..8ebd90c --- /dev/null +++ b/Numbers/Numbers.cs @@ -0,0 +1,568 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + using HarmonyLib; + using JetBrains.Annotations; + using RimWorld; + using RimWorld.Planet; + using UnityEngine; + using Verse; + + public class Numbers : Mod + { + private readonly Numbers_Settings settings; + + private static int reorderableGroupId = -1; + + public Numbers(ModContentPack content) : base(content) + { + Harmony harmony = new("mehni.rimworld.numbers"); + +#if DEBUG + Harmony.DEBUG = true; +#endif + + harmony.Patch(AccessTools.Method(typeof(DefGenerator), nameof(DefGenerator.GenerateImpliedDefs_PreResolve)), + postfix: new HarmonyMethod(typeof(Numbers), nameof(Columndefs))); + + harmony.Patch(AccessTools.Method(typeof(PawnColumnWorker), "HeaderClicked"), + prefix: new HarmonyMethod(typeof(Numbers), nameof(RightClickToRemoveHeader))); + + harmony.Patch(AccessTools.Method(typeof(PawnTable), nameof(PawnTable.PawnTableOnGUI)), + postfix: new HarmonyMethod(typeof(Numbers), nameof(ApplyColumnsRemoval)), + transpiler: new HarmonyMethod(typeof(Numbers), nameof(MakeHeadersReOrderable))); + + harmony.Patch(AccessTools.Method(typeof(PawnColumnWorker), nameof(PawnColumnWorker.DoHeader)), + transpiler: new HarmonyMethod(typeof(Numbers), nameof(UseWordWrapOnHeaders))); + + harmony.Patch(AccessTools.Method(typeof(PawnColumnWorker_Text), nameof(PawnColumnWorker_Text.DoCell)), + transpiler: new HarmonyMethod(typeof(Numbers), nameof(CentreCell))); + + harmony.Patch(AccessTools.Method(typeof(ReorderableWidget), nameof(ReorderableWidget.Reorderable)), + transpiler: new HarmonyMethod(typeof(Numbers), nameof(ReorderWidgetFromEventToInputTranspiler))); + + //we meet again, Fluffy. + Type pawnColumWorkerType = GenTypes.GetTypeInAnyAssembly("WorkTab.PawnColumnWorker_WorkType"); + if (pawnColumWorkerType != null && typeof(PawnColumnWorker).IsAssignableFrom(pawnColumWorkerType)) + { + harmony.Patch(AccessTools.Method(pawnColumWorkerType, "HeaderInteractions"), + prefix: new HarmonyMethod(typeof(Numbers), nameof(RightClickToRemoveHeader))); + } + + //we meet Uuugggg again too. Credit where it's due: + // https://github.com/alextd/RimWorld-EnhancementPack/blob/master/Source/PawnTableHighlightSelected.cs + harmony.Patch(AccessTools.Method(typeof(PawnColumnWorker_Label), nameof(PawnColumnWorker_Label.DoCell)), + postfix: new HarmonyMethod(typeof(Numbers), nameof(AddHighlightToLabel_PostFix)), + transpiler: new HarmonyMethod(typeof(Numbers), nameof(AddHighlightToLabel_Transpiler))); + + settings = GetSettings(); + } + + private static void Columndefs() + { + foreach (PawnColumnDef pawnColumnDef in ImpliedPawnColumnDefs()) + { + DefGenerator.AddImpliedDef(pawnColumnDef); + } + var pred = DefDatabase.GetNamed("Predator"); + pred.sortable = true; + pred.headerTip = "Predator"; + } + + private static bool RightClickToRemoveHeader(PawnColumnWorker __instance, Rect headerRect, PawnTable table) + { + if (Event.current.shift) + return true; + + if (Event.current.button != 1) + return true; + + if (table is not PawnTable_NumbersMain numbersTable) + return true; + + if (!Mouse.IsOver(headerRect)) + return true; + + numbersTable.EnqueueColumnRemoval(x => ReferenceEquals(__instance, x.Worker)); + + if (Find.WindowStack.currentlyDrawnWindow is MainTabWindow_Numbers numbers) + numbers.RefreshAndStoreSessionInWorldComp(); + + return false; + } + + private static void ApplyColumnsRemoval(PawnTable __instance) + { + if (__instance is PawnTable_NumbersMain table) + { + table.ApplyColumnRemoval(); + } + } + + private static IEnumerable MakeHeadersReOrderable(IEnumerable instructions, ILGenerator generator) + { + MethodInfo recacheIfDirty = AccessTools.Method(typeof(PawnTable), "RecacheIfDirty"); + MethodInfo reorderableGroup = AccessTools.Method(typeof(Numbers), nameof(ReorderableGroup)); + MethodInfo reorderableWidget = AccessTools.Method(typeof(Numbers), nameof(CallReorderableWidget)); + MethodInfo doHeader = AccessTools.Method(typeof(PawnColumnWorker), nameof(PawnColumnWorker.DoHeader)); + + var local = generator.DeclareLocal(typeof(int)); + + CodeInstruction[] codeInstructions = instructions.ToArray(); + for (int i = 0; i < codeInstructions.Length; i++) + { + CodeInstruction instruction = codeInstructions[i]; + if (i > 2 && codeInstructions[i - 1].Calls(recacheIfDirty)) + { + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Call, reorderableGroup); + yield return new CodeInstruction(OpCodes.Stloc, local.LocalIndex); + } + + //IL_0092: callvirt instance class RimWorld.PawnColumnWorker RimWorld.PawnColumnDef::get_Worker() + //IL_0097: ldloc.s 6 <-- insert here. + //IL_0099: ldarg.0 + //IL_009a: callvirt instance void RimWorld.PawnColumnWorker::DoHeader(valuetype [UnityEngine.CoreModule]UnityEngine.Rect, class RimWorld.PawnTable) + if (i < codeInstructions.Length + 3 && instruction.opcode == OpCodes.Ldloc_S && codeInstructions[i + 2].Calls(doHeader)) + { + yield return new CodeInstruction(OpCodes.Ldloc, local.LocalIndex); + yield return instruction; + yield return new CodeInstruction(OpCodes.Call, reorderableWidget); + } + yield return instruction; + } + } + + //public because of https://github.com/krypt-lynx/PawnTableGrouped + public static int ReorderableGroup(PawnTable pawnTable) + { + if (pawnTable is not PawnTable_NumbersMain numbersPawnTable) + reorderableGroupId = int.MinValue; + + if (Event.current.type == EventType.Repaint) + { + reorderableGroupId = ReorderableWidget.NewGroup(ReorderAction, ReorderableDirection.Horizontal, new Rect(0f, 0f, UI.screenWidth, UI.screenHeight)); + } + return reorderableGroupId; + } + + private static readonly Action ReorderAction = delegate (int from, int to) + { + var numbers = Find.WindowStack.Windows.OfType().FirstOrDefault(); + + if (numbers != null) + { + PawnColumnDef pawnColumnDef = numbers.pawnTableDef.columns[from]; + numbers.pawnTableDef.columns.Insert(to, pawnColumnDef); + //if it got inserted at a lower number, the index shifted up 1. If not, stick to the old. + numbers.pawnTableDef.columns.RemoveAt(from >= to ? from + 1 : from); + + numbers.RefreshAndStoreSessionInWorldComp(); + } + }; + + //public because of https://github.com/krypt-lynx/PawnTableGrouped + public static void CallReorderableWidget(int groupId, Rect rect) + { + if (groupId == int.MinValue) + return; + + ReorderableWidget.Reorderable(groupId, rect); + } + + private static IEnumerable UseWordWrapOnHeaders(IEnumerable instructions) + { + MethodInfo Truncate = AccessTools.Method(typeof(GenText), nameof(GenText.Truncate), [typeof(string), typeof(float), typeof(Dictionary)]); + MethodInfo WordWrap = AccessTools.Method(typeof(Numbers_Utility), nameof(Numbers_Utility.WordWrapAt)); + + var instructionList = instructions.ToList(); + for (int i = 0; i < instructionList.Count; i++) + { + if (instructionList[i].opcode == OpCodes.Ldnull && instructionList[i + 1].Calls(Truncate)) + { + yield return new CodeInstruction(OpCodes.Ldarg_2); + yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Numbers), nameof(Numbers.GetGameFont))); + yield return new CodeInstruction(OpCodes.Call, AccessTools.Property(typeof(Text), nameof(Text.Font)).GetSetMethod()); + + instructionList[i].opcode = OpCodes.Ldarg_2; + instructionList[i + 1].operand = WordWrap; + } + yield return instructionList[i]; + } + } + + private static GameFont GetGameFont(PawnTable table) + => table is PawnTable_NumbersMain && Numbers_Settings.useTinyFont ? GameFont.Tiny : GameFont.Small; + + private static IEnumerable CentreCell(IEnumerable instructions) + { + List instructionList = instructions.ToList(); + + MethodInfo anchorSetter = AccessTools.Property(typeof(Text), nameof(Text.Anchor)).GetSetMethod(); + MethodInfo transpilerHelper = AccessTools.Method(typeof(Numbers), nameof(TranspilerHelper)); + + for (int i = 0; i < instructionList.Count; i++) + { + CodeInstruction instruction = instructionList[i]; + if (instruction.opcode == OpCodes.Call && instructionList[i + 1].Calls(anchorSetter)) + { + yield return new CodeInstruction(OpCodes.Ldarg_3); //put Table on stack + instruction = new CodeInstruction(OpCodes.Call, transpilerHelper); + } + yield return instruction; + } + } + + //slight issue with job strings. Meh. + private static TextAnchor TranspilerHelper(PawnTable table) + => table is PawnTable_NumbersMain ? TextAnchor.MiddleCenter : TextAnchor.MiddleLeft; + + /// + /// TOO MUCH OF A MESS TO EXPLAIN + /// + /// Madness. + private static IEnumerable ReorderWidgetFromEventToInputTranspiler(IEnumerable instructions, ILGenerator generator) + { + MethodInfo GetCurrent = AccessTools.Property(typeof(Event), nameof(Event.current)).GetGetMethod(); + MethodInfo GetRawType = AccessTools.Property(typeof(Event), nameof(Event.rawType)).GetGetMethod(); + MethodInfo NoMouseButtonsPressed = AccessTools.Method(typeof(Numbers), nameof(Numbers.NoMouseButtonsPressed)); + MethodInfo WasClicked = AccessTools.Method(typeof(Numbers), nameof(Numbers.WasClicked)); + + FieldInfo released = AccessTools.Field(typeof(ReorderableWidget), "released"); + + bool yieldNext = true; + + List instructionArr = instructions.ToList(); + for (int i = 0; i < instructionArr.ToArray().Length; i++) + { + CodeInstruction instruction = instructionArr[i]; + if (instruction.Calls(GetCurrent)) + { + if (instructionArr[i + 1].operand != null && instructionArr[i + 1].Calls(GetRawType)) + { + //L_02bc: Label1 + //L_02bc: call UnityEngine.Event get_current() + //L_02c1: callvirt EventType get_rawType() + //L_02c6: ldc.i4.1 + // => + // call Input.GetMouseButtonUp(1) (or 0) + yield return new CodeInstruction(OpCodes.Nop) + { + labels = [generator.DefineLabel()] + }; + instruction.opcode = OpCodes.Call; + instruction.operand = NoMouseButtonsPressed; + instructionArr.RemoveAt(i + 1); + } + } + if (instruction.StoresField(released)) + { + yield return instruction; + CodeInstruction codeInst = new(OpCodes.Ldarg_2) + { + labels = [generator.DefineLabel()] + }; + codeInst.labels.AddRange(instructionArr[i + 1].labels); + yield return codeInst; + yield return new CodeInstruction(OpCodes.Call, WasClicked); + yieldNext = false; + } + + if (!yieldNext && instruction.opcode == OpCodes.Ldarg_1) + yieldNext = true; + + if (yieldNext) + yield return instruction; + + if (instruction.Calls(AccessTools.Method(typeof(Mouse), nameof(Mouse.IsOver)))) + yield return new CodeInstruction(OpCodes.And); + } + } + + [UsedImplicitly] + public static bool NoMouseButtonsPressed() + => !Input.GetMouseButton(0) + && !Input.GetMouseButton(1); + + [UsedImplicitly] + public static bool WasClicked(bool useRightButton) + => useRightButton && Input.GetMouseButtonDown(1) + || !useRightButton && Input.GetMouseButtonDown(0); + + + private static void AddHighlightToLabel_PostFix(Rect rect, Pawn pawn) + { + if (!Numbers_Settings.pawnTableHighlightSelected) return; + + if (Find.Selector.IsSelected(pawn)) + Widgets.DrawHighlightSelected(rect); + } + + //again, copied from https://github.com/alextd/RimWorld-EnhancementPack/blob/master/Source/PawnTableHighlightSelected.cs + private static IEnumerable AddHighlightToLabel_Transpiler(IEnumerable instructions) + { + MethodInfo TryJumpAndSelectInfo = AccessTools.Method(typeof(CameraJumper), nameof(CameraJumper.TryJumpAndSelect)); + MethodInfo EscapeCurrentTabInfo = AccessTools.Method(typeof(MainTabsRoot), nameof(MainTabsRoot.EscapeCurrentTab)); + + foreach (CodeInstruction i in instructions) + { + if (i.Calls(TryJumpAndSelectInfo)) + i.operand = AccessTools.Method(typeof(Numbers), nameof(ClickPawn)); + if (i.Calls(EscapeCurrentTabInfo)) + i.operand = AccessTools.Method(typeof(Numbers), nameof(SodThisImOut)); + + yield return i; + } + } + + public static void ClickPawn(GlobalTargetInfo target, CameraJumper.MovementMode mode = CameraJumper.MovementMode.Pan) + { + if (!Numbers_Settings.pawnTableClickSelect) + { + CameraJumper.TryJumpAndSelect(target, mode); + return; + } + + if (Current.ProgramState != ProgramState.Playing) + { + return; + } + + if (target.Thing is Pawn pawn && pawn.Spawned) + { + if (Event.current.shift) + { + if (Find.Selector.IsSelected(pawn)) + { + Find.Selector.Deselect(pawn); + } + else + { + Find.Selector.Select(pawn); + } + } + else if (Event.current.alt) + { + Find.MainTabsRoot.EscapeCurrentTab(false); + CameraJumper.TryJumpAndSelect(target, mode); + } + else + { + if (Find.Selector.IsSelected(pawn)) + { + CameraJumper.TryJump(target, mode); + } + if (!Find.Selector.IsSelected(pawn) || Find.Selector.NumSelected > 1 && Event.current.button == 1) + { + Find.Selector.ClearSelection(); + Find.Selector.Select(pawn); + } + } + } + else //default + { + CameraJumper.TryJumpAndSelect(target, mode); + } + } + + public static void SodThisImOut(MainTabsRoot o1, bool o2) + { + if (!Numbers_Settings.pawnTableClickSelect) + o1.EscapeCurrentTab(o2); + } + + private static NeedDef _dummyNeed; + public static NeedDef DummyNeed => _dummyNeed ??= DefDatabase.GetNamedSilentFail("Authority"); + // the xml says + // + // temporary my ass. + + private static IEnumerable ImpliedPawnColumnDefs() + => DefDatabase.AllDefsListForReading.Select(GenerateNewPawnColumnDefFor) + .Concat(DefDatabase + .AllDefsListForReading.Select(GenerateNewPawnColumnDefFor)) + .Concat(DefDatabase + .AllDefsListForReading.Except(DummyNeed).Select(GenerateNewPawnColumnDefFor)) + .Concat(DefDatabase + .AllDefsListForReading.Select(GenerateNewPawnColumnDefFor)) + .Concat(DefDatabase + .AllDefsListForReading.Select(GenerateNewPawnColumnDefFor)) + .Concat(DefDatabase + .AllDefsListForReading.Select(GenerateNewPawnColumnDefFor)); + + private static PawnColumnDef GenerateNewPawnColumnDefFor(Def def) + { + bool prependDescription = def is not PawnCapacityDef; + PawnColumnDef pcd = new() + { + defName = HorribleStringParsersForSaving.CreateDefNameFromType(def), + sortable = true, + headerTip = (prependDescription ? def.description + "\n\n" : "") + "Numbers_ColumnHeader_Tooltip".Translate(), + generated = true, + label = def.LabelCap, + modContentPack = def.modContentPack, + modExtensions = [new DefModExtension_PawnColumnDefs()] + }; + switch (def) + { + case RecordDef recordDef: + pcd.workerClass = typeof(PawnColumnWorker_Record); + pcd.GetModExtension().record = recordDef; + break; + case PawnCapacityDef pawnCapacityDef: + pcd.workerClass = typeof(PawnColumnWorker_Capacity); + pcd.GetModExtension().capacity = pawnCapacityDef; + break; + case NeedDef needDef: + pcd.workerClass = typeof(PawnColumnWorker_Need); + pcd.GetModExtension().need = needDef; + break; + case StatDef statDef: + pcd.workerClass = typeof(PawnColumnWorker_Stat); + pcd.GetModExtension().stat = statDef; + break; + case SkillDef skillDef: + pcd.workerClass = typeof(PawnColumnWorker_Skill); + pcd.GetModExtension().skill = skillDef; + break; + case AbilityDef abilityDef: + pcd.workerClass = typeof(PawnColumnWorker_Ability); + pcd.GetModExtension().ability = abilityDef; + break; + default: + throw new ArgumentException($"Unsupported Def of type {def.GetType()}"); + } + + return pcd; + } + + + private static Vector2 scrollPosition; + + public override void DoSettingsWindowContents(Rect inRect) + { + base.DoSettingsWindowContents(inRect); + + Listing_Standard listingStandard = new(); + listingStandard.Begin(inRect); + listingStandard.CheckboxLabeled("Numbers_showMoreInfoThanVanilla".Translate(), ref Numbers_Settings.showMoreInfoThanVanilla); + listingStandard.CheckboxLabeled("Numbers_coolerThanTheWildlifeTab".Translate(), ref Numbers_Settings.coolerThanTheWildlifeTab); + listingStandard.CheckboxLabeled("Numbers_coolerThanTheAnimalTab".Translate(), ref Numbers_Settings.coolerThanTheAnimalTab); + listingStandard.CheckboxLabeled("Numbers_pawnTableClickSelect".Translate(), ref Numbers_Settings.pawnTableClickSelect, "Numbers_pawnTableClickSelect_Desc".Translate()); + listingStandard.CheckboxLabeled("Numbers_pawnTableHighSelected".Translate(), ref Numbers_Settings.pawnTableHighlightSelected, "Numbers_pawnTableHighSelected_Desc".Translate()); + listingStandard.CheckboxLabeled("Numbers_useSmolFont".Translate(), ref Numbers_Settings.useTinyFont); + listingStandard.SliderLabeled("Numbers_maxTableHeight".Translate(), ref Numbers_Settings.maxHeight, Numbers_Settings.maxHeight.ToStringPercent(), 0.3f); + listingStandard.End(); + + DrawResetButton(inRect); + + DrawStoredTables(inRect); + + //writing is done by closing the window. + } + + private void DrawStoredTables(Rect inRect) + { + float rowHeight = 20f; + float buttonHeight = 16f; + + float height = RegenPawnTableDefsFromSettings().Count * rowHeight; + Rect outRect; + float num = 0f; + int num2 = 0; + + //erdelf unknowningly to the rescue + Widgets.BeginScrollView(inRect.BottomPart(0.6f).TopPart(0.8f), ref scrollPosition, outRect = new Rect(inRect.x, inRect.y - rowHeight * 2, inRect.width - 18f, height)); + List list = RegenPawnTableDefsFromSettings(); + for (int i = 0; i < list.Count; i++) + { + string current = list[i]; + + if (num + rowHeight >= scrollPosition.y && num <= scrollPosition.y + outRect.height) + { + Rect rect = new(0f, num, outRect.width, rowHeight); + if (num2 % 2 == 0) + { + Widgets.DrawAltRect(rect); + } + GUI.BeginGroup(rect); + Rect rect2 = new(rect.width - buttonHeight, (rect.height - buttonHeight) / 2f, buttonHeight, buttonHeight); + if (Widgets.ButtonImage(rect2, StaticConstructorOnGameStart.DeleteX, Color.white, GenUI.SubtleMouseoverColor)) + { + settings.storedPawnTableDefs.RemoveAt(i); + } + TooltipHandler.TipRegion(rect2, "delet this"); + + Rect rect5 = new(0, 0, rect.width - rowHeight - 2f, rect.height); + Text.Anchor = TextAnchor.MiddleLeft; + Text.Font = GameFont.Small; + + Widgets.Label(rect5, current); + GUI.color = Color.white; + Text.Anchor = TextAnchor.UpperLeft; + GUI.EndGroup(); + } + num += rowHeight; + num2++; + } + Widgets.EndScrollView(); + } + + private static void DrawResetButton(Rect inRect) + { + if (Widgets.ButtonText(inRect.BottomPart(0.5f).TopPart(0.1f), "Numbers_resetToDefault".Translate())) + { + var worldComp = Find.World.GetComponent(); + worldComp?.sessionTable.Clear(); + + foreach (var (pawnTable, columns) in StaticConstructorOnGameStart.PawnTableDef_Columns) + { + if (worldComp == null) + { + break; + } + var def = DefDatabase.GetNamed(pawnTable); + + List newColumnList = []; + + foreach (var columnName in columns) + { + var columnDef = DefDatabase.GetNamed(columnName); + newColumnList.Add(columnDef); + } + worldComp.sessionTable[def] = newColumnList; + def.columns = newColumnList; + } + } + } + + public override void WriteSettings() + { + base.WriteSettings(); + Find.World?.GetComponent()?.NotifySettingsChanged(); + } + + private readonly List cachedList = []; + + private List RegenPawnTableDefsFromSettings() + { + cachedList.Clear(); + + foreach (string storedPawnTableDef in settings.storedPawnTableDefs) + { + if (storedPawnTableDef.Split(',')[1] == "Default") + cachedList.Add(storedPawnTableDef.Split(',')[0].Split('_')[1] + " (" + storedPawnTableDef.Split(',')[1] + ")"); + //Numbers_MainTable,Default => MainTable (Default) + else + cachedList.Add(storedPawnTableDef.Split(',')[1]); + } + return cachedList; + } + + public override string SettingsCategory() => "Numbers"; + } +} diff --git a/Numbers/Numbers.csproj b/Numbers/Numbers.csproj new file mode 100644 index 0000000..e8c57e5 --- /dev/null +++ b/Numbers/Numbers.csproj @@ -0,0 +1,19 @@ + + + net48 + Numbers + Numbers + Copyright © Mehni 2024 + 1.1.0.0 + none + latest + ..\1.5\Assemblies\ + false + + + + + all + + + \ No newline at end of file diff --git a/Numbers/Numbers_PawnColumnDef.cs b/Numbers/Numbers_PawnColumnDef.cs new file mode 100644 index 0000000..8ad722f --- /dev/null +++ b/Numbers/Numbers_PawnColumnDef.cs @@ -0,0 +1,15 @@ +using RimWorld; +using Verse; + +namespace Numbers +{ + public class Numbers_PawnColumnDef : PawnColumnDef + { + public RecordDef record; + public PawnCapacityDef capacity; + public NeedDef need; + public StatDef stat; + public SkillDef skill; + public PrisonerInteractionModeDef prisonerInteraction; + } +} diff --git a/Numbers/Numbers_Settings.cs b/Numbers/Numbers_Settings.cs new file mode 100644 index 0000000..d1c8588 --- /dev/null +++ b/Numbers/Numbers_Settings.cs @@ -0,0 +1,56 @@ +namespace Numbers +{ + using System.Collections.Generic; + using Verse; + + public class Numbers_Settings : ModSettings + { + + public static float maxHeight = 1f; + + public static bool showMoreInfoThanVanilla = true; + public static bool coolerThanTheWildlifeTab = true; // don't deny it. + public static bool coolerThanTheAnimalTab = false; // you flatter me. + + public static bool pawnTableHighlightSelected = true; + public static bool pawnTableClickSelect = true; + + public static bool useTinyFont = false; + + public List storedPawnTableDefs = []; + private readonly List workingList = []; + + public void StoreNewPawnTableDef(string pawnTableDeftoSave) + { + workingList.Clear(); + foreach (string ptd in storedPawnTableDefs) + { + workingList.Add(ptd.Split(',')[0] + ptd.Split(',')[1]); + } + //overwrite old one + string label = pawnTableDeftoSave.Split(',')[0] + pawnTableDeftoSave.Split(',')[1]; + + if (workingList.Contains(label)) + storedPawnTableDefs.RemoveAll(x => x.Split(',')[0] + x.Split(',')[1] == label); + + if (label == "Default") + storedPawnTableDefs.Insert(0, pawnTableDeftoSave); + else + storedPawnTableDefs.Add(pawnTableDeftoSave); + + Write(); + } + + public override void ExposeData() + { + Scribe_Values.Look(ref showMoreInfoThanVanilla, "showMoreInfoThanVanilla", true); + Scribe_Values.Look(ref coolerThanTheWildlifeTab, "coolerThanTheWildlifeTab", true); + Scribe_Values.Look(ref coolerThanTheAnimalTab, "coolerThanTheAnimalTab"); + Scribe_Values.Look(ref pawnTableHighlightSelected, "pawnTableHighlightSelected", true); + Scribe_Values.Look(ref pawnTableClickSelect, "pawnTableClickSelect", true); + Scribe_Values.Look(ref maxHeight, "maxHeight", 1f); + Scribe_Values.Look(ref useTinyFont, "useTinyFont"); + Scribe_Collections.Look(ref storedPawnTableDefs, "numbersPawnTableDefs"); + } + } +} diff --git a/Numbers/Numbers_SettingsHelper.cs b/Numbers/Numbers_SettingsHelper.cs new file mode 100644 index 0000000..f5ff717 --- /dev/null +++ b/Numbers/Numbers_SettingsHelper.cs @@ -0,0 +1,39 @@ +namespace Numbers +{ + using System; + using UnityEngine; + using Verse; + + static class Numbers_SettingsHelper + { + public static void SliderLabeled(this Listing_Standard ls, string label, ref int val, string format, float min = 0f, float max = 100f, string tooltip = null) + { + float fVal = val; + ls.SliderLabeled(label: label, val: ref fVal, format: format, min: min, max: max, tooltip: tooltip); + val = (int)fVal; + } + public static void SliderLabeled(this Listing_Standard ls, string label, ref float val, string format, float min = 0f, float max = 1f, string tooltip = null) + { + Rect rect = ls.GetRect(height: Text.LineHeight); + Rect rect2 = rect.LeftPart(pct: .70f).Rounded(); + Rect rect3 = rect.RightPart(pct: .30f).Rounded().LeftPart(pct: .67f).Rounded(); + Rect rect4 = rect.RightPart(pct: .10f).Rounded(); + + TextAnchor anchor = Text.Anchor; + Text.Anchor = TextAnchor.MiddleLeft; + Widgets.Label(rect: rect2, label: label); + + float result = Widgets.HorizontalSlider(rect: rect3, value: val, min: min, max: max, middleAlignment: true); + val = result; + Text.Anchor = TextAnchor.MiddleRight; + Widgets.Label(rect: rect4, label: String.Format(format: format, arg0: val)); + if (!tooltip.NullOrEmpty()) + { + TooltipHandler.TipRegion(rect: rect, tip: tooltip); + } + + Text.Anchor = anchor; + ls.Gap(gapHeight: ls.verticalSpacing); + } + } +} diff --git a/Numbers/Numbers_Utility.cs b/Numbers/Numbers_Utility.cs new file mode 100644 index 0000000..0560b83 --- /dev/null +++ b/Numbers/Numbers_Utility.cs @@ -0,0 +1,106 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public static class Numbers_Utility + { + public static bool IsEnemy(this Pawn p) + => p.HostileTo(Faction.OfPlayer); + + public static bool IsGuest(this Pawn p) + => p.guest != null + && !p.guest.IsPrisoner + && p.Faction != null + && !p.Faction.HostileTo(Faction.OfPlayer) + && p.Faction != Faction.OfPlayer; + + public static bool IsVisible(this Pawn p) + => p.SpawnedOrAnyParentSpawned + && p.PositionHeld != IntVec3.Invalid + && !p.PositionHeld.Fogged(p.MapHeld); + + public static bool IsWildAnimal(this Pawn p) + => p.Faction == null + && p.AnimalOrWildMan(); + + public static bool IsAnimal(this Pawn p) + => p.RaceProps != null + && p.RaceProps.Animal; + + public static DefModExtension_PawnColumnDefs Ext(this PawnColumnDef def, bool logError = true) + { + var ext = def.GetModExtension(); + + if (logError && ext == null) + { + Log.Error($"Numbers expected DefModExtension PawnColumnDefs, got null for def {def.defName}"); + } + + return ext; + } + + public static DefModExtension_PawnTableDefs Ext(this PawnTableDef def) + { + var ext = def.GetModExtension(); + + if (ext == null) + { + Log.Error($"Numbers expected DefModExtension PawnTableDef, got null for def {def.defName}"); + } + + return ext; + } + + public static string WordWrapAt(this string text, float length, PawnTable table = null) + { + if (table != null && table is not PawnTable_NumbersMain) + return text.Truncate(length); + + IEnumerable> source = from p in text.Select((c, idx) => new Pair(c, idx)) + where p.First == ' ' + select p; + if (!source.Any()) + { + return text; + } + Pair pair = source.MinBy(p => Mathf.Abs(Text.CalcSize(text.Substring(0, p.Second)).x - Text.CalcSize(text.Substring(p.Second + 1)).x)); + return text.Substring(0, pair.Second) + "\n" + text.Substring(pair.Second + 1); + } + + public static bool InfoCardButton(float x, float y, string text) + { + if (InfoCardButtonWorker(x, y)) + { + Find.WindowStack.Add(new Dialog_MessageBox(text)); + return true; + } + return false; + } + + private static bool InfoCardButtonWorker(float x, float y) + { + Rect rect = new(x, y, 24f, 24f); + TooltipHandler.TipRegion(rect, "DefInfoTip".Translate()); + bool result = Widgets.ButtonImage(rect, StaticConstructorOnGameStart.Info, GUI.color); + UIHighlighter.HighlightOpportunity(rect, "InfoCard"); + return result; + } + } + + [DefOf] + public class NumbersDefOf + { + public static PawnTableDef Numbers_MainTable; //aka Colonists + public static PawnTableDef Numbers_Enemies; + public static PawnTableDef Numbers_Prisoners; + public static PawnTableDef Numbers_Guests; + public static PawnTableDef Numbers_Animals; + public static PawnTableDef Numbers_WildAnimals; + public static PawnTableDef Numbers_Corpses; + public static PawnTableDef Numbers_AnimalCorpses; + } +} diff --git a/Numbers/OptionsMaker.cs b/Numbers/OptionsMaker.cs new file mode 100644 index 0000000..496a249 --- /dev/null +++ b/Numbers/OptionsMaker.cs @@ -0,0 +1,304 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public class OptionsMaker + { + private readonly MainTabWindow_Numbers numbers; + private readonly Numbers_Settings settings; + + private PawnColumnDef _allowedareawide; + private PawnColumnDef AllowedAreaWide => _allowedareawide ??= _allowedareawide = DefDatabase.GetNamedSilentFail("AllowedAreaWide"); + + private PawnColumnDef _allowedarea; + private PawnColumnDef AllowedArea => _allowedarea ??= _allowedarea = DefDatabase.GetNamedSilentFail("AllowedArea"); + + private PawnColumnDef _xenoType; + private PawnColumnDef XenoType => _xenoType ??= _xenoType = DefDatabase.GetNamedSilentFail("Xenotype"); + + private PawnTableDef PawnTable + { + get => numbers.pawnTableDef; + set => numbers.pawnTableDef = value; + } + + private static readonly Func filterRoyalty = pcd => ModLister.RoyaltyInstalled || !pcd.HasModExtension(); + private static readonly Func filterBioTech = pcd => ModLister.BiotechInstalled || !pcd.HasModExtension(); + private static readonly Func filterIdeology = pcd => ModLister.IdeologyInstalled || !pcd.HasModExtension(); + + public OptionsMaker(MainTabWindow_Numbers mainTabWindow) + { + numbers = mainTabWindow; + settings = LoadedModManager.GetMod().GetSettings(); + } + + public List PresetOptionsMaker() + { + var savedLayouts = LoadPlayerCreatedLayouts(); + List list = + [ + new FloatMenuOption("Numbers_SaveCurrentLayout".Translate(), Save) + ]; + list.AddRange(savedLayouts); + + list.AddRange( + [ + new FloatMenuOption("Numbers_Presets.Load".Translate("Numbers_Presets.Medical".Translate()), () => ChangeMainTableTo(StaticConstructorOnGameStart.medicalPreset)), + new FloatMenuOption("Numbers_Presets.Load".Translate("Numbers_Presets.Combat".Translate()), () => ChangeMainTableTo(StaticConstructorOnGameStart.combatPreset)), + new FloatMenuOption("Numbers_Presets.Load".Translate("Numbers_Presets.WorkTabPlus".Translate()), () => ChangeMainTableTo(StaticConstructorOnGameStart.workTabPlusPreset)), + new FloatMenuOption("Numbers_Presets.Load".Translate("Numbers_Presets.ColonistNeeds".Translate()), () => ChangeMainTableTo(StaticConstructorOnGameStart.colonistNeedsPreset)), + //maybe Psycasting here, index 6 + savedLayouts.Count, referenced below + new FloatMenuOption("Numbers_SetAsDefault".Translate(), SetAsDefault, + extraPartWidth: 29f, + extraPartOnGUI: rect => Numbers_Utility.InfoCardButton(rect.x + 5f, rect.y + (rect.height - 24f) / 2, "Numbers_SetAsDefaultExplanation".Translate(PawnTable.LabelCap))), + new FloatMenuOption("Numbers_LoadDefault".Translate(), LoadDefault) + ]); + if (ModLister.RoyaltyInstalled) + { + list.Insert(6 + savedLayouts.Count, new FloatMenuOption("Numbers_Presets.Load".Translate("Numbers_Presets.Psycasting".Translate()), () => ChangeMainTableTo(StaticConstructorOnGameStart.psycastingPreset))); + } + + return list; + } + + private IEnumerable General() + { + yield return new FloatMenuOption("Race".Translate(), () => AddPawnColumnAtBestPositionAndRefresh(DefDatabase.GetNamedSilentFail("Numbers_Race"))); + yield return new FloatMenuOption("Faction".Translate(), () => AddPawnColumnAtBestPositionAndRefresh(DefDatabase.GetNamedSilentFail("Numbers_Faction"))); + yield return new FloatMenuOption("Gender", () => AddPawnColumnAtBestPositionAndRefresh(DefDatabase.GetNamedSilentFail("Gender"))); + } + + public List FloatMenuOptionsFor(IEnumerable pcdList) + => pcdList.Select(pcd => new FloatMenuOption(GetBestLabelForPawnColumn(pcd), () => AddPawnColumnAtBestPositionAndRefresh(pcd))).ToList(); + + public List OtherOptionsMaker() + { + List list = [.. General()]; + + //equipment bearers + if (new[] { NumbersDefOf.Numbers_MainTable, + NumbersDefOf.Numbers_Prisoners, + NumbersDefOf.Numbers_Enemies, + NumbersDefOf.Numbers_Corpses, + NumbersDefOf.Numbers_Guests + }.Contains(PawnTable)) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.EquipmentBearers.options)); + } + + //all living things + if (!new[] { NumbersDefOf.Numbers_AnimalCorpses, NumbersDefOf.Numbers_Corpses }.Contains(PawnTable)) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.LivingThings.options)); + } + + if (PawnTable == NumbersDefOf.Numbers_Prisoners) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.Prisoners.options)); + } + + if (PawnTable == NumbersDefOf.Numbers_Animals) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.Animals.options + .Concat(DefDatabase.GetNamed("Animals").columns) + .Where(x => pcdValidator(x)) + .Except([AllowedArea, AllowedAreaWide]))); + } + + if (PawnTable == NumbersDefOf.Numbers_MainTable) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.MainTable.options + .Concat(DefDatabase.GetNamed("Assign").columns) + .Concat(DefDatabase.GetNamed("Restrict").columns) + .Where(x => pcdValidator(x)) + .Except([AllowedArea, AllowedAreaWide, XenoType]))); + } + + if (PawnTable == NumbersDefOf.Numbers_WildAnimals) + { + list.RemoveAll(x => x.Label == "Gender"); //duplicate + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.WildAnimals.options + .Concat(DefDatabase.GetNamed("Wildlife").columns) + .Where(x => pcdValidator(x)))); + } + + //all dead things + if (new[] { NumbersDefOf.Numbers_AnimalCorpses, NumbersDefOf.Numbers_Corpses }.Contains(PawnTable)) + { + list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.DeadThings.options)); + } + + return [.. list.OrderBy(x => x.Label)]; + } + + public List OptionsMakerForGenericDef(IEnumerable listOfDefs) where T : Def + { + List list = []; + + foreach (var defCurrent in listOfDefs) + { + void Action() + { + PawnColumnDef pcd = DefDatabase.GetNamedSilentFail(HorribleStringParsersForSaving.CreateDefNameFromType(defCurrent)); + AddPawnColumnAtBestPositionAndRefresh(pcd); + } + string label = defCurrent.LabelCap; + list.Add(new FloatMenuOption(label, Action)); + } + + return list; + } + + public List PawnSelector() + { + List list = []; + foreach (KeyValuePair> filter in WorldComponent_Numbers.PrimaryFilter) + { + void Action() + { + if (filter.Value != MainTabWindow_Numbers.filterValidator.First()) + { + PawnTable = filter.Key; + + if (Find.World.GetComponent().sessionTable.TryGetValue(filter.Key, out List listPawnColumDef)) + PawnTable.columns = listPawnColumDef; + + numbers.UpdateFilter(); + numbers.Notify_ResolutionChanged(); + } + } + list.Add(new FloatMenuOption(filter.Key.label, Action)); + } + return list; + } + + private void Save() + { + //not actually saved like this, just the easiest way to pass it around + PawnTableDef ptdPawnTableDef = new() + { + columns = PawnTable.columns, + modContentPack = PawnTable.modContentPack, + workerClass = PawnTable.workerClass, + defName = PawnTable.defName, + label = "NumbersTable" + Rand.Range(0, 10000) + }; + Find.WindowStack.Add(new Dialog_IHaveToCreateAnEntireFuckingDialogForAGODDAMNOKAYBUTTONFFS(ptdPawnTableDef)); + } + + private List LoadPlayerCreatedLayouts() + { + List loadOptions = []; + foreach (string tableDefToBe in settings.storedPawnTableDefs) + { + void ApplySetting() + { + PawnTableDef ptD = HorribleStringParsersForSaving.TurnCommaDelimitedStringIntoPawnTableDef(tableDefToBe); + + PawnTable = DefDatabase.GetNamed(ptD.defName); + PawnTable.columns = ptD.columns; + + numbers.UpdateFilter(); + numbers.RefreshAndStoreSessionInWorldComp(); + } + string label = tableDefToBe.Split(',')[1] == "Default" ? tableDefToBe.Split(',')[0].Split('_')[1] + " (" + tableDefToBe.Split(',')[1] + ")" : tableDefToBe.Split(',')[1]; + loadOptions.Add(new FloatMenuOption(label, ApplySetting)); + } + + return loadOptions; + } + + private void ChangeMainTableTo(List list) + { + PawnTable = NumbersDefOf.Numbers_MainTable; + PawnTable.columns = new List(list); + numbers.UpdateFilter(); + numbers.Notify_ResolutionChanged(); + } + + private void SetAsDefault() + { + string pawnTableDeftoSave = HorribleStringParsersForSaving.TurnPawnTableDefIntoCommaDelimitedString(PawnTable, true); + settings.StoreNewPawnTableDef(pawnTableDeftoSave); + } + + private void LoadDefault() + { + bool foundSomething = false; + foreach (string tableDefToBe in settings.storedPawnTableDefs) + { + string[] ptdToBe = tableDefToBe.Split(','); + if (ptdToBe[1] == "Default" && PawnTable.defName == ptdToBe[0]) + { + foundSomething = true; + PawnTableDef ptD = HorribleStringParsersForSaving.TurnCommaDelimitedStringIntoPawnTableDef(tableDefToBe); + + PawnTable = DefDatabase.GetNamed(ptD.defName); + PawnTable.columns = ptD.columns; + numbers.UpdateFilter(); + numbers.RefreshAndStoreSessionInWorldComp(); + break; + } + } + if (!foundSomething) + Messages.Message("Numbers_NoDefaultStoredForThisView".Translate(), MessageTypeDefOf.RejectInput); + } + + private static string GetBestLabelForPawnColumn(PawnColumnDef pcd) + { + if (pcd == null) + return string.Empty; + + if (pcd.workType != null) + return pcd.workType.labelShort; + + if (!pcd.LabelCap.NullOrEmpty()) + return pcd.LabelCap; + + if (!pcd.headerTip.NullOrEmpty()) + return pcd.headerTip; + + return pcd.defName; + } + + private void AddPawnColumnAtBestPositionAndRefresh(PawnColumnDef pcd) + { + if (pcd == null) + return; + int lastIndex = PawnTable.columns.FindLastIndex(x => x.Worker is PawnColumnWorker_RemainingSpace); + PawnTable.columns.Insert(Mathf.Max(1, lastIndex), pcd); + + numbers.RefreshAndStoreSessionInWorldComp(); + } + + private static readonly Func pcdValidator = pcd => + { + try + { + return pcd.Worker is not PawnColumnWorker_Gap + && pcd.Worker is not PawnColumnWorker_Label + && pcd.Worker is not PawnColumnWorker_RemainingSpace + && pcd.Worker is not PawnColumnWorker_CopyPaste + && pcd.Worker is not PawnColumnWorker_MedicalCare + && pcd.Worker is not RimWorld.PawnColumnWorker_Ideo //definitely don't want the vanilla one. + && pcd.Worker is not RimWorld.PawnColumnWorker_MentalState //definitely don't want the vanilla one. + && pcd.Worker is not PawnColumnWorker_Timetable + || (!(pcd.label.NullOrEmpty() && pcd.HeaderIcon == null) && !pcd.HeaderInteractable) + && filterRoyalty(pcd) + && filterIdeology(pcd) + && filterBioTech(pcd); + } + catch (ArgumentNullException ex) + { + Log.Error($"{pcd.defName} from {pcd.modContentPack.Name} threw ArgumentNullException {ex}"); + return false; + } + }; + //basically all that are already present, don't have an interactable header, and uh + } +} diff --git a/Numbers/PawnColumnOptionDef.cs b/Numbers/PawnColumnOptionDef.cs new file mode 100644 index 0000000..63c2cb7 --- /dev/null +++ b/Numbers/PawnColumnOptionDef.cs @@ -0,0 +1,28 @@ +namespace Numbers +{ + using RimWorld; + using System.Collections.Generic; + using Verse; + + public class PawnColumnOptionDef : Def + { + public List options; + } + + [DefOf] + public class PawnColumnOptionDefOf + { + public static PawnColumnOptionDef EquipmentBearers; + public static PawnColumnOptionDef LivingThings; + public static PawnColumnOptionDef Prisoners; + public static PawnColumnOptionDef Animals; + public static PawnColumnOptionDef MainTable; + public static PawnColumnOptionDef WildAnimals; + public static PawnColumnOptionDef DeadThings; + + public PawnColumnOptionDefOf() + { + DefOfHelper.EnsureInitializedInCtor(typeof(PawnColumnOptionDef)); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Ability.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Ability.cs new file mode 100644 index 0000000..fb90545 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Ability.cs @@ -0,0 +1,53 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + public class PawnColumnWorker_Ability : PawnColumnWorker_Icon + { + + protected override Texture2D GetIconFor(Pawn pawn) + { + AbilityDef abilityDef = def.Ext().ability; + foreach (Ability a in pawn.abilities.abilities) + { + if (a.def == abilityDef) + { + return abilityDef.uiIcon; + } + } + return null; + } + + public override int GetMinWidth(PawnTable table) + { + return 26; + } + + protected override string GetHeaderTip(PawnTable table) => def.Ext().ability.GetTooltip() + "\n\n" + "Numbers_ColumnHeader_Tooltip".Translate(); + + public override void DoHeader(Rect rect, PawnTable table) + { + Rect interactableHeaderRect = GetInteractableHeaderRect(rect, table); + if (Mouse.IsOver(interactableHeaderRect)) + { + Widgets.DrawHighlight(interactableHeaderRect); + string headerTip = GetHeaderTip(table); + if (!headerTip.NullOrEmpty()) + { + TooltipHandler.TipRegion(interactableHeaderRect, headerTip); + } + } + if (Widgets.ButtonInvisible(interactableHeaderRect)) + { + HeaderClicked(rect, table); + } + + Texture2D abilityIcon = def.Ext().ability.uiIcon; + Rect position = new(rect.x, rect.yMax - 26, 26, 26); + GUI.DrawTexture(position, abilityIcon); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Age.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Age.cs new file mode 100644 index 0000000..a8f13cb --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Age.cs @@ -0,0 +1,18 @@ +namespace Numbers +{ + using System; + using RimWorld; + using Verse; + + public class PawnColumnWorker_Age : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => Math.Round(pawn.ageTracker.AgeBiologicalYearsFloat, 2).ToString("0.00"); + + public override int Compare(Pawn a, Pawn b) + => a.ageTracker.AgeBiologicalYearsFloat.CompareTo(b.ageTracker.AgeBiologicalYearsFloat); + + public override int GetMinWidth(PawnTable table) + => base.GetMinWidth(table) + 20; + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AllHediffs.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AllHediffs.cs new file mode 100644 index 0000000..beda605 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AllHediffs.cs @@ -0,0 +1,89 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_AllHediffs : PawnColumnWorker_Icon + { + protected override Texture2D GetIconFor(Pawn pawn) + => VisibleHediffs(pawn).Any() + ? StaticConstructorOnGameStart.Plus + : null; + + protected override string GetIconTip(Pawn pawn) + { + StringBuilder icontipBuilder = new(); + foreach (IGrouping diffs in VisibleHediffGroupsInOrder(pawn)) + { + foreach (IGrouping current in diffs.GroupBy(x => x.UIGroupKey)) + { + int count = current.Count(); + string text = current.First().LabelCap; + if (count != 1) + { + text = text + " x" + count; + } + icontipBuilder.AppendWithComma(text); + } + } + return icontipBuilder.ToString(); + } + + public override int Compare(Pawn a, Pawn b) + => VisibleHediffs(a).Count().CompareTo(VisibleHediffs(b).Count()); + + protected override string GetHeaderTip(PawnTable table) + => base.GetHeaderTip(table) + "\n\n" + "Numbers_ColumnHeader_Tooltip".Translate(); + + public override void DoHeader(Rect rect, PawnTable table) + { + base.DoHeader(rect, table); + GUI.color = Color.cyan; + float scale = 0.7f; + int sizeOfVanillaRescueTex = 24; + + Vector2 headerIconSize = new( + Mathf.Min(sizeOfVanillaRescueTex, StaticConstructorOnGameStart.Plus.width) * scale, + Mathf.Min(sizeOfVanillaRescueTex, StaticConstructorOnGameStart.Plus.height) * scale); + + int xOffSet = (int)((rect.width - headerIconSize.x) / 4f); + Rect position = new( + x: rect.x + xOffSet, + y: rect.yMax - Mathf.Min(sizeOfVanillaRescueTex, StaticConstructorOnGameStart.Plus.height), + width: headerIconSize.x, + height: headerIconSize.y); + + GUI.DrawTexture(position, StaticConstructorOnGameStart.Plus); + GUI.color = Color.white; + } + + protected virtual IEnumerable VisibleHediffs(Pawn pawn) + { + List mpca = pawn.health.hediffSet.GetMissingPartsCommonAncestors(); + foreach (Hediff_MissingPart t in mpca) + { + yield return t; + } + + IEnumerable visibleDiffs = pawn.health.hediffSet.hediffs.Where(d => !(d is Hediff_MissingPart) && d.Visible); + foreach (Hediff diff in visibleDiffs) + { + yield return diff; + } + } + + private IEnumerable> VisibleHediffGroupsInOrder(Pawn pawn) + => VisibleHediffs(pawn) + .GroupBy(x => x.Part) + .OrderByDescending(x => GetListPriority(x.First().Part)); + + private static float GetListPriority(BodyPartRecord rec) + => rec == null + ? 9999999f + : (int)rec.height * 10000 + rec.coverageAbsWithChildren; + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AllowedAreaWithMassAssign.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AllowedAreaWithMassAssign.cs new file mode 100644 index 0000000..c2ea0ea --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AllowedAreaWithMassAssign.cs @@ -0,0 +1,57 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using System.Linq; + using Verse; + + public class PawnColumnWorker_AllowedAreaWithMassAssign : PawnColumnWorker_AllowedAreaWide + { + public override int GetOptimalWidth(PawnTable table) + { + var assignableAreas = Find.CurrentMap.areaManager.AllAreas.Where(area => area.AssignableAsAllowed()); + var bla = Text.CalcSize(assignableAreas.Select(x => x.Label).ToCommaList()); + return (int)Mathf.Max(bla.x + 48, def.width); + } + + public override int GetMinWidth(PawnTable table) + { + return Mathf.Min(def.width, GetOptimalWidth(table)); + } + + protected override string GetHeaderTip(PawnTable table) + { + return base.GetHeaderTip(table) + "\nShift + control + click: Set all pawns to zone"; + } + + protected override void HeaderClicked(Rect headerRect, PawnTable table) + { + base.HeaderClicked(headerRect, table); + if (Find.CurrentMap == null) + { + return; + } + var allAreas = Find.CurrentMap.areaManager.AllAreas; + var assignableAreas = 1 + allAreas.Count(area => area.AssignableAsAllowed()); + var rectWidth = headerRect.width / assignableAreas; + Text.WordWrap = false; + Text.Font = GameFont.Tiny; + var areaIndexOffset = 1; + foreach (var area in allAreas) + { + if (area.AssignableAsAllowed()) + { + var startPosition = areaIndexOffset * rectWidth; + var rect = new Rect(headerRect.x + startPosition, headerRect.y, rectWidth, headerRect.height); + if (Mouse.IsOver(rect) && Event.current.control && Event.current.shift && Event.current.button == 0) + { + table.PawnsListForReading.ForEach(pawn => pawn.playerSettings.AreaRestrictionInPawnCurrentMap = area); + } + areaIndexOffset++; + } + } + Text.WordWrap = true; + Text.Font = GameFont.Small; + } + } +} \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalEggProgress.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalEggProgress.cs new file mode 100644 index 0000000..13b2c29 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalEggProgress.cs @@ -0,0 +1,37 @@ +namespace Numbers +{ + using System.Linq; + using HarmonyLib; + using RimWorld; + using Verse; + + public class PawnColumnWorker_AnimalEggProgress : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.reproductive) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompEggLayer); + + if (comp != null) + return ((float)Traverse.Create((CompEggLayer)comp).Field("eggProgress").GetValue()).ToStringPercent(); + } + return null; + } + + public override int Compare(Pawn a, Pawn b) + => GetScoreFor(a).CompareTo(GetScoreFor(b)); + + private float GetScoreFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.reproductive) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompEggLayer); + + if (comp != null) + return (float)Traverse.Create((CompEggLayer)comp).Field("eggProgress").GetValue(); + } + return -1; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalFilthRate.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalFilthRate.cs new file mode 100644 index 0000000..dddcaab --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalFilthRate.cs @@ -0,0 +1,21 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_AnimalFilthRate : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return GetScoreFor(pawn).ToString("F2"); + } + + public override int Compare(Pawn a, Pawn b) + => GetScoreFor(a).CompareTo(GetScoreFor(b)); + + private float GetScoreFor(Pawn pawn) + { + return pawn.GetStatValueForPawn(StatDefOf.FilthRate, pawn); + } + } +} \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalMilkFullness.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalMilkFullness.cs new file mode 100644 index 0000000..e89a34b --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalMilkFullness.cs @@ -0,0 +1,36 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using Verse; + + public class PawnColumnWorker_AnimalMilkFullness : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.milkable) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompMilkable); + + if (comp != null) + return ((CompMilkable)comp).Fullness.ToStringPercent(); + } + return null; + } + + public override int Compare(Pawn a, Pawn b) + => GetScoreFor(a).CompareTo(GetScoreFor(b)); + + private float GetScoreFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.milkable) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompMilkable); + + if (comp != null) + return ((CompMilkable)comp).Fullness; + } + return -1; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs new file mode 100644 index 0000000..e14db1b --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs @@ -0,0 +1,21 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_AnimalWildness : PawnColumnWorker_Text + { + public override int Compare(Pawn a, Pawn b) + => (a.AnimalOrWildMan() || b.AnimalOrWildMan()) + ? GetValue(a).CompareTo(GetValue(b)) + : 0; + + protected override string GetTextFor(Pawn pawn) + => pawn.AnimalOrWildMan() + ? GetValue(pawn).ToStringPercent() + : string.Empty; + + private float GetValue(Pawn pawn) + => pawn.RaceProps.wildness; + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWoolGrowth.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWoolGrowth.cs new file mode 100644 index 0000000..1bef1ac --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWoolGrowth.cs @@ -0,0 +1,36 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using Verse; + + public class PawnColumnWorker_AnimalWoolGrowth : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.shearable) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompShearable); + + if (comp != null) + return ((CompShearable)comp).Fullness.ToStringPercent(); + } + return null; + } + + public override int Compare(Pawn a, Pawn b) + => GetScoreFor(a).CompareTo(GetScoreFor(b)); + + private float GetScoreFor(Pawn pawn) + { + if (pawn.ageTracker.CurLifeStage.shearable) + { + var comp = pawn.AllComps.FirstOrDefault(x => x is CompShearable); + + if (comp != null) + return ((CompShearable)comp).Fullness; + } + return -1; + } + } +} \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Backstory.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Backstory.cs new file mode 100644 index 0000000..0746c92 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Backstory.cs @@ -0,0 +1,17 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_Backstory : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.story.TitleShortCap; + + public override int GetMinWidth(PawnTable table) + => 80; + + public override int Compare(Pawn a, Pawn b) + => a.story.TitleShortCap.CompareTo(b.story.TitleShortCap); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Bandwidth.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Bandwidth.cs new file mode 100644 index 0000000..50bab62 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Bandwidth.cs @@ -0,0 +1,107 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + public class PawnColumnWorker_Bandwidth : PawnColumnWorker + { + private static readonly Color EmptyBlockColor = new(0.3f, 0.3f, 0.3f, 1f); + + private static readonly Color FilledBlockColor = ColorLibrary.Yellow; + + private static readonly Color ExcessBlockColor = ColorLibrary.Red; + + public override int Compare(Pawn a, Pawn b) + { + return (a.mechanitor?.TotalBandwidth ?? 0).CompareTo(b.mechanitor?.TotalBandwidth ?? 0); + } + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + var tracker = pawn.mechanitor; + if (tracker == null) + { + return; + } + //shamelessly ripped from MechanitorBandwithGizo. + int totalBandwidth = tracker.TotalBandwidth; + int usedBandwidth = tracker.UsedBandwidth; + string text = usedBandwidth.ToString("F0") + " / " + totalBandwidth.ToString("F0"); + TaggedString taggedString = "Bandwidth".Translate().Colorize(ColoredText.TipSectionTitleColor) + ": " + text + "\n\n" + "BandwidthGizmoTip".Translate(); + int usedBandwidthFromSubjects = tracker.UsedBandwidthFromSubjects; + if (usedBandwidthFromSubjects > 0) + { + taggedString += (string)("\n\n" + ("BandwidthUsage".Translate() + ": ")) + usedBandwidthFromSubjects; + IEnumerable entries = from p in tracker.OverseenPawns + where !p.IsGestating() + group p by p.kindDef into p + select (string)(p.Key.LabelCap + " x") + p.Count() + " (+" + p.Sum((Pawn mech) => mech.GetStatValue(StatDefOf.BandwidthCost)) + ")"; + taggedString += "\n\n" + entries.ToLineList(" - "); + } + int usedBandwidthFromGestation = tracker.UsedBandwidthFromGestation; + if (usedBandwidthFromGestation > 0) + { + taggedString += (string)("\n\n" + "MechGestationBandwidthUsed".Translate() + ": ") + usedBandwidthFromGestation; + IEnumerable entries2 = from p in tracker.OverseenPawns + where p.IsGestating() + group p by p.kindDef into p + select (string)(p.Key.LabelCap + " x") + p.Count() + " (+" + p.Sum((Pawn mech) => mech.GetStatValue(StatDefOf.BandwidthCost)) + ")"; + taggedString += "\n\n" + entries2.ToLineList(" - "); + } + TooltipHandler.TipRegion(rect, taggedString); + + int num = Mathf.Max(usedBandwidth, totalBandwidth); + + int num2 = 2; + int num3 = Mathf.FloorToInt(rect.height / (float)num2); + int num4 = Mathf.FloorToInt(rect.width / (float)num3); + int num5 = 0; + while (num2 * num4 < num) + { + num2++; + num3 = Mathf.FloorToInt(rect.height / (float)num2); + num4 = Mathf.FloorToInt(rect.width / (float)num3); + num5++; + if (num5 >= 1000) + { + Debug.LogError("Failed to fit bandwidth cells into rect."); + return; + } + } + int num6 = Mathf.FloorToInt(rect.width / (float)num3); + int num7 = num2; + float num8 = (rect.width - (float)(num6 * num3)) / 2f; + int num9 = 0; + int usedBandwidthFromGestation2 = tracker.UsedBandwidthFromGestation; + int num10 = ((num7 <= 2) ? 4 : 2); + for (int i = 0; i < num7; i++) + { + for (int j = 0; j < num6; j++) + { + num9++; + Rect rect5 = new Rect(rect.x + (float)(j * num3) + num8, rect.y + (float)(i * num3), num3, num3).ContractedBy(2f); + if (num9 <= num) + { + if (num9 <= usedBandwidthFromGestation2) + { + Widgets.DrawRectFast(rect5, EmptyBlockColor); + Widgets.DrawRectFast(rect5.ContractedBy(num10), FilledBlockColor); + } + else if (num9 <= usedBandwidth) + { + Widgets.DrawRectFast(rect5, (num9 <= totalBandwidth) ? FilledBlockColor : ExcessBlockColor); + } + else + { + Widgets.DrawRectFast(rect5, EmptyBlockColor); + } + } + } + } + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Bleedrate.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Bleedrate.cs new file mode 100644 index 0000000..f053391 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Bleedrate.cs @@ -0,0 +1,54 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Bleedrate : PawnColumnWorker_Text + { + private static readonly Color MediumPainColor = new(0.9f, 0.9f, 0f); + + private static readonly Color SeverePainColor = new(0.9f, 0.5f, 0f); + + public override int Compare(Pawn a, Pawn b) + => a.health.hediffSet.BleedRateTotal.CompareTo(b.health.hediffSet.BleedRateTotal); + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + GUI.color = FindPrettyColourForBleedingPawn(pawn); + base.DoCell(rect, pawn, table); + GUI.color = Color.white; + } + + protected override string GetTextFor(Pawn pawn) + => pawn.health.hediffSet.BleedRateTotal.ToStringPercent(); + + protected override string GetTip(Pawn pawn) + { + int ticksUntilDeathDueToBloodLoss = HealthUtility.TicksUntilDeathDueToBloodLoss(pawn); + + if (ticksUntilDeathDueToBloodLoss < GenDate.TicksPerDay) + return "TimeToDeath".Translate(ticksUntilDeathDueToBloodLoss.ToStringTicksToPeriod()); + + return "WontBleedOutSoon".Translate(); + } + + private Color FindPrettyColourForBleedingPawn(Pawn pawn) + { + float isThisMyBlood = pawn.health.hediffSet.BleedRateTotal; + + if (isThisMyBlood <= 0f) + return HealthUtility.GoodConditionColor; + + if (isThisMyBlood < 0.8f) + return Color.gray; + + if (isThisMyBlood < 1f && !Mathf.Approximately(isThisMyBlood, 1f)) + return MediumPainColor; + + return Mathf.Approximately(isThisMyBlood, 1f) + ? SeverePainColor + : HealthUtility.RedColor; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Capacity.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Capacity.cs new file mode 100644 index 0000000..d03c9fc --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Capacity.cs @@ -0,0 +1,32 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Capacity : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.health.capacities.GetLevel(def.Ext().capacity).ToStringPercent(); + + protected override string GetTip(Pawn pawn) + => HealthCardUtility.GetPawnCapacityTip(pawn, def.Ext().capacity); + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + GUI.color = HealthCardUtility.GetEfficiencyLabel(pawn, def.Ext().capacity).Second; + base.DoCell(rect, pawn, table); + GUI.color = Color.white; + } + + public override int GetMinWidth(PawnTable table) + => base.GetMinWidth(table) + 8; //based on Sight column. + + public override int Compare(Pawn a, Pawn b) + => a.health.capacities.GetLevel(def.Ext().capacity) + .CompareTo(b.health.capacities.GetLevel(def.Ext().capacity)); + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_DiseaseProgression.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_DiseaseProgression.cs new file mode 100644 index 0000000..d3c9a19 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_DiseaseProgression.cs @@ -0,0 +1,183 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using HarmonyLib; + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + public class PawnColumnWorker_DiseaseProgression : PawnColumnWorker + { + private static readonly Color SeverePainColor = new(0.9f, 0.5f, 0f); + + //[TweakValue("AAAADiseaseProgression")] //assumes a perfectly square icon. + public static float MaxIconSize = 22f; + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.Dead || pawn.health?.hediffSet == null || !pawn.health.hediffSet.HasImmunizableNotImmuneHediff()) + return; + + HediffWithComps mostSevere = FindMostSevereHediff(pawn); + + if (mostSevere == null) + return; + + float deltaSeverity = GetTextFor(mostSevere); + + GUI.color = GetPrettyColorFor(deltaSeverity); + + Rect rect2 = new(rect.x, rect.y, rect.width, Mathf.Min(rect.height, 30f)); + Text.Font = GameFont.Small; + Text.Anchor = TextAnchor.MiddleCenter; + Text.WordWrap = false; + Widgets.Label(rect2, GetTextFor(mostSevere).ToStringPercent()); + Text.WordWrap = true; + Text.Anchor = TextAnchor.UpperLeft; + string tip = GetTip(pawn, mostSevere); + if (!tip.NullOrEmpty()) + { + TooltipHandler.TipRegion(rect2, tip); + } + + float severityChangePerDayFromImmu = (float)AccessTools.Method(typeof(HediffComp_Immunizable), "SeverityChangePerDay") + .Invoke(mostSevere.TryGetComp(), null); + + float severityChangePerDayFromTendD = 0f; + + if (mostSevere.TryGetComp()?.IsTended ?? false) + { + severityChangePerDayFromTendD = + mostSevere.TryGetComp().TProps.severityPerDayTended * + mostSevere.TryGetComp().tendQuality; + } + + float immunityPerDay = 0f; + + ImmunityRecord immunityRecord = pawn.health.immunity.GetImmunityRecord(mostSevere.def); + if (immunityRecord != null) + immunityPerDay = immunityRecord.ImmunityChangePerTick(pawn, true, mostSevere) * GenDate.TicksPerDay; + + GUI.color = Color.white; + + bool redFlag = !(severityChangePerDayFromTendD + severityChangePerDayFromImmu > immunityPerDay); + + Texture2D texture2D = redFlag ? StaticConstructorOnGameStart.SortingIcon : StaticConstructorOnGameStart.SortingDescendingIcon; + GUI.color = redFlag ? HealthUtility.GoodConditionColor : HealthUtility.RedColor; + Rect position2 = new(rect.xMax - texture2D.width - 1f, rect.yMax - texture2D.height - 1f, texture2D.width, texture2D.height); + GUI.DrawTexture(position2, texture2D); + GUI.color = Color.white; + } + + public override void DoHeader(Rect rect, PawnTable table) + { + Texture2D skull = StaticConstructorOnGameStart.IconDead; + Texture2D immune = StaticConstructorOnGameStart.IconImmune; + + //[ [x] | [] ] + float oneFourthLeftCenteredOnIconWidth = (rect.width / 6) - MaxIconSize / 2; + //[ [] | [x] ] + float oneFourthRightCenteredOnIconWidth = (rect.width - (rect.width / 6)) - MaxIconSize / 2; + + //skull vs immunity icon. One left, one right. + Rect skullPosition = new(rect.x + oneFourthLeftCenteredOnIconWidth, rect.yMax - MaxIconSize, MaxIconSize, MaxIconSize); + GUI.DrawTexture(skullPosition, skull); + + Rect immunePosition = new(rect.x + oneFourthRightCenteredOnIconWidth, rect.yMax - MaxIconSize, MaxIconSize, MaxIconSize); + GUI.DrawTexture(immunePosition.ScaledBy(0.8f), immune); + + Rect rect2 = rect; + rect2.y += 3f; + Text.Anchor = TextAnchor.LowerCenter; + Widgets.Label(rect2, "vs"); + Text.Anchor = TextAnchor.UpperLeft; + + //rest is copypasta + if (table.SortingBy == def) + { + Texture2D texture2D = (!table.SortingDescending) ? StaticConstructorOnGameStart.SortingIcon : StaticConstructorOnGameStart.SortingDescendingIcon; + Rect position2 = new(rect.xMax - texture2D.width - 1f, rect.yMax - texture2D.height - 1f, texture2D.width, texture2D.height); + GUI.DrawTexture(position2, texture2D); + } + if (def.HeaderInteractable) + { + Rect interactableHeaderRect = GetInteractableHeaderRect(rect, table); + Widgets.DrawHighlightIfMouseover(interactableHeaderRect); + if (interactableHeaderRect.Contains(Event.current.mousePosition)) + { + string headerTip = GetHeaderTip(table); + if (!headerTip.NullOrEmpty()) + { + TooltipHandler.TipRegion(interactableHeaderRect, headerTip); + } + } + if (Widgets.ButtonInvisible(interactableHeaderRect)) + { + HeaderClicked(rect, table); + } + } + } + + public override int GetMinWidth(PawnTable table) + => def.width; + + private string GetTip(Pawn pawn, HediffWithComps severe) + => severe.LabelCap + ": " + severe.SeverityLabel + "\n" + severe.TipStringExtra; + + private float GetTextFor(HediffWithComps hediff) + => hediff?.TryGetComp().Immunity - hediff?.Severity ?? -1f; //nullcheck for Comparer. + + private Color GetPrettyColorFor(float deltaSeverity) + { + if (deltaSeverity <= -0.4f) + return HealthUtility.RedColor; + + if (deltaSeverity <= -0.2f) + return SeverePainColor; + + if (deltaSeverity <= -0.1f) + return HealthUtility.ImpairedColor; + + if (deltaSeverity <= -0.05f) + return HealthUtility.SlightlyImpairedColor; + + if (deltaSeverity <= 0.05f) + return Color.gray; + + return HealthUtility.GoodConditionColor; + } + + private HediffWithComps FindMostSevereHediff(Pawn pawn) + { + IEnumerable tmplist = + pawn.health.hediffSet.hediffs.Where(x => x.Visible && x is HediffWithComps && !x.FullyImmune()).Cast(); + + float delta = float.MinValue; + HediffWithComps mostSevereHediff = null; + + foreach (HediffWithComps hediff in tmplist) + { + HediffComp_Immunizable hediffCompImmunizable = hediff.TryGetComp(); + + if (hediffCompImmunizable == null) + continue; + + if (hediffCompImmunizable.Immunity - hediff.Severity > delta) + { + delta = hediffCompImmunizable.Immunity - hediff.Severity; + mostSevereHediff = hediff; + } + } + + return mostSevereHediff; + } + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(def.LabelCap.Resolve().WordWrapAt(GetMinWidth(table))).y); + + public override int Compare(Pawn a, Pawn b) + => GetTextFor(FindMostSevereHediff(a)).CompareTo(GetTextFor(FindMostSevereHediff(b))); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs new file mode 100644 index 0000000..0cfceb6 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs @@ -0,0 +1,48 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + public class PawnColumnWorker_Entropy : PawnColumnWorker + { + private static readonly Texture2D EntropyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.46f, 0.34f, 0.35f)); + + //mostly from PawnColumnWorker_Need + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (!pawn.HasPsylink) + return; + + float curEntropyLevel = pawn.psychicEntropy.EntropyRelativeValue; + + float barHeight = 14f; + float barWidth = barHeight + 15f; + if (rect.height < 50f) + { + barHeight *= Mathf.InverseLerp(0f, 50f, rect.height); + } + + Text.Font = (rect.height <= 55f) ? GameFont.Tiny : GameFont.Small; + Text.Anchor = TextAnchor.UpperLeft; + Rect rect3 = new(rect.x, rect.y + rect.height / 2f, rect.width, rect.height / 2f); + rect3 = new Rect(rect3.x + barWidth, rect3.y, rect3.width - barWidth * 2f, rect3.height - barHeight); + + Widgets.FillableBar(rect3, curEntropyLevel, EntropyBarTex); + + Text.Font = GameFont.Small; + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 110); + + public override int Compare(Pawn a, Pawn b) + { + int hasPsylink = a.HasPsylink.CompareTo(b.HasPsylink); + if (hasPsylink != 0) { return hasPsylink; } + return (a.psychicEntropy?.EntropyRelativeValue ?? 0f).CompareTo(b.psychicEntropy?.EntropyRelativeValue ?? 0f); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Faction.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Faction.cs new file mode 100644 index 0000000..890a3ff --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Faction.cs @@ -0,0 +1,18 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + class PawnColumnWorker_Faction : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.Faction?.Name; + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 150); + + public override int Compare(Pawn a, Pawn b) + => GetTextFor(a).CompareTo(GetTextFor(b)); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_FoodConsumption.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_FoodConsumption.cs new file mode 100644 index 0000000..08a70db --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_FoodConsumption.cs @@ -0,0 +1,16 @@ +using RimWorld; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_FoodConsumption : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => (pawn?.needs?.food?.FoodFallPerTickAssumingCategory(HungerCategory.Fed) * 60000f ?? 0).ToString("0.##"); + + public override int Compare(Pawn a, Pawn b) + => (a?.needs?.food?.FoodFallPerTickAssumingCategory(HungerCategory.Fed) * 60000f ?? 0) + .CompareTo( + b?.needs?.food?.FoodFallPerTickAssumingCategory(HungerCategory.Fed) * 60000f ?? 0); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Forbidden.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Forbidden.cs new file mode 100644 index 0000000..19fc80d --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Forbidden.cs @@ -0,0 +1,15 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_Forbidden : PawnColumnWorker_Checkbox + { + protected override bool GetValue(Pawn pawn) => ((Thing)pawn.ParentHolder).IsForbidden(Faction.OfPlayer); + + protected override void SetValue(Pawn pawn, bool value, PawnTable table) + { + ((Thing)pawn.ParentHolder).SetForbidden(value); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Gear.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Gear.cs new file mode 100644 index 0000000..7505e37 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Gear.cs @@ -0,0 +1,102 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + using Verse.AI; + + public class PawnColumnWorker_Equipment : PawnColumnWorker + { + private int width; + private static readonly int baseWidth = 6 * 28; //6 boxes, 28 wide each. + private const float gWidth = 28f; + private const float gHeight = 28f; + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + GUI.BeginGroup(rect); + + float x = 0; + + if (pawn.equipment != null) + { + foreach (ThingWithComps thing in pawn.equipment.AllEquipmentListForReading) + { + Rect rect2 = new(x, 0, gWidth, gHeight); + DrawThing(rect2, thing, pawn); + x += gWidth; + } + } + + if (pawn.apparel != null) + { + foreach (Apparel thing in pawn.apparel.WornApparel.OrderByDescending(ap => ap.def.apparel.bodyPartGroups[0].listOrder)) + { + Rect rect2 = new(x, 0, gWidth, gHeight); + DrawThing(rect2, thing, pawn); + x += gWidth; + if (x > width) + width = (int)x; + } + } + + GUI.EndGroup(); + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(width, baseWidth); + + private void DrawThing(Rect rect, Thing thing, Pawn selPawn) + { + if (Widgets.ButtonInvisible(rect) && Event.current.button == 1) + { + List list = + [ + new FloatMenuOption("ThingInfo".Translate(), () => Find.WindowStack.Add(new Dialog_InfoCard(thing))) + ]; + + if (selPawn.IsColonistPlayerControlled) + { + Action dropAction = DropThing(thing, selPawn); + list.Add(new FloatMenuOption("DropThing".Translate(), dropAction)); + } + FloatMenu window = new(list, thing.LabelCap); + Find.WindowStack.Add(window); + } + GUI.BeginGroup(rect); + if (thing.def.DrawMatSingle?.mainTexture != null) + { + Widgets.ThingIcon(new Rect(3f, 3f, 27f, 27f), thing); + } + GUI.EndGroup(); + TooltipHandler.TipRegion(rect, new TipSignal(thing.LabelCap)); + } + + private static Action DropThing(Thing thing, Pawn selPawn) + { + if (thing is Apparel ap && selPawn.apparel != null && selPawn.apparel.WornApparel.Contains(ap)) + { + return () => selPawn.jobs.TryTakeOrderedJob(new Job(JobDefOf.RemoveApparel, ap)); + } + + if (thing is ThingWithComps eq && selPawn.equipment.AllEquipmentListForReading.Contains(eq)) + { + return() => selPawn.jobs.TryTakeOrderedJob(new Job(JobDefOf.DropEquipment, eq)); + } + + if (!thing.def.destroyOnDrop) + { + return () => selPawn.inventory.innerContainer.TryDrop(thing, selPawn.Position, selPawn.Map, ThingPlaceMode.Near, out Thing unused); + } + + return null; + } + + public override int Compare(Pawn a, Pawn b) + => (a.equipment.HasAnything() ? a.equipment.AllEquipmentListForReading.First().LabelCap : string.Empty) + .CompareTo(b.equipment.HasAnything() ? b.equipment.AllEquipmentListForReading.First().LabelCap : string.Empty); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Genes.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Genes.cs new file mode 100644 index 0000000..2d5acf6 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Genes.cs @@ -0,0 +1,23 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using Verse; + + //todo: probably better with icons to hover over for a tooltip or smth + public class PawnColumnWorker_Endogenes : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return pawn.genes?.Endogenes?.Select(gene => gene.Label).ToCommaList(); + } + } + + public class PawnColumnWorker_Xenogenes : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return pawn.genes?.Xenogenes?.Select(gene => gene.Label).ToCommaList(); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_GenesRegrowTime.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_GenesRegrowTime.cs new file mode 100644 index 0000000..be131b8 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_GenesRegrowTime.cs @@ -0,0 +1,45 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + //todo: probably better with icons to hover over for a tooltip or smth + public class PawnColumnWorker_GenesRegrowTime : PawnColumnWorker_Text + { + private int GetTicksRemaining(Pawn pawn) + { + var hediff = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.XenogermReplicating); + + if (hediff == null) + { + return 0; + } + + var disappears = hediff.TryGetComp(); + + if (disappears == null) + { + return 0; + } + + return disappears.ticksToDisappear; + } + + protected override string GetTextFor(Pawn pawn) + { + var ticks = GetTicksRemaining(pawn); + + if (ticks == 0) + { + return null; + } + + return ticks.ToStringTicksToPeriod(shortForm: true); + } + + + public override int Compare(Pawn a, Pawn b) + => this.GetTicksRemaining(a).CompareTo(this.GetTicksRemaining(b)); + } + +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Guilt.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Guilt.cs new file mode 100644 index 0000000..9d9ba38 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Guilt.cs @@ -0,0 +1,24 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Guilt : PawnColumnWorker_Icon + { + protected override string GetIconTip(Pawn pawn) + { + return pawn.guilt?.Tip; + } + + public override int Compare(Pawn a, Pawn b) + { + return a.guilt?.TicksUntilInnocent.CompareTo(b.guilt?.TicksUntilInnocent) ?? base.Compare(a, b); + } + + protected override Texture2D GetIconFor(Pawn pawn) + { + return (pawn.guilt?.IsGuilty ?? false) ? TexUI.GuiltyTex : null; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_HediffIsBad.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_HediffIsBad.cs new file mode 100644 index 0000000..e9f9e31 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_HediffIsBad.cs @@ -0,0 +1,14 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using Verse; + + public class PawnColumnWorker_HediffIsBad : PawnColumnWorker_AllHediffs + { + protected override IEnumerable VisibleHediffs(Pawn pawn) + { + return base.VisibleHediffs(pawn).Where(x => x.def.isBad); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Ideology.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Ideology.cs new file mode 100644 index 0000000..561fe48 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Ideology.cs @@ -0,0 +1,28 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Ideology : PawnColumnWorker + { + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn?.Ideo == null) + { + return; + } + IdeoUIUtility.DrawIdeoPlate(rect, pawn.Ideo, pawn); + } + + public override int GetMinWidth(PawnTable table) + { + return Mathf.Max(base.GetMinWidth(table), 140); + } + + public override int Compare(Pawn a, Pawn b) + { + return (a.ideo?.Certainty ?? 0).CompareTo(b.ideo?.Certainty ?? 0); + } + } +} \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Inspiration.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Inspiration.cs new file mode 100644 index 0000000..6d4b30c --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Inspiration.cs @@ -0,0 +1,26 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Inspiration : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.InspirationDef?.LabelCap; + + public override int Compare(Pawn a, Pawn b) + => (a.Inspired ? a.InspirationDef.GetHashCode() : int.MinValue) + .CompareTo(b.Inspired ? b.InspirationDef.GetHashCode() : int.MinValue); + + protected override string GetTip(Pawn pawn) + { + int? inspirationTimeRemaining = (int?)((pawn.InspirationDef?.baseDurationDays - pawn.Inspiration?.AgeDays) * GenDate.TicksPerDay); + + return inspirationTimeRemaining.HasValue ? "ExpiresIn".Translate().Resolve() + ": " + inspirationTimeRemaining.Value.ToStringTicksToPeriod() : string.Empty; + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 130); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Inventory.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Inventory.cs new file mode 100644 index 0000000..07f3174 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Inventory.cs @@ -0,0 +1,78 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Inventory : PawnColumnWorker + { + private int width; + private static readonly int baseWidth = 3 * 28; //3 boxes, 28 wide each. + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.inventory?.innerContainer == null) + return; + + GUI.BeginGroup(rect); + float x = 0; + float gWidth = 28f; + float gHeight = 28f; + + foreach (Thing thing in pawn.inventory.innerContainer) + { + Rect rect2 = new(x, 0, gWidth, gHeight); + DrawThing(rect2, thing, pawn); + x += gWidth; + if (x > width) + width = (int)x; + } + GUI.EndGroup(); + } + + public override int GetMinWidth(PawnTable table) => Mathf.Max(width, baseWidth, base.GetMinWidth(table)); + + private void DrawThing(Rect rect, Thing thing, Pawn selPawn) + { + if (Widgets.ButtonInvisible(rect) && Event.current.button == 1) + { + List list = + [ + new FloatMenuOption("ThingInfo".Translate(), () => Find.WindowStack.Add(new Dialog_InfoCard(thing))) + ]; + + if (selPawn.IsColonistPlayerControlled) + { + Action action = null; + + if (!thing.def.destroyOnDrop) + { + action = delegate + { + selPawn.inventory.innerContainer.TryDrop(thing, selPawn.Position, selPawn.Map, ThingPlaceMode.Near, out Thing unused); + }; + } + list.Add(new FloatMenuOption("DropThing".Translate(), action)); + } + FloatMenu window = new(list, thing.LabelCap); + Find.WindowStack.Add(window); + } + + GUI.BeginGroup(rect); + if (thing.def.DrawMatSingle?.mainTexture != null) + { + Widgets.ThingIcon(new Rect(3f, 3f, 27f, 27f), thing); + } + GUI.EndGroup(); + TooltipHandler.TipRegion(rect, new TipSignal(thing.LabelCap)); + } + + public override int Compare(Pawn a, Pawn b) + => (a.inventory?.innerContainer?.Count() ?? -1) + .CompareTo(b.inventory?.innerContainer?.Count() ?? -1); + } +} + diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_InventoryDropAll.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_InventoryDropAll.cs new file mode 100644 index 0000000..93c38c6 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_InventoryDropAll.cs @@ -0,0 +1,26 @@ +using RimWorld; +using UnityEngine; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_InventoryDropAll : PawnColumnWorker_Icon + { + protected override Texture2D GetIconFor(Pawn pawn) + { + var playerControlled = pawn.Faction != null && (pawn.IsColonistPlayerControlled || pawn.IsPrisonerOfColony || (pawn.AnimalOrWildMan() && pawn.Faction.IsPlayer)); + + return playerControlled && pawn.inventory.FirstUnloadableThing != default ? StaticConstructorOnGameStart.Drop : null; + } + + protected override void ClickedIcon(Pawn pawn) + { + var playerControlled = pawn.Faction != null && (pawn.IsColonistPlayerControlled || pawn.IsPrisonerOfColony || (pawn.AnimalOrWildMan() && pawn.Faction.IsPlayer)); + + if (playerControlled && pawn.inventory.FirstUnloadableThing != default) + { + pawn.inventory.DropAllNearPawn(pawn.PositionHeld); + } + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs new file mode 100644 index 0000000..4ef8fd6 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs @@ -0,0 +1,35 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_JobCurrent : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + if (!Numbers_Settings.showMoreInfoThanVanilla && !(pawn.Faction == Faction.OfPlayer || pawn.HostFaction == Faction.OfPlayer) && !pawn.InMentalState) + return null; + + if (pawn.jobs.curDriver != null) + { + string text = pawn.jobs.curDriver.GetReport().CapitalizeFirst(); + GenText.SetTextSizeToFit(text, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn))); + + return text; + } + return null; + } + + protected override string GetTip(Pawn pawn) => GetTextFor(pawn); + + public override int Compare(Pawn a, Pawn b) + => (a.jobs?.curDriver.GetReport()).CompareTo(b.jobs?.curDriver.GetReport()); + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 200); + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs new file mode 100644 index 0000000..e78a995 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs @@ -0,0 +1,35 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_JobQueued : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + if (pawn.jobs?.jobQueue.Any() ?? false) + { + string text = pawn.jobs.jobQueue[0].job.GetReport(pawn).CapitalizeFirst(); + + GenText.SetTextSizeToFit(text, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn))); + + return text; + } + return null; + } + + public override int Compare(Pawn a, Pawn b) + => (a.jobs?.jobQueue?.Count ?? 0).CompareTo(b.jobs?.jobQueue?.Count ?? 0); + + protected override string GetTip(Pawn pawn) + => pawn.jobs?.jobQueue?.Count.ToString(); + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 200); + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_LeatherType.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_LeatherType.cs new file mode 100644 index 0000000..bcc263f --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_LeatherType.cs @@ -0,0 +1,13 @@ +using RimWorld; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_LeatherType : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return pawn.RaceProps?.leatherDef?.LabelCap; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Meditation.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Meditation.cs new file mode 100644 index 0000000..7acb205 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Meditation.cs @@ -0,0 +1,17 @@ +using RimWorld; +using UnityEngine; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_Meditation : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return MeditationUtility.FocusTypesAvailableForPawnString(pawn); + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 200); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_MentalState.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_MentalState.cs new file mode 100644 index 0000000..42b944c --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_MentalState.cs @@ -0,0 +1,19 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_MentalState : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.MentalState?.InspectLine ?? string.Empty; + + public override int Compare(Pawn a, Pawn b) + => ((int?)a.MentalState?.def?.category ?? -1) + .CompareTo((int?)b.MentalState?.def?.category ?? -1); + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Need.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Need.cs new file mode 100644 index 0000000..25b89e8 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Need.cs @@ -0,0 +1,101 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Reflection; + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + public class PawnColumnWorker_Need : PawnColumnWorker + { + private static readonly FieldInfo needThreshPercent = typeof(Need).GetField("threshPercents", BindingFlags.NonPublic | BindingFlags.Instance); + + //mostly from Koisama + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.needs == null) + return; + + if (pawn.RaceProps.IsMechanoid) + return; + + if (!Numbers_Settings.showMoreInfoThanVanilla && pawn.RaceProps.Animal && pawn.Faction == null) + return; + + Need need = pawn.needs.TryGetNeed(def.Ext().need); + + if (need == null) + return; + + float barHeight = 14f; + float barWidth = barHeight + 15f; + if (rect.height < 50f) + { + barHeight *= Mathf.InverseLerp(0f, 50f, rect.height); + } + + Text.Font = (rect.height <= 55f) ? GameFont.Tiny : GameFont.Small; + Text.Anchor = TextAnchor.UpperLeft; + Rect rect3 = new(rect.x, rect.y + rect.height / 2f, rect.width, rect.height / 2f); + rect3 = new Rect(rect3.x + barWidth, rect3.y, rect3.width - barWidth * 2f, rect3.height - barHeight); + + Widgets.FillableBar(rect3, need.CurLevelPercentage); + Widgets.FillableBarChangeArrows(rect3, need.GUIChangeArrow); + + List threshPercents = (List)needThreshPercent.GetValue(need); + if (threshPercents != null) + { + foreach (float t in threshPercents) + { + NeedDrawBarThreshold(rect3, t, need.CurLevelPercentage); + } + } + + float curInstantLevel = need.CurInstantLevelPercentage; + if (curInstantLevel >= 0f) + { + NeedDrawBarInstantMarkerAt(rect3, curInstantLevel); + } + Text.Font = GameFont.Small; + } + + private void NeedDrawBarThreshold(Rect barRect, float threshPct, float curLevel) + { + float num = (barRect.width <= 60f) ? 1 : 2; + Rect position = new(barRect.x + barRect.width * threshPct - (num - 1f), barRect.y + barRect.height / 2f, num, barRect.height / 2f); + Texture2D image; + if (threshPct < curLevel) + { + image = BaseContent.BlackTex; + GUI.color = new Color(1f, 1f, 1f, 0.9f); + } + else + { + image = BaseContent.GreyTex; + GUI.color = new Color(1f, 1f, 1f, 0.5f); + } + GUI.DrawTexture(position, image); + GUI.color = Color.white; + } + + private void NeedDrawBarInstantMarkerAt(Rect barRect, float pct) + { + float seekerSize = 12f; + if (barRect.width < 150f) + { + seekerSize /= 2f; + } + Vector2 vector = new(barRect.x + barRect.width * pct, barRect.y + barRect.height); + Rect position = new(vector.x - seekerSize / 2f, vector.y, seekerSize, seekerSize); + GUI.DrawTexture(position, StaticConstructorOnGameStart.BarInstantMarkerTex); + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 110); + + public override int Compare(Pawn a, Pawn b) + => (a.needs?.TryGetNeed(def.Ext().need)?.CurLevel ?? 0) + .CompareTo(b.needs?.TryGetNeed(def.Ext().need)?.CurLevel ?? 0); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_NeedsTreatment.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_NeedsTreatment.cs new file mode 100644 index 0000000..39479c2 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_NeedsTreatment.cs @@ -0,0 +1,26 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_NeedsTreatment : PawnColumnWorker_Icon + { + protected override Texture2D GetIconFor(Pawn pawn) + => pawn.health.HasHediffsNeedingTendByPlayer() + ? StaticConstructorOnGameStart.IconTendedNeed + : StaticConstructorOnGameStart.IconTendedWell; + + public override int Compare(Pawn a, Pawn b) + => a.health.hediffSet.GetHediffsTendable().Count() + .CompareTo(b.health.hediffSet.GetHediffsTendable().Count()); + + protected override string GetIconTip(Pawn pawn) + => pawn.health.hediffSet.GetHediffsTendable() + .Select(x => x.LabelCap).ToCommaList(); + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_OperationDropDown.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_OperationDropDown.cs new file mode 100644 index 0000000..6aede2b --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_OperationDropDown.cs @@ -0,0 +1,84 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_OperationDropDown : PawnColumnWorker + { + public delegate TResult Func + (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + public static Func, AcceptanceReport, int, BodyPartRecord, FloatMenuOption> + GenerateSurgeryOptionFunc = + (Func, AcceptanceReport, int, BodyPartRecord, FloatMenuOption>)Delegate + .CreateDelegate( + typeof(Func, AcceptanceReport, int, BodyPartRecord, FloatMenuOption>), + null, + typeof(HealthCardUtility).GetMethod("GenerateSurgeryOption", + BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod) ?? throw new InvalidOperationException("GenerateSurgeryOption is null.")); + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (Widgets.ButtonText(rect, "AddBill".Translate())) + { + Find.WindowStack.Add(new FloatMenu(RecipeOptionsMaker(pawn))); + } + + UIHighlighter.HighlightOpportunity(rect, "AddBill"); + } + + public override int GetMinCellHeight(Pawn pawn) + { + return 30; + } + + public override int GetMinWidth(PawnTable table) + { + return 150; + } + + private static List RecipeOptionsMaker(Pawn pawn) + { + List list = []; + int num = 0; + foreach (RecipeDef current in pawn.def.AllRecipes.Where(x => x.AvailableNow)) + { + var acceptanceReport = current.Worker.AvailableReport(pawn); + if (acceptanceReport.Accepted || !acceptanceReport.Reason.NullOrEmpty()) + { + List missingIngredientsList = current.PotentiallyMissingIngredients(null, pawn.Map).ToList(); + + if (missingIngredientsList.Count == 0 || (!current.dontShowIfAnyIngredientMissing && + !missingIngredientsList.Any(x => x.isTechHediff || x.IsDrug))) + { + if (current.targetsBodyPart) + { + foreach (var item in current.Worker.GetPartsToApplyOn(pawn, current)) + { + if (current.AvailableOnNow(pawn, item)) + { + list.Add(GenerateSurgeryOptionFunc(pawn, pawn, current, missingIngredientsList, acceptanceReport, num, item)); + num++; + } + } + + } + else + { + list.Add(GenerateSurgeryOptionFunc(pawn, pawn, current, missingIngredientsList, acceptanceReport, num, null)); + num++; + } + } + + } + } + + return list; + } + } +} \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Pain.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Pain.cs new file mode 100644 index 0000000..4febc32 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Pain.cs @@ -0,0 +1,38 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Pain : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.health.hediffSet.PainTotal.ToStringPercent(); + + protected override string GetTip(Pawn pawn) + => GetPainTip(pawn); + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + GUI.color = HealthCardUtility.GetPainLabel(pawn).Second; + base.DoCell(rect, pawn, table); + GUI.color = Color.white; + } + + private static string GetPainTip(Pawn pawn) + => PainCausingHediffs(pawn).ToCommaList(); + + private static IEnumerable PainCausingHediffs(Pawn pawn) + => pawn.health.hediffSet.hediffs + .Where(t => t.PainFactor != 1f || t.PainOffset != 0f) + .Select(t => t.Part?.LabelCap + ": " + t.LabelCap); + + public override int GetMinWidth(PawnTable table) + => base.GetMinWidth(table) + 12; + + public override int Compare(Pawn a, Pawn b) + => a.health.hediffSet.PainTotal.CompareTo(b.health.hediffSet.PainTotal); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerInteraction.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerInteraction.cs new file mode 100644 index 0000000..965b09d --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerInteraction.cs @@ -0,0 +1,76 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + using Verse.Sound; + + public class PawnColumnWorker_PrisonerInteraction : PawnColumnWorker + { + //for mods, like Prison Labour, that add more interactinodefs. + private readonly int width = DefDatabase.DefCount * 30; + private bool dragging; + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.guest == null) + return; + + GUI.BeginGroup(rect); + float x = 0f; + + foreach (PrisonerInteractionModeDef current in from prisonerinteractionmode in DefDatabase.AllDefsListForReading + orderby prisonerinteractionmode.listOrder + select prisonerinteractionmode) + { + DrawInteractionRadioButton(new Rect(x, 3f, 30f, 30f), pawn, current); + TooltipHandler.TipRegion(new Rect(x, 0f, 30f, 30f), new TipSignal(current.LabelCap)); + x += 30f; + } + GUI.EndGroup(); + } + + private void DrawInteractionRadioButton(Rect rect, Pawn pawn, PrisonerInteractionModeDef prisonerInteraction) + { + //inspired by RimWorld.AreaAllowedGUI.DoAreaSelector(Rect rect, Pawn p, Area area) + Widgets.RadioButton(rect.x, rect.y, pawn.guest.ExclusiveInteractionMode == prisonerInteraction); + { + if (Input.GetMouseButtonUp(0)) + { + dragging = false; + } + if (!Input.GetMouseButtonDown(0)) + { + dragging = false; + } + if (Mouse.IsOver(rect)) + { + if (Input.GetMouseButton(0)) + { + dragging = true; + pawn.guest.SetExclusiveInteraction(prisonerInteraction); + } + if (dragging && pawn.guest.ExclusiveInteractionMode != prisonerInteraction) + { + pawn.guest.SetExclusiveInteraction(prisonerInteraction); + SoundDefOf.Designate_DragStandard_Changed.PlayOneShotOnCamera(); + } + if (ModsConfig.IdeologyActive && pawn.guest.ExclusiveInteractionMode == PrisonerInteractionModeDefOf.Convert && pawn.guest.ideoForConversion == null) + { + pawn.guest.ideoForConversion = Faction.OfPlayer.ideos.PrimaryIdeo; + } + } + } + } + + public override int Compare(Pawn a, Pawn b) + => (a.guest?.ExclusiveInteractionMode?.listOrder ?? 0).CompareTo(b.guest?.ExclusiveInteractionMode?.listOrder ?? 0); + + public override int GetMinWidth(PawnTable table) + => width; + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerResistance.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerResistance.cs new file mode 100644 index 0000000..6c18847 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_PrisonerResistance.cs @@ -0,0 +1,18 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_PrisonerResistance : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return pawn.guest.Resistance.ToString("F1"); + } + + public override int Compare(Pawn a, Pawn b) => a.guest.Resistance.CompareTo(b.guest.Resistance); + + public override int GetMinHeaderHeight(PawnTable table) => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Psyfocus.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Psyfocus.cs new file mode 100644 index 0000000..9751876 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Psyfocus.cs @@ -0,0 +1,59 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Psyfocus : PawnColumnWorker + { + //mostly from PawnColumnWorker_Need + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (!pawn.HasPsylink) + return; + + float curPsyfocusLevel = pawn.psychicEntropy.CurrentPsyfocus; + float targetPsyfocusLevel = pawn.psychicEntropy.TargetPsyfocus; + + float barHeight = 14f; + float barWidth = barHeight + 15f; + if (rect.height < 50f) + { + barHeight *= Mathf.InverseLerp(0f, 50f, rect.height); + } + + Text.Font = (rect.height <= 55f) ? GameFont.Tiny : GameFont.Small; + Text.Anchor = TextAnchor.UpperLeft; + Rect rect3 = new(rect.x, rect.y + rect.height / 2f, rect.width, rect.height / 2f); + rect3 = new Rect(rect3.x + barWidth, rect3.y, rect3.width - barWidth * 2f, rect3.height - barHeight); + + Widgets.FillableBar(rect3, curPsyfocusLevel); + + DrawPsyfocusTargetMarkerAt(rect3, targetPsyfocusLevel); + Text.Font = GameFont.Small; + } + + private void DrawPsyfocusTargetMarkerAt(Rect barRect, float pct) + { + float seekerSize = 12f; + if (barRect.width < 150f) + { + seekerSize /= 2f; + } + Vector2 vector = new(barRect.x + barRect.width * pct, barRect.y + barRect.height); + Rect position = new(vector.x - seekerSize / 2f, vector.y, seekerSize, seekerSize); + GUI.DrawTexture(position, StaticConstructorOnGameStart.BarInstantMarkerTex); + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(base.GetMinWidth(table), 110); + + public override int Compare(Pawn a, Pawn b) + { + int hasPsylink = a.HasPsylink.CompareTo(b.HasPsylink); + if (hasPsylink != 0) { return hasPsylink; } + return (a.psychicEntropy?.CurrentPsyfocus ?? 0f).CompareTo(b.psychicEntropy?.CurrentPsyfocus ?? 0f); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_PsylinkLevel.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_PsylinkLevel.cs new file mode 100644 index 0000000..e77f607 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_PsylinkLevel.cs @@ -0,0 +1,17 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_PsylinkLevel : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => (pawn.psychicEntropy?.Psylink?.level ?? 0).ToString(); + + public override int Compare(Pawn a, Pawn b) + => (a.psychicEntropy?.Psylink?.level ?? 0).CompareTo((b.psychicEntropy?.Psylink?.level ?? 0)); + + public override int GetMinWidth(PawnTable table) + => base.GetMinWidth(table) + 10; + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Race.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Race.cs new file mode 100644 index 0000000..5144809 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Race.cs @@ -0,0 +1,37 @@ +namespace Numbers +{ + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + using System.Reflection; + + public class PawnColumnWorker_Race : PawnColumnWorker_Text + { + private readonly Dictionary widthsTables = WorldComponent_Numbers.PrimaryFilter.Keys.ToDictionary(x => x, x => 0f); + + protected override string GetTextFor(Pawn pawn) + { + string text = pawn.kindDef.race.LabelCap.Resolve() ?? string.Empty; + + if (Find.WindowStack.currentlyDrawnWindow is MainTabWindow_Numbers numbers) + { + float width = Mathf.Max( (int)Text.CalcSize(text).x , widthsTables[numbers.pawnTableDef]); + widthsTables[numbers.pawnTableDef] = width; + } + + return text; + } + + public override int GetMinWidth(PawnTable table) + { + if (!(typeof(PawnTable).GetField("def", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(table) is PawnTableDef tableDef)) + throw new System.Exception($"tableDef not found {table}"); + + return Mathf.Max(base.GetMinWidth(table), 80, (int)widthsTables[tableDef]); + } + + public override int Compare(Pawn a, Pawn b) => a.kindDef.race.LabelCap.Resolve().CompareTo(b.kindDef.race.LabelCap.Resolve()); + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Record.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Record.cs new file mode 100644 index 0000000..192c5a8 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Record.cs @@ -0,0 +1,38 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Record : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + RecordDef recordDef = def.Ext().record; + string recordValue; + + if (recordDef.type == RecordType.Time) + recordValue = pawn.records.GetAsInt(recordDef).ToStringTicksToPeriod(); + else + recordValue = pawn.records.GetValue(recordDef).ToString("0.##"); + + return recordValue; + } + + protected override string GetTip(Pawn pawn) => def.Ext().record.description; + + public override int GetMinWidth(PawnTable table) => Mathf.Max(50, Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, 150)).x)); + + public override int GetMinHeaderHeight(PawnTable table) => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); //not messy at all. + + public override int Compare(Pawn a, Pawn b) + { + RecordDef recordDef = def.Ext().record; + + if (recordDef.type == RecordType.Time) + return a.records.GetAsInt(recordDef).CompareTo(b.records.GetAsInt(recordDef)); + return a.records.GetValue(recordDef).CompareTo(b.records.GetValue(recordDef)); + } + + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Recruitable.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Recruitable.cs new file mode 100644 index 0000000..2d9b006 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Recruitable.cs @@ -0,0 +1,29 @@ +using RimWorld; +using UnityEngine; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_Recruitable : PawnColumnWorker_Icon + { + protected override string GetIconTip(Pawn pawn) + { + if (pawn?.guest?.Recruitable == false) + { + return "Unrecruitable".Translate().AsTipTitle().CapitalizeFirst() + "\n\n" + "UnrecruitableDesc".Translate(pawn.Named("PAWN")).Resolve(); + } + return null; + } + + public override int Compare(Pawn a, Pawn b) + { + //either do complicated stuff with negation or just swap a and b. + return b.guest?.Recruitable.CompareTo(a.guest?.Recruitable) ?? base.Compare(b, a); + } + + protected override Texture2D GetIconFor(Pawn pawn) + { + return (pawn.guest?.Recruitable ?? true) ? null : StaticConstructorOnGameStart.UnwaveringlyLoyal; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs new file mode 100644 index 0000000..0762b5b --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs @@ -0,0 +1,38 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_SelfTend : PawnColumnWorker_Checkbox + { + public static float IconPositionVertical = 35f; + public static float IconPositionHorizontal = 5f; + + protected override bool GetValue(Pawn pawn) => pawn.playerSettings.selfTend; + + protected override bool HasCheckbox(Pawn pawn) => pawn.IsColonist && !pawn.Dead && !(pawn.WorkTypeIsDisabled(WorkTypeDefOf.Doctor)); + + protected override void SetValue(Pawn pawn, bool value, PawnTable table) + { + if (value && pawn.workSettings.GetPriority(WorkTypeDefOf.Doctor) == 0) + Messages.Message("MessageSelfTendUnsatisfied".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.CautionInput, false); + + pawn.playerSettings.selfTend = value; + } + + protected override string GetHeaderTip(PawnTable table) => "SelfTend".Translate() + "\n\n" + "Numbers_ColumnHeader_Tooltip".Translate(); + + protected override string GetTip(Pawn pawn) => "SelfTendTip".Translate(Faction.OfPlayer.def.pawnsPlural, TendUtility.SelfTendQualityFactor.ToStringPercent()).CapitalizeFirst(); + + public override void DoHeader(Rect rect, PawnTable table) + { + float scale = 0.3f; + base.DoHeader(rect, table); + Vector2 headerIconSize = new Vector2(StaticConstructorOnGameStart.Tame.width, StaticConstructorOnGameStart.Tame.height) * scale; + int num = (int)((rect.width - headerIconSize.x) * 0.4); + Rect position = new(rect.x + num + IconPositionHorizontal, rect.yMax - StaticConstructorOnGameStart.Tame.height + IconPositionVertical, headerIconSize.x, headerIconSize.y); + GUI.DrawTexture(position, StaticConstructorOnGameStart.Tame); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs new file mode 100644 index 0000000..da9abc6 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs @@ -0,0 +1,84 @@ +namespace Numbers +{ + using System.Reflection; + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + //mostly from Koisama + public class PawnColumnWorker_Skill : PawnColumnWorker + { + + private static readonly Texture2D passionMinorIcon = ContentFinder.Get("UI/Icons/PassionMinor"); + private static readonly Texture2D passionMajorIcon = ContentFinder.Get("UI/Icons/PassionMajor"); + private static readonly Texture2D SkillBarFillTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.25f)); + private static readonly Texture2D SkillBarBgTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.07f)); + private static readonly Color DisabledSkillColor = new(1f, 1f, 1f, 0.5f); + + private static readonly MethodInfo mGetSkillDescription = typeof(SkillUI).GetMethod("GetSkillDescription", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, [typeof(SkillRecord)], null); + + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.RaceProps.IsMechanoid) + return; + if (pawn.RaceProps.Animal) + return; + + SkillRecord skill = pawn.skills?.GetSkill(def.Ext().skill); + + if (skill == null) + return; + + GUI.BeginGroup(rect); + Rect position = new(3f, 3f, 24f, 24f); + if (skill.passion > Passion.None) + { + Texture2D image = (skill.passion != Passion.Major) ? passionMinorIcon : passionMajorIcon; + GUI.DrawTexture(position, image); + } + if (!skill.TotallyDisabled) + { + Rect rect3 = new(position.xMax, 0f, rect.width - position.xMax, rect.height); + Widgets.FillableBar(rect3, skill.Level / 20f, SkillBarFillTex, SkillBarBgTex, false); + } + Rect rect4 = new(position.xMax + 4f, 0f, 999f, rect.height); + rect4.yMin += 3f; + string label; + if (skill.TotallyDisabled) + { + GUI.color = DisabledSkillColor; + label = "-"; + } + else + { + label = skill.Level.ToStringCached(); + } + GenUI.SetLabelAlign(TextAnchor.MiddleLeft); + Widgets.Label(rect4, label); + GenUI.ResetLabelAlign(); + GUI.color = Color.white; + GUI.EndGroup(); + string tip = GetTip(skill); + if (!tip.NullOrEmpty()) + { + TooltipHandler.TipRegion(rect, tip); + } + } + + private string GetTip(SkillRecord skill) => (string)mGetSkillDescription.Invoke(null, new[] { skill }); + + public override int GetMinWidth(PawnTable table) => Mathf.Max(base.GetMinWidth(table), 120); + + public override int Compare(Pawn a, Pawn b) + { + // genes give extra levels, so can't just compare by xp anymore. + int ret = (a.skills?.GetSkill(def.Ext().skill)?.GetLevel(true) ?? 0).CompareTo(b.skills?.GetSkill(def.Ext().skill)?.GetLevel(true) ?? 0); + if (ret == 0) + { + ret = (a.skills?.GetSkill(def.Ext().skill)?.XpTotalEarned ?? 0).CompareTo(b.skills?.GetSkill(def.Ext().skill)?.XpTotalEarned ?? 0); + } + return ret; + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Stat.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Stat.cs new file mode 100644 index 0000000..36cd51e --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Stat.cs @@ -0,0 +1,38 @@ +namespace Numbers +{ + using RimWorld; + using UnityEngine; + using Verse; + + public class PawnColumnWorker_Stat : PawnColumnWorker_Text + { + public const int minWidthBasedOnNarrowestColumnThatColumnBeingMass = 69; + public const int maxWidthBasedOnColumnsWithALongAssNameLikeThisInt = 150; + public const int margin = 5; + + protected override string GetTextFor(Pawn pawn) + { + Thing thing = pawn; + + if (pawn.ParentHolder is Corpse tmpCorpse && this.def.Ext().stat != StatDefOf.LeatherAmount) //this is dumb, but corpses don't seem to have leather. + thing = tmpCorpse; + + return def.Ext().stat.Worker.IsDisabledFor(thing) ? null + : def.Ext().stat.Worker.ValueToString(thing.GetStatValue(def.Ext().stat), true); + } + + public override int GetMinWidth(PawnTable table) + => Mathf.Max(minWidthBasedOnNarrowestColumnThatColumnBeingMass, + Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, maxWidthBasedOnColumnsWithALongAssNameLikeThisInt)).x)) + + margin; + + public override int GetMinHeaderHeight(PawnTable table) + => Mathf.CeilToInt(Text.CalcSize(Numbers_Utility.WordWrapAt(def.LabelCap, GetMinWidth(table))).y); //not messy at all. + + public override int Compare(Pawn a, Pawn b) + => (def.Ext().stat.Worker.IsDisabledFor(a) ? 0 : a.GetStatValue(def.Ext().stat)).CompareTo + (def.Ext().stat.Worker.IsDisabledFor(b) ? 0 : b.GetStatValue(def.Ext().stat)); + + } +} + \ No newline at end of file diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Strip.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Strip.cs new file mode 100644 index 0000000..8403303 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Strip.cs @@ -0,0 +1,20 @@ +namespace Numbers +{ + using RimWorld; + using Verse; + + public class PawnColumnWorker_Strip : PawnColumnWorker_Designator + { + protected override DesignationDef DesignationType => DesignationDefOf.Strip; + + protected override bool HasCheckbox(Pawn pawn) + { + return StrippableUtility.CanBeStrippedByColony(pawn); + } + + protected override void Notify_DesignationAdded(Pawn pawn) + { + StrippableUtility.CheckSendStrippingImpactsGoodwillMessage(pawn); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs new file mode 100644 index 0000000..ef681bc --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs @@ -0,0 +1,28 @@ +namespace Numbers +{ + using System; + using RimWorld; + using Verse; + + public class PawnColumnWorker_TameChance : PawnColumnWorker_Text + { + public override int Compare(Pawn a, Pawn b) => GetValue(a).CompareTo(GetValue(b)); + + protected override string GetTextFor(Pawn pawn) => pawn.AnimalOrWildMan() ? GetValue(pawn).ToStringPercent() : string.Empty; + + private float GetValue(Pawn pawn) => pawn.AnimalOrWildMan() ? TameChanceFactorCurve_Wildness.Evaluate(pawn.RaceProps.wildness) : 0; + + +#if DEBUG + [Obsolete] + //RimWorld.InteractionWorker_RecruitAttempt.TameChanceFactorCurve_Wildness is private, so I copy-pasted the simple thing. + // Updaters beware: this is likely to be outdated. Verify. +#endif + private static readonly SimpleCurve TameChanceFactorCurve_Wildness = + [ + new CurvePoint(1f, 0f), + new CurvePoint(0.5f, 1f), + new CurvePoint(0f, 2f) + ]; + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Trait.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Trait.cs new file mode 100644 index 0000000..50e5464 --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Trait.cs @@ -0,0 +1,14 @@ +namespace Numbers +{ + using System.Linq; + using RimWorld; + using Verse; + + public class PawnColumnWorker_Trait : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + { + return pawn.story?.traits?.allTraits.Select(x => x.Label).ToCommaList(); + } + } +} diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Will.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Will.cs new file mode 100644 index 0000000..e8aa89b --- /dev/null +++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Will.cs @@ -0,0 +1,24 @@ +using RimWorld; +using Verse; + +namespace Numbers +{ + public class PawnColumnWorker_Will : PawnColumnWorker_Text + { + protected override string GetTextFor(Pawn pawn) + => pawn.guest.will.ToString("F1"); + + protected override string GetTip(Pawn pawn) + { + var range = pawn.kindDef.initialWillRange.Value; + + return string.Format("{0} : {1}-{2}", "WillFromPawnKind".Translate(pawn.kindDef.LabelCap), range.min, range.max); + } + + protected override string GetHeaderTip(PawnTable table) + => "WillLevelDesc".Translate(); + + public override int Compare(Pawn a, Pawn b) + => a.guest?.will.CompareTo(b?.guest?.will) ?? 0; + } +} diff --git a/Numbers/PawnTable_NumbersMain.cs b/Numbers/PawnTable_NumbersMain.cs new file mode 100644 index 0000000..5cb7d7f --- /dev/null +++ b/Numbers/PawnTable_NumbersMain.cs @@ -0,0 +1,56 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using RimWorld; + using Verse; + + public class PawnTable_NumbersMain : PawnTable + { + private List _originalColumns; + + public PawnTable_NumbersMain(PawnTableDef def, Func> pawnsGetter, int uiWidth, int uiHeight) : base(def, pawnsGetter, uiWidth, uiHeight) + { + PawnTableDef = def; + _originalColumns = def.columns; + + SetMinMaxSize(def.minWidth, uiWidth, 0, (int)(uiHeight * Numbers_Settings.maxHeight)); + SetDirty(); + } + + public PawnTableDef PawnTableDef { get; protected set; } + + Queue> filtersToApply = new(); + + protected override IEnumerable LabelSortFunction(IEnumerable input) + { + if (PawnTableDef == NumbersDefOf.Numbers_MainTable) + { + return PlayerPawnsDisplayOrderUtility.InOrder(input); + } + return base.LabelSortFunction(input); + } + + public int RemoveColumns(Predicate predicate) + { + return PawnTableDef.columns.RemoveAll(predicate); + } + + // Postponing column removal until PawnTable drawing is finished + // Immediate removal causes change of column indexes in middle of drawing process + // it makes vanilla game to render nonsense for a single update + // and also causes support issues for Grouped Pawn Tables mod (caches mismatch) + public void EnqueueColumnRemoval(Predicate predicate) + { + filtersToApply.Enqueue(predicate); + } + + public void ApplyColumnRemoval() + { + while (filtersToApply.Count > 0) + { + RemoveColumns(filtersToApply.Dequeue()); + } + } + } +} diff --git a/Numbers/Properties/AssemblyInfo.cs b/Numbers/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..41d4d82 --- /dev/null +++ b/Numbers/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ba30d06a-3eaf-4302-8fd2-9c6a9bd177c4")] diff --git a/Numbers/StaticConstructorOnGameStart.cs b/Numbers/StaticConstructorOnGameStart.cs new file mode 100644 index 0000000..d2be6f7 --- /dev/null +++ b/Numbers/StaticConstructorOnGameStart.cs @@ -0,0 +1,162 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using UnityEngine; + using Verse; + + [StaticConstructorOnStartup] + static class StaticConstructorOnGameStart + { + public static readonly Texture2D DeleteX = ContentFinder.Get("UI/Buttons/Delete"), + Info = ContentFinder.Get("UI/Buttons/InfoButton"), + Predator = ContentFinder.Get("UI/Icons/Animal/Predator"), + Tame = ContentFinder.Get("UI/Icons/Animal/Tame"), + List = ContentFinder.Get("UI/Buttons/DevRoot/ToggleTweak"), + Plus = ContentFinder.Get("UI/Icons/Trainables/Rescue"), + IconImmune = ContentFinder.Get("UI/Icons/Medical/IconImmune"), + IconDead = ContentFinder.Get("Things/Mote/BattleSymbols/Skull"), + IconTendedWell = ContentFinder.Get("UI/Icons/Medical/TendedWell"), + IconTendedNeed = ContentFinder.Get("UI/Icons/Medical/TendedNeed"), + SortingIcon = ContentFinder.Get("UI/Icons/Sorting"), + SortingDescendingIcon = ContentFinder.Get("UI/Icons/SortingDescending"), + BarInstantMarkerTex = ContentFinder.Get("UI/Misc/BarInstantMarker"), + Drop = ContentFinder.Get("UI/Buttons/Drop"), + UnwaveringlyLoyal = ContentFinder.Get("UI/Icons/UnwaveringlyLoyal"); + + public static List combatPreset = [], + workTabPlusPreset = [], + colonistNeedsPreset = [], + psycastingPreset = [], + medicalPreset = []; + + public static Type animalTab; + public static Type wildLifeTab; + + public static Dictionary> PawnTableDef_Columns { get; private set; } + + static StaticConstructorOnGameStart() + { + AddTrainablesToAnimalTable(); + + AddRemainingSpaceToPawnTableDefs(); + + AddHeaderToolTipToPawnColumns(); + + PopulatePresets(); + + //for the sake of compatibility (Better Pawn Control / other mods which subclass it.) + animalTab = DefDatabase.GetNamed("Animals").tabWindowClass; + wildLifeTab = DefDatabase.GetNamed("Wildlife").tabWindowClass; + + CreateCacheMappingOfDefsForReset(); + } + + private static void CreateCacheMappingOfDefsForReset() + { + PawnTableDef_Columns = DefDatabase.AllDefsListForReading.Where(x => x.defName.StartsWith("Numbers")) + .ToDictionary(x => x.defName, x => x.columns.Select(x => x.defName).ToList()); + } + + private static void AddTrainablesToAnimalTable() + { + PawnTableDef animalsTable = NumbersDefOf.Numbers_Animals; + + foreach (PawnColumnDef item in DefDatabase.AllDefsListForReading.Where(x => x.Worker is PawnColumnWorker_Trainable)) + { + animalsTable.columns.Insert(animalsTable.columns.FindIndex(x => x.Worker is PawnColumnWorker_Checkbox) - 1, item); + } + } + + private static void AddRemainingSpaceToPawnTableDefs() + { + IEnumerable allPawntableDefs = DefDatabase.AllDefsListForReading.Where(x => x.HasModExtension()); + + PawnColumnDef remainingspace = DefDatabase.AllDefsListForReading.First(x => x.Worker is PawnColumnWorker_RemainingSpace); + + IEnumerable ptsDfromPtDses = allPawntableDefs as PawnTableDef[] ?? allPawntableDefs.ToArray(); + + foreach (PawnTableDef PTSDfromPTDs in ptsDfromPtDses) + { + PTSDfromPTDs.columns.Insert(PTSDfromPTDs.columns.Count, remainingspace); + } + } + + private static void AddHeaderToolTipToPawnColumns() + { + foreach (PawnColumnDef pawnColumnDef in DefDatabase + .AllDefsListForReading + .Where(x => !x.generated + && x.defName.StartsWith("Numbers_") + && !(x.Worker is PawnColumnWorker_AllHediffs + || x.Worker is PawnColumnWorker_SelfTend + || x.Worker is PawnColumnWorker_Ability))) //these PawnColumnWorkers override GetHeaderTip. + { + pawnColumnDef.headerTip += (pawnColumnDef.headerTip.NullOrEmpty() ? "" : "\n\n") + "Numbers_ColumnHeader_Tooltip".Translate(); + } + } + + private static void PopulatePresets() + { + combatPreset.AddRange(DefDatabase.GetNamed("Numbers_CombatPreset").columns); + workTabPlusPreset.AddRange(DefDatabase.GetNamed("Numbers_WorkTabPlusPreset").columns); + colonistNeedsPreset.AddRange(DefDatabase.GetNamed("Numbers_ColonistNeedsPreset").columns); + PopulatePsycastingPreset(); + PopulateMedicalPreset(); + } + + private static void PopulatePsycastingPreset() + { + psycastingPreset.Add(DefDatabase.GetNamed("LabelShortWithIcon")); + psycastingPreset.Add(DefDatabase.GetNamed("Numbers_PsylinkLevel")); + psycastingPreset.Add(DefDatabase.GetNamed("Numbers_Psyfocus")); + psycastingPreset.Add(DefDatabase.GetNamed("Numbers_Entropy")); + psycastingPreset.AddRange( + DefDatabase.AllDefsListForReading.Where(pcd => pcd.Ext(logError: false)?.ability != null).ToList() + .OrderBy(x => x.Ext().ability.level) + .ThenBy(x => x.Ext().ability.PsyfocusCost) + .ThenBy(x => x.Ext().ability.EntropyGain) + .ThenBy(x => x.Ext().ability.defName) + ); + } + + private static void PopulateMedicalPreset() + { + medicalPreset.AddRange(new List + { + DefDatabase.GetNamed("LabelShortWithIcon"), + DefDatabase.GetNamed("MedicalCare"), + DefDatabase.GetNamed("Numbers_SelfTend"), + DefDatabase.GetNamed("Numbers_HediffList"), + DefDatabase.GetNamed("Numbers_HediffBadList"), + DefDatabase.GetNamed("Numbers_RimWorld_StatDef_MedicalSurgerySuccessChance"), + DefDatabase.GetNamed("Numbers_RimWorld_StatDef_MedicalTendQuality"), + DefDatabase.GetNamed("Numbers_RimWorld_StatDef_MedicalTendSpeed"), + DefDatabase.GetNamed("Numbers_Bleedrate"), + DefDatabase.GetNamed("Numbers_Pain") + }); + medicalPreset.AddRange(DefDatabase.AllDefsListForReading + .Where(pcd => pcd.workType != null) + .Where(x => x.workType.defName == "Patient" || + x.workType.defName == "Doctor" || + x.workType.defName == "PatientBedRest").Reverse()); + + medicalPreset + .AddRange(DefDatabase + .AllDefsListForReading + .Select(x => DefDatabase + .GetNamed(HorribleStringParsersForSaving.CreateDefNameFromType(x)))); + + medicalPreset.RemoveAll(x => x.defName == "Numbers_Verse_PawnCapacityDef_Metabolism"); //I need space + medicalPreset.AddRange(new List + { + DefDatabase.GetNamed("Numbers_NeedsTreatment"), + DefDatabase.GetNamed("Numbers_Operations"), + DefDatabase.GetNamed("Numbers_DiseaseProgress"), + DefDatabase.GetNamed("RemainingSpace") + }); + } + } +} diff --git a/Numbers/WorldComponent_Numbers.cs b/Numbers/WorldComponent_Numbers.cs new file mode 100644 index 0000000..56a5dfe --- /dev/null +++ b/Numbers/WorldComponent_Numbers.cs @@ -0,0 +1,99 @@ +namespace Numbers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using RimWorld; + using RimWorld.Planet; + using Verse; + + public class WorldComponent_Numbers : WorldComponent + { + public WorldComponent_Numbers(World world) : base(world) + { + } + + public override void FinalizeInit() + { + base.FinalizeInit(); + primaryFilter = PrimaryFilter.First(); + + if (!sessionTable.Any()) + { + List storedPawnTables = LoadedModManager.GetMod().GetSettings().storedPawnTableDefs; + foreach (string item in storedPawnTables) + { + if (item.Split(',')[1] == "Default" && sessionTable.All(x => x.Key.defName != item.Split(',')[0])) + { + PawnTableDef pawnTableDef = HorribleStringParsersForSaving.TurnCommaDelimitedStringIntoPawnTableDef(item); + sessionTable.Add(pawnTableDef, pawnTableDef.columns); + } + } + } + NotifySettingsChanged(); + } + + public void ResetLoadList() + { + loadList.Clear(); + } + + public KeyValuePair> primaryFilter; + + private List loadList; + + public Dictionary> sessionTable = []; + + public override void ExposeData() + { + foreach (PawnTableDef type in DefDatabase.AllDefsListForReading.Where(x => x.HasModExtension())) + { + switch (Scribe.mode) + { + case LoadSaveMode.Saving: + if (sessionTable.TryGetValue(type, out List workList)) + { + Scribe_Collections.Look(ref workList, "Numbers_" + type, LookMode.Def); + sessionTable[type] = workList; + } + break; + + case LoadSaveMode.LoadingVars: + Scribe_Collections.Look(ref loadList, "Numbers_" + type, LookMode.Def); + if (!loadList.NullOrEmpty()) + sessionTable[type] = loadList; + break; + } + } + } + + public static readonly Dictionary> PrimaryFilter = new() + { + //{ "All", (pawn) => true }, + { NumbersDefOf.Numbers_MainTable, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsColonist }, + { NumbersDefOf.Numbers_Enemies, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsEnemy() }, + { NumbersDefOf.Numbers_Prisoners, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsPrisoner }, + { NumbersDefOf.Numbers_Guests, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsGuest() }, + { NumbersDefOf.Numbers_Animals, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsAnimal() && pawn.Faction == Faction.OfPlayer }, + { NumbersDefOf.Numbers_WildAnimals, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsWildAnimal() }, + { NumbersDefOf.Numbers_Corpses, pawn => pawn.Dead && pawn.IsVisible() && !pawn.IsAnimal() }, + { NumbersDefOf.Numbers_AnimalCorpses, pawn => pawn.Dead && pawn.IsVisible() && pawn.IsAnimal() } + }; + + internal void NotifySettingsChanged() + { + DefDatabase.GetNamed("Wildlife").tabWindowClass + = Numbers_Settings.coolerThanTheWildlifeTab + ? typeof(MainTabWindow_NumbersWildLife) + : StaticConstructorOnGameStart.wildLifeTab; + + DefDatabase.GetNamed("Animals").tabWindowClass + = Numbers_Settings.coolerThanTheAnimalTab + ? typeof(MainTabWindow_NumbersAnimals) + : StaticConstructorOnGameStart.animalTab; + + DefDatabase.GetNamed("Wildlife").Notify_ClearingAllMapsMemory(); + DefDatabase.GetNamed("Animals").Notify_ClearingAllMapsMemory(); + } + } +} diff --git a/README.md b/README.md index 2fe9cbf..d798ef5 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,56 @@ # Numbers! -Mod for RimWorld. +Adds a customizable general overview tab, allowing you to see any stats on all your colonists or prisoners in a single window. Quickly compare colonists to see who your best doctor is, or to assign gear optimally. -Ever wanted to compare multiple colonists? Quickly see who is on the verge of a mental break? -Now it's possible! ![Main Image](./.github/assets/images/img1.png) ### Features -- Customizable overview tab, ~~up to 10 values at once~~ displays as many columns as you can fit on your screen -- Displays Stats, Skills, Needs -- Prisoner and medical controls, equipment overview, current job -- Works with colonists, prisoners, enemies, animals, wild animals, and even corpses +- Customizable overview tab, displays as many columns as you can fit on your screen. +- Displays Stats, Skills, Needs, Gear, Queued jobs, Pawn Records, etc etc. +- Prisoner and medical controls, equipment overview, current job. +- A Medical Tab that's better than Fluffy's Medical Tab. +- Works with colonists, prisoners, enemies, animals, wild animals, and even corpses. +- Presets! Save, load, move and share your custom layouts. Store them as default. -[RimWorld forum](https://ludeon.com/forums/index.php?topic=16558.0) +### Usability -### Download +- Slide and reorganise columns as you see fit. Reorderable headers! +- Click headers to sort by stat and compare. +- Click to jump to colonist. +- Right-click headers to close. +- Draggable options for things like: prisoner interaction, all checkmarks. Try it on outfits, medical care, hostility response mode and be pleasantly surprised. -**Last update:** 22/12/2016 (updated to `0.6.0`) +It can be added to existing saves without problems. -[Latest release](https://github.com/koisama/kNumbers/releases/latest) +### Links -[All the releases](https://github.com/koisama/kNumbers/releases) +- [Latest release](https://github.com/Mehni/kNumbers/releases/latest) +- [Steam](https://steamcommunity.com/sharedfiles/filedetails/?id=1414302321) +- [Ludeon](https://ludeon.com/forums/index.php?topic=35832.0) +- [GitHub](https://github.com/Mehni/kNumbers) +- [All the releases](https://github.com/Mehni/kNumbers/releases) -### Changelog +## Credits -[Check changelog here](./CHANGELOG.md). +Much thanks to [Maarxx](https://github.com/maarxx) for singlehandedly adding support for Royalty. Check out their mods [here](https://ludeon.com/forums/index.php?topic=53539)! +### Languages -### Inspired by +- English: Mehni +- Chinese (simplified): AlongWY +- German: Amalek +- Russian: JasKill +- Spanish: Crusader -Inspired by MedicalInfo by Fluffy (l2032) +## Adding a column (for contributors) -### License +1. Add a new class in Numbers\PawnColumnWorkers. Use the `Numbers` namespace. Inherit from the correct PawnColumnWorker. +1. Create a new PawnColumnDef. Save it in `1.1\Defs\PawnColumnDef\PawnColumns_Numbers.xml`. Adhere to the naming scheme there. +1. To add your new column to the Misc button, add the defName of your PawnColumnDef to the appropriate Def in `1.1\Defs\PawnColumnOptionDef\Numbers_PawnColumnOptionDef.xml`. This step should not be skipped. +1. To add your new column to the default table, add the defName of your PawnColumnDef to the approppriate PawnTableDef in `1.1\Defs\PawnTableDef\Numbers_PawnTableDef.xml`. -This mod can be used by anyone for any purpose as long as it's free and there's proper attribution - mod name, author's name and a link to this page. +## License + +Original idea by koisama: https://github.com/koisama/kNumbers, whose original license I respect by the preceding link. For the license since 2018/11/21, see LICENSE. \ No newline at end of file diff --git a/Source/kNumbers.sln b/Source/kNumbers.sln deleted file mode 100644 index ea99091..0000000 --- a/Source/kNumbers.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "kNumbers", "kNumbers\kNumbers.csproj", "{37259212-9221-451E-9B38-B06865555576}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {37259212-9221-451E-9B38-B06865555576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {37259212-9221-451E-9B38-B06865555576}.Debug|Any CPU.Build.0 = Debug|Any CPU - {37259212-9221-451E-9B38-B06865555576}.Release|Any CPU.ActiveCfg = Release|Any CPU - {37259212-9221-451E-9B38-B06865555576}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Source/kNumbers/KListObject.cs b/Source/kNumbers/KListObject.cs deleted file mode 100644 index 99f45ac..0000000 --- a/Source/kNumbers/KListObject.cs +++ /dev/null @@ -1,583 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using Verse; -using RimWorld; -using System.Reflection; -using System.Collections; - -namespace kNumbers -{ - [StaticConstructorOnStartup] - public class KListObject : IExposable - { - - public enum objectType - { - Stat, - Health, //can wait - Need, - Skill, - Gear, //weapon and all apparel - ControlPrisonerGetsFood, - ControlMedicalCare, - ControlPrisonerInteraction, - CurrentJob, - AnimalMilkFullness, - AnimalWoolGrowth, - Age, - MentalState, - Capacity - } - - public objectType oType; - public string label; - public object displayObject; - public float minWidthDesired = 120f; - - private static Texture2D passionMinorIcon = ContentFinder.Get("UI/Icons/PassionMinor", true), - passionMajorIcon = ContentFinder.Get("UI/Icons/PassionMajor", true), - SkillBarFillTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.25f)), - SkillBarBgTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.07f)), - BarInstantMarkerTex = BarInstantMarkerTex = ContentFinder.Get("UI/Misc/BarInstantMarker", true); - - public static Texture2D[] careTextures = new Texture2D[] - { - ContentFinder.Get("UI/Icons/Medical/NoCare", true), - ContentFinder.Get("UI/Icons/Medical/NoMeds", true), - ThingDefOf.HerbalMedicine.uiIcon, - ThingDefOf.Medicine.uiIcon, - ThingDefOf.GlitterworldMedicine.uiIcon - }; - - private static readonly Color DisabledSkillColor = new Color(1f, 1f, 1f, 0.5f); - private static readonly Color ThingLabelColor = new Color(0.9f, 0.9f, 0.9f, 1f); - private static readonly Color HighlightColor = new Color(0.5f, 0.5f, 0.5f, 1f); - - private static MethodInfo mGetSkillDescription = typeof(SkillUI).GetMethod("GetSkillDescription", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, new[] { typeof(SkillRecord) }, null); - - private static FieldInfo needThreshPercent = typeof(Need).GetField("threshPercents", BindingFlags.NonPublic | BindingFlags.Instance); - - public void ExposeData() - { - - Scribe_Values.Look(ref oType, "oType"); - Scribe_Values.Look(ref minWidthDesired, "minWidthDesired"); - Scribe_Values.Look(ref this.label, "label"); - - switch (oType) - { - case objectType.Stat: - StatDef tempObjectS = (StatDef)displayObject; - Scribe_Defs.Look(ref tempObjectS, "displayObject"); - displayObject = tempObjectS; - break; - - case objectType.Skill: - SkillDef tempObjectK = (SkillDef)displayObject; - Scribe_Defs.Look(ref tempObjectK, "displayObject"); - displayObject = tempObjectK; - break; - - case objectType.Need: - NeedDef tempObjectN = (NeedDef)displayObject; - Scribe_Defs.Look(ref tempObjectN, "displayObject"); - displayObject = tempObjectN; - break; - - case objectType.Capacity: - PawnCapacityDef tempObjectCap = (PawnCapacityDef)displayObject; - Scribe_Defs.Look(ref tempObjectCap, "displayObject"); - displayObject = tempObjectCap; - break; - - } - - } - - //Scribe wants it - public KListObject() - { - oType = objectType.Stat; - label = " - "; - displayObject = null; - } - - public KListObject(objectType type, string defName, object dObject) - { - this.oType = type; - this.label = defName; - this.displayObject = dObject; - - switch (oType) - { - case objectType.Skill: - minWidthDesired = 120f; - break; - - case objectType.Age: - case objectType.AnimalMilkFullness: - case objectType.AnimalWoolGrowth: - case objectType.Stat: - minWidthDesired = 80f; - break; - - case objectType.Capacity: - minWidthDesired = 60f; - break; - - case objectType.Need: - minWidthDesired = 110f; - break; - - case objectType.Gear: - minWidthDesired = 210f; - break; - - case objectType.ControlPrisonerGetsFood: - minWidthDesired = 40f; - break; - - case objectType.MentalState: - case objectType.ControlPrisonerInteraction: - minWidthDesired = 160f; - break; - - case objectType.ControlMedicalCare: - minWidthDesired = 100f; - break; - - case objectType.CurrentJob: - minWidthDesired = 260f; - break; - } - - } - - private void DrawSkill(Rect rect, Pawn ownerPawn) - { - if (ownerPawn.RaceProps.IsMechanoid) return; - if (ownerPawn.RaceProps.Animal) return; - - SkillRecord skill = ownerPawn.skills.GetSkill((SkillDef)displayObject); - GUI.BeginGroup(rect); - Rect position = new Rect(3f, 3f, 24f, 24f); - if (skill.passion > Passion.None) - { - Texture2D image = (skill.passion != Passion.Major) ? passionMinorIcon : passionMajorIcon; - GUI.DrawTexture(position, image); - } - if (!skill.TotallyDisabled) - { - Rect rect3 = new Rect(position.xMax, 0f, rect.width - position.xMax, rect.height); - Widgets.FillableBar(rect3, (float)skill.Level / 20f, SkillBarFillTex, SkillBarBgTex, false); - } - Rect rect4 = new Rect(position.xMax + 4f, 0f, 999f, rect.height); - rect4.yMin += 3f; - string label; - if (skill.TotallyDisabled) - { - GUI.color = DisabledSkillColor; - label = "-"; - } - else - { - label = skill.Level.ToStringCached(); - } - GenUI.SetLabelAlign(TextAnchor.MiddleLeft); - Widgets.Label(rect4, label); - GenUI.ResetLabelAlign(); - GUI.color = Color.white; - GUI.EndGroup(); - TooltipHandler.TipRegion(rect, new TipSignal((string)mGetSkillDescription.Invoke(null, new[] { skill }), skill.def.GetHashCode() * 397945)); - } - - - private void DrawNeed(Rect rect, Pawn ownerPawn) - { - if (ownerPawn.RaceProps.IsMechanoid) return; - if (ownerPawn.needs == null) return; - //TODO: rebuild using code in DrawOnGUI - Need need = ownerPawn.needs.TryGetNeed((NeedDef)displayObject); - if (need == null) return; - - if (Mouse.IsOver(rect)) - { - Widgets.DrawHighlight(rect); - } - - TooltipHandler.TipRegion(rect, new TipSignal(() => need.GetTipString(), rect.GetHashCode())); - float num2 = 14f; - float num3 = num2 + 15f; - if (rect.height < 50f) - { - num2 *= Mathf.InverseLerp(0f, 50f, rect.height); - } - - - - Text.Font = ((rect.height <= 55f) ? GameFont.Tiny : GameFont.Small); - Text.Anchor = TextAnchor.UpperLeft; - Rect rect3 = new Rect(rect.x, rect.y + rect.height / 2f, rect.width, rect.height / 2f); - rect3 = new Rect(rect3.x + num3, rect3.y, rect3.width - num3 * 2f, rect3.height - num2); - Widgets.FillableBar(rect3, need.CurLevelPercentage); - Widgets.FillableBarChangeArrows(rect3, need.GUIChangeArrow); - List threshPercents = (List)needThreshPercent.GetValue(need); - if (threshPercents != null) - { - for (int i = 0; i < threshPercents.Count; i++) - { - needDrawBarThreshold(rect3, threshPercents[i], need.CurLevelPercentage); - } - } - float curInstantLevel = need.CurInstantLevelPercentage; - if (curInstantLevel >= 0f) - { - needDrawBarInstantMarkerAt(rect3, curInstantLevel); - } - Text.Font = GameFont.Small; - } - - private void DrawGear(Rect rect, ThingWithComps ownerPawn) - { - GUI.BeginGroup(rect); - float x = 0; - float gWidth = 28f; - float gHeight = 28f; - Pawn p1 = (ownerPawn is Pawn) ? (ownerPawn as Pawn) : (ownerPawn as Corpse).InnerPawn; - if (p1.RaceProps.Animal) return; - if (p1.equipment != null) - foreach(ThingWithComps thing in p1.equipment.AllEquipmentListForReading) - { - Rect rect2 = new Rect(x, 0, gWidth, gHeight); - DrawThing(rect2, thing, p1); - x += gWidth; - } - - if (p1.apparel != null) - foreach (Apparel thing in from ap in p1.apparel.WornApparel - orderby ap.def.apparel.bodyPartGroups[0].listOrder descending - select ap) - { - Rect rect2 = new Rect(x, 0, gWidth, gHeight); - DrawThing(rect2, thing, p1); - x += gWidth; - } - GUI.EndGroup(); - } - - private void DrawThing(Rect rect, Thing thing, Pawn selPawn) - { - - if (Mouse.IsOver(rect)) - { - GUI.color = HighlightColor; - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - if (Widgets.ButtonInvisible(rect) && Event.current.button == 1) - { - List list = new List(); - list.Add(new FloatMenuOption("ThingInfo".Translate(), delegate - { - Find.WindowStack.Add(new Dialog_InfoCard(thing)); - }, MenuOptionPriority.Default, null, null)); - if (selPawn.IsColonistPlayerControlled) - { - Action action = null; - ThingWithComps eq = thing as ThingWithComps; - Apparel ap = thing as Apparel; - if (ap != null) - { - Apparel unused; - action = delegate - { - selPawn.apparel.TryDrop(ap, out unused, selPawn.Position, true); - }; - } - else if (eq != null && selPawn.equipment.AllEquipmentListForReading.Contains(eq)) - { - ThingWithComps unused; - action = delegate - { - selPawn.equipment.TryDropEquipment(eq, out unused, selPawn.Position, true); - }; - } - else if (!thing.def.destroyOnDrop) - { - Thing unused; - action = delegate - { - selPawn.inventory.innerContainer.TryDrop(thing, selPawn.Position, selPawn.Map, ThingPlaceMode.Near, out unused); - }; - } - list.Add(new FloatMenuOption("DropThing".Translate(), action, MenuOptionPriority.Default, null, null)); - } - FloatMenu window = new FloatMenu(list, thing.LabelCap, false); - Find.WindowStack.Add(window); - } - GUI.BeginGroup(rect); - if (thing.def.DrawMatSingle != null && thing.def.DrawMatSingle.mainTexture != null) - { - Widgets.ThingIcon(new Rect(3f, 3f, 27f, 27f), thing); - } - GUI.EndGroup(); - TooltipHandler.TipRegion(rect, new TipSignal(thing.LabelCap)); - } - - - - public void needDrawBarThreshold(Rect barRect, float threshPct, float curLevel) - { - float num = (float)((barRect.width <= 60f) ? 1 : 2); - Rect position = new Rect(barRect.x + barRect.width * threshPct - (num - 1f), barRect.y + barRect.height / 2f, num, barRect.height / 2f); - Texture2D image; - if (threshPct < curLevel) - { - image = BaseContent.BlackTex; - GUI.color = new Color(1f, 1f, 1f, 0.9f); - } - else - { - image = BaseContent.GreyTex; - GUI.color = new Color(1f, 1f, 1f, 0.5f); - } - GUI.DrawTexture(position, image); - GUI.color = Color.white; - } - - public void needDrawBarInstantMarkerAt(Rect barRect, float pct) - { - float num = 12f; - if (barRect.width < 150f) - { - num /= 2f; - } - Vector2 vector = new Vector2(barRect.x + barRect.width * pct, barRect.y + barRect.height); - Rect position = new Rect(vector.x - num / 2f, vector.y, num, num); - GUI.DrawTexture(position, BarInstantMarkerTex); - } - - //from MedicalInfo - public static void MedicalCareSetter(Rect rect, ref MedicalCareCategory medCare) - { - float iconSize = rect.width / 5f; - float iconHeightOffset = (rect.height - iconSize) / 2; - Rect rect2 = new Rect(rect.x, rect.y + iconHeightOffset, iconSize, iconSize); - for (int i = 0; i < 5; i++) - { - MedicalCareCategory mc = (MedicalCareCategory)i; - Widgets.DrawHighlightIfMouseover(rect2); - GUI.DrawTexture(rect2, careTextures[i]); - if (Widgets.ButtonInvisible(rect2)) - { - medCare = mc; - } - if (medCare == mc) - { - GUI.DrawTexture(rect2, Widgets.CheckboxOnTex); - } - TooltipHandler.TipRegion(rect2, () => mc.GetLabel(), 632165 + i * 17); - rect2.x += rect2.width; - } - } - - public void Draw(Rect rect, ThingWithComps ownerPawn) - { - Text.Font = GameFont.Small; - string value = "-"; - - switch (oType) - { - case objectType.Stat: - Text.Anchor = TextAnchor.MiddleCenter; - StatDef stat = (StatDef)displayObject; - stat.neverDisabled = true; - string statValue = (stat.ValueToString(ownerPawn.GetStatValue((StatDef)displayObject, true))); - Widgets.Label(rect, statValue); - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.AppendLine(stat.LabelCap); - stringBuilder.AppendLine(); - stringBuilder.AppendLine(stat.description); - TooltipHandler.TipRegion(rect, new TipSignal(stringBuilder.ToString(), rect.GetHashCode())); - break; - - case objectType.Skill: - if ((ownerPawn is Pawn) && (ownerPawn as Pawn).RaceProps.Humanlike) DrawSkill(rect, ownerPawn as Pawn); - break; - - case objectType.Need: - if (ownerPawn is Pawn) DrawNeed(rect, ownerPawn as Pawn); - break; - - case objectType.Capacity: - Text.Anchor = TextAnchor.MiddleCenter; - if (ownerPawn is Pawn) - { - Pawn p = (Pawn)ownerPawn; - PawnCapacityDef cap = (PawnCapacityDef)displayObject; - - Pair effLabel = HealthCardUtility.GetEfficiencyLabel(p, cap); - string pawnCapTip = HealthCardUtility.GetPawnCapacityTip(p, cap); - - - // I stole this one line from Fluffy's Medical Tab. THANKS FLUFFY! - string capValue = (p.health.capacities.GetLevel(cap) * 100f).ToString("F0") + "%"; - GUI.color = effLabel.Second; - Widgets.Label(rect, capValue); - GUI.color = Color.white; - - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - - StringBuilder stringBuilder2 = new StringBuilder(); - stringBuilder2.AppendLine(cap.LabelCap); - stringBuilder2.AppendLine(); - stringBuilder2.AppendLine(cap.description); - TooltipHandler.TipRegion(rect, new TipSignal(stringBuilder2.ToString(), rect.GetHashCode())); - } - break; - - case objectType.MentalState: - Text.Font = GameFont.Tiny; - Text.Anchor = TextAnchor.MiddleCenter; - if (ownerPawn is Pawn && (ownerPawn as Pawn).MentalState != null) { - string ms = ((ownerPawn as Pawn).MentalState.InspectLine); - Widgets.Label(rect, ms); - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - } - Text.Font = GameFont.Medium; - break; - - case objectType.Age: - Text.Anchor = TextAnchor.MiddleCenter; - string ageValue = ((ownerPawn as Pawn).ageTracker.AgeBiologicalYears.ToString()); - Widgets.Label(rect, ageValue); - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - break; - - case objectType.Gear: - DrawGear(rect, ownerPawn); - break; - - case objectType.ControlPrisonerGetsFood: - if (ownerPawn is Pawn) - { - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - bool getsFood = (ownerPawn as Pawn).guest.GetsFood; - Widgets.CheckboxLabeled(new Rect(rect.x + 8f, rect.y + 3f, 27f, 27f), "", ref getsFood, false); - (ownerPawn as Pawn).guest.GetsFood = getsFood; - } - break; - - case objectType.ControlPrisonerInteraction: - if (ownerPawn is Pawn) - { - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - float x = 8f; - - GUI.BeginGroup(rect); - IEnumerator enumerator = Enum.GetValues(typeof(PrisonerInteractionModeDef)).GetEnumerator(); - try - { - while (enumerator.MoveNext()) - { - PrisonerInteractionModeDef prisonerInteractionMode = (PrisonerInteractionModeDef)(enumerator.Current); - if (Widgets.RadioButton(new Vector2(x, 3f), (ownerPawn as Pawn).guest.interactionMode == prisonerInteractionMode)) - { - (ownerPawn as Pawn).guest.interactionMode = prisonerInteractionMode; - } - TooltipHandler.TipRegion(new Rect(x, 0f, 30f, 30f), new TipSignal(prisonerInteractionMode.label)); - x += 30f; - } - } - finally - { - IDisposable disposable = enumerator as IDisposable; - if (disposable != null) - { - disposable.Dispose(); - } - } - GUI.EndGroup(); - } - break; - - case objectType.ControlMedicalCare: - if (ownerPawn is Pawn) MedicalCareSetter(rect, ref (ownerPawn as Pawn).playerSettings.medCare); - break; - - case objectType.AnimalMilkFullness: - Text.Anchor = TextAnchor.MiddleCenter; - if (ownerPawn is Pawn && ((Pawn)ownerPawn).ageTracker.CurLifeStage.milkable) - { - var comp = ((Pawn)ownerPawn).AllComps.Where(x => x is CompMilkable).FirstOrDefault(); - if(comp != null) - value = ((CompMilkable)comp).Fullness.ToStringPercent(); - } - - Widgets.Label(rect, value); - break; - - case objectType.AnimalWoolGrowth: - Text.Anchor = TextAnchor.MiddleCenter; - if (ownerPawn is Pawn && ((Pawn)ownerPawn).ageTracker.CurLifeStage.shearable) - { - var comp = ((Pawn)ownerPawn).AllComps.Where(x => x is CompShearable).FirstOrDefault(); - if (comp != null) - value = ((CompShearable)comp).Fullness.ToStringPercent(); - } - - Widgets.Label(rect, value); - break; - - case objectType.CurrentJob: - if(ownerPawn is Pawn && ((Pawn)ownerPawn).jobs.curDriver != null ) - { - string text = ((Pawn)ownerPawn).jobs.curDriver.GetReport(); - Text.Anchor = TextAnchor.MiddleLeft; - Rect tRect = new Rect(rect.xMin + 2, rect.yMin + 3, rect.width - 2, rect.height); - GenText.SetTextSizeToFit(text, tRect); - - if (Text.Font == GameFont.Tiny) - Widgets.Label(tRect, text); - else - { - Rect sRect = new Rect(rect.xMin + 2, rect.yMin, rect.width - 2, rect.height); - Widgets.Label(sRect, text); - } - - if (Mouse.IsOver(rect)) - { - GUI.DrawTexture(rect, TexUI.HighlightTex); - } - } - break; - } - - - } - - - } -} diff --git a/Source/kNumbers/MainTabWindow_Numbers.cs b/Source/kNumbers/MainTabWindow_Numbers.cs deleted file mode 100644 index d879f7f..0000000 --- a/Source/kNumbers/MainTabWindow_Numbers.cs +++ /dev/null @@ -1,898 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using UnityEngine; -using Verse; -using RimWorld; -using System.Reflection; - -namespace kNumbers -{ - public abstract class MainTabWindow_ThingWithComp : MainTabWindow - { - public const int cFreeSpaceAtTheEnd = 50; - - public const float buttonWidth = 160f; - - public const float PawnRowHeight = 35f; - - protected const float NameColumnWidth = 175f; - - protected const float NameLeftMargin = 15f; - - protected Vector2 scrollPosition = Vector2.zero; - - protected List things = new List(); - - public float kListDesiredWidth = 0f; - /* - protected List pawns - { - set - { - this.things = value.Select(p=>p as ThingWithComps).ToList(); - } - } - */ - protected int ThingsCount - { - get - { - return this.things.Count; - } - } - - protected abstract void DrawPawnRow(Rect r, ThingWithComps p); - - public override void PreOpen() - { - base.PreOpen(); - this.BuildPawnList(); - } - - public override void PostOpen() - { - base.PostOpen(); - this.windowRect.size = this.InitialSize; - } - - public override void DoWindowContents(Rect inRect) - { - base.DoWindowContents(inRect); - this.windowRect.size = this.InitialSize; - } - - protected virtual void BuildPawnList() - { - this.things.Clear(); - } - - public void Notify_PawnsChanged() - { - this.BuildPawnList(); - } - - protected void DrawRows(Rect outRect) - { - float winWidth = outRect.width - 16f; - Rect viewRect = new Rect(0f, 0f, winWidth, (float)this.things.Count * PawnRowHeight); - - Widgets.BeginScrollView(outRect, ref this.scrollPosition, viewRect); - float num = 0f; - for (int i = 0; i < this.things.Count; i++) - { - ThingWithComps p = this.things[i]; - Rect rect = new Rect(0f, num, viewRect.width, PawnRowHeight); - if (num - this.scrollPosition.y + PawnRowHeight >= 0f && num - this.scrollPosition.y <= outRect.height) - { - GUI.color = new Color(1f, 1f, 1f, 0.2f); - Widgets.DrawLineHorizontal(0f, num, viewRect.width); - GUI.color = Color.white; - this.PreDrawPawnRow(rect, p); - this.DrawPawnRow(rect, p); - this.PostDrawPawnRow(rect, p); - } - num += PawnRowHeight; - } - Widgets.EndScrollView(); - Text.Anchor = TextAnchor.UpperLeft; - } - - private void PreDrawPawnRow(Rect rect, ThingWithComps p) - { - Rect rect2 = new Rect(0f, rect.y, rect.width, PawnRowHeight); - if (Mouse.IsOver(rect2)) - { - GUI.DrawTexture(rect2, TexUI.HighlightTex); - } - Rect rect3 = new Rect(0f, rect.y, 175f, PawnRowHeight); - Rect position = rect3.ContractedBy(3f); - if (p is Pawn) - { - if ((p as Pawn).health.summaryHealth.SummaryHealthPercent < 0.999f) - { - Rect rect4 = new Rect(rect3); - rect4.xMin -= 4f; - rect4.yMin += 4f; - rect4.yMax -= 6f; - Widgets.FillableBar(rect4, (p as Pawn).health.summaryHealth.SummaryHealthPercent, GenMapUI.OverlayHealthTex, BaseContent.ClearTex, false); - } - } - if (Mouse.IsOver(rect3)) - { - GUI.DrawTexture(position, TexUI.HighlightTex); - } - string label; - Pawn p1 = (p is Corpse) ? (p as Corpse).InnerPawn : p as Pawn; - if (!p1.RaceProps.Humanlike && p1.Name != null && !p1.Name.Numerical) - { - label = p1.Name.ToStringShort.CapitalizeFirst() + ", " + p1.KindLabel; - } - else - { - label = p1.LabelCap; - } - Text.Font = GameFont.Small; - Text.Anchor = TextAnchor.MiddleLeft; - Text.WordWrap = false; - Rect rect5 = new Rect(rect3); - rect5.xMin += 15f; - Widgets.Label(rect5, label); - Text.WordWrap = true; - if (Widgets.ButtonInvisible(rect3)) - { - //shift-selection: keep tab, don't deselect, don't move camera - if (Event.current.shift) - { - //do nothing - } - //alt-selection: deselect, remove tab - else if (Event.current.alt) - { - Find.MainTabsRoot.EscapeCurrentTab(true); - Find.Selector.ClearSelection(); - } - //normal selection: remove tab, deselect, move camera - else - { - Find.MainTabsRoot.EscapeCurrentTab(true); - Find.Selector.ClearSelection(); - Find.CameraDriver.JumpToVisibleMapLoc(p.PositionHeld); - } - - //finally select if pawn is present - if (p.Spawned) - { - Find.Selector.Select(p, true, true); - } - return; - } - TipSignal tooltip = p.GetTooltip(); - tooltip.text = "ClickToJumpTo".Translate() + "\n\n" + tooltip.text; - TooltipHandler.TipRegion(rect3, tooltip); - } - - private void PostDrawPawnRow(Rect rect, ThingWithComps p) - { - if (p is Pawn) - { - if ((p as Pawn).Downed) - { - GUI.color = new Color(1f, 0f, 0f, 0.5f); - Widgets.DrawLineHorizontal(rect.x, rect.center.y, rect.width); - GUI.color = Color.white; - } - } - } - } - - - public class MainTabWindow_Numbers : MainTabWindow_ThingWithComp - { - - public enum pawnType - { - Colonists, - Prisoners, - Guests, - Enemies, //assuming humanlike enemies, animals somewhat worked, but mechanoids will crash the tab - Animals, - WildAnimals, - Corpses, - AnimalCorpses, - } - - public enum orderBy - { - Name, - Column - } - - // List things; - public static bool pawnListDescending = false; - public static bool isDirty = true; - int pawnListUpdateNext = 0; - - //global lists - List pawnHumanlikeStatDef = new List(); - List pawnAnimalStatDef = new List(); - List pawnHumanlikeNeedDef = new List(); - List pawnAnimalNeedDef = new List(); - List pawnSkillDef = new List(); - - //local lists - content depends on pawn type - List pStatDef; - List pNeedDef; - - List kList = new List(); - - orderBy chosenOrderBy = orderBy.Name; - KListObject sortObject; - - float maxWindowWidth = 1060f; - - public override Vector2 RequestedTabSize - { - get - { - float maxWidth = (maxWindowWidth > kListDesiredWidth + 70) ? maxWindowWidth : kListDesiredWidth + 70; - return new Vector2(maxWidth, 90f + (float)base.ThingsCount * PawnRowHeight + 65f + 16f); - } - } - - public MainTabWindow_Numbers() - { - Pawn tmpPawn; - - MethodInfo statsToDraw = typeof(StatsReportUtility).GetMethod("StatsToDraw", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, new Type[] { typeof(Thing) }, null); - - tmpPawn = PawnGenerator.GeneratePawn(PawnKindDefOf.SpaceSoldier, Faction.OfPlayer); - - pawnHumanlikeStatDef = (from s in ((IEnumerable)statsToDraw.Invoke(null, new[] { tmpPawn })) where s.ShouldDisplay && s.stat != null select s.stat).OrderBy(stat => stat.LabelCap).ToList(); - pawnHumanlikeNeedDef.AddRange(DefDatabase.AllDefsListForReading); - - tmpPawn = PawnGenerator.GeneratePawn(PawnKindDefOf.Thrumbo, null); - pawnAnimalStatDef = (from s in ((IEnumerable)statsToDraw.Invoke(null, new[] { tmpPawn })) where s.ShouldDisplay && s.stat != null select s.stat).ToList(); - pawnAnimalNeedDef = tmpPawn.needs.AllNeeds.Where(x => x.def.showOnNeedList).Select(x => x.def).ToList(); - } - - String numbersXMLPath - { - get - { - //TODO: FIX!!! - return Path.Combine(GenFilePaths.ModsConfigFilePath, "kNumbers.config"); - } - } - - public void writePresets() - { - - } - - public void readPresets() - { - - } - - public override void PreOpen() - { - var component = Find.World.GetComponent(); - component.savedKLists.TryGetValue(component.chosenPawnType, out kList); - if (kList == null) - { - kList = new List(); - component.savedKLists[component.chosenPawnType] = kList; - } - base.PreOpen(); - isDirty = true; - } - - bool fits(float desiredSize) - { - return (kListDesiredWidth + desiredSize + 70 < maxWindowWidth); - } - - - bool isEnemy(Pawn p) - { - return - !p.IsPrisoner && - ( - ((p.Faction != null) && p.Faction.HostileTo(Faction.OfPlayer)) || - (!p.RaceProps.Animal && (!p.RaceProps.Humanlike || p.RaceProps.IsMechanoid)) - ) && - !p.Position.Fogged(Find.VisibleMap) && (p.Position != IntVec3.Invalid); - } - - bool isWildAnimal(Pawn p) - { - return p.RaceProps.Animal && (p.Faction != Faction.OfPlayer) && !p.Position.Fogged(Find.VisibleMap) && (p.Position != IntVec3.Invalid); - } - - bool isGuest(Pawn p) - { - return - (p.guest != null) && !p.guest.IsPrisoner && - (p.Faction != null) && !p.Faction.HostileTo(Faction.OfPlayer) && p.Faction != Faction.OfPlayer && - !p.Position.Fogged(Find.VisibleMap) && (p.Position != IntVec3.Invalid); - } - - void UpdatePawnList() - { - var component = Find.World.GetComponent(); - - this.things.Clear(); - IEnumerable tempPawns = new List(); - switch (component.chosenPawnType) - { - default: - case pawnType.Colonists: - tempPawns = Find.VisibleMap.mapPawns.FreeColonists.Cast().ToList(); - pStatDef = pawnHumanlikeStatDef; - pNeedDef = pawnHumanlikeNeedDef; - break; - - case pawnType.Prisoners: - tempPawns = Find.VisibleMap.mapPawns.PrisonersOfColony.Cast().ToList(); - pStatDef = pawnHumanlikeStatDef; - pNeedDef = pawnHumanlikeNeedDef; - break; - - case pawnType.Guests: - tempPawns = Find.VisibleMap.mapPawns.AllPawns.Where(isGuest).Cast().ToList(); - pStatDef = pawnHumanlikeStatDef; - pNeedDef = pawnHumanlikeNeedDef; - break; - - case pawnType.Enemies: - // tempPawns = Find.MapPawns.PawnsHostileToColony.Cast().ToList(); - tempPawns = (from p in Find.VisibleMap.mapPawns.AllPawns where isEnemy(p) select p).Cast().ToList(); - pStatDef = pawnHumanlikeStatDef; - pNeedDef = pawnHumanlikeNeedDef; - break; - - case pawnType.Animals: - tempPawns = (from p in Find.VisibleMap.mapPawns.PawnsInFaction(Faction.OfPlayer) where p.RaceProps.Animal select p).Cast().ToList(); - pStatDef = pawnAnimalStatDef; - pNeedDef = pawnAnimalNeedDef; - break; - - case pawnType.WildAnimals: - tempPawns = (from p in Find.VisibleMap.mapPawns.AllPawns where isWildAnimal(p) select p).Cast().ToList(); - pStatDef = pawnAnimalStatDef; - pNeedDef = pawnAnimalNeedDef; - break; - - case pawnType.Corpses: - tempPawns = Find.VisibleMap.listerThings.AllThings.Where(p => (p is Corpse) && (!(p as Corpse).InnerPawn.RaceProps.Animal)).Cast().ToList(); - pStatDef = new List(); - pNeedDef = new List(); - break; - case pawnType.AnimalCorpses: - tempPawns = Find.VisibleMap.listerThings.AllThings.Where(p => (p is Corpse) && (p as Corpse).InnerPawn.RaceProps.Animal && !p.Position.Fogged(Find.VisibleMap)).Cast().ToList(); - pStatDef = new List(); - pNeedDef = new List(); - break; - } - - switch (chosenOrderBy) - { - default: - case orderBy.Name: - this.things = (from p in tempPawns - orderby p.LabelCap ascending - select p).ToList(); - break; - - case orderBy.Column: - switch (sortObject.oType) - { - case KListObject.objectType.Stat: - this.things = (from p in tempPawns - orderby p.GetStatValue((StatDef)sortObject.displayObject, true) ascending - select p).ToList(); - break; - - case KListObject.objectType.Need: - - this.things = (from p in tempPawns - where (p is Pawn) && !(p as Pawn).RaceProps.IsMechanoid && ((p as Pawn).needs != null) - orderby ((p as Pawn).needs.TryGetNeed((NeedDef)sortObject.displayObject) != null ? (p as Pawn).needs.TryGetNeed((NeedDef)sortObject.displayObject).CurLevel : 0) ascending - select p).ToList(); - break; - - case KListObject.objectType.Capacity: - - this.things = (from p in tempPawns - where (p is Pawn) && ((p as Pawn).health != null) - orderby ((p as Pawn).health.capacities.GetLevel((PawnCapacityDef)sortObject.displayObject)) ascending - select p).ToList(); - break; - - case KListObject.objectType.Skill: - this.things = (from p in tempPawns - where (p is Pawn) && (p as Pawn).RaceProps.Humanlike && ((p as Pawn).skills != null) - orderby (p as Pawn).skills.GetSkill((SkillDef)sortObject.displayObject).XpTotalEarned ascending - select p).ToList(); - break; - - case KListObject.objectType.Gear: - this.things = tempPawns.Where(p => (p is Pawn) || ((p is Corpse) && (!(p as Corpse).InnerPawn.RaceProps.Animal))).OrderBy(p => { - Pawn p1 = (p is Pawn) ? (p as Pawn) : (p as Corpse).InnerPawn; - return (p1.equipment != null) ? ((p1.equipment.AllEquipmentListForReading.Any()) ? p1.equipment.AllEquipmentListForReading.First().LabelCap : "") : ""; - }).ToList(); - break; - - case KListObject.objectType.MentalState: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).MentalState != null ? (p as Pawn).MentalState.ToString() : "").ToList(); - break; - - case KListObject.objectType.ControlPrisonerGetsFood: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).guest.GetsFood).ToList(); - break; - - case KListObject.objectType.ControlPrisonerInteraction: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).guest.interactionMode).ToList(); - break; - - case KListObject.objectType.Age: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).ageTracker.AgeBiologicalYearsFloat).ToList(); - break; - - case KListObject.objectType.ControlMedicalCare: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).playerSettings.medCare).ToList(); - break; - - case KListObject.objectType.CurrentJob: - this.things = tempPawns.Where(p => p is Pawn).OrderBy(p => (p as Pawn).jobs.curDriver.GetReport()).ToList(); - break; - - case KListObject.objectType.AnimalMilkFullness: - this.things = tempPawns.Where(p => p is Pawn).OrderBy( - p => { - float f = -1; - if ((p as Pawn).ageTracker.CurLifeStage.milkable) - { - var comp = p.AllComps.OfType().FirstOrDefault(); - if (comp != null) - f = comp.Fullness; - } - return f; - } - ).ToList(); - break; - - case KListObject.objectType.AnimalWoolGrowth: - this.things = tempPawns.Where(p => p is Pawn).OrderBy( - p => { - float f = -1; - if ((p as Pawn).ageTracker.CurLifeStage.milkable) - { - var comp = p.AllComps.OfType().FirstOrDefault(); - if (comp != null) - f = comp.Fullness; - } - return f; - } - ).ToList(); - break; - - default: - //no way to sort - this.things = tempPawns.ToList(); - break; - } - - break; - } - - if (pawnListDescending) - { - this.things.Reverse(); - } - - isDirty = false; - pawnListUpdateNext = Find.TickManager.TicksGame + Verse.GenTicks.TickRareInterval; - - } - - public void PawnSelectOptionsMaker() - { - List list = new List(); - foreach (pawnType pawn in Enum.GetValues(typeof(pawnType))) - { - Action action = delegate - { - var component = Find.World.GetComponent(); - if (pawn != component.chosenPawnType) - { - component.savedKLists.TryGetValue(pawn, out kList); - if (kList == null) - { - kList = new List(); - component.savedKLists[pawn] = kList; - } - component.chosenPawnType = pawn; - isDirty = true; - } - }; - - list.Add(new FloatMenuOption(("koisama.pawntype." + pawn.ToString()).Translate(), action, MenuOptionPriority.Default, null, null)); - } - Find.WindowStack.Add(new FloatMenu(list)); - } - - public void StatsOptionsMaker() - { - - List list = new List(); - foreach (StatDef stat in pStatDef) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Stat, stat.LabelCap, stat); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption(stat.LabelCap, action, MenuOptionPriority.Default, null, null)); - } - Find.WindowStack.Add(new FloatMenu(list)); - } - - public void SkillsOptionsMaker() - { - List list = new List(); - foreach (SkillDef skill in DefDatabase.AllDefsListForReading) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Skill, skill.LabelCap, skill); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption(skill.LabelCap, action, MenuOptionPriority.Default, null, null)); - } - Find.WindowStack.Add(new FloatMenu(list)); - } - - public void NeedsOptionsMaker() - { - List list = new List(); - foreach (NeedDef need in pNeedDef) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Need, need.LabelCap, need); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption(need.LabelCap, action, MenuOptionPriority.Default, null, null)); - } - Find.WindowStack.Add(new FloatMenu(list)); - } - - public void CapacityOptionsMaker() - { - List list = new List(); - foreach (PawnCapacityDef pcd in DefDatabase.AllDefsListForReading) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Capacity, pcd.LabelCap, pcd); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption(pcd.LabelCap, action, MenuOptionPriority.Default, null, null)); - } - Find.WindowStack.Add(new FloatMenu(list)); - } - - //presets - public void PresetOptionsMaker() - { - - } - - //other hardcoded options - public void OtherOptionsMaker() - { - var component = Find.World.GetComponent(); - List list = new List(); - - //equipment bearers - if (new[] { pawnType.Colonists, pawnType.Prisoners, pawnType.Enemies, pawnType.Corpses }.Contains(component.chosenPawnType)) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Gear, "koisama.Equipment".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.Equipment".Translate(), action, MenuOptionPriority.Default, null, null)); - } - - //all living things - if (new[] { pawnType.Colonists, pawnType.Prisoners, pawnType.Enemies, pawnType.Animals, pawnType.WildAnimals, pawnType.Guests }.Contains(component.chosenPawnType)) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.Age, "koisama.Age".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.Age".Translate(), action, MenuOptionPriority.Default, null, null)); - - action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.MentalState, "koisama.MentalState".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.MentalState".Translate(), action, MenuOptionPriority.Default, null, null)); - } - - if (component.chosenPawnType == pawnType.Prisoners) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.ControlPrisonerGetsFood, "GetsFood".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("GetsFood".Translate(), action, MenuOptionPriority.Default, null, null)); - - Action action2 = delegate - { - KListObject kl = new KListObject(KListObject.objectType.ControlPrisonerInteraction, "koisama.Interaction".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.Interaction".Translate(), action2, MenuOptionPriority.Default, null, null)); - } - - if (component.chosenPawnType == pawnType.Animals) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.AnimalMilkFullness, "MilkFullness".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("MilkFullness".Translate(), action, MenuOptionPriority.Default, null, null)); - - Action action2 = delegate - { - KListObject kl = new KListObject(KListObject.objectType.AnimalWoolGrowth, "WoolGrowth".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("WoolGrowth".Translate(), action2, MenuOptionPriority.Default, null, null)); - } - - //healable - if (new[] { pawnType.Colonists, pawnType.Prisoners, pawnType.Animals }.Contains(component.chosenPawnType)) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.ControlMedicalCare, "koisama.MedicalCare".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.MedicalCare".Translate(), action, MenuOptionPriority.Default, null, null)); - } - - if (!new[] { pawnType.Corpses, pawnType.AnimalCorpses }.Contains(component.chosenPawnType)) - { - Action action = delegate - { - KListObject kl = new KListObject(KListObject.objectType.CurrentJob, "koisama.CurrentJob".Translate(), null); - //if (fits(kl.minWidthDesired)) - kList.Add(kl); - }; - list.Add(new FloatMenuOption("koisama.CurrentJob".Translate(), action, MenuOptionPriority.Default, null, null)); - } - - Find.WindowStack.Add(new FloatMenu(list)); - } - - public override void DoWindowContents(Rect r) - { - var component = Find.World.GetComponent(); - maxWindowWidth = Screen.width; - base.DoWindowContents(r); - - if (pawnListUpdateNext < Find.TickManager.TicksGame) - isDirty = true; - - if (isDirty) - { - UpdatePawnList(); - } - - Rect position = new Rect(0f, 0f, r.width, 115f); - GUI.BeginGroup(position); - - float x = 0f; - Text.Font = GameFont.Small; - - //pawn/prisoner list switch - Rect sourceButton = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(sourceButton, ("koisama.pawntype." + component.chosenPawnType.ToString()).Translate())) - { - PawnSelectOptionsMaker(); - } - x += buttonWidth + 10; - TooltipHandler.TipRegion(sourceButton, new TipSignal("koisama.Numbers.ClickToToggle".Translate(), sourceButton.GetHashCode())); - - //stats btn - Rect addColumnButton = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(addColumnButton, "koisama.Numbers.AddColumnLabel".Translate())) - { - StatsOptionsMaker(); - } - x += buttonWidth + 10; - - //skills btn - if (new[] { pawnType.Colonists, pawnType.Prisoners, pawnType.Enemies }.Contains(component.chosenPawnType)) - { - Rect skillColumnButton = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(skillColumnButton, "koisama.Numbers.AddSkillColumnLabel".Translate())) - { - SkillsOptionsMaker(); - } - x += buttonWidth + 10; - } - - //needs btn - Rect needsColumnButton = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(needsColumnButton, "koisama.Numbers.AddNeedsColumnLabel".Translate())) - { - NeedsOptionsMaker(); - } - x += buttonWidth + 10; - - //cap btn - Rect capacityColumnButton = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(capacityColumnButton, "koisama.Numbers.AddCapacityColumnLabel".Translate())) - { - CapacityOptionsMaker(); - } - x += buttonWidth + 10; - - Rect otherColumnBtn = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(otherColumnBtn, "koisama.Numbers.AddOtherColumnLabel".Translate())) - { - OtherOptionsMaker(); - } - x += buttonWidth + 10; - - //TODO: implement - /* - Rect addPresetBtn = new Rect(x, 0f, buttonWidth, PawnRowHeight); - if (Widgets.ButtonText(addPresetBtn, "koisama.Numbers.SetPresetLabel".Translate())) - { - PresetOptionsMaker(); - } - x += buttonWidth + 10; - */ - - Rect thingCount = new Rect(10f, 45f, 200f, 30f); - Widgets.Label(thingCount, "koisama.Numbers.Count".Translate() + ": " + this.things.Count().ToString()); - - x = 0; - //names - Rect nameLabel = new Rect(x, 75f, NameColumnWidth, PawnRowHeight); - Text.Anchor = TextAnchor.LowerCenter; - Widgets.Label(nameLabel, "koisama.Numbers.Name".Translate()); - if (Widgets.ButtonInvisible(nameLabel)) - { - if (chosenOrderBy == orderBy.Name) - { - pawnListDescending = !pawnListDescending; - } - else - { - chosenOrderBy = orderBy.Name; - pawnListDescending = false; - } - isDirty = true; - } - - TooltipHandler.TipRegion(nameLabel, "koisama.Numbers.SortByTooltip".Translate("koisama.Numbers.Name".Translate())); - Widgets.DrawHighlightIfMouseover(nameLabel); - x += NameColumnWidth; - - //header - //TODO: better interface - auto width calculation - bool offset = true; - kListDesiredWidth = 175f; - Text.Anchor = TextAnchor.MiddleCenter; - - for (int i = 0; i < kList.Count; i++) - { - float colWidth = kList[i].minWidthDesired; - - if (colWidth + kListDesiredWidth + cFreeSpaceAtTheEnd > maxWindowWidth) - { - break; - } - - kListDesiredWidth += colWidth; - - Rect defLabel = new Rect(x - 35, 25f + (offset ? 10f : 50f), colWidth + 70, 40f); - Widgets.DrawLine(new Vector2(x + colWidth / 2, 55f + (offset ? 15f : 55f)), new Vector2(x + colWidth / 2, 113f), Color.gray, 1); - Widgets.Label(defLabel, kList[i].label); - - StringBuilder labelSB = new StringBuilder(); - labelSB.AppendLine("koisama.Numbers.SortByTooltip".Translate(kList[i].label)); - labelSB.AppendLine("koisama.Numbers.RemoveTooltip".Translate()); - TooltipHandler.TipRegion(defLabel, labelSB.ToString()); - Widgets.DrawHighlightIfMouseover(defLabel); - - if (Widgets.ButtonInvisible(defLabel)) - { - if (Event.current.button == 1) - { - kList.RemoveAt(i); - } - else - { - - if (chosenOrderBy == orderBy.Column && kList[i].Equals(sortObject)) - { - pawnListDescending = !pawnListDescending; - } - else - { - sortObject = kList[i]; - chosenOrderBy = orderBy.Column; - pawnListDescending = false; - } - } - isDirty = true; - } - offset = !offset; - x += colWidth; - } - GUI.EndGroup(); - - //content - Rect content = new Rect(0f, position.yMax, r.width, r.height - position.yMax); - GUI.BeginGroup(content); - base.DrawRows(new Rect(0f, 0f, content.width, content.height)); - GUI.EndGroup(); - } - - protected override void DrawPawnRow(Rect r, ThingWithComps p) - { - float x = 175f; - float y = r.yMin; - - Text.Anchor = TextAnchor.MiddleCenter; - - //TODO: better interface - auto width calculation, make sure columns won't overlap - for (int i = 0; i < kList.Count; i++) - { - float colWidth = kList[i].minWidthDesired; - if (colWidth + x + cFreeSpaceAtTheEnd > maxWindowWidth) - { - //soft break - break; - } - Rect capCell = new Rect(x, y, colWidth, PawnRowHeight); - kList[i].Draw(capCell, p); - x += colWidth; - } - - /* - if (p.health.Downed) { - Widgets.DrawLine(new Vector2(5f, y + PawnRowHeight / 2), new Vector2(r.xMax - 5f, y + PawnRowHeight / 2), Color.red, 1); - }*/ - - } - - } -} \ No newline at end of file diff --git a/Source/kNumbers/Properties/AssemblyInfo.cs b/Source/kNumbers/Properties/AssemblyInfo.cs deleted file mode 100644 index d3f0903..0000000 --- a/Source/kNumbers/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RWNumbers")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("RWNumbers")] -[assembly: AssemblyCopyright("Copyright © koisama 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("37259212-9221-451e-9b38-b06865555576")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.0.2")] -[assembly: AssemblyFileVersion("1.1.0.2")] diff --git a/Source/kNumbers/WorldComponent_Numbers.cs b/Source/kNumbers/WorldComponent_Numbers.cs deleted file mode 100644 index 8ca63a1..0000000 --- a/Source/kNumbers/WorldComponent_Numbers.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using RimWorld.Planet; -using Verse; - -namespace kNumbers -{ - class WorldComponent_Numbers : WorldComponent - { - public Dictionary> savedKLists = new Dictionary>(); - public MainTabWindow_Numbers.pawnType chosenPawnType = new MainTabWindow_Numbers.pawnType(); - public static bool hasData = false; - - public WorldComponent_Numbers(World world) : base(world) { } - - public override void ExposeData() - { - Scribe_Values.Look(ref chosenPawnType, "chosenPawnType", MainTabWindow_Numbers.pawnType.Colonists); - foreach (MainTabWindow_Numbers.pawnType type in Enum.GetValues(typeof(MainTabWindow_Numbers.pawnType))) - { - List tmpKList; - savedKLists.TryGetValue(type, out tmpKList); - Scribe_Collections.Look(ref tmpKList, "klist-" + type, LookMode.Deep); - savedKLists[type] = tmpKList; - } - } - } -} diff --git a/Source/kNumbers/kNumbers.csproj b/Source/kNumbers/kNumbers.csproj deleted file mode 100644 index c7d99a9..0000000 --- a/Source/kNumbers/kNumbers.csproj +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Debug - AnyCPU - {37259212-9221-451E-9B38-B06865555576} - Library - Properties - koisama - RWNumbers - v3.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - AnyCPU - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - false - - - Always - - - - ..\..\..\..\RimWorldWin_Data\Managed\Assembly-CSharp.dll - - - - - - - - - ..\..\..\..\RimWorldWin_Data\Managed\UnityEngine.dll - - - - - - - - - - - -copy /y $(TargetFileName) ..\..\..\..\Assemblies -cd $(ProjectDir) -rd /s /q bin -rd /s /q obj - - - \ No newline at end of file diff --git a/Textures/UI/Icons/Trainables/Rescue.png b/Textures/UI/Icons/Trainables/Rescue.png new file mode 100644 index 0000000..c316ae3 Binary files /dev/null and b/Textures/UI/Icons/Trainables/Rescue.png differ diff --git a/_PublisherPlus.xml b/_PublisherPlus.xml new file mode 100644 index 0000000..099e284 --- /dev/null +++ b/_PublisherPlus.xml @@ -0,0 +1,10 @@ + + + + .editorconfig + .git + .vs + Numbers\bin + Numbers\obj + + \ No newline at end of file