strusik Posted February 1 Author Share Posted February 1 2 hours ago, 363rdChemicalCompany said: One trick I use before O emable sricpt heavy mods thta I dont know if I iwll like them or not is this: -Clone a profile of my exsiting Vortex profile -Copy/paste the last 2 or 3 savegame files into that new profile's save game folder - Enable the new mod and play it. -Now my previous playthrough and save files are completely protected from any shenanigans. I also always tried to keep backups when adding new mods, but the thing is that this particular mod I played with from the beginning and it didn't cause any problems, and then in a later game I noticed that it conflicts with certain mechanics of Sim Settlements 2, and decided to remove it, besides the author on the mod page wrote how to do it. I did, and it ended up breaking something in the settlement happiness system Link to comment Share on other sites More sharing options...
subaverage Posted February 1 Share Posted February 1 Here is a little tutorial what you can do: https://www.youtube.com/watch?v=hyPDQuWg6jQ and on the modpage is another little tutorial video plus some information in the description. I never did more than this, but as I said without success. Link to comment Share on other sites More sharing options...
strusik Posted February 1 Author Share Posted February 1 Spoiler PEX format v3.9 GameID: 2 Source : F:\Spiele\Steam\SteamApps\common\Fallout 4\Data\Scripts\Source\User\workshopscript.psc Modified : 2017-11-25 20:12:04 Compiled : 2017-11-25 20:12:10 User : Stefan Computer : STEFAN-PC /; ScriptName workshopscript extends ObjectReference conditional { script for Workshop reference } ;-- Structs ----------------------------------------- Struct DailyUpdateData int totalPopulation int robotPopulation int brahminPopulation int unassignedPopulation float vendorIncome float currentHappiness float damageMult float productivity int availableBeds int shelteredBeds int bonusHappiness int happinessModifier int safety int safetyDamage int foodProduction int waterProduction int availableFood int availableWater int safetyPerNPC float totalHappiness EndStruct ;-- Properties -------------------------------------- Group Optional Faction Property SettlementOwnershipFaction Auto { optional - if the workshop settlement has an ownership faction, set this here so the player can be added to that faction when workshop becomes player-owned } bool Property UseOwnershipFaction = True Auto { set to false to not use the ownership faction } ActorBase Property CustomWorkshopNPC Auto Const { Patch 1.4: the actor that gets created when a settlement makes a successful recruitment roll - overrides properties on WorkshopParentScript } Message Property CustomUnownedMessage Auto Const { Patch 1.4: a custom unowned message, that overrides standard messages from WorkshopParentScript } bool Property AllowBrahminRecruitment = True Auto Const { Patch 1.6: set to false to prevent brahmin from being randomly recruited at this workshop settlement } EndGroup Group BuildingBudget int Property MaxTriangles Auto { if > 0, initialize WorkshopMaxTriangles to this value } int Property MaxDraws Auto { if > 0, initialize WorkshopMaxDraws to this value } int Property CurrentTriangles Auto { if > 0, initialize WorkshopCurrentTriangles to this value } int Property CurrentDraws Auto { if > 0, initialize WorkshopCurrentDraws to this value } EndGroup Group Flags bool Property OwnedByPlayer = False Auto conditional { all workshops start "unowned" - activate after location is cleared to "own" } bool Property StartsHostile = False Auto conditional { set to true for workbench locations that start out with hostiles in control (to prevent it being counted as a valid Minuteman recruiting target) } bool Property EnableAutomaticPlayerOwnership = True Auto { TRUE = workshop will automatically become usable when the location is cleared (or if there are no bosses) FALSE = workshop won't be usable by player until SetOwnedByPlayer(true) is called on it } bool Property AllowUnownedFromLowHappiness = False Auto { TRUE = workshop can become unowned due to low happiness (<=minHappinessThreshold) FALSE (default) = workshop can never become unowned, no matter how low the happiness (for special cases like the Castle) } bool Property HappinessWarning Auto conditional hidden { set to true when happiness warning given; set back to false when happiness goes above the warning level NOTE: only applies when AllowUnownedFromLowHappiness = true } int Property DaysSinceLastVisit Auto conditional hidden { this gets cleared when player visits, incremented by daily update } bool Property PlayerHasVisited Auto conditional hidden { this gets set to true the first time player visits - used by ResetWorkshop to initialize data on first visit } bool Property MinRecruitmentProhibitRandom = False Auto conditional { set to TRUE to prohibit random Minutemen recruitment quests from picking this workshop } bool Property MinRecruitmentAllowRandomAfterPlayerOwned = True Auto conditional { set to FALSE to prohibit random Minutemen quests from picking this workshop AFTER the player takes over (TRUE = random quests are allowed once owned by player) } bool Property AllowAttacksBeforeOwned = True Auto conditional { set to FALSE to prevent attacks when unowned NOTE: this always gets set to true when the player takes ownership for the first time } bool Property AllowAttacks = True Auto conditional { set to FALSE to prevent ALL random attacks (e.g. the Castle) } bool Property RadioBeaconFirstRecruit = False Auto conditional hidden { set to true after player first builds a radio beacon here and gets the first "quick" recruit } bool Property ShowedWorkshopMenuExitMessage = False Auto conditional hidden { set to true after player first exits the workshop menu here } EndGroup Group VendorData ObjectReference[] Property VendorContainersMisc Auto hidden { array of Misc vendor containers, indexed by vendor level } ObjectReference[] Property VendorContainersArmor Auto hidden ObjectReference[] Property VendorContainersWeapons Auto hidden ObjectReference[] Property VendorContainersBar Auto hidden ObjectReference[] Property VendorContainersClinic Auto hidden ObjectReference[] Property VendorContainersClothing Auto hidden EndGroup Group WorkshopRadioData ObjectReference Property WorkshopRadioRef Auto Const { if WorkshopRadioRef exists, it will override the default WorkshopRadioRef from WorkshopParent } float Property workshopRadioInnerRadius = 9000 Auto Const { override workshop parent values } float Property workshopRadioOuterRadius = 20000 Auto Const { override workshop parent values } Scene Property WorkshopRadioScene Auto Const { if WorkshopRadioRef exists, WorkshopRadioScene will be started instead of the default scene from WorkshopParent } bool Property bWorkshopRadioRefIsUnique = True Auto Const { TRUE: WorkshopRadioScene is unique to this workshop, so it should be stopped/disabled when radio is shut off (completely) } EndGroup workshopparentscript Property WorkshopParent Auto Const mandatory { parent quest - holds most general workshop properties } Location Property myLocation Auto hidden { workshop's location (filled onInit) this is a property so the WorkshopParent script can access it } ObjectReference Property myMapMarker Auto hidden { workshop's map marker (filled by WorkshopParent.InitializeLocation) } ;-- Variables --------------------------------------- float vendorIncomeBaseMult = 2 float happinessBonusFood = 20 Const float maxStoredWaterPerPopulation = 0.25 Const int minHappinessWarningThreshold = 15 Const float attackChanceBase = 0.05 Const float damageDailyRepairBase = 5 Const int minVendorIncomePopulation = 5 float attackChancePopulationMult = 0.02 Const int maxStoredFoodPerPopulation = 1 Const int iBaseMaxNPCs = 10 Const float maxHappinessNoWater = 30 Const int happinessBonusChangePerUpdate = 2 Const int maxStoredFertilizerBase = 10 int maxBrahminFertilizerProduction = 3 float happinessChangeMult = 0.2 Const int dailyUpdateTimerID = 1 Const int buildWorkObjectTimerID = 0 Const float attractNPCHappinessMult = 0.5 Const float brahminProductionBoost = 0.5 bool bDailyUpdateInProgress = False float maxHappinessNoFood = 30 Const float minProductivity = 0.25 Const float happinessBonusShelter = 10 Const float happinessBonusWater = 20 Const float maxVendorIncome = 50 float damageDailyPopulationMult = 0.2 Const bool showVendorTraces = True int maxStoredScavengeBase = 100 Const float minDailyUpdateWaitHours = 0.2 float maxDailyUpdateWaitHours = 1 int maxProductionPerBrahmin = 10 float minDaysSinceLastAttack = 1 Const int maxStoredFoodBase = 10 Const float attackChanceSafetyMult = 0.01 Const float attackChanceResourceMult = 0.05 Const int iMaxBonusAttractChancePopulation = 5 Const int iMaxSurplusNPCs = 5 Const float vendorIncomePopulationMult = 0.03 float productivityHappinessMult = 0.75 Const int maxStoredScavengePerPopulation = 5 Const float happinessBonusBed = 10 Const int WorkshopID = -1 int minHappinessClearWarningThreshold = 20 Const float maxHappinessNoShelter = 60 Const float happinessBonusSafety = 20 Const int minHappinessChangePerUpdate = 1 Const int minHappinessThreshold = 10 Const float attractNPCDailyChance = 0.1 Const int maxStoredWaterBase = 5 Const ;-- Functions --------------------------------------- Event OnWorkshopObjectDestroyed(ObjectReference akReference) WorkshopParent.RemoveObjectPUBLIC(akReference, Self) EndEvent int Function GetWorkshopID() If (WorkshopID < 0) Self.InitWorkshopID(WorkshopParent.GetWorkshopID(Self)) EndIf return WorkshopID EndFunction float Function GetProductivityMultiplier(workshopdatascript#workshopratingkeyword[] ratings) float currentHappiness = Self.GetValue(ratings[WorkshopParent.WorkshopRatingHappiness].resourceValue) return minProductivity + currentHappiness / 100 as float * (1 as float - minProductivity) EndFunction Function SetOwnedByPlayer(bool bIsOwned) If (!bIsOwned && OwnedByPlayer) OwnedByPlayer = bIsOwned WorkshopParent.DisplayMessage(WorkshopParent.WorkshopLosePlayerOwnership, None, myLocation) Self.SetValue(WorkshopParent.WorkshopPlayerLostControl, 1) ObjectReference[] WorkshopActors = WorkshopParent.GetWorkshopActors(Self) int I = 0 While (I < WorkshopActors.length) workshopnpcscript theActor = (WorkshopActors as Actor) as workshopnpcscript If (theActor) theActor.RemoveFromFaction(WorkshopParent.FarmDiscountFaction) theActor.UpdatePlayerOwnership(Self) EndIf I += 1 EndWhile WorkshopParent.ClearCaravansFromWorkshopPUBLIC(Self) ElseIf (bIsOwned && !OwnedByPlayer) OwnedByPlayer = bIsOwned If (!WorkshopParent.PlayerOwnsAWorkshop) WorkshopParent.PlayerOwnsAWorkshop = True EndIf float currentHappiness = Self.GetValue(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingHappiness].resourceValue) float currentHappinessTarget = Self.GetValue(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingHappinessTarget].resourceValue) If (currentHappiness < minHappinessClearWarningThreshold as float || currentHappinessTarget < minHappinessClearWarningThreshold as float) WorkshopParent.ModifyResourceData(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingHappiness].resourceValue, Self, minHappinessClearWarningThreshold as float) WorkshopParent.ModifyResourceData(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingHappinessTarget].resourceValue, Self, minHappinessClearWarningThreshold as float) EndIf WorkshopParent.DisplayMessage(WorkshopParent.WorkshopGainPlayerOwnership, None, myLocation) If (Self.GetValue(WorkshopParent.WorkshopPlayerLostControl) == 0 as float) Game.IncrementStat("Workshops Unlocked", 1) Else Self.SetValue(WorkshopParent.WorkshopPlayerLostControl, 0) EndIf If (MinRecruitmentAllowRandomAfterPlayerOwned) MinRecruitmentProhibitRandom = False EndIf AllowAttacksBeforeOwned = True ObjectReference[] workshopactors = WorkshopParent.GetWorkshopActors(Self) int i = 0 While (i < workshopactors.length) workshopnpcscript theactor = (workshopactors as Actor) as workshopnpcscript If (theactor) theactor.UpdatePlayerOwnership(Self) EndIf i += 1 EndWhile EndIf OwnedByPlayer = bIsOwned Self.BlockActivation(!OwnedByPlayer, False) Self.SetValue(WorkshopParent.WorkshopPlayerOwnership, bIsOwned as float) If (bIsOwned) Self.SetActorOwner(Game.GetPlayer().GetActorBase(), False) myLocation.SetCleared(False) If (SettlementOwnershipFaction as bool && UseOwnershipFaction) Game.GetPlayer().AddToFaction(SettlementOwnershipFaction) EndIf Else Self.SetActorOwner(None, False) If (SettlementOwnershipFaction as bool && UseOwnershipFaction) Game.GetPlayer().RemoveFromFaction(SettlementOwnershipFaction) EndIf EndIf WorkshopParent.SendPlayerOwnershipChangedEvent(Self) EndFunction float Function CheckActorHappiness(float currentHappiness, bool bFood, bool bWater, bool bBed, bool bShelter) If (!bWater && currentHappiness > maxHappinessNoWater) currentHappiness = maxHappinessNoWater EndIf If (!bFood && currentHappiness > maxHappinessNoFood) currentHappiness = maxHappinessNoFood EndIf If (!bShelter && currentHappiness > maxHappinessNoShelter) currentHappiness = maxHappinessNoShelter EndIf return currentHappiness EndFunction Function RepairDamageToResource(ActorValue resourceValue) ActorValue damageRating = WorkshopParent.GetDamageRatingValue(resourceValue) workshopdatascript#workshopratingkeyword[] ratings = WorkshopParent.WorkshopRatings bool bPopulationDamage = damageRating == ratings[WorkshopParent.WorkshopRatingDamagePopulation].resourceValue float currentDamage = 0 If (bPopulationDamage) currentDamage = WorkshopParent.GetPopulationDamage(Self) Else currentDamage = Self.GetValue(damageRating) EndIf WorkshopParent.wsTrace(Self as string + " RepairDamageToResource: damageRating=" + damageRating as string + " bPopulationDamage=" + bPopulationDamage as string, 0, False) int currentWorkshopID = WorkshopParent.WorkshopCurrentWorkshopID.GetValueInt() If (currentDamage > 0 as float) WorkshopParent.wsTrace(Self as string + " RepairDamageToResource: " + currentDamage as string + " for " + " resourceValue=" + resourceValue as string, 0, False) float repairAmount = 1 as float bool bHealedActor = False If (damageRating != ratings[WorkshopParent.WorkshopRatingDamagePopulation].resourceValue) repairAmount = Self.CalculateRepairAmount(ratings) repairAmount = Math.max(repairAmount, 1) WorkshopParent.wsTrace("\t\trepair amount=" + repairAmount as string, 0, False) Else Location[] linkedLocations = myLocation.GetAllLinkedLocations(WorkshopParent.WorkshopCaravanKeyword) If (linkedLocations.length > 0) int index = 0 While (index < WorkshopParent.CaravanActorAliases.GetCount()) workshopnpcscript caravanActor = WorkshopParent.CaravanActorAliases.GetAt(index) as workshopnpcscript If (caravanActor as bool && caravanActor.GetWorkshopID() == WorkshopID && caravanActor.IsWounded()) bHealedActor = True WorkshopParent.WoundActor(caravanActor, False) return EndIf index += 1 EndWhile EndIf If (!bHealedActor) If (WorkshopID == currentWorkshopID) int I = 0 ObjectReference[] WorkshopActors = WorkshopParent.GetWorkshopActors(Self) While (I < WorkshopActors.length && !bHealedActor) workshopnpcscript theActor = WorkshopActors as workshopnpcscript If (theActor as bool && theActor.IsWounded()) bHealedActor = True WorkshopParent.WoundActor(theActor, False) EndIf I += 1 EndWhile EndIf EndIf EndIf If (!bHealedActor) repairAmount = Math.min(repairAmount, currentDamage) WorkshopParent.ModifyResourceData(damageRating, Self, repairAmount * -1) WorkshopParent.wsTrace("\t\tworkshopID=" + WorkshopID as string + ", currentWorkshopID=" + currentWorkshopID as string, 0, False) If (WorkshopID == currentWorkshopID && damageRating != ratings[WorkshopParent.WorkshopRatingDamagePopulation].resourceValue) WorkshopParent.wsTrace("\t\tCurrent workshop - find item(s) to repair " + repairAmount as string + " damage...", 0, False) int i = 0 ObjectReference[] ResourceObjects = Self.GetWorkshopResourceObjects(resourceValue, 1) While (i < ResourceObjects.length && repairAmount > 0 as float) workshopobjectscript theObject = ResourceObjects as workshopobjectscript float damage = theObject.GetResourceDamage(resourceValue) WorkshopParent.wsTrace("\t\t" + theObject as string + "=" + damage as string + " damage", 0, False) If (damage > 0 as float) float modDamage = Math.min(repairAmount, damage) * -1 If (theObject.ModifyResourceDamage(resourceValue, modDamage)) repairAmount += modDamage EndIf EndIf i += 1 EndWhile EndIf EndIf EndIf EndFunction Function DailyUpdateAttractNewSettlers(workshopdatascript#workshopratingkeyword[] ratings, workshopscript#dailyupdatedata updateData) DaysSinceLastVisit += 1 int radioRating = Self.GetValue(ratings[WorkshopParent.WorkshopRatingRadio].resourceValue) as int If (radioRating > 0 && Self.HasKeyword(WorkshopParent.WorkshopType02) == False && updateData.unassignedPopulation < iMaxSurplusNPCs && updateData.totalPopulation < Self.GetMaxWorkshopNPCs()) float attractChance = attractNPCDailyChance + updateData.currentHappiness / 100 as float * attractNPCHappinessMult If (updateData.totalPopulation < iMaxBonusAttractChancePopulation) attractChance += (iMaxBonusAttractChancePopulation - updateData.totalPopulation) as float * attractNPCDailyChance EndIf float dieRoll = Utility.RandomFloat(0, 1) If (dieRoll <= attractChance) workshopnpcscript newWorkshopActor = WorkshopParent.CreateActor(Self, False, None, False) updateData.totalPopulation = updateData.totalPopulation + 1 If (newWorkshopActor.GetValue(WorkshopParent.WorkshopGuardPreference) == 0 as float) If (Self.GetValue(ratings[WorkshopParent.WorkshopRatingBrahmin].resourceValue) == 0 && AllowBrahminRecruitment) int brahminRoll = Utility.RandomInt(0, 100) If (brahminRoll <= WorkshopParent.recruitmentBrahminChance) Actor newBrahmin = WorkshopParent.CreateActor(Self, True, None, False) as Actor EndIf EndIf EndIf EndIf EndIf EndFunction Event OnInit() If (MaxTriangles > 0) Self.SetValue(WorkshopParent.WorkshopMaxTriangles, MaxTriangles as float) EndIf If (MaxDraws > 0) Self.SetValue(WorkshopParent.WorkshopMaxDraws, MaxDraws as float) EndIf If (CurrentTriangles > 0) Self.SetValue(WorkshopParent.WorkshopCurrentTriangles, CurrentTriangles as float) EndIf If (CurrentDraws > 0) Self.SetValue(WorkshopParent.WorkshopCurrentDraws, CurrentDraws as float) EndIf Self.SetValue(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingHappinessTarget].resourceValue, WorkshopParent.startingHappinessTarget) EndEvent Function DailyUpdateConsumeResources(workshopdatascript#workshopratingkeyword[] ratings, workshopscript#dailyupdatedata updateData, ObjectReference containerRef, bool bRealUpdate) If (updateData.totalPopulation == 0) return EndIf float ActorHappiness = 0 bool ActorBed = False bool ActorShelter = False bool ActorFood = False bool ActorWater = False int missingFood = 0 int missingWater = 0 int missingBeds = 0 int missingShelter = 0 int missingSafety = 0 int I = 0 While (I < updateData.totalPopulation - updateData.robotPopulation) ActorHappiness = 0 as float ActorFood = False ActorWater = False ActorBed = False ActorShelter = False WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: actor " + I as string, 0, False) If (updateData.availableFood > 0) ActorFood = True updateData.availableFood = updateData.availableFood - 1 If (updateData.foodProduction > 0) updateData.foodProduction = updateData.foodProduction - 1 ElseIf (bRealUpdate) containerRef.RemoveItem(WorkshopParent.WorkshopConsumeFood as Form, 1, False, None) EndIf ActorHappiness += happinessBonusFood WorkshopParent.wsTrace(Self as string + " +FOOD - happiness=" + ActorHappiness as string, 0, False) Else missingFood += 1 EndIf If (updateData.availableWater > 0) ActorWater = True updateData.availableWater = updateData.availableWater - 1 If (updateData.waterProduction > 0) updateData.waterProduction = updateData.waterProduction - 1 ElseIf (bRealUpdate) containerRef.RemoveItem(WorkshopParent.WorkshopConsumeWater as Form, 1, False, None) EndIf ActorHappiness += happinessBonusWater WorkshopParent.wsTrace(Self as string + " +WATER - happiness=" + ActorHappiness as string, 0, False) Else missingWater += 1 EndIf If (updateData.availableBeds > 0) ActorBed = True updateData.availableBeds = updateData.availableBeds - 1 ActorHappiness += happinessBonusBed WorkshopParent.wsTrace(Self as string + " +BED - happiness=" + ActorHappiness as string, 0, False) Else missingBeds += 1 EndIf If (updateData.shelteredBeds > 0) ActorShelter = True updateData.shelteredBeds = updateData.shelteredBeds - 1 ActorHappiness += happinessBonusShelter WorkshopParent.wsTrace(Self as string + " +SHELTER - happiness=" + ActorHappiness as string, 0, False) EndIf If (updateData.safetyPerNPC > 0) ActorHappiness += happinessBonusSafety EndIf ActorHappiness = Self.CheckActorHappiness(ActorHappiness, ActorFood, ActorWater, ActorBed, ActorShelter) WorkshopParent.wsTrace(Self as string + " Final actor happiness=" + ActorHappiness as string, 0, False) updateData.totalHappiness = updateData.totalHappiness + ActorHappiness I += 1 EndWhile updateData.totalHappiness = updateData.totalHappiness + (50 * updateData.robotPopulation) as float WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingMissingBeds].resourceValue, Self, missingBeds as float) If (bRealUpdate) WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingMissingFood].resourceValue, Self, missingFood as float) WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingMissingWater].resourceValue, Self, missingWater as float) EndIf updateData.totalHappiness = updateData.totalHappiness + updateData.bonusHappiness as float WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: totalHappiness=" + updateData.totalHappiness as string + ", totalActors=" + updateData.totalPopulation as string + ", happiness modifier=" + updateData.happinessModifier as string, 0, False) updateData.totalHappiness = Math.max(updateData.totalHappiness / updateData.totalPopulation as float + updateData.happinessModifier as float, 0 as float) updateData.totalHappiness = Math.min(updateData.totalHappiness, 100 as float) WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: Happiness Target=" + updateData.totalHappiness as string, 0, False) WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingHappinessTarget].resourceValue, Self, updateData.totalHappiness) If (bRealUpdate) float deltaHappinessFloat = (updateData.totalHappiness - updateData.currentHappiness) * happinessChangeMult int deltaHappiness = 0 If (deltaHappinessFloat < 0 as float) deltaHappiness = Math.floor(deltaHappinessFloat) Else deltaHappiness = Math.Ceiling(deltaHappinessFloat) EndIf If (deltaHappiness != 0 && Math.abs(deltaHappiness as float) < minHappinessChangePerUpdate as float) deltaHappiness = minHappinessChangePerUpdate * (deltaHappiness as float / Math.abs(deltaHappiness as float)) as int EndIf WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: happiness change=" + deltaHappiness as string, 0, False) WorkshopParent.ModifyResourceData(ratings[WorkshopParent.WorkshopRatingHappiness].resourceValue, Self, deltaHappiness as float) float finalHappiness = Self.GetValue(ratings[WorkshopParent.WorkshopRatingHappiness].resourceValue) WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: final happiness=" + finalHappiness as string, 0, False) If (finalHappiness >= WorkshopParent.HappinessAchievementValue as float) Game.AddAchievement(WorkshopParent.HappinessAchievementID) EndIf If (OwnedByPlayer && AllowUnownedFromLowHappiness) If (finalHappiness <= minHappinessWarningThreshold as float && HappinessWarning == False) HappinessWarning = True WorkshopParent.DisplayMessage(WorkshopParent.WorkshopUnhappinessWarning, None, myLocation) ElseIf (finalHappiness <= minHappinessThreshold as float) Self.SetOwnedByPlayer(False) EndIf If (finalHappiness > minHappinessClearWarningThreshold as float && HappinessWarning == True) HappinessWarning = False EndIf EndIf If (updateData.happinessModifier != 0) float modifierSign = (-1) as float * updateData.happinessModifier as float / Math.abs(updateData.happinessModifier as float) WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: modifierSign=" + modifierSign as string, 0, False) int deltaHappinessModifier = 0 float deltaHappinessModifierFloat = Math.abs(updateData.happinessModifier as float) * modifierSign * happinessChangeMult WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: deltaHappinessModifierFloat=" + deltaHappinessModifierFloat as string, 0, False) If (deltaHappinessModifierFloat > 0 as float) deltaHappinessModifier = Math.floor(deltaHappinessModifierFloat) Else deltaHappinessModifier = Math.Ceiling(deltaHappinessModifierFloat) EndIf WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: deltaHappinessModifier=" + deltaHappinessModifier as string, 0, False) If (Math.abs(deltaHappinessModifier as float) < happinessBonusChangePerUpdate as float) deltaHappinessModifier = (modifierSign * happinessBonusChangePerUpdate as float) as int EndIf WorkshopParent.wsTrace(Self as string + "\tCalculateHappiness: FINAL deltaHappinessModifier=" + deltaHappinessModifier as string, 0, False) If (deltaHappinessModifier as float > Math.abs(updateData.happinessModifier as float)) WorkshopParent.SetHappinessModifier(Self, 0 as float) Else WorkshopParent.ModifyHappinessModifier(Self, deltaHappinessModifier as float) EndIf EndIf EndIf EndFunction Function DailyUpdateSurplusResources(workshopdatascript#workshopratingkeyword[] ratings, workshopscript#dailyupdatedata updateData, ObjectReference containerRef) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\tAdd surplus to workshop container: ", 0, False) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) int currentStoredFood = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeFood as Form) int currentStoredWater = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeWater as Form) int currentStoredScavenge = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeScavenge as Form) int currentStoredFertilizer = containerRef.GetItemCount(WorkshopParent.WorkshopProduceFertilizer as Form) WorkshopParent.wsTrace(Self as string + "\t\tCheck stored resources: food=" + currentStoredFood as string + ", water=" + currentStoredWater as string + ", scavenge=" + currentStoredScavenge as string, 0, False) bool bAllowFoodProduction = True If (currentStoredFood > maxStoredFoodBase + maxStoredFoodPerPopulation * updateData.totalPopulation) bAllowFoodProduction = False EndIf bool bAllowWaterProduction = True If (currentStoredWater > maxStoredWaterBase + Math.floor(maxStoredWaterPerPopulation * updateData.totalPopulation as float)) bAllowWaterProduction = False EndIf bool bAllowScavengeProduction = True If (currentStoredScavenge > maxStoredScavengeBase + maxStoredScavengePerPopulation * updateData.totalPopulation) bAllowScavengeProduction = False EndIf bool bAllowFertilizerProduction = True If (currentStoredFertilizer > maxStoredFertilizerBase) bAllowFertilizerProduction = False EndIf WorkshopParent.wsTrace(Self as string + "\t\tAllow production? food: " + bAllowFoodProduction as string + ", water: " + bAllowWaterProduction as string + ", scavenge: " + bAllowScavengeProduction as string, 0, False) If (updateData.foodProduction > 0 && bAllowFoodProduction) updateData.foodProduction = Math.floor(updateData.foodProduction as float * updateData.productivity) WorkshopParent.wsTrace(Self as string + "\t\tFOOD SURPLUS: +" + updateData.foodProduction as string, 0, False) If (updateData.foodProduction > 0) WorkshopParent.ProduceFood(Self, updateData.foodProduction) EndIf EndIf If (updateData.waterProduction > 0 && bAllowWaterProduction) WorkshopParent.wsTrace(Self as string + "\t\tWATER SURPLUS: +" + updateData.waterProduction as string, 0, False) containerRef.AddItem(WorkshopParent.WorkshopProduceWater as Form, updateData.waterProduction, False) EndIf If (updateData.brahminPopulation > 0 && bAllowFertilizerProduction) int fertilizerProduction = Math.min(updateData.brahminPopulation as float, maxBrahminFertilizerProduction as float) as int WorkshopParent.wsTrace(Self as string + "\t\tFERTILIZER PRODUCTION: +" + fertilizerProduction as string, 0, False) containerRef.AddItem(WorkshopParent.WorkshopProduceFertilizer as Form, fertilizerProduction, False) EndIf int scavengePopulation = (updateData.unassignedPopulation as float - Self.GetValue(ratings[WorkshopParent.WorkshopRatingDamagePopulation].resourceValue)) as int int scavengeProductionGeneral = Self.GetValue(ratings[WorkshopParent.WorkshopRatingScavengeGeneral].resourceValue) as int int scavengeAmount = Math.Ceiling(scavengePopulation as float * updateData.productivity * updateData.damageMult + scavengeProductionGeneral as float * updateData.productivity) WorkshopParent.wsTrace(Self as string + "\t\tscavenge population: " + scavengePopulation as string + " unassigned, " + scavengeProductionGeneral as string + " dedicated scavengers", 0, False) If (scavengeAmount > 0 && bAllowScavengeProduction) WorkshopParent.wsTrace(Self as string + "\t\tSCAVENGING: +" + scavengeAmount as string, 0, False) containerRef.AddItem(WorkshopParent.WorkshopProduceScavenge as Form, scavengeAmount, False) EndIf If (updateData.vendorIncome > 0 as float) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\tVendor income: ", 0, False) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tProductivity mult: +" + updateData.productivity as string, 0, showVendorTraces) int vendorIncomeFinal = 0 float linkedPopulation = WorkshopParent.GetLinkedPopulation(Self, False) WorkshopParent.wsTrace(Self as string + "\t\tLinked population: +" + linkedPopulation as string, 0, showVendorTraces) float vendorPopulation = linkedPopulation + updateData.totalPopulation as float WorkshopParent.wsTrace(Self as string + "\t\tTotal population: +" + vendorPopulation as string, 0, showVendorTraces) If (vendorPopulation >= minVendorIncomePopulation as float) linkedPopulation = WorkshopParent.GetLinkedPopulation(Self, True) WorkshopParent.wsTrace(Self as string + "\t\tLinked population (productivity adjusted): +" + linkedPopulation as string, 0, showVendorTraces) vendorPopulation = updateData.totalPopulation as float * updateData.productivity + linkedPopulation WorkshopParent.wsTrace(Self as string + "\t\tTotal vendor population: " + vendorPopulation as string, 0, showVendorTraces) WorkshopParent.wsTrace(Self as string + "\t\tBase income: +" + updateData.vendorIncome as string, 0, showVendorTraces) float incomeBonus = updateData.vendorIncome * vendorIncomePopulationMult * vendorPopulation WorkshopParent.wsTrace(Self as string + "\t\tPopulation bonus: +" + incomeBonus as string, 0, showVendorTraces) updateData.vendorIncome = updateData.vendorIncome + incomeBonus vendorIncomeFinal = Math.Ceiling(updateData.vendorIncome) vendorIncomeFinal = Math.min(vendorIncomeFinal as float, maxVendorIncome) as int If (vendorIncomeFinal as float >= 1) containerRef.AddItem(WorkshopParent.WorkshopProduceVendorIncome as Form, vendorIncomeFinal, False) EndIf EndIf WorkshopParent.wsTrace(Self as string + "\t\tVENDOR INCOME: " + vendorIncomeFinal as string, 0, showVendorTraces) EndIf EndFunction Function RepairDamage() WorkshopParent.wsTrace("\tRepair damage: " + Self as string, 0, False) workshopdatascript#workshopratingkeyword[] ratings = WorkshopParent.WorkshopRatings Self.RepairDamageToResource(ratings[WorkshopParent.WorkshopRatingFood].resourceValue) Self.RepairDamageToResource(ratings[WorkshopParent.WorkshopRatingWater].resourceValue) Self.RepairDamageToResource(ratings[WorkshopParent.WorkshopRatingSafety].resourceValue) Self.RepairDamageToResource(ratings[WorkshopParent.WorkshopRatingPower].resourceValue) Self.RepairDamageToResource(ratings[WorkshopParent.WorkshopRatingPopulation].resourceValue) float currentDamage = Self.GetValue(ratings[WorkshopParent.WorkshopRatingDamageCurrent].resourceValue) If (currentDamage > 0 as float) WorkshopParent.UpdateCurrentDamage(Self) EndIf EndFunction Event OnWorkshopObjectRepaired(ObjectReference akReference) workshopobjectactorscript workshopObjectActor = akReference as workshopobjectactorscript If (workshopObjectActor) workshopobjectscript workshopObject = akReference as workshopobjectscript workshopObject.OnDestructionStageChanged(1, 0) EndIf workshopobjectscript workshopObjectRef = akReference as workshopobjectscript If (workshopObjectRef) var[] kargs = new var[2] kargs[0] = workshopObjectRef as var kargs[1] = Self as var WorkshopParent.SendCustomEvent("workshopparentscript_WorkshopObjectRepaired", kargs) EndIf EndEvent int Function GetMaxWorkshopNPCs() int iMaxNPCs = iBaseMaxNPCs + Game.GetPlayer().GetValue(WorkshopParent.Charisma) as int return iMaxNPCs EndFunction ObjectReference[] Function InitializeVendorChests(int vendorType) int containerArraySize = WorkshopParent.VendorTopLevel + 1 ObjectReference[] vendorContainers = new ObjectReference[containerArraySize] FormList vendorContainerList = WorkshopParent.WorkshopVendorContainers[vendorType] int vendorLevel = 0 While (vendorLevel <= WorkshopParent.VendorTopLevel) vendorContainers[vendorLevel] = WorkshopParent.WorkshopHoldingCellMarker.PlaceAtMe(vendorContainerList.GetAt(vendorLevel), 1, False, False, True) vendorLevel += 1 EndWhile return vendorContainers EndFunction int Function GetTotalWaterRating(workshopdatascript#workshopratingkeyword[] ratings) int waterRating = Self.GetValue(ratings[WorkshopParent.WorkshopRatingWater].resourceValue) as int waterRating += Self.GetContainer().GetItemCount(WorkshopParent.WorkshopConsumeWater as Form) return waterRating EndFunction int Function GetTotalFoodRating(workshopdatascript#workshopratingkeyword[] ratings) int foodRating = Self.GetValue(ratings[WorkshopParent.WorkshopRatingFood].resourceValue) as int foodRating += Self.GetContainer().GetItemCount(WorkshopParent.WorkshopConsumeFood as Form) return foodRating EndFunction Event OnWorkshopObjectMoved(ObjectReference akReference) workshopobjectscript workshopObjectRef = akReference as workshopobjectscript If (workshopObjectRef) var[] kargs = new var[2] kargs[0] = workshopObjectRef as var kargs[1] = Self as var WorkshopParent.SendCustomEvent("workshopparentscript_WorkshopObjectMoved", kargs) EndIf EndEvent Function CheckForAttack(bool bForceAttack) WorkshopParent.wsTrace("------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace("\tCheck for attack: " + Self as string, 0, False) WorkshopParent.wsTrace("------------------------------------------------------------------------------ ", 0, False) workshopdatascript#workshopratingkeyword[] ratings = WorkshopParent.WorkshopRatings WorkshopParent.ModifyResourceData(ratings[WorkshopParent.WorkshopRatingLastAttackDaysSince].resourceValue, Self, 1) If (AllowAttacks == False) WorkshopParent.wsTrace("\t\tattacks not allowed - no attack roll for " + Self as string, 0, False) return EndIf If (AllowAttacksBeforeOwned == False && OwnedByPlayer == False && bForceAttack == False) WorkshopParent.wsTrace("\t\tattacks on unowned workshop not allowed - no attack roll for " + Self as string, 0, False) return EndIf ObjectReference containerRef = Self.GetContainer() If (!containerRef) WorkshopParent.wsTrace(Self as string + " ERROR - no container linked to workshop " + Self as string + " with " + WorkshopParent.WorkshopLinkContainer as string, 2, False) return EndIf int totalPopulation = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingPopulation].resourceValue) as int int safety = Self.GetValue(ratings[WorkshopParent.WorkshopRatingSafety].resourceValue) as int int safetyPerNPC = 0 If (totalPopulation > 0) safetyPerNPC = Math.Ceiling((safety / totalPopulation) as float) ElseIf (bForceAttack) safetyPerNPC = safety Else WorkshopParent.wsTrace("\t\t0 population - no attack roll", 0, False) return EndIf int daysSinceLastAttack = Self.GetValue(ratings[WorkshopParent.WorkshopRatingLastAttackDaysSince].resourceValue) as int If (minDaysSinceLastAttack > daysSinceLastAttack as float && !bForceAttack) WorkshopParent.wsTrace("\t\t" + daysSinceLastAttack as string + " days since last attack - no attack roll", 0, False) return EndIf int foodRating = Self.GetTotalFoodRating(ratings) int waterRating = Self.GetTotalWaterRating(ratings) WorkshopParent.wsTrace("\tStarting stats:", 0, False) WorkshopParent.wsTrace("\t\tpopulation=" + totalPopulation as string, 0, False) WorkshopParent.wsTrace("\t\tfood rating=" + foodRating as string, 0, False) WorkshopParent.wsTrace("\t\twater rating=" + waterRating as string, 0, False) WorkshopParent.wsTrace("\t\ttotal safety=" + safety as string, 0, False) WorkshopParent.wsTrace("\t\tsafety per NPC=" + safetyPerNPC as string, 0, False) WorkshopParent.wsTrace("\tAttack chance:", 0, False) WorkshopParent.wsTrace("\t\tbase chance=" + attackChanceBase as string, 0, False) WorkshopParent.wsTrace("\t\tresources=+" + (attackChanceResourceMult * (foodRating + waterRating) as float) as string, 0, False) WorkshopParent.wsTrace("\t\tsafety=-" + (attackChanceSafetyMult * safety as float) as string, 0, False) WorkshopParent.wsTrace("\t\tpopulation=-" + (attackChancePopulationMult * totalPopulation as float) as string, 0, False) float attackChance = attackChanceBase + attackChanceResourceMult * (foodRating + waterRating) as float - attackChanceSafetyMult * safety as float - attackChancePopulationMult * totalPopulation as float If (attackChance < attackChanceBase) attackChance = attackChanceBase EndIf WorkshopParent.wsTrace("\t\tTOTAL=" + attackChance as string, 0, False) float attackRoll = Utility.RandomFloat(0, 1) WorkshopParent.wsTrace("\tAttack roll = " + attackRoll as string, 0, False) If (attackRoll <= attackChance || bForceAttack) int attackStrength = WorkshopParent.CalculateAttackStrength(foodRating, waterRating) WorkshopParent.TriggerAttack(Self, attackStrength) EndIf EndFunction Event OnUnload() DaysSinceLastVisit = 0 EndEvent Event OnTimerGameTime(int aiTimerID) If (aiTimerID == dailyUpdateTimerID) If (WorkshopParent.IsEditLocked() || WorkshopParent.DailyUpdateInProgress) float waitTime = Utility.RandomFloat(minDailyUpdateWaitHours, maxDailyUpdateWaitHours) WorkshopParent.wsTrace(Self as string + " DailyUpdate: system busy, try again in " + waitTime as string + " game hours.", 0, False) Self.StartTimerGameTime(waitTime, dailyUpdateTimerID) Else Self.DailyUpdate(True) EndIf EndIf EndEvent Function DailyUpdate(bool bRealUpdate) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + " \tDAILY UPDATE: bRealUpdate=" + bRealUpdate as string, 0, True) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) If (bDailyUpdateInProgress) If (bRealUpdate) While (bDailyUpdateInProgress) WorkshopParent.wsTrace(Self as string + "\t\twaiting for update lock to clear...", 0, False) Utility.wait(0.5) EndWhile Else WorkshopParent.wsTrace(Self as string + "\t\tupdate already in progress - don't try again right now", 0, False) return EndIf EndIf bDailyUpdateInProgress = True WorkshopParent.DailyUpdateInProgress = True workshopdatascript#workshopratingkeyword[] ratings = WorkshopParent.WorkshopRatings workshopscript#dailyupdatedata updateData = new workshopscript#dailyupdatedata updateData.totalPopulation = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingPopulation].resourceValue) as int updateData.robotPopulation = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingPopulationRobots].resourceValue) as int updateData.brahminPopulation = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingBrahmin].resourceValue) as int updateData.unassignedPopulation = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingPopulationUnassigned].resourceValue) as int updateData.vendorIncome = Self.GetValue(ratings[WorkshopParent.WorkshopRatingVendorIncome].resourceValue) * vendorIncomeBaseMult updateData.currentHappiness = Self.GetValue(ratings[WorkshopParent.WorkshopRatingHappiness].resourceValue) updateData.damageMult = 1 as float - Self.GetValue(ratings[WorkshopParent.WorkshopRatingDamageCurrent].resourceValue) / 100 updateData.productivity = Self.GetProductivityMultiplier(ratings) updateData.availableBeds = Self.GetBaseValue(ratings[WorkshopParent.WorkshopRatingBeds].resourceValue) as int updateData.shelteredBeds = Self.GetValue(ratings[WorkshopParent.WorkshopRatingBeds].resourceValue) as int updateData.bonusHappiness = Self.GetValue(ratings[WorkshopParent.WorkshopRatingBonusHappiness].resourceValue) as int updateData.happinessModifier = Self.GetValue(ratings[WorkshopParent.WorkshopRatingHappinessModifier].resourceValue) as int updateData.safety = Self.GetValue(ratings[WorkshopParent.WorkshopRatingSafety].resourceValue) as int updateData.safetyDamage = Self.GetValue(WorkshopParent.GetDamageRatingValue(ratings[WorkshopParent.WorkshopRatingSafety].resourceValue)) as int updateData.totalHappiness = 0 If (bRealUpdate) Self.DailyUpdateAttractNewSettlers(ratings, updateData) EndIf ObjectReference containerRef = Self.GetContainer() If (!containerRef) WorkshopParent.wsTrace(Self as string + " ERROR - no container linked to workshop " + Self as string + " with " + WorkshopParent.WorkshopLinkContainer as string, 2, False) bDailyUpdateInProgress = False WorkshopParent.DailyUpdateInProgress = False return EndIf If (Self.GetWorkshopID() as float == WorkshopParent.WorkshopCurrentWorkshopID.GetValue()) ObjectReference[] WorkshopActors = WorkshopParent.GetWorkshopActors(Self) int I = 0 While (I < WorkshopActors.length) WorkshopParent.UpdateActorsWorkObjects(WorkshopActors as workshopnpcscript, Self, False) I += 1 EndWhile EndIf Self.DailyUpdateProduceResources(ratings, updateData, containerRef, bRealUpdate) Self.DailyUpdateConsumeResources(ratings, updateData, containerRef, bRealUpdate) If (bRealUpdate) Self.DailyUpdateSurplusResources(ratings, updateData, containerRef) Self.RepairDamage() Self.RecalculateWorkshopResources(True) Self.CheckForAttack(False) EndIf If (updateData.totalPopulation >= WorkshopParent.TradeCaravanMinimumPopulation && Self.GetValue(ratings[WorkshopParent.WorkshopRatingCaravan].resourceValue) > 0 as float) WorkshopParent.TradeCaravanWorkshops.AddRef(Self as ObjectReference) Else WorkshopParent.TradeCaravanWorkshops.RemoveRef(Self as ObjectReference) EndIf WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\tDAILY UPDATE - DONE - bRbRealUpdate=" + bRealUpdate as string, 0, True) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) bDailyUpdateInProgress = False WorkshopParent.DailyUpdateInProgress = False EndFunction Function CheckOwnership() If (myLocation.IsCleared() && !OwnedByPlayer && EnableAutomaticPlayerOwnership) Self.SetOwnedByPlayer(True) EndIf If (!OwnedByPlayer) If (CustomUnownedMessage) CustomUnownedMessage.Show(0, 0, 0, 0, 0, 0, 0, 0, 0) Else int totalPopulation = Self.GetBaseValue(WorkshopParent.WorkshopRatings[WorkshopParent.WorkshopRatingPopulation].resourceValue) as int If (totalPopulation > 0) WorkshopParent.WorkshopUnownedSettlementMessage.Show(0, 0, 0, 0, 0, 0, 0, 0, 0) ElseIf (myLocation.IsCleared() == False && EnableAutomaticPlayerOwnership) WorkshopParent.WorkshopUnownedHostileMessage.Show(0, 0, 0, 0, 0, 0, 0, 0, 0) Else WorkshopParent.WorkshopUnownedMessage.Show(0, 0, 0, 0, 0, 0, 0, 0, 0) EndIf EndIf EndIf EndFunction Event OnLoad() Self.BlockActivation(!OwnedByPlayer, False) If (Self.GetBaseObject() as Container) ObjectReference linkedContainer = Self.GetLinkedRef(WorkshopParent.WorkshopLinkContainer) If (linkedContainer) linkedContainer.RemoveAllItems(Self as ObjectReference, False) EndIf ObjectReference[] linkedContainers = Self.GetLinkedRefChildren(WorkshopParent.WorkshopLinkContainer) int I = 0 While (I < linkedContainers.length) linkedContainer = linkedContainers If (linkedContainer) linkedContainer.RemoveAllItems(Self as ObjectReference, False) EndIf I += 1 EndWhile EndIf If (!myLocation) myLocation = Self.GetCurrentLocation() EndIf EndEvent Event OnTimer(int aiTimerID) If (aiTimerID == buildWorkObjectTimerID) WorkshopParent.TryToAssignResourceObjectsPUBLIC(Self) EndIf EndEvent ObjectReference Function GetContainer() If (Self.GetBaseObject() as Container) return Self as ObjectReference Else return Self.GetLinkedRef(WorkshopParent.WorkshopLinkContainer) EndIf EndFunction Event OnWorkshopObjectPlaced(ObjectReference akReference) If (WorkshopParent.BuildObjectPUBLIC(akReference, Self)) Self.StartTimer(3, buildWorkObjectTimerID) EndIf EndEvent Event OnWorkshopMode(bool aStart) If (aStart) If (OwnedByPlayer) WorkshopParent.SetCurrentWorkshop(Self) EndIf var[] kargs = new var[2] kargs[0] = None kargs[1] = Self as var WorkshopParent.SendCustomEvent("workshopparentscript_WorkshopEnterMenu", kargs) EndIf If (aStart && WorkshopParent.DogmeatAlias.GetRef() as bool) WorkshopParent.WorkshopDogmeatWhileBuildingScene.Start() Else WorkshopParent.WorkshopDogmeatWhileBuildingScene.Stop() EndIf If (aStart && WorkshopParent.CompanionAlias.GetRef() as bool) WorkshopParent.WorkshopCompanionWhileBuildingScene.Start() Else WorkshopParent.WorkshopCompanionWhileBuildingScene.Stop() EndIf If (!aStart) If (ShowedWorkshopMenuExitMessage == False) ShowedWorkshopMenuExitMessage = True WorkshopParent.WorkshopExitMenuMessage.ShowAsHelpMessage("WorkshopMenuExit", 10, 0 as float, 1, "NoMenu", 0) EndIf WorkshopParent.TryToAssignResourceObjectsPUBLIC(Self) EndIf Self.DailyUpdate(False) EndEvent Function DailyUpdateProduceResources(workshopdatascript#workshopratingkeyword[] ratings, workshopscript#dailyupdatedata updateData, ObjectReference containerRef, bool bRealUpdate) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\tProduce resources: ", 0, False) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) updateData.foodProduction = Self.GetValue(ratings[WorkshopParent.WorkshopRatingFood].resourceValue) as int updateData.waterProduction = Self.GetValue(ratings[WorkshopParent.WorkshopRatingWater].resourceValue) as int WorkshopParent.wsTrace(Self as string + "\t\t\tBase food: " + updateData.foodProduction as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\t\tBase water: " + updateData.waterProduction as string, 0, False) int missingSafety = Math.max(0 as float, (updateData.totalPopulation - updateData.safety) as float) as int WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingMissingSafety].resourceValue, Self, missingSafety as float) updateData.foodProduction = Math.max(0 as float, (updateData.foodProduction - Self.GetValue(WorkshopParent.GetDamageRatingValue(ratings[WorkshopParent.WorkshopRatingFood].resourceValue)) as int) as float) as int updateData.waterProduction = Math.max(0 as float, (updateData.waterProduction - Self.GetValue(WorkshopParent.GetDamageRatingValue(ratings[WorkshopParent.WorkshopRatingWater].resourceValue)) as int) as float) as int If (updateData.brahminPopulation > 0) int brahminMaxFoodBoost = Math.min((updateData.brahminPopulation * maxProductionPerBrahmin) as float, updateData.foodProduction as float) as int int brahminFoodProduction = Math.Ceiling(brahminMaxFoodBoost as float * brahminProductionBoost) WorkshopParent.wsTrace(Self as string + "\t\t\tBrahmin food boost: " + brahminFoodProduction as string, 0, False) updateData.foodProduction = updateData.foodProduction + brahminFoodProduction EndIf WorkshopParent.SetResourceData(ratings[WorkshopParent.WorkshopRatingFoodActual].resourceValue, Self, updateData.foodProduction as float) WorkshopParent.wsTrace(Self as string + "\t\t\tActual production:", 0, False) WorkshopParent.wsTrace(Self as string + "\t\t\t\tFood: " + updateData.foodProduction as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\t\t\tWater: " + updateData.waterProduction as string, 0, False) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) WorkshopParent.wsTrace(Self as string + "\tConsume resources and calculate happiness: ", 0, False) WorkshopParent.wsTrace(Self as string + "------------------------------------------------------------------------------ ", 0, False) updateData.safety = Math.max((updateData.safety - updateData.safetyDamage) as float, 0 as float) as int updateData.safetyPerNPC = 0 If (updateData.totalPopulation > 0) updateData.safetyPerNPC = Math.Ceiling((updateData.safety / updateData.totalPopulation) as float) EndIf updateData.availableFood = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeFood as Form) updateData.availableWater = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeWater as Form) WorkshopParent.wsTrace(Self as string + "\tStarting stats:", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tpopulation=" + updateData.totalPopulation as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\tfood=" + updateData.availableFood as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\twater=" + updateData.availableWater as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\tbeds=" + updateData.availableBeds as string + " (" + updateData.shelteredBeds as string + " sheltered)", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tbonus happiness=" + updateData.bonusHappiness as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\ttotal safety=" + updateData.safety as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\tsafety per NPC=" + updateData.safetyPerNPC as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\tunassignedPopulation=" + updateData.unassignedPopulation as string, 0, False) updateData.availableFood = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeFood as Form) + updateData.foodProduction updateData.availableWater = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeWater as Form) + updateData.waterProduction WorkshopParent.wsTrace(Self as string + "\tAfter production:", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tfood=" + updateData.availableFood as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\twater=" + updateData.availableWater as string, 0, False) int neededFood = updateData.totalPopulation - updateData.robotPopulation - updateData.availableFood int neededWater = updateData.totalPopulation - updateData.robotPopulation - updateData.availableWater If (neededFood > 0 || neededWater > 0) WorkshopParent.wsTrace(Self as string + "\tResource shortage - try to get from linked workshops:", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tfood=" + neededFood as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\twater=" + neededWater as string, 0, False) WorkshopParent.TransferResourcesFromLinkedWorkshops(Self, neededFood, neededWater) EndIf updateData.availableFood = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeFood as Form) + updateData.foodProduction updateData.availableWater = containerRef.GetItemCount(WorkshopParent.WorkshopConsumeWater as Form) + updateData.waterProduction WorkshopParent.wsTrace(Self as string + "\tFinal stats after transfers:", 0, False) WorkshopParent.wsTrace(Self as string + "\t\tfood=" + updateData.availableFood as string, 0, False) WorkshopParent.wsTrace(Self as string + "\t\twater=" + updateData.availableWater as string, 0, False) EndFunction bool Function RecalculateWorkshopResources(bool bOnlyIfLocationLoaded) If (bOnlyIfLocationLoaded == False || myLocation.IsLoaded()) Self.RecalculateResources() return True Else return False EndIf EndFunction Function InitWorkshopID(int newWorkshopID) If (WorkshopID < 0) WorkshopID = newWorkshopID EndIf EndFunction float Function CalculateRepairAmount(workshopdatascript#workshopratingkeyword[] ratings) float uninjuredPopulation = Self.GetValue(ratings[WorkshopParent.WorkshopRatingPopulation].resourceValue) float productivityMult = Self.GetProductivityMultiplier(ratings) float amountRepaired = Math.Ceiling(uninjuredPopulation * damageDailyPopulationMult * damageDailyRepairBase * productivityMult) as float return amountRepaired EndFunction ObjectReference[] Function GetVendorContainersByType(int vendorType) If (vendorType == 0) If (VendorContainersMisc == None) VendorContainersMisc = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersMisc ElseIf (vendorType == 1) If (VendorContainersArmor == None) VendorContainersArmor = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersArmor ElseIf (vendorType == 2) If (VendorContainersWeapons == None) VendorContainersWeapons = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersWeapons ElseIf (vendorType == 3) If (VendorContainersBar == None) VendorContainersBar = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersBar ElseIf (vendorType == 4) If (VendorContainersClinic == None) VendorContainersClinic = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersClinic ElseIf (vendorType == 5) If (VendorContainersClothing == None) VendorContainersClothing = Self.InitializeVendorChests(vendorType) EndIf return VendorContainersClothing EndIf EndFunction Event OnActivate(ObjectReference akActionRef) If (akActionRef == Game.GetPlayer() as ObjectReference) Self.CheckOwnership() If (OwnedByPlayer) Self.StartWorkshop(True) EndIf EndIf EndEvent Event WorkshopParentScript.WorkshopDailyUpdate(workshopparentscript akSender, var[] akArgs) float waitTime = WorkshopParent.dailyUpdateIncrement * WorkshopID as float Self.StartTimerGameTime(waitTime, dailyUpdateTimerID) EndEvent By the way I was able to decompile the script and see its source code. Maybe that can tell something Link to comment Share on other sites More sharing options...
jjb54 Posted February 1 Share Posted February 1 9 hours ago, strusik said: The thing is, I wouldn't say the mod itself was breaking my game. Everything worked when it was installed, the problems started after I uninstalled it (I tracked it down through my save history), I have a theory that I might be able to get it working again if I can figure out which files in the root folder of the game are responsible for the workshop and replace them with vanilla files (my ideas on this might seem strange to you, but I think it should work), since I think the mod overwrote something and now it refuses to work without it Well I did read a lot of posts that shared a whole number of problems and issues w/the mod in question ... again, sadly .... that does not speak well for the mod and it's likely reason. As one person suggested: If you have a prior game before the mod was installed try it, ( though based on my reading the specific posts in the Mod Site in question ... ) I'm not sure that's going to work .. but, yes, give it a try. I had one person tell me ... he had tried a mod that really had NOTHING to do with setting up settlement quests ... until this mod he tried. Screwed up so he only got three ( Settlement set up quests ) and the rest were locked out. He actually had to do a total clean install of FO 4 , which took him seriously out of his ".. happy place .." Link to comment Share on other sites More sharing options...
strusik Posted February 2 Author Share Posted February 2 42 minutes ago, jjb54 said: Well I did read a lot of posts that shared a whole number of problems and issues w/the mod in question ... again, sadly .... that does not speak well for the mod and it's likely reason. As one person suggested: If you have a prior game before the mod was installed try it, ( though based on my reading the specific posts in the Mod Site in question ... ) I'm not sure that's going to work .. but, yes, give it a try. I had one person tell me ... he had tried a mod that really had NOTHING to do with setting up settlement quests ... until this mod he tried. Screwed up so he only got three ( Settlement set up quests ) and the rest were locked out. He actually had to do a total clean install of FO 4 , which took him seriously out of his ".. happy place .." I think I'm going to have to start my walkthrough all over again too. Actually, I always look and read carefully everything about a mod when I want to install it, and in general I have a very good collection of mods, with which there were no problems. But apparently, when I downloaded this s#*!, I did it late at night and tired, and at this fateful moment did not pay attention. This "good" author ended up breaking another mod for me first, and after I tried to fix it, he broke my game as well It's a pity that on nexus there are so many such mods, which are not moderated in any way, it would be great to have something like a rating system, where shitty mods that have low ratings would be removed from the site Link to comment Share on other sites More sharing options...
subaverage Posted February 2 Share Posted February 2 If you want to have more settlement attacks you can try this one: https://www.mediafire.com/file/4ibjnbfpl4tv0uk/More_Attackers_-_Get_Off_My_Buildzone-27465-1-1-7.7z/file It has MCM support and let's attackers spawn out of your buildzone. If you want to try please make a save before and perhaps a copy of it. I use this mod since many years and never experienced any problem with it, but I do not use Sim Settlements. Link to comment Share on other sites More sharing options...
strusik Posted February 2 Author Share Posted February 2 3 hours ago, subaverage said: If you want to have more settlement attacks you can try this one: https://www.mediafire.com/file/4ibjnbfpl4tv0uk/More_Attackers_-_Get_Off_My_Buildzone-27465-1-1-7.7z/file It has MCM support and let's attackers spawn out of your buildzone. If you want to try please make a save before and perhaps a copy of it. I use this mod since many years and never experienced any problem with it, but I do not use Sim Settlements. Thanks for the recommendation, I've already had time to install another mod in the meantime: https://www.nexusmods.com/fallout4/mods/37393 It is also quite good and has compatibility with Sim Settlements 2 and allows you to create really huge raids on half a hundred opponents and even more (it can be customized in the mod itself) Link to comment Share on other sites More sharing options...
jjb54 Posted February 3 Share Posted February 3 On 2/1/2024 at 4:37 PM, strusik said: I think I'm going to have to start my walkthrough all over again too. Actually, I always look and read carefully everything about a mod when I want to install it, and in general I have a very good collection of mods, with which there were no problems. But apparently, when I downloaded this s#*!, I did it late at night and tired, and at this fateful moment did not pay attention. This "good" author ended up breaking another mod for me first, and after I tried to fix it, he broke my game as well It's a pity that on nexus there are so many such mods, which are not moderated in any way, it would be great to have something like a rating system, where shitty mods that have low ratings would be removed from the site Cannot tell you how many times I've done that very thing, only to kick myself in the butt for doing it! So I totally understand as I have "been there done that" also. Link to comment Share on other sites More sharing options...
strusik Posted February 3 Author Share Posted February 3 9 hours ago, jjb54 said: Cannot tell you how many times I've done that very thing, only to kick myself in the butt for doing it! So I totally understand as I have "been there done that" also. Well, nothing to do, these mods are like a drug, first installed one and then you can not stop, haha the process of installing and searching for mods for me bring more fun than the game itself. We're junkies and sometimes we get some bad shіt Link to comment Share on other sites More sharing options...
Recommended Posts