package com.metalrain.stocksimulator.state.systems; import com.badlogic.ashley.core.Engine; import com.badlogic.ashley.core.Entity; import com.badlogic.ashley.core.Family; import com.badlogic.ashley.systems.IntervalSystem; import com.badlogic.ashley.utils.ImmutableArray; import com.metalrain.stocksimulator.state.GameState; import com.metalrain.stocksimulator.state.RxBus; import com.metalrain.stocksimulator.state.components.GameStateComponent; import com.metalrain.stocksimulator.state.components.InventoryComponent; import com.metalrain.stocksimulator.state.components.MarketDemandComponent; import com.metalrain.stocksimulator.state.components.MarketItemComponent; import com.metalrain.stocksimulator.state.components.MarketVolatilityComponent; import com.metalrain.stocksimulator.state.components.NameComponent; import com.metalrain.stocksimulator.state.components.PriceComponent; import com.metalrain.stocksimulator.state.components.PriceHistoryComponent; import com.metalrain.stocksimulator.state.components.StockImpactEventComponent; import com.metalrain.stocksimulator.state.components.WalletComponent; import java.util.Random; /** * Created by Adam Hammer on 6/22/2015. */ public class MarketSystem extends IntervalSystem { private final RxBus bus; private final Random random; private final int maxIntevals; public int getMaxIntevals() { return maxIntevals; } int interval = 0; private Family gameStateFamily; private Family marketItemFamily; private Family stockImpactEventComponent; private Family playerFamily; private Engine engine; public int getInterval() { return interval; } public MarketSystem(RxBus bus, int seed, int max_intervals) { super(1f); random = new Random(seed); this.bus = bus; this.maxIntevals = max_intervals; } @Override public void addedToEngine(Engine engine) { this.engine = engine; this.marketItemFamily = Family.all(MarketItemComponent.class, MarketVolatilityComponent.class, PriceComponent.class, PriceHistoryComponent.class).get(); playerFamily = Family.all(WalletComponent.class, NameComponent.class, InventoryComponent.class).get(); this.gameStateFamily = Family.all(GameStateComponent.class).get(); this.stockImpactEventComponent = Family.all(StockImpactEventComponent.class).get(); } @Override public void updateInterval() { if (interval >= maxIntevals) return; interval++; StockImpactEventComponent component = injectMarketEvents(); performMarketCalculations(component); bus.post(new MarketUpdatedMessage()); if (interval == maxIntevals)bus.post(new TimesUpMessage()); } private void performMarketCalculations(StockImpactEventComponent current_event) { try { Entity gameStateEntity = engine.getEntitiesFor(gameStateFamily).first(); GameStateComponent gameStateComponent = gameStateEntity.getComponent(GameStateComponent.class); gameStateComponent.market_interval++; //Grab a list of ImmutableArray<Entity> entities = engine.getEntitiesFor(marketItemFamily); for (Entity e : entities) { PriceComponent pc = e.getComponent(PriceComponent.class); NameComponent nc = e.getComponent(NameComponent.class); MarketVolatilityComponent volatilityComponent = e.getComponent(MarketVolatilityComponent.class); MarketDemandComponent demandComponent = e.getComponent(MarketDemandComponent.class); PriceHistoryComponent priceHistoryComponent = e.getComponent(PriceHistoryComponent.class); priceHistoryComponent.registerPrice(pc, gameStateComponent.market_interval); if (current_event != null && current_event.appliesTo(nc.name)) current_event.apply(nc, demandComponent); //Clamp price in range if (pc.price < volatilityComponent.min_price) { demandComponent.demand = demandComponent.supply + 1; pc.price = volatilityComponent.min_price; } //Market Crash!! if (random.nextDouble() < (volatilityComponent.volatility/10000f)) { demandComponent.demand = -(random.nextDouble()*volatilityComponent.volatility * 500); } //Regular market activity int delta = (int) (random.nextDouble() * ((demandComponent.demand - demandComponent.supply)/50f) * (volatilityComponent.volatility)); pc.price += delta; demandComponent.demand *= demandComponent.demandFalloff; demandComponent.supply *= demandComponent.supplyFalloff; //Bonus demand to keep things looking on up demandComponent.demand += 1; } updatePlayerValues(entities); } catch (Exception e) { e.printStackTrace(); } } private void updatePlayerValues(ImmutableArray<Entity> entities) { ImmutableArray<Entity> players = engine.getEntitiesFor(playerFamily); for (Entity p:players) { int wallet_amount = p.getComponent(WalletComponent.class).balance; int investment_amount = p.getComponent(InventoryComponent.class).getInventoryValue(entities); p.getComponent(PriceHistoryComponent.class).registerPrice(new PriceComponent(investment_amount+wallet_amount),interval); } } private StockImpactEventComponent generateRandom() { if (random.nextBoolean()) { return new StockImpactEventComponent("Demand UP!", interval, new String[]{GameState.names[0], GameState.names[1], GameState.names[2], GameState.names[3], GameState.names[4], GameState.names[5]}, new int[]{0, 0, 0, 0, 0, 0, 0}, new int[]{ (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200), (random.nextBoolean()?1:-1)*random.nextInt(200)} ); } else return new StockImpactEventComponent("Supply Changed", interval, new String[]{GameState.names[0], GameState.names[1], GameState.names[2], GameState.names[3], GameState.names[4], GameState.names[5]}, new int[]{ (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200), (random.nextBoolean() ? 1 : -1) * random.nextInt(200)}, new int[]{0, 0, 0, 0, 0, 0, 0} ); } private StockImpactEventComponent injectMarketEvents() { if (random.nextDouble() > 0.1f) return null; Entity e = new Entity(); StockImpactEventComponent impact = generateRandom(); e.add(impact); engine.addEntity(e); bus.post(impact); return impact; } }