Skip to content

Commit

Permalink
Merge pull request runejs#357 from runejs/feature/quest-requirements
Browse files Browse the repository at this point in the history
quest requirements small expansion
  • Loading branch information
Promises authored Oct 14, 2021
2 parents 6335a09 + e0266c3 commit bb4f096
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"equipment_type": "one_handed",
"requirements": {
"quests": {
"goblin_diplomacy": 20
"tyn:goblin_diplomacy": 20
}
},
"offensive_bonuses": {
Expand Down
5 changes: 5 additions & 0 deletions data/config/items/equipment/standard-metals/rune-armour.json
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@
"crush": 72,
"magic": -6,
"ranged": 80
},
"requirements": {
"quests" : {
"rs:dragon_slayer": "complete"
}
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions data/config/items/equipment/standard-metals/rune-god-armour.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@
"crush": 72,
"magic": -6,
"ranged": 80
},
"requirements": {
"quests" : {
"rs:dragon_slayer": "complete"
}
}
}
},
Expand Down Expand Up @@ -222,6 +227,11 @@
"crush": 72,
"magic": -6,
"ranged": 80
},
"requirements": {
"quests" : {
"rs:dragon_slayer": "complete"
}
}
}
},
Expand Down Expand Up @@ -327,6 +337,11 @@
"crush": 72,
"magic": -6,
"ranged": 80
},
"requirements": {
"quests" : {
"rs:dragon_slayer": "complete"
}
}
}
}
Expand Down
62 changes: 44 additions & 18 deletions src/engine/world/actor/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { filestore, serverConfig } from '@server/game';
import {
findMusicTrack, findNpc, findSongIdByRegionId, musicRegions, equipmentIndex,
EquipmentSlot, getEquipmentSlot, ItemDetails, findItem, findQuest,
npcIdMap, widgets, NpcDetails, PlayerQuest, QuestKey
npcIdMap, widgets, NpcDetails, PlayerQuest, QuestKey, itemMap
} from '@engine/config';
import { daysSinceLastLogin, colors, hexToRgb, rgbTo16Bit,getVarbitMorphIndex } from '@engine/util';
import { OutboundPacketHandler, Isaac } from '@engine/net';
Expand Down Expand Up @@ -460,6 +460,25 @@ export class Player extends Actor {
return playerQuest;
}

/**
* Checks if the player has unlocked the required stage of a quest
* @param questId The ID of the quest to find the player's status on.
* @param minimumStage The minimum quest stage required, defaults to completed
* @return boolean if the player has reached the required stage, if the quest does not exist it defaults to true
*/
public hasQuestRequirement(questId: string, minimumStage: QuestKey = 'complete'): boolean {
if(!questMap[questId]) {
logger.warn(`Quest data not found for ${questId}`);
return true;
}
let playerQuest = this.quests.find(quest => quest.questId === questId);
if(!playerQuest) {
playerQuest = new PlayerQuest(questId);
this.quests.push(playerQuest);
}
return playerQuest.progress === minimumStage || playerQuest.progress >= minimumStage;
}

/**
* Sets a player's quest progress to the specified value.
* @param questId The ID of the quest to set the progress of.
Expand Down Expand Up @@ -831,31 +850,36 @@ export class Player extends Actor {
return this.equipment.items[equipmentIndex(equipmentSlot)] || null;
}

public canEquipItem(item: ItemDetails): boolean {
const requirements = item.equipmentData?.requirements;
if (!requirements) return true;

const hasSkillRequirements = Object.entries(requirements.skills || {}).every(([skill, level]) => this.skills.hasLevel(skill as SkillName, level));
const hasQuestRequirements = Object.entries(requirements.quests || {}).every(([quest, stage]) => this.getQuest(quest).progress >= stage);

return hasSkillRequirements && hasQuestRequirements;
}

public missingItemEquipRequirements(item: ItemDetails): string[] {
/**
* Check if a player can equip an item
* @param item either an ItemDetails instance or the string id of the item to be checked
* @return {equipable: boolean, missingRequirements: string[]} equipable is false if for any reason the item can not
* be equipped, if it can not be equipped, a list of reasons are attached as the missingRequirements array
*
* defaults to equipable=true if the item string id does not exist
*/
public canEquipItem(item: ItemDetails | string): { equipable: boolean, missingRequirements?: string[] } {
if(typeof item === 'string') {
item = itemMap[item];
if(!item) {
return { equipable: true }
}
}
const missingRequirements = [];
const requirements = item.equipmentData?.requirements;
if (!requirements) return missingRequirements;
if (!requirements) return { equipable: true };

missingRequirements.push(
...Object.entries(requirements.skills || {})
.filter(([skill, level]) => !this.skills.hasLevel(skill as SkillName, level))
.map(([skill, level]) => `You need to be at least level ${level} ${skill} to equip this item.`),
...Object.entries(requirements.quests || {})
.filter(([quest, stage]) => this.getQuest(quest).progress < stage)
.map(([quest]) => `You must progress further in the ${quest.replace(/_/g, ' ')} quest to equip this item.`)
.filter(([quest, stage]) => this.hasQuestRequirement(quest, stage))
.map(([quest]) => `You must progress further in the ${quest.replace(/^([a-z]+:)/gm, '').replace(/_/g, ' ')} quest to equip this item.`)
);

return missingRequirements;
return { equipable: missingRequirements.length === 0, missingRequirements: missingRequirements };
}

public equipItem(itemId: number, itemSlot: number, slot: EquipmentSlot | number): boolean {
Expand Down Expand Up @@ -884,9 +908,11 @@ export class Player extends Actor {
return;
}

const missingRequirements = this.missingItemEquipRequirements(itemDetails);
if (missingRequirements.length) {
missingRequirements.forEach( s => {this.sendMessage(s)});
const equippable = this.canEquipItem(itemDetails);
if (!equippable.equipable) {
if(equippable.missingRequirements) {
equippable.missingRequirements.forEach(async (s) => this.sendMessage(s));
}
return;
}

Expand Down
19 changes: 19 additions & 0 deletions src/plugins/commands/quest-list-command.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { commandActionHandler } from '@engine/action';
import { questMap } from '@engine/plugins';

const action: commandActionHandler = (details) => {
for (const quest of Object.values(questMap)) {
details.player.sendLogMessage(quest.id, details.isConsole);
}
};

export default {
pluginId: 'promises:quest-list-command',
hooks: [
{
type: 'player_command',
commands: [ 'quest-list', 'quests' ],
handler: action
}
]
};

0 comments on commit bb4f096

Please sign in to comment.