-
Notifications
You must be signed in to change notification settings - Fork 7
/
catch_to_live.py
377 lines (303 loc) · 14.6 KB
/
catch_to_live.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# coding=utf-8
# coding=utf8
import bs
import bsUtils
import random
class CheckNeedNewMadMessage(object):
def __init__(self, spaz=None):
self.spaz = spaz
class ClearProtectMessage(object):
def __init__(self):
pass
class grimPlayer(bs.PlayerSpaz):
def __init__(self, color, highlight, character, player, gameProtectionTime=3, hitPoints=5):
bs.PlayerSpaz.__init__(self, color=color, highlight=highlight, character=character, player=player)
self._inmad = False # 默认不是处于疯狂状态
self._madProtect = False # 默认处于无保护状态
self.hitPoints = hitPoints * 1000
self.hitPointsMax = self.hitPoints
self.gameProtectionTime = gameProtectionTime
self._startMadTime = None
self._allMadTime = None
self._startProtectTime = None
self.normalColor = color
self.madColor = (1, 0, 0)
self.protectColor = (0, 0, 1)
def handleMessage(self, m):
if isinstance(m, bs.PickedUpMessage):
if not self.getPlayer().isAlive():
return
oppoSpaz = m.node.getDelegate()
if not oppoSpaz.getPlayer().isAlive():
return
# 让对方放手
oppoSpaz.onPickUpRelease()
oppoSpaz.onPickUpPress()
oppoSpaz.onPickUpRelease()
if self._madProtect:
bs.PlayerSpaz.handleMessage(self, m)
return
if oppoSpaz._inmad:
oppoSpaz.stopMad()
oppoSpaz.protectAdd()
leftTime = (oppoSpaz._allMadTime - bs.getGameTime() + oppoSpaz._startMadTime)
self.onMad(leftTime)
bs.PlayerSpaz.handleMessage(self, m)
elif isinstance(m, bs.DieMessage):
self._inmad = False
if not self._dead and not m.immediate:
self._activity().handleMessage(CheckNeedNewMadMessage(self))
bs.PlayerSpaz.handleMessage(self, m)
else:
bs.PlayerSpaz.handleMessage(self, m)
def protectAdd(self):
# self.setScoreText(str(self.gameProtectionTime) + 's Crazy Protection')
self.setScoreText('Anti-Crazy')
self.node.color = self.protectColor
self._madProtect = True
self._startProtectTime = bs.getGameTime()
bs.gameTimer(self.gameProtectionTime * 1000, bs.Call(self.protectClear, self._startProtectTime))
# add hockey
self.node.hockey = True
def protectClear(self, checkProtectStartTime):
if self._madProtect and self._startProtectTime == checkProtectStartTime:
self._madProtect = False
if self._inmad:
# 躲不了系统给的MAD
return
self.node.color = self.normalColor
# add hockey
self.node.hockey = False
def onMad(self, madTime=10000):
# 10秒后炸掉
if self._inmad:
return
self._inmad = True
self.getPlayer().assignInputCall('pickUpPress', self.onPickUpPress)
self.getPlayer().assignInputCall('pickUpRelease', self.onPickUpRelease)
self.node.hockey = True
self.node.color = self.madColor
self._startMadTime = bs.getGameTime()
self._allMadTime = madTime
bs.gameTimer(madTime, bs.WeakCall(self.madExplode, self._startMadTime))
def stopMad(self):
self._inmad = False
self.getPlayer().assignInputCall('pickUpPress', lambda: None)
self.getPlayer().assignInputCall('pickUpRelease', lambda: None)
self.node.hockey = False
self.node.color = self.normalColor
def madExplode(self, checkStartTime):
if self._inmad and self._startMadTime == checkStartTime:
self.shatter(extreme=True)
self.handleMessage(bs.DieMessage())
def bsGetAPIVersion():
return 4
def bsGetGames():
return [CatchToLiveGame]
class CatchToLiveGame(bs.TeamGameActivity):
@classmethod
def getName(cls):
return 'Catch To Live'
@classmethod
def getScoreInfo(cls):
return {'scoreName': 'Survived',
'scoreType': 'milliseconds',
'scoreVersion': 'B'}
@classmethod
def getDescription(cls, sessionType):
return 'If you\'re CRAZY and don\'t wanna die\nThen PICKUP others!\nMOD By Deva(spdv123 on GitHub)\n'
@classmethod
def getSupportedMaps(cls, sessionType):
# return ['Rampage']
return bs.getMapsSupportingPlayType("melee")
@classmethod
def getSettings(cls, sessionType):
return [("Mad Time To Die (Approximate)", {'minValue': 5, 'default': 10, 'increment': 1}),
("Protection Time After Catching", {'minValue': 1, 'default': 3, 'increment': 1}),
("Player HP", {
'choices': [('normal', 1), ('2 times', 2), ('3 times', 3), ('5 times', 5), ('7 times', 7),
('10 times', 10)], 'default': 5}),
("Epic Mode", {'default': False}),
("Allow Landmine", {'default': True})]
# we support teams, free-for-all, and co-op sessions
@classmethod
def supportsSessionType(cls, sessionType):
return True if (issubclass(sessionType, bs.FreeForAllSession)) else False
def __init__(self, settings):
bs.TeamGameActivity.__init__(self, settings)
if self.settings['Epic Mode']: self._isSlowMotion = True
# print messages when players die (since its meaningful in this game)
self.announcePlayerDeaths = True
self._lastPlayerDeathTime = None
# called when our game is transitioning in but not ready to start..
# ..we can go ahead and set our music and whatnot
def onTransitionIn(self):
bs.TeamGameActivity.onTransitionIn(self, music='Epic' if self.settings['Epic Mode'] else 'Survival')
# called when our game actually starts
def onBegin(self):
# self.playerList = []
bs.TeamGameActivity.onBegin(self)
self._madTime = self.settings['Mad Time To Die (Approximate)'] * 1000
# bs.gameTimer(t,self._decrementMeteorTime,repeat=True)
# kick off the first wave in a few seconds
t = 3000
if self.settings['Epic Mode']: t /= 4
# bs.gameTimer(t,self._setMeteorTimer)
self._timer = bs.OnScreenTimer()
self._timer.start()
bs.gameTimer(10, bs.WeakCall(self.updateSpazText), repeat=True)
bs.gameTimer(t, bs.WeakCall(self.handleMessage, CheckNeedNewMadMessage()), repeat=False)
bs.gameTimer(1000, self._checkNeedMad, repeat=True)
# bs.gameTimer(5000, self._checkEndGame) # 4秒之后检测一波
def updateSpazText(self):
for team in self.teams:
for player in team.players:
try:
if player.actor._inmad:
leftTime = (player.actor._allMadTime - bs.getGameTime() + player.actor._startMadTime) / 1000.0
if leftTime > 0.0:
player.actor.setScoreText('Crazy')
# player.actor.setScoreText('%.2f' % (leftTime), color=(1, 1, 1))
else:
player.actor.setScoreText('')
elif player.actor._madProtect:
player.actor.setScoreText('Anti-Crazy')
else:
player.actor.setScoreText('')
except:
pass
# overriding the default character spawning..
def spawnPlayer(self, player):
position = self.getMap().getFFAStartPosition(self.players)
angle = 20
name = player.getName()
lightColor = bsUtils.getNormalizedColor(player.color)
displayColor = bs.getSafeColor(player.color, targetIntensity=0.75)
spaz = grimPlayer(color=player.color,
highlight=player.highlight,
character=player.character,
player=player,
gameProtectionTime=self.settings['Protection Time After Catching'],
hitPoints=self.settings['Player HP'])
player.setActor(spaz)
# For some reason, I can't figure out how to get a list of all spaz.
# Therefore, I am making the list here so I can get which spaz belongs
# to the player supplied by HitMessage.
# self.playerList.append(spaz)
spaz.node.name = name
spaz.node.nameColor = displayColor
spaz.connectControlsToPlayer()
self.scoreSet.playerGotNewSpaz(player, spaz)
# add landmine
spaz.bombTypeDefault = 'landMine' # random.choice(['ice', 'impact', 'landMine', 'normal', 'sticky', 'tnt'])
spaz.bombType = spaz.bombTypeDefault
# move to the stand position and add a flash of light
spaz.handleMessage(bs.StandMessage(position, angle if angle is not None else random.uniform(0, 360)))
t = bs.getGameTime()
bs.playSound(self._spawnSound, 1, position=spaz.node.position)
light = bs.newNode('light', attrs={'color': lightColor})
spaz.node.connectAttr('position', light, 'position')
bsUtils.animate(light, 'intensity', {0: 0, 250: 1, 500: 0})
bs.gameTimer(500, light.delete)
# lets reconnect this player's controls to this
# spaz but *without* the ability to attack or pick stuff up
spaz.connectControlsToPlayer(enablePunch=False,
enableBomb=self.settings['Allow Landmine'],
enablePickUp=False)
# player.assignInputCall('pickUpPress', lambda: None)
# player.assignInputCall('pickUpRelease', lambda: None)
# also lets have them make some noise when they die..
spaz.playBigDeathSound = True
return spaz
def onPlayerJoin(self, player):
# don't allow joining after we start
# (would enable leave/rejoin tomfoolery)
if self.hasBegun():
bs.screenMessage(bs.Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', player.getName(full=True))]),
color=(0, 1, 0))
# for score purposes, mark them as having died right as the game started
player.gameData['noScore'] = True
return
self.spawnPlayer(player)
def onPlayerLeave(self, player):
# augment default behavior...
bs.TeamGameActivity.onPlayerLeave(self, player)
# a departing player may trigger game-over
bs.gameTimer(100, bs.Call(self._checkEndGame))
# various high-level game events come through this method
def handleMessage(self, m):
if isinstance(m, bs.PlayerSpazDeathMessage):
bs.TeamGameActivity.handleMessage(self, m) # (augment standard behavior)
deathTime = bs.getGameTime()
# record the player's moment of death
m.spaz.getPlayer().gameData['deathTime'] = deathTime
# in co-op mode, end the game the instant everyone dies (more accurate looking)
# in teams/ffa, allow a one-second fudge-factor so we can get more draws
if isinstance(self.getSession(), bs.CoopSession):
# teams will still show up if we check now.. check in the next cycle
bs.pushCall(self._checkEndGame)
self._lastPlayerDeathTime = deathTime # also record this for a final setting of the clock..
else:
bs.gameTimer(1000, self._checkEndGame)
elif isinstance(m, CheckNeedNewMadMessage):
self._checkNeedMad()
else:
# default handler:
bs.TeamGameActivity.handleMessage(self, m)
def _checkNeedMad(self):
# print('check if we need a new mad')
alivePlayers = []
for team in self.teams:
for player in team.players:
if player.isAlive():
alivePlayers.append(player)
if player.actor._inmad:
# print('no need for new mad')
return
if len(alivePlayers) == 0:
return
selectedPlayer = random.choice(alivePlayers)
selectedPlayer.actor.onMad(random.randint(self._madTime - 2500, self._madTime + 2500))
def _checkEndGame(self):
livingTeamCount = 0
for team in self.teams:
for player in team.players:
if player.isAlive():
livingTeamCount += 1
break
# in co-op, we go till everyone is dead.. otherwise we go until one team remains
if isinstance(self.getSession(), bs.CoopSession):
if livingTeamCount <= 0: self.endGame()
else:
if livingTeamCount <= 1: self.endGame()
def endGame(self):
curTime = bs.getGameTime()
# mark 'death-time' as now for any still-living players
# and award players points for how long they lasted.
# (these per-player scores are only meaningful in team-games)
for team in self.teams:
for player in team.players:
# throw an extra fudge factor +1 in so teams that
# didn't die come out ahead of teams that did
if 'deathTime' not in player.gameData: player.gameData['deathTime'] = curTime + 1
if 'noScore' in player.gameData: player.gameData['deathTime'] = self._timer.getStartTime()
# award a per-player score depending on how many seconds they lasted
# (per-player scores only affect teams mode; everywhere else just looks at the per-team score)
score = (player.gameData['deathTime'] - self._timer.getStartTime()) / 1000
if 'deathTime' not in player.gameData: score += 50 # a bit extra for survivors
self.scoreSet.playerScored(player, score, screenMessage=False)
# stop updating our time text, and set the final time to match
# exactly when our last guy died.
self._timer.stop(endTime=self._lastPlayerDeathTime)
# ok now calc game results: set a score for each team and then tell the game to end
results = bs.TeamGameResults()
# remember that 'free-for-all' mode is simply a special form of 'teams' mode
# where each player gets their own team, so we can just always deal in teams
# and have all cases covered
for team in self.teams:
# set the team score to the max time survived by any player on that team
longestLife = 0
for player in team.players:
longestLife = max(longestLife, (player.gameData['deathTime'] - self._timer.getStartTime()))
results.setTeamScore(team, longestLife)
self.end(results=results)