| Name | Author | Game Mode | Rating | |||||
|---|---|---|---|---|---|---|---|---|
| NpcBunnies | Cranky | Mutator | N/A | |||||
namespace npcBunniesQuests
{
enum QuestType
{
Coins = 0,
Gems = 1,
DefeatMonster = 2,
DefeatBoss = 3
}
class NpcQuest
{
int questType = QuestType::Coins;
int amount = 0;
GEM::Color gemType = GEM::RED;
int objectType = 0;
bool countAfterQuestIsStarted = true;
bool completeQuestTogether = false;
bool respawn = false;
int goToSet = -1;
bool iconSpecified = false;
bool iconHidden = false;
npcBunniesAnimations::NpcUiAnimation icon;
}
enum RewardType
{
RewardCoins = 0,
RewardGems = 1,
RewardAmmo = 2,
RewardPowerup = 3,
RewardTeleport = 4,
RewardMoveable = 5,
RewardTrigger = 6,
RewardFastFire = 7,
RewardGuidePath = 8
}
class NpcReward
{
int rewardType = RewardType::RewardCoins;
int amount = 0;
GEM::Color gemType = GEM::RED;
int weaponType = WEAPON::BOUNCER;
float x = 0;
float y = 0;
bool moveable = true;
int npcIndex = -1;
int guidePathIndex = -1;
int triggerId = -1;
bool triggerState = true;
bool iconSpecified = false;
bool iconHidden = false;
npcBunniesAnimations::NpcUiAnimation icon;
}
enum DefeatMonsterEvent
{
MonsterUnknown = 0,
Bat = OBJECT::BAT,
BeeBoy = OBJECT::BEEBOY,
Bees = OBJECT::BEES,
Bee = OBJECT::BEE,
Butterfly = OBJECT::BUTTERFLY,
Crab = OBJECT::CRAB,
Demon = OBJECT::DEMON,
DoggyDogg = OBJECT::DOGGYDOGG,
Dragonfly = OBJECT::DRAGONFLY,
Dragon = OBJECT::DRAGON,
FatChick = OBJECT::FATCHICK,
Fencer = OBJECT::FENCER,
Fish = OBJECT::FISH,
Hatter = OBJECT::HATTER,
Helmut = OBJECT::HELMUT,
LabRat = OBJECT::LABRAT,
FloatLizard = OBJECT::FLOATLIZARD,
XmasLizard = OBJECT::XMASLIZARD,
Lizard = OBJECT::LIZARD,
StandMonkey = OBJECT::STANDMONKEY,
Monkey = OBJECT::MONKEY,
XmasNormalTurtle = OBJECT::XMASNORMTURTLE,
TubeTurtle = OBJECT::TUBETURTLE,
TufTurtle = OBJECT::TUFTURT,
NormalTurtle = OBJECT::NORMTURTLE,
Rapier = OBJECT::RAPIER,
Raven = OBJECT::RAVEN,
Skeleton = OBJECT::SKELETON,
Spark = OBJECT::SPARK,
FloatSucker = OBJECT::FLOATSUCKER,
Sucker = OBJECT::SUCKER,
Cat = OBJECT::CAT,
PacmanGhost = OBJECT::PACMANGHOST,
Moth = OBJECT::MOTH,
Witch = OBJECT::WITCH
}
enum DefeatBossEvent
{
BossUnknown = 0,
XmasBilsy = OBJECT::XMASBILSY,
Bilsy = OBJECT::BILSY,
Bolly = OBJECT::BOLLY,
Bubba = OBJECT::BUBBA,
Devan = OBJECT::DEVANROBOT,
DevilDevan = OBJECT::DEVILDEVAN,
Queen = OBJECT::QUEEN,
Robot = OBJECT::ROBOT,
RocketTurtle = OBJECT::ROCKETTURTLE,
TufBoss = OBJECT::TUFBOSS,
Tweedle = OBJECT::TWEEDLEBOSS,
Uterus = OBJECT::UTERUS
}
dictionary defeatedObjectCounts;
dictionary trackedDefeatEventIds;
dictionary questStartDefeatedObjectCounts;
dictionary activeQuestDefeatProgress;
dictionary unlockedGuidePaths;
array<string> defeatedObjectPlayerNames;
array<bool> trackedDefeatObjectWasActive;
array<int> trackedDefeatObjectEventID;
array<string> trackedDefeatObjectLastHitPlayer;
array<bool> trackedDefeatObjectCounted;
int lastTrackedDefeatObjectScanTick = -9999;
bool trackedDefeatNeedsGlobalScan = false;
bool forceTrackedDefeatObjectScan = false;
string MakeActiveQuestDefeatProgressKey(const string &in playerName, int npcId, int setIndex, int eventID)
{
return playerName + "|" + npcId + "|" + setIndex + "|" + eventID;
}
int GetActiveQuestDefeatProgressForName(const string &in playerName, int npcId, int setIndex, int eventID)
{
int count = 0;
activeQuestDefeatProgress.get(MakeActiveQuestDefeatProgressKey(playerName, npcId, setIndex, eventID), count);
return count;
}
void SetActiveQuestDefeatProgressForName(const string &in playerName, int npcId, int setIndex, int eventID, int count)
{
if(playerName == "" || npcId < 0 || setIndex < 0 || eventID <= 0) return;
activeQuestDefeatProgress.set(MakeActiveQuestDefeatProgressKey(playerName, npcId, setIndex, eventID), count);
}
string MakeUnlockedGuidePathKey(const string &in playerName, int npcId, int pathIndex)
{
return playerName + "|" + npcId + "|" + pathIndex;
}
bool IsGuidePathUnlocked(const string &in playerName, int npcId, int pathIndex)
{
if(playerName == "" || npcId < 0 || pathIndex < 0) return false;
bool unlocked = false;
return unlockedGuidePaths.get(MakeUnlockedGuidePathKey(playerName, npcId, pathIndex), unlocked) && unlocked;
}
void UnlockGuidePathForPlayer(const string &in playerName, int npcId, int pathIndex)
{
if(playerName == "" || npcId < 0 || pathIndex < 0) return;
unlockedGuidePaths.set(MakeUnlockedGuidePathKey(playerName, npcId, pathIndex), true);
}
bool FindGuidePathReward(npcBunniesCore::npcBunny &in npc, int pathIndex, int &out setIndex, int &out rewardIndex)
{
setIndex = -1;
rewardIndex = -1;
for(uint s = 0; s < npc.dialogueSets.length; s++)
{
npcBunniesDialogue::DialogueSet@ set = npc.dialogueSets[s];
for(uint r = 0; r < set.rewards.length; r++)
{
NpcReward@ reward = set.rewards[r];
if(reward !is null && reward.rewardType == RewardType::RewardGuidePath && reward.guidePathIndex == pathIndex)
{
setIndex = int(s);
rewardIndex = int(r);
return true;
}
}
}
return false;
}
bool IsGuidePathRewardLockedForPlayer(npcBunniesCore::npcBunny &in npc, const string &in playerName, int pathIndex)
{
int setIndex, rewardIndex;
if(!FindGuidePathReward(npc, pathIndex, setIndex, rewardIndex)) return false;
return !IsGuidePathUnlocked(playerName, npc.id, pathIndex);
}
int GetAvailableGuidePathCountForPlayer(npcBunniesCore::npcBunny &in npc, const string &in playerName)
{
for(uint i = 0; i < npc.guidePaths.length; i++)
if(IsGuidePathRewardLockedForPlayer(npc, playerName, int(i))) return int(i);
return int(npc.guidePaths.length);
}
void IncrementActiveQuestDefeatProgressForName(const string &in playerName, int eventID)
{
if(playerName == "" || eventID <= 0) return;
for(uint npcId = 0; npcId < npcBunniesCore::npcBunnies.length; npcId++)
{
npcBunniesCore::npcBunny npc = npcBunniesCore::EnsureNpcQuestState(npcBunniesCore::npcBunnies[npcId]);
for(uint setIndex = 0; setIndex < npc.dialogueSets.length; setIndex++)
{
if(!npcBunniesCore::HasPlayerSeenQuestOffer(playerName, int(npcId), int(setIndex))) continue;
npcBunniesDialogue::DialogueSet@ set = npc.dialogueSets[setIndex];
if(set.choicesAnswerMethod != npcBunniesCore::DialogueAction::Quest) continue;
for(uint q = 0; q < set.quests.length; q++)
{
NpcQuest@ quest = set.quests[q];
if(quest is null || (quest.questType != QuestType::DefeatMonster && quest.questType != QuestType::DefeatBoss) || quest.objectType != eventID) continue;
int count = GetActiveQuestDefeatProgressForName(playerName, int(npcId), int(setIndex), eventID) + 1;
SetActiveQuestDefeatProgressForName(playerName, int(npcId), int(setIndex), eventID, count);
}
}
npcBunniesCore::npcBunnies[npcId] = npc;
}
}
string MakeDefeatedObjectKey(const string &in playerName, int eventID)
{
return playerName + "|" + eventID;
}
string MakeQuestStartDefeatedObjectKey(const string &in playerName, int npcId, int setIndex, int eventID)
{
return playerName + "|" + npcId + "|" + setIndex + "|" + eventID;
}
void AddUniqueDefeatedObjectPlayerName(const string &in playerName)
{
if(playerName == "") return;
for(uint i = 0; i < defeatedObjectPlayerNames.length; i++) if(defeatedObjectPlayerNames[i] == playerName) return;
defeatedObjectPlayerNames.insertLast(playerName);
}
void TrackDefeatEventID(int eventID, bool needsGlobalScan = false)
{
if(eventID > 0) trackedDefeatEventIds.set(eventID + "", true);
if(needsGlobalScan) trackedDefeatNeedsGlobalScan = true;
}
bool IsTrackedDefeatEventID(int eventID)
{
if(eventID <= 0) return false;
bool tracked = false;
return trackedDefeatEventIds.get(eventID + "", tracked) && tracked;
}
int GetDefeatedObjectCountForName(const string &in playerName, int eventID)
{
int count = 0;
defeatedObjectCounts.get(MakeDefeatedObjectKey(playerName, eventID), count);
return count;
}
int GetDefeatedObjectCount(jjPLAYER@ player, int eventID)
{
if(player is null) return 0;
return GetDefeatedObjectCountForName(player.nameUnformatted, eventID);
}
int GetDefeatedObjectCountTogether(int eventID)
{
int count = 0;
for(uint i = 0; i < defeatedObjectPlayerNames.length; i++) count += GetDefeatedObjectCountForName(defeatedObjectPlayerNames[i], eventID);
return count;
}
int GetQuestDefeatedObjectBaseline(jjPLAYER@ player, int npcId, int setIndex, int eventID, bool completeTogether)
{
if(player is null || npcId < 0 || setIndex < 0) return 0;
int count = 0;
questStartDefeatedObjectCounts.get(MakeQuestStartDefeatedObjectKey(player.nameUnformatted, npcId, setIndex, eventID), count);
return count;
}
int GetQuestDefeatedObjectProgress(NpcQuest@ quest, jjPLAYER@ player, int npcId, int setIndex)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return 0;
if(quest is null || player is null) return 0;
if(quest.countAfterQuestIsStarted)
{
if(npcId < 0 || setIndex < 0 || !npcBunniesCore::HasPlayerSeenQuestOffer(player.nameUnformatted, npcId, setIndex)) return 0;
return GetActiveQuestDefeatProgressForName(player.nameUnformatted, npcId, setIndex, quest.objectType);
}
int count = quest.completeQuestTogether ? GetDefeatedObjectCountTogether(quest.objectType) : GetDefeatedObjectCount(player, quest.objectType);
return count > 0 ? count : 0;
}
bool HasActiveObjectAtTile(int eventID, int xTile, int yTile)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return false;
for(int i = 1; i < jjObjectCount; i++)
{
jjOBJ@ obj = jjObjects[i];
if(obj.isActive && int(obj.eventID) == eventID && int(obj.xPos) / 32 == xTile && int(obj.yPos) / 32 == yTile) return true;
}
return false;
}
void RespawnQuestObjects(int eventID)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return;
if(eventID <= 0) return;
for(int x = 0; x < jjLayerWidth[4]; x++)
{
for(int y = 0; y < jjLayerHeight[4]; y++)
{
if(int(jjEventGet(x, y)) == eventID && !HasActiveObjectAtTile(eventID, x, y)) jjAddObject(eventID, x * 32, y * 32);
}
}
}
bool RespawnNpcFightingTargetAt(int eventID, int xTile, int yTile)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return false;
if(eventID <= 0 || !npcBunniesFighting::IsNpcFightingTargetEventID(eventID)) return false;
if(HasActiveObjectAtTile(eventID, xTile, yTile)) return false;
jjAddObject(eventID, xTile * 32, yTile * 32);
return true;
}
void SendNpcRespawnMonsterToClients(int eventID, int xTile, int yTile)
{
if(!jjIsServer || !npcBunniesCore::ENABLE_NPC_SYNC) return;
jjSTREAM packet;
packet.push("npcRespawnMonsterAt " + eventID + " " + xTile + " " + yTile);
jjSendPacket(packet);
}
int RespawnNpcFightingTargets(bool syncClients = false)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return 0;
int respawned = 0;
for(int x = 0; x < jjLayerWidth[4]; x++)
{
for(int y = 0; y < jjLayerHeight[4]; y++)
{
int eventID = int(jjEventGet(x, y));
if(eventID <= 0 || !npcBunniesFighting::IsNpcFightingTargetEventID(eventID)) continue;
if(RespawnNpcFightingTargetAt(eventID, x, y)) respawned++;
if(syncClients) SendNpcRespawnMonsterToClients(eventID, x, y);
}
}
return respawned;
}
void RequestRespawnNpcFightingTargets()
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return;
if(!npcBunniesCore::ENABLE_NPC_SYNC) { RespawnNpcFightingTargets(); return; }
jjSTREAM packet;
packet.push("npcRespawnMonsters");
jjSendPacket(packet);
}
void StartQuestForPlayer(int npcId, int setIndex, jjPLAYER@ player)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return;
if(player is null || npcId < 0 || npcId >= int(npcBunniesCore::npcBunnies.length)) return;
npcBunniesCore::npcBunny npc = npcBunniesCore::EnsureNpcQuestState(npcBunniesCore::npcBunnies[npcId]);
if(setIndex < 0 || setIndex >= int(npc.dialogueSets.length)) return;
npcBunniesDialogue::DialogueSet@ set = npc.dialogueSets[setIndex];
for(uint i = 0; i < set.quests.length; i++)
{
NpcQuest@ quest = set.quests[i];
if(quest is null || (quest.questType != QuestType::DefeatMonster && quest.questType != QuestType::DefeatBoss)) continue;
if(set.respawnMonsters || quest.respawn) RespawnQuestObjects(quest.objectType);
if(quest.countAfterQuestIsStarted) { forceTrackedDefeatObjectScan = true; lastTrackedDefeatObjectScanTick = -9999; }
if(quest.countAfterQuestIsStarted)
{
int count = quest.completeQuestTogether ? GetDefeatedObjectCountTogether(quest.objectType) : GetDefeatedObjectCount(player, quest.objectType);
questStartDefeatedObjectCounts.set(MakeQuestStartDefeatedObjectKey(player.nameUnformatted, npcId, setIndex, quest.objectType), count);
}
SetActiveQuestDefeatProgressForName(player.nameUnformatted, npcId, setIndex, quest.objectType, 0);
}
}
void EnsureTrackedDefeatObjectArrays()
{
int length = jjObjectCount + 1;
if(length < 1) length = 1;
if(int(trackedDefeatObjectWasActive.length) >= length) return;
uint oldLength = trackedDefeatObjectWasActive.length;
trackedDefeatObjectWasActive.resize(length);
trackedDefeatObjectEventID.resize(length);
trackedDefeatObjectLastHitPlayer.resize(length);
trackedDefeatObjectCounted.resize(length);
for(uint i = oldLength; i < trackedDefeatObjectWasActive.length; i++)
{
trackedDefeatObjectWasActive[i] = false;
trackedDefeatObjectEventID[i] = 0;
trackedDefeatObjectLastHitPlayer[i] = "";
trackedDefeatObjectCounted[i] = false;
}
}
void IncrementDefeatedObjectCountForName(const string &in playerName, int eventID)
{
if(playerName == "" || eventID <= 0) return;
int count = GetDefeatedObjectCountForName(playerName, eventID) + 1;
defeatedObjectCounts.set(MakeDefeatedObjectKey(playerName, eventID), count);
AddUniqueDefeatedObjectPlayerName(playerName);
}
void IncrementDefeatForActiveQuestPlayers(int eventID)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return;
if(eventID <= 0) return;
for(uint npcId = 0; npcId < npcBunniesCore::npcBunnies.length; npcId++)
{
npcBunniesCore::npcBunny npc = npcBunniesCore::EnsureNpcQuestState(npcBunniesCore::npcBunnies[npcId]);
for(int playerId = 0; playerId < 32; playerId++)
{
int setIndex = npc.activeQuestSet[playerId];
if(setIndex < 0 || setIndex >= int(npc.dialogueSets.length) || !jjPlayers[playerId].isInGame) continue;
npcBunniesDialogue::DialogueSet@ set = npc.dialogueSets[setIndex];
bool needsEvent = false;
for(uint q = 0; q < set.quests.length; q++)
{
NpcQuest@ quest = set.quests[q];
if(quest !is null && (quest.questType == QuestType::DefeatMonster || quest.questType == QuestType::DefeatBoss) && quest.objectType == eventID) needsEvent = true;
}
if(needsEvent)
{
string playerName = jjPlayers[playerId].nameUnformatted;
int count = GetActiveQuestDefeatProgressForName(playerName, int(npcId), setIndex, eventID) + 1;
SetActiveQuestDefeatProgressForName(playerName, int(npcId), setIndex, eventID, count);
}
}
npcBunniesCore::npcBunnies[npcId] = npc;
}
}
bool HasActiveCountAfterStartDefeatQuest()
{
for(uint npcId = 0; npcId < npcBunniesCore::npcBunnies.length; npcId++)
{
npcBunniesCore::npcBunny npc = npcBunniesCore::EnsureNpcQuestState(npcBunniesCore::npcBunnies[npcId]);
for(int playerId = 0; playerId < 32; playerId++)
{
if(!jjPlayers[playerId].isInGame || playerId >= int(npc.activeQuestSet.length)) continue;
int setIndex = npc.activeQuestSet[playerId];
if(setIndex < 0 || setIndex >= int(npc.dialogueSets.length)) continue;
npcBunniesDialogue::DialogueSet@ set = npc.dialogueSets[setIndex];
for(uint q = 0; q < set.quests.length; q++)
{
NpcQuest@ quest = set.quests[q];
if(quest !is null && quest.countAfterQuestIsStarted && (quest.questType == QuestType::DefeatMonster || quest.questType == QuestType::DefeatBoss)) return true;
}
}
}
return false;
}
void UpdateTrackedDefeatObjects()
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return;
if(trackedDefeatEventIds.getSize() == 0) return;
if(lastTrackedDefeatObjectScanTick + npcBunniesCore::NPC_DEFEAT_TRACK_SCAN_INTERVAL > jjGameTicks) return;
lastTrackedDefeatObjectScanTick = jjGameTicks;
bool forceScan = forceTrackedDefeatObjectScan;
forceTrackedDefeatObjectScan = false;
if(!trackedDefeatNeedsGlobalScan && !forceScan && !HasActiveCountAfterStartDefeatQuest()) return;
EnsureTrackedDefeatObjectArrays();
for(int i = 1; i < int(trackedDefeatObjectWasActive.length); i++)
{
bool activeNow = i < jjObjectCount && jjObjects[i].isActive && IsTrackedDefeatEventID(jjObjects[i].eventID);
if(activeNow)
{
if(!trackedDefeatObjectWasActive[i] || trackedDefeatObjectEventID[i] != int(jjObjects[i].eventID))
{
trackedDefeatObjectLastHitPlayer[i] = "";
trackedDefeatObjectCounted[i] = false;
}
trackedDefeatObjectWasActive[i] = true;
trackedDefeatObjectEventID[i] = jjObjects[i].eventID;
}
else if(trackedDefeatObjectWasActive[i])
{
if(!trackedDefeatObjectCounted[i])
{
if(trackedDefeatObjectLastHitPlayer[i] != "") { IncrementDefeatedObjectCountForName(trackedDefeatObjectLastHitPlayer[i], trackedDefeatObjectEventID[i]); IncrementActiveQuestDefeatProgressForName(trackedDefeatObjectLastHitPlayer[i], trackedDefeatObjectEventID[i]); }
else IncrementDefeatForActiveQuestPlayers(trackedDefeatObjectEventID[i]);
}
trackedDefeatObjectWasActive[i] = false;
trackedDefeatObjectEventID[i] = 0;
trackedDefeatObjectLastHitPlayer[i] = "";
trackedDefeatObjectCounted[i] = false;
}
}
}
bool AreNpcQuestsComplete(npcBunniesDialogue::DialogueSet@ set, jjPLAYER@ player, int npcId = -1, int setIndex = -1)
{
if(set is null) return true;
for(uint i = 0; i < set.quests.length; i++)
{
if(!IsQuestComplete(set.quests[i], player, npcId, setIndex)) return false;
}
return true;
}
bool IsQuestComplete(NpcQuest@ quest, jjPLAYER@ player, int npcId = -1, int setIndex = -1)
{
if(quest is null) return true;
if(player is null) return false;
if(quest.amount <= 0) return true;
if(quest.questType == QuestType::Coins) return player.coins >= quest.amount;
if(quest.questType == QuestType::Gems) return player.gems[quest.gemType] >= quest.amount;
if(quest.questType == QuestType::DefeatMonster || quest.questType == QuestType::DefeatBoss)
{
if(!npcBunniesCore::ENABLE_NPC_MONSTER_QUESTS) return false;
if(quest.objectType <= 0) return false;
return GetQuestDefeatedObjectProgress(quest, player, npcId, setIndex) >= quest.amount;
}
return false;
}
void SpendQuestCosts(npcBunniesDialogue::DialogueSet@ set, jjPLAYER@ player)
{
if(set is null) return;
for(uint i = 0; i < set.quests.length; i++) SpendQuestCost(set.quests[i], player);
}
void SpendQuestCost(NpcQuest@ quest, jjPLAYER@ player)
{
if(quest is null || quest.amount <= 0) return;
if(quest.questType == QuestType::Coins)
player.coins = player.coins >= quest.amount ? player.coins - quest.amount : 0;
else if(quest.questType == QuestType::Gems)
player.gems[quest.gemType] = player.gems[quest.gemType] >= quest.amount ? player.gems[quest.gemType] - quest.amount : 0;
}
int ParseDefeatEventID(const string &in value)
{
int eventID = parseInt(value);
if (value == "0" || eventID != 0)
return eventID;
// =========================
// Bosses
// =========================
if (jjRegexMatch(value, "Bilsy", true))
return OBJECT::BILSY;
if (jjRegexMatch(value, "XmasBilsy", true) || jjRegexMatch(value, "ChristmasBilsy", true))
return OBJECT::XMASBILSY;
if (jjRegexMatch(value, "Bolly", true))
return OBJECT::BOLLY;
if (jjRegexMatch(value, "Bubba", true))
return OBJECT::BUBBA;
if (jjRegexMatch(value, "DevilDevan", true))
return OBJECT::DEVILDEVAN;
if (jjRegexMatch(value, "Queen", true))
return OBJECT::QUEEN;
if (jjRegexMatch(value, "Robot", true))
return OBJECT::ROBOT;
if (jjRegexMatch(value, "RocketTurtle", true))
return OBJECT::ROCKETTURTLE;
if (jjRegexMatch(value, "SchwarzenGuard", true) || jjRegexMatch(value, "TurtleBoss", true) || jjRegexMatch(value, "TufBoss", true))
return OBJECT::TUFBOSS;
if (jjRegexMatch(value, "Tweedle", true))
return OBJECT::TWEEDLEBOSS;
if (jjRegexMatch(value, "Uterus", true))
return OBJECT::UTERUS;
// =========================
// Enemies / Monsters
// =========================
if (jjRegexMatch(value, "Bat", true))
return OBJECT::BAT;
if (jjRegexMatch(value, "Bee", true))
return OBJECT::BEE;
if (jjRegexMatch(value, "BeeBoy", true))
return OBJECT::BEEBOY;
if (jjRegexMatch(value, "Bees", true))
return OBJECT::BEES;
if (jjRegexMatch(value, "Butterfly", true) || jjRegexMatch(value, "EvilButterfly", true))
return OBJECT::BUTTERFLY;
if (jjRegexMatch(value, "Crab", true))
return OBJECT::CRAB;
if (jjRegexMatch(value, "Demon", true))
return OBJECT::DEMON;
if (jjRegexMatch(value, "Dog", true) || jjRegexMatch(value, "Doggy", true))
return OBJECT::DOGGYDOGG;
if (jjRegexMatch(value, "Dragon", true))
return OBJECT::DRAGON;
if (jjRegexMatch(value, "Dragonfly", true))
return OBJECT::DRAGONFLY;
if (jjRegexMatch(value, "FatChick", true))
return OBJECT::FATCHICK;
if (jjRegexMatch(value, "Fencer", true))
return OBJECT::FENCER;
if (jjRegexMatch(value, "Fish", true))
return OBJECT::FISH;
if (jjRegexMatch(value, "Hatter", true))
return OBJECT::HATTER;
if (jjRegexMatch(value, "Helmut", true))
return OBJECT::HELMUT;
if (jjRegexMatch(value, "LabRat", true) || jjRegexMatch(value, "Rat", true))
return OBJECT::LABRAT;
if (jjRegexMatch(value, "Lizard", true))
return OBJECT::LIZARD;
if (jjRegexMatch(value, "FloatLizard", true))
return OBJECT::FLOATLIZARD;
if (jjRegexMatch(value, "XmasLizard", true))
return OBJECT::XMASLIZARD;
if (jjRegexMatch(value, "Monkey", true))
return OBJECT::MONKEY;
if (jjRegexMatch(value, "StandMonkey", true))
return OBJECT::STANDMONKEY;
if (jjRegexMatch(value, "XmasTurtle", true) || jjRegexMatch(value, "XmasNormalTurtle", true)
|| jjRegexMatch(value, "ChristmasTurtle", true) || jjRegexMatch(value, "ChristmasNormalTurtle", true))
return OBJECT::XMASNORMTURTLE;
if (jjRegexMatch(value, "TubeTurtle", true))
return OBJECT::TUBETURTLE;
if (jjRegexMatch(value, "TufTurtle", true))
return OBJECT::TUFTURT;
if (jjRegexMatch(value, "Turtle", true) || jjRegexMatch(value, "NormalTurtle", true))
return OBJECT::NORMTURTLE;
if (jjRegexMatch(value, "Rapier", true) || jjRegexMatch(value, "Ghost", true))
return OBJECT::RAPIER;
if (jjRegexMatch(value, "Raven", true))
return OBJECT::RAVEN;
if (jjRegexMatch(value, "Skeleton", true))
return OBJECT::SKELETON;
if (jjRegexMatch(value, "Spark", true))
return OBJECT::SPARK;
if (jjRegexMatch(value, "Sucker", true))
return OBJECT::SUCKER;
if (jjRegexMatch(value, "FloatSucker", true))
return OBJECT::FLOATSUCKER;
if (jjRegexMatch(value, "Cat", true))
return OBJECT::CAT;
if (jjRegexMatch(value, "PacmanGhost", true))
return OBJECT::PACMANGHOST;
if (jjRegexMatch(value, "Moth", true))
return OBJECT::MOTH;
if (jjRegexMatch(value, "Witch", true))
return OBJECT::WITCH;
return 0;
}
int ParseQuestType(const string &in value)
{
if(jjRegexMatch(value, "Gem", true) || jjRegexMatch(value, "Gems", true)) return QuestType::Gems;
if(jjRegexMatch(value, "DefeatBoss", true) || jjRegexMatch(value, "Boss", true)) return QuestType::DefeatBoss;
if(jjRegexMatch(value, "DefeatMonster", true) || jjRegexMatch(value, "Monster", true)) return QuestType::DefeatMonster;
return QuestType::Coins;
}
//----------------------------------------------------------------------------------------------------
// NPC REWARD REGION
// Summary: Rewards are applied after all quests in a dialogue set pass. Currency rewards add to the player,
// teleport changes player position, trigger rewards set jjTriggers, and moveable rewards update an NPC flag.
void GrantNpcRewards(npcBunniesDialogue::DialogueSet@ set, jjPLAYER@ player, int npcId)
{
if(set is null) return;
SpendQuestCosts(set, player);
for(uint i = 0; i < set.rewards.length; i++) GrantNpcReward(set.rewards[i], player, npcId);
set.rewardsGranted = true;
}
void GrantNpcAmmoReward(jjPLAYER@ player, int weaponType, int amount)
{
if(player is null || amount <= 0 || weaponType <= 0 || weaponType >= 10) return;
int targetAmmo = player.ammo[weaponType] + amount;
int originalMaximum = jjWeapons[weaponType].maximum;
if(targetAmmo > jjWeapons[weaponType].maximum) jjWeapons[weaponType].maximum = targetAmmo;
player.ammo[weaponType] = targetAmmo;
jjWeapons[weaponType].maximum = originalMaximum;
}
void GrantNpcReward(NpcReward@ reward, jjPLAYER@ player, int npcId)
{
if(reward is null) return;
if(reward.rewardType == RewardType::RewardCoins) player.coins += reward.amount;
else if(reward.rewardType == RewardType::RewardGems) player.gems[reward.gemType] = player.gems[reward.gemType] + reward.amount;
else if(reward.rewardType == RewardType::RewardAmmo) GrantNpcAmmoReward(player, reward.weaponType, reward.amount);
else if(reward.rewardType == RewardType::RewardPowerup) player.powerup[reward.weaponType] = true;
else if(reward.rewardType == RewardType::RewardTeleport)
{
player.xPos = reward.x * 32;
player.yPos = reward.y * 32;
}
else if(reward.rewardType == RewardType::RewardTrigger)
{
if(0 <= reward.triggerId && reward.triggerId < 32) jjTriggers[reward.triggerId] = reward.triggerState;
}
else if(reward.rewardType == RewardType::RewardMoveable)
{
int target = reward.npcIndex >= 0 ? reward.npcIndex : npcId;
if(0 <= target && target < int(npcBunniesCore::npcBunnies.length)) npcBunniesCore::npcBunnies[target].moveable = reward.moveable;
}
else if(reward.rewardType == RewardType::RewardFastFire)
{
int amount = reward.amount > 0 ? reward.amount : 5;
player.fastfire = player.fastfire - amount >= 6 ? player.fastfire - amount : 6;
}
else if(reward.rewardType == RewardType::RewardGuidePath)
{
if(player !is null && 0 <= npcId && npcId < int(npcBunniesCore::npcBunnies.length) && 0 <= reward.guidePathIndex && reward.guidePathIndex < int(npcBunniesCore::npcBunnies[npcId].guidePaths.length))
UnlockGuidePathForPlayer(player.nameUnformatted, npcId, reward.guidePathIndex);
}
}
int ParseRewardType(const string &in value)
{
if(jjRegexMatch(value, "Gem", true) || jjRegexMatch(value, "Gems", true)) return RewardType::RewardGems;
if(jjRegexMatch(value, "Ammo", true)) return RewardType::RewardAmmo;
if(jjRegexMatch(value, "Powerup", true)) return RewardType::RewardPowerup;
if(jjRegexMatch(value, "Teleport", true)) return RewardType::RewardTeleport;
if(jjRegexMatch(value, "Trigger", true)) return RewardType::RewardTrigger;
if(jjRegexMatch(value, "FastFire", true) || jjRegexMatch(value, "Fast Fire", true)) return RewardType::RewardFastFire;
if(jjRegexMatch(value, "GuidePath", true) || jjRegexMatch(value, "Guide Path", true)) return RewardType::RewardGuidePath;
if(jjRegexMatch(value, "Moveable", true) || jjRegexMatch(value, "Movable", true)) return RewardType::RewardMoveable;
return RewardType::RewardCoins;
}
GEM::Color ParseGemType(const string &in value)
{
if(jjRegexMatch(value, "Green", true)) return GEM::GREEN;
if(jjRegexMatch(value, "Blue", true)) return GEM::BLUE;
if(jjRegexMatch(value, "Purple", true)) return GEM::PURPLE;
return GEM::RED;
}
int ParseWeaponType(const string &in value)
{
if(value == "2" || jjRegexMatch(value, "Bouncer", true)) return WEAPON::BOUNCER;
if(value == "3" || jjRegexMatch(value, "Ice", true) || jjRegexMatch(value, "Freezer", true)) return WEAPON::ICE;
if(value == "4" || jjRegexMatch(value, "Seeker", true)) return WEAPON::SEEKER;
if(value == "5" || jjRegexMatch(value, "RF", true)) return WEAPON::RF;
if(value == "6" || jjRegexMatch(value, "Toaster", true)) return WEAPON::TOASTER;
if(value == "7" || jjRegexMatch(value, "TNT", true)) return WEAPON::TNT;
if(value == "8" || jjRegexMatch(value, "Pepper", true)) return WEAPON::GUN8;
if(value == "9" || jjRegexMatch(value, "Electro", true)) return WEAPON::GUN9;
return WEAPON::BOUNCER;
}
//----------------------------------------------------------------------------------------------------
// NPC JSON PARSING REGION
// Summary: LoadNpcDialogueFile builds <level>_npc.asdat from jjLevelFileName, falls back to <level>_npc.asdat,
// removes // and /* */ comments outside quoted strings, then parses the JSON-like NPC/dialogue structure.
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.