diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 10a818e6..b67ee4bf 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml index 4c13fce4..29d970db 100644 --- a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml +++ b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml @@ -1,6 +1,5 @@ - WULA_EnterMaintenancePod WulaFallenEmpire.JobDriver_EnterMaintenancePod @@ -29,4 +28,10 @@ true false + + + WULA_RecycleMechanoid + WulaFallenEmpire.JobDriver_RecycleMechanoid + 正在准备进入猫猫地堡。 + \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml index 027dce73..a8c15187 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Drop.xml @@ -1,11 +1,364 @@ - - - WULA_RecycleMechanoid - WulaFallenEmpire.JobDriver_RecycleMechanoid - 正在准备进入猫猫地堡。 - + + + WulaWall_Cleanzone + + 清理出一块场地并准备好资源,使得乌拉帝国母舰可以向此处投放建筑。建造好的信标可以收起或移至他处,但是必须要有母舰或者后勤舰在上空才能投送建筑。\n\n乌拉帝国用于建造堡垒的外壁相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + MinifiedThing + Normal + +
  • BuildingsMisc
  • +
    + + Wula/Building/Linked/WulaWall/WulaWall_Atlas + Graphic_Multi + (1,1) + (73,185,254,155) + + false + false + false + false + false + Building + PassThroughOnly + 0 + false + false + + 0 + false + + 1 + 1 + 1 + 0 + + (1,1) + 0 + 1 + + 0 + + 15 + + + BuildingDestroyed_Metal_Small + false + false + + WULA_Buildings + +
  • + WulaWall_Incoming + true + 1 + WULA_Flyover_BaseBuilder + true + false + 乌拉帝国母舰或后勤舰 +
  • +
    +
    + + WulaWall_Incoming + + (1,1) + + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Graphic_Single + CutoutFlying + (1,1) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (1, 1) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + WulaWall +
    + +
  • + Smoke_Joint +
  • +
    +
    + + WulaWall + + 乌拉帝国堡垒外壁,相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 + 1800 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + + Wula/Building/Linked/WulaWall/WulaWall_Atlas + Graphic_Single + CutoutComplex + (0.5, 0.5, 0.5) + + + 20 + 1 + 1200 + 2500 + 0 + 0.22 + 0.1 + + + 15 + + + 0 + + true + + + + +
  • Metallic
  • +
    +
    +
    + + false + Heavy + + +
  • + Bomb + 0.01 +
  • +
  • + Thump + 0.1 +
  • +
    + +
  • + + true + false +
  • +
  • + MeditationFocusStrength + +
  • Minimal
  • + + +
  • + CompPowerTransmitter + true +
  • +
    +
    + + WulaDoor_Cleanzone + + 清理出一块场地并准备好资源,使得乌拉帝国母舰可以向此处投放建筑。建造好的信标可以收起或移至他处,但是必须要有母舰或者后勤舰在上空才能投送建筑。\n\n乌拉帝国堡垒的大门不仅能够抵御大量爆炸和震荡伤害,还拥有无需通电即可运转的伺服系统来增加大门通过速度。 + Building_Door + Building + DoorMoveable + 1 + true + + Wula/Building/Door/WulaAutodoor_Mover + Graphic_Single + (73,185,254,155) + + + 1 + 1 + 0 + 1 + + + 50 + 1 + + false + + false + true + false + false + false + false + false + Normal + PassThroughOnly + 0 + false + + Light + Structure + RealtimeOnly + WULA_Buildings + + true + true + true + Door_OpenPowered + Door_ClosePowered + Door_OpenManual + Door_CloseManual + Blueprint_Door + + Wula/Building/Door/WulaAutodoor_BluePrint + + false + + 2505 + Wula/Building/Door/WulaAutodoor + +
  • + WulaDoor_Incoming + true + 1 + WULA_Flyover_BaseBuilder + true + false + 乌拉帝国母舰或后勤舰 +
  • +
    +
    + + WulaDoor_Incoming + + (1,1) + + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Graphic_Single + CutoutFlying + (1,1) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (1, 1) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + WulaDoor +
    + +
  • + Smoke_Joint +
  • +
    +
    + + WulaDoor + + 乌拉帝国堡垒的大门,不仅能够抵御大量爆炸和震荡伤害,还拥有无需通电即可运转的伺服系统来增加大门通过速度。 + Building_Door + Building + DoorMoveable + 1 + true + + Wula/Building/Door/WulaAutodoor_Mover + Graphic_Single + + + false + + + + 2 + 1000 + 0 + 3000 + 20 + 2 + + + 50 + 1 + + false + true + Normal + + + false + + Light + Structure + true + 1.0 + true + RealtimeOnly + +
  • + + true + false +
  • +
  • + CompPowerTrader + 0 + true +
  • +
  • +
  • + true +
  • +
    + +
  • + Bomb + 0.01 +
  • +
  • + Thump + 0.01 +
  • +
    + + true + true + true + Door_OpenPowered + Door_ClosePowered + Door_OpenManual + Door_CloseManual + Blueprint_Door + + Wula/Building/Door/WulaAutodoor_BluePrint + + false + + 2505 + Wula/Building/Door/WulaAutodoor + Misc2 +
    + + WULA_Cat_Bunker_Cleanzone @@ -32,10 +385,10 @@ Building PassThroughOnly + 0 false 0.5 false - 0 false @@ -49,6 +402,7 @@ 1 300 + 3 BuildingDestroyed_Metal_Small @@ -134,7 +488,7 @@ 0 - 2500 + 500 1 20 0 @@ -148,6 +502,11 @@ 3.5 +
  • + + true + false +
  • 6 @@ -228,11 +587,194 @@ + + + WULA_MaintenancePod_Cleanzone + + 清理出一块场地并准备好资源,使得乌拉帝国母舰可以向此处投放建筑。建造好的信标可以收起或移至他处,但是必须要有母舰或者后勤舰在上空才能投送建筑。\n\n合成人维护舱是为乌拉帝国合成人设计的设施,机械乌拉需要定期进入其中进行身体机能的维护和校准,否则他们的身体会逐渐衰弱。维护需要消耗零部件,同时会修理所有的伤口。 + Wula/Building/WULA_MaintenancePod_south + MinifiedThing + Normal + + WulaSpecies + + +
  • BuildingsMisc
  • + + + Wula/Building/WULA_Dropping_Building_Cleanzone + Graphic_Multi + (3,3) + + false + + + Building + PassThroughOnly + false + 0.5 + false + 0 + false + + + 1 + 1 + 1 + 0 + + (3,3) + 0 + 1 + + 150 + 10 + + + BuildingDestroyed_Metal_Small + + WULA_Buildings + +
  • + WULA_MaintenancePod_Incoming + true + 1 + WULA_Flyover_BaseBuilder + true + false + 乌拉帝国母舰或后勤舰 +
  • +
    +
    + + WULA_MaintenancePod_Incoming + + (3,3) + + Wula/Building/WULA_MaintenancePod_Incoming + Graphic_Single + CutoutFlying + (3,3) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (2, 2) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + WULA_MaintenancePod +
    + +
  • + Smoke_Joint +
  • +
    +
    + + WULA_MaintenancePod + + 一个为乌拉帝国合成人设计的全自动维护舱,机械乌拉需要定期进入其中进行身体机能的维护和校准,否则他们的身体会逐渐衰弱。维护需要消耗零部件,同时会修理所有的伤口。 + true + + Wula/Building/WULA_MaintenancePod_south + Graphic_Single + (3, 3) + + (1.5, 1.5, 1.7) + + + + RealtimeOnly + true + + Building + PassThroughOnly + 42 + true + 0.5 + false + false + + 250 + 20000 + 50 + 0.5 + -5 + + (3,3) + (0,0,-2) + true + + 150 + 10 + + + 8 + + BuildingDestroyed_Metal_Big + 1800 + + Normal + +
  • + + true + false +
  • +
  • + CompPowerTrader + 50 +
  • +
  • +
  • + 20.0 + + +
  • ComponentIndustrial
  • + + + 零部件 + true + true + true + +
  • + BiosculpterPod_Enter + BiosculpterPod_Exit + BiosculpterPod_Operating + 30000 + 150000 + 500 + 25 + 2 + 1 + 0.3 + 1.0 + true + true + 5 +
  • +
    + +
  • PlaceWorker_PreventInteractionSpotOverlap
  • +
    +
    + - WULA_Cube_Productor_BIO - - 一台仿制乌拉帝国科技而建造的塑性构造体,不仅要消耗大量木头用以提供生物能,还只能生产基础的衣物和能源核心用以维持生存——不过它很轻,可以随探险队一起移动。 + WULA_WeaponArmor_Productor + + 一台用于联络乌拉帝国母舰和后勤舰并下达武器、装备订单的特殊通讯台。这些武器装备的生产不需要殖民地参与,只需要使用乌拉帝国物资交换舱将材料发送给帝国舰队,然后根据材料数量下单即可。 WulaFallenEmpire.Building_GlobalWorkTable MapMeshAndRealTime Normal @@ -280,12 +822,6 @@
  • WULA_Base_Technology
  • - - -
  • Make_WULA_Charge_Cube
  • -
  • Recharge_WULA_Charge_Cube
  • -
  • Wula_Make_Zro
  • -
  • WulaFallenEmpire.ITab_GlobalBills
  • @@ -328,21 +864,14 @@ 20 - + -
  • WulaFallenEmpire.ITab_ResourceSubmitterContents
  • +
  • ITab_Storage
  • +
  • PlaceWorker_NotUnderRoof
  • diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Structure.xml b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Structure.xml index a6bfb0fa..39e31834 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Structure.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_Structure.xml @@ -1,64 +1,5 @@ - - WulaWall - - 乌拉帝国堡垒外壁,相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 - 1800 - Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon - - Wula/Building/Linked/WulaWall/WulaWall_Atlas - Graphic_Single - CutoutComplex - (0.5, 0.5, 0.5) - - Structure - -
  • WULA_Structure_Technology
  • -
    - - 2 - 1 - 10000 - 2500 - 0 - 0.22 - 0.1 - - 15 - - true - - -
  • Metallic
  • -
    - Heavy - - -
  • - Bomb - 0.01 -
  • -
  • - Thump - 0.1 -
  • -
    - -
  • - MeditationFocusStrength - -
  • Minimal
  • - - -
  • - CompPowerTransmitter - true -
  • -
    -
    WulaWall_Indoor @@ -66,92 +7,6 @@ 乌拉帝国非承重墙体,相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 - - WulaDoor - - 乌拉帝国堡垒的大门,不仅能够抵御大量爆炸和震荡伤害,还拥有无需通电即可运转的伺服系统来增加大门通过速度。 - Building_Door - Building - DoorMoveable - 1 - true - - Wula/Building/Door/WulaAutodoor_Mover - Graphic_Single - - - false - - - - 2 - 7500 - 0 - 3000 - 20 - 2 - - - 50 - 1 - - false - true - Normal - - - false - - Light - Structure - true - 1.0 - true - RealtimeOnly - -
  • - CompPowerTrader - 0 - true -
  • -
  • -
  • - true -
  • -
    - -
  • - Bomb - 0.01 -
  • -
  • - Thump - 0.01 -
  • -
    - - true - true - true - Door_OpenPowered - Door_ClosePowered - Door_OpenManual - Door_CloseManual - Blueprint_Door - - Wula/Building/Door/WulaAutodoor_BluePrint - - false - - 2505 - Wula/Building/Door/WulaAutodoor - Misc2 - 6 - -
  • WULA_Structure_Technology
  • -
    -
    WulaFloor diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml index 9a59d70c..afa37e74 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/Buildings_WULA.xml @@ -655,98 +655,4 @@
    - - - - WULA_MaintenancePod - - 一个为乌拉帝国合成人设计的全自动维护舱,机械乌拉需要定期进入其中进行身体机能的维护和校准,否则他们的身体会逐渐衰弱。维护需要消耗零部件,同时会修理所有的伤口。 - true - - Wula/Building/WULA_Synth_Maintainer_south - Graphic_Single - (3, 3) - - (1.5, 1.5, 1.7) - - - - RealtimeOnly - true - - Building - PassThroughOnly - 42 - true - 0.5 - false - false - - 250 - 20000 - 50 - 0.5 - -5 - - (3,3) - (0,0,-2) - true - -
  • WULA_Base_Technology
  • -
    - - 150 - 10 - - - 8 - - BuildingDestroyed_Metal_Big - 1800 - - WULA_Buildings - MinifiedThing - -
  • BuildingsMisc
  • -
    - Normal - -
  • - CompPowerTrader - 50 -
  • -
  • -
  • - 20.0 - - -
  • ComponentIndustrial
  • - - - 零部件 - true - true - true - -
  • - BiosculpterPod_Enter - BiosculpterPod_Exit - BiosculpterPod_Operating - 30000 - 150000 - 500 - 25 - 2 - 1 - 0.3 - 1.0 - true - true - 5 -
  • -
    - -
  • PlaceWorker_PreventInteractionSpotOverlap
  • -
    -
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml index 6c0a85e5..32fcde2f 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml @@ -30,6 +30,10 @@ 0 0 + + false + false + false true 1 50 diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml index 044846e3..5fa604b1 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml @@ -61,7 +61,7 @@ -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Stun_Technology @@ -117,7 +117,7 @@ -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Melee_Technology @@ -211,7 +211,7 @@ -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Stun_Technology @@ -315,8 +315,7 @@ Interact_Rifle -
  • WULA_Cube_Productor_BIO
  • -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_Technology UnfinishedWeapon @@ -444,8 +443,7 @@ Interact_ChargeRifle -
  • WULA_Cube_Productor_BIO
  • -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_Technology UnfinishedWeapon @@ -525,8 +523,7 @@ -
  • WULA_Cube_Productor_BIO
  • -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_Technology UnfinishedWeapon @@ -613,7 +610,7 @@ Interact_ChargeRifle -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_3_Bomb_Technology UnfinishedWeapon @@ -765,8 +762,7 @@ Interact_Rifle -
  • WULA_Cube_Productor_BIO
  • -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Laser_Technology UnfinishedWeapon @@ -886,7 +882,7 @@ -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Laser_Technology UnfinishedWeapon @@ -1089,7 +1085,7 @@ Interact_ChargeRifle -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Ranged_Technology UnfinishedWeapon @@ -1194,7 +1190,7 @@ None -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_3_Bomb_Technology UnfinishedWeapon @@ -1571,7 +1567,7 @@ Interact_Rifle -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_2_Missile_Technology UnfinishedWeapon @@ -1737,7 +1733,7 @@ 0.8 -
  • WULA_Cube_Productor_Energy
  • +
  • WULA_WeaponArmor_Productor
  • WULA_Synth_Weapon_3_Bomb_Technology UnfinishedWeapon diff --git a/1.6/1.6/Defs/WulaMiscSettingDefs/WulaHullDef.xml b/1.6/1.6/Defs/WulaMiscSettingDefs/WulaHullDef.xml index be10e44d..b27d6a2e 100644 --- a/1.6/1.6/Defs/WulaMiscSettingDefs/WulaHullDef.xml +++ b/1.6/1.6/Defs/WulaMiscSettingDefs/WulaHullDef.xml @@ -1,18 +1,13 @@ - - - + WulaWall - CutoutWithOverlay - Wula/Building/Linked/WulaWall/AngledWulaWall_northwest Wula/Building/Linked/WulaWall/AngledWulaWall_northeast Wula/Building/Linked/WulaWall/AngledWulaWall_southwest @@ -21,6 +16,5 @@ Wula/Building/Linked/WulaWall/AngledWulaWall_Partial_northeast Wula/Building/Linked/WulaWall/AngledWulaWall_Partial_southwest Wula/Building/Linked/WulaWall/AngledWulaWall_Partial_southeast - - + --> diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml index 3f1e4f1d..532ea9ca 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml @@ -145,8 +145,8 @@ 距上次维护 - 全球生产 - 生产订单 + 舰队生产 + 舰队生产订单 添加生产订单 恢复 暂停 @@ -154,7 +154,7 @@ 等待资源 完成 未知 - 全球存储中的资源不足 + 帝国舰队存储的资源不足 无可用配方 可用配方 @@ -172,18 +172,18 @@ 种输出物品 - 空投产品 - 将产物储存器中的所有物品通过空投舱分发到指定区域 + 空投成品 + 将乌拉帝国母舰和后勤舰上完成加工的所有物品通过空投舱投放到指定区域 无法执行空投:工作台未就绪 - 没有可空投的产品 + 没有可空投的物品 目标距离超出最大空投范围({0}) 没有有效的空投落点。请选择另一个位置 无法分配物品到空投舱 成功空投了{0}个空投舱 - 资源提交器 - 提交到储存器 - 将所有存储物品转移到全局储存 + 舰队资源储存 + 提交到舰队贮存 + 将所有存储物品转移到舰队贮存 存储物品 {0}个物品已提交到储存器 提交物品失败 @@ -219,16 +219,27 @@ 无物品 价值 -物品 -堆叠 -物品名称 -数量 -存储中无物品 -{0}\n总数: {1}\n堆叠: {2}\n价值: {3} -设备不可用 -没有可提交的物品 -查看全局存储 -查看全局存储中的物品 -未知原因 -价值 + 物品 + 堆叠 + 物品名称 + 数量 + 存储中无物品 + {0}\n总数: {1}\n堆叠: {2}\n价值: {3} + 设备不可用 + 没有可提交的物品 + 查看全局存储 + 查看全局存储中的物品 + 未知原因 + 价值 + + Load Resource Submitter + No items available + Available + To Load + Max + Set load count for {0} + Load All + Clear All + Loading jobs created + Description \ No newline at end of file diff --git a/Content/Textures/Wula/Building/WULA_Dropping_Building_Cleanzone.png b/Content/Textures/Wula/Building/WULA_Dropping_Building_Cleanzone.png index cfdd2ef4..e1f47394 100644 Binary files a/Content/Textures/Wula/Building/WULA_Dropping_Building_Cleanzone.png and b/Content/Textures/Wula/Building/WULA_Dropping_Building_Cleanzone.png differ diff --git a/Content/Textures/Wula/Building/WULA_MaintenancePod_Incoming.png b/Content/Textures/Wula/Building/WULA_MaintenancePod_Incoming.png new file mode 100644 index 00000000..11f3a440 Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_MaintenancePod_Incoming.png differ diff --git a/Content/Textures/Wula/Building/WULA_MaintenancePod_south.png b/Content/Textures/Wula/Building/WULA_MaintenancePod_south.png new file mode 100644 index 00000000..c8b4d4e0 Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_MaintenancePod_south.png differ diff --git a/Content/Textures/Wula/Building/WULA_Synth_Maintainer_south.png b/Content/Textures/Wula/Building/WULA_Synth_Maintainer_south.png deleted file mode 100644 index 44793376..00000000 Binary files a/Content/Textures/Wula/Building/WULA_Synth_Maintainer_south.png and /dev/null differ diff --git a/Content/Textures/Wula/UI/Commands/WULA_AirdropProducts.png b/Content/Textures/Wula/UI/Commands/WULA_AirdropProducts.png new file mode 100644 index 00000000..ff123698 Binary files /dev/null and b/Content/Textures/Wula/UI/Commands/WULA_AirdropProducts.png differ diff --git a/Content/Textures/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.png b/Content/Textures/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.png index 26ffb56c..11e14a9f 100644 Binary files a/Content/Textures/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.png and b/Content/Textures/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.png differ diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_InitialFaction/CompProperties_InitialFaction.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_InitialFaction/CompProperties_InitialFaction.cs new file mode 100644 index 00000000..84a62023 --- /dev/null +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_InitialFaction/CompProperties_InitialFaction.cs @@ -0,0 +1,78 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_FactionSetter : CompProperties + { + // 派系配置 + public FactionDef factionDef = null; // 指定的派系定义 + public bool usePlayerFactionIfNull = true; // 如果没有指定派系,是否使用玩家派系 + public bool overrideExistingFaction = true; // 是否覆盖已有的派系归属 + + public CompProperties_FactionSetter() + { + compClass = typeof(CompFactionSetter); + } + } + + public class CompFactionSetter : ThingComp + { + private bool factionSet = false; + + public CompProperties_FactionSetter Props => (CompProperties_FactionSetter)props; + + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + + if (!respawningAfterLoad && !factionSet) + { + SetFaction(); + factionSet = true; + } + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref factionSet, "factionSet", false); + } + + private void SetFaction() + { + // 如果不需要覆盖已有派系且建筑已有派系,则跳过 + if (!Props.overrideExistingFaction && parent.Faction != null) + return; + + Faction faction = GetTargetFaction(); + if (faction != null && faction != parent.Faction) + { + parent.SetFaction(faction); + Log.Message($"Set faction for {parent.Label} to {faction.Name}"); + } + } + + private Faction GetTargetFaction() + { + // 1. 如果指定了派系定义,使用该派系 + if (Props.factionDef != null) + { + Faction faction = Find.FactionManager.FirstFactionOfDef(Props.factionDef); + if (faction != null) + return faction; + } + + // 2. 默认使用玩家派系 + if (Props.usePlayerFactionIfNull) + return Faction.OfPlayer; + + return null; + } + + public override string CompInspectStringExtra() + { + return base.CompInspectStringExtra(); + } + } +} diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs index 67abc7fd..66a600e2 100644 --- a/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs @@ -44,29 +44,9 @@ namespace WulaFallenEmpire // 是否已经生成初始单位 private bool initialUnitsSpawned = false; - // 是否已经执行过归属权转换 - private bool ownershipTransferred = false; - public int StoredCount => storedMechanoids.Count; public int MaxStorage => Props.maxStorageCapacity; - // 强制归属权转换 - private void TransferOwnership() - { - if (ownershipTransferred) - return; - - // 获取目标派系(默认为玩家派系) - Faction targetFaction = Props.ownershipFaction ?? Faction.OfPlayer; - - if (Faction != targetFaction) - { - Log.Message($"[MechanoidRecycler] Transferring ownership from {Faction?.Name ?? "NULL"} to {targetFaction.Name}"); - SetFaction(targetFaction); - } - - ownershipTransferred = true; - } // 生成初始单位 private void SpawnInitialUnits() @@ -105,12 +85,6 @@ namespace WulaFallenEmpire { base.SpawnSetup(map, respawningAfterLoad); - // 执行归属权转换 - if (!respawningAfterLoad) - { - TransferOwnership(); - } - // 如果不是从存档加载,生成初始单位 if (!respawningAfterLoad) { @@ -400,7 +374,6 @@ namespace WulaFallenEmpire Scribe_Collections.Look(ref storedMechanoids, "storedMechanoids", LookMode.Reference); Scribe_Collections.Look(ref spawnQueue, "spawnQueue", LookMode.Deep); Scribe_Values.Look(ref initialUnitsSpawned, "initialUnitsSpawned", false); - Scribe_Values.Look(ref ownershipTransferred, "ownershipTransferred", false); if (Scribe.mode == LoadSaveMode.PostLoadInit) { diff --git a/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs b/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs index b093fadf..1efa5c6c 100644 --- a/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs +++ b/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs @@ -31,6 +31,11 @@ namespace WulaFallenEmpire public float fadeOutStartProgress = 0.7f; // 开始淡出的进度阈值(0-1) public float defaultFadeOutDuration = 1.5f; // 默认淡出持续时间(仅用于销毁) + // 新增:淡入淡出开关 + private bool useFadeEffects = true; + private bool useFadeIn = true; + private bool useFadeOut = true; + // 进场动画相关 - 新增 public float approachDuration = 1.0f; // 进场动画持续时间(秒) public float currentApproachTime = 0f; // 当前进场动画时间 @@ -183,32 +188,33 @@ namespace WulaFallenEmpire } } - // 淡入透明度(0-1) + // 修改后的淡入透明度属性 public float FadeInAlpha { get { - if (fadeInCompleted) return 1f; + if (!useFadeIn || fadeInCompleted) return 1f; return Mathf.Clamp01(currentFadeInTime / fadeInDuration); } } - // 淡出透明度(0-1) + // 修改后的淡出透明度属性 public float FadeOutAlpha { get { - if (!fadeOutStarted) return 1f; + if (!useFadeOut || !fadeOutStarted) return 1f; if (fadeOutCompleted) return 0f; return Mathf.Clamp01(1f - (currentFadeOutTime / fadeOutDuration)); } } - // 总体透明度(淡入 * 淡出) + // 修改后的总体透明度属性 public float OverallAlpha { get { + if (!useFadeEffects) return 1f; return FadeInAlpha * FadeOutAlpha; } } @@ -246,7 +252,6 @@ namespace WulaFallenEmpire { innerContainer = new ThingOwner(this); } - public override void ExposeData() { base.ExposeData(); @@ -262,7 +267,6 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref fadeInDuration, "fadeInDuration", 1.5f); Scribe_Values.Look(ref currentFadeInTime, "currentFadeInTime", 0f); Scribe_Values.Look(ref fadeInCompleted, "fadeInCompleted", false); - // 淡出效果数据保存 Scribe_Values.Look(ref fadeOutDuration, "fadeOutDuration", 0f); Scribe_Values.Look(ref currentFadeOutTime, "currentFadeOutTime", 0f); @@ -270,56 +274,60 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref fadeOutCompleted, "fadeOutCompleted", false); Scribe_Values.Look(ref fadeOutStartProgress, "fadeOutStartProgress", 0.7f); Scribe_Values.Look(ref defaultFadeOutDuration, "defaultFadeOutDuration", 1.5f); - - // 进场动画数据保存 - 新增 + // 进场动画数据保存 Scribe_Values.Look(ref approachDuration, "approachDuration", 1.0f); Scribe_Values.Look(ref currentApproachTime, "currentApproachTime", 0f); Scribe_Values.Look(ref approachCompleted, "approachCompleted", false); Scribe_Values.Look(ref approachOffsetDistance, "approachOffsetDistance", 3f); Scribe_Values.Look(ref useApproachAnimation, "useApproachAnimation", true); - + // 新增:淡入淡出开关保存 + Scribe_Values.Look(ref useFadeEffects, "useFadeEffects", true); + Scribe_Values.Look(ref useFadeIn, "useFadeIn", true); + Scribe_Values.Look(ref useFadeOut, "useFadeOut", true); Scribe_References.Look(ref caster, "caster"); Scribe_References.Look(ref faction, "faction"); } - public override void SpawnSetup(Map map, bool respawningAfterLoad) { base.SpawnSetup(map, respawningAfterLoad); - Log.Message($"FlyOver Spawned - Start: {startPosition}, End: {endPosition}, Speed: {flightSpeed}, Altitude: {altitude}"); if (!respawningAfterLoad) { Log.Message($"FlyOver Direction - Vector: {MovementDirection}, Rotation: {ExactRotation.eulerAngles}"); - // 设置初始位置 base.Position = startPosition; hasStarted = true; - - // 重置淡入状态 - currentFadeInTime = 0f; - fadeInCompleted = false; - - // 重置淡出状态 - currentFadeOutTime = 0f; - fadeOutStarted = false; - fadeOutCompleted = false; - fadeOutDuration = 0f; - - // 重置进场动画状态 - 新增 - currentApproachTime = 0f; - approachCompleted = false; - - // 从 ModExtension 加载进场动画配置 + // 从 ModExtension 加载配置 var extension = def.GetModExtension(); if (extension != null) { useApproachAnimation = extension.useApproachAnimation; approachDuration = extension.approachDuration; approachOffsetDistance = extension.approachOffsetDistance; + + // 加载淡入淡出配置 + useFadeEffects = extension.useFadeEffects; + useFadeIn = extension.useFadeIn; + useFadeOut = extension.useFadeOut; + + // 设置淡入淡出持续时间 + fadeInDuration = extension.defaultFadeInDuration; + defaultFadeOutDuration = extension.defaultFadeOutDuration; + fadeOutStartProgress = extension.fadeOutStartProgress; } - + // 重置淡入状态 + currentFadeInTime = 0f; + fadeInCompleted = !useFadeIn; // 如果不使用淡入,直接标记为完成 + // 重置淡出状态 + currentFadeOutTime = 0f; + fadeOutStarted = false; + fadeOutCompleted = false; + fadeOutDuration = 0f; + // 重置进场动画状态 + currentApproachTime = 0f; + approachCompleted = !useApproachAnimation; // 如果不使用进场动画,直接标记为完成 + Log.Message($"FlyOver fade effects: {useFadeEffects}, fadeIn: {useFadeIn}, fadeOut: {useFadeOut}"); Log.Message($"FlyOver approach animation: {useApproachAnimation}, duration: {approachDuration}s, offset: {approachOffsetDistance}"); - // 开始飞行音效 if (playFlyOverSound && def.skyfaller?.floatingSound != null) { @@ -329,15 +337,12 @@ namespace WulaFallenEmpire } } } - protected override void Tick() { base.Tick(); - if (!hasStarted || hasCompleted) return; - - // 更新进场动画 - 新增 + // 更新进场动画 if (useApproachAnimation && !approachCompleted) { currentApproachTime += 1f / 60f; @@ -348,9 +353,8 @@ namespace WulaFallenEmpire Log.Message("FlyOver approach animation completed"); } } - - // 更新淡入效果 - if (!fadeInCompleted) + // 更新淡入效果(仅在启用时) + if (useFadeIn && !fadeInCompleted) { currentFadeInTime += 1f / 60f; if (currentFadeInTime >= fadeInDuration) @@ -359,18 +363,15 @@ namespace WulaFallenEmpire currentFadeInTime = fadeInDuration; } } - // 更新飞行进度 currentProgress += flightSpeed * 0.001f; - - // 检查是否应该开始淡出(基于剩余距离动态计算) - if (!fadeOutStarted && currentProgress >= fadeOutStartProgress) + // 检查是否应该开始淡出(仅在启用时) + if (useFadeOut && !fadeOutStarted && currentProgress >= fadeOutStartProgress) { StartFadeOut(); } - - // 更新淡出效果 - if (fadeOutStarted && !fadeOutCompleted) + // 更新淡出效果(仅在启用时) + if (useFadeOut && fadeOutStarted && !fadeOutCompleted) { currentFadeOutTime += 1f / 60f; if (currentFadeOutTime >= fadeOutDuration) @@ -380,19 +381,15 @@ namespace WulaFallenEmpire Log.Message("FlyOver fade out completed"); } } - // 更新当前位置 UpdatePosition(); - // 维持飞行音效(在淡出时逐渐降低音量) UpdateFlightSound(); - // 检查是否到达终点 if (currentProgress >= 1f) { CompleteFlyOver(); } - // 生成飞行轨迹特效(在淡出时减少特效) CreateFlightEffects(); } @@ -419,11 +416,12 @@ namespace WulaFallenEmpire } } + // 修改后的音效更新方法 private void UpdateFlightSound() { if (flightSoundPlaying != null) { - if (fadeOutStarted) + if (useFadeOut && fadeOutStarted) { // 淡出时逐渐降低音效音量 flightSoundPlaying.externalParams["VolumeFactor"] = FadeOutAlpha; @@ -456,17 +454,16 @@ namespace WulaFallenEmpire Destroy(); } - // 新增:紧急销毁方法(使用默认淡出时间) + // 修改后的紧急销毁方法 public void EmergencyDestroy() { - if (!fadeOutStarted) + if (useFadeOut && !fadeOutStarted) { // 如果还没有开始淡出,使用默认淡出时间 fadeOutStarted = true; fadeOutDuration = defaultFadeOutDuration; Log.Message($"FlyOver emergency destroy with default fade out: {defaultFadeOutDuration}s"); } - // 设置标记,下一帧会处理淡出 hasCompleted = true; } @@ -483,6 +480,7 @@ namespace WulaFallenEmpire innerContainer.Clear(); } + // 修改后的特效生成方法 private void CreateFlightEffects() { // 在飞行轨迹上生成粒子效果 @@ -490,13 +488,11 @@ namespace WulaFallenEmpire { Vector3 effectPos = DrawPos; effectPos.y = AltitudeLayer.MoteOverhead.AltitudeFor(); - // 淡出时减少粒子效果强度 - float effectIntensity = fadeOutStarted ? FadeOutAlpha : 1f; + float effectIntensity = (useFadeOut && fadeOutStarted) ? FadeOutAlpha : 1f; FleckMaker.ThrowSmoke(effectPos, base.Map, 1f * effectIntensity); - // 可选:根据速度生成更多效果 - if (flightSpeed > 2f && !fadeOutStarted) + if (flightSpeed > 2f && !(useFadeOut && fadeOutStarted)) { FleckMaker.ThrowAirPuffUp(effectPos, base.Map); } @@ -628,11 +624,12 @@ namespace WulaFallenEmpire return innerContainer[0]; } - // 工具方法:创建飞越物体 + // 修改后的 MakeFlyOver 方法,添加淡入淡出参数 public static FlyOver MakeFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map, float speed = 1f, float height = 10f, ThingOwner contents = null, float fadeInDuration = 1.5f, float defaultFadeOutDuration = 1.5f, Pawn casterPawn = null, - bool useApproachAnimation = true, float approachDuration = 1.0f, float approachOffsetDistance = 3f) // 新增参数 + bool useApproachAnimation = true, float approachDuration = 1.0f, float approachOffsetDistance = 3f, + bool? useFadeEffects = null, bool? useFadeIn = null, bool? useFadeOut = null) // 新增参数 { FlyOver flyOver = (FlyOver)ThingMaker.MakeThing(flyOverDef); flyOver.startPosition = start; @@ -642,13 +639,16 @@ namespace WulaFallenEmpire flyOver.fadeInDuration = fadeInDuration; flyOver.defaultFadeOutDuration = defaultFadeOutDuration; flyOver.caster = casterPawn; - - // 进场动画参数 - 新增 + + // 进场动画参数 flyOver.useApproachAnimation = useApproachAnimation; flyOver.approachDuration = approachDuration; flyOver.approachOffsetDistance = approachOffsetDistance; - - // 简化派系设置 - 直接设置 faction 字段 + // 淡入淡出参数 - 新增 + if (useFadeEffects.HasValue) flyOver.useFadeEffects = useFadeEffects.Value; + if (useFadeIn.HasValue) flyOver.useFadeIn = useFadeIn.Value; + if (useFadeOut.HasValue) flyOver.useFadeOut = useFadeOut.Value; + // 简化派系设置 if (casterPawn != null && casterPawn.Faction != null) { flyOver.faction = casterPawn.Faction; @@ -658,20 +658,18 @@ namespace WulaFallenEmpire { Log.Warning($"FlyOver: Cannot set faction - casterPawn: {casterPawn?.Label ?? "NULL"}, casterFaction: {casterPawn?.Faction?.Name ?? "NULL"}"); } - if (contents != null) { flyOver.innerContainer.TryAddRangeOrTransfer(contents); } - GenSpawn.Spawn(flyOver, start, map); - - Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height}, Faction: {flyOver.faction?.Name ?? "NULL"}"); + Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height}, " + + $"FadeEffects: {flyOver.useFadeEffects}, FadeIn: {flyOver.useFadeIn}, FadeOut: {flyOver.useFadeOut}"); return flyOver; } } - // 扩展的 ModExtension 配置 - 新增进场动画参数 + // 扩展的 ModExtension 配置 - 新增进场动画参数和淡入淡出开关 public class FlyOverShadowExtension : DefModExtension { public string customShadowPath; @@ -684,17 +682,20 @@ namespace WulaFallenEmpire public float defaultFadeInDuration = 1.5f; public float defaultFadeOutDuration = 0.5f; public float fadeOutStartProgress = 0.98f; - + // 动态淡出配置 public float minFadeOutDuration = 0.5f; public float maxFadeOutDuration = 0.5f; public float fadeOutDistanceFactor = 0.01f; - - public float ActuallyHeight = 150f; - // 进场动画配置 - 新增 + public float ActuallyHeight = 150f; + // 进场动画配置 public bool useApproachAnimation = true; public float approachDuration = 1.0f; public float approachOffsetDistance = 3f; + // 新增:淡入淡出开关 + public bool useFadeEffects = true; // 是否启用淡入淡出效果 + public bool useFadeIn = true; // 是否启用淡入效果 + public bool useFadeOut = true; // 是否启用淡出效果 } } diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs b/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs index 69dd6b61..f8d29c56 100644 --- a/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs +++ b/Source/WulaFallenEmpire/GlobalWorkTable/Building_GlobalWorkTable.cs @@ -35,16 +35,17 @@ namespace WulaFallenEmpire breakdownableComp = GetComp(); } + // 在 Building_GlobalWorkTable 类中修改 Tick 方法 protected override void Tick() { base.Tick(); - - // 改为每tick处理,以实现精确的工作量控制 - if (Find.TickManager.TicksGame % ProcessInterval == 0 && + + // 修复:改为每60 ticks(1秒)处理一次,避免每tick处理导致的精度问题 + if (Find.TickManager.TicksGame % 60 == 0 && Find.TickManager.TicksGame != lastProcessTick) { lastProcessTick = Find.TickManager.TicksGame; - + if (CurrentlyUsableForGlobalBills()) { globalOrderStack.ProcessOrders(); @@ -84,7 +85,7 @@ namespace WulaFallenEmpire action = StartAirdropTargeting, defaultLabel = "WULA_AirdropProducts".Translate(), defaultDesc = "WULA_AirdropProductsDesc".Translate(), - icon = ContentFinder.Get("UI/Commands/Airdrop"), + icon = ContentFinder.Get("Wula/UI/Commands/WULA_AirdropProducts"), disabledReason = "WULA_CannotAirdrop".Translate() }; } diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/Building_ResourceSubmitter.cs b/Source/WulaFallenEmpire/GlobalWorkTable/Building_ResourceSubmitter.cs index c1c65721..34ee548b 100644 --- a/Source/WulaFallenEmpire/GlobalWorkTable/Building_ResourceSubmitter.cs +++ b/Source/WulaFallenEmpire/GlobalWorkTable/Building_ResourceSubmitter.cs @@ -3,14 +3,17 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; using Verse; +using System; +using System.Text; namespace WulaFallenEmpire { - public class Building_ResourceSubmitter : Building_Storage + public class Building_ResourceSubmitter : Building { - private CompPowerTrader powerComp; - private CompRefuelable refuelableComp; - private CompFlickable flickableComp; + public CompPowerTrader powerComp; + public CompRefuelable refuelableComp; + public CompFlickable flickableComp; + public CompResourceSubmitter submitterComp; public override void SpawnSetup(Map map, bool respawningAfterLoad) { @@ -18,11 +21,9 @@ namespace WulaFallenEmpire powerComp = GetComp(); refuelableComp = GetComp(); flickableComp = GetComp(); + submitterComp = GetComp(); } - /// - /// 检查建筑是否可用(电力、燃料、开关等) - /// public bool IsOperational { get @@ -37,309 +38,31 @@ namespace WulaFallenEmpire } } - /// - /// 获取建筑的中心位置(用于生成 Skyfaller) - /// - public IntVec3 CenterPosition + public string GetInoperativeReason() { - get - { - // 对于偶数尺寸的建筑,返回中心附近的单元格 - var center = Position + new IntVec3(def.Size.x / 2, 0, def.Size.z / 2); - // 确保在建筑范围内 - return center; - } + if (powerComp != null && !powerComp.PowerOn) + return "WULA_NoPower".Translate(); + if (refuelableComp != null && !refuelableComp.HasFuel) + return "WULA_NoFuel".Translate(); + if (flickableComp != null && !flickableComp.SwitchIsOn) + return "WULA_SwitchOff".Translate(); + return "WULA_UnknownReason".Translate(); } - public override IEnumerable GetGizmos() - { - foreach (Gizmo g in base.GetGizmos()) - { - yield return g; - } - - // 添加提交到资源储存器的命令 - yield return new Command_Action - { - action = SubmitContentsToStorage, - defaultLabel = "WULA_SubmitToStorage".Translate(), - defaultDesc = "WULA_SubmitToStorageDesc".Translate(), - icon = ContentFinder.Get("UI/Commands/Upload"), - disabledReason = GetDisabledReason() - }; - } - - /// - /// 获取存储的物品列表 - 修复版本 - /// - private List GetStoredItems() - { - var items = new List(); - - // 方法1:通过直接持有的物品获取(如果建筑本身是容器) - if (this is IThingHolder thingHolder) - { - ThingOwner directlyHeldThings = thingHolder.GetDirectlyHeldThings(); - if (directlyHeldThings != null) - { - items.AddRange(directlyHeldThings); - } - } - - // 方法2:通过存储设置获取地图上的物品 - if (items.Count == 0) - { - // 获取建筑的存储设置 - var storageSettings = GetStoreSettings(); - if (storageSettings != null) - { - // 查找地图上被此建筑接受的物品 - foreach (Thing thing in Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways)) - { - if (thing.Position.InHorDistOf(Position, 2f) && storageSettings.AllowedToAccept(thing)) - { - items.Add(thing); - } - } - } - } - - return items; - } - - /// - /// 获取禁用原因 - /// - private string GetDisabledReason() - { - if (!IsOperational) - { - if (powerComp != null && !powerComp.PowerOn) - return "WULA_NoPower".Translate(); - if (refuelableComp != null && !refuelableComp.HasFuel) - return "WULA_NoFuel".Translate(); - if (flickableComp != null && !flickableComp.SwitchIsOn) - return "WULA_SwitchOff".Translate(); - } - - if (GetStoredItems().Count == 0) - return "WULA_NoItemsToSubmit".Translate(); - - return string.Empty; - } - - /// - /// 提交内容到资源储存器 - /// - private void SubmitContentsToStorage() - { - if (!IsOperational) - { - Messages.Message("WULA_DeviceNotOperational".Translate(), MessageTypeDefOf.RejectInput); - return; - } - - var storedItems = GetStoredItems(); - if (storedItems.Count == 0) - { - Messages.Message("WULA_NoItemsToSubmit".Translate(), MessageTypeDefOf.RejectInput); - return; - } - - // 执行提交逻辑 - if (TrySubmitItems(storedItems)) - { - // 生成 Skyfaller 演出效果 - CreateSubmissionEffect(); - - Messages.Message("WULA_ItemsSubmitted".Translate(storedItems.Count), MessageTypeDefOf.PositiveEvent); - } - else - { - Messages.Message("WULA_SubmissionFailed".Translate(), MessageTypeDefOf.NegativeEvent); - } - } - - /// - /// 尝试提交物品到资源储存器 - /// - private bool TrySubmitItems(List items) - { - try - { - var globalStorage = Find.World.GetComponent(); - if (globalStorage == null) - { - Log.Error("GlobalStorageWorldComponent not found"); - return false; - } - - int submittedCount = 0; - var processedItems = new List(); - - foreach (Thing item in items) - { - if (item == null || item.Destroyed) - continue; - - // 检查是否为装备或武器 - if (IsEquipment(item.def)) - { - // 装备和武器直接添加到输出存储 - globalStorage.AddToOutputStorage(item.def, item.stackCount); - processedItems.Add(item); - submittedCount += item.stackCount; - } - else - { - // 其他物品添加到输入存储 - globalStorage.AddToInputStorage(item.def, item.stackCount); - processedItems.Add(item); - submittedCount += item.stackCount; - } - } - - // 从世界中移除已提交的物品 - foreach (Thing item in processedItems) - { - // 如果物品在建筑的直接容器中 - if (this is IThingHolder thingHolder) - { - ThingOwner directlyHeldThings = thingHolder.GetDirectlyHeldThings(); - if (directlyHeldThings != null && directlyHeldThings.Contains(item)) - { - directlyHeldThings.Remove(item); - } - } - - // 如果物品在地图上,直接销毁 - if (item.Spawned) - { - item.Destroy(); - } - } - - Log.Message($"Successfully submitted {submittedCount} items to global storage"); - return submittedCount > 0; - } - catch (System.Exception ex) - { - Log.Error($"Error submitting items to storage: {ex}"); - return false; - } - } - - /// - /// 检查是否为装备或武器 - /// - private bool IsEquipment(ThingDef thingDef) - { - return thingDef.IsApparel || thingDef.IsWeapon || thingDef.category == ThingCategory.Building; - } - - /// - /// 创建提交效果(Skyfaller) - /// - private void CreateSubmissionEffect() - { - try - { - // 获取 Skyfaller 定义 - ThingDef skyfallerDef = DefDatabase.GetNamedSilentFail("DropPodIncoming"); - if (skyfallerDef == null) - { - // 备用方案:使用简单的效果 - CreateFallbackEffect(); - return; - } - - // 创建空的 Skyfaller - Skyfaller skyfaller = (Skyfaller)ThingMaker.MakeThing(skyfallerDef); - - // 设置位置(建筑中心) - IntVec3 dropPos = CenterPosition; - - // 确保位置有效 - if (!dropPos.IsValid || !dropPos.InBounds(Map)) - { - dropPos = Position; // 回退到建筑位置 - } - - // 生成 Skyfaller - GenSpawn.Spawn(skyfaller, dropPos, Map); - - // 可选:添加一些视觉效果 - FleckMaker.ThrowLightningGlow(dropPos.ToVector3Shifted(), Map, 2f); - - Log.Message("Created submission skyfaller effect"); - } - catch (System.Exception ex) - { - Log.Error($"Error creating skyfaller effect: {ex}"); - CreateFallbackEffect(); - } - } - - /// - /// 备用效果(如果 Skyfaller 失败) - /// - private void CreateFallbackEffect() - { - try - { - IntVec3 center = CenterPosition; - - // 生成闪光效果 - for (int i = 0; i < 3; i++) - { - FleckMaker.ThrowLightningGlow(center.ToVector3Shifted(), Map, 1.5f); - } - - // 生成烟雾效果 - FleckMaker.ThrowSmoke(center.ToVector3Shifted(), Map, 2f); - - Log.Message("Created fallback submission effect"); - } - catch (System.Exception ex) - { - Log.Error($"Error creating fallback effect: {ex}"); - } - } - - /// - /// 修复的检查字符串方法 - 避免空行问题 - /// public override string GetInspectString() { StringBuilder stringBuilder = new StringBuilder(); - // 获取基础检查字符串 string baseString = base.GetInspectString(); if (!baseString.NullOrEmpty()) { stringBuilder.Append(baseString); } - // 获取存储信息 - var storedItems = GetStoredItems(); - int itemCount = storedItems.Count; - int totalStack = storedItems.Sum(item => item.stackCount); - - // 添加存储信息 - if (stringBuilder.Length > 0) - { - stringBuilder.AppendLine(); - } - stringBuilder.Append($"{"WULA_StoredItems".Translate()}: {itemCount} ({totalStack} {"WULA_Items".Translate()})"); - - // 添加状态信息(如果不工作) if (!IsOperational) { - if (stringBuilder.Length > 0) - { - stringBuilder.AppendLine(); - } - stringBuilder.Append($"{"WULA_Status".Translate()}: {"WULA_Inoperative".Translate()}"); + if (stringBuilder.Length > 0) stringBuilder.AppendLine(); + stringBuilder.Append($"{"WULA_Status".Translate()}: {"WULA_Inoperative".Translate()} - {GetInoperativeReason()}"); } return stringBuilder.ToString(); diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/Command_LoadToResourceSubmitter.cs b/Source/WulaFallenEmpire/GlobalWorkTable/Command_LoadToResourceSubmitter.cs new file mode 100644 index 00000000..d07f1cc7 --- /dev/null +++ b/Source/WulaFallenEmpire/GlobalWorkTable/Command_LoadToResourceSubmitter.cs @@ -0,0 +1,21 @@ +using RimWorld; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class Command_LoadToResourceSubmitter : Command + { + public CompResourceSubmitter submitterComp; + + public override void ProcessInput(Event ev) + { + base.ProcessInput(ev); + + if (submitterComp?.parent == null) return; + + // 打开装载界面,类似运输舱的界面 + Find.WindowStack.Add(new Dialog_LoadResourceSubmitter(submitterComp)); + } + } +} diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/CompResourceSubmitter.cs b/Source/WulaFallenEmpire/GlobalWorkTable/CompResourceSubmitter.cs new file mode 100644 index 00000000..d3e9460b --- /dev/null +++ b/Source/WulaFallenEmpire/GlobalWorkTable/CompResourceSubmitter.cs @@ -0,0 +1,391 @@ +using RimWorld; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Verse; +using System; +using System.Text; + +namespace WulaFallenEmpire +{ + public class CompResourceSubmitter : ThingComp, IThingHolder + { + public ThingOwner innerContainer; + public List leftToLoad; + + private bool massUsageDirty = true; + private float cachedMassUsage; + + public CompProperties_ResourceSubmitter Props => (CompProperties_ResourceSubmitter)props; + + public float MassUsage + { + get + { + if (massUsageDirty) + { + massUsageDirty = false; + cachedMassUsage = CollectionsMassCalculator.MassUsage(innerContainer, IgnorePawnsInventoryMode.IgnoreIfAssignedToUnload, includePawnsMass: false); + } + return cachedMassUsage; + } + } + + public bool OverMassCapacity => MassUsage > Props.massCapacity; + + public bool AnythingLeftToLoad => FirstThingLeftToLoad != null; + + public Thing FirstThingLeftToLoad + { + get + { + if (leftToLoad == null) return null; + for (int i = 0; i < leftToLoad.Count; i++) + { + if (leftToLoad[i].CountToTransfer != 0 && leftToLoad[i].HasAnyThing) + return leftToLoad[i].AnyThing; + } + return null; + } + } + + public CompResourceSubmitter() + { + innerContainer = new ThingOwner(this); + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Deep.Look(ref innerContainer, "innerContainer", this); + Scribe_Collections.Look(ref leftToLoad, "leftToLoad", LookMode.Deep); + + if (Scribe.mode == LoadSaveMode.Saving) + { + leftToLoad?.RemoveWhere(t => t == null); + } + } + + public ThingOwner GetDirectlyHeldThings() + { + return innerContainer; + } + + public void GetChildHolders(List outChildren) + { + ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings()); + } + + // 在 CompResourceSubmitter 类中添加或更新以下方法: + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + massUsageDirty = true; + } + + public override void PostDeSpawn(Map map, DestroyMode mode = DestroyMode.Vanish) + { + base.PostDeSpawn(map, mode); + if (mode != DestroyMode.WillReplace) + { + innerContainer.TryDropAll(parent.Position, map, ThingPlaceMode.Near); + } + } + + public override IEnumerable CompGetGizmosExtra() + { + foreach (Gizmo g in base.CompGetGizmosExtra()) + { + yield return g; + } + + // 装载命令 + Command_LoadToResourceSubmitter loadCommand = new Command_LoadToResourceSubmitter(); + loadCommand.defaultLabel = "WULA_LoadResourceSubmitter".Translate(); + loadCommand.defaultDesc = "WULA_LoadResourceSubmitterDesc".Translate(); + loadCommand.icon = ContentFinder.Get("UI/Commands/LoadTransporter"); + loadCommand.submitterComp = this; + + // 禁用检查 + if (!parent.Spawned) + { + loadCommand.Disable("WULA_NotSpawned".Translate()); + } + else if (!IsOperational()) + { + loadCommand.Disable(GetInoperativeReason()); + } + + yield return loadCommand; + + // 取消装载/卸载命令 + if (innerContainer.Any || AnythingLeftToLoad) + { + Command_Action cancelCommand = new Command_Action(); + cancelCommand.defaultLabel = innerContainer.Any ? "WULA_Unload".Translate() : "WULA_CancelLoad".Translate(); + cancelCommand.defaultDesc = innerContainer.Any ? "WULA_UnloadDesc".Translate() : "WULA_CancelLoadDesc".Translate(); + cancelCommand.icon = ContentFinder.Get("UI/Designators/Cancel"); + cancelCommand.action = CancelLoad; + yield return cancelCommand; + } + + // 发射命令 + Command_Action launchCommand = new Command_Action(); + launchCommand.defaultLabel = "WULA_LaunchSubmitter".Translate(); + launchCommand.defaultDesc = "WULA_LaunchSubmitterDesc".Translate(); + launchCommand.icon = ContentFinder.Get("UI/Commands/Launch"); + launchCommand.action = TryLaunch; + + // 发射条件检查 + if (!parent.Spawned) + { + launchCommand.Disable("WULA_NotSpawned".Translate()); + } + else if (!IsOperational()) + { + launchCommand.Disable(GetInoperativeReason()); + } + else if (!innerContainer.Any) + { + launchCommand.Disable("WULA_NoItemsToSubmit".Translate()); + } + else if (OverMassCapacity) + { + launchCommand.Disable("WULA_OverMassCapacity".Translate(MassUsage.ToString("F1"), Props.massCapacity.ToString("F1"))); + } + + yield return launchCommand; + } + + public override string CompInspectStringExtra() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("WULA_SubmitterContents".Translate() + ": " + innerContainer.ContentsString.CapitalizeFirst()); + + string massString = "WULA_Mass".Translate() + ": " + MassUsage.ToString("F1") + " / " + Props.massCapacity.ToString("F1") + " kg"; + stringBuilder.AppendLine().Append(OverMassCapacity ? massString.Colorize(ColorLibrary.RedReadable) : massString); + + if (!IsOperational()) + { + stringBuilder.AppendLine().Append("WULA_Status".Translate() + ": " + "WULA_Inoperative".Translate().Colorize(ColorLibrary.RedReadable)); + } + + return stringBuilder.ToString(); + } + + public void AddToTheToLoadList(TransferableOneWay t, int count) + { + if (!t.HasAnyThing || count <= 0) return; + + if (leftToLoad == null) + { + leftToLoad = new List(); + } + + TransferableOneWay existing = TransferableUtility.TransferableMatching(t.AnyThing, leftToLoad, TransferAsOneMode.PodsOrCaravanPacking); + if (existing != null) + { + for (int i = 0; i < t.things.Count; i++) + { + if (!existing.things.Contains(t.things[i])) + { + existing.things.Add(t.things[i]); + } + } + if (existing.CanAdjustBy(count).Accepted) + { + existing.AdjustBy(count); + } + } + else + { + TransferableOneWay newTransferable = new TransferableOneWay(); + leftToLoad.Add(newTransferable); + newTransferable.things.AddRange(t.things); + newTransferable.AdjustTo(count); + } + } + + public void Notify_ThingAdded(Thing t) + { + SubtractFromToLoadList(t, t.stackCount); + massUsageDirty = true; + } + + public void Notify_ThingRemoved(Thing t) + { + massUsageDirty = true; + } + + public void Notify_ThingAddedAndMergedWith(Thing t, int mergedCount) + { + SubtractFromToLoadList(t, mergedCount); + massUsageDirty = true; + } + + private int SubtractFromToLoadList(Thing t, int count) + { + if (leftToLoad == null) return 0; + + TransferableOneWay transferable = TransferableUtility.TransferableMatchingDesperate(t, leftToLoad, TransferAsOneMode.PodsOrCaravanPacking); + if (transferable == null || transferable.CountToTransfer <= 0) return 0; + + int num = Mathf.Min(count, transferable.CountToTransfer); + transferable.AdjustBy(-num); + + if (transferable.CountToTransfer <= 0) + { + leftToLoad.Remove(transferable); + } + + return num; + } + + private void CancelLoad() + { + if (leftToLoad != null) + { + leftToLoad.Clear(); + } + innerContainer.TryDropAll(parent.Position, parent.Map, ThingPlaceMode.Near); + massUsageDirty = true; + } + + private void TryLaunch() + { + if (!IsOperational()) + { + Messages.Message(GetInoperativeReason(), MessageTypeDefOf.RejectInput); + return; + } + + if (!innerContainer.Any) + { + Messages.Message("WULA_NoItemsToSubmit".Translate(), MessageTypeDefOf.RejectInput); + return; + } + + if (OverMassCapacity) + { + Messages.Message("WULA_OverMassCapacity".Translate(MassUsage.ToString("F1"), Props.massCapacity.ToString("F1")), MessageTypeDefOf.RejectInput); + return; + } + + if (SubmitContentsToStorage()) + { + CreateLaunchEffect(); + parent.Destroy(); + } + } + + private bool SubmitContentsToStorage() + { + try + { + var globalStorage = Find.World.GetComponent(); + if (globalStorage == null) + { + Log.Error("GlobalStorageWorldComponent not found"); + return false; + } + + int submittedCount = 0; + List processedItems = new List(); + + // 复制列表以避免修改时迭代 + List itemsToProcess = innerContainer.ToList(); + + foreach (Thing item in itemsToProcess) + { + if (item == null || item.Destroyed) continue; + + if (IsEquipment(item.def)) + { + globalStorage.AddToOutputStorage(item.def, item.stackCount); + } + else + { + globalStorage.AddToInputStorage(item.def, item.stackCount); + } + + processedItems.Add(item); + submittedCount += item.stackCount; + } + + // 从容器中移除已提交的物品 + foreach (Thing item in processedItems) + { + innerContainer.Remove(item); + } + + Messages.Message("WULA_ItemsSubmitted".Translate(submittedCount), MessageTypeDefOf.PositiveEvent); + Log.Message($"Successfully submitted {submittedCount} items to global storage"); + return submittedCount > 0; + } + catch (Exception ex) + { + Log.Error($"Error submitting items to storage: {ex}"); + Messages.Message("WULA_SubmissionFailed".Translate(), MessageTypeDefOf.NegativeEvent); + return false; + } + } + + private bool IsEquipment(ThingDef thingDef) + { + return thingDef.IsApparel || thingDef.IsWeapon || thingDef.category == ThingCategory.Building; + } + + private void CreateLaunchEffect() + { + try + { + // 使用自定义的 Skyfaller 定义 + ThingDef skyfallerDef = DefDatabase.GetNamedSilentFail("ResourceSubmitterSkyfaller"); + if (skyfallerDef == null) + { + // 备用:使用运输舱效果 + skyfallerDef = DefDatabase.GetNamedSilentFail("DropPodIncoming"); + } + + if (skyfallerDef != null) + { + Skyfaller skyfaller = (Skyfaller)ThingMaker.MakeThing(skyfallerDef); + GenSpawn.Spawn(skyfaller, parent.Position, parent.Map); + } + + // 视觉效果 + for (int i = 0; i < 3; i++) + { + FleckMaker.ThrowLightningGlow(parent.DrawPos, parent.Map, 2f); + } + FleckMaker.ThrowSmoke(parent.DrawPos, parent.Map, 3f); + } + catch (Exception ex) + { + Log.Error($"Error creating launch effect: {ex}"); + } + } + + private bool IsOperational() + { + var building = parent as Building_ResourceSubmitter; + return building?.IsOperational ?? false; + } + + private string GetInoperativeReason() + { + var building = parent as Building_ResourceSubmitter; + return building?.GetInoperativeReason() ?? "WULA_UnknownReason".Translate(); + } + } + + public class CompProperties_ResourceSubmitter : CompProperties + { + public float massCapacity = 150f; + + public CompProperties_ResourceSubmitter() + { + compClass = typeof(CompResourceSubmitter); + } + } +} diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/Dialog_LoadResourceSubmitter.cs b/Source/WulaFallenEmpire/GlobalWorkTable/Dialog_LoadResourceSubmitter.cs new file mode 100644 index 00000000..739074ea --- /dev/null +++ b/Source/WulaFallenEmpire/GlobalWorkTable/Dialog_LoadResourceSubmitter.cs @@ -0,0 +1,354 @@ +using RimWorld; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Verse; +using Verse.AI; + +namespace WulaFallenEmpire +{ + public class Dialog_LoadResourceSubmitter : Window + { + private CompResourceSubmitter submitterComp; + private Vector2 scrollPosition; + private float scrollViewHeight; + private List transferables; + + public override Vector2 InitialSize => new Vector2(800f, 600f); + + public Dialog_LoadResourceSubmitter(CompResourceSubmitter submitterComp) + { + this.submitterComp = submitterComp; + forcePause = true; + doCloseX = true; + doCloseButton = true; + absorbInputAroundWindow = true; + + transferables = new List(); + RefreshTransferables(); + } + + public override void DoWindowContents(Rect inRect) + { + Rect titleRect = new Rect(0f, 0f, inRect.width, 35f); + Text.Font = GameFont.Medium; + Widgets.Label(titleRect, "WULA_LoadResourceSubmitter".Translate()); + Text.Font = GameFont.Small; + + // 简化的物品列表 + Rect listRect = new Rect(0f, 40f, inRect.width, inRect.height - 100f); + DoSimpleTransferableList(listRect); + + // 按钮区域 + Rect buttonRect = new Rect(0f, inRect.height - 55f, inRect.width, 30f); + DoButtons(buttonRect); + + // 状态信息 + Rect statusRect = new Rect(0f, inRect.height - 25f, inRect.width, 25f); + DoStatusInfo(statusRect); + } + + private void DoSimpleTransferableList(Rect rect) + { + Widgets.DrawMenuSection(rect); + Rect outRect = rect.ContractedBy(10f); + Rect viewRect = new Rect(0f, 0f, outRect.width - 16f, scrollViewHeight); + + Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect); + + float curY = 0f; + + // 列标题 + Rect headerRect = new Rect(0f, curY, viewRect.width, 25f); + DoColumnHeaders(headerRect); + curY += 30f; + + if (transferables.Count == 0) + { + Rect emptyRect = new Rect(0f, curY, viewRect.width, 30f); + Text.Anchor = TextAnchor.MiddleCenter; + Widgets.Label(emptyRect, "WULA_NoItemsAvailable".Translate()); + Text.Anchor = TextAnchor.UpperLeft; + curY += 35f; + } + else + { + foreach (var transferable in transferables) + { + if (transferable.things.Count == 0) continue; + + Thing sampleThing = transferable.things[0]; + Rect rowRect = new Rect(0f, curY, viewRect.width, 30f); + + if (DoTransferableRow(rowRect, transferable, sampleThing)) + { + TooltipHandler.TipRegion(rowRect, GetThingTooltip(sampleThing, transferable.CountToTransfer)); + } + + curY += 35f; + } + } + + if (Event.current.type == EventType.Layout) + { + scrollViewHeight = curY; + } + + Widgets.EndScrollView(); + } + + private void DoColumnHeaders(Rect rect) + { + float columnWidth = rect.width / 4f; + + // 物品名称列 + Rect nameRect = new Rect(rect.x, rect.y, columnWidth * 2f, rect.height); + Text.Anchor = TextAnchor.MiddleLeft; + Widgets.Label(nameRect, "WULA_ItemName".Translate()); + + // 可用数量列 + Rect availableRect = new Rect(rect.x + columnWidth * 2f, rect.y, columnWidth, rect.height); + Text.Anchor = TextAnchor.MiddleCenter; + Widgets.Label(availableRect, "WULA_Available".Translate()); + + // 装载数量列 + Rect loadRect = new Rect(rect.x + columnWidth * 3f, rect.y, columnWidth, rect.height); + Widgets.Label(loadRect, "WULA_ToLoad".Translate()); + Text.Anchor = TextAnchor.UpperLeft; + + // 标题下划线 + Widgets.DrawLineHorizontal(rect.x, rect.yMax - 2f, rect.width); + } + + private bool DoTransferableRow(Rect rect, TransferableOneWay transferable, Thing sampleThing) + { + Widgets.DrawHighlightIfMouseover(rect); + + float columnWidth = rect.width / 4f; + + // 图标 + Rect iconRect = new Rect(rect.x + 2f, rect.y + 2f, 26f, 26f); + Widgets.ThingIcon(iconRect, sampleThing); + + // 名称 + Rect nameRect = new Rect(rect.x + 32f, rect.y, columnWidth * 2f - 32f, rect.height); + Text.Anchor = TextAnchor.MiddleLeft; + string label = sampleThing.LabelCap; + if (label.Length > 25) + { + label = label.Substring(0, 25) + "..."; + } + Widgets.Label(nameRect, label); + + // 可用数量 + int availableCount = transferable.things.Sum(t => t.stackCount); + Rect availableRect = new Rect(rect.x + columnWidth * 2f, rect.y, columnWidth, rect.height); + Text.Anchor = TextAnchor.MiddleCenter; + Widgets.Label(availableRect, availableCount.ToString()); + + // 装载数量调整 + Rect adjustRect = new Rect(rect.x + columnWidth * 3f, rect.y, columnWidth, rect.height); + DoCountAdjust(adjustRect, transferable, availableCount); + + Text.Anchor = TextAnchor.UpperLeft; + + return Mouse.IsOver(rect); + } + + private void DoCountAdjust(Rect rect, TransferableOneWay transferable, int availableCount) + { + int currentCount = transferable.CountToTransfer; + + Rect labelRect = new Rect(rect.x, rect.y, 40f, rect.height); + Rect minusRect = new Rect(rect.x + 45f, rect.y, 25f, rect.height); + Rect plusRect = new Rect(rect.x + 75f, rect.y, 25f, rect.height); + Rect maxRect = new Rect(rect.x + 105f, rect.y, 35f, rect.height); + + Text.Anchor = TextAnchor.MiddleCenter; + + // 当前数量 + Widgets.Label(labelRect, currentCount.ToString()); + + // 减少按钮 + if (Widgets.ButtonText(minusRect, "-") && currentCount > 0) + { + transferable.AdjustBy(-1); + } + + // 增加按钮 + if (Widgets.ButtonText(plusRect, "+") && currentCount < availableCount) + { + transferable.AdjustBy(1); + } + + // 最大按钮 + if (Widgets.ButtonText(maxRect, "WULA_Max".Translate()) && availableCount > 0) + { + Find.WindowStack.Add(new Dialog_Slider( + "WULA_SetLoadCount".Translate(transferable.AnyThing.LabelCap), + 0, availableCount, + value => transferable.AdjustTo(value), + currentCount + )); + } + + Text.Anchor = TextAnchor.UpperLeft; + } + + private void DoButtons(Rect rect) + { + float buttonWidth = rect.width / 2f - 5f; + + // 加载所有按钮 + Rect loadAllRect = new Rect(rect.x, rect.y, buttonWidth, rect.height); + if (Widgets.ButtonText(loadAllRect, "WULA_LoadAll".Translate())) + { + foreach (var transferable in transferables) + { + transferable.AdjustTo(transferable.things.Sum(t => t.stackCount)); + } + } + + // 清除所有按钮 + Rect clearAllRect = new Rect(rect.x + buttonWidth + 10f, rect.y, buttonWidth, rect.height); + if (Widgets.ButtonText(clearAllRect, "WULA_ClearAll".Translate())) + { + foreach (var transferable in transferables) + { + transferable.AdjustTo(0); + } + } + } + + private void DoStatusInfo(Rect rect) + { + Widgets.DrawMenuSection(rect); + Rect innerRect = rect.ContractedBy(5f); + + Text.Anchor = TextAnchor.MiddleLeft; + + // 计算总质量 + float totalMass = 0f; + foreach (var transferable in transferables) + { + if (transferable.CountToTransfer > 0) + { + float thingMass = transferable.AnyThing.GetStatValue(StatDefOf.Mass); + totalMass += thingMass * transferable.CountToTransfer; + } + } + + // 质量信息 + string massText = "WULA_Mass".Translate() + ": " + totalMass.ToString("F1") + " / " + submitterComp.Props.massCapacity.ToString("F1") + " kg"; + if (totalMass > submitterComp.Props.massCapacity) + { + massText = massText.Colorize(ColorLibrary.RedReadable); + } + + Widgets.Label(innerRect, massText); + Text.Anchor = TextAnchor.UpperLeft; + } + + private string GetThingTooltip(Thing thing, int count) + { + float mass = thing.GetStatValue(StatDefOf.Mass); + float value = thing.MarketValue * count; + return $"{thing.LabelCap}\n{"WULA_Mass".Translate()}: {mass:F2} kg\n{"WULA_Value".Translate()}: {value}\n{"WULA_Description".Translate()}: {thing.def.description}"; + } + + private void RefreshTransferables() + { + transferables.Clear(); + + // 获取地图上所有可搬运的物品 + foreach (Thing thing in submitterComp.parent.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways)) + { + if ((thing.IsInValidStorage() || thing.Spawned) && !thing.Position.Fogged(thing.Map)) + { + AddToTransferables(thing); + } + } + + // 按物品类型排序 + transferables.SortBy(t => t.AnyThing.def.label); + } + + private void AddToTransferables(Thing thing) + { + if (thing.def.category == ThingCategory.Item) + { + TransferableOneWay transferable = TransferableUtility.TransferableMatching(thing, transferables, TransferAsOneMode.PodsOrCaravanPacking); + if (transferable == null) + { + transferable = new TransferableOneWay(); + transferables.Add(transferable); + transferable.things.Add(thing); + } + else + { + transferable.things.Add(thing); + } + } + } + + public override void PostClose() + { + base.PostClose(); + + // 应用装载设置到提交器 + if (submitterComp != null) + { + submitterComp.leftToLoad?.Clear(); + + foreach (TransferableOneWay transferable in transferables) + { + if (transferable.CountToTransfer > 0) + { + submitterComp.AddToTheToLoadList(transferable, transferable.CountToTransfer); + } + } + + // 开始装载工作 + StartLoadingJobs(); + } + } + + private void StartLoadingJobs() + { + if (submitterComp?.parent?.Map == null) return; + + foreach (TransferableOneWay transferable in transferables) + { + if (transferable.CountToTransfer > 0) + { + foreach (Thing thing in transferable.things) + { + if (transferable.CountToTransfer <= 0) break; + + // 创建搬运到提交器的工作 + Job job = JobMaker.MakeJob(JobDefOf.HaulToContainer, thing, submitterComp.parent); + job.count = Mathf.Min(thing.stackCount, transferable.CountToTransfer); + job.haulMode = HaulMode.ToContainer; + + // 寻找殖民者执行工作 + Pawn pawn = FindBestPawnForJob(job); + if (pawn != null) + { + pawn.jobs.TryTakeOrderedJob(job); + transferable.AdjustBy(-job.count); + } + } + } + } + + Messages.Message("WULA_LoadingJobsCreated".Translate(), MessageTypeDefOf.PositiveEvent); + } + + private Pawn FindBestPawnForJob(Job job) + { + return submitterComp.parent.Map.mapPawns.FreeColonistsSpawned + .Where(p => p.workSettings.WorkIsActive(WorkTypeDefOf.Hauling)) + .FirstOrDefault(p => p.CanReserveAndReach(job.targetA, PathEndMode.ClosestTouch, Danger.Some)); + } + } +} diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs index 54af7293..20045e27 100644 --- a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs +++ b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrder.cs @@ -2,6 +2,7 @@ using RimWorld; using System.Collections.Generic; using System.Text; +using UnityEngine; using Verse; namespace WulaFallenEmpire @@ -12,7 +13,6 @@ namespace WulaFallenEmpire public int targetCount = 1; public int currentCount = 0; public bool paused = true; // 初始状态为暂停 - public float progress = 0f; // 生产状态 public ProductionState state = ProductionState.Waiting; @@ -24,18 +24,94 @@ namespace WulaFallenEmpire Completed // 完成 } + public string Label => recipe.LabelCap; + public string Description => $"{currentCount}/{targetCount} {recipe.products[0].thingDef.label}"; private float _progress = 0f; + public float progress + { + get => _progress; + set + { + // 确保进度在有效范围内 + _progress = Mathf.Clamp01(value); + + // 如果检测到异常值,记录警告 + if (value < 0f || value > 1f) + { + Log.Warning($"Progress clamped from {value} to {_progress} for {recipe?.defName ?? "unknown"}"); + } + } + } + public void ExposeData() { Scribe_Defs.Look(ref recipe, "recipe"); Scribe_Values.Look(ref targetCount, "targetCount", 1); Scribe_Values.Look(ref currentCount, "currentCount", 0); Scribe_Values.Look(ref paused, "paused", true); - Scribe_Values.Look(ref progress, "progress", 0f); + Scribe_Values.Look(ref _progress, "progress", 0f); // 序列化私有字段 Scribe_Values.Look(ref state, "state", ProductionState.Waiting); + + // 修复:加载后验证数据 + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + // 使用属性设置器来钳制值 + progress = _progress; + + // 确保状态正确 + UpdateState(); + } } - public string Label => recipe.LabelCap; - public string Description => $"{currentCount}/{targetCount} {recipe.products[0].thingDef.label}"; + // 修复:改进状态更新逻辑 + public void UpdateState() + { + if (state == ProductionState.Completed) + return; + + if (currentCount >= targetCount) + { + state = ProductionState.Completed; + progress = 0f; + return; + } + + if (HasEnoughResources()) + { + if (state == ProductionState.Waiting && !paused) + { + state = ProductionState.Producing; + progress = 0f; // 开始生产时重置进度 + } + } + else + { + if (state == ProductionState.Producing) + { + state = ProductionState.Waiting; + progress = 0f; // 资源不足时重置进度 + } + } + } + + // 修复:改进生产完成逻辑 + public void Produce() + { + var globalStorage = Find.World.GetComponent(); + if (globalStorage == null) + return; + foreach (var product in recipe.products) + { + globalStorage.AddToOutputStorage(product.thingDef, product.count); + } + + currentCount++; + progress = 0f; // 生产完成后重置进度 + + if (currentCount >= targetCount) + { + state = ProductionState.Completed; + } + } // 检查是否有足够资源 - 修复逻辑 public bool HasEnoughResources() @@ -103,68 +179,51 @@ namespace WulaFallenEmpire return true; } - - // 生产一个产品 - public void Produce() + // 修复:添加获取正确工作量的方法 + public float GetWorkAmount() { - var globalStorage = Find.World.GetComponent(); - if (globalStorage == null) return; + if (recipe == null) + return 1000f; - foreach (var product in recipe.products) - { - globalStorage.AddToOutputStorage(product.thingDef, product.count); - } - - currentCount++; - progress = 0f; - - if (currentCount >= targetCount) - { - state = ProductionState.Completed; - } - } + // 如果配方有明确的工作量且大于0,使用配方的工作量 + if (recipe.workAmount > 0) + return recipe.workAmount; - // 新增方法:检查并更新状态 - public void UpdateState() - { - if (state == ProductionState.Completed) return; - - if (HasEnoughResources()) + // 否则,使用第一个产品的WorkToMake属性 + if (recipe.products != null && recipe.products.Count > 0) { - if (state == ProductionState.Waiting && !paused) + ThingDef productDef = recipe.products[0].thingDef; + if (productDef != null) { - state = ProductionState.Producing; - } - } - else - { - if (state == ProductionState.Producing) - { - state = ProductionState.Waiting; - progress = 0f; // 重置进度 + // 获取产品的WorkToMake统计值 + float workToMake = productDef.GetStatValueAbstract(StatDefOf.WorkToMake); + if (workToMake > 0) + return workToMake; + + // 如果WorkToMake也是0或无效,使用产品的市场价值作为估算 + float marketValue = productDef.GetStatValueAbstract(StatDefOf.MarketValue); + if (marketValue > 0) + return marketValue * 10f; // 基于市场价值的估算 } } + + return 1000f; // 默认工作量 } - // 获取配方材料信息的字符串 + // 修复:在信息显示中使用正确的工作量 public string GetIngredientsInfo() { StringBuilder sb = new StringBuilder(); - // 添加标题 sb.AppendLine("WULA_RequiredIngredients".Translate() + ":"); - var globalStorage = Find.World.GetComponent(); - foreach (var ingredient in recipe.ingredients) { bool firstAllowedThing = true; - foreach (var thingDef in ingredient.filter.AllowedThingDefs) { int requiredCount = ingredient.CountRequiredOfFor(thingDef, recipe); int availableCount = globalStorage?.GetInputStorageCount(thingDef) ?? 0; - if (firstAllowedThing) { sb.Append(" - "); @@ -174,9 +233,7 @@ namespace WulaFallenEmpire { sb.Append(" / "); } - sb.Append($"{requiredCount} {thingDef.label}"); - // 添加可用数量信息 if (availableCount < requiredCount) { @@ -187,10 +244,8 @@ namespace WulaFallenEmpire sb.Append($" ({availableCount}/{requiredCount})"); } } - sb.AppendLine(); } - // 添加产品信息 sb.AppendLine(); sb.AppendLine("WULA_Products".Translate() + ":"); @@ -198,46 +253,37 @@ namespace WulaFallenEmpire { sb.AppendLine($" - {product.count} {product.thingDef.label}"); } - - // 添加工作量信息 + // 修复:使用正确的工作量信息 sb.AppendLine(); - sb.AppendLine("WULA_WorkAmount".Translate() + ": " + recipe.workAmount.ToStringWorkAmount()); - + sb.AppendLine("WULA_WorkAmount".Translate() + ": " + GetWorkAmount().ToStringWorkAmount()); return sb.ToString(); } - // 获取简化的材料信息(用于Tooltip) + + // 修复:在Tooltip中也使用正确的工作量 public string GetIngredientsTooltip() { StringBuilder sb = new StringBuilder(); - sb.AppendLine(recipe.LabelCap); sb.AppendLine(); - // 材料需求 sb.AppendLine("WULA_RequiredIngredients".Translate() + ":"); var globalStorage = Find.World.GetComponent(); - foreach (var ingredient in recipe.ingredients) { bool ingredientSatisfied = false; StringBuilder ingredientSB = new StringBuilder(); - foreach (var thingDef in ingredient.filter.AllowedThingDefs) { int requiredCount = ingredient.CountRequiredOfFor(thingDef, recipe); int availableCount = globalStorage?.GetInputStorageCount(thingDef) ?? 0; - if (ingredientSB.Length > 0) ingredientSB.Append(" / "); - ingredientSB.Append($"{requiredCount} {thingDef.label}"); - if (availableCount >= requiredCount) { ingredientSatisfied = true; } } - if (ingredientSatisfied) { sb.AppendLine($" {ingredientSB}"); @@ -247,7 +293,6 @@ namespace WulaFallenEmpire sb.AppendLine($" {ingredientSB}"); } } - // 产品 sb.AppendLine(); sb.AppendLine("WULA_Products".Translate() + ":"); @@ -255,7 +300,9 @@ namespace WulaFallenEmpire { sb.AppendLine($" {product.count} {product.thingDef.label}"); } - + // 修复:使用正确的工作量 + sb.AppendLine(); + sb.AppendLine("WULA_WorkAmount".Translate() + ": " + GetWorkAmount().ToStringWorkAmount()); return sb.ToString(); } } diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs index 1c7c82ec..f789f7f8 100644 --- a/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs +++ b/Source/WulaFallenEmpire/GlobalWorkTable/GlobalProductionOrderStack.cs @@ -1,7 +1,7 @@ -// GlobalProductionOrderStack.cs (调整为每秒1工作量) using RimWorld; using System.Collections.Generic; using Verse; +using UnityEngine; namespace WulaFallenEmpire { @@ -10,10 +10,10 @@ namespace WulaFallenEmpire public Building_GlobalWorkTable table; public List orders = new List(); - // 调整为每秒1工作量 - RimWorld中1秒=60ticks - private const float WorkPerSecond = 1f; + // 修复:明确的工作量定义 + private const float WorkPerSecond = 60f; // 每秒60工作量(标准RimWorld速度) private const float TicksPerSecond = 60f; - private const float WorkPerTick = WorkPerSecond / TicksPerSecond; + private const float WorkPerTick = WorkPerSecond / TicksPerSecond; // 每tick 1工作量 public GlobalProductionOrderStack(Building_GlobalWorkTable table) { @@ -24,6 +24,12 @@ namespace WulaFallenEmpire { Scribe_References.Look(ref table, "table"); Scribe_Collections.Look(ref orders, "orders", LookMode.Deep); + + // 修复:加载后验证和修复数据 + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + FixAllOrders(); + } } public void AddOrder(GlobalProductionOrder order) @@ -50,8 +56,11 @@ namespace WulaFallenEmpire public void ProcessOrders() { - foreach (var order in orders) + // 修复:使用倒序遍历避免修改集合问题 + for (int i = orders.Count - 1; i >= 0; i--) { + var order = orders[i]; + // 首先更新状态 order.UpdateState(); @@ -61,49 +70,176 @@ namespace WulaFallenEmpire // 生产中 if (order.state == GlobalProductionOrder.ProductionState.Producing) { - // 计算每tick的工作量进度 - float workAmount = order.recipe.workAmount; - float progressIncrement = WorkPerTick / workAmount; - - order.progress += progressIncrement; - - // 调试信息 - 减少频率以免太吵 - if (Find.TickManager.TicksGame % 600 == 0) // 每10秒输出一次调试信息 - { - Log.Message($"[DEBUG] Order {order.recipe.defName} progress: {order.progress:P0}, " + - $"workAmount: {workAmount}, increment: {progressIncrement:F6}"); - } - - if (order.progress >= 1f) - { - // 生产完成,消耗资源 - if (order.ConsumeResources()) - { - order.Produce(); - order.UpdateState(); - - Log.Message($"[SUCCESS] Produced {order.recipe.products[0].thingDef.defName}, " + - $"count: {order.currentCount}/{order.targetCount}, " + - $"workAmount: {workAmount}"); - } - else - { - order.state = GlobalProductionOrder.ProductionState.Waiting; - order.progress = 0f; - Log.Message($"[WARNING] Failed to consume resources for {order.recipe.defName}"); - } - } + ProcessProducingOrder(order, i); } else if (order.state == GlobalProductionOrder.ProductionState.Waiting && !order.paused) { - // 调试:检查为什么订单在等待状态 - if (Find.TickManager.TicksGame % 1200 == 0) // 每20秒检查一次 - { - Log.Message($"[DEBUG] Order {order.recipe.defName} is waiting. " + - $"HasEnoughResources: {order.HasEnoughResources()}, paused: {order.paused}"); - } + ProcessWaitingOrder(order); } } } + + private void ProcessProducingOrder(GlobalProductionOrder order, int index) + { + // 修复:使用正确的方法获取工作量 + float workAmount = GetWorkAmountForOrder(order); + + // 防止除零错误 + if (workAmount <= 0) + { + Log.Error($"Invalid workAmount ({workAmount}) for recipe {order.recipe.defName}"); + order.state = GlobalProductionOrder.ProductionState.Waiting; + order.progress = 0f; + return; + } + + // 修复:正确计算进度增量 + float progressIncrement = WorkPerTick / workAmount; + + // 修复:确保进度不会变成负数 + float newProgress = Mathf.Max(0f, order.progress + progressIncrement); + order.progress = newProgress; + + // 调试信息 + if (Find.TickManager.TicksGame % 300 == 0) // 每5秒输出一次 + { + Log.Message($"[DEBUG] Order {order.recipe.defName}: " + + $"progress={order.progress:P2}, " + + $"workAmount={workAmount}, " + + $"increment={progressIncrement:E4}, " + + $"state={order.state}"); + } + + // 修复:使用精确比较完成条件 + if (order.progress >= 1.0f) + { + CompleteProduction(order, index); + } + } + + // 修复:新增方法 - 正确获取订单的工作量 + private float GetWorkAmountForOrder(GlobalProductionOrder order) + { + if (order?.recipe == null) + return 1000f; // 默认值 + + // 如果配方有明确的工作量且大于0,使用配方的工作量 + if (order.recipe.workAmount > 0) + return order.recipe.workAmount; + + // 否则,使用第一个产品的WorkToMake属性 + if (order.recipe.products != null && order.recipe.products.Count > 0) + { + ThingDef productDef = order.recipe.products[0].thingDef; + if (productDef != null) + { + // 获取产品的WorkToMake统计值 + float workToMake = productDef.GetStatValueAbstract(StatDefOf.WorkToMake); + if (workToMake > 0) + return workToMake; + + // 如果WorkToMake也是0或无效,使用产品的市场价值作为估算 + float marketValue = productDef.GetStatValueAbstract(StatDefOf.MarketValue); + if (marketValue > 0) + return marketValue * 10f; // 基于市场价值的估算 + } + } + + // 最后的回退方案 + Log.Warning($"Could not determine work amount for recipe {order.recipe.defName}, using default value"); + return 1000f; // 默认工作量 + } + + private void ProcessWaitingOrder(GlobalProductionOrder order) + { + // 检查是否应该开始生产 + if (order.HasEnoughResources()) + { + order.state = GlobalProductionOrder.ProductionState.Producing; + order.progress = 0f; + + if (Find.TickManager.TicksGame % 600 == 0) // 每10秒记录一次 + { + Log.Message($"[INFO] Order {order.recipe.defName} started producing"); + } + } + else if (Find.TickManager.TicksGame % 1200 == 0) // 每20秒检查一次 + { + Log.Message($"[DEBUG] Order {order.recipe.defName} is waiting. " + + $"HasEnoughResources: {order.HasEnoughResources()}"); + } + } + + private void CompleteProduction(GlobalProductionOrder order, int index) + { + // 修复:生产完成,消耗资源 + if (order.ConsumeResources()) + { + order.Produce(); + order.UpdateState(); + + Log.Message($"[SUCCESS] Produced {order.recipe.products[0].thingDef.defName}, " + + $"count: {order.currentCount}/{order.targetCount}"); + + // 重置进度 + order.progress = 0f; + + // 如果订单完成,移除它 + if (order.state == GlobalProductionOrder.ProductionState.Completed) + { + orders.RemoveAt(index); + Log.Message($"[COMPLETE] Order {order.recipe.defName} completed and removed"); + } + } + else + { + // 修复:资源不足,回到等待状态 + order.state = GlobalProductionOrder.ProductionState.Waiting; + order.progress = 0f; + Log.Message($"[WARNING] Failed to consume resources for {order.recipe.defName}, resetting"); + } + } + + // 修复:全面数据修复方法 + private void FixAllOrders() + { + for (int i = orders.Count - 1; i >= 0; i--) + { + var order = orders[i]; + + // 修复进度值 + if (float.IsNaN(order.progress) || float.IsInfinity(order.progress)) + { + order.progress = 0f; + Log.Warning($"Fixed invalid progress for {order.recipe?.defName ?? "unknown"}"); + } + else if (order.progress < 0f) + { + order.progress = 0f; + Log.Warning($"Fixed negative progress for {order.recipe?.defName ?? "unknown"}"); + } + else if (order.progress > 1f) + { + order.progress = 1f; + Log.Warning($"Fixed excessive progress for {order.recipe?.defName ?? "unknown"}"); + } + + // 修复状态 + if (order.recipe == null) + { + Log.Warning($"Removing order with null recipe"); + orders.RemoveAt(i); + continue; + } + + // 强制更新状态 + order.UpdateState(); + } + } + + public void FixNegativeProgress() + { + FixAllOrders(); + } } } diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs b/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs index 3b3e732f..e5363d58 100644 --- a/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs +++ b/Source/WulaFallenEmpire/GlobalWorkTable/ITab_GlobalBills.cs @@ -310,7 +310,7 @@ namespace WulaFallenEmpire // 如果暂停,在状态前添加暂停标识 if (order.paused && order.state != GlobalProductionOrder.ProductionState.Completed) { - statusText = $"[Paused] {statusText}"; + statusText = $"[||] {statusText}"; } Widgets.Label(statusRect, statusText); diff --git a/Source/WulaFallenEmpire/GlobalWorkTable/ITab_ResourceSubmitterContents.cs b/Source/WulaFallenEmpire/GlobalWorkTable/ITab_ResourceSubmitterContents.cs deleted file mode 100644 index 6ec4ad58..00000000 --- a/Source/WulaFallenEmpire/GlobalWorkTable/ITab_ResourceSubmitterContents.cs +++ /dev/null @@ -1,409 +0,0 @@ -using RimWorld; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using Verse; - -namespace WulaFallenEmpire -{ - public class ITab_ResourceSubmitterContents : ITab - { - private Vector2 scrollPosition; - private float scrollViewHeight; - - private static readonly Vector2 WinSize = new Vector2(420f, 480f); - - protected Building_ResourceSubmitter SelSubmitter => (Building_ResourceSubmitter)base.SelThing; - - public ITab_ResourceSubmitterContents() - { - size = WinSize; - labelKey = "WULA_SubmitterContents"; - tutorTag = "SubmitterContents"; - } - - protected override void FillTab() - { - Rect mainRect = new Rect(0f, 0f, WinSize.x, WinSize.y).ContractedBy(10f); - - // 标题区域 - Text.Font = GameFont.Medium; - Widgets.Label(new Rect(mainRect.x, mainRect.y, mainRect.width, 30f), "WULA_SubmitterContents".Translate()); - Text.Font = GameFont.Small; - - // 状态信息 - Rect statusRect = new Rect(mainRect.x, mainRect.y + 35f, mainRect.width, 40f); - DoStatusInfo(statusRect); - - // 存储物品列表 - Rect itemsRect = new Rect(mainRect.x, mainRect.y + 80f, mainRect.width, mainRect.height - 120f); - DoItemsListing(itemsRect); - - // 操作按钮区域 - Rect buttonsRect = new Rect(mainRect.x, mainRect.yMax - 35f, mainRect.width, 30f); - DoActionButtons(buttonsRect); - } - - private void DoStatusInfo(Rect rect) - { - Widgets.DrawMenuSection(rect); - Rect innerRect = rect.ContractedBy(5f); - - // 运行状态 - string statusText = SelSubmitter.IsOperational ? - "WULA_Operational".Translate() : "WULA_Inoperative".Translate(); - Color statusColor = SelSubmitter.IsOperational ? Color.green : Color.red; - - Text.Anchor = TextAnchor.MiddleLeft; - Rect statusLabelRect = new Rect(innerRect.x, innerRect.y, innerRect.width * 0.6f, innerRect.height); - Widgets.Label(statusLabelRect, "WULA_Status".Translate() + ": " + statusText); - - // 物品数量 - var storedItems = SelSubmitter.GetStoredItems(); - int totalItems = storedItems.Count; - int totalStacks = storedItems.Sum(item => item.stackCount); - - Rect countRect = new Rect(innerRect.x + innerRect.width * 0.6f, innerRect.y, innerRect.width * 0.4f, innerRect.height); - Widgets.Label(countRect, $"{totalItems} {"WULA_Items".Translate()} ({totalStacks} {"WULA_Stacks".Translate()})"); - Text.Anchor = TextAnchor.UpperLeft; - - // 状态颜色指示 - GUI.color = statusColor; - Widgets.DrawBox(new Rect(statusLabelRect.x - 15f, statusLabelRect.y + 7f, 10f, 10f), 1); - GUI.color = Color.white; - } - - private void DoItemsListing(Rect rect) - { - Widgets.DrawMenuSection(rect); - Rect outRect = rect.ContractedBy(5f); - Rect viewRect = new Rect(0f, 0f, outRect.width - 16f, scrollViewHeight); - - var storedItems = SelSubmitter.GetStoredItems(); - - Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect); - - float curY = 0f; - - // 列标题 - Rect headerRect = new Rect(0f, curY, viewRect.width, 25f); - DoColumnHeaders(headerRect); - curY += 30f; - - if (storedItems.Count == 0) - { - Rect emptyRect = new Rect(0f, curY, viewRect.width, 30f); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label(emptyRect, "WULA_NoItemsInStorage".Translate()); - Text.Anchor = TextAnchor.UpperLeft; - curY += 35f; - } - else - { - // 按物品类型分组显示 - var groupedItems = storedItems - .GroupBy(item => item.def) - .OrderByDescending(g => g.Sum(item => item.stackCount)) - .ThenBy(g => g.Key.label); - - foreach (var group in groupedItems) - { - ThingDef thingDef = group.Key; - int totalCount = group.Sum(item => item.stackCount); - int stackCount = group.Count(); - - Rect itemRect = new Rect(0f, curY, viewRect.width, 28f); - if (DoItemRow(itemRect, thingDef, totalCount, stackCount)) - { - // 鼠标悬停时显示详细信息 - string tooltip = GetItemTooltip(thingDef, totalCount, stackCount); - TooltipHandler.TipRegion(itemRect, tooltip); - } - - curY += 32f; - - // 分隔线 - if (curY < viewRect.height - 5f) - { - Widgets.DrawLineHorizontal(0f, curY - 2f, viewRect.width); - curY += 5f; - } - } - } - - if (Event.current.type == EventType.Layout) - { - scrollViewHeight = curY; - } - - Widgets.EndScrollView(); - } - - private void DoColumnHeaders(Rect rect) - { - float columnWidth = rect.width / 4f; - - // 物品名称列 - Rect nameRect = new Rect(rect.x, rect.y, columnWidth * 2f, rect.height); - Text.Anchor = TextAnchor.MiddleLeft; - Widgets.Label(nameRect, "WULA_ItemName".Translate()); - - // 数量列 - Rect countRect = new Rect(rect.x + columnWidth * 2f, rect.y, columnWidth, rect.height); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label(countRect, "WULA_Count".Translate()); - - // 堆叠列 - Rect stacksRect = new Rect(rect.x + columnWidth * 3f, rect.y, columnWidth, rect.height); - Widgets.Label(stacksRect, "WULA_Stacks".Translate()); - Text.Anchor = TextAnchor.UpperLeft; - - // 标题下划线 - Widgets.DrawLineHorizontal(rect.x, rect.yMax - 2f, rect.width); - } - - private bool DoItemRow(Rect rect, ThingDef thingDef, int totalCount, int stackCount) - { - Widgets.DrawHighlightIfMouseover(rect); - - float columnWidth = rect.width / 4f; - - // 物品图标 - Rect iconRect = new Rect(rect.x + 2f, rect.y + 2f, 24f, 24f); - Widgets.ThingIcon(iconRect, thingDef); - - // 物品名称 - Rect nameRect = new Rect(rect.x + 30f, rect.y, columnWidth * 2f - 30f, rect.height); - Text.Anchor = TextAnchor.MiddleLeft; - string label = thingDef.LabelCap; - if (label.Length > 25) - { - label = label.Substring(0, 25) + "..."; - } - Widgets.Label(nameRect, label); - - // 总数量 - Rect countRect = new Rect(rect.x + columnWidth * 2f, rect.y, columnWidth, rect.height); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label(countRect, totalCount.ToString()); - - // 堆叠数量 - Rect stacksRect = new Rect(rect.x + columnWidth * 3f, rect.y, columnWidth, rect.height); - Widgets.Label(stacksRect, stackCount.ToString()); - Text.Anchor = TextAnchor.UpperLeft; - - return Mouse.IsOver(rect); - } - - private string GetItemTooltip(ThingDef thingDef, int totalCount, int stackCount) - { - return string.Format("WULA_ItemTooltip".Translate(), - thingDef.LabelCap, - totalCount, - stackCount, - thingDef.BaseMarketValue * totalCount); - } - - private void DoActionButtons(Rect rect) - { - float buttonWidth = rect.width / 2f - 5f; - - // 提交按钮 - Rect submitRect = new Rect(rect.x, rect.y, buttonWidth, rect.height); - bool hasItems = SelSubmitter.GetStoredItems().Count > 0; - bool isOperational = SelSubmitter.IsOperational; - - string submitLabel = "WULA_SubmitToStorage".Translate(); - string submitDesc = "WULA_SubmitToStorageDesc".Translate(); - - if (!isOperational) - { - submitLabel = "WULA_DeviceInoperative".Translate(); - submitDesc = GetInoperativeReason(); - } - else if (!hasItems) - { - submitLabel = "WULA_NoItemsToSubmit".Translate(); - submitDesc = "WULA_NoItemsToSubmitDesc".Translate(); - } - - if (Widgets.ButtonText(submitRect, submitLabel)) - { - if (isOperational && hasItems) - { - SelSubmitter.SubmitContentsToStorage(); - } - else if (!isOperational) - { - Messages.Message(GetInoperativeReason(), MessageTypeDefOf.RejectInput); - } - else - { - Messages.Message("WULA_NoItemsToSubmit".Translate(), MessageTypeDefOf.RejectInput); - } - } - - // 工具提示 - if (Mouse.IsOver(submitRect)) - { - TooltipHandler.TipRegion(submitRect, submitDesc); - } - - // 查看全局存储按钮 - Rect storageRect = new Rect(rect.x + buttonWidth + 10f, rect.y, buttonWidth, rect.height); - if (Widgets.ButtonText(storageRect, "WULA_ViewGlobalStorage".Translate())) - { - Find.WindowStack.Add(new Dialog_GlobalStorage()); - } - - if (Mouse.IsOver(storageRect)) - { - TooltipHandler.TipRegion(storageRect, "WULA_ViewGlobalStorageDesc".Translate()); - } - } - - private string GetInoperativeReason() - { - var submitter = SelSubmitter; - - if (submitter.powerComp != null && !submitter.powerComp.PowerOn) - return "WULA_NoPower".Translate(); - - if (submitter.refuelableComp != null && !submitter.refuelableComp.HasFuel) - return "WULA_NoFuel".Translate(); - - if (submitter.flickableComp != null && !submitter.flickableComp.SwitchIsOn) - return "WULA_SwitchOff".Translate(); - - return "WULA_UnknownReason".Translate(); - } - - public override void TabUpdate() - { - base.TabUpdate(); - } - } - - // 简单的全局存储查看对话框 - public class Dialog_GlobalStorage : Window - { - private Vector2 scrollPosition; - private float scrollViewHeight; - - public override Vector2 InitialSize => new Vector2(500f, 600f); - - public Dialog_GlobalStorage() - { - forcePause = false; - doCloseX = true; - doCloseButton = true; - closeOnClickedOutside = true; - absorbInputAroundWindow = true; - } - - public override void DoWindowContents(Rect inRect) - { - var globalStorage = Find.World.GetComponent(); - if (globalStorage == null) - { - Widgets.Label(inRect, "WULA_NoGlobalStorage".Translate()); - return; - } - - Rect titleRect = new Rect(0f, 0f, inRect.width, 30f); - Text.Font = GameFont.Medium; - Widgets.Label(titleRect, "WULA_GlobalStorage".Translate()); - Text.Font = GameFont.Small; - - // 输入存储 - Rect inputRect = new Rect(0f, 40f, inRect.width, (inRect.height - 100f) / 2f); - DoStorageSection(inputRect, globalStorage.inputStorage, "WULA_InputStorage".Translate()); - - // 输出存储 - Rect outputRect = new Rect(0f, 40f + (inRect.height - 100f) / 2f + 10f, inRect.width, (inRect.height - 100f) / 2f); - DoStorageSection(outputRect, globalStorage.outputStorage, "WULA_OutputStorage".Translate()); - } - - private void DoStorageSection(Rect rect, Dictionary storage, string label) - { - Widgets.DrawMenuSection(rect); - Rect innerRect = rect.ContractedBy(5f); - - // 标题 - Text.Font = GameFont.Medium; - Widgets.Label(new Rect(innerRect.x, innerRect.y, innerRect.width, 25f), label); - Text.Font = GameFont.Small; - - Rect listRect = new Rect(innerRect.x, innerRect.y + 30f, innerRect.width, innerRect.height - 35f); - DoStorageList(listRect, storage); - } - - private void DoStorageList(Rect rect, Dictionary storage) - { - Rect outRect = rect; - Rect viewRect = new Rect(0f, 0f, rect.width - 16f, scrollViewHeight); - - var items = storage - .Where(kvp => kvp.Value > 0) - .OrderByDescending(kvp => kvp.Value) - .ThenBy(kvp => kvp.Key.label) - .ToList(); - - Widgets.BeginScrollView(outRect, ref scrollPosition, viewRect); - - float curY = 0f; - - if (items.Count == 0) - { - Rect emptyRect = new Rect(0f, curY, viewRect.width, 30f); - Text.Anchor = TextAnchor.MiddleCenter; - Widgets.Label(emptyRect, "WULA_NoItems".Translate()); - Text.Anchor = TextAnchor.UpperLeft; - curY += 35f; - } - else - { - foreach (var kvp in items) - { - Rect itemRect = new Rect(0f, curY, viewRect.width, 25f); - DoStorageItemRow(itemRect, kvp.Key, kvp.Value); - curY += 28f; - } - } - - if (Event.current.type == EventType.Layout) - { - scrollViewHeight = curY; - } - - Widgets.EndScrollView(); - } - - private void DoStorageItemRow(Rect rect, ThingDef thingDef, int count) - { - Widgets.DrawHighlightIfMouseover(rect); - - // 图标 - Rect iconRect = new Rect(rect.x + 2f, rect.y + 2f, 20f, 20f); - Widgets.ThingIcon(iconRect, thingDef); - - // 名称 - Rect nameRect = new Rect(rect.x + 25f, rect.y, rect.width - 80f, rect.height); - Text.Anchor = TextAnchor.MiddleLeft; - Widgets.Label(nameRect, thingDef.LabelCap); - - // 数量 - Rect countRect = new Rect(rect.xMax - 50f, rect.y, 50f, rect.height); - Text.Anchor = TextAnchor.MiddleRight; - Widgets.Label(countRect, count.ToString()); - Text.Anchor = TextAnchor.UpperLeft; - - // 工具提示 - if (Mouse.IsOver(rect)) - { - string tooltip = $"{thingDef.LabelCap}\n{count} {"WULA_Items".Translate()}\n{"WULA_Value".Translate()}: {thingDef.BaseMarketValue * count}"; - TooltipHandler.TipRegion(rect, tooltip); - } - } - } -} diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs index 6f7cb1a7..196c465d 100644 --- a/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs +++ b/Source/WulaFallenEmpire/Pawn/WULA_Maintenance/Need_Maintenance.cs @@ -150,12 +150,6 @@ namespace WulaFallenEmpire // 立即检查状态变化 CheckStatusChanges(); - - if (pawn.IsColonistPlayerControlled && reduction > 0.01f) - { - Messages.Message("WULA_MaintenanceReducedDueToDamage".Translate(pawn.LabelShort, reduction.ToStringPercent()), - pawn, MessageTypeDefOf.NegativeEvent); - } } private void OnMaintenancePerformed(float amount) diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 71bdf8a4..4520ee44 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -71,6 +71,7 @@ + @@ -108,6 +109,9 @@ + + + @@ -206,7 +210,6 @@ - diff --git a/美术与文本源文件/Wula/Building/Linked/WulaWall/WULA_Fortress_Wall_Cleanzone.sai2 b/美术与文本源文件/Wula/Building/Linked/WulaWall/WULA_Fortress_Wall_Cleanzone.sai2 new file mode 100644 index 00000000..007c820a Binary files /dev/null and b/美术与文本源文件/Wula/Building/Linked/WulaWall/WULA_Fortress_Wall_Cleanzone.sai2 differ diff --git a/美术与文本源文件/Wula/Building/WULA_Cat_Bunker.sai2 b/美术与文本源文件/Wula/Building/WULA_Cat_Bunker.sai2 index ef8a7c73..5bba025b 100644 Binary files a/美术与文本源文件/Wula/Building/WULA_Cat_Bunker.sai2 and b/美术与文本源文件/Wula/Building/WULA_Cat_Bunker.sai2 differ diff --git a/美术与文本源文件/Wula/Building/WULA_Dropping_Building_Cleanzone.sai2 b/美术与文本源文件/Wula/Building/WULA_Dropping_Building_Cleanzone.sai2 index 74c7595e..d929c098 100644 Binary files a/美术与文本源文件/Wula/Building/WULA_Dropping_Building_Cleanzone.sai2 and b/美术与文本源文件/Wula/Building/WULA_Dropping_Building_Cleanzone.sai2 differ diff --git a/美术与文本源文件/Wula/Building/WULA_MaintenancePod.sai2 b/美术与文本源文件/Wula/Building/WULA_MaintenancePod.sai2 new file mode 100644 index 00000000..768d07e2 Binary files /dev/null and b/美术与文本源文件/Wula/Building/WULA_MaintenancePod.sai2 differ diff --git a/美术与文本源文件/Wula/Building/WULA_Synth_Maintainer_south.sai2 b/美术与文本源文件/Wula/Building/WULA_Synth_Maintainer_south.sai2 deleted file mode 100644 index b1fe4c47..00000000 Binary files a/美术与文本源文件/Wula/Building/WULA_Synth_Maintainer_south.sai2 and /dev/null differ diff --git a/美术与文本源文件/Wula/UI/Commands/WULA_AirdropProducts.sai2 b/美术与文本源文件/Wula/UI/Commands/WULA_AirdropProducts.sai2 new file mode 100644 index 00000000..f4f680a3 Binary files /dev/null and b/美术与文本源文件/Wula/UI/Commands/WULA_AirdropProducts.sai2 differ diff --git a/美术与文本源文件/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.sai2 b/美术与文本源文件/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.sai2 index ec0bf281..efa8c741 100644 Binary files a/美术与文本源文件/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.sai2 and b/美术与文本源文件/Wula/UI/Commands/WULA_NanoRepairHediff_Switch.sai2 differ