mirror of
https://github.com/OMGeeky/andors-trail.git
synced 2026-01-21 10:58:12 +01:00
Merge branch 'headless-scripts'
This commit is contained in:
@@ -58,10 +58,18 @@ public final class Dialogs {
|
||||
showConversation(currentActivity, context, phraseID, null);
|
||||
}
|
||||
|
||||
public static void showMapScriptMessage(final MainActivity currentActivity, final ControllerContext context, String phraseID) {
|
||||
showConversation(currentActivity, context, phraseID, null, false);
|
||||
}
|
||||
|
||||
public static void showConversation(final MainActivity currentActivity, final ControllerContext context, final String phraseID, final Monster npc) {
|
||||
showConversation(currentActivity, context, phraseID, npc, true);
|
||||
}
|
||||
private static void showConversation(final MainActivity currentActivity, final ControllerContext context, final String phraseID, final Monster npc, boolean giveRewardsForFirstPhrase) {
|
||||
context.gameRoundController.pause();
|
||||
Intent intent = new Intent(currentActivity, ConversationActivity.class);
|
||||
intent.setData(Uri.parse("content://com.gpl.rpg.AndorsTrail/conversation/" + phraseID));
|
||||
intent.putExtra("giveRewardsForFirstPhrase", giveRewardsForFirstPhrase);
|
||||
addMonsterIdentifiers(intent, npc);
|
||||
currentActivity.startActivityForResult(intent, MainActivity.INTENTREQUEST_CONVERSATION);
|
||||
}
|
||||
|
||||
@@ -36,10 +36,11 @@ import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class ConversationActivity extends Activity implements OnKeyListener
|
||||
public final class ConversationActivity
|
||||
extends Activity
|
||||
implements OnKeyListener
|
||||
, ConversationController.ConversationStatemachine.ConversationStateListener {
|
||||
public static final int ACTIVITYRESULT_ATTACK = Activity.RESULT_FIRST_USER + 1;
|
||||
public static final int ACTIVITYRESULT_REMOVE = Activity.RESULT_FIRST_USER + 2;
|
||||
|
||||
private static final int playerNameColor = Color.argb(255, 0xbb, 0x22, 0x22);
|
||||
private static final int NPCNameColor = Color.argb(255, 0xbb, 0xbb, 0x22);
|
||||
private static final int playerPhraseColor = 0;
|
||||
@@ -64,7 +65,7 @@ public final class ConversationActivity extends Activity implements OnKeyListene
|
||||
if (!app.isInitialized()) { finish(); return; }
|
||||
this.world = app.getWorld();
|
||||
this.player = world.model.player;
|
||||
this.conversationState = new ConversationController.ConversationStatemachine(world, app.getControllerContext(), getResources(), this);
|
||||
this.conversationState = new ConversationController.ConversationStatemachine(world, app.getControllerContext(), this);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
@@ -106,17 +107,22 @@ public final class ConversationActivity extends Activity implements OnKeyListene
|
||||
statementList.setFocusable(false);
|
||||
statementList.setFocusableInTouchMode(false);
|
||||
|
||||
String phraseID;
|
||||
boolean giveRewardsForFirstPhrase;
|
||||
boolean displayLastMessage = true;
|
||||
if (savedInstanceState != null) {
|
||||
conversationState.setCurrentNPC(Dialogs.getMonsterFromBundle(savedInstanceState, world));
|
||||
ArrayList<ConversationStatement> savedConversationHistory = savedInstanceState.getParcelableArrayList("conversationHistory");
|
||||
if (savedConversationHistory != null) conversationHistory.addAll(savedConversationHistory);
|
||||
final String phraseID = savedInstanceState.getString("phraseID");
|
||||
conversationState.proceedToRestoredState(phraseID);
|
||||
phraseID = savedInstanceState.getString("phraseID");
|
||||
giveRewardsForFirstPhrase = false;
|
||||
displayLastMessage = false;
|
||||
} else {
|
||||
conversationState.setCurrentNPC(Dialogs.getMonsterFromIntent(getIntent(), world));
|
||||
final String phraseID = getIntent().getData().getLastPathSegment();
|
||||
conversationState.proceedToPhrase(phraseID);
|
||||
phraseID = getIntent().getData().getLastPathSegment();
|
||||
giveRewardsForFirstPhrase = getIntent().getBooleanExtra("giveRewardsForFirstPhrase", true);
|
||||
}
|
||||
conversationState.proceedToPhrase(getResources(), phraseID, giveRewardsForFirstPhrase, displayLastMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,12 +211,12 @@ public final class ConversationActivity extends Activity implements OnKeyListene
|
||||
replyGroup.removeAllViews();
|
||||
nextButton.setEnabled(false);
|
||||
if (conversationState.hasOnlyOneNextReply()) {
|
||||
conversationState.playerSelectedNextStep();
|
||||
conversationState.playerSelectedNextStep(getResources());
|
||||
} else {
|
||||
if (rb == null) return;
|
||||
Reply r = (Reply) rb.getTag();
|
||||
addConversationStatement(player, rb.getText().toString(), playerPhraseColor);
|
||||
conversationState.playerSelectedReply(r);
|
||||
conversationState.playerSelectedReply(getResources(), r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +346,7 @@ public final class ConversationActivity extends Activity implements OnKeyListene
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextPhraseReached(String message, Actor actor) {
|
||||
public void onTextPhraseReached(String message, Actor actor, String phraseID) {
|
||||
addConversationStatement(actor, message, NPCPhraseColor);
|
||||
}
|
||||
|
||||
@@ -395,13 +401,11 @@ public final class ConversationActivity extends Activity implements OnKeyListene
|
||||
|
||||
@Override
|
||||
public void onConversationEndedWithCombat(Monster npc) {
|
||||
ConversationActivity.this.setResult(ACTIVITYRESULT_ATTACK);
|
||||
ConversationActivity.this.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConversationEndedWithRemoval(Monster npc) {
|
||||
ConversationActivity.this.setResult(ACTIVITYRESULT_REMOVE);
|
||||
ConversationActivity.this.finish();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.AttackResult;
|
||||
import com.gpl.rpg.AndorsTrail.controller.CombatController;
|
||||
import com.gpl.rpg.AndorsTrail.controller.MovementController;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.CombatActionListener;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.CombatTurnListener;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.PlayerMovementListener;
|
||||
@@ -36,7 +35,13 @@ import com.gpl.rpg.AndorsTrail.view.QuickButton.QuickButtonContextMenuInfo;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
|
||||
public final class MainActivity extends Activity implements PlayerMovementListener, CombatActionListener, CombatTurnListener, WorldEventListener {
|
||||
public final class MainActivity
|
||||
extends Activity
|
||||
implements
|
||||
PlayerMovementListener
|
||||
, CombatActionListener
|
||||
, CombatTurnListener
|
||||
, WorldEventListener {
|
||||
|
||||
public static final int INTENTREQUEST_MONSTERENCOUNTER = 2;
|
||||
public static final int INTENTREQUEST_CONVERSATION = 4;
|
||||
@@ -115,7 +120,6 @@ public final class MainActivity extends Activity implements PlayerMovementListen
|
||||
}
|
||||
break;
|
||||
case INTENTREQUEST_CONVERSATION:
|
||||
MovementController.refreshMonsterAggressiveness(world.model.currentMap, world.model.player);
|
||||
controllers.mapController.applyCurrentMapReplacements(getResources(), true);
|
||||
break;
|
||||
case INTENTREQUEST_SAVEGAME:
|
||||
@@ -340,6 +344,11 @@ public final class MainActivity extends Activity implements PlayerMovementListen
|
||||
Dialogs.showConversation(this, controllers, phraseID, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScriptAreaStartedConversation(String phraseID) {
|
||||
Dialogs.showMapScriptMessage(this, controllers, phraseID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerSteppedOnMonster(Monster m) {
|
||||
Dialogs.showMonsterEncounter(this, controllers, m);
|
||||
|
||||
@@ -263,7 +263,7 @@ public final class CombatController implements VisualEffectCompletedCallback {
|
||||
}
|
||||
|
||||
world.model.player.nextPosition.set(dest);
|
||||
controllers.movementController.moveToNextIfPossible(false);
|
||||
controllers.movementController.moveToNextIfPossible();
|
||||
|
||||
playerActionCompleted();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.quest.QuestLogEntry;
|
||||
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
|
||||
import com.gpl.rpg.AndorsTrail.util.ConstRange;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -63,7 +64,13 @@ public final class ConversationController {
|
||||
addQuestProgressReward(player, reward.rewardID, reward.value, result);
|
||||
break;
|
||||
case alignmentChange:
|
||||
player.addAlignment(reward.rewardID, reward.value);
|
||||
addAlignmentReward(player, reward.rewardID, reward.value);
|
||||
break;
|
||||
case giveItem:
|
||||
addItemReward(reward.rewardID, reward.value, result);
|
||||
break;
|
||||
case createTimer:
|
||||
world.model.worldData.createTimer(reward.rewardID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -76,22 +83,30 @@ public final class ConversationController {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addAlignmentReward(Player player, String faction, int delta) {
|
||||
player.addAlignment(faction, delta);
|
||||
MovementController.refreshMonsterAggressiveness(world.model.currentMap, world.model.player);
|
||||
}
|
||||
|
||||
private void addQuestProgressReward(Player player, String questID, int questProgress, PhraseRewards result) {
|
||||
QuestProgress progress = new QuestProgress(questID, questProgress);
|
||||
boolean added = player.addQuestProgress(progress);
|
||||
if (!added) return; // Only apply exp reward if the quest stage was reached just now (and not re-reached)
|
||||
|
||||
QuestLogEntry stage = world.quests.getQuestLogEntry(progress);
|
||||
if (stage != null) {
|
||||
result.loot.exp += stage.rewardExperience;
|
||||
result.questProgress.add(progress);
|
||||
}
|
||||
if (stage == null) return;
|
||||
result.loot.exp += stage.rewardExperience;
|
||||
result.questProgress.add(progress);
|
||||
}
|
||||
|
||||
private void addDropListReward(Player player, String droplistID, PhraseRewards result) {
|
||||
world.dropLists.getDropList(droplistID).createRandomLoot(result.loot, player);
|
||||
}
|
||||
|
||||
private void addItemReward(String itemTypeID, int quantity, PhraseRewards result) {
|
||||
result.loot.add(world.itemTypes.getItemType(itemTypeID), quantity);
|
||||
}
|
||||
|
||||
private void addSkillReward(Player player, SkillCollection.SkillID skillID, PhraseRewards result) {
|
||||
SkillInfo skill = world.skills.getSkill(skillID);
|
||||
boolean addedSkill = controllers.skillController.levelUpSkillByQuest(player, skill);
|
||||
@@ -153,6 +168,8 @@ public final class ConversationController {
|
||||
return player.getSkillLevel(SkillCollection.SkillID.valueOf(requirement.requireID)) >= requirement.value;
|
||||
case killedMonster:
|
||||
return world.model.statistics.getNumberOfKillsForMonsterType(requirement.requireID) >= requirement.value;
|
||||
case timerElapsed:
|
||||
return world.model.worldData.hasTimerElapsed(requirement.requireID, requirement.value);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -169,17 +186,15 @@ public final class ConversationController {
|
||||
private final WorldContext world;
|
||||
private final ControllerContext controllers;
|
||||
private final Player player;
|
||||
private final Resources res;
|
||||
private String phraseID;
|
||||
private Phrase currentPhrase;
|
||||
private Monster npc;
|
||||
public ConversationStateListener listener;
|
||||
|
||||
public ConversationStatemachine(WorldContext world, ControllerContext controllers, Resources res, ConversationStateListener listener) {
|
||||
public ConversationStatemachine(WorldContext world, ControllerContext controllers, ConversationStateListener listener) {
|
||||
this.world = world;
|
||||
this.player = world.model.player;
|
||||
this.controllers = controllers;
|
||||
this.res = res;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@@ -187,17 +202,17 @@ public final class ConversationController {
|
||||
public Monster getCurrentNPC() { return npc; }
|
||||
public String getCurrentPhraseID() { return phraseID; }
|
||||
|
||||
public void playerSelectedReply(Reply r) {
|
||||
public void playerSelectedReply(final Resources res, Reply r) {
|
||||
applyReplyEffect(player, r);
|
||||
proceedToPhrase(r.nextPhrase);
|
||||
proceedToPhrase(res, r.nextPhrase, true, true);
|
||||
}
|
||||
|
||||
public void playerSelectedNextStep() {
|
||||
playerSelectedReply(currentPhrase.replies[0]);
|
||||
public void playerSelectedNextStep(final Resources res) {
|
||||
playerSelectedReply(res, currentPhrase.replies[0]);
|
||||
}
|
||||
|
||||
public interface ConversationStateListener {
|
||||
void onTextPhraseReached(String message, Actor actor);
|
||||
void onTextPhraseReached(String message, Actor actor, String phraseID);
|
||||
void onConversationEnded();
|
||||
void onConversationEndedWithShop(Monster npc);
|
||||
void onConversationEndedWithCombat(Monster npc);
|
||||
@@ -207,7 +222,7 @@ public final class ConversationController {
|
||||
void onConversationHasReply(Reply r, String message);
|
||||
}
|
||||
|
||||
private void setCurrentPhrase(String phraseID) {
|
||||
private void setCurrentPhrase(final Resources res, String phraseID) {
|
||||
this.phraseID = phraseID;
|
||||
this.currentPhrase = world.conversationLoader.loadPhrase(phraseID, conversationCollection, res);
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
@@ -218,7 +233,7 @@ public final class ConversationController {
|
||||
}
|
||||
}
|
||||
|
||||
public void proceedToPhrase(String phraseID) {
|
||||
public void proceedToPhrase(final Resources res, String phraseID, boolean giveRewards, boolean displayPhraseMessage) {
|
||||
if (phraseID.equalsIgnoreCase(ConversationCollection.PHRASE_CLOSE)) {
|
||||
listener.onConversationEnded();
|
||||
return;
|
||||
@@ -233,41 +248,27 @@ public final class ConversationController {
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentPhrase(phraseID);
|
||||
setCurrentPhrase(res, phraseID);
|
||||
|
||||
ConversationController.PhraseRewards phraseRewards = controllers.conversationController.applyPhraseRewards(player, currentPhrase);
|
||||
if (phraseRewards != null) {
|
||||
listener.onPlayerReceivedRewards(phraseRewards);
|
||||
if (giveRewards) {
|
||||
ConversationController.PhraseRewards phraseRewards = controllers.conversationController.applyPhraseRewards(player, currentPhrase);
|
||||
if (phraseRewards != null) {
|
||||
listener.onPlayerReceivedRewards(phraseRewards);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPhrase.message == null) {
|
||||
for (Reply r : currentPhrase.replies) {
|
||||
if (!canSelectReply(world, r)) continue;
|
||||
applyReplyEffect(player, r);
|
||||
proceedToPhrase(r.nextPhrase);
|
||||
proceedToPhrase(res, r.nextPhrase, giveRewards, displayPhraseMessage);
|
||||
return;
|
||||
}
|
||||
} else if (displayPhraseMessage) {
|
||||
String message = getDisplayMessage(currentPhrase, player);
|
||||
listener.onTextPhraseReached(message, npc, phraseID);
|
||||
}
|
||||
|
||||
String message = getDisplayMessage(currentPhrase, player);
|
||||
listener.onTextPhraseReached(message, npc);
|
||||
|
||||
requestReplies();
|
||||
}
|
||||
|
||||
private void endConversationWithRemovingNPC() {
|
||||
controllers.monsterSpawnController.remove(world.model.currentMap, npc);
|
||||
listener.onConversationEndedWithRemoval(npc);
|
||||
}
|
||||
|
||||
private void endConversationWithCombat() {
|
||||
npc.forceAggressive();
|
||||
controllers.combatController.setCombatSelection(npc);
|
||||
controllers.combatController.enterCombat(CombatController.BeginTurnAs.player);
|
||||
listener.onConversationEndedWithCombat(npc);
|
||||
}
|
||||
|
||||
private void requestReplies() {
|
||||
if (hasOnlyOneNextReply()) {
|
||||
listener.onConversationCanProceedWithNext();
|
||||
return;
|
||||
@@ -279,9 +280,26 @@ public final class ConversationController {
|
||||
}
|
||||
}
|
||||
|
||||
public void proceedToRestoredState(String phraseID) {
|
||||
setCurrentPhrase(phraseID);
|
||||
requestReplies();
|
||||
private void endConversationWithRemovingNPC() {
|
||||
if (npc == null) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("Tried to remove NPC from conversation without having a valid npc target!");
|
||||
listener.onConversationEnded();
|
||||
return;
|
||||
}
|
||||
controllers.monsterSpawnController.remove(world.model.currentMap, npc);
|
||||
listener.onConversationEndedWithRemoval(npc);
|
||||
}
|
||||
|
||||
private void endConversationWithCombat() {
|
||||
if (npc == null) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("Tried to enter combat from conversation without having a valid npc target!");
|
||||
listener.onConversationEnded();
|
||||
return;
|
||||
}
|
||||
npc.forceAggressive();
|
||||
controllers.combatController.setCombatSelection(npc);
|
||||
controllers.combatController.enterCombat(CombatController.BeginTurnAs.player);
|
||||
listener.onConversationEndedWithCombat(npc);
|
||||
}
|
||||
|
||||
public boolean hasOnlyOneNextReply() {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.gpl.rpg.AndorsTrail.controller;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: oskar
|
||||
* Date: 8/7/13
|
||||
* Time: 3:26 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public class ConversationStatemachine {
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.controller;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.GameRoundListeners;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
|
||||
import com.gpl.rpg.AndorsTrail.util.TimedMessageTask;
|
||||
|
||||
public final class GameRoundController implements TimedMessageTask.Callback {
|
||||
@@ -79,8 +80,10 @@ public final class GameRoundController implements TimedMessageTask.Callback {
|
||||
gameRoundListeners.onNewRound();
|
||||
}
|
||||
public void onNewPlayerRound() {
|
||||
world.model.worldData.tickWorldTime();
|
||||
controllers.actorStatsController.applyConditionsToPlayer(world.model.player, false);
|
||||
controllers.actorStatsController.applySkillEffectsForNewRound(world.model.player, world.model.currentMap);
|
||||
controllers.mapController.handleMapEvents(world.model.currentMap, world.model.player.position, MapObject.MapObjectEvaluationType.afterEveryRound);
|
||||
}
|
||||
public void onNewMonsterRound() {
|
||||
controllers.actorStatsController.applyConditionsToMonsters(world.model.currentMap, false);
|
||||
@@ -91,6 +94,7 @@ public final class GameRoundController implements TimedMessageTask.Callback {
|
||||
controllers.monsterSpawnController.maybeSpawn(world.model.currentMap, world.model.currentTileMap);
|
||||
controllers.monsterMovementController.attackWithAgressiveMonsters();
|
||||
controllers.effectController.updateSplatters(world.model.currentMap);
|
||||
controllers.mapController.handleMapEvents(world.model.currentMap, world.model.player.position, MapObject.MapObjectEvaluationType.continuously);
|
||||
gameRoundListeners.onNewTick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.MapLayoutListeners;
|
||||
import com.gpl.rpg.AndorsTrail.controller.listeners.WorldEventListeners;
|
||||
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Actor;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Player;
|
||||
import com.gpl.rpg.AndorsTrail.model.conversation.Reply;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
||||
@@ -20,13 +22,38 @@ public final class MapController {
|
||||
private final WorldContext world;
|
||||
public final WorldEventListeners worldEventListeners = new WorldEventListeners();
|
||||
public final MapLayoutListeners mapLayoutListeners = new MapLayoutListeners();
|
||||
private ConversationController.ConversationStatemachine mapScriptExecutor;
|
||||
|
||||
public MapController(ControllerContext controllers, WorldContext world) {
|
||||
this.controllers = controllers;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public void handleMapEvent(MapObject o, Coord position) {
|
||||
public void handleMapEventsAfterMovement(PredefinedMap currentMap, Coord newPosition, Coord lastPosition) {
|
||||
// We don't allow event objects to overlap, so there can only be one object returned here.
|
||||
MapObject mapObject = currentMap.getEventObjectAt(newPosition);
|
||||
if (mapObject == null) return;
|
||||
|
||||
switch (mapObject.evaluateWhen) {
|
||||
case afterEveryRound:
|
||||
return;
|
||||
case whenEntering:
|
||||
// Do not trigger event if the player already was on the same MapObject before.
|
||||
if (mapObject.position.contains(lastPosition)) return;
|
||||
break;
|
||||
}
|
||||
handleMapEvent(mapObject, newPosition);
|
||||
}
|
||||
|
||||
public void handleMapEvents(PredefinedMap currentMap, Coord position, MapObject.MapObjectEvaluationType evaluationType) {
|
||||
MapObject mapObject = currentMap.getEventObjectAt(position);
|
||||
if (mapObject == null) return;
|
||||
if (mapObject.evaluateWhen != evaluationType) return;
|
||||
handleMapEvent(mapObject, position);
|
||||
}
|
||||
|
||||
private void handleMapEvent(MapObject o, Coord position) {
|
||||
if (!shouldHandleMapEvent(o)) return;
|
||||
switch (o.type) {
|
||||
case sign:
|
||||
if (o.id == null || o.id.length() <= 0) return;
|
||||
@@ -41,9 +68,26 @@ public final class MapController {
|
||||
case rest:
|
||||
steppedOnRestArea(o);
|
||||
break;
|
||||
case script:
|
||||
runScriptArea(o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldHandleMapEvent(MapObject mapObject) {
|
||||
if (world.model.uiSelections.isInCombat) {
|
||||
// Only "script" events may run while in combat.
|
||||
if (mapObject.type != MapObject.MapObjectType.script) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void runScriptArea(MapObject o) {
|
||||
Resources res = controllers.getResources();
|
||||
mapScriptExecutor.proceedToPhrase(res, o.id, true, true);
|
||||
controllers.mapController.applyCurrentMapReplacements(res, true);
|
||||
}
|
||||
|
||||
private void steppedOnRestArea(MapObject area) {
|
||||
if (controllers.preferences.confirmRest) {
|
||||
worldEventListeners.onPlayerSteppedOnRestArea(area);
|
||||
@@ -89,6 +133,7 @@ public final class MapController {
|
||||
m.resetTemporaryData();
|
||||
}
|
||||
controllers.monsterSpawnController.spawnAll(world.model.currentMap, world.model.currentTileMap);
|
||||
world.model.worldData.tickWorldTime(20);
|
||||
controllers.gameRoundController.resetRoundTimers();
|
||||
}
|
||||
|
||||
@@ -139,4 +184,21 @@ public final class MapController {
|
||||
public boolean satisfiesCondition(ReplaceableMapSection replacement) {
|
||||
return world.model.player.hasExactQuestProgress(replacement.requireQuestStage);
|
||||
}
|
||||
|
||||
private final ConversationController.ConversationStatemachine.ConversationStateListener conversationStateListener = new ConversationController.ConversationStatemachine.ConversationStateListener() {
|
||||
@Override
|
||||
public void onTextPhraseReached(String message, Actor actor, String phraseID) {
|
||||
worldEventListeners.onScriptAreaStartedConversation(phraseID);
|
||||
}
|
||||
@Override public void onPlayerReceivedRewards(ConversationController.PhraseRewards phraseRewards) { }
|
||||
@Override public void onConversationEnded() { }
|
||||
@Override public void onConversationEndedWithShop(Monster npc) { }
|
||||
@Override public void onConversationEndedWithCombat(Monster npc) { }
|
||||
@Override public void onConversationEndedWithRemoval(Monster npc) { }
|
||||
@Override public void onConversationCanProceedWithNext() { }
|
||||
@Override public void onConversationHasReply(Reply r, String message) { }
|
||||
};
|
||||
public void prepareScriptsOnCurrentMap() {
|
||||
mapScriptExecutor = new ConversationController.ConversationStatemachine(world, controllers, conversationStateListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ public final class MovementController implements TimedMessageTask.Callback {
|
||||
}
|
||||
}
|
||||
controllers.mapController.applyCurrentMapReplacements(res, false);
|
||||
controllers.mapController.prepareScriptsOnCurrentMap();
|
||||
newMap.visited = true;
|
||||
newMap.updateLastVisitTime();
|
||||
moveBlockedActors(newMap, model.currentTileMap);
|
||||
@@ -120,7 +121,7 @@ public final class MovementController implements TimedMessageTask.Callback {
|
||||
return;
|
||||
}
|
||||
|
||||
moveToNextIfPossible(true);
|
||||
moveToNextIfPossible();
|
||||
}
|
||||
|
||||
private boolean findWalkablePosition(int dx, int dy) {
|
||||
@@ -206,7 +207,7 @@ public final class MovementController implements TimedMessageTask.Callback {
|
||||
else return -v;
|
||||
}
|
||||
|
||||
public void moveToNextIfPossible(boolean handleEvents) {
|
||||
public void moveToNextIfPossible() {
|
||||
final Player player = world.model.player;
|
||||
final PredefinedMap currentMap = world.model.currentMap;
|
||||
final Coord newPosition = player.nextPosition;
|
||||
@@ -224,14 +225,9 @@ public final class MovementController implements TimedMessageTask.Callback {
|
||||
controllers.combatController.setCombatSelection(null, null);
|
||||
playerMovementListeners.onPlayerMoved(newPosition, player.lastPosition);
|
||||
|
||||
if (handleEvents) {
|
||||
MapObject o = currentMap.getEventObjectAt(newPosition);
|
||||
if (o != null) {
|
||||
if (!o.position.contains(player.lastPosition)) { // Do not trigger event if the player already was on the same MapObject before.
|
||||
controllers.mapController.handleMapEvent(o, newPosition);
|
||||
}
|
||||
}
|
||||
controllers.mapController.handleMapEventsAfterMovement(currentMap, newPosition, player.lastPosition);
|
||||
|
||||
if (!world.model.uiSelections.isInCombat) {
|
||||
Loot loot = currentMap.getBagAt(newPosition);
|
||||
if (loot != null) controllers.itemController.playerSteppedOnLootBag(loot);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.util.Collection;
|
||||
|
||||
public interface WorldEventListener {
|
||||
void onPlayerStartedConversation(Monster m, String phraseID);
|
||||
void onScriptAreaStartedConversation(String phraseID);
|
||||
void onPlayerSteppedOnMonster(Monster m);
|
||||
void onPlayerSteppedOnMapSignArea(MapObject area);
|
||||
void onPlayerSteppedOnKeyArea(MapObject area);
|
||||
|
||||
@@ -13,6 +13,10 @@ public final class WorldEventListeners extends ListOfListeners<WorldEventListene
|
||||
@Override public void call(WorldEventListener listener, Monster m, String phraseID) { listener.onPlayerStartedConversation(m, phraseID); }
|
||||
};
|
||||
|
||||
private final Function1<WorldEventListener, String> onScriptAreaStartedConversation = new Function1<WorldEventListener, String>() {
|
||||
@Override public void call(WorldEventListener listener, String phraseID) { listener.onScriptAreaStartedConversation(phraseID); }
|
||||
};
|
||||
|
||||
private final Function1<WorldEventListener, Monster> onPlayerSteppedOnMonster = new Function1<WorldEventListener, Monster>() {
|
||||
@Override public void call(WorldEventListener listener, Monster m) { listener.onPlayerSteppedOnMonster(m); }
|
||||
};
|
||||
@@ -58,6 +62,11 @@ public final class WorldEventListeners extends ListOfListeners<WorldEventListene
|
||||
callAllListeners(this.onPlayerStartedConversation, m, phraseID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScriptAreaStartedConversation(String phraseID) {
|
||||
callAllListeners(this.onScriptAreaStartedConversation, phraseID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerSteppedOnMonster(Monster m) {
|
||||
callAllListeners(this.onPlayerSteppedOnMonster, m);
|
||||
|
||||
@@ -3,16 +3,57 @@ package com.gpl.rpg.AndorsTrail.model;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class WorldData {
|
||||
private long worldTime = 0; // Measured in number of game rounds
|
||||
private final HashMap<String, Long> timers = new HashMap<String, Long>();
|
||||
|
||||
public WorldData() {}
|
||||
|
||||
public void tickWorldTime() {
|
||||
++worldTime;
|
||||
}
|
||||
public void tickWorldTime(int ticks) {
|
||||
worldTime += ticks;
|
||||
}
|
||||
public long getWorldTime() {
|
||||
return worldTime;
|
||||
}
|
||||
|
||||
public void createTimer(String name) {
|
||||
timers.put(name, worldTime);
|
||||
}
|
||||
|
||||
public void removeTimer(String name) {
|
||||
timers.remove(name);
|
||||
}
|
||||
|
||||
public boolean hasTimerElapsed(String name, long duration) {
|
||||
Long v = timers.get(name);
|
||||
if (v == null) return false;
|
||||
return v + duration <= worldTime;
|
||||
}
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public WorldData(DataInputStream src, int fileversion) throws IOException {
|
||||
worldTime = src.readLong();
|
||||
final int numTimers = src.readInt();
|
||||
for(int i = 0; i < numTimers; ++i) {
|
||||
final String timerName = src.readUTF();
|
||||
final long value = src.readLong();
|
||||
this.timers.put(timerName, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, int flags) throws IOException {
|
||||
dest.writeLong(worldTime);
|
||||
dest.writeInt(timers.size());
|
||||
for(Map.Entry<String, Long> e : timers.entrySet()) {
|
||||
dest.writeUTF(e.getKey());
|
||||
dest.writeLong(e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ public final class Requirement {
|
||||
,wear // Player must be wearing item(s). Items will NOT be removed when selecting reply.
|
||||
,skillLevel // Player needs to have a specific skill equal to or above a certain level
|
||||
,killedMonster
|
||||
,timerElapsed
|
||||
}
|
||||
|
||||
public final RequirementType requireType;
|
||||
|
||||
@@ -7,6 +7,8 @@ public final class Reward {
|
||||
,skillIncrease
|
||||
,actorCondition
|
||||
,alignmentChange
|
||||
,giveItem
|
||||
,createTimer
|
||||
}
|
||||
|
||||
public final RewardType rewardType;
|
||||
|
||||
@@ -20,13 +20,7 @@ public final class DropList {
|
||||
final int quantityRollBias = SkillController.getDropQuantityRollBias(item, player);
|
||||
int quantity = Constants.rollValue(item.quantity, quantityRollBias);
|
||||
|
||||
if (quantity != 0) {
|
||||
if (ItemTypeCollection.isGoldItemType(item.itemType.id)) {
|
||||
loot.gold += quantity;
|
||||
} else {
|
||||
loot.items.addItem(item.itemType, quantity);
|
||||
}
|
||||
}
|
||||
loot.add(item.itemType, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ public class ItemContainer {
|
||||
}
|
||||
|
||||
public void addItem(ItemType itemType, int quantity) {
|
||||
if (quantity == 0) return;
|
||||
|
||||
ItemEntry e = findItem(itemType.id);
|
||||
if (e != null) {
|
||||
e.quantity += quantity;
|
||||
|
||||
@@ -33,6 +33,14 @@ public final class Loot {
|
||||
this.items.add(l.items);
|
||||
}
|
||||
|
||||
public void add(ItemType itemType, int quantity) {
|
||||
if (ItemTypeCollection.isGoldItemType(itemType.id)) {
|
||||
gold += quantity;
|
||||
} else {
|
||||
items.addItem(itemType, quantity);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasItemsOrExp() {
|
||||
return exp != 0 || hasItemsOrGold();
|
||||
}
|
||||
@@ -61,7 +69,6 @@ public final class Loot {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
exp = 0;
|
||||
gold = 0;
|
||||
|
||||
@@ -11,6 +11,14 @@ public final class MapObject {
|
||||
,rest
|
||||
,keyarea
|
||||
,container
|
||||
,script
|
||||
}
|
||||
|
||||
public static enum MapObjectEvaluationType {
|
||||
whenEntering
|
||||
,onEveryStep
|
||||
,afterEveryRound
|
||||
,continuously
|
||||
}
|
||||
|
||||
public final CoordRect position;
|
||||
@@ -20,6 +28,7 @@ public final class MapObject {
|
||||
public final String place;
|
||||
public final QuestProgress requireQuestProgress;
|
||||
public final DropList dropList;
|
||||
public final MapObjectEvaluationType evaluateWhen;
|
||||
|
||||
private MapObject(
|
||||
final CoordRect position
|
||||
@@ -28,7 +37,9 @@ public final class MapObject {
|
||||
, final String map
|
||||
, final String place
|
||||
, final QuestProgress requireQuestProgress
|
||||
, final DropList dropList) {
|
||||
, final DropList dropList
|
||||
, final MapObjectEvaluationType evaluateWhen
|
||||
) {
|
||||
this.position = new CoordRect(position);
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
@@ -36,21 +47,25 @@ public final class MapObject {
|
||||
this.place = place;
|
||||
this.requireQuestProgress = requireQuestProgress;
|
||||
this.dropList = dropList;
|
||||
this.evaluateWhen = evaluateWhen;
|
||||
}
|
||||
|
||||
public static MapObject createMapSignEvent(final CoordRect position, final String phraseID) {
|
||||
return new MapObject(position, MapObjectType.sign, phraseID, null, null, null, null);
|
||||
return new MapObject(position, MapObjectType.sign, phraseID, null, null, null, null, MapObjectEvaluationType.whenEntering);
|
||||
}
|
||||
public static MapObject createNewMapEvent(final CoordRect position, final String thisMapTitle, final String destinationMap, final String destinationPlace) {
|
||||
return new MapObject(position, MapObjectType.newmap, thisMapTitle, destinationMap, destinationPlace, null, null);
|
||||
public static MapObject createMapChangeArea(final CoordRect position, final String thisMapTitle, final String destinationMap, final String destinationPlace) {
|
||||
return new MapObject(position, MapObjectType.newmap, thisMapTitle, destinationMap, destinationPlace, null, null, MapObjectEvaluationType.whenEntering);
|
||||
}
|
||||
public static MapObject createNewRest(final CoordRect position, final String placeId) {
|
||||
return new MapObject(position, MapObjectType.rest, placeId, null, null, null, null);
|
||||
public static MapObject createRestArea(final CoordRect position, final String placeId) {
|
||||
return new MapObject(position, MapObjectType.rest, placeId, null, null, null, null, MapObjectEvaluationType.whenEntering);
|
||||
}
|
||||
public static MapObject createNewKeyArea(final CoordRect position, final String phraseID, final QuestProgress requireQuestStage) {
|
||||
return new MapObject(position, MapObjectType.keyarea, phraseID, null, null, requireQuestStage, null);
|
||||
public static MapObject createKeyArea(final CoordRect position, final String phraseID, final QuestProgress requireQuestStage) {
|
||||
return new MapObject(position, MapObjectType.keyarea, phraseID, null, null, requireQuestStage, null, MapObjectEvaluationType.whenEntering);
|
||||
}
|
||||
public static MapObject createNewContainerArea(final CoordRect position, final DropList dropList) {
|
||||
return new MapObject(position, MapObjectType.container, null, null, null, null, dropList);
|
||||
public static MapObject createContainerArea(final CoordRect position, final DropList dropList) {
|
||||
return new MapObject(position, MapObjectType.container, null, null, null, null, dropList, MapObjectEvaluationType.whenEntering);
|
||||
}
|
||||
public static MapObject createScriptArea(final CoordRect position, final String phraseID, final MapObjectEvaluationType evaluateWhen) {
|
||||
return new MapObject(position, MapObjectType.script, phraseID, null, null, null, null, evaluateWhen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class TMXMapTranslator {
|
||||
else if(p.name.equalsIgnoreCase("place")) place = p.value;
|
||||
else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + ", mapchange " + object.name + "@" + topLeft.toString() + " has unrecognized property \"" + p.name + "\".");
|
||||
}
|
||||
mapObjects.add(MapObject.createNewMapEvent(position, object.name, map, place));
|
||||
mapObjects.add(MapObject.createMapChangeArea(position, object.name, map, place));
|
||||
} else if (object.type.equalsIgnoreCase("spawn")) {
|
||||
ArrayList<MonsterType> types = monsterTypes.getMonsterTypesFromSpawnGroup(object.name);
|
||||
int maxQuantity = 1;
|
||||
@@ -129,15 +129,36 @@ public final class TMXMapTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
mapObjects.add(MapObject.createNewKeyArea(position, phraseID, requireQuestStage));
|
||||
mapObjects.add(MapObject.createKeyArea(position, phraseID, requireQuestStage));
|
||||
} else if (object.type.equals("rest")) {
|
||||
mapObjects.add(MapObject.createNewRest(position, object.name));
|
||||
mapObjects.add(MapObject.createRestArea(position, object.name));
|
||||
} else if (object.type.equals("container")) {
|
||||
DropList dropList = dropLists.getDropList(object.name);
|
||||
if (dropList == null) continue;
|
||||
mapObjects.add(MapObject.createNewContainerArea(position, dropList));
|
||||
mapObjects.add(MapObject.createContainerArea(position, dropList));
|
||||
} else if (object.type.equals("replace")) {
|
||||
// Do nothing. Will be handled when reading map layers instead.
|
||||
} else if (object.type.equalsIgnoreCase("script")) {
|
||||
String phraseID = object.name;
|
||||
MapObject.MapObjectEvaluationType evaluateWhen = MapObject.MapObjectEvaluationType.whenEntering;
|
||||
for (TMXProperty p : object.properties) {
|
||||
if (p.name.equalsIgnoreCase("when")) {
|
||||
if (p.value.equalsIgnoreCase("enter")) {
|
||||
evaluateWhen = MapObject.MapObjectEvaluationType.whenEntering;
|
||||
} else if (p.value.equalsIgnoreCase("step")) {
|
||||
evaluateWhen = MapObject.MapObjectEvaluationType.onEveryStep;
|
||||
} else if (p.value.equalsIgnoreCase("round")) {
|
||||
evaluateWhen = MapObject.MapObjectEvaluationType.afterEveryRound;
|
||||
} else if (p.value.equalsIgnoreCase("always")) {
|
||||
evaluateWhen = MapObject.MapObjectEvaluationType.continuously;
|
||||
} else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("OPTIMIZE: Map " + m.name + ", script " + object.name + "@" + topLeft.toString() + " has unrecognized value for \"when\" property: \"" + p.value + "\".");
|
||||
}
|
||||
} else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("OPTIMIZE: Map " + m.name + ", script " + object.name + "@" + topLeft.toString() + " has unrecognized property \"" + p.name + "\".");
|
||||
}
|
||||
}
|
||||
mapObjects.add(MapObject.createScriptArea(position, phraseID, evaluateWhen));
|
||||
} else if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("OPTIMIZE: Map " + m.name + ", has unrecognized object type \"" + object.type + "\" for name \"" + object.name + "\".");
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
<option value="skillIncrease">Skill increase</option>
|
||||
<option value="actorCondition">Actor condition</option>
|
||||
<option value="alignmentChange">Alignment/faction change</option>
|
||||
<option value="giveItem">Item</option>
|
||||
<option value="createTimer">Create timer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div ng-show="reward.rewardType=='questProgress'">
|
||||
@@ -79,6 +81,22 @@
|
||||
<input type="text" size="3" id="rewardvalue" class="field at-input-quantity" ng-model="reward.value" />
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="reward.rewardType=='giveItem'">
|
||||
<div class="fieldWithLabel">
|
||||
<label for="rewardID" >Item ID:</label>
|
||||
<input type="text" size="30" id="rewardID" class="field at-input-id" ng-model="reward.rewardID" />
|
||||
</div>
|
||||
<div class="fieldWithLabel">
|
||||
<label for="rewardvalue">Quantity:</label>
|
||||
<input type="text" size="3" id="rewardvalue" class="field at-input-quantity" ng-model="reward.value" />
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="reward.rewardType=='createTimer'">
|
||||
<div class="fieldWithLabel">
|
||||
<label for="rewardID"><span class="hint hint--top" data-hint="Can be any unique string really, just something to refer to this timer in some reply requirement.">Timer ID:</span></label>
|
||||
<input type="text" size="30" id="rewardID" class="field at-input-id" ng-model="reward.rewardID" />
|
||||
</div>
|
||||
</div>
|
||||
<button ng-click="removeReward(phrase, reward)" class="btn pull-right" title="Remove reward"><i class="icon-trash"></i> Remove reward</button>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
@@ -173,6 +191,7 @@
|
||||
<option value="wear">Worn equipment</option>
|
||||
<option value="skillLevel">Skill level</option>
|
||||
<option value="killedMonster">Killed monster</option>
|
||||
<option value="timerElapsed">Timer elapsed</option>
|
||||
</select>
|
||||
</div>
|
||||
<div ng-show="require.requireType=='questProgress'">
|
||||
@@ -231,6 +250,16 @@
|
||||
<input type="text" size="3" id="requirevalue" class="field at-input-quantity" ng-model="require.value" />
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="require.requireType=='timerElapsed'">
|
||||
<div class="fieldWithLabel">
|
||||
<label for="requireID">Timer ID:</label>
|
||||
<input type="text" size="30" id="requireID" class="field at-input-id" ng-model="require.requireID" />
|
||||
</div>
|
||||
<div class="fieldWithLabel">
|
||||
<label for="requirevalue">Number of rounds:</label>
|
||||
<input type="text" size="3" id="requirevalue" class="field at-input-quantity" ng-model="require.value" />
|
||||
</div>
|
||||
</div>
|
||||
<button ng-click="removeRequirement(reply, require)" class="btn pull-right" title="Remove requirement"><i class="icon-trash"></i> Remove requirement</button>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user