mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-25 23:07:50 +00:00
Merge pull request #718 from Akka0/tower
Support Team Toggle in Tower & Refactor MonsterTide
This commit is contained in:
commit
f0aa8c2c53
@ -9,6 +9,10 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDungeonSettle(Scene scene) {
|
public void onDungeonSettle(Scene scene) {
|
||||||
|
if(scene.getScriptManager().getVariables().containsKey("stage")
|
||||||
|
&& scene.getScriptManager().getVariables().get("stage") == 1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
|
|
||||||
|
@ -117,7 +117,9 @@ public class EntityMonster extends GameEntity {
|
|||||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||||
}
|
}
|
||||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||||
getScene().getScriptManager().onMonsterDie();
|
if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){
|
||||||
|
getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this);
|
||||||
|
}
|
||||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, null);
|
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, null);
|
||||||
}
|
}
|
||||||
if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) {
|
if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) {
|
||||||
|
@ -7,10 +7,7 @@ import emu.grasscutter.data.def.TowerLevelData;
|
|||||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
||||||
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
|
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerLevelStarCondNotify;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -152,4 +149,10 @@ public class TowerManager {
|
|||||||
return recordMap.get(player.getServer().getTowerScheduleManager().getLastEntranceFloor())
|
return recordMap.get(player.getServer().getTowerScheduleManager().getLastEntranceFloor())
|
||||||
.getStarCount() >= 6;
|
.getStarCount() >= 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void mirrorTeamSetUp(int teamId) {
|
||||||
|
// use team user choose
|
||||||
|
player.getTeamManager().useTemporaryTeam(teamId);
|
||||||
|
player.sendPacket(new PacketTowerMiddleLevelChangeTeamNotify());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ public class TowerScheduleManager {
|
|||||||
|
|
||||||
public int getNextFloorId(int floorId){
|
public int getNextFloorId(int floorId){
|
||||||
var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId();
|
var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId();
|
||||||
|
var scheduleFloors = getScheduleFloors();
|
||||||
var nextId = 0;
|
var nextId = 0;
|
||||||
// find in entrance floors first
|
// find in entrance floors first
|
||||||
for(int i=0;i<entranceFloors.size()-1;i++){
|
for(int i=0;i<entranceFloors.size()-1;i++){
|
||||||
@ -56,10 +57,12 @@ public class TowerScheduleManager {
|
|||||||
nextId = entranceFloors.get(i+1);
|
nextId = entranceFloors.get(i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(floorId == entranceFloors.get(entranceFloors.size()-1)){
|
||||||
|
nextId = scheduleFloors.get(0);
|
||||||
|
}
|
||||||
if(nextId != 0){
|
if(nextId != 0){
|
||||||
return nextId;
|
return nextId;
|
||||||
}
|
}
|
||||||
var scheduleFloors = getScheduleFloors();
|
|
||||||
// find in schedule floors
|
// find in schedule floors
|
||||||
for(int i=0;i<scheduleFloors.size()-1;i++){
|
for(int i=0;i<scheduleFloors.size()-1;i++){
|
||||||
if(floorId == scheduleFloors.get(i)){
|
if(floorId == scheduleFloors.get(i)){
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
package emu.grasscutter.scripts;
|
package emu.grasscutter.scripts;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
|
import emu.grasscutter.scripts.service.ScriptMonsterSpawnService;
|
||||||
|
import emu.grasscutter.scripts.service.ScriptMonsterTideService;
|
||||||
|
import org.luaj.vm2.LuaError;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
|
||||||
import emu.grasscutter.data.def.MonsterData;
|
|
||||||
import emu.grasscutter.data.def.WorldLevelData;
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneBlock;
|
import emu.grasscutter.scripts.data.SceneBlock;
|
||||||
@ -39,27 +36,35 @@ public class SceneScriptManager {
|
|||||||
private final ScriptLib scriptLib;
|
private final ScriptLib scriptLib;
|
||||||
private final LuaValue scriptLibLua;
|
private final LuaValue scriptLibLua;
|
||||||
private final Map<String, Integer> variables;
|
private final Map<String, Integer> variables;
|
||||||
|
|
||||||
private Bindings bindings;
|
private Bindings bindings;
|
||||||
private SceneConfig config;
|
private SceneConfig config;
|
||||||
private List<SceneBlock> blocks;
|
private List<SceneBlock> blocks;
|
||||||
private boolean isInit;
|
private boolean isInit;
|
||||||
|
/**
|
||||||
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> triggers;
|
* SceneTrigger Set
|
||||||
|
*/
|
||||||
|
private final Map<String, SceneTrigger> triggers;
|
||||||
|
/**
|
||||||
|
* current triggers controlled by RefreshGroup
|
||||||
|
*/
|
||||||
|
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> currentTriggers;
|
||||||
private final Int2ObjectOpenHashMap<SceneRegion> regions;
|
private final Int2ObjectOpenHashMap<SceneRegion> regions;
|
||||||
|
private Map<Integer,SceneGroup> sceneGroups;
|
||||||
private SceneGroup currentGroup;
|
private SceneGroup currentGroup;
|
||||||
private AtomicInteger monsterAlive;
|
private ScriptMonsterTideService scriptMonsterTideService;
|
||||||
private AtomicInteger monsterTideCount;
|
private ScriptMonsterSpawnService scriptMonsterSpawnService;
|
||||||
private int monsterSceneLimit;
|
|
||||||
private ConcurrentLinkedQueue<Integer> monsterOrders;
|
|
||||||
|
|
||||||
public SceneScriptManager(Scene scene) {
|
public SceneScriptManager(Scene scene) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.scriptLib = new ScriptLib(this);
|
this.scriptLib = new ScriptLib(this);
|
||||||
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
|
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
|
||||||
this.triggers = new Int2ObjectOpenHashMap<>();
|
this.triggers = new HashMap<>();
|
||||||
|
this.currentTriggers = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
this.regions = new Int2ObjectOpenHashMap<>();
|
this.regions = new Int2ObjectOpenHashMap<>();
|
||||||
this.variables = new HashMap<>();
|
this.variables = new HashMap<>();
|
||||||
|
this.sceneGroups = new HashMap<>();
|
||||||
|
this.scriptMonsterSpawnService = new ScriptMonsterSpawnService(this);
|
||||||
|
|
||||||
// TEMPORARY
|
// TEMPORARY
|
||||||
if (this.getScene().getId() < 10) {
|
if (this.getScene().getId() < 10) {
|
||||||
@ -103,17 +108,35 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<SceneTrigger> getTriggersByEvent(int eventId) {
|
public Set<SceneTrigger> getTriggersByEvent(int eventId) {
|
||||||
return triggers.computeIfAbsent(eventId, e -> new HashSet<>());
|
return currentTriggers.computeIfAbsent(eventId, e -> new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerTrigger(SceneTrigger trigger) {
|
public void registerTrigger(SceneTrigger trigger) {
|
||||||
|
this.triggers.put(trigger.name, trigger);
|
||||||
getTriggersByEvent(trigger.event).add(trigger);
|
getTriggersByEvent(trigger.event).add(trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deregisterTrigger(SceneTrigger trigger) {
|
public void deregisterTrigger(SceneTrigger trigger) {
|
||||||
|
this.triggers.remove(trigger.name);
|
||||||
getTriggersByEvent(trigger.event).remove(trigger);
|
getTriggersByEvent(trigger.event).remove(trigger);
|
||||||
}
|
}
|
||||||
|
public void resetTriggers(List<String> triggerNames) {
|
||||||
|
for(var name : triggerNames){
|
||||||
|
var instance = triggers.get(name);
|
||||||
|
this.currentTriggers.get(instance.event).clear();
|
||||||
|
this.currentTriggers.get(instance.event).add(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void refreshGroup(SceneGroup group, int suiteIndex){
|
||||||
|
var suite = group.getSuiteByIndex(suiteIndex);
|
||||||
|
if(suite == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(suite.triggers.size() > 0){
|
||||||
|
resetTriggers(suite.triggers);
|
||||||
|
}
|
||||||
|
spawnMonstersInGroup(group, suite);
|
||||||
|
spawnGadgetsInGroup(group, suite);
|
||||||
|
}
|
||||||
public SceneRegion getRegionById(int id) {
|
public SceneRegion getRegionById(int id) {
|
||||||
return regions.get(id);
|
return regions.get(id);
|
||||||
}
|
}
|
||||||
@ -263,6 +286,7 @@ public class SceneScriptManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.sceneGroups.put(group.id, group);
|
||||||
} catch (ScriptException e) {
|
} catch (ScriptException e) {
|
||||||
Grasscutter.getLogger().error("Error loading group " + group.id + " in scene " + getScene().getId(), e);
|
Grasscutter.getLogger().error("Error loading group " + group.id + " in scene " + getScene().getId(), e);
|
||||||
}
|
}
|
||||||
@ -328,90 +352,30 @@ public class SceneScriptManager {
|
|||||||
if(suite == null){
|
if(suite == null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(suite.sceneMonsters.size() > 0){
|
spawnMonstersInGroup(group, suite);
|
||||||
this.currentGroup = group;
|
|
||||||
this.monsterSceneLimit = 0;
|
|
||||||
suite.sceneMonsters.forEach(mob -> spawnMonstersInGroup(group, mob));
|
|
||||||
}
|
}
|
||||||
|
public void spawnMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
||||||
|
if(suite == null || suite.sceneMonsters.size() <= 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.currentGroup = group;
|
||||||
|
suite.sceneMonsters.forEach(mob -> this.scriptMonsterSpawnService.spawnMonster(group.id, mob));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group) {
|
public void spawnMonstersInGroup(SceneGroup group) {
|
||||||
this.currentGroup = group;
|
this.currentGroup = group;
|
||||||
this.monsterSceneLimit = 0;
|
group.monsters.values().forEach(mob -> this.scriptMonsterSpawnService.spawnMonster(group.id, mob));
|
||||||
group.monsters.values().forEach(mob -> spawnMonstersInGroup(group, mob));
|
|
||||||
}
|
}
|
||||||
public void spawnMonstersInGroup(SceneGroup group,Integer[] ordersConfigId, int tideCount, int sceneLimit) {
|
|
||||||
|
public void startMonsterTideInGroup(SceneGroup group, Integer[] ordersConfigId, int tideCount, int sceneLimit) {
|
||||||
this.currentGroup = group;
|
this.currentGroup = group;
|
||||||
this.monsterSceneLimit = sceneLimit;
|
this.scriptMonsterTideService =
|
||||||
this.monsterTideCount = new AtomicInteger(tideCount);
|
new ScriptMonsterTideService(this, group, tideCount, sceneLimit, ordersConfigId);
|
||||||
this.monsterAlive = new AtomicInteger(0);
|
|
||||||
this.monsterOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
|
||||||
|
|
||||||
// add the last turn
|
|
||||||
group.monsters.keySet().stream()
|
|
||||||
.filter(i -> !this.monsterOrders.contains(i))
|
|
||||||
.forEach(this.monsterOrders::add);
|
|
||||||
for (int i = 0; i < sceneLimit; i++) {
|
|
||||||
spawnMonstersInGroup(group, group.monsters.get(this.monsterOrders.poll()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void spawnMonstersInGroup(SceneGroup group, SceneMonster monster) {
|
|
||||||
if(monster == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.monsterSceneLimit > 0){
|
|
||||||
this.monsterTideCount.decrementAndGet();
|
|
||||||
this.monsterAlive.incrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
MonsterData data = GameData.getMonsterDataMap().get(monster.monster_id);
|
|
||||||
|
|
||||||
if (data == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate level
|
|
||||||
int level = monster.level;
|
|
||||||
|
|
||||||
if (getScene().getDungeonData() != null) {
|
|
||||||
level = getScene().getDungeonData().getShowLevel();
|
|
||||||
} else if (getScene().getWorld().getWorldLevel() > 0) {
|
|
||||||
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getScene().getWorld().getWorldLevel());
|
|
||||||
|
|
||||||
if (worldLevelData != null) {
|
|
||||||
level = worldLevelData.getMonsterLevel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spawn mob
|
|
||||||
EntityMonster entity = new EntityMonster(getScene(), data, monster.pos, level);
|
|
||||||
entity.getRotation().set(monster.rot);
|
|
||||||
entity.setGroupId(group.id);
|
|
||||||
entity.setConfigId(monster.config_id);
|
|
||||||
|
|
||||||
getScene().addEntity(entity);
|
|
||||||
|
|
||||||
callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(entity.getConfigId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onMonsterDie(){
|
|
||||||
if(this.monsterSceneLimit <= 0){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.monsterAlive.decrementAndGet() >= this.monsterSceneLimit) {
|
|
||||||
// maybe not happen
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.monsterTideCount.get() > 0){
|
|
||||||
// add more
|
|
||||||
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
|
||||||
}else if(this.monsterAlive.get() == 0){
|
|
||||||
// spawn the last turn of monsters
|
|
||||||
//callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs());
|
|
||||||
while(!this.monsterOrders.isEmpty()){
|
|
||||||
spawnMonstersInGroup(this.currentGroup, this.currentGroup.monsters.get(this.monsterOrders.poll()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
public void spawnMonstersByConfigId(int configId, int delayTime) {
|
||||||
|
// TODO delay
|
||||||
|
this.scriptMonsterSpawnService.spawnMonster(this.currentGroup.id, this.currentGroup.monsters.get(configId));
|
||||||
}
|
}
|
||||||
// Events
|
// Events
|
||||||
|
|
||||||
@ -432,17 +396,35 @@ public class SceneScriptManager {
|
|||||||
args = CoerceJavaToLua.coerce(params);
|
args = CoerceJavaToLua.coerce(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = condition.call(this.getScriptLibLua(), args);
|
ret = safetyCall(trigger.condition, condition, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.checkboolean() == true) {
|
if (ret.isboolean() && ret.checkboolean()) {
|
||||||
LuaValue action = (LuaValue) this.getBindings().get(trigger.action);
|
LuaValue action = (LuaValue) this.getBindings().get(trigger.action);
|
||||||
action.call(this.getScriptLibLua(), LuaValue.NIL);
|
var arg = new ScriptArgs();
|
||||||
|
arg.param2 = 100;
|
||||||
|
var args = CoerceJavaToLua.coerce(arg);
|
||||||
|
safetyCall(trigger.action, action, args);
|
||||||
}
|
}
|
||||||
|
//TODO some ret may not bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public LuaValue safetyCall(){
|
public LuaValue safetyCall(String name, LuaValue func, LuaValue args){
|
||||||
//
|
try{
|
||||||
// }
|
return func.call(this.getScriptLibLua(), args);
|
||||||
|
}catch (LuaError error){
|
||||||
|
ScriptLib.logger.error("[LUA] call trigger failed {},{}",name,args,error);
|
||||||
|
return LuaValue.valueOf(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptMonsterTideService getScriptMonsterTideService() {
|
||||||
|
return scriptMonsterTideService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptMonsterSpawnService getScriptMonsterSpawnService() {
|
||||||
|
return scriptMonsterSpawnService;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,16 @@ public class ScriptLib {
|
|||||||
return sceneScriptManager;
|
return sceneScriptManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String printTable(LuaTable table){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{");
|
||||||
|
for(var meta : table.keys()){
|
||||||
|
sb.append(meta).append(":").append(table.get(meta)).append(",");
|
||||||
|
}
|
||||||
|
sb.append("}");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public int SetGadgetStateByConfigId(int configId, int gadgetState) {
|
public int SetGadgetStateByConfigId(int configId, int gadgetState) {
|
||||||
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}",
|
logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}",
|
||||||
configId,gadgetState);
|
configId,gadgetState);
|
||||||
@ -123,7 +133,7 @@ public class ScriptLib {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getSceneScriptManager().spawnMonstersInGroup(group, ordersConfigId, tideCount, sceneLimit);
|
this.getSceneScriptManager().startMonsterTideInGroup(group, ordersConfigId, tideCount, sceneLimit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -205,9 +215,12 @@ public class ScriptLib {
|
|||||||
return LuaValue.ZERO;
|
return LuaValue.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the actions and triggers to designated group
|
||||||
|
*/
|
||||||
public int RefreshGroup(LuaTable table) {
|
public int RefreshGroup(LuaTable table) {
|
||||||
logger.debug("[LUA] Call RefreshGroup with {}",
|
logger.debug("[LUA] Call RefreshGroup with {}",
|
||||||
table);
|
printTable(table));
|
||||||
// Kill and Respawn?
|
// Kill and Respawn?
|
||||||
int groupId = table.get("group_id").toint();
|
int groupId = table.get("group_id").toint();
|
||||||
int suite = table.get("suite").toint();
|
int suite = table.get("suite").toint();
|
||||||
@ -218,8 +231,7 @@ public class ScriptLib {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
|
getSceneScriptManager().refreshGroup(group, suite);
|
||||||
this.getSceneScriptManager().spawnGadgetsInGroup(group, suite);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -260,7 +272,7 @@ public class ScriptLib {
|
|||||||
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
|
public int SetMonsterBattleByGroup(int var1, int var2, int var3){
|
||||||
logger.debug("[LUA] Call SetMonsterBattleByGroup with {},{},{}",
|
logger.debug("[LUA] Call SetMonsterBattleByGroup with {},{},{}",
|
||||||
var1,var2,var3);
|
var1,var2,var3);
|
||||||
|
// TODO
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +282,7 @@ public class ScriptLib {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 8-1
|
|
||||||
public int GetGroupVariableValueByGroup(String name, int groupId){
|
public int GetGroupVariableValueByGroup(String name, int groupId){
|
||||||
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}",
|
logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}",
|
||||||
name,groupId);
|
name,groupId);
|
||||||
@ -288,7 +300,7 @@ public class ScriptLib {
|
|||||||
|
|
||||||
public int KillEntityByConfigId(LuaTable table){
|
public int KillEntityByConfigId(LuaTable table){
|
||||||
logger.debug("[LUA] Call KillEntityByConfigId with {}",
|
logger.debug("[LUA] Call KillEntityByConfigId with {}",
|
||||||
table);
|
printTable(table));
|
||||||
var configId = table.get("config_id");
|
var configId = table.get("config_id");
|
||||||
if(configId == LuaValue.NIL){
|
if(configId == LuaValue.NIL){
|
||||||
return 1;
|
return 1;
|
||||||
@ -306,6 +318,26 @@ public class ScriptLib {
|
|||||||
logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
|
logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
|
||||||
key,value,groupId);
|
key,value,groupId);
|
||||||
|
|
||||||
|
getSceneScriptManager().getVariables().put(key, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CreateMonster(LuaTable table){
|
||||||
|
logger.debug("[LUA] Call CreateMonster with {}",
|
||||||
|
printTable(table));
|
||||||
|
var configId = table.get("config_id").toint();
|
||||||
|
var delayTime = table.get("delay_time").toint();
|
||||||
|
|
||||||
|
getSceneScriptManager().spawnMonstersByConfigId(configId, delayTime);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TowerMirrorTeamSetUp(int team, int var1) {
|
||||||
|
logger.debug("[LUA] Call TowerMirrorTeamSetUp with {},{}",
|
||||||
|
team,var1);
|
||||||
|
|
||||||
|
getSceneScriptManager().getScene().getPlayers().get(0).getTowerManager().mirrorTeamSetUp(team-1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,4 +7,18 @@ public class SceneTrigger {
|
|||||||
public String source;
|
public String source;
|
||||||
public String condition;
|
public String condition;
|
||||||
public String action;
|
public String action;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if(obj instanceof SceneTrigger sceneTrigger){
|
||||||
|
return this.name.equals(sceneTrigger.name);
|
||||||
|
}
|
||||||
|
return super.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package emu.grasscutter.scripts.service;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.def.MonsterData;
|
||||||
|
import emu.grasscutter.data.def.WorldLevelData;
|
||||||
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
|
import emu.grasscutter.scripts.SceneScriptManager;
|
||||||
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
|
import emu.grasscutter.scripts.data.SceneMonster;
|
||||||
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ScriptMonsterSpawnService {
|
||||||
|
|
||||||
|
private final SceneScriptManager sceneScriptManager;
|
||||||
|
private final List<Consumer<EntityMonster>> onMonsterCreatedListener = new ArrayList<>();
|
||||||
|
|
||||||
|
private final List<Consumer<EntityMonster>> onMonsterDeadListener = new ArrayList<>();
|
||||||
|
|
||||||
|
public ScriptMonsterSpawnService(SceneScriptManager sceneScriptManager){
|
||||||
|
this.sceneScriptManager = sceneScriptManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMonsterCreatedListener(Consumer<EntityMonster> consumer){
|
||||||
|
onMonsterCreatedListener.add(consumer);
|
||||||
|
}
|
||||||
|
public void addMonsterDeadListener(Consumer<EntityMonster> consumer){
|
||||||
|
onMonsterCreatedListener.add(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMonsterDead(EntityMonster entityMonster){
|
||||||
|
onMonsterCreatedListener.stream().forEach(l -> l.accept(entityMonster));
|
||||||
|
}
|
||||||
|
public void spawnMonster(int groupId, SceneMonster monster) {
|
||||||
|
if(monster == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MonsterData data = GameData.getMonsterDataMap().get(monster.monster_id);
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate level
|
||||||
|
int level = monster.level;
|
||||||
|
|
||||||
|
if (sceneScriptManager.getScene().getDungeonData() != null) {
|
||||||
|
level = sceneScriptManager.getScene().getDungeonData().getShowLevel();
|
||||||
|
} else if (sceneScriptManager.getScene().getWorld().getWorldLevel() > 0) {
|
||||||
|
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(sceneScriptManager.getScene().getWorld().getWorldLevel());
|
||||||
|
|
||||||
|
if (worldLevelData != null) {
|
||||||
|
level = worldLevelData.getMonsterLevel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn mob
|
||||||
|
EntityMonster entity = new EntityMonster(sceneScriptManager.getScene(), data, monster.pos, level);
|
||||||
|
entity.getRotation().set(monster.rot);
|
||||||
|
entity.setGroupId(groupId);
|
||||||
|
entity.setConfigId(monster.config_id);
|
||||||
|
|
||||||
|
onMonsterCreatedListener.forEach(action -> action.accept(entity));
|
||||||
|
|
||||||
|
sceneScriptManager.getScene().addEntity(entity);
|
||||||
|
|
||||||
|
sceneScriptManager.callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(entity.getConfigId()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package emu.grasscutter.scripts.service;
|
||||||
|
|
||||||
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
|
import emu.grasscutter.scripts.SceneScriptManager;
|
||||||
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import emu.grasscutter.scripts.data.SceneMonster;
|
||||||
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class ScriptMonsterTideService {
|
||||||
|
private final SceneScriptManager sceneScriptManager;
|
||||||
|
private final SceneGroup currentGroup;
|
||||||
|
private final AtomicInteger monsterAlive;
|
||||||
|
private final AtomicInteger monsterTideCount;
|
||||||
|
private final AtomicInteger monsterKillCount;
|
||||||
|
private final int monsterSceneLimit;
|
||||||
|
private final ConcurrentLinkedQueue<Integer> monsterConfigOrders;
|
||||||
|
|
||||||
|
public ScriptMonsterTideService(SceneScriptManager sceneScriptManager,
|
||||||
|
SceneGroup group, int tideCount, int monsterSceneLimit, Integer[] ordersConfigId){
|
||||||
|
this.sceneScriptManager = sceneScriptManager;
|
||||||
|
this.currentGroup = group;
|
||||||
|
this.monsterSceneLimit = monsterSceneLimit;
|
||||||
|
this.monsterTideCount = new AtomicInteger(tideCount);
|
||||||
|
this.monsterKillCount = new AtomicInteger(0);
|
||||||
|
this.monsterAlive = new AtomicInteger(0);
|
||||||
|
this.monsterConfigOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
||||||
|
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterCreatedListener(this::onMonsterCreated);
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterDeadListener(this::onMonsterDead);
|
||||||
|
// spawn the first turn
|
||||||
|
for (int i = 0; i < this.monsterSceneLimit; i++) {
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().spawnMonster(group.id, getNextMonster());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMonsterCreated(EntityMonster entityMonster){
|
||||||
|
if(this.monsterSceneLimit > 0){
|
||||||
|
this.monsterTideCount.decrementAndGet();
|
||||||
|
this.monsterAlive.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SceneMonster getNextMonster(){
|
||||||
|
var nextId = this.monsterConfigOrders.poll();
|
||||||
|
if(currentGroup.monsters.containsKey(nextId)){
|
||||||
|
return currentGroup.monsters.get(nextId);
|
||||||
|
}
|
||||||
|
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
||||||
|
return currentGroup.monsters.values().stream().findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMonsterDead(EntityMonster entityMonster){
|
||||||
|
if(this.monsterSceneLimit <= 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this.monsterAlive.decrementAndGet() >= this.monsterSceneLimit) {
|
||||||
|
// maybe not happen
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.monsterKillCount.incrementAndGet();
|
||||||
|
if(this.monsterTideCount.get() > 0){
|
||||||
|
// add more
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().spawnMonster(this.currentGroup.id, getNextMonster());
|
||||||
|
}else if(this.monsterAlive.get() == 0){
|
||||||
|
// spawn the last turn of monsters
|
||||||
|
this.sceneScriptManager.callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs(this.monsterKillCount.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
import emu.grasscutter.net.proto.TowerMiddleLevelChangeTeamNotifyOuterClass;
|
||||||
|
|
||||||
|
public class PacketTowerMiddleLevelChangeTeamNotify extends BasePacket {
|
||||||
|
|
||||||
|
public PacketTowerMiddleLevelChangeTeamNotify() {
|
||||||
|
super(PacketOpcodes.TowerMiddleLevelChangeTeamNotify);
|
||||||
|
|
||||||
|
TowerMiddleLevelChangeTeamNotifyOuterClass.TowerMiddleLevelChangeTeamNotify proto =
|
||||||
|
TowerMiddleLevelChangeTeamNotifyOuterClass.TowerMiddleLevelChangeTeamNotify.newBuilder()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user