#!/usr/bin/python # -*- coding: GBK -*- #------------------------------------------------------------------------------- # #------------------------------------------------------------------------------- # ##@package GameWorldLogic.FBProcess.GameLogic_ChaosDemon # # @todo:»ìÂÒÑýÓò # @author xdh # @date 2016-06-04 16:00 # @version 1.0 # # # ÏêϸÃèÊö: »ìÂÒÑýÓò # #--------------------------------------------------------------------- #"""Version = 2017-06-23 16:30""" #--------------------------------------------------------------------- import FBCommon import IPY_GameWorld import GameWorldProcess import GameWorld import PlayerControl import NPCCustomRefresh import ItemControler import IpyGameDataPY import ChConfig import ShareDefine import ItemCommon import PlayerSuccess import FBHelpBattle import EventReport import PlayerWeekParty import math ( Def_PrepareTime, # ×¼±¸Ê±¼ä, Ãë Def_FightTime, # ¸±±¾Ê±¼ä, Ãë Def_ExitTime, # Í˳öʱ¼ä, Ãë Def_StarTime, # ÐǼ¶¶ÔÓ¦ºÄʱÅäÖÃ, Ãë ) = range(4) # ¸±±¾×´Ì¬ ( FB_Step_Open, #¿ªÆô FB_Step_Prepare, #×¼±¸ÖÐ FB_Step_Fight, # Õ½¶·ÖÐ FB_Step_Over, # ½áÊøµÈ´ý FB_Step_Close, # ¹Ø±ÕÖÐ ) = range(5) ChaosDemon_FBNextRefreshStep = 'ChaosDemon_FBNextRefreshStep' # Ë¢¹Ö½×¶ÎÊý ChaosDemon_FBNPCCnt = 'ChaosDemon_FBNPCCnt' # ¸±±¾Ê£Óà¹ÖÎïÊý ChaosDemon_FBNPCNeedRefreshCnt = 'ChaosDemon_FBNPCNeedRefreshCnt' # »¹ÐèˢеĹÖÎïÊý ChaosDemon_FBNPCRefreshCnt = 'ChaosDemon_FBNPCRefreshCnt' # µ±ÂÖˢеĹÖÎïÊý ChaosDemon_FBStar = 'ChaosDemon_FBStar' # µ±Ç°¸±±¾ÐǼ¶ ## OnDay´¦Àí # @param curPlayer # @return None def ChaosDemonOnDay(curPlayer): return ##---»ñµÃ¸±±¾Ë¢¹ÖÅäÖÃ--- # @param None # @return ÅäÖÃÐÅÏ¢ def __GetChaosDemonnpcCfg(): return IpyGameDataPY.GetFuncEvalCfg('ChaosDemonCfg') ##¿ªÆô¸±±¾ # @param tick ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå # @remarks ¿ªÆô¸±±¾ def OnOpenFB(tick): return ##¹Ø±Õ¸±±¾ # @param tick ʱ¼ä´Á # @return ÎÞÒâÒå # @remarks def OnCloseFB(tick): return ## ÊÇ·ñÄܹ»Í¨¹ý»î¶¯²éѯ½øÈë # @param curPlayer Íæ¼ÒʵÀý # @param mapID µØÍ¼ID # @param lineID Ïß·id # @param tick ʱ¼ä´Á # @return ²¼¶ûÖµ def OnEnterFBEvent(curPlayer, mapID, lineID, tick): return True ##¸±±¾Íæ¼Ò½øÈëµã # @param curPlayer Íæ¼ÒʵÀý # @param mapID µØÍ¼ID # @param lineId ·ÖÏßID # @param tick ʱ¼ä´Á # @return ×ø±êÁбí(X,Y) # @remarks ¸±±¾Íæ¼Ò½øÈëµã def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick): return ipyEnterPosInfo ##ÊÇ·ñ¿ÉÒÔ½øÈë # @param ask ÇëÇó½á¹¹Ìå # @param tick ʱ¼ä´Á # @return TChangeMapError # @remarks ÑéÖ¤¼Ò×åÊÇ·ñÔÚ½ñÌìµÄ¼Ò×åÕ½±í def OnChangeMapAsk(ask, tick): return IPY_GameWorld.cmeAccept ##Íæ¼Ò½øÈ븱±¾ # @param curPlayer Íæ¼ÒʵÀý # @param tick ʱ¼ä´Á # @return ÎÞÒâÒå # @remarks Íæ¼Ò½øÈ븱±¾ def DoEnterFB(curPlayer, tick): mapID = GameWorld.GetGameWorld().GetMapID() mapID = FBCommon.GetRecordMapID(mapID) gameFB = GameWorld.GetGameFB() ChaosDemonCfg = FBCommon.GetFBLineStepTime(mapID) # ÉèÖø±±¾¹«¹²ÊôÐԵĵ¥¶À´¦Àí£¬·ÀÖ¹¶ÓÔ±½øÈëºó±»ÐÞ¸Ä if not FBCommon.GetHadSetFBPropertyMark(): lineID = 0 FBCommon.SetFBPropertyMark(lineID) if gameFB.GetFBStep() == FB_Step_Open: FBCommon.SetFBStep(FB_Step_Prepare, tick) gameFB.SetGameFBDict(ChaosDemon_FBNextRefreshStep, 0) gameFB.SetGameFBDict(ChaosDemon_FBNPCCnt, 0) gameFB.SetGameFBDict(ChaosDemon_FBNPCRefreshCnt, 0) GameWorld.DebugLog("ChaosDemon DoEnterFB lineID=%s£¡" % FBCommon.GetFBPropertyMark(), curPlayer.GetID()) # ½øÈëÏûºÄ´¦Àí if not FBCommon.GetHadDelTicket(curPlayer): FBCommon.SetHadDelTicket(curPlayer) isHelpFight = False if FBCommon.SetIsHelpFight(curPlayer): isHelpFight = True GameWorld.DebugLog("ChaosDemon ÖúÕ½½øÈ븱±¾£¡", curPlayer.GetID()) # Ôö¼ÓÍæ¼Ò½øÈ븱±¾´ÎÊý FBCommon.AddEnterFBCount(curPlayer, mapID, 1) joinType = FBCommon.GetFBJoinType(curPlayer, isHelpFight) EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_ChaosDemon, 0, ChConfig.CME_Log_Start, joinType) PlayerWeekParty.AddWeekPartyActionCnt(curPlayer, ChConfig.Def_WPAct_ChaosDemon, 1) fbStep = gameFB.GetFBStep() if fbStep <= FB_Step_Prepare: notify_tick = ChaosDemonCfg[Def_PrepareTime] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick()) curPlayer.Sync_TimeTick(IPY_GameWorld.tttAddUpTime, 0, max(notify_tick, 0), True) curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True) elif fbStep == FB_Step_Fight: notify_tick = ChaosDemonCfg[Def_FightTime] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick()) curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True) __UpdChaosDemonFBStar(tick, True, curPlayer) FBHelpBattle.RefershTeamFBMemRelation(tick) #DoFBHelp(curPlayer, tick) return ## ×çÖä³Ç±¤Ë¢¹Ö # @return: True-ÒÑͨ¹Ø def __RefreshChaosDemonNextNPC(): gameFB = GameWorld.GetGameFB() npcCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCCnt) needRefreshCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCNeedRefreshCnt) # »¹ÓÐ¹Ö or »¹Ã»Ë¢Í꣬²»Ö´ÐÐÏÂÒ»²¨Ë¢Ð if npcCnt > 0 or needRefreshCnt > 0: return refreshStep = gameFB.GetGameFBDictByKey(ChaosDemon_FBNextRefreshStep) refreshNPCList = __GetChaosDemonnpcCfg() rMarkList = IpyGameDataPY.GetFuncEvalCfg('ChaosDemonCfg', 2) if refreshStep >= len(refreshNPCList) or refreshStep >= len(rMarkList): # ÒÑÊÇ×îºóÒ»²¨, ͨ¹Ø GameWorld.DebugLog("ÒÑÊÇ×îºóÒ»²¨, ͨ¹Ø") return True rMark = rMarkList[refreshStep] rNPCList = refreshNPCList[refreshStep] needRefreshCnt = 0 for rNPCInfo in rNPCList: needRefreshCnt += rNPCInfo[1] gameFB.SetGameFBDict(ChaosDemon_FBNPCRefreshCnt, needRefreshCnt) gameFB.SetGameFBDict(ChaosDemon_FBNPCNeedRefreshCnt, needRefreshCnt) NPCCustomRefresh.SetNPCRefresh(rMark, rNPCList, needRefreshCnt, needRefreshCnt) # ¸üÐÂÏÂÒ»²¨½×¶ÎÖµ gameFB.SetGameFBDict(ChaosDemon_FBNextRefreshStep, refreshStep + 1) #gameFB.SetGameFBDict(ChaosDemon_GameStep, refreshStep + 1) return ##Íæ¼ÒÍ˳ö¸±±¾. # @param curPlayer Íæ¼ÒʵÀý # @param tick ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå def DoExitFB(curPlayer, tick): GameWorld.DebugLog("ChaosDemon DoExitFB...", curPlayer.GetPlayerID()) fbStep = GameWorld.GetGameFB().GetFBStep() if fbStep <= FB_Step_Fight: FBHelpBattle.RefershTeamFBMemRelation(tick, curPlayer.GetPlayerID()) return ##Íæ¼ÒÖ÷¶¯À뿪¸±±¾. # @param curPlayer Íæ¼ÒʵÀý # @param tick ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå def DoPlayerLeaveFB(curPlayer, tick): GameWorld.DebugLog("ChaosDemon DoPlayerLeaveFB...", curPlayer.GetPlayerID()) return ##Íæ¼Ò¸±±¾¸´»î # @param curPlayer Íæ¼ÒʵÀý # @param rebornType # @param tick ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå def DoFBOnReborn(curPlayer, rebornType, tick): GameWorld.DebugLog("ChaosDemon DoFBOnReborn...rebornType=%s" % rebornType) #»Ø³Ç¸´»îÖØÖà return ## »ñÈ¡È볡Я´øÐÅÏ¢ # @param curPlayer # @param lineId ·ÖÏß # @return ×Ö·ûÐÍ ½øÈëÐéÄâ·ÖÏßID def GetPlayerResetWorldPosFBMsg(curPlayer, lineId): return "" ##¸±±¾¶¨Ê±Æ÷ # @param tick ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå # @remarks ¸±±¾¶¨Ê±Æ÷ def OnProcess(tick): fbStep = GameWorld.GetGameFB().GetFBStep() # ¸±±¾×¼±¸ if fbStep == FB_Step_Prepare: __DoLogic_FB_Prepare(tick) elif fbStep == FB_Step_Fight: __ProcessOverFight(tick) __UpdChaosDemonFBStar(tick) elif fbStep == FB_Step_Over: __ProcessCloseFB(tick) return ## ¸±±¾×¼±¸Âß¼­ # @param tick:ʱ¼ä´Á # @return ÎÞÒâÒå def __DoLogic_FB_Prepare(tick): #gameFB = GameWorld.GetGameFB() mapID = GameWorld.GetMap().GetMapID() fbCfg = FBCommon.GetFBLineStepTime(mapID) # ¼ä¸ôδµ½ if tick - GameWorld.GetGameFB().GetFBStepTick() < fbCfg[Def_PrepareTime] * 1000: return FBHelpBattle.RefershTeamFBMemRelation(tick) __RefreshChaosDemonNextNPC() playerManager = GameWorld.GetMapCopyPlayerManager() for i in range(playerManager.GetPlayerCount()): curPlayer = playerManager.GetPlayerByIndex(i) if not curPlayer: continue DoFBHelp(curPlayer, tick) FBCommon.SetFBStep(FB_Step_Fight, tick) FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttTowerTake, fbCfg[Def_FightTime] * 1000) return ## ɱ¹Ö½áÊø # @param tick # @return None def __ProcessOverFight(tick): mapID = GameWorld.GetMap().GetMapID() FightTime = FBCommon.GetFBLineStepTime(mapID)[Def_FightTime] openTick = GameWorld.GetGameWorld().GetOpenFBTick() if max(0, FightTime * 1000 - (tick - openTick)) > 0: return __DoChaosDemonOver(False, tick) return ## ¸±±¾¹Ø±Õ # @param tick # @return None def __ProcessCloseFB(tick): gameFB = GameWorld.GetGameFB() mapID = GameWorld.GetMap().GetMapID() if tick - gameFB.GetFBStepTick() < FBCommon.GetFBLineStepTime(mapID)[Def_ExitTime] * 1000: return FBCommon.DoLogic_FBKickAllPlayer() GameWorldProcess.CloseFB(tick) FBCommon.SetFBStep(FB_Step_Close, tick) return def __DoChaosDemonOver(isPass, tick): # Õ½¶·³¬Ê± gameFB = GameWorld.GetGameFB() if gameFB.GetFBStep() == FB_Step_Over: return costTime = tick - GameWorld.GetGameFB().GetFBStepTick() FBCommon.SetFBStep(FB_Step_Over, tick) mapID = GameWorld.GetMap().GetMapID() mapID = FBCommon.GetRecordMapID(mapID) star = GameWorld.GetGameFB().GetGameFBDictByKey(ChaosDemon_FBStar) itemDict = IpyGameDataPY.GetFuncEvalCfg('ChaosDemonReward') rateDict = IpyGameDataPY.GetFuncEvalCfg('ChaosDemonReward', 2, {}) giveExp = IpyGameDataPY.GetFuncCfg('ChaosDemonReward', 3) rate = rateDict.get(star, 0) prizeItemList = [] for itemID, itemCnt in itemDict.items(): # cnt = int(itemCnt*rate/100) # if cnt: prizeItemList.append([itemID, itemCnt, 1]) prizeItemList += IpyGameDataPY.GetFuncEvalCfg('ChaosDemonReward', 4, {}).get(star, []) exitTime = FBCommon.GetFBLineStepTime(mapID)[Def_ExitTime] * 1000 playerManager = GameWorld.GetMapCopyPlayerManager() playerCount = playerManager.GetPlayerCount() for index in xrange(playerCount): curPlayer = playerManager.GetPlayerByIndex(index) if not curPlayer: continue curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, exitTime, True) if not isPass: FBCommon.Notify_FB_Over(curPlayer, {FBCommon.Over_isPass: 0}) continue overDict = {FBCommon.Over_grade:star,FBCommon.Over_dataMapID:mapID,FBCommon.Over_isPass:int(isPass), FBCommon.Over_costTime:costTime} isHelp = False if FBCommon.GetIsHelpFight(curPlayer): isHelp = True else: #¸ø½±Àø needSpace = len(prizeItemList) emptySpace = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, needSpace) isSendMail = int(needSpace > emptySpace) # ÊÇ·ñ·¢ËÍÓʼþ if isSendMail: PlayerControl.SendMailByKey("ChaosDemonMail", [curPlayer.GetPlayerID()], prizeItemList) GameWorld.DebugLog("±³°ü¿Õ¼ä²»¹»£¬·¢ËÍÓʼþ: mailItemList=%s" % str(prizeItemList), curPlayer.GetPlayerID()) else: for itemID, itemCnt, isBind in prizeItemList: ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, 0, [IPY_GameWorld.rptItem], event=["ChaosDemon", False, {}]) reExp = PlayerControl.GetPlayerReExp(curPlayer) addExp = int(eval(giveExp) * rate/100) PlayerControl.PlayerControl(curPlayer).AddExp(addExp) # ֪ͨ½á¹û overDict[FBCommon.Over_itemInfo] = FBCommon.GetJsonItemList(prizeItemList) exp = addExp % ChConfig.Def_PerPointValue expPoint = addExp / ChConfig.Def_PerPointValue overDict[FBCommon.Over_exp] = exp overDict[FBCommon.Over_expPoint] = expPoint FBCommon.Notify_FB_Over(curPlayer, overDict) #³É¾Í PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_ChaosDemon, 1, [playerCount, star]) GameWorld.DebugLog("__SendChaosDemonOverInfo overDict=%s" % (str(overDict)), curPlayer.GetPlayerID()) return ##¸±±¾ÓÐNPCÕÙ³ö # @param curNPC: # @param tick:tick # @return None def DoFBRebornNPC(curNPC, tick): if curNPC.GetNPCID() not in __GetAllNPCIDList(): return gameFB = GameWorld.GetGameFB() npcCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCCnt) needRefreshCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCNeedRefreshCnt) npcCnt += 1 needRefreshCnt -= 1 gameFB.SetGameFBDict(ChaosDemon_FBNPCCnt, npcCnt) gameFB.SetGameFBDict(ChaosDemon_FBNPCNeedRefreshCnt, needRefreshCnt) GameWorld.DebugLog("DoFBRebornNPC, npcID=%s,ChaosDemon_FBNPCCnt=%s,needRefreshCnt=%s" % (curNPC.GetNPCID(), npcCnt, needRefreshCnt)) if needRefreshCnt <= 0: GameWorld.DebugLog("±¾²¨¹ÖÎïË¢ÐÂÍê±Ï£¡npcCnt=%s" % npcCnt) return def __GetAllNPCIDList(): refreshNPCList = __GetChaosDemonnpcCfg() npcIDList = [] for rList in refreshNPCList: for npcid, npccnt in rList: npcIDList.append(npcid) return npcIDList ##Íæ¼ÒɱËÀNPC # @param curPlayer:Íæ¼ÒʵÀý # @param curNPC:µ±Ç°±»É±ËÀµÄNPC # @param tick:ʱ¼ä´Á # @return ·µ»ØÖµÎÞÒâÒå # @remarks Íæ¼ÒÖ÷¶¯À뿪¸±±¾. def DoFB_Player_KillNPC(curPlayer, curNPC, tick): if curNPC.GetNPCID() not in __GetAllNPCIDList(): return gameFB = GameWorld.GetGameFB() npcCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCCnt) needRefreshCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCNeedRefreshCnt) npcCnt -= 1 gameFB.SetGameFBDict(ChaosDemon_FBNPCCnt, npcCnt) GameWorld.DebugLog("DoFB_Player_KillNPC, npcID=%s,ChaosDemon_FBNPCCnt=%s,needRefreshCnt=%s" % (curNPC.GetNPCID(), npcCnt, needRefreshCnt)) if npcCnt <= 0 and needRefreshCnt <= 0: GameWorld.DebugLog("±¾²¨ËùÓйÖÎïÒѱ»»÷ɱ£¡") isAllKilled = __RefreshChaosDemonNextNPC() if isAllKilled: __DoChaosDemonOver(True, tick) FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0) return ## ¼ì²éÊÇ·ñ¿É¹¥»÷£¬ Ö÷Åж¨²»¿É¹¥»÷µÄÇé¿ö£¬ÆäËûÂß¼­ÓÉÍâ²ã¾ö¶¨ # @param attacker ¹¥»÷·½ # @param defender ·ÀÊØ·½ # @return bool def CheckCanAttackTagObjInFB(attacker, defender): gameFB = GameWorld.GetGameFB() if gameFB.GetFBStep() != FB_Step_Fight: return False return True ## Íæ¼Ò¹¥»÷Íæ¼ÒÊÇ·ñÓгͷ£ # @param atkPlayer: ¹¥»÷·½ # @param defPlayer: ·ÀÊØ·½ # @return Íæ¼Ò¹¥»÷Íæ¼ÒÊÇ·ñÓгͷ£ def DoFBAttackHasPunish(atkPlayer, defPlayer): return True ## ¸üе±Ç°¸±±¾ÐǼ¶ def __UpdChaosDemonFBStar(tick, isEnter=False, curPlayer=None): gameFB = GameWorld.GetGameFB() curStar = gameFB.GetGameFBDictByKey(ChaosDemon_FBStar) if curStar == 1: return curStar mapID = GameWorld.GetMap().GetMapID() useSecond = int(math.ceil((tick - gameFB.GetFBStepTick()) / 1000.0)) chaosDemonCfg = FBCommon.GetFBLineStepTime(mapID) starTimeList = chaosDemonCfg[Def_StarTime] diffSecond = 0 updStar = 1 # ĬÈÏÖÁÉÙ1ÐÇ for star, starTime in enumerate(starTimeList, 2): if useSecond <= starTime: updStar = star diffSecond = starTime-useSecond if curStar == updStar and not isEnter: return curStar gameFB.SetGameFBDict(ChaosDemon_FBStar, updStar) GameWorld.DebugLog("__UpdFBStar useSecond=%s,curStar=%s,updStar=%s, diffSecond=%s" % (useSecond, curStar, updStar, diffSecond)) if curPlayer: DoFBHelp(curPlayer, tick) if updStar != 1: curPlayer.Sync_TimeTick(IPY_GameWorld.tttFlagTake, 0, diffSecond * 1000, True) else: playerManager = GameWorld.GetMapCopyPlayerManager() for index in xrange(playerManager.GetPlayerCount()): curPlayer = playerManager.GetPlayerByIndex(index) if not curPlayer: continue DoFBHelp(curPlayer, tick) if updStar != 1: curPlayer.Sync_TimeTick(IPY_GameWorld.tttFlagTake, 0, diffSecond * 1000, True) return updStar ##¸±±¾°ïÖúÐÅÏ¢ # @param curPlayer Íæ¼ÒʵÀý # @param tick ʱ¼ä´Á # @return ÎÞÒâÒå # @remarks ÓÃÓÚ֪ͨÕóÓª±È·ÖÌõ def DoFBHelp(curPlayer, tick): playerID = curPlayer.GetPlayerID() gameFB = GameWorld.GetGameFB() star = gameFB.GetGameFBDictByKey(ChaosDemon_FBStar) wheelNum = gameFB.GetGameFBDictByKey(ChaosDemon_FBNextRefreshStep) needKillCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCRefreshCnt) remainNPCCnt = gameFB.GetGameFBDictByKey(ChaosDemon_FBNPCCnt) KillNPCCnt = max(0, needKillCnt - remainNPCCnt) data = [KillNPCCnt, needKillCnt] lineID = FBCommon.GetFBPropertyMark() isHelp = FBCommon.GetIsHelpFight(curPlayer) helpCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FBRealHelpCount % ChConfig.Def_FBMapID_ChaosDemon) fbHelpDict = {FBCommon.Help_step:wheelNum, FBCommon.Help_grade:star, FBCommon.Help_npcTotal:KillNPCCnt, FBCommon.Help_lineID:lineID, FBCommon.Help_isHelp:isHelp, FBCommon.Help_helpCount:helpCount, FBCommon.Help_relation:FBHelpBattle.GetTeamFBMemRelationInfo(playerID)} FBCommon.Notify_FBHelp(curPlayer, fbHelpDict) GameWorld.DebugLog("DoFBHelp %s" % str(fbHelpDict), playerID) return ## ¸±±¾ÐÐΪ # @param curPlayer Íæ¼Ò # @param actionType ÐÐΪÀàÐÍ # @param actionInfo ÐÐΪÐÅÏ¢ # @param tick µ±Ç°Ê±¼ä # @return None def DoFBAction(curPlayer, actionType, actionInfo, tick): return