@@ -9,7 +9,7 @@ import { filestore, serverConfig } from '@server/game';
99import {
1010 findMusicTrack , findNpc , findSongIdByRegionId , musicRegions , equipmentIndex ,
1111 EquipmentSlot , getEquipmentSlot , ItemDetails , findItem , findQuest ,
12- npcIdMap , widgets , NpcDetails , PlayerQuest , QuestKey
12+ npcIdMap , widgets , NpcDetails , PlayerQuest , QuestKey , itemMap
1313} from '@engine/config' ;
1414import { daysSinceLastLogin , colors , hexToRgb , rgbTo16Bit , getVarbitMorphIndex } from '@engine/util' ;
1515import { OutboundPacketHandler , Isaac } from '@engine/net' ;
@@ -460,6 +460,25 @@ export class Player extends Actor {
460460 return playerQuest ;
461461 }
462462
463+ /**
464+ * Checks if the player has unlocked the required stage of a quest
465+ * @param questId The ID of the quest to find the player's status on.
466+ * @param minimumStage The minimum quest stage required, defaults to completed
467+ * @return boolean if the player has reached the required stage, if the quest does not exist it defaults to true
468+ */
469+ public hasQuestRequirement ( questId : string , minimumStage : QuestKey = 'complete' ) : boolean {
470+ if ( ! questMap [ questId ] ) {
471+ logger . warn ( `Quest data not found for ${ questId } ` ) ;
472+ return true ;
473+ }
474+ let playerQuest = this . quests . find ( quest => quest . questId === questId ) ;
475+ if ( ! playerQuest ) {
476+ playerQuest = new PlayerQuest ( questId ) ;
477+ this . quests . push ( playerQuest ) ;
478+ }
479+ return playerQuest . progress === minimumStage || playerQuest . progress >= minimumStage ;
480+ }
481+
463482 /**
464483 * Sets a player's quest progress to the specified value.
465484 * @param questId The ID of the quest to set the progress of.
@@ -831,31 +850,36 @@ export class Player extends Actor {
831850 return this . equipment . items [ equipmentIndex ( equipmentSlot ) ] || null ;
832851 }
833852
834- public canEquipItem ( item : ItemDetails ) : boolean {
835- const requirements = item . equipmentData ?. requirements ;
836- if ( ! requirements ) return true ;
837-
838- const hasSkillRequirements = Object . entries ( requirements . skills || { } ) . every ( ( [ skill , level ] ) => this . skills . hasLevel ( skill as SkillName , level ) ) ;
839- const hasQuestRequirements = Object . entries ( requirements . quests || { } ) . every ( ( [ quest , stage ] ) => this . getQuest ( quest ) . progress >= stage ) ;
840853
841- return hasSkillRequirements && hasQuestRequirements ;
842- }
843-
844- public missingItemEquipRequirements ( item : ItemDetails ) : string [ ] {
854+ /**
855+ * Check if a player can equip an item
856+ * @param item either an ItemDetails instance or the string id of the item to be checked
857+ * @return {equipable: boolean, missingRequirements: string[] } equipable is false if for any reason the item can not
858+ * be equipped, if it can not be equipped, a list of reasons are attached as the missingRequirements array
859+ *
860+ * defaults to equipable=true if the item string id does not exist
861+ */
862+ public canEquipItem ( item : ItemDetails | string ) : { equipable : boolean , missingRequirements ?: string [ ] } {
863+ if ( typeof item === 'string' ) {
864+ item = itemMap [ item ] ;
865+ if ( ! item ) {
866+ return { equipable : true }
867+ }
868+ }
845869 const missingRequirements = [ ] ;
846870 const requirements = item . equipmentData ?. requirements ;
847- if ( ! requirements ) return missingRequirements ;
871+ if ( ! requirements ) return { equipable : true } ;
848872
849873 missingRequirements . push (
850874 ...Object . entries ( requirements . skills || { } )
851875 . filter ( ( [ skill , level ] ) => ! this . skills . hasLevel ( skill as SkillName , level ) )
852876 . map ( ( [ skill , level ] ) => `You need to be at least level ${ level } ${ skill } to equip this item.` ) ,
853877 ...Object . entries ( requirements . quests || { } )
854- . filter ( ( [ quest , stage ] ) => this . getQuest ( quest ) . progress < stage )
855- . map ( ( [ quest ] ) => `You must progress further in the ${ quest . replace ( / _ / g, ' ' ) } quest to equip this item.` )
878+ . filter ( ( [ quest , stage ] ) => this . hasQuestRequirement ( quest , stage ) )
879+ . map ( ( [ quest ] ) => `You must progress further in the ${ quest . replace ( / ^ ( [ a - z ] + : ) / gm , '' ) . replace ( / _ / g, ' ' ) } quest to equip this item.` )
856880 ) ;
857881
858- return missingRequirements ;
882+ return { equipable : missingRequirements . length === 0 , missingRequirements : missingRequirements } ;
859883 }
860884
861885 public equipItem ( itemId : number , itemSlot : number , slot : EquipmentSlot | number ) : boolean {
@@ -884,9 +908,11 @@ export class Player extends Actor {
884908 return ;
885909 }
886910
887- const missingRequirements = this . missingItemEquipRequirements ( itemDetails ) ;
888- if ( missingRequirements . length ) {
889- missingRequirements . forEach ( s => { this . sendMessage ( s ) } ) ;
911+ const equippable = this . canEquipItem ( itemDetails ) ;
912+ if ( ! equippable . equipable ) {
913+ if ( equippable . missingRequirements ) {
914+ equippable . missingRequirements . forEach ( async ( s ) => this . sendMessage ( s ) ) ;
915+ }
890916 return ;
891917 }
892918
0 commit comments