Partially implemented RepeatableQuestController
This commit is contained in:
@@ -7,6 +7,7 @@ using Core.Models.Spt.Config;
|
||||
using Core.Models.Spt.Repeatable;
|
||||
using Core.Generators;
|
||||
using Core.Helpers;
|
||||
using Core.Models.Enums;
|
||||
using Core.Models.Utils;
|
||||
using Core.Routers;
|
||||
using Core.Servers;
|
||||
@@ -32,9 +33,10 @@ public class RepeatableQuestController
|
||||
protected RepeatableQuestGenerator _repeatableQuestGenerator;
|
||||
protected RepeatableQuestHelper _repeatableQuestHelper;
|
||||
protected QuestHelper _questHelper;
|
||||
protected DatabaseService _databaseService;
|
||||
protected ConfigServer _configServer;
|
||||
protected ICloner _cloner;
|
||||
private readonly QuestConfig _questConfig;
|
||||
protected QuestConfig _questConfig;
|
||||
|
||||
public RepeatableQuestController(
|
||||
ISptLogger<RepeatableQuestChangeRequest> logger,
|
||||
@@ -50,6 +52,7 @@ public class RepeatableQuestController
|
||||
RepeatableQuestGenerator repeatableQuestGenerator,
|
||||
RepeatableQuestHelper repeatableQuestHelper,
|
||||
QuestHelper questHelper,
|
||||
DatabaseService databaseService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner)
|
||||
{
|
||||
@@ -66,6 +69,7 @@ public class RepeatableQuestController
|
||||
_repeatableQuestGenerator = repeatableQuestGenerator;
|
||||
_repeatableQuestHelper = repeatableQuestHelper;
|
||||
_questHelper = questHelper;
|
||||
_databaseService = databaseService;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
|
||||
@@ -190,26 +194,230 @@ public class RepeatableQuestController
|
||||
|
||||
private PmcDataRepeatableQuest GetRepeatableQuestSubTypeFromProfile(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Get from profile, add if missing
|
||||
var repeatableQuestDetails = pmcData.RepeatableQuests.FirstOrDefault(
|
||||
(repeatable) => repeatable.Name == repeatableConfig.Name);
|
||||
if (repeatableQuestDetails is not null)
|
||||
{
|
||||
// Not in profile, generate
|
||||
var hasAccess = _profileHelper.HasAccessToRepeatableFreeRefreshSystem(pmcData);
|
||||
repeatableQuestDetails = new PmcDataRepeatableQuest(){
|
||||
Id = repeatableConfig.Id,
|
||||
Name= repeatableConfig.Name,
|
||||
ActiveQuests= [],
|
||||
InactiveQuests= [],
|
||||
EndTime= 0,
|
||||
ChangeRequirement= { },
|
||||
FreeChanges= hasAccess? repeatableConfig.FreeChanges: 0,
|
||||
FreeChangesAvailable= hasAccess? repeatableConfig.FreeChangesAvailable: 0,
|
||||
};
|
||||
|
||||
// Add base object that holds repeatable data to profile
|
||||
pmcData.RepeatableQuests.Add(repeatableQuestDetails);
|
||||
}
|
||||
|
||||
return repeatableQuestDetails;
|
||||
}
|
||||
|
||||
private bool CanProfileAccessRepeatableQuests(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// PMC and daily quests not unlocked yet
|
||||
if (repeatableConfig.Side == "Pmc" && !PlayerHasDailyPmcQuestsUnlocked(pmcData, repeatableConfig))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scav and daily quests not unlocked yet
|
||||
if (repeatableConfig.Side == "Scav" && !PlayerHasDailyScavQuestsUnlocked(pmcData))
|
||||
{
|
||||
_logger.Debug("Daily scav quests still locked, Intel center not built");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does player have daily pmc quests unlocked
|
||||
* @param pmcData Player profile to check
|
||||
* @param repeatableConfig Config of daily type to check
|
||||
* @returns True if unlocked
|
||||
*/
|
||||
private bool PlayerHasDailyPmcQuestsUnlocked(PmcData pmcData, RepeatableQuestConfig repeatableConfig)
|
||||
{
|
||||
return pmcData.Info.Level >= repeatableConfig.MinPlayerLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does player have daily scav quests unlocked
|
||||
* @param pmcData Player profile to check
|
||||
* @returns True if unlocked
|
||||
*/
|
||||
private bool PlayerHasDailyScavQuestsUnlocked(PmcData pmcData)
|
||||
{
|
||||
return (
|
||||
pmcData?.Hideout?.Areas?.FirstOrDefault((hideoutArea) => hideoutArea.Type == HideoutAreas.INTEL_CENTER)?.Level >= 1
|
||||
);
|
||||
}
|
||||
|
||||
private void ProcessExpiredQuests(PmcDataRepeatableQuest generatedRepeatables, PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var questsToKeep = new List<RepeatableQuest>();
|
||||
foreach (var activeQuest in generatedRepeatables.ActiveQuests) {
|
||||
var questStatusInProfile = pmcData.Quests.FirstOrDefault((quest) => quest.QId == activeQuest.Id);
|
||||
if (questStatusInProfile is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Keep finished quests in list so player can hand in
|
||||
if (questStatusInProfile.Status == QuestStatusEnum.AvailableForFinish)
|
||||
{
|
||||
questsToKeep.Add(activeQuest);
|
||||
_logger.Debug($"Keeping repeatable quest: ${ activeQuest.Id} in activeQuests since it is available to hand in");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clean up quest-related counters being left in profile
|
||||
_profileFixerService.RemoveDanglingConditionCounters(pmcData);
|
||||
|
||||
// Remove expired quest from pmc.quest array
|
||||
pmcData.Quests = pmcData.Quests.Where((quest) => quest.QId != activeQuest.Id).ToList();
|
||||
|
||||
// Store in inactive array
|
||||
generatedRepeatables.InactiveQuests.Add(activeQuest);
|
||||
}
|
||||
|
||||
generatedRepeatables.ActiveQuests = questsToKeep;
|
||||
}
|
||||
|
||||
private QuestTypePool GenerateQuestPool(RepeatableQuestConfig repeatableConfig, double? infoLevel)
|
||||
private QuestTypePool GenerateQuestPool(RepeatableQuestConfig repeatableConfig, int? pmcLevel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var questPool = CreateBaseQuestPool(repeatableConfig);
|
||||
|
||||
// Get the allowed locations based on the PMC's level
|
||||
var locations = GetAllowedLocationsForPmcLevel(repeatableConfig.Locations, pmcLevel.Value);
|
||||
|
||||
// Populate Exploration and Pickup quest locations
|
||||
foreach (var location in locations) {
|
||||
if (location.Key != ELocationName.any)
|
||||
{
|
||||
questPool.Pool.Exploration.Locations[location.Key] = location.Value;
|
||||
questPool.Pool.Pickup.Locations[location.Key] = location.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Add "any" to pickup quest pool
|
||||
questPool.Pool.Pickup.Locations[ELocationName.any] = ["any"];
|
||||
|
||||
var eliminationConfig = _repeatableQuestHelper.GetEliminationConfigByPmcLevel(pmcLevel.Value, repeatableConfig);
|
||||
var targetsConfig = _repeatableQuestHelper.ProbabilityObjectArray<string, BossInfo>(eliminationConfig.Targets);
|
||||
|
||||
// Populate Elimination quest targets and their locations
|
||||
foreach (var target in targetsConfig) {
|
||||
// Target is boss
|
||||
//if (target.isBoss)
|
||||
//{
|
||||
// questPool.Pool.Elimination.Targets[targetKey] = new { locations: ["any"] };
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // Non-boss targets
|
||||
// var possibleLocations = locations;
|
||||
|
||||
// var allowedLocations =
|
||||
// targetKey == "Savage"
|
||||
// ? possibleLocations.filter((location) => location != "laboratory") // Exclude labs for Savage targets.
|
||||
// : possibleLocations;
|
||||
|
||||
// questPool.Pool.Elimination.Targets[targetKey] = new { Locations = allowedLocations };
|
||||
//}
|
||||
_logger.Error("NOT IMPLEMENTED - GenerateQuestPool");
|
||||
}
|
||||
|
||||
return questPool;
|
||||
}
|
||||
|
||||
private QuestTypePool CreateBaseQuestPool(RepeatableQuestConfig repeatableConfig)
|
||||
{
|
||||
return new QuestTypePool
|
||||
{
|
||||
Types = _cloner.Clone(repeatableConfig.Types),
|
||||
Pool = new QuestPool
|
||||
{
|
||||
Exploration = new ExplorationPool
|
||||
{
|
||||
Locations = new Dictionary<ELocationName, List<string>>()
|
||||
},
|
||||
Elimination = new EliminationPool
|
||||
{
|
||||
Targets = new EliminationTargetPool()
|
||||
},
|
||||
Pickup = new ExplorationPool
|
||||
{
|
||||
Locations = new Dictionary<ELocationName, List<string>>()
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private Dictionary<ELocationName, List<string>> GetAllowedLocationsForPmcLevel(Dictionary<ELocationName, List<string>> locations, int pmcLevel)
|
||||
{
|
||||
var allowedLocation = new Dictionary<ELocationName, List<string>>();
|
||||
|
||||
foreach (var locationKvP in locations) {
|
||||
var locationNames = new List<string>();
|
||||
foreach (var locationName in locationKvP.Value) {
|
||||
if (IsPmcLevelAllowedOnLocation(locationName, pmcLevel))
|
||||
{
|
||||
locationNames.Add(locationName);
|
||||
}
|
||||
}
|
||||
|
||||
if (locationNames.Count > 0)
|
||||
{
|
||||
allowedLocation[locationKvP.Key] = locationNames;
|
||||
}
|
||||
}
|
||||
|
||||
return allowedLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given pmcLevel is allowed on the given location
|
||||
* @param location The location name to check
|
||||
* @param pmcLevel The level of the pmc
|
||||
* @returns True if the given pmc level is allowed to access the given location
|
||||
*/
|
||||
protected bool IsPmcLevelAllowedOnLocation(string location, int pmcLevel) {
|
||||
// All PMC levels are allowed for 'any' location requirement
|
||||
if (location == ELocationName.any.ToString()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var locationBase = _databaseService.GetLocation(location.ToLower())?.Base;
|
||||
if (locationBase is not null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return pmcLevel <= locationBase.RequiredPlayerLevelMax && pmcLevel >= locationBase.RequiredPlayerLevelMin;
|
||||
}
|
||||
|
||||
private int GetQuestCount(RepeatableQuestConfig repeatableConfig, PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (repeatableConfig.Name.ToLower() == "daily"
|
||||
&& _profileHelper.HasEliteSkillLevel(SkillTypes.Charisma, pmcData)
|
||||
)
|
||||
{
|
||||
// Elite charisma skill gives extra daily quest(s)
|
||||
return (repeatableConfig.NumQuests +
|
||||
_databaseService.GetGlobals().Configuration.SkillsSettings.Charisma.BonusSettings.EliteBonusSettings
|
||||
.RepeatableQuestExtraCount.GetValueOrDefault(0)
|
||||
);
|
||||
}
|
||||
|
||||
return repeatableConfig.NumQuests;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
using Core.Annotations;
|
||||
using Core.Annotations;
|
||||
using Core.Models.Spt.Config;
|
||||
using Core.Models.Utils;
|
||||
|
||||
namespace Core.Helpers;
|
||||
|
||||
[Injectable]
|
||||
public class RepeatableQuestHelper
|
||||
{
|
||||
protected ISptLogger<RepeatableQuestHelper> _logger;
|
||||
|
||||
public RepeatableQuestHelper(
|
||||
ISptLogger<RepeatableQuestHelper> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the relevant elimination config based on the current players PMC level
|
||||
/// </summary>
|
||||
@@ -19,8 +28,16 @@ public class RepeatableQuestHelper
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object ProbabilityObjectArray<K, V>(object configArrayInput) // TODO: ProbabilityObjectArray<K, V> for return type , param type was List<ProbabilityObject<K, V>>
|
||||
public Dictionary<K, ProbabilityData<V>> ProbabilityObjectArray<K, V>(object configArrayInput) // TODO: ProbabilityObjectArray<K, V> for return type , param type was List<ProbabilityObject<K, V>>
|
||||
{
|
||||
_logger.Error("Fuck this in particular, go look up ProbabilityObjectArray in node server, candidate for rewrite");
|
||||
throw new NotImplementedException();
|
||||
var x = new Dictionary<K, ProbabilityData<V>>();
|
||||
}
|
||||
|
||||
public class ProbabilityData<T>
|
||||
{
|
||||
public int RelativeProbability { get; set; }
|
||||
public T Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3662,7 +3662,7 @@ public class EliteBonusSettings
|
||||
public double? FenceStandingLossDiscount { get; set; }
|
||||
|
||||
[JsonPropertyName("RepeatableQuestExtraCount")]
|
||||
public double? RepeatableQuestExtraCount { get; set; }
|
||||
public int? RepeatableQuestExtraCount { get; set; }
|
||||
|
||||
[JsonPropertyName("ScavCaseDiscount")]
|
||||
public double? ScavCaseDiscount { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user