├── README.md ├── __init__.py ├── __pycache__ ├── MyEncoder.cpython-38.pyc ├── Run_chara.cpython-38.pyc ├── Runchara.cpython-38.pyc └── __init__.cpython-38.pyc ├── config.json ├── fonts └── msyh.ttf └── runchara.py /README.md: -------------------------------------------------------------------------------- 1 | # Pcr_Run 2 | 3 | 本插件为pcr角色的赛跑小游戏,使用HoshinoV2开发,内置了分群积分和下注系统。 4 | 5 | ## 安装 6 | 7 | 把项目文件放在名称为pcr_run文件夹里, 直接丢到hoshinobot的priconne里应该就可以了。 8 | 9 | ## 指令表 10 | 11 | 1. 群管理员以上权限发 测试赛跑 即可以开始赛跑,这个权限可以自己更改。 12 | 2. 发送 查金币 查询自己的赛跑积分。 13 | 3. 发送 领金币 可以在自己赛跑积分为0 时领取50积分。 14 | 4. 发送 赛跑排行榜 可以查询本群赛跑金币排行。 15 | 5. 发送 重置赛跑 可以重置赛跑状态(仅管理以上权限可用,仅用于赛跑卡死情况。) 16 | 17 | ## 自行设计添加角色 18 | 19 | 0. python新手,代码写的一般般,角色信息都在config.json里,有兴趣可以仿照着添加角色。 20 | 1. speed的列表决定跑动速度,每次跑动的距离从列表里随机抽一个。 21 | 2. skill_prob代表技能触发概率。 22 | 3. skill_text是技能文本。 23 | 4. skill_effect是用exec()实现的技能效果部分,直接用主文件里的技能函数,函数间用\n隔开,如果有技能效果中的额外文本,赋值给text即可,会补在技能文本后面。 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from hoshino import Service, R 2 | from hoshino.typing import * 3 | from hoshino import Service, priv, util 4 | from hoshino.util import DailyNumberLimiter, pic2b64, concat_pic, silence 5 | import sqlite3, os, random, asyncio 6 | from nonebot import MessageSegment 7 | from hoshino import Service 8 | from hoshino.typing import CQEvent 9 | import random 10 | import heapq 11 | from . import runchara 12 | import copy 13 | from PIL import Image,ImageFont,ImageDraw 14 | from io import BytesIO 15 | import base64 16 | sv = Service('pcr-run', enable_on_default=True) 17 | 18 | ROAD = '=' 19 | ROADLENGTH = 16 20 | TOTAL_NUMBER = 10 21 | NUMBER = 5 22 | ONE_TURN_TIME = 3 23 | SUPPORT_TIME = 30 24 | RUN_DB_PATH = os.path.expanduser('~/.hoshino/pcr_running_counter.db') 25 | FILE_PATH = os.path.dirname(__file__) 26 | #如果此项为True,则技能由图片形式发送,减少风控。 27 | SKILL_IMAGE = True 28 | class RunningJudger: 29 | def __init__(self): 30 | self.on = {} 31 | self.support = {} 32 | self.support_on = {} 33 | 34 | def set_support(self,gid): 35 | self.support[gid] = {} 36 | def get_support(self,gid): 37 | return self.support[gid] if self.support.get(gid) is not None else 0 38 | def add_support(self,gid,uid,id,score): 39 | self.support[gid][uid]=[id,score] 40 | def get_support_id(self,gid,uid): 41 | if self.support[gid].get(uid) is not None: 42 | return self.support[gid][uid][0] 43 | else : 44 | return 0 45 | def get_support_score(self,gid,uid): 46 | if self.support[gid].get(uid) is not None: 47 | return self.support[gid][uid][1] 48 | else : 49 | return 0 50 | def get_on_off_status(self, gid): 51 | return self.on[gid] if self.on.get(gid) is not None else False 52 | def turn_on(self, gid): 53 | self.on[gid] = True 54 | def turn_off(self, gid): 55 | self.on[gid] = False 56 | #下注开关 57 | def get_on_off_support_status(self, gid): 58 | return self.support_on[gid] if self.support_on.get(gid) is not None else False 59 | def turn_on_support(self, gid): 60 | self.support_on[gid] = True 61 | def turn_off_support(self, gid): 62 | self.support_on[gid] = False 63 | 64 | 65 | 66 | 67 | running_judger = RunningJudger() 68 | 69 | class ScoreCounter: 70 | def __init__(self): 71 | os.makedirs(os.path.dirname(RUN_DB_PATH), exist_ok=True) 72 | self._create_table() 73 | 74 | 75 | def _connect(self): 76 | return sqlite3.connect(RUN_DB_PATH) 77 | 78 | 79 | def _create_table(self): 80 | try: 81 | self._connect().execute('''CREATE TABLE IF NOT EXISTS SCORECOUNTER 82 | (GID INT NOT NULL, 83 | UID INT NOT NULL, 84 | SCORE INT NOT NULL, 85 | PRIMARY KEY(GID, UID));''') 86 | except: 87 | raise Exception('创建表发生错误') 88 | 89 | 90 | def _add_score(self, gid, uid ,score): 91 | try: 92 | current_score = self._get_score(gid, uid) 93 | conn = self._connect() 94 | conn.execute("INSERT OR REPLACE INTO SCORECOUNTER (GID,UID,SCORE) \ 95 | VALUES (?,?,?)", (gid, uid, current_score+score)) 96 | conn.commit() 97 | except: 98 | raise Exception('更新表发生错误') 99 | 100 | def _reduce_score(self, gid, uid ,score): 101 | try: 102 | current_score = self._get_score(gid, uid) 103 | if current_score >= score: 104 | conn = self._connect() 105 | conn.execute("INSERT OR REPLACE INTO SCORECOUNTER (GID,UID,SCORE) \ 106 | VALUES (?,?,?)", (gid, uid, current_score-score)) 107 | conn.commit() 108 | else: 109 | conn = self._connect() 110 | conn.execute("INSERT OR REPLACE INTO SCORECOUNTER (GID,UID,SCORE) \ 111 | VALUES (?,?,?)", (gid, uid, 0)) 112 | conn.commit() 113 | except: 114 | raise Exception('更新表发生错误') 115 | 116 | def _get_score(self, gid, uid): 117 | try: 118 | r = self._connect().execute("SELECT SCORE FROM SCORECOUNTER WHERE GID=? AND UID=?",(gid,uid)).fetchone() 119 | return 0 if r is None else r[0] 120 | except: 121 | raise Exception('查找表发生错误') 122 | 123 | #判断金币是否足够下注 124 | def _judge_score(self, gid, uid ,score): 125 | try: 126 | current_score = self._get_score(gid, uid) 127 | if current_score >= score: 128 | return 1 129 | else: 130 | return 0 131 | except Exception as e: 132 | raise Exception(str(e)) 133 | 134 | 135 | 136 | 137 | 138 | 139 | #这个类用于记录一些与技能有关的变量,如栞的ub计数,可可萝的主人 140 | class NumRecord: 141 | def __init__(self): 142 | self.kan_num = {} 143 | self.kokoro_num = {} 144 | 145 | def init_num(self,gid): 146 | self.kan_num[gid] = 1 147 | self.kokoro_num[gid] = 0 148 | def get_kan_num(self,gid): 149 | return self.kan_num[gid] 150 | def add_kan_num(self,gid,num): 151 | self.kan_num[gid]+=num 152 | def set_kokoro_num(self,gid,kokoro_id): 153 | l1 = list(range(1,NUMBER+1)) 154 | l1.remove(kokoro_id) 155 | self.kokoro_num[gid] = random.choice(l1) 156 | return self.kokoro_num[gid] 157 | def get_kokoro_num(self,gid): 158 | return self.kokoro_num[gid] 159 | 160 | numrecord = NumRecord() 161 | 162 | #将角色以角色编号的形式分配到赛道上,返回一个赛道的列表。 163 | def chara_select(): 164 | l = range(1,TOTAL_NUMBER+1) 165 | select_list = random.sample(l,5) 166 | return select_list 167 | #取得指定角色编号的赛道号,输入分配好的赛道和指定角色编号 168 | def get_chara_id(list,id): 169 | raceid= list.index(id)+1 170 | return raceid 171 | 172 | #输入赛道列表和自己的赛道,选出自己外最快的赛道 173 | def select_fast(position,id): 174 | list1 = copy.deepcopy(position) 175 | list1[id-1] = 999 176 | fast = list1.index(min(list1)) 177 | return fast+1 178 | 179 | #输入赛道列表和自己的赛道,选出自己外最慢的赛道。 180 | def select_last(position,id): 181 | list1 = copy.deepcopy(position) 182 | list1[id-1] = 0 183 | last = list1.index(max(list1)) 184 | return last+1 185 | 186 | #输入赛道列表,自己的赛道和数字n,选出自己外第n快的赛道。 187 | def select_number(position,id,n): 188 | lis = copy.deepcopy(position) 189 | lis[id-1] = 999 190 | max_NUMBER = heapq.nsmallest(n, lis) 191 | max_index = [] 192 | for t in max_NUMBER: 193 | index = lis.index(t) 194 | max_index.append(index) 195 | lis[index] = 0 196 | nfast = max_index[n-1] 197 | return nfast+1 198 | 199 | #输入自己的赛道号,选出自己外的随机1个赛道,返回一个赛道编号 200 | def select_random(id): 201 | l1 = list(range(1,NUMBER+1)) 202 | l1.remove(id) 203 | select_id = random.choice(l1) 204 | return select_id 205 | 206 | #输入自己的赛道号和数字n,选出自己外的随机n个赛道,返回一个赛道号的列表 207 | def nselect_random(id,n): 208 | l1 = list(range(1,NUMBER+1)) 209 | l1.remove(id) 210 | select_list = random.sample(l1,n) 211 | return select_list 212 | 213 | #选择除自己外的全部对象,返回赛道号的列表 214 | def select_all(id): 215 | l1 = list(range(1,NUMBER+1)) 216 | l1.remove(id) 217 | return l1 218 | 219 | def search_kokoro(charalist): 220 | if 10 in charalist: 221 | return charalist.index(10)+1 222 | 223 | else: 224 | return None 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | #对单一对象的基本技能:前进,后退,沉默,暂停,必放ub 234 | def forward(id,step,position): 235 | fid = int(id) 236 | position[fid-1] = position[fid-1] - step 237 | position[fid-1] = max (1,position[fid-1]) 238 | return 239 | 240 | def backward(id,step,position): 241 | 242 | position[id-1] = position[id-1] + step 243 | position[id-1] = min (ROADLENGTH,position[id-1]) 244 | return 245 | 246 | def give_silence(id,num,silence): 247 | silence[id-1] += num 248 | return 249 | 250 | def give_pause(id,num,pause): 251 | pause[id-1] += num 252 | return 253 | 254 | def give_ub(id,num,ub): 255 | ub[id-1] += num 256 | return 257 | 258 | def change_position(id,rid,position): 259 | position[id-1],position[rid-1] = position[rid-1],position[id-1] 260 | return 261 | 262 | #用于技能参数增加 263 | def add(a,b): 264 | return a+b 265 | 266 | 267 | 268 | 269 | 270 | #对列表多对象的基本技能 271 | 272 | def n_forward(list,step,position): 273 | for id in list: 274 | position[id-1] = position[id-1] - step 275 | position[id-1] = max (1,position[id-1]) 276 | return 277 | 278 | def n_backward(list,step,position): 279 | for id in list: 280 | position[id-1] = position[id-1] + step 281 | position[id-1] = min (ROADLENGTH,position[id-1]) 282 | return 283 | 284 | def n_give_silence(list,num,silence): 285 | for id in list: 286 | silence[id-1] += num 287 | return 288 | 289 | def n_give_pause(list,num,pause): 290 | for id in list: 291 | pause[id-1] += num 292 | return 293 | 294 | def n_give_ub(list,num,ub): 295 | for id in list: 296 | ub[id-1] += num 297 | return 298 | 299 | #概率触发的基本技能 300 | def prob_forward(prob,id,step,position): 301 | r=random.random() 302 | if r < prob: 303 | forward(id,step,position) 304 | return 1 305 | else : 306 | return 0 307 | 308 | 309 | def prob_backward(prob,id,step,position): 310 | r=random.random() 311 | if r < prob: 312 | backward(id,step,position) 313 | return 1 314 | else : 315 | return 0 316 | 317 | def prob_give_pause(prob,id,num,pause): 318 | r=random.random() 319 | if r < prob: 320 | give_pause(id,num,pause) 321 | return 1 322 | else : 323 | return 0 324 | 325 | def prob_give_silence(prob,id,num,silence): 326 | r=random.random() 327 | if r < prob: 328 | give_silence(id,num,silence) 329 | return 1 330 | else : 331 | return 0 332 | 333 | #根据概率触发技能的返回,判断是否增加文本,成功返回成功文本,失败返回失败文本 334 | def prob_text(is_prob,text1,text2): 335 | if is_prob == 1: 336 | addtion_text = text1 337 | else: 338 | addtion_text = text2 339 | return addtion_text 340 | 341 | #按概率表选择一个技能编号 342 | def skill_select(cid): 343 | c = runchara.Run_chara(str(cid)) 344 | skillnum_ = ['0','1', '2', '3', '4'] 345 | #概率列表,读json里的概率,被注释掉的为老版本固定概率 346 | r_ = c.getskill_prob_list() 347 | #r_ = [0.7, 0.1, 0.1, 0.08, 0.02] 348 | sum_ = 0 349 | ran = random.random() 350 | for num, r in zip(skillnum_, r_): 351 | sum_ += r 352 | if ran < sum_ :break 353 | return int (num) 354 | 355 | #加载指定角色的指定技能,返回角色名,技能文本和技能效果 356 | def skill_load(cid,sid): 357 | c = runchara.Run_chara(str(cid)) 358 | name = c.getname() 359 | if sid == 0: 360 | return name,"none","null" 361 | else : 362 | skill_text = c.getskill(sid)["skill_text"] 363 | skill_effect = c.getskill(sid)["skill_effect"] 364 | return name,skill_text,skill_effect 365 | 366 | 367 | #指定赛道的角色释放技能,输入分配好的赛道和赛道编号 368 | def skill_unit(Race_list,rid,position,silence,pause,ub,gid): 369 | #检查是否被沉默 370 | cid = Race_list[rid-1] 371 | sid = skill_select(cid) 372 | if ub[rid-1]!=0: 373 | sid = 3 374 | ub[rid-1]-= 1 375 | 376 | skill = skill_load(cid,sid) 377 | skillmsg = skill[0] 378 | skillmsg += ":" 379 | if silence[rid-1] == 1: 380 | skillmsg += "本回合被沉默" 381 | silence[rid-1] -= 1 382 | return skillmsg 383 | skillmsg += skill[1] 384 | list = Race_list 385 | id = rid 386 | position = position 387 | silence = silence 388 | pause = pause 389 | ub = ub 390 | kan_num = numrecord.get_kan_num(gid) 391 | kokoro_num = numrecord.get_kokoro_num(gid) 392 | if skill[2]== "null": 393 | return skillmsg 394 | loc = locals() 395 | addtion_text = '' 396 | exec(skill[2]) 397 | if 'text'in loc.keys(): 398 | addtion_text = loc['text'] 399 | if 'kan_num1'in loc.keys(): 400 | numrecord.add_kan_num(gid,loc['kan_num1']) 401 | skillmsg += addtion_text 402 | 403 | return skillmsg 404 | 405 | #每个赛道的角色轮流释放技能 406 | def skill_race(Race_list,position,silence,pause,ub,gid): 407 | skillmsg = "" 408 | for rid in range(1,6): 409 | skillmsg += skill_unit(Race_list,rid,position,silence,pause,ub,gid) 410 | if rid !=5: 411 | skillmsg += "\n" 412 | return skillmsg 413 | 414 | 415 | 416 | #初始状态相关函数 417 | def position_init(position): 418 | for i in range (0,NUMBER): 419 | position[i] = ROADLENGTH 420 | return 421 | 422 | def silence_init(silence): 423 | for i in range (0,NUMBER): 424 | silence[i] = 0 425 | return 426 | 427 | def pause_init(pause): 428 | for i in range (0,NUMBER): 429 | pause[i] = 0 430 | return 431 | 432 | def ub_init(ub): 433 | for i in range (0,NUMBER): 434 | ub[i] = 0 435 | return 436 | 437 | #赛道初始化 438 | def race_init(position,silence,pause,ub): 439 | position_init(position) 440 | silence_init(silence) 441 | pause_init(pause) 442 | ub_init(ub) 443 | return 444 | 445 | #一个角色跑步 检查是否暂停 446 | def one_unit_run(id,pause,position,Race_list): 447 | if pause[id-1] == 0: 448 | cid = Race_list[id-1] 449 | c = runchara.Run_chara(str(cid)) 450 | speedlist = c.getspeed() 451 | step = random.choice(speedlist) 452 | forward(id,step,position) 453 | return 454 | else: 455 | pause[id-1]-=1 456 | return 457 | 458 | #一轮跑步,每个角色跑一次 459 | def one_turn_run(pause,position,Race_list): 460 | for id in range(1,6): 461 | one_unit_run(id,pause,position,Race_list) 462 | 463 | #打印当前跑步状态 464 | def print_race(Race_list,position): 465 | racemsg = "" 466 | for id in range(1,6): 467 | cid = Race_list[id-1] 468 | c = runchara.Run_chara(str(cid)) 469 | icon = c.geticon() 470 | 471 | for n in range (1,ROADLENGTH+1): 472 | if n != position[id-1]: 473 | racemsg = racemsg + ROAD 474 | else: 475 | racemsg = racemsg + str(icon) 476 | if id != 5: 477 | racemsg = racemsg + "\n" 478 | 479 | return racemsg 480 | #检查比赛结束用,要考虑到同时冲线 481 | def check_game(position): 482 | winner = [] 483 | is_win = 0 484 | for id in range(1,6): 485 | if position[id-1] == 1: 486 | winner.append(id) 487 | is_win = 1 488 | return is_win,winner 489 | 490 | 491 | 492 | def introduce_race(Race_list): 493 | msg = '' 494 | for id in range(1,6): 495 | msg += f'{id}号:' 496 | cid = Race_list[id-1] 497 | c = runchara.Run_chara(str(cid)) 498 | icon = c.geticon() 499 | name = c.getname() 500 | msg += f'{name},图标为{icon}' 501 | msg += "\n" 502 | msg += f"所有人请在{SUPPORT_TIME}秒内选择支持的选手。格式如下:\n1/2/3/4/5号xx金币\n如果金币为0,可以发送:\n领金币" 503 | return msg 504 | 505 | 506 | @sv.on_prefix(('测试赛跑', '赛跑开始')) 507 | async def Racetest(bot, ev: CQEvent): 508 | if not priv.check_priv(ev, priv.ADMIN): 509 | await bot.finish(ev, '只有群管理才能开启赛跑', at_sender=True) 510 | if running_judger.get_on_off_status(ev.group_id): 511 | await bot.send(ev, "此轮赛跑还没结束,请勿重复使用指令。") 512 | return 513 | 514 | running_judger.turn_on(ev.group_id) 515 | running_judger.set_support(ev.group_id) 516 | gid = ev.group_id 517 | #用于记录各赛道上角色位置,第i号角色记录在position[i-1]上 518 | position = [ROADLENGTH for x in range(0,NUMBER)] 519 | #同理,记录沉默,暂停,以及必放ub标记情况 520 | silence = [0 for x in range(0,NUMBER)] 521 | pause = [0 for x in range(0,NUMBER)] 522 | ub = [0 for x in range(0,NUMBER)] 523 | numrecord.init_num(gid) 524 | Race_list = chara_select() 525 | msg = '兰德索尔赛跑即将开始!\n下面为您介绍参赛选手:' 526 | await bot.send(ev, msg) 527 | await asyncio.sleep(ONE_TURN_TIME) 528 | running_judger.turn_on_support(gid) 529 | #介绍选手,开始支持环节 530 | msg = introduce_race(Race_list) 531 | await bot.send(ev, msg) 532 | 533 | await asyncio.sleep(SUPPORT_TIME) 534 | running_judger.turn_off_support(gid) 535 | #支持环节结束 536 | msg = '支持环节结束,下面赛跑正式开始。' 537 | await bot.send(ev, msg) 538 | await asyncio.sleep(ONE_TURN_TIME) 539 | kokoro_id = search_kokoro(Race_list) 540 | if kokoro_id is not None: 541 | kokoro_num = numrecord.set_kokoro_num(gid,kokoro_id) 542 | msg=f'本局存在可可萝,可可萝的主人为{kokoro_num}号选手' 543 | await bot.send(ev, msg) 544 | await asyncio.sleep(ONE_TURN_TIME) 545 | 546 | race_init(position,silence,pause,ub) 547 | msg = '运动员们已经就绪!\n' 548 | msg += print_race(Race_list,position) 549 | await bot.send(ev, msg) 550 | 551 | gameend = 0 552 | i = 1 553 | while gameend == 0: 554 | await asyncio.sleep(ONE_TURN_TIME) 555 | msg = f'第{i}轮跑步:\n' 556 | one_turn_run(pause,position,Race_list) 557 | msg += print_race(Race_list,position) 558 | await bot.send(ev, msg) 559 | check = check_game(position) 560 | if check[0]!=0: 561 | break 562 | 563 | await asyncio.sleep(ONE_TURN_TIME) 564 | skillmsg = "技能发动阶段:\n" 565 | skillmsg += skill_race(Race_list,position,silence,pause,ub,gid) 566 | if SKILL_IMAGE ==True: 567 | im = Image.new("RGB", (600, 150), (255, 255, 255)) 568 | dr = ImageDraw.Draw(im) 569 | FONTS_PATH = os.path.join(FILE_PATH,'fonts') 570 | FONTS = os.path.join(FONTS_PATH,'msyh.ttf') 571 | font = ImageFont.truetype(FONTS, 14) 572 | dr.text((10, 5), skillmsg, font=font, fill="#000000") 573 | bio = BytesIO() 574 | im.save(bio, format='PNG') 575 | base64_str = 'base64://' + base64.b64encode(bio.getvalue()).decode() 576 | mes = f"[CQ:image,file={base64_str}]" 577 | await bot.send(ev, mes) 578 | else: 579 | await bot.send(ev, skillmsg) 580 | 581 | await asyncio.sleep(ONE_TURN_TIME) 582 | msg = f'技能发动结果:\n' 583 | msg += print_race(Race_list,position) 584 | await bot.send(ev, msg) 585 | 586 | i+=1 587 | check = check_game(position) 588 | gameend = check[0] 589 | winner = check[1] 590 | winmsg = "" 591 | for id in winner: 592 | winmsg += str(id) 593 | winmsg += "\n" 594 | msg = f'胜利者为:\n{winmsg}' 595 | score_counter = ScoreCounter() 596 | await bot.send(ev, msg) 597 | gid = ev.group_id 598 | support = running_judger.get_support(gid) 599 | winuid = [] 600 | supportmsg = '金币结算:\n' 601 | if support!=0: 602 | for uid in support: 603 | support_id = support[uid][0] 604 | support_score = support[uid][1] 605 | if support_id in winner: 606 | winuid.append(uid) 607 | winscore = support_score*2 608 | score_counter._add_score(gid, uid ,winscore) 609 | supportmsg += f'[CQ:at,qq={uid}]+{winscore}金币\n' 610 | else: 611 | score_counter._reduce_score(gid, uid ,support_score) 612 | supportmsg += f'[CQ:at,qq={uid}]-{support_score}金币\n' 613 | await bot.send(ev, supportmsg) 614 | running_judger.set_support(ev.group_id) 615 | running_judger.turn_off(ev.group_id) 616 | 617 | 618 | @sv.on_rex(r'^([1-5])号(\d+)(金币|分)$') 619 | async def on_input_score(bot, ev: CQEvent): 620 | try: 621 | if running_judger.get_on_off_support_status(ev.group_id): 622 | gid = ev.group_id 623 | uid = ev.user_id 624 | 625 | match = ev['match'] 626 | select_id = int(match.group(1)) 627 | input_score = int(match.group(2)) 628 | print(select_id,input_score) 629 | score_counter = ScoreCounter() 630 | #若下注该群下注字典不存在则创建 631 | if running_judger.get_support(gid) == 0: 632 | running_judger.set_support(gid) 633 | support = running_judger.get_support(gid) 634 | #检查是否重复下注 635 | if uid in support: 636 | msg = '您已经支持过了。' 637 | await bot.send(ev, msg, at_sender=True) 638 | return 639 | #检查金币是否足够下注 640 | if score_counter._judge_score(gid, uid ,input_score) == 0: 641 | msg = '您的金币不足。' 642 | await bot.send(ev, msg, at_sender=True) 643 | return 644 | else : 645 | running_judger.add_support(gid,uid,select_id,input_score) 646 | msg = f'支持{select_id}号成功。' 647 | await bot.send(ev, msg, at_sender=True) 648 | except Exception as e: 649 | await bot.send(ev, '错误:\n' + str(e)) 650 | 651 | 652 | 653 | @sv.on_prefix(['领金币','领取金币']) 654 | async def add_score(bot, ev: CQEvent): 655 | try: 656 | score_counter = ScoreCounter() 657 | gid = ev.group_id 658 | uid = ev.user_id 659 | 660 | current_score = score_counter._get_score(gid, uid) 661 | if current_score == 0: 662 | score_counter._add_score(gid, uid ,50) 663 | msg = '您已领取50金币' 664 | await bot.send(ev, msg, at_sender=True) 665 | return 666 | else: 667 | msg = '金币为0才能领取哦。' 668 | await bot.send(ev, msg, at_sender=True) 669 | return 670 | except Exception as e: 671 | await bot.send(ev, '错误:\n' + str(e)) 672 | @sv.on_prefix(['查金币','查询金币','查看金币']) 673 | async def get_score(bot, ev: CQEvent): 674 | try: 675 | score_counter = ScoreCounter() 676 | gid = ev.group_id 677 | uid = ev.user_id 678 | 679 | current_score = score_counter._get_score(gid, uid) 680 | msg = f'您的金币为{current_score}' 681 | await bot.send(ev, msg, at_sender=True) 682 | return 683 | except Exception as e: 684 | await bot.send(ev, '错误:\n' + str(e)) 685 | 686 | async def get_user_card_dict(bot, group_id): 687 | mlist = await bot.get_group_member_list(group_id=group_id) 688 | d = {} 689 | for m in mlist: 690 | d[m['user_id']] = m['card'] if m['card']!='' else m['nickname'] 691 | return d 692 | @sv.on_fullmatch(('赛跑排行榜', '赛跑群排行')) 693 | async def Race_ranking(bot, ev: CQEvent): 694 | try: 695 | user_card_dict = await get_user_card_dict(bot, ev.group_id) 696 | score_dict = {} 697 | score_counter = ScoreCounter() 698 | gid = ev.group_id 699 | for uid in user_card_dict.keys(): 700 | if uid != ev.self_id: 701 | score_dict[user_card_dict[uid]] = score_counter._get_score(gid, uid) 702 | group_ranking = sorted(score_dict.items(), key = lambda x:x[1], reverse = True) 703 | msg = '此群赛跑金币排行为:\n' 704 | for i in range(min(len(group_ranking), 10)): 705 | if group_ranking[i][1] != 0: 706 | msg += f'第{i+1}名: {group_ranking[i][0]}, 金币: {group_ranking[i][1]}分\n' 707 | await bot.send(ev, msg.strip()) 708 | except Exception as e: 709 | await bot.send(ev, '错误:\n' + str(e)) 710 | 711 | 712 | @sv.on_fullmatch('重置赛跑') 713 | async def init_runstatus(bot, ev: CQEvent): 714 | if not priv.check_priv(ev, priv.ADMIN): 715 | await bot.finish(ev, '只有群管理才能使用重置赛跑哦。', at_sender=True) 716 | running_judger.turn_off(ev.group_id) 717 | running_judger.set_support(ev.group_id) 718 | msg = '已重置本群赛跑状态!' 719 | await bot.send(ev, msg, at_sender=True) 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | -------------------------------------------------------------------------------- /__pycache__/MyEncoder.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rs794613/PcrRun/2be1b13d35fd35b4098930e5d48d843a0c6f03c7/__pycache__/MyEncoder.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/Run_chara.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rs794613/PcrRun/2be1b13d35fd35b4098930e5d48d843a0c6f03c7/__pycache__/Run_chara.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/Runchara.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rs794613/PcrRun/2be1b13d35fd35b4098930e5d48d843a0c6f03c7/__pycache__/Runchara.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rs794613/PcrRun/2be1b13d35fd35b4098930e5d48d843a0c6f03c7/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "1":{ 3 | "name":"霞", 4 | "icon":"🔍", 5 | "speed":[1,2,2,2,2,1,1,1], 6 | "skill":{ 7 | "1":{ 8 | "skill_porb":0.1, 9 | "skill_text":"助手跑到哪里去了?霞向前快跑了2步。", 10 | "skill_effect":"forward(id,2,position)" 11 | }, 12 | "2":{ 13 | "skill_porb":0.1, 14 | "skill_text":"霞使用了[束缚之径]!,霞前进1步,霞之外全员沉默1回合!", 15 | "skill_effect":"forward(id,1,position)\nn_give_silence(select_all(id),1,silence)" 16 | }, 17 | "3":{ 18 | "skill_porb":0.08, 19 | "skill_text":"霞使用了UB[罪恶囚笼] ,霞前进2步,霞之外全员暂停1回合!", 20 | "skill_effect":"forward(id,2,position)\nn_give_pause(select_all(id),1,pause)" 21 | }, 22 | "4":{ 23 | "skill_porb":0.02, 24 | "skill_text":"霞突然变成了魔法少女!霞前进3步,霞之外全员沉默1回合,暂停1回合。", 25 | "skill_effect":"forward(id,3,position)\nn_give_silence(select_all(id),1,silence)\nn_give_pause(select_all(id),1,pause)" 26 | } 27 | } 28 | 29 | } , 30 | 31 | 32 | "2":{ 33 | "name":"佩可", 34 | "icon":"🍙", 35 | "speed":[1,1,2,2,1,1,2], 36 | "skill":{ 37 | "1":{ 38 | "skill_porb":0.1, 39 | "skill_text":"佩可吃完了一个饭团,猛冲3步!跑的太快感觉好饿,沉默自己一回合。", 40 | "skill_effect":"forward(id,3,position)\ngive_silence(id,1,silence)" 41 | }, 42 | "2":{ 43 | "skill_porb":0.1, 44 | "skill_text":"'肚子空空的......'佩可后退1步去找找饭团。", 45 | "skill_effect":"backward(id,1,position)\ntext=prob_text(prob_forward(0.5,id,3,position),'找到饭团了,又回头走了3步。','')" 46 | }, 47 | "3":{ 48 | "skill_porb":0.08, 49 | "skill_text":"佩可使用了UB[公主突进]!佩可猛冲5步,并休息一回合。", 50 | "skill_effect":"forward(id,5,position)\ngive_pause(id,1,pause)" 51 | }, 52 | "4":{ 53 | "skill_porb":0.02, 54 | "skill_text":"'超全力全开!'佩可将自己以外第一名击退4步,并猛冲5步。", 55 | "skill_effect":"forward(id,5,position)\nbackward(select_fast(position,id),4,position)" 56 | } 57 | } 58 | 59 | } , 60 | "3":{ 61 | "name":"吉塔", 62 | "icon":"🎸", 63 | "speed":[1,2,2,2,2,1,1], 64 | "skill":{ 65 | "1":{ 66 | "skill_porb":0.1, 67 | "skill_text":"“今天先帮你代一刀吧。”吉塔前进1步,", 68 | "skill_effect":"forward(id,1,position)\ngid=select_random(id)\nforward(gid,1,position)\ntext=f'并帮{gid}号选手代了1刀,使其前进1步。'" 69 | }, 70 | "2":{ 71 | "skill_porb":0.1, 72 | "skill_text":"“今天3刀出完了吗?”吉塔督促了团员,吉塔前进3步,其他全员前进1步。", 73 | "skill_effect":"forward(id,3,position)\nn_forward(select_all(id),1,position)" 74 | }, 75 | "3":{ 76 | "skill_porb":0.08, 77 | "skill_text":"吉塔使用了UB[暴风雨之剑]!猛冲了4步。", 78 | "skill_effect":"forward(id,4,position)" 79 | }, 80 | "4":{ 81 | "skill_porb":0.02, 82 | "skill_text":"“@全体成员,今晚合刀!”吉塔发动了全会合刀。其他全员前进2步。吉塔前进5步。", 83 | "skill_effect":"forward(id,5,position)\nn_forward(select_all(id),2,position)" 84 | } 85 | } 86 | 87 | } , 88 | "4":{ 89 | "name":"凯留", 90 | "icon":"🐱", 91 | "speed":[1,2,2,2,2,1,1], 92 | "skill":{ 93 | "1":{ 94 | "skill_porb":0.1, 95 | "skill_text":"真拿你没办法呢,看我的吧!凯留向前快跑了1步,并且将自己外第一名击退了2步。", 96 | "skill_effect":"forward(id,1,position)\nbackward(select_fast(position,id),2,position)" 97 | }, 98 | "2":{ 99 | "skill_porb":0.1, 100 | "skill_text":"“我只是个监视者......”凯留发动了[二五仔],后退了1步,", 101 | "skill_effect":"backward(id,1,position)\ngid=select_random(id)\nbackward(gid,2,position)\ntext=f'并将{gid}号选手击退了2步。'" 102 | }, 103 | "3":{ 104 | "skill_porb":0.08, 105 | "skill_text":"凯留使用了UB[格林炸裂]!凯留前进了1步,除凯留外全体后退2步!", 106 | "skill_effect":"forward(id,1,position)\nn_backward(select_all(id),2,position)" 107 | }, 108 | "4":{ 109 | "skill_porb":0.02, 110 | "skill_text":"[新春炸裂]!!!凯留突然穿上了和服,猛冲了8步!!!", 111 | "skill_effect":"forward(id,8,position)" 112 | } 113 | } 114 | 115 | } , 116 | "5":{ 117 | "name":"初音", 118 | "icon":"⭐️", 119 | "speed":[1,2,2,2,2,2,1], 120 | "skill":{ 121 | "1":{ 122 | "skill_porb":0.1, 123 | "skill_text":"初音使用了超能力飞行,向前飞了两步。", 124 | "skill_effect":"forward(id,2,position)" 125 | }, 126 | "2":{ 127 | "skill_porb":0.1, 128 | "skill_text":"“好困啊,先睡一觉吧......”初音睡着了,暂停1回合,", 129 | "skill_effect":"give_pause(id,1,pause)\ngid=select_random(id)\ngive_pause(gid,1,pause)\ntext=f'并拉了{gid}号选手一起睡。'" 130 | }, 131 | "3":{ 132 | "skill_porb":0.09, 133 | "skill_text":"初音使用了UB[流星]。其他全员后退1步,初音前进了2步。", 134 | "skill_effect":"forward(id,2,position)\nn_backward(select_all(id),1,position)" 135 | }, 136 | "4":{ 137 | "skill_porb":0.03, 138 | "skill_text":"初音不知不觉升到了六星,使用了[大荒星陨]!其他全员暂停一回合并后退3步!", 139 | "skill_effect":"n_backward(select_all(id),3,position)\nn_give_pause(select_all(id),1,pause)" 140 | } 141 | } 142 | 143 | } , 144 | 145 | "6":{ 146 | "name":"镜华", 147 | "icon":"💦", 148 | "speed":[1,2,1,2,1,2,1], 149 | "skill":{ 150 | "1":{ 151 | "skill_porb":0.1, 152 | "skill_text":"“你,你再盯着我,我要喊警察了哦......”镜华快跑1步喊来警察,将自己外第1位击退一步。", 153 | "skill_effect":"forward(id,1,position)\nbackward(select_fast(position,id),1,position)" 154 | }, 155 | "2":{ 156 | "skill_porb":0.1, 157 | "skill_text":"[冰枪术]!镜华前进了1步。", 158 | "skill_effect":"forward(id,1,position)\ntext=prob_text(prob_forward(0.4,id,3,position),'暴击了!又额外走了3步。','')" 159 | }, 160 | "3":{ 161 | "skill_porb":0.08, 162 | "skill_text":"镜华使用了UB[宇宙蓝色闪光]!镜华前进了3步,", 163 | "skill_effect":"forward(id,3,position)\ngid=select_random(id)\nbackward(gid,4,position)\ntext=f'并将{gid}号选手击退了4步。'" 164 | }, 165 | "4":{ 166 | "skill_porb":0.02, 167 | "skill_text":"镜华戴上了万圣帽子!镜华前进了4步,且下一回合必放UB,其他全员前进1步。", 168 | "skill_effect":"forward(id,4,position)\ngive_ub(id,1,ub)\nn_forward(select_all(id),1,position)" 169 | } 170 | } 171 | 172 | } , 173 | 174 | 175 | "7":{ 176 | "name":"纺希", 177 | "icon":"✂️", 178 | "speed":[1,2,2,1,2,2,1,1], 179 | "skill":{ 180 | "1":{ 181 | "skill_porb":0.1, 182 | "skill_text":"[琴弦捕获]! 纺希将自己外第1位向后拉2步,使自己外最末位前进2步,自己前进了1步。", 183 | "skill_effect":"forward(id,1,position)\nfid=select_fast(position,id)\nsid=select_last(position,id)\nbackward(fid,2,position)\nforward(sid,2,position)" 184 | }, 185 | "2":{ 186 | "skill_porb":0.1, 187 | "skill_text":"[螺旋纱线]!纺希将自己外第1位向后拉1步,并暂停1回合!", 188 | "skill_effect":"fid=select_fast(position,id)\nbackward(fid,1,position)\ngive_pause(fid,1,pause)" 189 | }, 190 | "3":{ 191 | "skill_porb":0.09, 192 | "skill_text":"纺希使用了UB[不幸的束缚]!纺希与自己外第一位交换位置后,又前进了1步!", 193 | "skill_effect":"fid=select_fast(position,id)\nchange_position(id,fid,position)\nforward(id,1,position)" 194 | }, 195 | "4":{ 196 | "skill_porb":0.03, 197 | "skill_text":"纺希穿上了万圣衣服,自己前进3步,自己外第1位暂停2回合。", 198 | "skill_effect":"forward(id,3,position)\ngive_pause(select_fast(position,id),2,pause)" 199 | } 200 | } 201 | 202 | } , 203 | 204 | 205 | 206 | "8":{ 207 | "name":"栞", 208 | "icon":"😷", 209 | "speed":[1,1,2,2,2,2,1], 210 | "skill":{ 211 | "1":{ 212 | "skill_porb":0.1, 213 | "skill_text":"[全力之矢]!栞使自己外第一名后退2步,第二名后退1步,下一回合必放UB。", 214 | "skill_effect":"backward(select_number(position,id,2),1,position)\nbackward(select_fast(position,id),2,position)\ngive_ub(id,1,ub)" 215 | }, 216 | "2":{ 217 | "skill_porb":0.1, 218 | "skill_text":"栞骑上了喵特酱,前进了2步。下一回合必放UB。自己有些头晕,暂停一回合。", 219 | "skill_effect":"forward(id,2,position)\ngive_ub(id,1,ub)\ngive_pause(id,1,pause)" 220 | }, 221 | "3":{ 222 | "skill_porb":0.09, 223 | "skill_text":"栞使用了UB[附魔之矢]!", 224 | "skill_effect":"step=2*kan_num\nforward(id,step,position)\nkan_num1=1\ntext=f'前进了{step}步,并且变得更强了。'\nprint(kan_num1)" 225 | }, 226 | "4":{ 227 | "skill_porb":0.03, 228 | "skill_text":"栞突然变成了魔法少女!栞前进了4步,且下一回合必放UB!", 229 | "skill_effect":"forward(id,4,position)\ngive_ub(id,1,ub)" 230 | } 231 | } 232 | 233 | } , 234 | 235 | 236 | 237 | "9":{ 238 | "name":"美美", 239 | "icon":"🐰", 240 | "speed":[1,2,2,2,2,2,1], 241 | "skill":{ 242 | "1":{ 243 | "skill_porb":0.1, 244 | "skill_text":"“哥哥快来和美美一起玩吧!”美美将自己外第1名和第2名击退2步。", 245 | "skill_effect":"backward(select_number(position,id,2),2,position)\nbackward(select_fast(position,id),2,position)" 246 | }, 247 | "2":{ 248 | "skill_porb":0.1, 249 | "skill_text":"[兔子先生声援]!美美前进2步,并使自己外最后1名前进两步。", 250 | "skill_effect":"forward(id,2,position)\nforward(select_last(position,id),2,position)" 251 | }, 252 | "3":{ 253 | "skill_porb":0.08, 254 | "skill_text":"美美使用了UB[兔子先生斩击!美美前进了2步,自己外第1名后退3步,第2名后退4步!", 255 | "skill_effect":"forward(id,2,position)\nbackward(select_number(position,id,2),4,position)\nbackward(select_fast(position,id),3,position)" 256 | }, 257 | "4":{ 258 | "skill_porb":0.02, 259 | "skill_text":"“让你看看万圣节的魔法吧![天兔霸断剑]!”美美前进了3步,全体后退1步,自己外第1名额外后退4步!", 260 | "skill_effect":"forward(id,3,position)\nn_backward(select_all(id),1,position)\nbackward(select_fast(position,id),4,position)" 261 | } 262 | } 263 | 264 | } , 265 | 266 | 267 | "10":{ 268 | "name":"可可萝", 269 | "icon":"🐴", 270 | "speed":[1,2,2,2,2,1,1,1], 271 | "skill":{ 272 | "1":{ 273 | "skill_porb":0.1, 274 | "skill_text":"“和主人的心之连结让我产生了这股力量呢。”可可萝前进2步,主人前进1步。", 275 | "skill_effect":"forward(id,2,position)\nforward(kokoro_num,1,position)" 276 | }, 277 | "2":{ 278 | "skill_porb":0.1, 279 | "skill_text":"[三重斩击]可可萝向前冲了4步,", 280 | "skill_effect":"forward(id,4,position)\ntext=prob_text(prob_backward(0.75,id,3,position),'又向后退了3步。','卡住了!没有回来。')" 281 | }, 282 | "3":{ 283 | "skill_porb":0.09, 284 | "skill_text":"可可萝使用了UB[极光绽放]!可可萝前进4步,主人前进2步,其他全体前进1步。", 285 | "skill_effect":"forward(id,4,position)\nforward(kokoro_num,1,position)\nn_forward(select_all(id),1,position)" 286 | }, 287 | "4":{ 288 | "skill_porb":0.02, 289 | "skill_text":"“想着主人跳舞,身心都暖了起来”。可可萝跳起了舞,前进4步,主人下回合必放UB。", 290 | "skill_effect":"forward(id,4,position)\ngive_ub(kokoro_num,1,ub)" 291 | } 292 | } 293 | 294 | } 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | } 303 | -------------------------------------------------------------------------------- /fonts/msyh.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rs794613/PcrRun/2be1b13d35fd35b4098930e5d48d843a0c6f03c7/fonts/msyh.ttf -------------------------------------------------------------------------------- /runchara.py: -------------------------------------------------------------------------------- 1 | import os,sys 2 | import json 3 | import random 4 | from hoshino import util 5 | 6 | 7 | class Run_chara: 8 | # 通过传入文件名 读入对应的角色Json文档进行初始化 9 | def __init__(self, id:str): 10 | project_path = os.path.dirname(os.path.abspath(__file__)) 11 | file_path = os.path.join(project_path,'config.json') 12 | 13 | # 读文件 14 | with open(file_path,"r", encoding='UTF-8') as f: 15 | self.config = json.loads(f.read()) 16 | 17 | 18 | # 搬运数据 19 | self.id = id 20 | self.name = self.config[id]['name'] 21 | self.icon = self.config[id]["icon"] 22 | self.speed = self.config[id]['speed'] 23 | self.skill = self.config[id]['skill'] 24 | del self.config 25 | 26 | 27 | 28 | def getskill(self,sid): 29 | skill = self.skill[str(sid)] 30 | return skill 31 | def geticon(self): 32 | icon = self.icon 33 | return str(icon) 34 | def getname(self): 35 | name = self.name 36 | return str(name) 37 | def getspeed(self): 38 | return self.speed 39 | def getskill_prob_list(self): 40 | prob_list = [0 for x in range(0,5)] 41 | sum = 1 42 | for i in range(1,5): 43 | prob_list[i]=self.skill[str(i)]["skill_porb"] 44 | sum -= prob_list[i] 45 | prob_list[0] = sum 46 | return prob_list 47 | 48 | 49 | 50 | 51 | --------------------------------------------------------------------------------