Compare commits

...
411 Commits
Author SHA1 Message Date
Hide_D 10c4814f34 Merge remote-tracking branch 'origin/devel' into compare/scenario-effects 2026-07-30 18:38:44 +00:00
Hide_D fe221a7bd9 test(compare): trace scenario action effects 2026-07-30 18:38:35 +00:00
Hide_D 191abf83c0 test: isolate S100 inheritance browser logs 2026-07-29 08:51:51 +00:00
Hide_D edfeae5f0f fix: block S100 inheritance stat resets 2026-07-29 08:42:38 +00:00
Hide_D 424184a51a fix: define mixed S100 dex conversion ownership 2026-07-29 07:29:43 +00:00
Hide_D 03a321f95d fix: prevent S100 dex conversion refills 2026-07-29 06:36:33 +00:00
Hide_D e3615fa6bb fix: cap S100 NPC dex growth at forty percent 2026-07-29 05:20:53 +00:00
Hide_D 32991f736d fix: expose S100 event traits to frontend 2026-07-29 05:11:19 +00:00
Hide_D 8b2748d3d4 feat: 재선택 현재 능력치 기준 표시 2026-07-28 16:56:02 +00:00
Hide_D 883080e275 feat: 100기 NPC 동조 및 후보 추첨 기능 개선과 초기 능력치 계산 로직 추가 2026-07-28 16:28:13 +00:00
Hide_D ce807e2564 유니크 획득 확률 조금 더 증가 2026-07-28 16:11:24 +00:00
Hide_D 9a2ac82373 시나리오 문제점 수정 2026-07-28 16:07:21 +00:00
Hide_D 3c35539c16 CreateManyNPC 추가 2026-07-28 16:04:50 +00:00
Hide_D 5ab08403c6 feat: 100기 NPC 동조와 후보 추첨 보완 2026-07-28 16:02:14 +00:00
Hide_D c1ce478d22 feat: exclude prior event seasons from all-star pool 2026-07-28 00:43:46 +00:00
Hide_D d8bf8ba922 feat: expand 100th-season pool through phase 99 2026-07-28 00:29:25 +00:00
Hide_D 8cdc9c9b84 compare: trace nation betting user lifecycle 2026-07-27 11:08:24 +00:00
Hide_D df189f4408 compare: trace NPC nation support lifecycle 2026-07-27 11:02:08 +00:00
Hide_D 47fa7885c5 compare: trace invader lifecycle across months 2026-07-27 10:48:40 +00:00
Hide_D 004dbb39b4 compare: add staged tax rate fixtures 2026-07-27 10:07:34 +00:00
Hide_D cd94c15137 compare: configure scenario static events 2026-07-27 09:49:51 +00:00
Hide_D eeb965353e compare: trace scenario 911 troop join event 2026-07-27 09:36:48 +00:00
Hide_D 6dd09bd4b4 compare: project general ownership presence 2026-07-27 09:09:40 +00:00
Hide_D a73189a604 compare: trace monthly disaster snapshots 2026-07-27 00:34:17 +00:00
Hide_D 4341341a07 compare: run optional general turn lifecycle 2026-07-26 23:30:25 +00:00
Hide_D 4b82f0b35c compare: preserve ordered conflict fixtures 2026-07-26 23:09:26 +00:00
Hide_D b417e117ad compare: expose active action inheritance points 2026-07-26 21:49:35 +00:00
Hide_D 85e435e99d compare: expose disband membership fields 2026-07-26 20:12:13 +00:00
Hide_D e48c13a92f compare: expose founding cooldown field 2026-07-26 17:26:57 +00:00
Hide_D 4495f0c06e compare: expose status transition fields 2026-07-26 17:03:53 +00:00
Hide_D 312711b7ed compare: expose officer city in turn snapshots 2026-07-26 15:14:49 +00:00
Hide_D 3e8c18b8d3 compare: expose canonical history logs 2026-07-26 13:09:37 +00:00
Hide_D fb0f768f2c compare: expose world killturn in turn snapshots 2026-07-26 12:54:05 +00:00
Hide_D 5fc230d89b compare: align isolated rank nation fixtures 2026-07-26 12:51:10 +00:00
Hide_D 5fd1a6c752 compare: require matching args for multistep completion 2026-07-26 12:34:49 +00:00
Hide_D 76a5ea273a compare: observe nation history in turn snapshots 2026-07-26 12:04:55 +00:00
Hide_D 3d0a5a4be8 merge: observe betrayal in turn traces 2026-07-26 10:25:49 +00:00
Hide_D 23309113ec test: observe betrayal in turn traces 2026-07-26 10:25:41 +00:00
Hide_D 1a1bc541f5 merge: clone fixture general rank data 2026-07-26 09:46:12 +00:00
Hide_D 20060a89fd test: clone fixture general rank data 2026-07-26 09:45:57 +00:00
Hide_D 24f788d1a0 merge: observe selected diplomacy pairs 2026-07-26 09:30:30 +00:00
Hide_D 813957479d test: observe selected diplomacy pairs 2026-07-26 09:30:21 +00:00
Hide_D cdf58c54e0 merge: create missing fixture generals 2026-07-26 08:52:43 +00:00
Hide_D 6399134380 test: create missing fixture generals 2026-07-26 08:52:26 +00:00
Hide_D eb49e6f8ff merge: expose nation command cooldowns 2026-07-26 08:49:50 +00:00
Hide_D ef855eb2cc test: expose nation command cooldowns 2026-07-26 08:49:41 +00:00
Hide_D c970e6586d test: expose random capital city metadata 2026-07-26 07:58:49 +00:00
Hide_D 6eaa529048 merge: compare best-general rank data 2026-07-26 06:05:12 +00:00
Hide_D fe39241a90 test: compare general rank data state 2026-07-26 06:05:06 +00:00
Hide_D d936d93be8 merge: trace general command cooldown state 2026-07-26 04:55:23 +00:00
Hide_D 89127c0258 Trace general command cooldown state 2026-07-26 04:55:17 +00:00
Hide_D 57aa07453e merge: trace instant diplomacy responses 2026-07-26 03:11:09 +00:00
Hide_D 0722f6ab5e Add instant diplomacy response traces 2026-07-26 03:10:50 +00:00
Hide_D b9c51da782 merge: observe generated nation command generals 2026-07-26 02:29:03 +00:00
Hide_D c290404e42 test: observe generated nation command generals 2026-07-26 02:28:48 +00:00
Hide_D cc0f965cb4 merge: project nation strategy limit 2026-07-26 01:55:01 +00:00
Hide_D 64736d194e test: project nation strategy limit 2026-07-26 01:54:32 +00:00
Hide_D 963b04e8b0 merge: project nation receive-assist state 2026-07-26 01:44:38 +00:00
Hide_D e58ffab2a2 test: project nation receive-assist state 2026-07-26 01:44:22 +00:00
Hide_D de29e2e157 merge: support multi-turn nation command traces 2026-07-26 01:28:27 +00:00
Hide_D 7aa1b1889c test: support multi-turn nation command traces 2026-07-26 01:28:15 +00:00
Hide_D 618cfe5720 Merge general command comparison fixtures 2026-07-26 01:05:44 +00:00
Hide_D a8cecf8ec2 test: extend general command comparison fixtures 2026-07-26 01:05:30 +00:00
Hide_D d858c64a3c merge: expand turn command fixture controls 2026-07-26 00:11:00 +00:00
Hide_D f49b1d26a5 test: expand turn command fixture controls 2026-07-26 00:10:47 +00:00
Hide_D 92e5f2472d merge: add aggregate monthly boundary trace 2026-07-25 23:43:09 +00:00
Hide_D 11144f1f88 test: add aggregate monthly boundary trace 2026-07-25 23:43:03 +00:00
Hide_D 34c9a9b53e merge: trace core monthly event actions 2026-07-25 22:47:42 +00:00
Hide_D 84d9cf9eb4 test(compare): trace core monthly event actions 2026-07-25 22:47:35 +00:00
Hide_D 8a4cc5df21 merge: trace monthly post tail effects 2026-07-25 22:33:50 +00:00
Hide_D df0b8ccebe test(compare): trace monthly post tail effects 2026-07-25 22:33:41 +00:00
Hide_D ac47bc58bd merge: add monthly wander comparison trace 2026-07-25 22:21:01 +00:00
Hide_D 570ef6f005 test(compare): trace monthly wander disband 2026-07-25 22:20:55 +00:00
Hide_D 7eecde62fa merge: add monthly diplomacy comparison trace 2026-07-25 22:08:19 +00:00
Hide_D 4e0e5c9cd7 test(compare): trace monthly diplomacy transitions 2026-07-25 22:08:08 +00:00
Hide_D 18abcde0d5 merge: add monthly nation statistics trace 2026-07-25 21:57:21 +00:00
Hide_D 6176b64c28 test(compare): trace monthly nation statistics 2026-07-25 21:57:10 +00:00
Hide_D 3bae1157b6 merge: add monthly pre-update comparison trace 2026-07-25 21:36:49 +00:00
Hide_D 5a51ad5699 test(compare): trace monthly pre-update boundary 2026-07-25 21:36:26 +00:00
Hide_D 312d20269c merge: trace remaining monthly event actions 2026-07-25 21:19:49 +00:00
Hide_D 178d6f042b test: trace monthly unique and inheritance actions 2026-07-25 21:15:35 +00:00
Hide_D 3352b64d0f merge: trace monthly speciality and betrayal actions 2026-07-25 20:55:59 +00:00
Hide_D e7d86a16d5 test: trace monthly speciality and betrayal actions 2026-07-25 20:55:40 +00:00
Hide_D 820c25d8dc merge: trace monthly scout policy actions 2026-07-25 20:28:43 +00:00
Hide_D f2dcb4d4d1 test: trace monthly scout policy actions 2026-07-25 20:28:33 +00:00
Hide_D de357cfe95 merge: trace nation betting lifecycle 2026-07-25 20:16:41 +00:00
Hide_D 0f333f8c96 Add nation betting comparison fixtures 2026-07-25 20:16:24 +00:00
Hide_D 93e8adadac merge: trace city changes and NPC troop leaders 2026-07-25 19:50:02 +00:00
Hide_D 8f98626075 test(compare): trace city changes and NPC troop leaders 2026-07-25 19:47:36 +00:00
Hide_D a321eb1362 merge: trace monthly invader lifecycle 2026-07-25 19:20:19 +00:00
Hide_D 1a17fad0a5 test: trace monthly invader lifecycle 2026-07-25 19:19:56 +00:00
Hide_D c74efbb372 merge: trace RaiseNPCNation monthly action 2026-07-25 18:56:46 +00:00
Hide_D 66f79ca5d2 test: trace monthly NPC nation creation 2026-07-25 18:56:40 +00:00
Hide_D f42f844f17 merge: trace monthly NPC registration 2026-07-25 18:40:21 +00:00
Hide_D aee98e15d7 test: trace monthly NPC registration 2026-07-25 18:40:12 +00:00
Hide_D 0936dabc9e merge: add CreateManyNPC comparison fixture 2026-07-25 18:16:11 +00:00
Hide_D 39b209caf0 test(compare): trace CreateManyNPC monthly action 2026-07-25 18:15:27 +00:00
Hide_D 07867b3aaf merge: add CreateAdminNPC no-op comparison fixture 2026-07-25 17:50:27 +00:00
Hide_D de1f74cb44 Add CreateAdminNPC no-op comparison fixture 2026-07-25 17:50:21 +00:00
Hide_D 65c97107c6 merge: add monthly war income comparison fixture 2026-07-25 17:45:43 +00:00
Hide_D d796eda13c Add monthly war income comparison fixture 2026-07-25 17:45:38 +00:00
Hide_D 2a9029470f merge: add semi-annual monthly comparison fixture 2026-07-25 17:35:40 +00:00
Hide_D 254364bab8 Add semi-annual monthly comparison fixture 2026-07-25 17:35:30 +00:00
Hide_D 0319410ade merge: add nation level monthly comparison fixture 2026-07-25 17:20:17 +00:00
Hide_D 6b64f6f8ed Add nation level monthly comparison fixture 2026-07-25 17:20:09 +00:00
Hide_D 62fcb2e987 merge: add monthly event comparison trace 2026-07-25 16:56:34 +00:00
Hide_D ff3ef4e4f3 test: add monthly city supply trace 2026-07-25 16:56:26 +00:00
Hide_D 008b0e416c merge: add full turn command comparison runner 2026-07-25 14:17:50 +00:00
Hide_D bf96849027 test: execute legacy turn command fixtures 2026-07-25 14:17:25 +00:00
Hide_D 1b035e4a42 merge: add canonical turn fixture setup 2026-07-25 11:20:57 +00:00
Hide_D 47dec60c2b test: support canonical legacy turn fixtures 2026-07-25 11:20:53 +00:00
Hide_D c03a28be93 merge: add legacy turn command trace runner 2026-07-25 11:14:28 +00:00
Hide_D d1ab2b0450 test: trace legacy turn command execution 2026-07-25 11:14:19 +00:00
Hide_D 95f66e4c39 feat: add 100th-season all-star growth event 2026-07-25 10:46:23 +00:00
Hide_D fe9ae97821 merge: add turn state differential exporter 2026-07-25 09:35:22 +00:00
Hide_D 98e0a676cb test: export canonical legacy turn snapshots 2026-07-25 09:35:04 +00:00
Hide_D 2bb1387bc4 test: expose legacy trait catalog 2026-07-25 08:05:38 +00:00
Hide_D af382c541e test: expose legacy item catalog for comparison 2026-07-25 06:38:54 +00:00
Hide_D 8616a094e5 test: add deterministic battle trace exporter 2026-07-25 05:56:45 +00:00
Hide_D 4de7ebec17 요양 깃수 추가 2026-03-04 14:16:08 +00:00
Hide_D d43dff35fb fix: 디버그 코드 복구 2026-02-18 18:54:46 +00:00
Hide_D 5b13f8bd30 ip 기록 2026-02-17 22:31:08 +09:00
Hide_D e51bc6f711 fix: 턴 데몬에 cookie jar 적용 2026-02-17 20:35:15 +09:00
Hide_D 1b08aa0c58 wip: 디버그 코드 추가 2026-02-17 19:12:28 +09:00
Hide_D f2547fe207 dbg 2026-02-17 18:32:04 +09:00
류화영 cec7726731 fix: 방랑군이 빈번하게 해산하는 문제 해결 시도 2026-01-19 22:50:11 +09:00
Hide_D d679a6fed8 fix: InheritancePointManager 버그 수정 2025-11-01 17:38:02 +00:00
Hide_D 6fe156eb7c fix: composer uninstall 누락 2025-10-29 13:00:46 +00:00
Hide_D 663ddbe76a fix: inheritance_result 작성 문제 2025-10-28 20:24:25 +00:00
Hide_D 30297454f7 refac: inheritance_result로 데이터 이관 2025-10-28 20:15:05 +00:00
Hide_D bc602722bf feat: schema에 inheritance_result 추가
- storage에 의미없이 쌓이는 데이터 이관
2025-10-28 20:09:30 +00:00
Hide_D be8f147216 dep: brandonwamboldt/utilphp 제거 2025-10-28 19:56:02 +00:00
Hide_D b9495fb64a refac: 턴 데몬 전체를 async로 변경경 2025-10-07 20:05:55 +09:00
Hide_D 07b217b290 fix: 서버 오픈 핸들러를 00초에 맞추도록 변경경 2025-10-07 19:54:24 +09:00
Hide_D 42fac46062 refac: brandonwamboldt/utilphp 의존 코드 수정
- 실제 의존성 제거는 이후에에
2025-10-07 19:26:22 +09:00
Hide_D 24bc8985d0 __filename 2025-10-04 11:39:35 +00:00
Hide_D 76a2d5ff63 daemon typescript 버전 추가 2025-10-04 11:29:03 +00:00
Hide_D 148f32f78b fix: execute engine updated 2025-10-04 11:04:36 +00:00
Hide_D 62f5b6597e proc.php 일부 수정
- api.php 미사용 경로 대비
2025-10-04 10:59:56 +00:00
Hide_D 7e810b0279 LogText 끄기 2025-09-07 06:01:04 +00:00
Hide_D 2336b29b65 fix: ?? 2025-08-30 06:15:25 +00:00
Hide_D 185c0e16a0 fix: AI 일부 key 접근 문제 수정 2025-08-30 06:11:37 +00:00
Hide_D 656baeb9ee fix: 토너먼트 분노 공격 확률 오류 수정 (#263)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/263
2025-08-23 10:08:13 +09:00
류화영 3e06304dc7 fix: 토너먼트 분노 공격 확률 오류 수정 2025-08-23 09:23:00 +09:00
Hide_D 4bb940c8c5 fix: ?? 연산자 우선순위 2025-08-20 12:59:40 +00:00
Hide_D 2b376b6aab fix: logError 버그 수정 2025-07-06 06:15:18 +00:00
Hide_D 04df26ff83 misc: 군웅할거 손견 국명 손책으로 변경
- 서버 시작 시점에서 손견은 맞으나, 땅따 시작점에는 손책임
2025-06-28 12:37:16 +00:00
Hide_D aca4240b92 game: 강서유서 월드로 명칭 변경 2025-06-26 18:37:42 +00:00
Hide_D faf26fa8a2 game: 강서유서 소설 월드(비세력) 수정 2025-06-26 18:36:19 +00:00
Hide_D 030ab1e7ea game: 군웅축록 연도 수정 2025-06-26 18:25:14 +00:00
Hide_D 7f2c1d4782 game: 역사모드4-2 황제 원술
- 제작자: 강서유서
- 유비가 서주를 가지고 있어야 원술을 치지 않나?
2025-06-26 18:23:36 +00:00
Hide_D 9132138a99 game: 군웅축록 외교 2025-06-26 17:54:32 +00:00
Hide_D 84875d60bd game: 역사모드2-2 반동탁연합 결성(정사)
- 제작자: 강서유서
2025-06-26 17:51:39 +00:00
Hide_D 3cbaf76626 game: 역사모드3-2 군웅축록
- 제작자: 강서유서
2025-06-26 17:26:26 +00:00
Hide_D f4846d0d66 game: 무한대흥 NPC 능력치 감소 2025-06-25 15:07:52 +00:00
Hide_D f183dcc72b frontend: 기술 제한 표기 수정 2025-06-25 14:16:19 +00:00
Hide_D 63cc5d8e88 game: 무한대흥 초기 성수 3천 2025-06-25 13:58:47 +00:00
Hide_D f858c32fdf feat: 점령 후 일반 도시 성벽 수치 조정 가능 2025-06-25 13:58:29 +00:00
Hide_D 60eb127d71 game: 천지비급 상인 등장 2025-06-25 13:54:47 +00:00
Hide_D ede33f3a37 game: ban 메시지 빈도 감소 2025-06-25 13:53:36 +00:00
Hide_D ffd53a2390 game: 무한대흥 스탯 2025-06-25 13:20:21 +00:00
Hide_D 2591fbde67 game: 무한대흥 시나리오 2025-06-25 13:12:41 +00:00
Hide_D 922d3f1938 feat: 기술 등급 제한 수치 유연화 2025-06-25 13:12:32 +00:00
Hide_D 64522ba8a6 fix: ChangeCity에서 _max 키 입력 가능하게 2025-06-25 13:09:24 +00:00
Hide_D 7b1eedb574 feat: ChangeCity에 최대 내정 수치도 연산자로 바꿀 수 있도록 2025-06-25 12:31:29 +00:00
Hide_D 7ec6ca605f run_daemon timeout 2025-05-28 13:55:30 +00:00
Hide_D 5a5c613814 game: 랜임 확률 보정 완화
- 강국의 디버프 감소소
2025-03-05 17:35:08 +00:00
Hide_D 1a3ef20a35 fix: 다병종 밸런스 누락분 수정정 2025-02-08 13:54:01 +00:00
Hide_D fba966177d fix: 고급모드 연구턴 커맨드 창 넘치는 문제 2025-01-25 19:52:28 +00:00
Hide_D 62c72dfdbe fix: 척사 버그 수정 2025-01-24 15:26:56 +09:00
Hide_D 1ae1ff9b72 refac,fix: reqTech, reqRegions, reqCities 간이 호출 추가 2025-01-24 15:23:13 +09:00
Hide_D c1e12c2737 fix: 버그 수정 2025-01-24 15:19:23 +09:00
Hide_D de09a66d6f fix: 병종 연구 커맨드에서 금쌀 검새 안하는 문제 해결 2025-01-24 10:07:56 +09:00
Hide_D 3c2012da46 fix: 사령턴에서 불가능한 턴이 별도 강조가 없는 문제 수정 2025-01-23 17:32:36 +00:00
Hide_D d55be54320 fix: 연구커맨드 검사 조건 2025-01-23 17:27:20 +00:00
Hide_D dcbefa1a96 fix: 연구 커맨드에 금쌀 표기 없음 2025-01-23 17:20:10 +00:00
Hide_D be8f1fff96 fix: 버그 수정 2025-01-23 17:17:37 +00:00
Hide_D 6117dbdcc0 fix: 이벤트 다병종 화시병 위치 2025-01-23 17:14:35 +00:00
Hide_D 0a39ba1023 fix: NPC AI가 현재 병종 기술등급을 고려하지 않는 문제 수정
- 아직 사용하지 않는 징병 페이지 요구 기술 항목도 수정
2025-01-23 17:13:11 +00:00
Hide_D dae5f65baa fix: 특성초토화시에만 did_특성초토화 증가 2025-01-23 17:08:50 +00:00
Hide_D 080bb30103 fix: 버그수정2 2025-01-22 19:42:43 +00:00
Hide_D 9e647c7ce5 fix: 도시 규모조건 징병 불가 2025-01-22 19:41:20 +00:00
Hide_D 73606b0fb4 feat: 초토화시 내부 카운트 추가 2025-01-22 18:54:23 +00:00
Hide_D e62eb36cc2 feat: event 연구 커맨드 추가 2025-01-22 18:53:08 +00:00
Hide_D 6b81f744d4 feat: event용 연구 추가 2025-01-22 18:41:24 +00:00
Hide_D 1a9b3b78cb fix: 화륜차 조건 추가 2025-01-22 18:40:59 +00:00
Hide_D c3cbf956d0 fix: 병종 조건에서 같은 키가 여러개인 경우 대비 2025-01-22 18:40:49 +00:00
Hide_D 91188c555d fix: 커맨드의 aux값값 2025-01-22 18:16:37 +00:00
Hide_D 913028dd6c fix: 병종 특성관련 발생 버그 수정 2025-01-22 18:08:18 +00:00
Hide_D dfb3f6478d game(wip): 다병종 시나리오에 병종 지정 2025-01-22 17:56:17 +00:00
Hide_D 6afc6221d3 feat: 특정 등급 이상 도시 보유 조건 추가 2025-01-22 17:48:49 +00:00
Hide_D 7b5a02487e misc: ReqCitiesWithCityLevel 설명 보완 2025-01-22 17:36:17 +00:00
Hide_D 533b79762e game(wip): 다병종 깃수 준비 2025-01-22 17:29:58 +00:00
Hide_D 53b7dbfdd0 feat: 병종 징병 조건 추가
- 군주 및 수뇌
- 군주 및 수뇌 아님
- 도시의 규모 요구
- 특정 Nation Aux 값 요구
2025-01-22 17:17:30 +00:00
Hide_D fd14c5403b feat: NationAuxKey Enum 2025-01-22 16:57:23 +00:00
Hide_D dc476e73a1 feat: 병종 검사에서 $nation['aux']를 정식 입력 2025-01-22 16:54:27 +00:00
Hide_D e60150705e refac: Constraint의 generalObj destGeneralObj로 General 객체 입력 2025-01-22 16:53:39 +00:00
Hide_D 2869ba5c42 feat,refac: GameUnitConstraint 개념 추가
- GameUnitDetail의 요구 기술, 지역, 도시, 연도를 GameUnitConstraint로 통합
- GameUnitConstraint는 조건 검사, 설명 제공
- 병종 정의를 GameUnitConstraint 이용 재정의
- test 함수에 General 객체 요구,
- test 함수의 ownCities에 단순 도시 외 도시 정보 추가
- 변경된 값에 맞게 호출 함수 변경
2025-01-22 16:26:15 +00:00
Hide_D 91e56644b4 feat: 토너먼트 페이지 관리자 조작 버튼 제거
- 필요할땐 다른 페이지에서 만들어 쓰도록
2024-12-28 08:47:45 +00:00
Hide_D e0b7a3d763 game: 철기병 방어 향상 2024-12-22 05:25:47 +00:00
Hide_D 6a25f03687 fix: namespace 2024-12-22 04:28:29 +00:00
Hide_D 104f306deb fix: callSammoAPI apiPath 호출 2024-12-22 04:27:02 +00:00
Hide_D 09c21cd466 fix: api prefix 2024-12-22 04:23:30 +00:00
Hide_D 5b89797f57 fix: admin_member 페이지 수정 시도 2024-12-22 04:12:59 +00:00
Hide_D ab1cc5146d feat: 유저 관리 패널에 유저 차단 추가 2024-12-22 04:05:44 +00:00
Hide_D 2483a7723f feat: RootAPI/Admin/BanEmailAddress 2024-12-22 03:56:12 +00:00
Hide_D 367db15d93 misc: DB로는 global salt 넘기지 않음 2024-12-22 03:52:39 +00:00
Hide_D 30e02aac08 feat: 가입 시 영구 차단된 이메일 검사 2024-12-22 03:42:08 +00:00
Hide_D ce5ddf05fe fix: 1달이상 지난 삭제요청 계정에 대해 자동삭제하지 않는 버그 수정 2024-12-22 02:46:28 +00:00
Hide_D 475837bca0 feat: 영구 차단 계정용 table 2024-12-22 02:43:18 +00:00
Hide_D bd0ae25afd game: 징계가 남아있는 경우 탈퇴 불가 2024-12-21 09:14:14 +00:00
Hide_D 688de08feb game: 선양시에도 거병/수뇌/외교권자 페널티 검사 2024-12-21 08:56:24 +00:00
Hide_D 83b550adbe game: 거병에도 '건국 금지 패널티 적용' 2024-12-21 08:52:08 +00:00
Hide_D fa89bae7d9 game: NPC 장수 능력치 초기화 불가 2024-12-21 04:03:05 +00:00
Hide_D 456246362f game: NPC의 유저 관직 부여 로직 수정 2024-12-21 03:59:21 +00:00
Hide_D b472440ec1 fix: 이미지 경로에 빈칸이 있는 경우 2024-12-20 15:50:38 +00:00
Hide_D 7b5613d032 fix: 유저 부운영자는 시나리오 리셋시 생성하지 않음 2024-12-14 09:05:07 +00:00
Hide_D f5b3b985ce feat: 시스템 권한 분리
- 부운영자를 부운영자(시스템), 부운영자(유저)로 분리
2024-12-14 04:06:03 +00:00
Hide_D 515298700a term utf-8 2024-12-13 13:12:41 +00:00
Hide_D 41d7566acb game: 롤시나리오 메시지 빈도 재조정 2024-12-11 17:07:31 +00:00
Hide_D f4196263fa game: 롤 시나리오 NPC 메시지 빈도 조절 2024-12-11 17:04:07 +00:00
Hide_D 6bc69ac467 game: 리그오브레전드 v1.1 2024-12-09 17:49:37 +00:00
Hide_D 15b2c8b8e6 game: 재야 의술장은 국가 장수를 치료하지 않음 2024-12-06 18:12:24 +00:00
Hide_D 8e1d33e880 misc: 강서유서 소설 월드 추가 수정 2024-12-06 16:28:20 +00:00
Hide_D 797902552d misc: 강서유서 소설 월드 수정 2024-12-06 15:46:47 +00:00
Hide_D f3d2dcdad2 사소한 수정 2024-12-06 15:36:17 +00:00
Hide_D 928478a8ad misc: 강서유서 소설월드 업데이트 2024-12-06 15:34:50 +00:00
Hide_D 5023ee800b 시나리오 변환시 환경 변수에 json 허용 2024-12-06 15:22:47 +00:00
Hide_D 4a70625487 avif support 2024-12-06 15:09:07 +00:00
Hide_D 26327b5c8c 롤시나리오 m장 이름 지정 2024-12-06 12:37:09 +00:00
Hide_D 372f47760b 리그오브레전드 시나리오 연동 조정
- 군주가 '성인이 되어 나타납니다'로 무효화되는 문제 수정
2024-12-06 11:46:33 +00:00
Hide_D 3111a5eb71 롤 시나리오 1.0으로 업데이트, 비급 and/or 파죽지세도 추가 (#262)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/262
2024-12-05 17:07:54 +09:00
sars 74f914488b 빙의 금지 장수 포함 2024-12-05 00:04:10 -08:00
sars a8d219afec iconPath 재설정, 100에서 29로 숫자 조절 2024-12-04 23:26:54 -08:00
sars 4b4a7ffdf0 롤 시나리오 1.0으로 업데이트, 비급 and/or 파죽지세도 추가 2024-12-04 23:04:36 -08:00
Hide_D 98e2e2f125 리그오브레전드 베타 아이콘 추가 (#261)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/261
2024-12-03 12:24:50 +09:00
sars 05000ae954 리그오브레전드 베타 아이콘 추가 2024-12-02 19:21:45 -08:00
Hide_D 85bf53f317 챔피언들과 미니언들 시작날짜 조절 (#260)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/260
2024-11-27 17:42:28 +09:00
sars d65407079e 챔피언들과 미니언들 시작날짜 조절 v2 2024-11-27 00:11:52 -08:00
sars a8c9946aa9 챔피언들과 미니언들 시작날짜 조절 2024-11-26 23:59:35 -08:00
Hide_D 1e5b2de913 LoL 시나리오 생년월일 (#257)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/257
2024-11-27 16:26:34 +09:00
Hide_D 747ab3d563 LoL 시나리오 생년월일 2024-11-27 16:26:08 +09:00
sars 82ffbba661 수식을 수치로 수정해서 다시 변환시도 2024-11-26 23:18:01 -08:00
sars 3f08876079 리그오브레전드 시나리오 추가 2024-11-26 23:09:37 -08:00
Hide_D 5622839ffa feat: 설문 게시자 표시 2024-09-28 13:09:51 +00:00
Hide_D 4b3ab5e31c feat: 설문 등록 시 등록자 유저명 저장 2024-09-28 13:04:29 +00:00
Hide_D f774a28e2a fix: 로그인 시 세션에 저장되는 username을 id가 아니라 name값으로 변경 2024-09-28 13:03:00 +00:00
Hide_D 61bdb8da01 fix: 부대 이름 변경 오작동 2024-09-23 13:43:35 +00:00
Hide_D c117ada117 fix: event 커맨드 수정
- 탑승즉시이동: 불필요한 추가 조사 제거
- 발령즉시집합: 발령자가 탑승중인 경우 변수값 변경
  - 장수 커맨드 실행 시 cityID에 따라 다시 받아오므로 해당 변경으로 충분
2024-09-23 13:35:28 +00:00
Hide_D 1f0d0f992d game: 부대탈퇴지시 ui 2024-09-18 16:30:01 +00:00
Hide_D 6445b77b90 game: 부대탑승후 이동 이벤트시 로그 기록 2024-09-18 16:17:24 +00:00
Hide_D 6d935733e6 game: 충차 도구 치안치 하향 2024-09-18 16:09:02 +00:00
Hide_D cfd0a2d26f game: 충차 도구 추가 2024-09-18 16:08:37 +00:00
Hide_D 749e8f673b fix: StaticEventHandler 버그 수정 2024-09-18 16:08:25 +00:00
Hide_D 4812f324e0 fix: StaticEventHandler 버그 수정 2024-09-18 16:02:41 +00:00
Hide_D 085f34b307 feat: 부대탈퇴지시 2024-09-18 15:22:27 +00:00
Hide_D 622ce7b780 game: 축지 시나리오 벌점 제한 2배 2024-09-18 15:11:18 +00:00
Hide_D 34b1fc9c5e feat: 벌점 제한 계수를 GameConst로 이동 2024-09-18 15:10:34 +00:00
Hide_D 9cc27c40aa game: 축지 시나리오 수비 설정 제한 완화 2024-09-18 15:08:37 +00:00
Hide_D eece1cbae5 feat: 수비 설정 제한을 GameConst로 이동 2024-09-18 15:08:21 +00:00
Hide_D 7e6770b5e7 game: 축지 시나리오 유닛세트 2024-09-18 15:02:38 +00:00
Hide_D a0c032c2c6 game: 축지 이벤트 작업 2024-09-18 14:54:56 +00:00
Hide_D 3d12de3838 refac: API/Troop 의 $me를 GeneralLite로 변경
- StaticEventHandler 처리도 추가
2024-09-18 14:54:40 +00:00
Hide_D 477b77b59f feat: StaticEventHandler 처리기 추가
- 커맨드 종료 시점에 호출
  - pre, post 각각이 필요한지는 논의 필요
  - 일단 용도에 따라 pre, post 둘중에 하나만 처리
- eventType으로는 full qualified class name 사용
  - 꼭 그럴필요는 없지만, 커맨드에 한해서는 이렇게
2024-09-18 14:54:11 +00:00
Hide_D 04a7a34fcc 부대 이동 관련 초기 코드 2024-09-17 00:48:54 +09:00
Hide_D 86f1805160 fix: 병가 인구 상승률 버그 수정 (#255)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/255
2024-07-30 14:57:43 +09:00
jyp9 d573e9f98a fix: 병가 인구 상승률 버그 수정
fix: 병가 인구 상승률 버그 수정
2024-07-30 14:55:40 +09:00
Hide_D 3ad16d96be game: 긴급천도시 모든 장수에게 알림,
- 수뇌에게는 집합 메시지도 남김
2024-07-16 13:09:43 +09:00
Hide_D d8870caf29 feat: 포인트 초기화 추가
- 급하니까 일단 땜빵
2024-07-10 18:11:10 +00:00
Hide_D 7c9d5d34f6 feat: 스탯 초기화용 API 준비 2024-07-10 17:20:38 +00:00
Hide_D 5268ce9b71 game: 훈련, 사기진작 시 병력이 낮을 때도 숙련 상승량 조정 2024-07-10 17:00:35 +00:00
Hide_D e395c98a6c fix: 도시 주둔 장수 중 해당 국가 소속만 계략 확률 감소에 영향을 주도록 수정 (#254)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/254
2024-07-08 17:01:17 +09:00
Hide_D d5897e2a49 fix: 건국 유니크 100% 수정 2024-06-22 15:42:58 +00:00
Hide_D c82003f982 game: 건국시 확정 유니크, 유산 포인트 250점 2024-06-22 15:41:43 +00:00
Hide_D 5447274aa8 game: 사령턴 입력, 인사부 처리 시 삭턴 변경 2024-06-22 15:28:39 +00:00
Hide_D 688162ffbf fix: 이벤트 클래식은 907이 아니라 908이었어야함 2024-06-20 12:31:49 +00:00
Hide_D 220d1d821d fix: 삼황내문 로직 누락 수정 2024-06-19 13:23:07 +09:00
Hide_D 2b16c3c1a9 fix: 삼황내문을 새 저지 로직에 맞게 변경 2024-06-19 13:22:20 +09:00
Hide_D d731acdaef Revert "fix: 삼황내문을 새 저지 로직에 맞게 수정"
This reverts commit 3511b159a8.
2024-06-19 13:19:30 +09:00
Hide_D 3511b159a8 fix: 삼황내문을 새 저지 로직에 맞게 수정 2024-06-19 13:18:15 +09:00
Hide_D 28cea4ee09 fix: 메시지 수정 2024-06-08 18:55:48 +00:00
Hide_D 8e7227c29d fix: DummyGeneral에 penaltyList 2024-06-08 18:52:47 +00:00
Hide_D f0cc22d9d8 fix: NoChief 처리 부실 2024-06-08 18:48:46 +00:00
Hide_D b6f19fa38b feat: 유산포인트로 장수 소유자 확인 2024-06-08 18:42:39 +00:00
Hide_D 86305087f7 Revert "장수목록에서 장수명에 마우스를 올리면 본닉 공개"
This reverts commit a3d7ef30dd.
2024-06-08 17:52:13 +00:00
Hide_D 7b6f64db61 fix: 유저장이 수뇌 금지 장수밖에 없을때 NPC 임명 동작 2024-06-08 17:47:35 +00:00
Hide_D 06f086bcf0 fix: penalty 오타 2024-06-08 17:37:43 +00:00
Hide_D 606c1664f2 feat: 내정보에 징계목록 출력 2024-06-08 17:37:33 +00:00
Hide_D 0c07060f4d feat: 메시지 전송 페널티 2024-06-08 17:22:10 +00:00
Hide_D 8bd0cc1c64 feat: 건국 금지, 지정 임관 금지 패널티 2024-06-08 17:21:55 +00:00
Hide_D f12262b946 feat: 건국 불가 페널티 2024-06-08 16:16:52 +00:00
Hide_D 9415d79a3a feat: Constraint 시스템에 NoPaneltyKey 추가 2024-06-08 16:15:19 +00:00
Hide_D ad223a9c75 feat: NPC 임명로직에 NoChief, NoAmbassador 반영 2024-06-08 16:06:22 +00:00
Hide_D 8737b19e79 fix: 이미 수뇌인 장수는 NPC에게 외교권을 못받는 버그 수정 2024-06-08 15:58:52 +00:00
Hide_D 552d73430c feat: 유저장의 수뇌 임명 불가 penalty 2024-06-08 15:55:26 +00:00
Hide_D fba5fbdb6b feat: PenaltyKey::NoChiefTurnInput 2024-06-08 15:48:01 +00:00
Hide_D 3da11bf21c feat: 내 정보 설정 저장지 페널티 갱신 2024-06-08 15:41:27 +00:00
Hide_D c83f9a0465 game: 휴전 -> 종전 2024-06-08 14:43:40 +00:00
Hide_D 9f67ae1f4e feat: General::penaltyList 2024-06-08 14:38:31 +00:00
Hide_D 383431b79f feat: PenaltyKey enum 2024-06-08 14:06:12 +00:00
Hide_D d5c0d16758 game: 저지 작동 방식 변경
- 최대 페이즈를 1 깎는 형태로 변경
2024-06-08 13:24:32 +00:00
devsamanddevsam 87294d5477 fix: 도시 주둔 장수 중 해당 국가 소속만 계략 확률 감소에 영향을 주도록 수정 2024-06-01 07:00:35 +09:00
Hide_D c45758b054 game: 이벤트 클래식 유니크 최대 획득 확률 계수 수정 2024-05-22 17:45:45 +00:00
Hide_D a84f07f3ad game: 이벤트 클래식 시나리오 2024-05-22 17:43:29 +00:00
Hide_D 3c6ed3441b fix: MeekroDB 최신버전에서는 $db->get()으로 raw 호출을 먼저 시작해선 안됨 2024-05-22 17:00:27 +00:00
Hide_D 68cd61d86e fix: file_cache 문제 추가 수정 2024-05-22 16:47:20 +00:00
Hide_D 3470817e9e Nette FileStorage 요구 주소 문제 2024-05-22 16:45:29 +00:00
sars a3d7ef30dd 장수목록에서 장수명에 마우스를 올리면 본닉 공개 2024-05-20 19:03:51 -07:00
Hide_D db09e8da89 composer upgrade 2024-05-17 18:26:08 +00:00
Hide_D 37fa5321cc 초기 설치 코드 정돈, meekrodb 반영 2024-05-17 18:18:37 +00:00
Hide_D 63edb03193 APIHelper에 MeekroDBExceptionr에러시 logError 2024-05-17 18:16:54 +00:00
Hide_D 8d02102024 dep 2024-05-17 18:14:32 +00:00
Hide_D 75a13094e0 game: 해산시 군주외 장수는 즉시 임관 가능 2024-03-16 18:18:35 +00:00
Hide_D 7a4c70ada2 game: 강서유서 소설 월드 2024-03-16 18:07:59 +00:00
Hide_D 65c84a29e1 fix: 방랑군이동시 현재 소재 위치 확인 2024-03-16 18:07:42 +00:00
Hide_D eea34dadad fix: 이민족 수도 이동 2024-03-05 16:44:27 +00:00
Hide_D f1e6ac7b89 fix: 이민족 도시 이동 규칙 재작성
- 무한루프일 수 있으므로 그냥 SQL에 NOT IN을 넣자..
2024-02-29 10:35:32 +09:00
Hide_D 7b24f66f93 fix: 버그 수정 2024-02-29 10:28:10 +09:00
Hide_D b2b2934ce9 refac: 전체 penalty는 expire와 value
- 게임 개시시 expire가 되지 않은 것을 기준 value만 전달
- 즉, 페널티는 깃수 단위 적용
2024-02-29 10:27:04 +09:00
Hide_D 6ed3e673df game: 내정이라는 용어의 중의성 해소를 위해, 국가 성향의 내정이란 용어를 농상으로 바꾸고, 물자조달 커맨드를 내정의 하위 분류에서 국가로 이동 (#249)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/249
2024-02-29 10:18:00 +09:00
Hide_D aa7dcab1fd fix: 이민족 발동 시 수도가 이성이라 수도를 옮겼는데 다시 이성이 되는 경우 해결 (#250)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/250
2024-02-29 10:17:52 +09:00
devsamanddevsam e2e578e485 game: 내정이라는 용어의 중의성 해소를 위해, 국가 성향의 내정이란 용어를 농상으로 바꾸고, 물자조달 커맨드를 내정의 하위 분류에서 국가로 이동 2024-02-29 08:09:23 +09:00
devsamanddevsam 6cebc903c9 fix: typo 2024-02-29 08:02:11 +09:00
devsamanddevsam c0190959e3 fix: 이민족 발동 시 수도가 이성이라 수도를 옮겼는데 다시 이성이 되는 경우 해결 2024-02-29 08:01:02 +09:00
Hide_D bb26366769 fix: 이민족 발동 시 이성이 수도인 경우 문제 해결 2024-02-26 16:05:37 +00:00
Hide_D 71849a457b game: 종횡가의 전략 디메리트 감소
- 전략 쿨타임 2배 -> 4/3배
2024-02-26 16:01:16 +00:00
Hide_D 7c1a8d96a2 fix: 정규턴에 어긋나는 개인턴, 사령턴을 보정
- 조회시에만 사용
2024-02-26 15:58:41 +00:00
Hide_D cebd152daf fix: 경매장 소수점 제거 2024-02-26 15:43:07 +00:00
Hide_D 2ca03389d2 fix: 유니크 경매 항목 변경시 금액이 자동 조절되도록 수정
- 굳이 기존 값을 남길 이유가 없어보임
2024-02-24 15:14:24 +00:00
Hide_D cacf0981ce game: 턴 시간과 도시 지정을 같이 가능하도록 변경 2024-02-24 12:05:49 +00:00
Hide_D bcf5b5cb7d game: 턴 지정 단위를 1/30에서 1/60으로 변경 2024-02-24 11:46:32 +00:00
Hide_D 66b2f1a8f2 game: NPC는 건국 한턴 기다림 2024-02-24 11:45:08 +00:00
Hide_D 40ecca5440 game, feat: 커맨드마다 다른 랜덤값으로 유니크 시도
- 사전 거병 후 개인 턴일 때, 유니크 중복이 발생하는 경우가 있었음
2024-02-24 11:28:38 +00:00
Hide_D a96c2312d0 game, feat: 턴 시간 지정 방식을 30단계 중 선택하도록 변경
- 1분서버인 경우 120초 단위로
- 유산포인트 3000 -> 2500
2024-02-24 11:21:04 +00:00
Hide_D faff3f4e6a JSON -> Json
- 대체 왜 어떤 파일에는 에러가 나지 않았는가
2024-02-20 18:45:40 +09:00
Hide_D 83abf44380 feat: 유저의 제재 목록을 장수 생성/빙의시 가져옴 2024-02-18 03:24:21 +00:00
Hide_D e83960d67f fix: 사전거병시 삭턴 정상 반영 2024-02-18 03:10:42 +00:00
Hide_D c6b2e64c05 penalty에 sendPrivateMsgDelay추가 2024-02-18 03:08:21 +00:00
Hide_D 029f719112 fix: 스탯 계산 시에 캐시 사용하는 부분 수정 시도 (#241)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/241
2024-02-17 00:01:49 +09:00
Hide_D 46f460c8ad Merge branch 'devel' into stat_cache_fix 2024-02-17 00:01:40 +09:00
Hide_D af4401d9bb fix: 사전거병 후 군주가 사라지는 경우에 대한 수정 (#247)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/247
2024-02-17 00:01:34 +09:00
devsamanddevsam 2f00aee947 아주 약간 효율적으로 수정 2024-01-26 22:17:06 +09:00
devsamanddevsam dd2b032fa3 리뷰 내용 반영 2024-01-26 22:13:44 +09:00
Hide_D 1b858ae36c fix: onCalcOpposeStat이 제대로 전파되지 않았음 2023-12-30 04:15:33 +00:00
devsamanddevsam 69f4d8e2c7 fix: 사전거병 후 군주가 사라지는 경우에 대한 수정 2023-12-29 12:07:59 +09:00
Hide_D f24aea0120 fix: 수정된 턴 시간 변경 로직에서 바뀌기 이전 턴을 시드로 계속 사용하는 문제 수정 (#246)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/246
Reviewed-by: Hide_D <hided62@gmail.com>
2023-12-27 17:42:48 +09:00
Jinhyun Kim f6dc7f49e2 fix: 수정된 턴 시간 변경 로직에서 바뀌기 이전 턴을 시드로 계속 사용하는 문제 수정 2023-12-27 17:25:51 +09:00
Hide_D c1f105226f refac: 기존 commandButton.php 삭제
- 이젠 MainControlBar로 대체됨
2023-12-25 08:28:36 +00:00
Hide_D cecab2b0cf feat: 이호경식 발동시 '어느 국가'인지 바로 표기 2023-12-25 08:07:57 +00:00
Hide_D 39f4e89b03 feat: HasRouteWithEnemy에서 "교전 중인 국가가 아닙니다" 추가
- 경로에 도달할 방법이 없는 것은 맞으나..
- 교전중이 아니라는 것에 의미가 있음
2023-12-25 08:05:34 +00:00
Hide_D 83f595a27a feat: 종전시 세력 정보란에 문구 남김 2023-12-25 07:59:57 +00:00
Hide_D b0db11544d fix: 인사부 연동 스크립트 오타 수정 2023-12-25 07:56:27 +00:00
Hide_D 8e3551cb11 feat: 턴 시간 변경을 직관적인 동작으로 재 설계
- '다다음턴' 부터 시간을 00:00 ~ 59:59까지 랜덤하게
2023-12-25 07:51:54 +00:00
Hide_D 61d99a3043 초기 3년 이전에도 하야 가능
- 기존엔 1인국의 문제가 있었으나, 이미 NPC국이 자리를 채웠다.
2023-12-25 07:30:25 +00:00
Hide_D fe80deff0c 【가상모드27-e】 아시아 명장전(비급+파죽지세) (#244)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/244
2023-11-21 00:12:38 +09:00
포스트모더니즘 536c00f5a8 【가상모드27-e】 아시아 명장전(비급+파죽지세) 2023-11-21 00:04:20 +09:00
포스트모더니즘 66ed8635dd 【가상모드14-b】 걸그룹대전(비급) 시나리오 추가 2023-11-20 23:49:45 +09:00
포스트모더니즘 311c485cec fix: 불가침 제의를 같은 국가로 지정할 수 있는 버그 수정 2023-10-30 12:23:16 +09:00
포스트모더니즘andHide_D 5b5cf4e6d3 misc: 허보 대상 도시 선택 시에 선포 중인 경우 추가 2023-10-30 09:21:47 +09:00
포스트모더니즘 c5ed2d47fc fix: 스탯 계산 시에 캐시 사용하는 부분 수정 시도 2023-10-29 09:05:29 +09:00
포스트모더니즘 428ec0d0ed misc: 유니크 경매 취소 시에 경매 경매가 취소되었다고 표시되는 문제 수정 2023-10-29 08:37:36 +09:00
Jinhyun Kim 96c5f987d6 misc: 등용장 수락 시에도 국가 이름 볼드 처리 2023-10-14 07:57:27 +09:00
Hide_D f0ae28b087 fix: 이전 커밋에서 ' 하나를 "로 변경 2023-09-15 12:54:31 +09:00
Jinhyun Kim fa4a266d77 misc: 개인 기록에 전략 수행 내역이 남도록 수정, 백성동원 대상 도시도 남도록 수정 2023-09-09 07:48:48 +09:00
Hide_D 32e854858e feat: 랜덤 턴 초기화 시간 범위를 상세하게 알려줌 2023-09-03 17:11:41 +00:00
Hide_D f13371e679 fix: 저격에서 raiseType을 저격시도/저격발동 일치 2023-08-17 10:25:04 +09:00
Hide_D 2420f594a6 game: 자동 출병 조건 일부 수정
- 국고 병령이 2000 밑이더라도, 유저장은 출병
2023-08-14 07:30:16 +00:00
Hide_D b7b0a1050c feat: 도시 함락 시 수비 장수에게 트리거 발동 2023-08-14 06:04:43 +00:00
Hide_D d2a90157b9 fix: 트래픽에서 접속자수가 제대로 집계되지 않는 문제 2023-08-13 07:26:09 +00:00
Hide_D a32cb3a2c0 fix: 수비X 관련 warning
- 버그는 있으나 의도대로는 작동하였음
2023-08-12 10:07:58 +00:00
Hide_D 7c0a3a6955 fix: 접속량 정보가 기록되지 않았음 2023-08-12 10:06:08 +00:00
Hide_D 7d2e2945a1 fix: 연감 한번 더 수정 2023-08-10 19:08:21 +09:00
Hide_D dc526c7359 fix: 연감 수정 2023-08-10 19:06:40 +09:00
Hide_D 6c4cb484da fix: 연감 1개월차 수정 2023-08-10 19:06:01 +09:00
Hide_D d41246de9d fix: 초기 시작시 연감이 안보임 2023-08-10 19:04:55 +09:00
Hide_D 6d40783224 fix: 수극으로 인한 저격 소모 2023-08-07 13:19:52 +00:00
Hide_D 6eb6014e80 game: 출병시 전멸시페이즈 증가 적용
- 마지막 페이즈가 아닐 때 전멸 시 페이즈 증가
2023-08-07 11:26:43 +00:00
Hide_D 103cf3f882 game: 파죽지세 시나리오에서 수비끔시 훈사영향없음 2023-08-07 11:24:17 +00:00
Hide_D 5969e0c82b fix: 수극이 다른 저격과 따로 동작 2023-08-05 10:12:34 +00:00
Hide_D 945f9027dd game: StrongAttacker의 보정을 공방40%씩으로
- 병종저격하면 동률
2023-08-05 09:10:17 +00:00
Hide_D 0bf3145042 game: 파죽지세 모드, 접경귀환 2023-08-05 09:01:54 +00:00
Hide_D 905669755f feat: 접경 귀환 기능 추가 2023-08-05 08:57:15 +00:00
Hide_D 57b12e8c04 fix: Session에서 로그인 정보를 세심히. 2023-08-05 08:47:45 +00:00
Hide_D eccd883edc feat: NotOccupiedCity constraint 2023-08-05 07:59:26 +00:00
Hide_D 895b134cd0 feat: InstantAction 개념 추가 2023-08-05 07:54:55 +00:00
Hide_D 7258573e4d misc: 닥공전 이름을 파죽지세로 변경 2023-08-05 07:20:12 +00:00
Hide_D cbdfa6f6fc feat: 닥공전 기능 추가
- 장수 상대로 공격자인 경우
  - 공, 방 50%씩
2023-08-05 07:15:36 +00:00
Hide_D ed25c58410 fix: 오타 수정 2023-08-05 07:14:40 +00:00
Hide_D 16cfa46864 feat: scenarioEffect 추가
- 모든 General에 iAction으로 작동
2023-08-05 06:53:19 +00:00
Hide_D e54a0a6668 feat: 시나리오 생성 시 에러가 발생하면 메시지를 띄움 2023-08-05 06:52:50 +00:00
Hide_D eb545724ea fix: 천통후 이벤트에서 유산 포인트를 얻을 수 있는 문제 수정 2023-08-05 05:19:40 +00:00
Hide_D 7858b48bad fix: b_betting 수정 2023-08-03 16:20:32 +00:00
Hide_D a4ed41edbe fix: mergeQueryColumn위치 수정 2023-08-03 14:19:23 +00:00
Hide_D b5a9e52c43 fix: 인사부는 GeneralLite가 아니라 General 필요
- 추방시 명성 깎이는 문제 때문
2023-08-03 13:35:55 +00:00
Hide_D c6166d3295 fix: 수뇌임명 안되는 버그 수정
- 아니 대체 왜 경고를 안 띄우는거야!
2023-08-03 13:32:37 +00:00
Hide_D 9520d29109 fix: General 생성 코드 수정 2023-08-03 13:31:30 +00:00
Hide_D 3edfff146e General 클래스를 General, GeneralLite로 분리 (#236)
내부 코드 사용례에서 General 테이블의 column을 일부만 가져오는 경우가 다수 있습니다.

다만 General 클래스에서 각종 iAction에 해당하는 트리거 함수 호출을 위해서는 모든 column을 다 가져와야 정상 동작이 가능한 만큼, iAction interface를 구현한 General 클래스와, 구현하지 않은 GeneralLite 클래스 둘로 나눕니다.

또한 General 클래스에서는 필요한 column을 다 가져오도록 변경합니다.

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/236
2023-08-03 21:32:01 +09:00
Hide_D 38416ccdf8 fix,refac: 잠재적인 버그 위치 수정
- aux가 null이 아니라 0으로 되고 있었음
- (0 == null) == true이니 그동안 되고는 있었겠으나..
- increaseInheritancePointRaw()를 호출하도록 변경
2023-08-01 16:24:55 +00:00
Hide_D eeb5eabd12 feat: increaseInheritancePoint에 더해진 후의 값 반환 2023-08-01 16:24:52 +00:00
Hide_D 41273f97db feat,refac: increaseInheritancePointRaw 추가
- ownerID만으로 처리 가능
2023-08-01 16:24:43 +00:00
Jinhyun KimandGitea 0e23677e1b Merge pull request 'fix: 징병 가능 여부 판별 시 상대 년도 판별 로직 오류 해결' (#233) from jyp9/core:relyearfix into devel 2023-07-29 14:57:59 +00:00
Hide_D 0f085c7f36 fix: zero-ref 2023-07-27 17:27:11 +00:00
Hide_D bd90076441 phan: update config.php 2023-07-27 17:27:08 +00:00
Hide_D 1801bdf55b fix: 설문조사 시 아이템 추첨 문제
-  tryUniqueItemLottery()는 itemObjs 배열을 요구
- itemObjs 배열은 GeneralQueryMode::Full 에서만 사용가능
- 즉, Lite여서는 안됨!
2023-07-21 13:26:26 +00:00
Hide_D f27f0edfb6 fix: 빙의시 경고 제거 2023-07-21 13:22:04 +00:00
Hide_D 02f23e7db4 fix: 토너먼트 경고 해제 2023-07-21 13:09:45 +00:00
Hide_D 9871e24811 fix: defaultEventColumn에 turntime 추가
- 많이 쓰일 것으로 예상
2023-07-18 11:05:07 +09:00
Hide_D a7dac2ce15 fix: mergeQueryColumn에서 query 계산 방식 변경
- 요청 쿼리 = queryMode + reqColumn로 변경
- 기존에는 null일 경우에만 queryMode 전체, null이 아니면 queryMode를 한 단계 낮추고,
   reqColumn을 더하는 형태였음
- 지난 버그에서 혼동을 일으키는 요소였으므로 수정
2023-07-18 10:54:36 +09:00
Hide_D ed1d2cbf0d Revert "fix: 발령에서 destGeneral에 turntime 필요"
This reverts commit 06ca32802b.
2023-07-18 10:49:37 +09:00
Hide_D 06ca32802b fix: 발령에서 destGeneral에 turntime 필요 2023-07-17 17:44:45 +00:00
Hide_D 568b45f93a fix: minimumColumn에 owner 필요 2023-07-17 17:43:32 +00:00
420 changed files with 143983 additions and 4042 deletions
+1
View File
@@ -29,6 +29,7 @@ d_pic/*.jpg
d_pic/*.gif d_pic/*.gif
d_pic/*.png d_pic/*.png
d_pic/*.webp d_pic/*.webp
d_pic/*.avif
d_pic/uploaded_image d_pic/uploaded_image
/dist_js /dist_js
+2 -5
View File
@@ -15,9 +15,8 @@ return [
// Note that the **only** effect of choosing `'5.6'` is to infer // Note that the **only** effect of choosing `'5.6'` is to infer
// that functions removed in php 7.0 exist. // that functions removed in php 7.0 exist.
// (See `backward_compatibility_checks` for additional options) // (See `backward_compatibility_checks` for additional options)
"target_php_version" => '8.1', "target_php_version" => '8.2',
"minimum_target_php_version" => '8.1', "minimum_target_php_version" => '8.2',
'backward_compatibility_checks ' => true,
'minimum_severity' => \Phan\Issue::SEVERITY_NORMAL, 'minimum_severity' => \Phan\Issue::SEVERITY_NORMAL,
'file_list' => [ 'file_list' => [
@@ -29,8 +28,6 @@ return [
'hwe/_admin1_submit.php', 'hwe/_admin1_submit.php',
'hwe/_admin2.php', 'hwe/_admin2.php',
'hwe/_admin2_submit.php', 'hwe/_admin2_submit.php',
'hwe/_admin4.php',
'hwe/_admin4_submit.php',
'hwe/_admin5.php', 'hwe/_admin5.php',
'hwe/_admin5_submit.php', 'hwe/_admin5_submit.php',
'hwe/_admin7.php', 'hwe/_admin7.php',
+4 -5
View File
@@ -8,12 +8,11 @@
], ],
"config": { "config": {
"platform": { "platform": {
"php": "8.2" "php": "8.3"
} }
}, },
"require": { "require": {
"brandonwamboldt/utilphp": "^1.1", "sergeytsalkov/meekrodb": "^2.5",
"sergeytsalkov/meekrodb": "^2.3",
"league/plates": "^3.5", "league/plates": "^3.5",
"vlucas/valitron": "^1.4", "vlucas/valitron": "^1.4",
"php-extended/php-tail": "^5.0", "php-extended/php-tail": "^5.0",
@@ -22,10 +21,10 @@
"xemlock/htmlpurifier-html5": "^0.1.7", "xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^2.1", "catfan/medoo": "^2.1",
"phan/phan": "^5.4", "phan/phan": "^5.4",
"nette/caching": "^3.2", "nette/caching": "^3.3",
"illuminate/database": "^10.0", "illuminate/database": "^10.0",
"illuminate/events": "^10.0", "illuminate/events": "^10.0",
"php-ds/php-ds": "^1.4", "php-ds/php-ds": "^1.5",
"hided62/ldto": "^1.0", "hided62/ldto": "^1.0",
"league/uri": "^6.8" "league/uri": "^6.8"
}, },
Generated
+717 -587
View File
@@ -4,79 +4,29 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "e878a776667c3f0cbef0a48b3504d965", "content-hash": "7edae9b6be35e66ffd0d180f5fac6679",
"packages": [ "packages": [
{
"name": "brandonwamboldt/utilphp",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/brandonwamboldt/utilphp.git",
"reference": "36c32efc4f0679c05163464a550f45c8d83fe683"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brandonwamboldt/utilphp/zipball/36c32efc4f0679c05163464a550f45c8d83fe683",
"reference": "36c32efc4f0679c05163464a550f45c8d83fe683",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"satooshi/php-coveralls": "dev-master"
},
"type": "library",
"autoload": {
"psr-0": {
"utilphp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brandon Wamboldt",
"email": "brandon.wamboldt@gmail.com"
}
],
"description": "util.php is a collection of useful functions and snippets that you need or could use every day, designed to avoid conflicts with existing projects",
"homepage": "https://github.com/brandonwamboldt/utilphp",
"keywords": [
"collection",
"helpers",
"php",
"utility"
],
"support": {
"issues": "https://github.com/brandonwamboldt/utilphp/issues",
"source": "https://github.com/brandonwamboldt/utilphp/tree/master"
},
"time": "2015-02-02T17:56:14+00:00"
},
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.11.0", "version": "0.12.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/brick/math.git", "url": "https://github.com/brick/math.git",
"reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" "reference": "f510c0a40911935b77b86859eb5223d58d660df1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
"reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", "reference": "f510c0a40911935b77b86859eb5223d58d660df1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.0" "php": "^8.1"
}, },
"require-dev": { "require-dev": {
"php-coveralls/php-coveralls": "^2.2", "php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^9.0", "phpunit/phpunit": "^10.1",
"vimeo/psalm": "5.0.0" "vimeo/psalm": "5.16.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -96,12 +46,17 @@
"arithmetic", "arithmetic",
"bigdecimal", "bigdecimal",
"bignum", "bignum",
"bignumber",
"brick", "brick",
"math" "decimal",
"integer",
"math",
"mathematics",
"rational"
], ],
"support": { "support": {
"issues": "https://github.com/brick/math/issues", "issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.11.0" "source": "https://github.com/brick/math/tree/0.12.1"
}, },
"funding": [ "funding": [
{ {
@@ -109,20 +64,89 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-01-15T23:15:59+00:00" "time": "2023-11-29T23:19:16+00:00"
}, },
{ {
"name": "catfan/medoo", "name": "carbonphp/carbon-doctrine-types",
"version": "v2.1.8", "version": "2.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/catfan/Medoo.git", "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
"reference": "b49a620cf1ad0d2e90ebd9f85b82aa11271df5f4" "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/catfan/Medoo/zipball/b49a620cf1ad0d2e90ebd9f85b82aa11271df5f4", "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"reference": "b49a620cf1ad0d2e90ebd9f85b82aa11271df5f4", "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"doctrine/dbal": "<3.7.0 || >=4.0.0"
},
"require-dev": {
"doctrine/dbal": "^3.7.0",
"nesbot/carbon": "^2.71.0 || ^3.0.0",
"phpunit/phpunit": "^10.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "KyleKatarn",
"email": "kylekatarnls@gmail.com"
}
],
"description": "Types to use Carbon in Doctrine",
"keywords": [
"carbon",
"date",
"datetime",
"doctrine",
"time"
],
"support": {
"issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0"
},
"funding": [
{
"url": "https://github.com/kylekatarnls",
"type": "github"
},
{
"url": "https://opencollective.com/Carbon",
"type": "open_collective"
},
{
"url": "https://tidelift.com/funding/github/packagist/nesbot/carbon",
"type": "tidelift"
}
],
"time": "2023-12-11T17:09:12+00:00"
},
{
"name": "catfan/medoo",
"version": "v2.1.12",
"source": {
"type": "git",
"url": "https://github.com/catfan/Medoo.git",
"reference": "d1ff4e0e873a3e032e3d8804031dd6be4e013b22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/catfan/Medoo/zipball/d1ff4e0e873a3e032e3d8804031dd6be4e013b22",
"reference": "d1ff4e0e873a3e032e3d8804031dd6be4e013b22",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -185,20 +209,20 @@
"type": "open_collective" "type": "open_collective"
} }
], ],
"time": "2023-01-20T09:30:24+00:00" "time": "2024-02-03T11:28:59+00:00"
}, },
{ {
"name": "composer/pcre", "name": "composer/pcre",
"version": "3.1.0", "version": "3.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/pcre.git", "url": "https://github.com/composer/pcre.git",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "url": "https://api.github.com/repos/composer/pcre/zipball/5b16e25a5355f1f3afdfc2f954a0a80aec4826a8",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -240,7 +264,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/composer/pcre/issues", "issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.1.0" "source": "https://github.com/composer/pcre/tree/3.1.3"
}, },
"funding": [ "funding": [
{ {
@@ -256,20 +280,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-17T09:50:14+00:00" "time": "2024-03-19T10:26:25+00:00"
}, },
{ {
"name": "composer/semver", "name": "composer/semver",
"version": "3.3.2", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/semver.git", "url": "https://github.com/composer/semver.git",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
"reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -319,9 +343,9 @@
"versioning" "versioning"
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues", "issues": "https://github.com/composer/semver/issues",
"source": "https://github.com/composer/semver/tree/3.3.2" "source": "https://github.com/composer/semver/tree/3.4.0"
}, },
"funding": [ "funding": [
{ {
@@ -337,20 +361,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-04-01T19:23:25+00:00" "time": "2023-08-31T09:50:34+00:00"
}, },
{ {
"name": "composer/xdebug-handler", "name": "composer/xdebug-handler",
"version": "3.0.3", "version": "3.0.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/composer/xdebug-handler.git", "url": "https://github.com/composer/xdebug-handler.git",
"reference": "ced299686f41dce890debac69273b47ffe98a40c" "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
"reference": "ced299686f41dce890debac69273b47ffe98a40c", "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -361,7 +385,7 @@
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.0", "phpstan/phpstan": "^1.0",
"phpstan/phpstan-strict-rules": "^1.1", "phpstan/phpstan-strict-rules": "^1.1",
"symfony/phpunit-bridge": "^6.0" "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -385,9 +409,9 @@
"performance" "performance"
], ],
"support": { "support": {
"irc": "irc://irc.freenode.org/composer", "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/xdebug-handler/issues", "issues": "https://github.com/composer/xdebug-handler/issues",
"source": "https://github.com/composer/xdebug-handler/tree/3.0.3" "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
}, },
"funding": [ "funding": [
{ {
@@ -403,32 +427,79 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-02-25T21:32:43+00:00" "time": "2024-05-06T16:37:16+00:00"
}, },
{ {
"name": "doctrine/inflector", "name": "doctrine/deprecations",
"version": "2.0.6", "version": "1.1.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/inflector.git", "url": "https://github.com/doctrine/deprecations.git",
"reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024" "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpstan/phpstan": "1.4.10 || 1.10.15",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "0.18.4",
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.3"
},
"time": "2024-01-30T19:34:25+00:00"
},
{
"name": "doctrine/inflector",
"version": "2.0.10",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc",
"reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2 || ^8.0" "php": "^7.2 || ^8.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^10", "doctrine/coding-standard": "^11.0",
"phpstan/phpstan": "^1.8", "phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.3", "phpstan/phpstan-strict-rules": "^1.3",
"phpunit/phpunit": "^8.5 || ^9.5", "phpunit/phpunit": "^8.5 || ^9.5",
"vimeo/psalm": "^4.25" "vimeo/psalm": "^4.25 || ^5.4"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -478,7 +549,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/inflector/issues", "issues": "https://github.com/doctrine/inflector/issues",
"source": "https://github.com/doctrine/inflector/tree/2.0.6" "source": "https://github.com/doctrine/inflector/tree/2.0.10"
}, },
"funding": [ "funding": [
{ {
@@ -494,24 +565,24 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-10-20T09:10:12+00:00" "time": "2024-02-18T20:23:39+00:00"
}, },
{ {
"name": "ezyang/htmlpurifier", "name": "ezyang/htmlpurifier",
"version": "v4.16.0", "version": "v4.17.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git", "url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8" "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8", "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c",
"reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8", "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0" "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
}, },
"require-dev": { "require-dev": {
"cerdic/css-tidy": "^1.7 || ^2.0", "cerdic/css-tidy": "^1.7 || ^2.0",
@@ -553,9 +624,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues", "issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0" "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0"
}, },
"time": "2022-09-18T07:06:19+00:00" "time": "2023-11-17T15:01:25+00:00"
}, },
{ {
"name": "felixfbecker/advanced-json-rpc", "name": "felixfbecker/advanced-json-rpc",
@@ -604,16 +675,16 @@
}, },
{ {
"name": "hided62/ldto", "name": "hided62/ldto",
"version": "v1.0.0", "version": "v1.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hided62/ldto.git", "url": "https://github.com/hided62/ldto.git",
"reference": "4c05401406f8afc1636a90763c13884f8fff0d14" "reference": "7f0cc568e35120868fe1178e96265c4fa0624820"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hided62/ldto/zipball/4c05401406f8afc1636a90763c13884f8fff0d14", "url": "https://api.github.com/repos/hided62/ldto/zipball/7f0cc568e35120868fe1178e96265c4fa0624820",
"reference": "4c05401406f8afc1636a90763c13884f8fff0d14", "reference": "7f0cc568e35120868fe1178e96265c4fa0624820",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -652,22 +723,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/hided62/ldto/issues", "issues": "https://github.com/hided62/ldto/issues",
"source": "https://github.com/hided62/ldto/tree/v1.0.0" "source": "https://github.com/hided62/ldto/tree/v1.0.1"
}, },
"time": "2022-08-05T14:30:13+00:00" "time": "2023-03-04T07:51:45+00:00"
}, },
{ {
"name": "illuminate/bus", "name": "illuminate/bus",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/bus.git", "url": "https://github.com/illuminate/bus.git",
"reference": "139999f560611623c7da494faa3d8a92f8e22e68" "reference": "33993b8f54e91b03fb5000e55693e146e7370763"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/bus/zipball/139999f560611623c7da494faa3d8a92f8e22e68", "url": "https://api.github.com/repos/illuminate/bus/zipball/33993b8f54e91b03fb5000e55693e146e7370763",
"reference": "139999f560611623c7da494faa3d8a92f8e22e68", "reference": "33993b8f54e91b03fb5000e55693e146e7370763",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -707,20 +778,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2022-11-30T17:23:35+00:00" "time": "2024-02-23T15:38:25+00:00"
}, },
{ {
"name": "illuminate/collections", "name": "illuminate/collections",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/collections.git", "url": "https://github.com/illuminate/collections.git",
"reference": "f48e6e52860edc9f261f414a85ed2b9b295a324c" "reference": "f9589f1063a449111dcaa1d68285b507d9483a95"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/collections/zipball/f48e6e52860edc9f261f414a85ed2b9b295a324c", "url": "https://api.github.com/repos/illuminate/collections/zipball/f9589f1063a449111dcaa1d68285b507d9483a95",
"reference": "f48e6e52860edc9f261f414a85ed2b9b295a324c", "reference": "f9589f1063a449111dcaa1d68285b507d9483a95",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -762,11 +833,11 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-22T14:38:35+00:00" "time": "2024-03-20T20:09:13+00:00"
}, },
{ {
"name": "illuminate/conditionable", "name": "illuminate/conditionable",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/conditionable.git", "url": "https://github.com/illuminate/conditionable.git",
@@ -812,16 +883,16 @@
}, },
{ {
"name": "illuminate/container", "name": "illuminate/container",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/container.git", "url": "https://github.com/illuminate/container.git",
"reference": "fed3ee8f7389ad431833935d9ed665bc02ac2cca" "reference": "ddc26273085fad3c471b2602ad820e0097ff7939"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/fed3ee8f7389ad431833935d9ed665bc02ac2cca", "url": "https://api.github.com/repos/illuminate/container/zipball/ddc26273085fad3c471b2602ad820e0097ff7939",
"reference": "fed3ee8f7389ad431833935d9ed665bc02ac2cca", "reference": "ddc26273085fad3c471b2602ad820e0097ff7939",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -859,20 +930,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-01-25T18:11:51+00:00" "time": "2023-06-18T09:12:03+00:00"
}, },
{ {
"name": "illuminate/contracts", "name": "illuminate/contracts",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/contracts.git", "url": "https://github.com/illuminate/contracts.git",
"reference": "84f1da424ab9596a422ce118abd05667b0069624" "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/84f1da424ab9596a422ce118abd05667b0069624", "url": "https://api.github.com/repos/illuminate/contracts/zipball/8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac",
"reference": "84f1da424ab9596a422ce118abd05667b0069624", "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -907,24 +978,24 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-14T15:00:37+00:00" "time": "2024-01-15T18:52:32+00:00"
}, },
{ {
"name": "illuminate/database", "name": "illuminate/database",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/database.git", "url": "https://github.com/illuminate/database.git",
"reference": "782940a3092e86c8d022d6d8d168b64fb97933a5" "reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/database/zipball/782940a3092e86c8d022d6d8d168b64fb97933a5", "url": "https://api.github.com/repos/illuminate/database/zipball/eb8edf206d3a6eea8894bc6e21f53469e27dd5c9",
"reference": "782940a3092e86c8d022d6d8d168b64fb97933a5", "reference": "eb8edf206d3a6eea8894bc6e21f53469e27dd5c9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"brick/math": "^0.9.3|^0.10.2|^0.11", "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12",
"ext-pdo": "*", "ext-pdo": "*",
"illuminate/collections": "^10.0", "illuminate/collections": "^10.0",
"illuminate/container": "^10.0", "illuminate/container": "^10.0",
@@ -933,6 +1004,10 @@
"illuminate/support": "^10.0", "illuminate/support": "^10.0",
"php": "^8.1" "php": "^8.1"
}, },
"conflict": {
"carbonphp/carbon-doctrine-types": ">=3.0",
"doctrine/dbal": ">=4.0"
},
"suggest": { "suggest": {
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^3.5.1).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^3.5.1).",
"ext-filter": "Required to use the Postgres database driver.", "ext-filter": "Required to use the Postgres database driver.",
@@ -976,20 +1051,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-23T18:43:10+00:00" "time": "2024-04-29T13:23:17+00:00"
}, },
{ {
"name": "illuminate/events", "name": "illuminate/events",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/events.git", "url": "https://github.com/illuminate/events.git",
"reference": "c68138ea57360c19a145e5912fb474cfd1845366" "reference": "a931bfa88edc6ac52c9abbfd7b769343d321d3eb"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/events/zipball/c68138ea57360c19a145e5912fb474cfd1845366", "url": "https://api.github.com/repos/illuminate/events/zipball/a931bfa88edc6ac52c9abbfd7b769343d321d3eb",
"reference": "c68138ea57360c19a145e5912fb474cfd1845366", "reference": "a931bfa88edc6ac52c9abbfd7b769343d321d3eb",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1031,20 +1106,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-16T15:35:09+00:00" "time": "2024-03-04T14:41:04+00:00"
}, },
{ {
"name": "illuminate/macroable", "name": "illuminate/macroable",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/macroable.git", "url": "https://github.com/illuminate/macroable.git",
"reference": "7686fe9dba1e236e6f695a148b551264b9fd479e" "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/macroable/zipball/7686fe9dba1e236e6f695a148b551264b9fd479e", "url": "https://api.github.com/repos/illuminate/macroable/zipball/dff667a46ac37b634dcf68909d9d41e94dc97c27",
"reference": "7686fe9dba1e236e6f695a148b551264b9fd479e", "reference": "dff667a46ac37b634dcf68909d9d41e94dc97c27",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1077,20 +1152,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-01-30T23:18:36+00:00" "time": "2023-06-05T12:46:42+00:00"
}, },
{ {
"name": "illuminate/pipeline", "name": "illuminate/pipeline",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/pipeline.git", "url": "https://github.com/illuminate/pipeline.git",
"reference": "549fc7f9b2e6fef0436ca0f68714e1a0e4de8aad" "reference": "f802187e917a171332cc90f8c1a102939c57405d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/pipeline/zipball/549fc7f9b2e6fef0436ca0f68714e1a0e4de8aad", "url": "https://api.github.com/repos/illuminate/pipeline/zipball/f802187e917a171332cc90f8c1a102939c57405d",
"reference": "549fc7f9b2e6fef0436ca0f68714e1a0e4de8aad", "reference": "f802187e917a171332cc90f8c1a102939c57405d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1125,20 +1200,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2022-06-10T06:51:19+00:00" "time": "2023-12-19T14:47:26+00:00"
}, },
{ {
"name": "illuminate/support", "name": "illuminate/support",
"version": "v10.1.5", "version": "v10.48.10",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/support.git", "url": "https://github.com/illuminate/support.git",
"reference": "0311d96fb673e9694e1df838abb12f4e4019cdc4" "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/0311d96fb673e9694e1df838abb12f4e4019cdc4", "url": "https://api.github.com/repos/illuminate/support/zipball/ee3a1aaed36d916654ce0ae09dfbd38644a4f582",
"reference": "0311d96fb673e9694e1df838abb12f4e4019cdc4", "reference": "ee3a1aaed36d916654ce0ae09dfbd38644a4f582",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1150,7 +1225,7 @@
"illuminate/conditionable": "^10.0", "illuminate/conditionable": "^10.0",
"illuminate/contracts": "^10.0", "illuminate/contracts": "^10.0",
"illuminate/macroable": "^10.0", "illuminate/macroable": "^10.0",
"nesbot/carbon": "^2.62.1", "nesbot/carbon": "^2.67",
"php": "^8.1", "php": "^8.1",
"voku/portable-ascii": "^2.0" "voku/portable-ascii": "^2.0"
}, },
@@ -1196,7 +1271,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-02-23T07:42:03+00:00" "time": "2024-04-07T17:47:33+00:00"
}, },
{ {
"name": "league/plates", "name": "league/plates",
@@ -1435,16 +1510,16 @@
}, },
{ {
"name": "microsoft/tolerant-php-parser", "name": "microsoft/tolerant-php-parser",
"version": "v0.1.1", "version": "v0.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/microsoft/tolerant-php-parser.git", "url": "https://github.com/microsoft/tolerant-php-parser.git",
"reference": "6a965617cf484355048ac6d2d3de7b6ec93abb16" "reference": "3eccfd273323aaf69513e2f1c888393f5947804b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/6a965617cf484355048ac6d2d3de7b6ec93abb16", "url": "https://api.github.com/repos/microsoft/tolerant-php-parser/zipball/3eccfd273323aaf69513e2f1c888393f5947804b",
"reference": "6a965617cf484355048ac6d2d3de7b6ec93abb16", "reference": "3eccfd273323aaf69513e2f1c888393f5947804b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1474,34 +1549,39 @@
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios", "description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios",
"support": { "support": {
"issues": "https://github.com/microsoft/tolerant-php-parser/issues", "issues": "https://github.com/microsoft/tolerant-php-parser/issues",
"source": "https://github.com/microsoft/tolerant-php-parser/tree/v0.1.1" "source": "https://github.com/microsoft/tolerant-php-parser/tree/v0.1.2"
}, },
"time": "2021-07-16T21:28:12+00:00" "time": "2022-10-05T17:30:19+00:00"
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.66.0", "version": "2.72.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "496712849902241f04902033b0441b269effe001" "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/496712849902241f04902033b0441b269effe001", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83",
"reference": "496712849902241f04902033b0441b269effe001", "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"carbonphp/carbon-doctrine-types": "*",
"ext-json": "*", "ext-json": "*",
"php": "^7.1.8 || ^8.0", "php": "^7.1.8 || ^8.0",
"psr/clock": "^1.0",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16", "symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
}, },
"provide": {
"psr/clock-implementation": "1.0"
},
"require-dev": { "require-dev": {
"doctrine/dbal": "^2.0 || ^3.1.4", "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0",
"doctrine/orm": "^2.7", "doctrine/orm": "^2.7 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.0", "friendsofphp/php-cs-fixer": "^3.0",
"kylekatarnls/multi-tester": "^2.0", "kylekatarnls/multi-tester": "^2.0",
"ondrejmirtes/better-reflection": "*", "ondrejmirtes/better-reflection": "*",
@@ -1578,20 +1658,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-29T18:53:47+00:00" "time": "2024-01-25T10:35:09+00:00"
}, },
{ {
"name": "netresearch/jsonmapper", "name": "netresearch/jsonmapper",
"version": "v4.1.0", "version": "v4.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/cweiske/jsonmapper.git", "url": "https://github.com/cweiske/jsonmapper.git",
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0",
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1602,7 +1682,7 @@
"php": ">=7.1" "php": ">=7.1"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
"squizlabs/php_codesniffer": "~3.5" "squizlabs/php_codesniffer": "~3.5"
}, },
"type": "library", "type": "library",
@@ -1627,31 +1707,33 @@
"support": { "support": {
"email": "cweiske@cweiske.de", "email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues", "issues": "https://github.com/cweiske/jsonmapper/issues",
"source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0" "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1"
}, },
"time": "2022-12-08T20:46:14+00:00" "time": "2024-01-31T06:18:54+00:00"
}, },
{ {
"name": "nette/caching", "name": "nette/caching",
"version": "v3.2.2", "version": "v3.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/caching.git", "url": "https://github.com/nette/caching.git",
"reference": "ceb814d7f0a2bb4eb5afbe908467801001187745" "reference": "3053707a892e100e81efb53dc8c294dca5e076d0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/caching/zipball/ceb814d7f0a2bb4eb5afbe908467801001187745", "url": "https://api.github.com/repos/nette/caching/zipball/3053707a892e100e81efb53dc8c294dca5e076d0",
"reference": "ceb814d7f0a2bb4eb5afbe908467801001187745", "reference": "3053707a892e100e81efb53dc8c294dca5e076d0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"nette/finder": "^2.4 || ^3.0", "nette/utils": "^4.0",
"nette/utils": "^3.2 || ~4.0.0", "php": "8.0 - 8.3"
"php": ">=8.0 <8.3" },
"conflict": {
"latte/latte": ">=3.0.0 <3.0.12"
}, },
"require-dev": { "require-dev": {
"latte/latte": "^2.11 || ^3.0", "latte/latte": "^2.11 || ^3.0.12",
"nette/di": "^3.1 || ^4.0", "nette/di": "^3.1 || ^4.0",
"nette/tester": "^2.4", "nette/tester": "^2.4",
"phpstan/phpstan": "^1.0", "phpstan/phpstan": "^1.0",
@@ -1663,7 +1745,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.2-dev" "dev-master": "3.3-dev"
} }
}, },
"autoload": { "autoload": {
@@ -1698,79 +1780,26 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/caching/issues", "issues": "https://github.com/nette/caching/issues",
"source": "https://github.com/nette/caching/tree/v3.2.2" "source": "https://github.com/nette/caching/tree/v3.3.0"
}, },
"time": "2023-02-04T13:52:33+00:00" "time": "2024-03-10T22:07:25+00:00"
},
{
"name": "nette/finder",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/nette/finder.git",
"reference": "027395c638637de95c8e9fad49a7c51249404ed2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/finder/zipball/027395c638637de95c8e9fad49a7c51249404ed2",
"reference": "027395c638637de95c8e9fad49a7c51249404ed2",
"shasum": ""
},
"require": {
"nette/utils": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https://davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https://nette.org/contributors"
}
],
"description": "🔍 Nette Finder: find files and directories with an intuitive API.",
"homepage": "https://nette.org",
"keywords": [
"filesystem",
"glob",
"iterator",
"nette"
],
"support": {
"issues": "https://github.com/nette/finder/issues",
"source": "https://github.com/nette/finder/tree/v3.0.0"
},
"time": "2022-12-14T17:05:54+00:00"
}, },
{ {
"name": "nette/utils", "name": "nette/utils",
"version": "v4.0.0", "version": "v4.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/utils.git", "url": "https://github.com/nette/utils.git",
"reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e" "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/cacdbf5a91a657ede665c541eda28941d4b09c1e", "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218",
"reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e", "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0 <8.3" "php": ">=8.0 <8.4"
}, },
"conflict": { "conflict": {
"nette/finder": "<3", "nette/finder": "<3",
@@ -1778,7 +1807,7 @@
}, },
"require-dev": { "require-dev": {
"jetbrains/phpstorm-attributes": "dev-master", "jetbrains/phpstorm-attributes": "dev-master",
"nette/tester": "^2.4", "nette/tester": "^2.5",
"phpstan/phpstan": "^1.0", "phpstan/phpstan": "^1.0",
"tracy/tracy": "^2.9" "tracy/tracy": "^2.9"
}, },
@@ -1788,8 +1817,7 @@
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json", "ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...", "ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -1838,22 +1866,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/utils/issues", "issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.0" "source": "https://github.com/nette/utils/tree/v4.0.4"
}, },
"time": "2023-02-02T10:41:53+00:00" "time": "2024-01-17T16:50:36+00:00"
}, },
{ {
"name": "phan/phan", "name": "phan/phan",
"version": "5.4.1", "version": "5.4.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phan/phan.git", "url": "https://github.com/phan/phan.git",
"reference": "fef40178a952bcfcc3f69b76989dd613c3d5c759" "reference": "86a7acd99c1239b8867b49feca2398851212e7fe"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phan/phan/zipball/fef40178a952bcfcc3f69b76989dd613c3d5c759", "url": "https://api.github.com/repos/phan/phan/zipball/86a7acd99c1239b8867b49feca2398851212e7fe",
"reference": "fef40178a952bcfcc3f69b76989dd613c3d5c759", "reference": "86a7acd99c1239b8867b49feca2398851212e7fe",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1863,11 +1891,11 @@
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"felixfbecker/advanced-json-rpc": "^3.0.4", "felixfbecker/advanced-json-rpc": "^3.0.4",
"microsoft/tolerant-php-parser": "0.1.1", "microsoft/tolerant-php-parser": "0.1.2",
"netresearch/jsonmapper": "^1.6.0|^2.0|^3.0|^4.0", "netresearch/jsonmapper": "^1.6.0|^2.0|^3.0|^4.0",
"php": "^7.2.0|^8.0.0", "php": "^7.2.0|^8.0.0",
"sabre/event": "^5.1.3", "sabre/event": "^5.1.3",
"symfony/console": "^3.2|^4.0|^5.0|^6.0", "symfony/console": "^3.2|^4.0|^5.0|^6.0|^7.0",
"symfony/polyfill-mbstring": "^1.11.0", "symfony/polyfill-mbstring": "^1.11.0",
"symfony/polyfill-php80": "^1.20.0", "symfony/polyfill-php80": "^1.20.0",
"tysonandre/var_representation_polyfill": "^0.0.2|^0.1.0" "tysonandre/var_representation_polyfill": "^0.0.2|^0.1.0"
@@ -1913,26 +1941,27 @@
"keywords": [ "keywords": [
"analyzer", "analyzer",
"php", "php",
"static" "static",
"static analysis"
], ],
"support": { "support": {
"issues": "https://github.com/phan/phan/issues", "issues": "https://github.com/phan/phan/issues",
"source": "https://github.com/phan/phan/tree/5.4.1" "source": "https://github.com/phan/phan/tree/5.4.3"
}, },
"time": "2022-08-26T00:49:07+00:00" "time": "2023-12-26T17:57:35+00:00"
}, },
{ {
"name": "php-ds/php-ds", "name": "php-ds/php-ds",
"version": "v1.4.1", "version": "v1.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-ds/polyfill.git", "url": "https://github.com/php-ds/polyfill.git",
"reference": "43d2df301a9e2017f67b8c11d94a5222f9c00fd1" "reference": "7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-ds/polyfill/zipball/43d2df301a9e2017f67b8c11d94a5222f9c00fd1", "url": "https://api.github.com/repos/php-ds/polyfill/zipball/7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4",
"reference": "43d2df301a9e2017f67b8c11d94a5222f9c00fd1", "reference": "7b2c5f1843466d50769a0682ce6fa9ddaaa99cb4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1940,10 +1969,10 @@
"php": ">=7.0" "php": ">=7.0"
}, },
"provide": { "provide": {
"ext-ds": "1.3.0" "ext-ds": "1.5.0"
}, },
"require-dev": { "require-dev": {
"php-ds/tests": "^1.3" "php-ds/tests": "^1.5"
}, },
"suggest": { "suggest": {
"ext-ds": "to improve performance and reduce memory usage" "ext-ds": "to improve performance and reduce memory usage"
@@ -1972,22 +2001,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/php-ds/polyfill/issues", "issues": "https://github.com/php-ds/polyfill/issues",
"source": "https://github.com/php-ds/polyfill/tree/v1.4.1" "source": "https://github.com/php-ds/polyfill/tree/v1.5.0"
}, },
"time": "2022-03-09T20:39:30+00:00" "time": "2023-12-19T16:52:21+00:00"
}, },
{ {
"name": "php-extended/php-system", "name": "php-extended/php-system",
"version": "5.0.0", "version": "5.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "git@gitlab.com:php-extended/php-system.git", "url": "git@gitlab.com:php-extended/php-system.git",
"reference": "c269fbf3d358679b229b922b6c5be5dac9bbd1ab" "reference": "a80365cc08f43e740f3d1b77505d3242d954555a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://gitlab.com/api/v4/projects/php-extended%2Fphp-system/repository/archive.zip?sha=c269fbf3d358679b229b922b6c5be5dac9bbd1ab", "url": "https://gitlab.com/api/v4/projects/php-extended%2Fphp-system/repository/archive.zip?sha=a80365cc08f43e740f3d1b77505d3242d954555a",
"reference": "c269fbf3d358679b229b922b6c5be5dac9bbd1ab", "reference": "a80365cc08f43e740f3d1b77505d3242d954555a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2025,20 +2054,20 @@
"issues": "https://gitlab.com/php-extended/php-system/issues", "issues": "https://gitlab.com/php-extended/php-system/issues",
"source": "https://gitlab.com/php-extended/php-system" "source": "https://gitlab.com/php-extended/php-system"
}, },
"time": "2022-12-12T07:20:57+00:00" "time": "2023-06-26T19:35:14+00:00"
}, },
{ {
"name": "php-extended/php-tail", "name": "php-extended/php-tail",
"version": "5.0.0", "version": "5.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "git@gitlab.com:php-extended/php-tail.git", "url": "git@gitlab.com:php-extended/php-tail.git",
"reference": "d932ed124887b0e0691751a4bb197b759707e1d8" "reference": "4a76745626d8e0359fee3bf87614e2478b3f80c5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://gitlab.com/api/v4/projects/php-extended%2Fphp-tail/repository/archive.zip?sha=d932ed124887b0e0691751a4bb197b759707e1d8", "url": "https://gitlab.com/api/v4/projects/php-extended%2Fphp-tail/repository/archive.zip?sha=4a76745626d8e0359fee3bf87614e2478b3f80c5",
"reference": "d932ed124887b0e0691751a4bb197b759707e1d8", "reference": "4a76745626d8e0359fee3bf87614e2478b3f80c5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2078,20 +2107,20 @@
"issues": "https://gitlab.com/php-extended/php-tail/issues", "issues": "https://gitlab.com/php-extended/php-tail/issues",
"source": "https://gitlab.com/php-extended/php-tail" "source": "https://gitlab.com/php-extended/php-tail"
}, },
"time": "2022-12-18T11:15:32+00:00" "time": "2023-06-26T19:35:24+00:00"
}, },
{ {
"name": "php-extended/polyfill-php80-stringable", "name": "php-extended/polyfill-php80-stringable",
"version": "1.2.0", "version": "1.2.12",
"source": { "source": {
"type": "git", "type": "git",
"url": "git@gitlab.com:php-extended/polyfill-php80-stringable.git", "url": "https://gitlab.com/php-extended/polyfill-php80-stringable.git",
"reference": "a6199e7ea09ddafaae9c22d6bd297aa4704b6608" "reference": "ea728554a1d83c75ebb7eec69689fdb6c067b5e4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://gitlab.com/api/v4/projects/php-extended%2Fpolyfill-php80-stringable/repository/archive.zip?sha=a6199e7ea09ddafaae9c22d6bd297aa4704b6608", "url": "https://gitlab.com/api/v4/projects/php-extended%2Fpolyfill-php80-stringable/repository/archive.zip?sha=ea728554a1d83c75ebb7eec69689fdb6c067b5e4",
"reference": "a6199e7ea09ddafaae9c22d6bd297aa4704b6608", "reference": "ea728554a1d83c75ebb7eec69689fdb6c067b5e4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2126,7 +2155,7 @@
"issues": "https://gitlab.com/php-extended/polyfill-php80-stringable/issues", "issues": "https://gitlab.com/php-extended/polyfill-php80-stringable/issues",
"source": "https://gitlab.com/php-extended/polyfill-php80-stringable" "source": "https://gitlab.com/php-extended/polyfill-php80-stringable"
}, },
"time": "2022-12-07T22:15:21+00:00" "time": "2024-03-31T13:21:37+00:00"
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
@@ -2183,28 +2212,35 @@
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "5.3.0", "version": "5.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170" "reference": "298d2febfe79d03fe714eb871d5538da55205b1a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/298d2febfe79d03fe714eb871d5538da55205b1a",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "reference": "298d2febfe79d03fe714eb871d5538da55205b1a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/deprecations": "^1.1",
"ext-filter": "*", "ext-filter": "*",
"php": "^7.2 || ^8.0", "php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.2", "phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.3", "phpdocumentor/type-resolver": "^1.7",
"phpstan/phpdoc-parser": "^1.7",
"webmozart/assert": "^1.9.1" "webmozart/assert": "^1.9.1"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "~1.3.2", "mockery/mockery": "~1.3.5",
"psalm/phar": "^4.8" "phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^5.13"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -2228,36 +2264,39 @@
}, },
{ {
"name": "Jaap van Otterdijk", "name": "Jaap van Otterdijk",
"email": "account@ijaap.nl" "email": "opensource@ijaap.nl"
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.0"
}, },
"time": "2021-10-19T17:43:47+00:00" "time": "2024-04-09T21:13:58+00:00"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
"version": "1.6.2", "version": "1.8.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git", "url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" "reference": "153ae662783729388a584b4361f2545e4d841e3c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", "reference": "153ae662783729388a584b4361f2545e4d841e3c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.4 || ^8.0", "doctrine/deprecations": "^1.0",
"phpdocumentor/reflection-common": "^2.0" "php": "^7.3 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
}, },
"require-dev": { "require-dev": {
"ext-tokenizer": "*", "ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1", "phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8", "phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-phpunit": "^1.1",
@@ -2289,9 +2328,104 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues", "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2"
}, },
"time": "2022-10-14T12:47:21+00:00" "time": "2024-02-23T11:10:43+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.29.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc",
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
"nikic/php-parser": "^4.15",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0"
},
"time": "2024-05-06T12:04:23+00:00"
},
{
"name": "psr/clock",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/clock.git",
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Psr\\Clock\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for reading the clock.",
"homepage": "https://github.com/php-fig/clock",
"keywords": [
"clock",
"now",
"psr",
"psr-20",
"time"
],
"support": {
"issues": "https://github.com/php-fig/clock/issues",
"source": "https://github.com/php-fig/clock/tree/1.0.0"
},
"time": "2022-11-25T14:36:26+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@@ -2348,25 +2482,25 @@
}, },
{ {
"name": "psr/http-message", "name": "psr/http-message",
"version": "1.0.1", "version": "1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-fig/http-message.git", "url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "php": "^7.2 || ^8.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "1.0.x-dev" "dev-master": "1.1.x-dev"
} }
}, },
"autoload": { "autoload": {
@@ -2395,9 +2529,9 @@
"response" "response"
], ],
"support": { "support": {
"source": "https://github.com/php-fig/http-message/tree/master" "source": "https://github.com/php-fig/http-message/tree/1.1"
}, },
"time": "2016-08-06T14:39:51+00:00" "time": "2023-04-04T09:50:52+00:00"
}, },
{ {
"name": "psr/log", "name": "psr/log",
@@ -2568,16 +2702,16 @@
}, },
{ {
"name": "sergeytsalkov/meekrodb", "name": "sergeytsalkov/meekrodb",
"version": "v2.4", "version": "v2.5.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/SergeyTsalkov/meekrodb.git", "url": "https://github.com/SergeyTsalkov/meekrodb.git",
"reference": "e30c240d54bc81f58c58507a9ed768032eb494a5" "reference": "08b683a274365983aaf033cf9c589dcbe5190028"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/e30c240d54bc81f58c58507a9ed768032eb494a5", "url": "https://api.github.com/repos/SergeyTsalkov/meekrodb/zipball/08b683a274365983aaf033cf9c589dcbe5190028",
"reference": "e30c240d54bc81f58c58507a9ed768032eb494a5", "reference": "08b683a274365983aaf033cf9c589dcbe5190028",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2610,55 +2744,52 @@
"support": { "support": {
"email": "support@meekro.com", "email": "support@meekro.com",
"issues": "https://github.com/SergeyTsalkov/meekrodb/issues", "issues": "https://github.com/SergeyTsalkov/meekrodb/issues",
"source": "https://github.com/SergeyTsalkov/meekrodb/tree/v2.4" "source": "https://github.com/SergeyTsalkov/meekrodb/tree/v2.5.1"
}, },
"time": "2021-06-29T04:31:23+00:00" "time": "2023-10-10T00:28:49+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.2.7", "version": "v7.0.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45" "reference": "c981e0e9380ce9f146416bde3150c79197ce9986"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/cbad09eb8925b6ad4fb721c7a179344dc4a19d45", "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986",
"reference": "cbad09eb8925b6ad4fb721c7a179344dc4a19d45", "reference": "c981e0e9380ce9f146416bde3150c79197ce9986",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.2",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^1.1|^2|^3", "symfony/service-contracts": "^2.5|^3",
"symfony/string": "^5.4|^6.0" "symfony/string": "^6.4|^7.0"
}, },
"conflict": { "conflict": {
"symfony/dependency-injection": "<5.4", "symfony/dependency-injection": "<6.4",
"symfony/dotenv": "<5.4", "symfony/dotenv": "<6.4",
"symfony/event-dispatcher": "<5.4", "symfony/event-dispatcher": "<6.4",
"symfony/lock": "<5.4", "symfony/lock": "<6.4",
"symfony/process": "<5.4" "symfony/process": "<6.4"
}, },
"provide": { "provide": {
"psr/log-implementation": "1.0|2.0|3.0" "psr/log-implementation": "1.0|2.0|3.0"
}, },
"require-dev": { "require-dev": {
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0", "symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^5.4|^6.0", "symfony/dependency-injection": "^6.4|^7.0",
"symfony/event-dispatcher": "^5.4|^6.0", "symfony/event-dispatcher": "^6.4|^7.0",
"symfony/lock": "^5.4|^6.0", "symfony/http-foundation": "^6.4|^7.0",
"symfony/process": "^5.4|^6.0", "symfony/http-kernel": "^6.4|^7.0",
"symfony/var-dumper": "^5.4|^6.0" "symfony/lock": "^6.4|^7.0",
}, "symfony/messenger": "^6.4|^7.0",
"suggest": { "symfony/process": "^6.4|^7.0",
"psr/log": "For using the console logger", "symfony/stopwatch": "^6.4|^7.0",
"symfony/event-dispatcher": "", "symfony/var-dumper": "^6.4|^7.0"
"symfony/lock": "",
"symfony/process": ""
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -2687,12 +2818,12 @@
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"keywords": [ "keywords": [
"cli", "cli",
"command line", "command-line",
"console", "console",
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.2.7" "source": "https://github.com/symfony/console/tree/v7.0.7"
}, },
"funding": [ "funding": [
{ {
@@ -2708,20 +2839,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-25T17:00:03+00:00" "time": "2024-04-18T09:29:19+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
"version": "v3.2.1", "version": "v3.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git", "url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "0121954c80fd17c18cf050fe73360e63bb43d4fb" "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0121954c80fd17c18cf050fe73360e63bb43d4fb", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"reference": "0121954c80fd17c18cf050fe73360e63bb43d4fb", "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2730,7 +2861,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "3.3-dev" "dev-main": "3.5-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@@ -2759,7 +2890,7 @@
"description": "A generic function and convention to trigger deprecation notices", "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
}, },
"funding": [ "funding": [
{ {
@@ -2775,33 +2906,34 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-02T07:48:03+00:00" "time": "2024-04-18T09:32:20+00:00"
}, },
{ {
"name": "symfony/lock", "name": "symfony/lock",
"version": "v6.2.7", "version": "v6.4.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/lock.git", "url": "https://github.com/symfony/lock.git",
"reference": "febdeed9473e568ff34bf4350c04760f5357dfe2" "reference": "c6b3959c418a7c1115c060fab77927ca4bd2546a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/lock/zipball/febdeed9473e568ff34bf4350c04760f5357dfe2", "url": "https://api.github.com/repos/symfony/lock/zipball/c6b3959c418a7c1115c060fab77927ca4bd2546a",
"reference": "febdeed9473e568ff34bf4350c04760f5357dfe2", "reference": "c6b3959c418a7c1115c060fab77927ca4bd2546a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"psr/log": "^1|^2|^3" "psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3"
}, },
"conflict": { "conflict": {
"doctrine/dbal": "<2.13", "doctrine/dbal": "<2.13",
"symfony/cache": "<6.2" "symfony/cache": "<6.2"
}, },
"require-dev": { "require-dev": {
"doctrine/dbal": "^2.13|^3.0", "doctrine/dbal": "^2.13|^3|^4",
"predis/predis": "~1.0" "predis/predis": "^1.1|^2.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -2837,7 +2969,7 @@
"semaphore" "semaphore"
], ],
"support": { "support": {
"source": "https://github.com/symfony/lock/tree/v6.2.7" "source": "https://github.com/symfony/lock/tree/v6.4.7"
}, },
"funding": [ "funding": [
{ {
@@ -2853,20 +2985,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-24T10:42:00+00:00" "time": "2024-04-18T09:22:46+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.27.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a" "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2880,9 +3012,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@@ -2919,7 +3048,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@@ -2935,20 +3064,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-grapheme", "name": "symfony/polyfill-intl-grapheme",
"version": "v1.27.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354" "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354", "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2959,9 +3088,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@@ -3000,7 +3126,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@@ -3016,20 +3142,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.27.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3040,9 +3166,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@@ -3084,7 +3207,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@@ -3100,20 +3223,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.27.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3127,9 +3250,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@@ -3167,7 +3287,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@@ -3183,20 +3303,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.27.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3204,9 +3324,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.27-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@@ -3250,7 +3367,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@@ -3266,36 +3383,34 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-11-03T14:55:06+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v3.2.1", "version": "v3.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "aee5f59db63978f7785290b94d2f12286b1b590a" "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/aee5f59db63978f7785290b94d2f12286b1b590a", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"reference": "aee5f59db63978f7785290b94d2f12286b1b590a", "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"psr/container": "^2.0" "psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
}, },
"conflict": { "conflict": {
"ext-psr": "<1.1|>=2" "ext-psr": "<1.1|>=2"
}, },
"suggest": {
"symfony/service-implementation": ""
},
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "3.3-dev" "dev-main": "3.5-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@@ -3335,7 +3450,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.2.1" "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
}, },
"funding": [ "funding": [
{ {
@@ -3351,38 +3466,38 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-16T12:50:33+00:00" "time": "2024-04-18T09:32:20+00:00"
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v6.2.7", "version": "v7.0.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "67b8c1eec78296b85dc1c7d9743830160218993d" "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/67b8c1eec78296b85dc1c7d9743830160218993d", "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63",
"reference": "67b8c1eec78296b85dc1c7d9743830160218993d", "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.2",
"symfony/polyfill-ctype": "~1.8", "symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0" "symfony/polyfill-mbstring": "~1.0"
}, },
"conflict": { "conflict": {
"symfony/translation-contracts": "<2.0" "symfony/translation-contracts": "<2.5"
}, },
"require-dev": { "require-dev": {
"symfony/error-handler": "^5.4|^6.0", "symfony/error-handler": "^6.4|^7.0",
"symfony/http-client": "^5.4|^6.0", "symfony/http-client": "^6.4|^7.0",
"symfony/intl": "^6.2", "symfony/intl": "^6.4|^7.0",
"symfony/translation-contracts": "^2.0|^3.0", "symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^5.4|^6.0" "symfony/var-exporter": "^6.4|^7.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -3421,7 +3536,7 @@
"utf8" "utf8"
], ],
"support": { "support": {
"source": "https://github.com/symfony/string/tree/v6.2.7" "source": "https://github.com/symfony/string/tree/v7.0.7"
}, },
"funding": [ "funding": [
{ {
@@ -3437,32 +3552,35 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-24T10:42:00+00:00" "time": "2024-04-18T09:29:19+00:00"
}, },
{ {
"name": "symfony/translation", "name": "symfony/translation",
"version": "v6.2.7", "version": "v6.4.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation.git", "url": "https://github.com/symfony/translation.git",
"reference": "90db1c6138c90527917671cd9ffa9e8b359e3a73" "reference": "7495687c58bfd88b7883823747b0656d90679123"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/90db1c6138c90527917671cd9ffa9e8b359e3a73", "url": "https://api.github.com/repos/symfony/translation/zipball/7495687c58bfd88b7883823747b0656d90679123",
"reference": "90db1c6138c90527917671cd9ffa9e8b359e3a73", "reference": "7495687c58bfd88b7883823747b0656d90679123",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2.3|^3.0" "symfony/translation-contracts": "^2.5|^3.0"
}, },
"conflict": { "conflict": {
"symfony/config": "<5.4", "symfony/config": "<5.4",
"symfony/console": "<5.4", "symfony/console": "<5.4",
"symfony/dependency-injection": "<5.4", "symfony/dependency-injection": "<5.4",
"symfony/http-client-contracts": "<2.5",
"symfony/http-kernel": "<5.4", "symfony/http-kernel": "<5.4",
"symfony/service-contracts": "<2.5",
"symfony/twig-bundle": "<5.4", "symfony/twig-bundle": "<5.4",
"symfony/yaml": "<5.4" "symfony/yaml": "<5.4"
}, },
@@ -3470,25 +3588,19 @@
"symfony/translation-implementation": "2.3|3.0" "symfony/translation-implementation": "2.3|3.0"
}, },
"require-dev": { "require-dev": {
"nikic/php-parser": "^4.13", "nikic/php-parser": "^4.18|^5.0",
"psr/log": "^1|^2|^3", "psr/log": "^1|^2|^3",
"symfony/config": "^5.4|^6.0", "symfony/config": "^5.4|^6.0|^7.0",
"symfony/console": "^5.4|^6.0", "symfony/console": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/finder": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0|^7.0",
"symfony/http-client-contracts": "^1.1|^2.0|^3.0", "symfony/http-client-contracts": "^2.5|^3.0",
"symfony/http-kernel": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/intl": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0|^7.0",
"symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-intl-icu": "^1.21",
"symfony/routing": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0|^7.0",
"symfony/service-contracts": "^1.1.2|^2|^3", "symfony/service-contracts": "^2.5|^3",
"symfony/yaml": "^5.4|^6.0" "symfony/yaml": "^5.4|^6.0|^7.0"
},
"suggest": {
"nikic/php-parser": "To use PhpAstExtractor",
"psr/log-implementation": "To use logging capability in translator",
"symfony/config": "",
"symfony/yaml": ""
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -3519,7 +3631,7 @@
"description": "Provides tools to internationalize your application", "description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/translation/tree/v6.2.7" "source": "https://github.com/symfony/translation/tree/v6.4.7"
}, },
"funding": [ "funding": [
{ {
@@ -3535,32 +3647,29 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-24T10:42:00+00:00" "time": "2024-04-18T09:22:46+00:00"
}, },
{ {
"name": "symfony/translation-contracts", "name": "symfony/translation-contracts",
"version": "v3.2.1", "version": "v3.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation-contracts.git", "url": "https://github.com/symfony/translation-contracts.git",
"reference": "1f40e77fbb12a16d841688f42fecefd8ceb43ed6" "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/1f40e77fbb12a16d841688f42fecefd8ceb43ed6", "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
"reference": "1f40e77fbb12a16d841688f42fecefd8ceb43ed6", "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1" "php": ">=8.1"
}, },
"suggest": {
"symfony/translation-implementation": ""
},
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "3.3-dev" "dev-main": "3.5-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@@ -3600,7 +3709,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.2.1" "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
}, },
"funding": [ "funding": [
{ {
@@ -3616,7 +3725,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-16T12:50:33+00:00" "time": "2024-04-18T09:32:20+00:00"
}, },
{ {
"name": "tysonandre/var_representation_polyfill", "name": "tysonandre/var_representation_polyfill",
@@ -3930,16 +4039,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.11.0", "version": "1.11.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3977,7 +4086,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/myclabs/DeepCopy/issues", "issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
}, },
"funding": [ "funding": [
{ {
@@ -3985,29 +4094,31 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-03-03T13:19:32+00:00" "time": "2023-03-08T13:26:56+00:00"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",
"version": "v4.15.3", "version": "v5.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nikic/PHP-Parser.git", "url": "https://github.com/nikic/PHP-Parser.git",
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-ctype": "*",
"ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": ">=7.0" "php": ">=7.4"
}, },
"require-dev": { "require-dev": {
"ircmaxell/php-yacc": "^0.0.7", "ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
}, },
"bin": [ "bin": [
"bin/php-parse" "bin/php-parse"
@@ -4015,7 +4126,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "4.9-dev" "dev-master": "5.0-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4039,26 +4150,27 @@
], ],
"support": { "support": {
"issues": "https://github.com/nikic/PHP-Parser/issues", "issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
}, },
"time": "2023-01-16T22:05:37+00:00" "time": "2024-03-05T20:51:40+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
"version": "2.0.3", "version": "2.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phar-io/manifest.git", "url": "https://github.com/phar-io/manifest.git",
"reference": "97803eca37d319dfa7826cc2437fc020857acb53" "reference": "54750ef60c58e43759730615a392c31c80e23176"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
"reference": "97803eca37d319dfa7826cc2437fc020857acb53", "reference": "54750ef60c58e43759730615a392c31c80e23176",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-libxml": "*",
"ext-phar": "*", "ext-phar": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"phar-io/version": "^3.0.1", "phar-io/version": "^3.0.1",
@@ -4099,9 +4211,15 @@
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": { "support": {
"issues": "https://github.com/phar-io/manifest/issues", "issues": "https://github.com/phar-io/manifest/issues",
"source": "https://github.com/phar-io/manifest/tree/2.0.3" "source": "https://github.com/phar-io/manifest/tree/2.0.4"
}, },
"time": "2021-07-20T11:28:43+00:00" "funding": [
{
"url": "https://github.com/theseer",
"type": "github"
}
],
"time": "2024-03-03T12:33:53+00:00"
}, },
{ {
"name": "phar-io/version", "name": "phar-io/version",
@@ -4156,23 +4274,23 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "10.0.1", "version": "10.1.14",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "b9c21a93dd8c8eed79879374884ee733259475cc" "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b9c21a93dd8c8eed79879374884ee733259475cc", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"reference": "b9c21a93dd8c8eed79879374884ee733259475cc", "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-libxml": "*", "ext-libxml": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"nikic/php-parser": "^4.15", "nikic/php-parser": "^4.18 || ^5.0",
"php": ">=8.1", "php": ">=8.1",
"phpunit/php-file-iterator": "^4.0", "phpunit/php-file-iterator": "^4.0",
"phpunit/php-text-template": "^3.0", "phpunit/php-text-template": "^3.0",
@@ -4184,16 +4302,16 @@
"theseer/tokenizer": "^1.2.0" "theseer/tokenizer": "^1.2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.0" "phpunit/phpunit": "^10.1"
}, },
"suggest": { "suggest": {
"ext-pcov": "*", "ext-pcov": "PHP extension that provides line coverage",
"ext-xdebug": "*" "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "10.0-dev" "dev-main": "10.1-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4221,7 +4339,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.0.1" "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
}, },
"funding": [ "funding": [
{ {
@@ -4229,20 +4348,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-25T05:35:03+00:00" "time": "2024-03-12T15:33:41+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
"version": "4.0.1", "version": "4.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "fd9329ab3368f59fe1fe808a189c51086bd4b6bd" "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/fd9329ab3368f59fe1fe808a189c51086bd4b6bd", "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
"reference": "fd9329ab3368f59fe1fe808a189c51086bd4b6bd", "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4281,7 +4400,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.0.1" "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
}, },
"funding": [ "funding": [
{ {
@@ -4289,7 +4409,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-10T16:53:14+00:00" "time": "2023-08-31T06:24:48+00:00"
}, },
{ {
"name": "phpunit/php-invoker", "name": "phpunit/php-invoker",
@@ -4356,16 +4476,16 @@
}, },
{ {
"name": "phpunit/php-text-template", "name": "phpunit/php-text-template",
"version": "3.0.0", "version": "3.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git", "url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d" "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/9f3d3709577a527025f55bcf0f7ab8052c8bb37d", "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d", "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4403,7 +4523,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues", "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.0" "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -4411,7 +4532,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T06:56:46+00:00" "time": "2023-08-31T14:07:24+00:00"
}, },
{ {
"name": "phpunit/php-timer", "name": "phpunit/php-timer",
@@ -4474,16 +4595,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.0.13", "version": "10.5.20",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c37a88d7a905266eab6498817a1bf1170043313f" "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c37a88d7a905266eab6498817a1bf1170043313f", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/547d314dc24ec1e177720d45c6263fb226cc2ae3",
"reference": "c37a88d7a905266eab6498817a1bf1170043313f", "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4497,7 +4618,7 @@
"phar-io/manifest": "^2.0.3", "phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2", "phar-io/version": "^3.0.2",
"php": ">=8.1", "php": ">=8.1",
"phpunit/php-code-coverage": "^10.0", "phpunit/php-code-coverage": "^10.1.5",
"phpunit/php-file-iterator": "^4.0", "phpunit/php-file-iterator": "^4.0",
"phpunit/php-invoker": "^4.0", "phpunit/php-invoker": "^4.0",
"phpunit/php-text-template": "^3.0", "phpunit/php-text-template": "^3.0",
@@ -4507,15 +4628,15 @@
"sebastian/comparator": "^5.0", "sebastian/comparator": "^5.0",
"sebastian/diff": "^5.0", "sebastian/diff": "^5.0",
"sebastian/environment": "^6.0", "sebastian/environment": "^6.0",
"sebastian/exporter": "^5.0", "sebastian/exporter": "^5.1",
"sebastian/global-state": "^6.0", "sebastian/global-state": "^6.0.1",
"sebastian/object-enumerator": "^5.0", "sebastian/object-enumerator": "^5.0",
"sebastian/recursion-context": "^5.0", "sebastian/recursion-context": "^5.0",
"sebastian/type": "^4.0", "sebastian/type": "^4.0",
"sebastian/version": "^4.0" "sebastian/version": "^4.0"
}, },
"suggest": { "suggest": {
"ext-soap": "*" "ext-soap": "To be able to generate mocks based on WSDL files"
}, },
"bin": [ "bin": [
"phpunit" "phpunit"
@@ -4523,7 +4644,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "10.0-dev" "dev-main": "10.5-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4554,7 +4675,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.13" "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.20"
}, },
"funding": [ "funding": [
{ {
@@ -4570,20 +4692,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-27T13:07:57+00:00" "time": "2024-04-24T06:32:35+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
"version": "2.0.0", "version": "2.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git", "url": "https://github.com/sebastianbergmann/cli-parser.git",
"reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae" "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae", "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084",
"reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae", "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4618,7 +4740,8 @@
"homepage": "https://github.com/sebastianbergmann/cli-parser", "homepage": "https://github.com/sebastianbergmann/cli-parser",
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues", "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
"source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0" "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
"source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -4626,7 +4749,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T06:58:15+00:00" "time": "2024-03-02T07:12:49+00:00"
}, },
{ {
"name": "sebastian/code-unit", "name": "sebastian/code-unit",
@@ -4741,16 +4864,16 @@
}, },
{ {
"name": "sebastian/comparator", "name": "sebastian/comparator",
"version": "5.0.0", "version": "5.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git", "url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c" "reference": "2db5010a484d53ebf536087a70b4a5423c102372"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/72f01e6586e0caf6af81297897bd112eb7e9627c", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c", "reference": "2db5010a484d53ebf536087a70b4a5423c102372",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4761,7 +4884,7 @@
"sebastian/exporter": "^5.0" "sebastian/exporter": "^5.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.0" "phpunit/phpunit": "^10.3"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -4805,7 +4928,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues", "issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.0" "security": "https://github.com/sebastianbergmann/comparator/security/policy",
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
}, },
"funding": [ "funding": [
{ {
@@ -4813,24 +4937,24 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:07:16+00:00" "time": "2023-08-14T13:18:12+00:00"
}, },
{ {
"name": "sebastian/complexity", "name": "sebastian/complexity",
"version": "3.0.0", "version": "3.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git", "url": "https://github.com/sebastianbergmann/complexity.git",
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6" "reference": "68ff824baeae169ec9f2137158ee529584553799"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/e67d240970c9dc7ea7b2123a6d520e334dd61dc6", "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6", "reference": "68ff824baeae169ec9f2137158ee529584553799",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"nikic/php-parser": "^4.10", "nikic/php-parser": "^4.18 || ^5.0",
"php": ">=8.1" "php": ">=8.1"
}, },
"require-dev": { "require-dev": {
@@ -4839,7 +4963,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "3.0-dev" "dev-main": "3.2-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4862,7 +4986,8 @@
"homepage": "https://github.com/sebastianbergmann/complexity", "homepage": "https://github.com/sebastianbergmann/complexity",
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues", "issues": "https://github.com/sebastianbergmann/complexity/issues",
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.0" "security": "https://github.com/sebastianbergmann/complexity/security/policy",
"source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
}, },
"funding": [ "funding": [
{ {
@@ -4870,20 +4995,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T06:59:47+00:00" "time": "2023-12-21T08:37:17+00:00"
}, },
{ {
"name": "sebastian/diff", "name": "sebastian/diff",
"version": "5.0.0", "version": "5.1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/diff.git", "url": "https://github.com/sebastianbergmann/diff.git",
"reference": "70dd1b20bc198da394ad542e988381b44e64e39f" "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/70dd1b20bc198da394ad542e988381b44e64e39f", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e",
"reference": "70dd1b20bc198da394ad542e988381b44e64e39f", "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4891,12 +5016,12 @@
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^10.0", "phpunit/phpunit": "^10.0",
"symfony/process": "^4.2 || ^5" "symfony/process": "^6.4"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "5.0-dev" "dev-main": "5.1-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4928,7 +5053,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/diff/issues", "issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/5.0.0" "security": "https://github.com/sebastianbergmann/diff/security/policy",
"source": "https://github.com/sebastianbergmann/diff/tree/5.1.1"
}, },
"funding": [ "funding": [
{ {
@@ -4936,20 +5062,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:00:31+00:00" "time": "2024-03-02T07:15:17+00:00"
}, },
{ {
"name": "sebastian/environment", "name": "sebastian/environment",
"version": "6.0.0", "version": "6.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/environment.git", "url": "https://github.com/sebastianbergmann/environment.git",
"reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc" "reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/b6f3694c6386c7959915a0037652e0c40f6f69cc", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
"reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc", "reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4964,7 +5090,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "6.0-dev" "dev-main": "6.1-dev"
} }
}, },
"autoload": { "autoload": {
@@ -4991,7 +5117,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/environment/issues", "issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/6.0.0" "security": "https://github.com/sebastianbergmann/environment/security/policy",
"source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
}, },
"funding": [ "funding": [
{ {
@@ -4999,20 +5126,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:03:04+00:00" "time": "2024-03-23T08:47:14+00:00"
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",
"version": "5.0.0", "version": "5.1.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git", "url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0" "reference": "955288482d97c19a372d3f31006ab3f37da47adf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf",
"reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0", "reference": "955288482d97c19a372d3f31006ab3f37da47adf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5026,7 +5153,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "5.0-dev" "dev-main": "5.1-dev"
} }
}, },
"autoload": { "autoload": {
@@ -5068,7 +5195,8 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues", "issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/5.0.0" "security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2"
}, },
"funding": [ "funding": [
{ {
@@ -5076,20 +5204,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:06:49+00:00" "time": "2024-03-02T07:17:12+00:00"
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
"version": "6.0.0", "version": "6.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git", "url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "aab257c712de87b90194febd52e4d184551c2d44" "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/aab257c712de87b90194febd52e4d184551c2d44", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
"reference": "aab257c712de87b90194febd52e4d184551c2d44", "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5123,13 +5251,14 @@
} }
], ],
"description": "Snapshotting of global state", "description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state", "homepage": "https://www.github.com/sebastianbergmann/global-state",
"keywords": [ "keywords": [
"global state" "global state"
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues", "issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.0" "security": "https://github.com/sebastianbergmann/global-state/security/policy",
"source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2"
}, },
"funding": [ "funding": [
{ {
@@ -5137,24 +5266,24 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:07:38+00:00" "time": "2024-03-02T07:19:19+00:00"
}, },
{ {
"name": "sebastian/lines-of-code", "name": "sebastian/lines-of-code",
"version": "2.0.0", "version": "2.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git", "url": "https://github.com/sebastianbergmann/lines-of-code.git",
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130" "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/17c4d940ecafb3d15d2cf916f4108f664e28b130", "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130", "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"nikic/php-parser": "^4.10", "nikic/php-parser": "^4.18 || ^5.0",
"php": ">=8.1" "php": ">=8.1"
}, },
"require-dev": { "require-dev": {
@@ -5186,7 +5315,8 @@
"homepage": "https://github.com/sebastianbergmann/lines-of-code", "homepage": "https://github.com/sebastianbergmann/lines-of-code",
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.0" "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
}, },
"funding": [ "funding": [
{ {
@@ -5194,7 +5324,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-02-03T07:08:02+00:00" "time": "2023-12-21T08:38:20+00:00"
}, },
{ {
"name": "sebastian/object-enumerator", "name": "sebastian/object-enumerator",
@@ -5482,16 +5612,16 @@
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.1", "version": "1.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/theseer/tokenizer.git", "url": "https://github.com/theseer/tokenizer.git",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5520,7 +5650,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": { "support": {
"issues": "https://github.com/theseer/tokenizer/issues", "issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.1" "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
}, },
"funding": [ "funding": [
{ {
@@ -5528,7 +5658,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-07-28T10:34:58+00:00" "time": "2024-03-03T12:36:25+00:00"
} }
], ],
"aliases": [], "aliases": [],
@@ -5539,7 +5669,7 @@
"platform": [], "platform": [],
"platform-dev": [], "platform-dev": [],
"platform-overrides": { "platform-overrides": {
"php": "8.2" "php": "8.3"
}, },
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }
BIN
View File
Binary file not shown.
+4 -1
View File
@@ -99,7 +99,10 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
$err = str_replace(ROOT, '{ROOT}', $err); $err = str_replace(ROOT, '{ROOT}', $err);
$errstr = str_replace(ROOT, '{ROOT}', $errstr); $errstr = str_replace(ROOT, '{ROOT}', $errstr);
$errpath = str_replace(ROOT, '{ROOT}', $errpath); $errpath = str_replace(ROOT, '{ROOT}', $errpath);
$trace = array_map(function (string $text) { $trace = array_map(function (string|array $text) {
if (is_array($text)) {
$text = Json::encode($text);
}
return str_replace(ROOT, '{ROOT}', $text); return str_replace(ROOT, '{ROOT}', $text);
}, $trace); }, $trace);
+1 -1
View File
@@ -56,7 +56,7 @@ $rootDB->insert('member', [
'token_valid_until' => '2999-01-01 00:00:00', 'token_valid_until' => '2999-01-01 00:00:00',
'pw' => $finalPassword, 'pw' => $finalPassword,
'salt' => $userSalt, 'salt' => $userSalt,
'grade' => 6, 'grade' => 7,
'name' => $nickname, 'name' => $nickname,
'reg_date' => $nowDate 'reg_date' => $nowDate
]); ]);
+2 -9
View File
@@ -17,18 +17,11 @@ if (!class_exists('\\sammo\\RootDB')) {
$rootDB = RootDB::db(); $rootDB = RootDB::db();
$rootDB->throw_exception_on_nonsql_error = false; $rootDB->addHook('run_failed', function ($params) {
$rootDB->nonsql_error_handler = function ($params) {
Json::die([
'step' => 'conn_fail'
]);
};
$rootDB->error_handler = function ($params) {
Json::die([ Json::die([
'step' => 'sql_fail' 'step' => 'sql_fail'
]); ]);
}; });
$memberCnt = $rootDB->queryFirstField('SELECT count(`NO`) from member'); $memberCnt = $rootDB->queryFirstField('SELECT count(`NO`) from member');
if ($memberCnt == 0) { if ($memberCnt == 0) {
+3 -11
View File
@@ -150,20 +150,12 @@ if (!file_exists(ROOT . '/d_setting/.htaccess')) {
$rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4'); $rootDB = new \MeekroDB($host, $username, $password, $dbName, $port, 'utf8mb4');
$rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true; $rootDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$rootDB->throw_exception_on_nonsql_error = false; $rootDB->addHook('run_failed', function ($args) {
$rootDB->nonsql_error_handler = function ($params) {
Json::die([ Json::die([
'result' => false, 'result' => false,
'reason' => 'DB 접속에 실패했습니다.' 'reason' => '에러.'. $args['error']
]); ]);
}; });
$rootDB->error_handler = function ($params) {
Json::die([
'result' => false,
'reason' => 'SQL을 제대로 실행하지 못했습니다. DB상태를 확인해 주세요.'
]);
};
$mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨. $mysqli_obj = $rootDB->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
+11 -1
View File
@@ -92,4 +92,14 @@ CREATE TABLE `login_token` (
INDEX `by_date` (`user_id`, `expire_date`) INDEX `by_date` (`user_id`, `expire_date`)
) )
COLLATE='utf8mb4_general_ci' COLLATE='utf8mb4_general_ci'
ENGINE=Aria; ENGINE=Aria;
CREATE TABLE `banned_member` (
`no` INT NOT NULL AUTO_INCREMENT,
`hashed_email` VARCHAR(128) NOT NULL COLLATE 'utf8mb4_general_ci' COMMENT 'SHA512(salt | email | salt )',
`info` TEXT NULL COLLATE 'utf8mb4_general_ci' COMMENT '부가정보',
PRIMARY KEY (`no`),
UNIQUE INDEX `email` (`hashed_email`(128))
)
COLLATE='utf8mb4_general_ci'
ENGINE = Aria;
+1 -1
View File
@@ -6,7 +6,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if($session->userGrade < 5) { if($session->userGrade < 6) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+1 -1
View File
@@ -6,7 +6,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
header('location:_admin1.php'); header('location:_admin1.php');
die(); die();
} }
+1 -1
View File
@@ -7,7 +7,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+2 -2
View File
@@ -15,7 +15,7 @@ $msg = Util::getPost('msg', 'string');
//로그인 검사 //로그인 검사
$session = Session::requireLogin()->loginGame()->setReadOnly(); $session = Session::requireLogin()->loginGame()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
header('location:_admin2.php'); header('location:_admin2.php');
} }
@@ -33,7 +33,7 @@ $src = MessageTarget::buildQuick($session->generalID);
$genObjList = []; $genObjList = [];
$env = []; $env = [];
if ($genlist) { if ($genlist) {
$genObjList = General::createGeneralObjListFromDB($genlist); $genObjList = General::createObjListFromDB($genlist);
$env = $gameStor->cacheAll(); $env = $gameStor->cacheAll();
} }
switch ($btn) { switch ($btn) {
+1 -1
View File
@@ -20,7 +20,7 @@ if ($type2 < 0 || $type2 > 6) {
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+1 -1
View File
@@ -12,7 +12,7 @@ $nation = Util::getPost('nation', 'int');
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID(); $userID = Session::getUserID();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
header('location:_admin5.php'); header('location:_admin5.php');
die(); die();
} }
+3 -3
View File
@@ -31,13 +31,13 @@ $queryMap = [
]; ];
if ($reqQueryType === null || !key_exists($reqQueryType, $queryMap)) { if ($reqQueryType === null || !key_exists($reqQueryType, $queryMap)) {
$reqQueryType = Util::array_first_key($queryMap); $reqQueryType = array_key_first($queryMap);
} }
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
@@ -76,7 +76,7 @@ if (!$gen) {
$gen = $generalBasicList[0]['no']; $gen = $generalBasicList[0]['no'];
} }
$generalObj = General::createGeneralObjFromDB($gen, null, GeneralQueryMode::FullWithAccessLog); $generalObj = General::createObjFromDB($gen, null, GeneralQueryMode::FullWithAccessLog);
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
+1 -1
View File
@@ -12,7 +12,7 @@ $type = 0;
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die(requireAdminPermissionHTML()); die(requireAdminPermissionHTML());
} }
+2 -2
View File
@@ -7,7 +7,7 @@ include "func.php";
//로그인 검사 //로그인 검사
$session = Session::requireGameLogin()->setReadOnly(); $session = Session::requireGameLogin()->setReadOnly();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die('권한 부족'); die('권한 부족');
} }
@@ -26,7 +26,7 @@ foreach ($db->queryFirstColumn(
} }
$inheritPointManager = InheritancePointManager::getInstance(); $inheritPointManager = InheritancePointManager::getInstance();
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){ foreach(General::createObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
$inheritPointManager->mergeTotalInheritancePoint($genObj); $inheritPointManager->mergeTotalInheritancePoint($genObj);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner')); $inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
} }
+5 -2
View File
@@ -243,11 +243,14 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
"SELECT nation,no,name,owner_name as ownerName, owner, picture, imgsvr, "SELECT nation,no,name,owner_name as ownerName, owner, picture, imgsvr,
experience, dedication, experience, dedication,
dex1, dex2, dex3, dex4, dex5, dex1, dex2, dex3, dex4, dex5,
horse, weapon, book, item horse, weapon, book, item, aux
FROM general WHERE %l", FROM general WHERE %l",
$btn == "NPC 보기" ? "npc>=2" : "npc<2" $btn == "NPC 보기" ? "npc>=2" : "npc<2"
) as $general) { ) as $general) {
$generalID = $general['no']; $generalID = $general['no'];
foreach (['dex1', 'dex2', 'dex3', 'dex4', 'dex5'] as $dexKey) {
$general[$dexKey] = CentennialAllStarGrowthService::recordableRawValue($general, $dexKey);
}
$general['bgColor'] = $nationColor[$general['nation']] ?? GameConst::$basecolor4; $general['bgColor'] = $nationColor[$general['nation']] ?? GameConst::$basecolor4;
$general['fgColor'] = newColor($general['bgColor']); $general['fgColor'] = newColor($general['bgColor']);
$general['nationName'] = $nationName[$general['nation']]; $general['nationName'] = $nationName[$general['nation']];
@@ -427,4 +430,4 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
</div> </div>
</body> </body>
</html> </html>
+18 -33
View File
@@ -12,34 +12,19 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("갱신정보", 1); increaseRefresh("갱신정보", 1);
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxrefresh', 'maxonline']); $admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxrefresh', 'maxonline', 'recentTraffic']);
$log = getRawFileLogRecent(__DIR__ . '/logs/' . UniqueConst::$serverID . '/_traffic.txt', 11, 100); $recentTraffic = $admin['recentTraffic'] ?? [];
$date = [];
$year = [];
$month = [];
$refresh = [];
$online = [];
$curonline = getOnlineNum(); $curonline = getOnlineNum();
foreach ($log as $i => $value) {
$parse = Json::decode($value); $recentTraffic[] = [
if (is_array($parse) === false) { 'year' => $admin['year'],
continue; 'month' => $admin['month'],
} 'refresh' => $admin['refresh'],
if (count($parse) < 5) { 'online' => $curonline,
continue; 'date' => TimeUtil::now()
} ];
$date[$i] = $parse[0];
$year[$i] = $parse[1];
$month[$i] = $parse[2];
$refresh[$i] = $parse[3];
$online[$i] = $parse[4];
}
$year[] = $admin['year'];
$month[] = $admin['month'];
$date[] = TimeUtil::now();
if ($admin['maxrefresh'] == 0) { if ($admin['maxrefresh'] == 0) {
$admin['maxrefresh'] = 1; $admin['maxrefresh'] = 1;
@@ -113,13 +98,13 @@ if ($admin['maxonline'] < $curonline) {
</td> </td>
</tr> </tr>
<?php <?php
$refresh[] = $admin['refresh']; foreach ($recentTraffic as $trafficItem) {
foreach ($refresh as $i => $value) { $value = $trafficItem['refresh'];
$w = round($value / $admin['maxrefresh'] * 100, 1); $w = round($value / $admin['maxrefresh'] * 100, 1);
$color = getTrafficColor($w); $color = getTrafficColor($w);
$dt = substr($date[$i], 11, 5); ?> $dt = substr($trafficItem['date'], 11, 5); ?>
<tr height=30> <tr height=30>
<td width=100 align=center><?= $year[$i] ?>년 <?= $month[$i] ?>월</td> <td width=100 align=center><?= $trafficItem['year'] ?>년 <?= $trafficItem['month'] ?>월</td>
<td width=60 align=center class='bg2'><?= $dt ?></td> <td width=60 align=center class='bg2'><?= $dt ?></td>
<td width=2 align=center class='bg1'></td> <td width=2 align=center class='bg1'></td>
<td width=320> <td width=320>
@@ -154,13 +139,13 @@ if ($admin['maxonline'] < $curonline) {
</td> </td>
</tr> </tr>
<?php <?php
$online[] = $curonline; foreach ($recentTraffic as $trafficItem) {
foreach ($online as $i => $value) { $value = $trafficItem['online'];
$w = round($value / $admin['maxonline'] * 100, 1); $w = round($value / $admin['maxonline'] * 100, 1);
$color = getTrafficColor($w); $color = getTrafficColor($w);
$dt = substr($date[$i], 11, 5); ?> $dt = substr($trafficItem['date'], 11, 5); ?>
<tr height=30> <tr height=30>
<td width=100 align=center><?= $year[$i] ?>년 <?= $month[$i] ?>월</td> <td width=100 align=center><?= $trafficItem['year'] ?>년 <?= $trafficItem['month'] ?>월</td>
<td width=60 align=center class='bg2'><?= $dt ?></td> <td width=60 align=center class='bg2'><?= $dt ?></td>
<td width=2 align=center class='bg1'></td> <td width=2 align=center class='bg1'></td>
<td width=320> <td width=320>
+8 -7
View File
@@ -2,6 +2,7 @@
namespace sammo; namespace sammo;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
@@ -506,28 +507,28 @@ if ($str3) {
$tournamentType = [ $tournamentType = [
'전 력 전' => [ '전 력 전' => [
'종합', '종합',
function (General $general) { function (GeneralLite $general) {
return $general->getVar('leadership') + $general->getVar('strength') + $general->getVar('intel'); return $general->getVar('leadership') + $general->getVar('strength') + $general->getVar('intel');
}, },
'tt', 'tt',
], ],
'통 솔 전' => [ '통 솔 전' => [
'통솔', '통솔',
function (General $general) { function (GeneralLite $general) {
return $general->getVar('leadership'); return $general->getVar('leadership');
}, },
'tl', 'tl',
], ],
'일 기 토' => [ '일 기 토' => [
'무력', '무력',
function (General $general) { function (GeneralLite $general) {
return $general->getVar('strength'); return $general->getVar('strength');
}, },
'ts', 'ts',
], ],
'설 전' => [ '설 전' => [
'지력', '지력',
function (General $general) { function (GeneralLite $general) {
return $general->getVar('intel'); return $general->getVar('intel');
}, },
'ti', 'ti',
@@ -564,12 +565,12 @@ if ($str3) {
$winColumn = RankColumn::from("{$rankColumn}w"); $winColumn = RankColumn::from("{$rankColumn}w");
$drawColumn = RankColumn::from("{$rankColumn}d"); $drawColumn = RankColumn::from("{$rankColumn}d");
$loseColumn = RankColumn::from("{$rankColumn}l"); $loseColumn = RankColumn::from("{$rankColumn}l");
$tournamentRankerList = General::createGeneralObjListFromDB( $tournamentRankerList = GeneralLite::createObjListFromDB(
$db->queryFirstColumn('SELECT general_id FROM rank_data WHERE `type`= %s ORDER BY value DESC LIMIT 40', $gameColumn->value), $db->queryFirstColumn('SELECT general_id FROM rank_data WHERE `type`= %s ORDER BY value DESC LIMIT 40', $gameColumn->value),
[$prizeColumn->value, $gameColumn->value, $winColumn->value, $drawColumn->value, $loseColumn->value, 'leadership', 'strength', 'intel', 'no', 'npc', 'name'], [$prizeColumn->value, $gameColumn->value, $winColumn->value, $drawColumn->value, $loseColumn->value, 'leadership', 'strength', 'intel', 'no', 'npc', 'name'],
GeneralQueryMode::Core GeneralLiteQueryMode::Core
); );
usort($tournamentRankerList, function (General $lhs, General $rhs) use ($gameColumn, $winColumn, $drawColumn, $loseColumn) { usort($tournamentRankerList, function (GeneralLite $lhs, GeneralLite $rhs) use ($gameColumn, $winColumn, $drawColumn, $loseColumn) {
$result = - ($lhs->getRankVar($gameColumn) <=> $rhs->getRankVar($gameColumn)); $result = - ($lhs->getRankVar($gameColumn) <=> $rhs->getRankVar($gameColumn));
if ($result !== 0) return $result; if ($result !== 0) return $result;
$result = - ( $result = - (
+3 -4
View File
@@ -177,7 +177,7 @@ $templates = new \League\Plates\Engine('templates');
$valid = 1; $valid = 1;
} }
if ($userGrade >= 5) { if ($userGrade >= 6) {
$valid = true; $valid = true;
$showDetailedInfo = true; $showDetailedInfo = true;
} }
@@ -275,7 +275,7 @@ $templates = new \League\Plates\Engine('templates');
$ourGeneral = false; $ourGeneral = false;
} }
if ($userGrade == 6) { if ($userGrade == 7) {
$ourGeneral = true; $ourGeneral = true;
} }
@@ -327,8 +327,7 @@ $templates = new \League\Plates\Engine('templates');
if ($ourGeneral && !$isNPC) { if ($ourGeneral && !$isNPC) {
$turnText = []; $turnText = [];
$generalObj = new General($general, null, null, null, null, null, null, false); foreach ($generalTurnList[$general['no']] as $turnRawIdx => $turn) {
foreach ($generalTurnList[$generalObj->getID()] as $turnRawIdx => $turn) {
$turnIdx = $turnRawIdx + 1; $turnIdx = $turnRawIdx + 1;
$turnText[] = "{$turnIdx} : $turn"; $turnText[] = "{$turnIdx} : $turn";
} }
+28 -5
View File
@@ -24,7 +24,7 @@ $gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
increaseRefresh("내정보", 1); increaseRefresh("내정보", 1);
$me = General::createGeneralObjFromDB($generalID, null, GeneralQueryMode::FullWithAccessLog); $me = General::createObjFromDB($generalID, null, GeneralQueryMode::FullWithAccessLog);
$myset = $me->getVar('myset'); $myset = $me->getVar('myset');
if ($myset > 0) { if ($myset > 0) {
@@ -37,7 +37,8 @@ $lastRefresh = $db->queryFirstField(
'SELECT %b FROM %b WHERE %b = %i', 'SELECT %b FROM %b WHERE %b = %i',
GeneralAccessLogColumn::lastRefresh->value, GeneralAccessLogColumn::lastRefresh->value,
TableName::generalAccessLog->value, TableName::generalAccessLog->value,
GeneralAccessLogColumn::generalID->value, $generalID GeneralAccessLogColumn::generalID->value,
$generalID
); );
$targetTime = addTurn($lastRefresh, $gameStor->turnterm, GameConst::$minTurnDieOnPrestart); $targetTime = addTurn($lastRefresh, $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
@@ -50,13 +51,19 @@ if ($gameStor->turntime <= $gameStor->opentime) {
} }
} }
if($me->getNationID() == 0){ if ($me->getNationID() == 0) {
$showBuildNationCandidateBtn = true; $showBuildNationCandidateBtn = true;
} }
} }
$use_treatment = $me->getAuxVar('use_treatment') ?? 10; $use_treatment = $me->getAuxVar('use_treatment') ?? 10;
$use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1; $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
$changeDefence999Train = -3;
$changeDefence999Atmos = -6;
$changeDefence999Train = $me->onCalcDomestic('changeDefenceTrain', "train999", $changeDefence999Train);
$changeDefence999Atmos = $me->onCalcDomestic('changeDefenceTrain', "atmos999", $changeDefence999Atmos);
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@@ -128,11 +135,22 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<?php foreach ([90, 80, 60, 40] as $targetDefenceTrain) : ?> <?php foreach ([90, 80, 60, 40] as $targetDefenceTrain) : ?>
<option value='<?= $targetDefenceTrain ?>' <?= $me->getVar('defence_train') == $targetDefenceTrain ? "selected" : ""; ?>><?= formatDefenceTrain($targetDefenceTrain) ?>(훈사<?= $targetDefenceTrain ?>)</option> <option value='<?= $targetDefenceTrain ?>' <?= $me->getVar('defence_train') == $targetDefenceTrain ? "selected" : ""; ?>><?= formatDefenceTrain($targetDefenceTrain) ?>(훈사<?= $targetDefenceTrain ?>)</option>
<?php endforeach; ?> <?php endforeach; ?>
<option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>[훈련 -3, 사기 -6]</option> <option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>
<?php if ($changeDefence999Train != 0 || $changeDefence999Train != 0) :
?>[<?= $changeDefence999Train != 0 ? "훈련 {$changeDefence999Train}," : '' ?><?= $changeDefence999Atmos != 0 ? "사기 {$changeDefence999Atmos}" : ''
?>]<?php endif ?></option>
</select> </select>
】<br><br> 】<br><br>
<input type=<?= $submit ?> id='set_my_setting' name=btn style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px; value=설정저장><br> <input type=<?= $submit ?> id='set_my_setting' name=btn style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px; value=설정저장><br>
∞<span style='color:orange'>설정저장은 이달중 <?= $myset ?>회 남았습니다.</span><br><br> ∞<span style='color:orange'>설정저장은 이달중 <?= $myset ?>회 남았습니다.</span><br><br>
<?php if ($me->getPenaltyList()->count()) : ?>
징계 목록(저장 시 갱신)<br>
<?php foreach ($me->getPenaltyList() as $penaltyKey => $penalty) : ?>
<span style='color:red'><?= $penaltyKey->getHelptext() ?> : <?= $penalty ?></span><br>
<?php endforeach; ?>
<br />
<?php endif; ?>
<?php if (!($gameStor->autorun_user['limit_minutes'] ?? false)) : ?> <?php if (!($gameStor->autorun_user['limit_minutes'] ?? false)) : ?>
휴 가 신 청<br> 휴 가 신 청<br>
<button type="button" id='vacation' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>휴가 신청</button><br><br> <button type="button" id='vacation' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>휴가 신청</button><br><br>
@@ -150,6 +168,11 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<button type="button" id='buildNationCandidate' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>사전 거병</button><br><br> <button type="button" id='buildNationCandidate' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>사전 거병</button><br><br>
<?php endif; ?> <?php endif; ?>
<?php if (GameConst::$availableInstantAction['instantRetreat'] ?? false) : ?>
거리 3칸 이내 아국 도시로 즉시 이동<br>
<button type="button" id='instantRetreat' style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>접경 귀환</button><br><br>
<?php endif; ?>
<?php if ($gameStor->npcmode == 2 && $me->getNPCType() == 0) : ?> <?php if ($gameStor->npcmode == 2 && $me->getNPCType() == 0) : ?>
다른 장수 선택 (<?= substr($me->getAuxVar('next_change') ?? TimeUtil::now(), 0, 19) ?> 부터)<br> 다른 장수 선택 (<?= substr($me->getAuxVar('next_change') ?? TimeUtil::now(), 0, 19) ?> 부터)<br>
<a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>다른 장수 선택</button></a><br><br> <a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?= GameConst::$basecolor2 ?>;color:white;width:160px;height:30px;font-size:14px;>다른 장수 선택</button></a><br><br>
@@ -178,7 +201,7 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<div class="row mx-1"> <div class="row mx-1">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<?php foreach ($me->getItems() as $itemKey => $item) : ?> <?php foreach ($me->getItems() as $itemKey => $item) : ?>
<button type="button" data-item-type='<?=$itemKey?>' class="drop-item-btn btn btn-primary <?= $item->getName() == '-' ? 'disabled' : '' ?>"><?= $item->getName() ?></button> <button type="button" data-item-type='<?= $itemKey ?>' class="drop-item-btn btn btn-primary <?= $item->getName() == '-' ? 'disabled' : '' ?>"><?= $item->getName() ?></button>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</div> </div>
+2 -58
View File
@@ -18,7 +18,7 @@ $me = $db->queryFirstRow(
'SELECT no,tournament,refresh_score,turntime from `general` 'SELECT no,tournament,refresh_score,turntime from `general`
LEFT JOIN general_access_log AS l ON `general`.no = l.general_id where owner=%i', $userID LEFT JOIN general_access_log AS l ON `general`.no = l.general_id where owner=%i', $userID
); );
$generalID = $me['no'];
$admin = $gameStor->getValues(['tournament', 'phase', 'turnterm', 'tnmt_msg', 'tnmt_type', 'develcost', 'tnmt_trig']); $admin = $gameStor->getValues(['tournament', 'phase', 'turnterm', 'tnmt_msg', 'tnmt_type', 'develcost', 'tnmt_trig']);
$turnTerm = $admin['turnterm']; $turnTerm = $admin['turnterm'];
@@ -125,63 +125,7 @@ $globalBetTotal = array_sum($globalBet);
</tr> </tr>
</table> </table>
<table align=center class='tb_layout bg0'> <table align=center class='tb_layout bg0'>
<?php if ($session->userGrade >= 5) : ?> <?php if ($me['no'] > 0 && $me['tournament'] == 0 && $admin['tournament'] == 1) : ?>
<form method=post action=c_tournament.php>
<tr>
<td colspan=8><input type=textarea size=150 style=color:white;background-color:black; name=msg><input type=submit name=btn value='메시지'></td>
</tr>
<tr>
<td colspan=8>
<button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button>
<?php if ($admin['tournament'] == 0) : ?>
<select name=trig size=1 style=color:white;background-color:black;>
<option style=color:white; value=0 <?= !$admin['tnmt_trig'] ? 'selected' : '' ?>>수동진행</option>
<option style=color:white; value=1 <?= $admin['tnmt_trig'] ? 'selected' : '' ?>>자동진행</option>
</select>
<input type=submit name=btn value='자동개최설정'>
<?php else : ?>
<input type=submit name=btn value='중단' onclick='return confirm("진짜 중단하시겠습니까?")'>
<?php endif; ?>
<?php switch ($admin['tournament']) {
case 1:
echo "<input type=submit name=btn value='랜덤투입'>";
echo "<input type=submit name=btn value='랜덤전부투입'>";
break;
case 2:
echo "<input type=submit name=btn value='예선'><input type=submit name=btn value='예선전부'>";
break;
case 3:
echo "<input type=submit name=btn value='추첨'><input type=submit name=btn value='추첨전부'>";
break;
case 4:
echo "<input type=submit name=btn value='본선'><input type=submit name=btn value='본선전부'>";
break;
case 5:
echo "<input type=submit name=btn value='배정'>";
break;
case 6:
echo "<input type=submit name=btn value='베팅마감'>";
break;
case 7:
echo "<input type=submit name=btn value='16강'>";
break;
case 8:
echo "<input type=submit name=btn value='8강'>";
break;
case 9:
echo "<input type=submit name=btn value='4강'>";
break;
case 10:
echo "<input type=submit name=btn value='결승'>";
break;
} ?>
</td>
</tr>
</form>
<?php elseif ($me['no'] > 0 && $me['tournament'] == 0 && $admin['tournament'] == 1) : ?>
<form method=post action=c_tournament.php> <form method=post action=c_tournament.php>
<tr> <tr>
<td colspan=8><button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button><button type="submit" class="btn btn-sammo-base2" onclick='return confirm("참가비 금<?= $admin['develcost'] ?>이 필요합니다. 참가하시겠습니까?")'>참가</button><input type='hidden' name='btn' value='참가'/></td> <td colspan=8><button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button><button type="submit" class="btn btn-sammo-base2" onclick='return confirm("참가비 금<?= $admin['develcost'] ?>이 필요합니다. 참가하시겠습니까?")'>참가</button><input type='hidden' name='btn' value='참가'/></td>
+242
View File
@@ -0,0 +1,242 @@
<?php
declare(strict_types=1);
namespace sammo;
use Ds\Map;
use sammo\Enums\RankColumn;
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
require_once 'lib.php';
require_once 'func.php';
final class ComparisonTracingRNG implements RNG
{
private int $sequence = 0;
/** @var array<int, array<string, mixed>> */
public array $calls = [];
public function __construct(private readonly RNG $inner)
{
}
public static function getMaxInt(): int
{
return LiteHashDRBG::getMaxInt();
}
public function nextBytes(int $bytes): string
{
$value = $this->inner->nextBytes($bytes);
$this->record('nextBytes', ['bytes' => $bytes], bin2hex($value));
return $value;
}
public function nextBits(int $bits): string
{
$value = $this->inner->nextBits($bits);
$this->record('nextBits', ['bits' => $bits], bin2hex($value));
return $value;
}
public function nextInt(?int $max = null): int
{
$value = $this->inner->nextInt($max);
$this->record('nextInt', ['maxInclusive' => $max], $value);
return $value;
}
public function nextFloat1(): float
{
$value = $this->inner->nextFloat1();
$this->record('nextFloat1', [], $value);
return $value;
}
private function record(string $operation, array $arguments, mixed $result): void
{
$this->calls[] = [
'seq' => $this->sequence++,
'operation' => $operation,
'arguments' => $arguments,
'result' => $result,
];
}
}
function comparisonExtractRankVar(array $raw): Map
{
$rankVars = new Map();
foreach ($raw as $rawKey => $rawValue) {
$key = RankColumn::tryFrom($rawKey);
if ($key !== null) {
$rankVars[$key] = $rawValue;
}
}
return $rankVars;
}
function comparisonBuildGeneral(
array $raw,
array $city,
array $nation,
int $year,
int $month,
bool $defender = false,
): General {
$aux = [];
if (array_key_exists('inheritBuff', $raw)) {
$aux['inheritBuff'] = $raw['inheritBuff'];
}
$raw['aux'] = Json::encode($aux);
$raw['owner'] = 0;
return new General(
$raw,
comparisonExtractRankVar($raw),
null,
$city,
$nation,
$year,
$month,
$defender,
);
}
function comparisonRunBattle(array $fixture): array
{
$seed = (string)($fixture['seed'] ?? 'battle-differential');
$year = (int)$fixture['year'];
$month = (int)$fixture['month'];
$startYear = (int)($fixture['startYear'] ?? 180);
$rawAttacker = $fixture['attackerGeneral'];
$rawAttackerCity = $fixture['attackerCity'];
$rawAttackerNation = $fixture['attackerNation'];
$rawDefenderCity = $fixture['defenderCity'];
$rawDefenderNation = $fixture['defenderNation'];
// 비교 fixture에 명시된 경우에만 ref runtime의 scenario action chain을
// 활성화합니다. 일반 비교 fixture의 기존 동작은 그대로 유지합니다.
$scenarioEffect = $fixture['scenarioEffect'] ?? null;
if ($scenarioEffect === '' || $scenarioEffect === 'None') {
$scenarioEffect = null;
}
if (
$scenarioEffect !== null
&& (!is_string($scenarioEffect) || getScenarioEffectClass($scenarioEffect) === null)
) {
throw new \InvalidArgumentException('scenarioEffect is invalid');
}
GameConst::$scenarioEffect = $scenarioEffect;
$tracingRng = new ComparisonTracingRNG(new LiteHashDRBG($seed));
$warRng = new RandUtil($tracingRng);
$attacker = new WarUnitGeneral(
$warRng,
comparisonBuildGeneral($rawAttacker, $rawAttackerCity, $rawAttackerNation, $year, $month),
$rawAttackerNation,
true,
);
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$defenderList = [];
foreach ($fixture['defenderGenerals'] as $rawDefender) {
$defenderList[] = new WarUnitGeneral(
$warRng,
comparisonBuildGeneral($rawDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, true),
$rawDefenderNation,
false,
);
}
if (count($defenderList) && extractBattleOrder($city, $attacker) > 0) {
$defenderList[] = $city;
}
usort(
$defenderList,
fn(WarUnit $lhs, WarUnit $rhs): int =>
-(extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker)),
);
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind();
$finishedDefenders = [];
$getNextDefender = function (?WarUnit $previous, bool $requestNext) use (
$iterDefender,
$attacker,
&$finishedDefenders,
): ?WarUnit {
if ($previous !== null) {
$finishedDefenders[] = buildWarTraceUnitSnapshot($previous);
}
if (!$requestNext || !$iterDefender->valid()) {
return null;
}
$next = $iterDefender->current();
if (extractBattleOrder($next, $attacker) <= 0) {
return null;
}
$iterDefender->next();
return $next;
};
$events = [];
$conquered = processWar_NG(
$seed,
$attacker,
$getNextDefender,
$city,
static function (array $event) use (&$events): void {
$events[] = $event;
},
);
$attackerLogs = $attacker->getLogger()->rollback();
$defenderLogs = [];
foreach ($defenderList as $defenderUnit) {
if (!($defenderUnit instanceof WarUnitGeneral)) {
continue;
}
$snapshot = buildWarTraceUnitSnapshot($defenderUnit);
$defenderLogs[(string)$snapshot['id']] = $defenderUnit->getLogger()->rollback();
}
$cityLogs = $city->getLogger()->rollback();
return [
'engine' => 'ref',
'seed' => $seed,
'conquered' => $conquered,
'attacker' => buildWarTraceUnitSnapshot($attacker),
'city' => buildWarTraceUnitSnapshot($city),
'finishedDefenders' => $finishedDefenders,
'events' => $events,
'rng' => $tracingRng->calls,
'logs' => [
'attacker' => $attackerLogs,
'defenders' => $defenderLogs,
'city' => $cityLogs,
],
];
}
$fixturePath = $argv[1] ?? null;
if ($fixturePath === null || ($fixturePath !== '-' && !is_file($fixturePath))) {
fwrite(STDERR, "usage: php compare/battle_trace.php <fixture.json|->\n");
exit(2);
}
try {
$fixtureJson = $fixturePath === '-' ? stream_get_contents(STDIN) : file_get_contents($fixturePath);
$fixture = json_decode((string)$fixtureJson, true, flags: JSON_THROW_ON_ERROR);
echo json_encode(
comparisonRunBattle($fixture),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
} catch (\Throwable $throwable) {
fwrite(STDERR, $throwable::class . ': ' . $throwable->getMessage() . PHP_EOL);
exit(1);
}
@@ -0,0 +1,23 @@
{
"action": "AddGlobalBetray",
"args": [2, 1],
"setup": {
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2, 3],
"general": [
{ "id": 1, "values": { "name": "배신0", "betray": 0 } },
{ "id": 2, "values": { "name": "배신1", "betray": 1 } },
{ "id": 3, "values": { "name": "배신2", "betray": 2 } }
]
},
"environment": {
"year": 194,
"month": 1,
"startyear": 190
},
"observe": {
"generalIds": [1, 2, 3]
},
"compactOutput": true
}
@@ -0,0 +1,79 @@
{
"action": "AssignGeneralSpeciality",
"setup": {
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2, 3],
"general": [
{
"id": 1,
"values": {
"name": "내정대상",
"nation": 1,
"age": 30,
"leadership": 40,
"strength": 45,
"intel": 80,
"special": "None",
"specage": 30,
"special2": "che_신산",
"specage2": 99,
"aux": {
"prev_types_special": ["che_경작"]
}
}
},
{
"id": 2,
"values": {
"name": "전투대상",
"nation": 1,
"age": 30,
"leadership": 80,
"strength": 75,
"intel": 40,
"special": "che_인덕",
"specage": 99,
"special2": "None",
"specage2": 30,
"dex1": 200,
"dex2": 10,
"dex3": 10,
"dex4": 10,
"dex5": 10,
"aux": {
"prev_types_special2": ["che_돌격"]
}
}
},
{
"id": 3,
"values": {
"name": "계승대상",
"nation": 2,
"age": 30,
"leadership": 50,
"strength": 50,
"intel": 50,
"special": "che_경작",
"specage": 99,
"special2": "None",
"specage2": 30,
"aux": {
"inheritSpecificSpecialWar": "che_의술",
"marker": 3
}
}
}
]
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190
},
"observe": {
"generalIds": [1, 2, 3]
},
"compactOutput": true
}
@@ -0,0 +1,54 @@
{
"action": "AutoDeleteInvader",
"compactOutput": true,
"args": [1],
"setup": {
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"resetDiplomacy": true,
"nation": [
{
"id": 1,
"values": {
"name": "ⓞ남만족",
"capital": 69,
"gennum": 1,
"tech": 100,
"level": 2,
"type": "che_병가"
}
}
],
"general": [
{
"id": 1,
"values": {
"name": "ⓞ남만대왕",
"nation": 1,
"city": 69,
"officer_level": 12,
"npc": 9
}
}
],
"event": [
{
"id": 990001,
"action": [["AutoDeleteInvader", 1]]
}
]
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"currentEventID": 990001
},
"observe": {
"generalIds": [1]
}
}
@@ -0,0 +1,24 @@
{
"action": "BlockScoutAction",
"args": [true],
"setup": {
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"nation": [
{ "id": 1, "values": { "name": "위", "level": 2, "scout": 0 } },
{ "id": 2, "values": { "name": "촉", "level": 2, "scout": 0 } }
],
"gameEnvironment": {
"block_change_scout": false
}
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190
},
"observe": {
"nationIds": [1, 2]
}
}
@@ -0,0 +1,226 @@
{
"action": "MonthlyBoundary",
"compactOutput": true,
"environment": {
"year": 190,
"month": 12,
"startyear": 190,
"turnterm": 10,
"starttime": "2026-07-25 00:00:00",
"turntime": "2026-07-25 02:00:00"
},
"setup": {
"syncEnvironment": true,
"world": {
"hiddenSeed": "monthly-boundary-core-catalog"
},
"gameEnvironment": {
"isunited": 1,
"refreshLimit": 3,
"block_change_scout": false
},
"resetCities": true,
"deleteOtherCities": true,
"keepCityIds": [1, 2],
"city": [
{
"id": 1,
"values": {
"name": "경계도시",
"level": 1,
"nation": 1,
"pop": 10000,
"pop_max": 20000,
"agri": 1000,
"agri_max": 2000,
"comm": 1000,
"comm_max": 2000,
"secu": 1000,
"secu_max": 2000,
"trust": 50,
"trade": 100,
"def": 1000,
"def_max": 2000,
"wall": 1000,
"wall_max": 2000,
"officer_set": 1,
"state": 31,
"term": 1,
"supply": 1,
"front": 2,
"conflict": {},
"dead": 0
}
},
{
"id": 2,
"values": {
"name": "중립도시",
"level": 8,
"nation": 0,
"pop": 12000,
"pop_max": 22000,
"agri": 1200,
"agri_max": 2200,
"comm": 1200,
"comm_max": 2200,
"secu": 1200,
"secu_max": 2200,
"trust": 55,
"trade": 100,
"def": 1200,
"def_max": 2200,
"wall": 1200,
"wall_max": 2200,
"officer_set": 1,
"state": 0,
"term": 0,
"supply": 0,
"front": 0,
"conflict": {},
"dead": 0
}
}
],
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{
"id": 1,
"values": {
"name": "경계군주",
"nation": 1,
"city": 1,
"officer_level": 12,
"npc": 0,
"age": 30,
"belong": 3,
"makelimit": 2,
"gold": 1000,
"rice": 1000,
"crew": 100,
"train": 80,
"atmos": 70,
"leadership": 50,
"strength": 50,
"intel": 50,
"experience": 0,
"dedication": 0,
"dex1": 0,
"dex2": 0,
"dex3": 0,
"dex4": 0,
"dex5": 0,
"personal": "None",
"special": "None",
"specage": 0,
"special2": "None",
"specage2": 0,
"betray": 0,
"bornyear": 160,
"deadyear": 250
}
},
{
"id": 2,
"values": {
"name": "경계재야",
"nation": 0,
"city": 2,
"officer_level": 0,
"npc": 0,
"age": 25,
"belong": 4,
"makelimit": 0,
"gold": 500,
"rice": 500,
"crew": 50,
"train": 60,
"atmos": 50,
"leadership": 40,
"strength": 40,
"intel": 40,
"experience": 0,
"dedication": 0,
"dex1": 0,
"dex2": 0,
"dex3": 0,
"dex4": 0,
"dex5": 0,
"personal": "None",
"special": "None",
"specage": 0,
"special2": "None",
"specage2": 0,
"betray": 0,
"bornyear": 165,
"deadyear": 250
}
}
],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"nation": [
{
"id": 1,
"values": {
"name": "경계국",
"color": "#123456",
"capital": 1,
"gennum": 1,
"gold": 10000,
"rice": 20000,
"tech": 100,
"power": 10,
"level": 2,
"type": "che_유가",
"bill": 100,
"rate": 20,
"rate_tmp": 10,
"scout": 1,
"chief_set": 1,
"strategic_cmd_limit": 2,
"surlimit": 1,
"spy": "{}"
}
}
],
"resetDiplomacy": true,
"resetEvents": true,
"event": [
{
"id": 991001,
"target": "PRE_MONTH",
"priority": 1000,
"condition": true,
"action": [
["NoticeToHistoryLog", "aggregate-pre", 6]
]
},
{
"id": 991002,
"target": "MONTH",
"priority": 1000,
"condition": true,
"action": [
["ProcessIncome", "gold"],
["NewYear"],
["ResetOfficerLock"],
["RandomizeCityTradeRate"],
["ChangeCity", "all", {"pop": "+10", "trust": 60}],
["NoticeToHistoryLog", "aggregate-month", 6],
["DeleteEvent"]
]
}
]
},
"observe": {
"generalIds": [1, 2],
"nationIds": [1],
"cityIds": [1, 2],
"eventIds": [991001, 991002],
"accessGeneralIds": [1, 2]
}
}
@@ -0,0 +1,34 @@
{
"action": "NewYear",
"environment": {
"year": 191,
"month": 1,
"startyear": 190
},
"setup": {
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{
"id": 1,
"values": {
"nation": 1,
"age": 30,
"belong": 3
}
},
{
"id": 2,
"values": {
"nation": 0,
"age": 30,
"belong": 4
}
}
]
},
"observe": {
"generalIds": [1, 2]
}
}
@@ -0,0 +1,11 @@
{
"action": "NoticeToHistoryLog",
"args": ["<S>새해 알림</>", 6],
"environment": {
"year": 191,
"month": 1,
"startyear": 190
},
"setup": {},
"observe": {}
}
@@ -0,0 +1,75 @@
{
"action": "ProcessIncome",
"args": ["gold"],
"environment": {
"year": 190,
"month": 7,
"startyear": 190
},
"setup": {
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"general": [
{
"id": 1,
"values": {
"nation": 1,
"city": 1,
"officer_level": 5,
"npc": 0,
"gold": 1000,
"rice": 1000,
"dedication": 100
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "갑국",
"capital": 1,
"gold": 10000,
"rice": 20000,
"level": 1,
"rate_tmp": 20
}
}
],
"city": [
{
"id": 1,
"values": {
"name": "갑성",
"nation": 1,
"level": 4,
"supply": 1,
"pop": 10000,
"pop_max": 20000,
"agri": 1000,
"agri_max": 2000,
"comm": 1000,
"comm_max": 2000,
"secu": 1000,
"secu_max": 2000,
"trust": 80,
"def": 500,
"def_max": 1000,
"wall": 500,
"wall_max": 1000
}
}
]
},
"observe": {
"generalIds": [1],
"nationIds": [1],
"cityIds": [1],
"nationEnvironmentKeys": ["prev_income_gold", "prev_income_rice"]
}
}
@@ -0,0 +1,33 @@
{
"action": "ResetOfficerLock",
"environment": {
"year": 191,
"month": 1,
"startyear": 190
},
"setup": {
"resetCities": true,
"resetNations": true,
"city": [
{
"id": 1,
"values": {
"nation": 1,
"officer_set": 1
}
}
],
"nation": [
{
"id": 1,
"values": {
"chief_set": 1
}
}
]
},
"observe": {
"cityIds": [1],
"nationIds": [1]
}
}
@@ -0,0 +1,9 @@
{
"action": "CreateAdminNPC",
"environment": {
"year": 193,
"month": 12,
"startyear": 190
},
"observe": {}
}
@@ -0,0 +1,15 @@
{
"action": "CreateManyNPC",
"args": [2, 0],
"environment": {
"year": 193,
"month": 5,
"startyear": 190,
"turnterm": 10,
"turntime": "0193-05-01 00:00:00"
},
"setup": {
"resetGenerals": true
},
"observe": {}
}
@@ -0,0 +1,69 @@
{
"action": "FinishNationBetting",
"args": [1],
"setup": {
"clearBetting": true,
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"nation": [
{ "id": 1, "values": { "name": "위", "gennum": 1, "power": 100, "level": 2 } },
{ "id": 2, "values": { "name": "촉", "gennum": 1, "power": 300, "level": 0 } }
],
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{ "id": 1, "values": { "name": "장수1", "nation": 1, "owner": 1, "npc": 0 } },
{ "id": 2, "values": { "name": "장수2", "nation": 2, "owner": 2, "npc": 0 } }
],
"bettingInfo": [
{
"id": 1,
"type": "bettingNation",
"name": "천통국 예상",
"finished": false,
"selectCnt": 1,
"isExclusive": null,
"reqInheritancePoint": true,
"openYearMonth": 2400,
"closeYearMonth": 2424,
"candidates": [
{
"title": "위",
"info": "국력: 100<br>장수 수: 1<br>도시 수: 1",
"isHtml": true,
"aux": { "nation": 1 }
},
{
"title": "촉",
"info": "국력: 300<br>장수 수: 1<br>도시 수: 1",
"isHtml": true,
"aux": { "nation": 2 }
}
],
"winner": null
}
],
"bet": [
{ "betting_id": 1, "general_id": 0, "user_id": null, "betting_type": "[-1]", "amount": 100 },
{ "betting_id": 1, "general_id": 1, "user_id": 1, "betting_type": "[0]", "amount": 100 },
{ "betting_id": 1, "general_id": 2, "user_id": 2, "betting_type": "[1]", "amount": 100 }
],
"inheritancePrevious": {
"1": 900,
"2": 900
},
"syncEnvironment": true
},
"environment": {
"year": 202,
"month": 1,
"startyear": 190
},
"observe": {
"generalIds": [1, 2],
"nationIds": [1, 2],
"ownerIds": [1, 2]
}
}
@@ -0,0 +1,40 @@
{
"action": "InvaderEnding",
"compactOutput": true,
"setup": {
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"setAllCitiesNation": 1,
"nation": [
{
"id": 1,
"values": {
"name": "기준국",
"capital": 1,
"gennum": 1,
"tech": 100,
"level": 2,
"type": "che_유가"
}
}
],
"gameEnvironment": {
"isunited": 1,
"refreshLimit": 3
},
"event": [
{
"id": 990002,
"action": [["InvaderEnding"]]
}
]
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"currentEventID": 990002
},
"observe": {}
}
@@ -0,0 +1,108 @@
{
"action": "InvaderLifecycle",
"args": [10, 150, 100, 20],
"setup": {
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"resetDiplomacy": true,
"resetEvents": true,
"city": [
{
"id": 1,
"values": {
"name": "기준도시",
"level": 3,
"nation": 1,
"pop": 1000,
"pop_max": 10000,
"agri": 2000,
"agri_max": 20000,
"comm": 3000,
"comm_max": 30000,
"secu": 4000,
"secu_max": 40000,
"def": 5000,
"def_max": 50000,
"wall": 6000,
"wall_max": 60000
}
},
{
"id": 48,
"values": {
"name": "남만",
"level": 4,
"nation": 0,
"pop": 1000,
"pop_max": 10000,
"agri": 2000,
"agri_max": 20000,
"comm": 3000,
"comm_max": 30000,
"secu": 4000,
"secu_max": 40000,
"def": 5000,
"def_max": 50000,
"wall": 6000,
"wall_max": 60000
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "기준국",
"capital": 1,
"gennum": 1,
"tech": 100,
"level": 2,
"type": "che_유가"
}
}
],
"general": [
{
"id": 1,
"values": {
"name": "군주",
"nation": 1,
"city": 1,
"officer_level": 12,
"npc": 0,
"leadership": 50,
"strength": 50,
"intel": 50,
"experience": 1000,
"dedication": 1000,
"dex1": 10,
"dex2": 20,
"dex3": 30,
"dex4": 40,
"dex5": 50,
"turntime": "0200-01-01 00:05:00"
}
}
],
"gameEnvironment": {
"isunited": 0,
"refreshLimit": 3
},
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {}
}
@@ -0,0 +1,42 @@
{
"action": "LostUniqueItem",
"args": [0.2],
"environment": {
"year": 210,
"month": 1,
"startyear": 180
},
"setup": {
"syncEnvironment": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{
"id": 1,
"values": {
"name": "갑",
"npc": 0,
"horse": "che_명마_12_옥란백용구",
"weapon": "che_무기_15_의천검",
"book": "che_서적_01_효경전",
"item": "che_저지_삼황내문"
}
},
{
"id": 2,
"values": {
"name": "을",
"npc": 1,
"horse": "che_명마_12_사륜거",
"weapon": "che_무기_01_단도",
"book": "None",
"item": "che_부적_태현청생부"
}
}
]
},
"observe": {
"generalIds": [1, 2]
}
}
@@ -0,0 +1,74 @@
{
"action": "MergeInheritPointRank",
"environment": {
"year": 210,
"month": 1,
"startyear": 180
},
"setup": {
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"clearInheritanceOwnerIds": [100],
"gameEnvironment": {
"isunited": 0
},
"general": [
{
"id": 1,
"values": {
"name": "갑",
"nation": 1,
"owner": 100,
"npc": 0,
"belong": 3,
"dex1": 1000,
"dex2": 0,
"dex3": 0,
"dex4": 0,
"dex5": 0
}
}
],
"inheritancePoints": [
{"ownerId": 100, "key": "previous", "value": 999},
{"ownerId": 100, "key": "lived_month", "value": 2},
{"ownerId": 100, "key": "max_domestic_critical", "value": 4},
{"ownerId": 100, "key": "active_action", "value": 15},
{"ownerId": 100, "key": "unifier", "value": 6},
{"ownerId": 100, "key": "tournament", "value": 7}
],
"rankData": [
{"generalId": 1, "type": "warnum", "value": 2},
{"generalId": 1, "type": "firenum", "value": 1},
{"generalId": 1, "type": "betwin", "value": 2},
{"generalId": 1, "type": "betgold", "value": 4000},
{"generalId": 1, "type": "betwingold", "value": 2000},
{"generalId": 1, "type": "inherit_earned_dyn", "value": 999},
{"generalId": 1, "type": "inherit_earned_act", "value": 11},
{"generalId": 1, "type": "inherit_earned", "value": 999},
{"generalId": 1, "type": "inherit_spent_dyn", "value": 9},
{"generalId": 1, "type": "inherit_spent", "value": 999}
]
},
"observe": {
"generalIds": [1],
"ownerIds": [100],
"inheritanceKeys": [
"previous",
"lived_month",
"max_domestic_critical",
"active_action",
"unifier",
"tournament"
],
"rankGeneralIds": [1],
"rankTypes": [
"inherit_earned",
"inherit_earned_act",
"inherit_earned_dyn",
"inherit_spent",
"inherit_spent_dyn"
]
}
}
@@ -0,0 +1,75 @@
{
"action": "NationBettingLifecycle",
"args": [1, 100],
"bettorGeneralIds": [1, 2],
"bettorOwnerIds": [1, 2],
"setup": {
"clearBetting": true,
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"nation": [
{
"id": 1,
"values": {
"name": "위",
"color": "#111111",
"capital": 1,
"gennum": 1,
"gold": 1000,
"rice": 2000,
"tech": 100,
"power": 100,
"level": 2,
"type": "che_유가"
}
},
{
"id": 2,
"values": {
"name": "촉",
"color": "#222222",
"capital": 2,
"gennum": 1,
"gold": 3000,
"rice": 4000,
"tech": 200,
"power": 300,
"level": 2,
"type": "che_병가"
}
}
],
"resetCities": true,
"deleteOtherCities": true,
"keepCityIds": [1, 2],
"city": [
{ "id": 1, "values": { "name": "허창", "nation": 1, "level": 3 } },
{ "id": 2, "values": { "name": "성도", "nation": 2, "level": 3 } }
],
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{ "id": 1, "values": { "name": "장수1", "nation": 1, "city": 1, "owner": 1, "npc": 0 } },
{ "id": 2, "values": { "name": "장수2", "nation": 2, "city": 2, "owner": 2, "npc": 0 } }
],
"inheritancePrevious": {
"1": 1000,
"2": 1000
},
"rankData": [
{ "generalId": 1, "type": "inherit_spent_dyn", "value": 0 },
{ "generalId": 1, "type": "inherit_earned_act", "value": 0 },
{ "generalId": 2, "type": "inherit_spent_dyn", "value": 0 },
{ "generalId": 2, "type": "inherit_earned_act", "value": 0 }
],
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190
},
"observe": {}
}
@@ -0,0 +1,77 @@
{
"action": "NpcNationLifecycle",
"setup": {
"resetCities": true,
"resetGenerals": true,
"resetNations": true,
"city": [
{
"id": 1,
"values": {
"name": "점유도시",
"level": 5,
"nation": 1,
"pop": 10001,
"pop_max": 50001,
"agri": 1001,
"agri_max": 5001,
"comm": 2001,
"comm_max": 6001,
"secu": 3001,
"secu_max": 7001,
"def": 4001,
"def_max": 8001,
"wall": 5001,
"wall_max": 9001
}
},
{
"id": 48,
"values": {
"name": "건국도시",
"level": 5,
"nation": 0,
"pop": 10048,
"pop_max": 50048,
"agri": 1048,
"agri_max": 5048,
"comm": 2048,
"comm_max": 6048,
"secu": 3048,
"secu_max": 7048,
"def": 4048,
"def_max": 8048,
"wall": 5048,
"wall_max": 9048
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "기준국",
"capital": 1,
"gennum": 0,
"tech": 120,
"level": 2,
"type": "che_유가"
}
}
],
"gameEnvironment": {
"lastNPCTroopLeaderID": 40
},
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {}
}
@@ -0,0 +1,65 @@
{
"action": "OpenNationBetting",
"args": [1, 500],
"setup": {
"clearBetting": true,
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"nation": [
{
"id": 1,
"values": {
"name": "위",
"color": "#111111",
"capital": 1,
"gennum": 1,
"gold": 1000,
"rice": 2000,
"tech": 100,
"power": 100,
"level": 2,
"type": "che_유가"
}
},
{
"id": 2,
"values": {
"name": "촉",
"color": "#222222",
"capital": 2,
"gennum": 1,
"gold": 3000,
"rice": 4000,
"tech": 200,
"power": 300,
"level": 2,
"type": "che_병가"
}
}
],
"resetCities": true,
"city": [
{ "id": 1, "values": { "nation": 1, "level": 3 } },
{ "id": 2, "values": { "nation": 2, "level": 3 } }
],
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{ "id": 1, "values": { "name": "장수1", "nation": 1, "city": 1, "owner": 1, "npc": 0 } },
{ "id": 2, "values": { "name": "장수2", "nation": 2, "city": 2, "owner": 2, "npc": 0 } }
],
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190
},
"observe": {
"generalIds": [1, 2],
"cityIds": [1, 2],
"nationIds": [1, 2]
}
}
@@ -0,0 +1,178 @@
{
"action": "PostUpdateMonthly",
"environment": {
"year": 193,
"month": 2,
"startyear": 193,
"seedYear": 193,
"seedMonth": 1
},
"setup": {
"world": {
"hiddenSeed": "monthly-post-diplomacy-fixture"
},
"syncEnvironment": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2, 3, 4],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2, 3, 4],
"general": [
{
"id": 1,
"values": {
"name": "갑장",
"nation": 1,
"npc": 2,
"crew": 0,
"gold": 0,
"rice": 0,
"leadership": 10,
"strength": 10,
"intel": 10,
"experience": 0,
"dedication": 0
}
},
{
"id": 2,
"values": {
"name": "을장",
"nation": 2,
"npc": 2,
"crew": 0,
"gold": 0,
"rice": 0,
"leadership": 10,
"strength": 10,
"intel": 10,
"experience": 0,
"dedication": 0
}
},
{
"id": 3,
"values": {
"name": "병장",
"nation": 3,
"npc": 2,
"crew": 0,
"gold": 0,
"rice": 0,
"leadership": 10,
"strength": 10,
"intel": 10,
"experience": 0,
"dedication": 0
}
},
{
"id": 4,
"values": {
"name": "정장",
"nation": 4,
"npc": 2,
"crew": 0,
"gold": 0,
"rice": 0,
"leadership": 10,
"strength": 10,
"intel": 10,
"experience": 0,
"dedication": 0
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "갑국",
"gennum": 2,
"level": 1
}
},
{
"id": 2,
"values": {
"name": "을국",
"gennum": 1,
"level": 1
}
},
{
"id": 3,
"values": {
"name": "병국",
"gennum": 1,
"level": 1
}
},
{
"id": 4,
"values": {
"name": "정국",
"gennum": 1,
"level": 1
}
}
],
"resetDiplomacy": true,
"diplomacy": [
{
"fromNationId": 1,
"toNationId": 2,
"state": 1,
"term": 1,
"dead": 777
},
{
"fromNationId": 2,
"toNationId": 1,
"state": 1,
"term": 1,
"dead": 888
},
{
"fromNationId": 1,
"toNationId": 3,
"state": 0,
"term": 5,
"dead": 250
},
{
"fromNationId": 3,
"toNationId": 1,
"state": 0,
"term": 5,
"dead": 50
},
{
"fromNationId": 3,
"toNationId": 4,
"state": 0,
"term": 1,
"dead": 0
},
{
"fromNationId": 4,
"toNationId": 3,
"state": 0,
"term": 1,
"dead": 0
},
{
"fromNationId": 2,
"toNationId": 4,
"state": 7,
"term": 1,
"dead": 999
}
]
},
"observe": {
"generalIds": [1, 2, 3, 4],
"nationIds": [1, 2, 3, 4]
}
}
@@ -0,0 +1,162 @@
{
"action": "PostUpdateMonthly",
"environment": {
"year": 193,
"month": 2,
"startyear": 193,
"seedYear": 193,
"seedMonth": 1
},
"setup": {
"world": {
"hiddenSeed": "monthly-post-nation-stats-fixture"
},
"syncEnvironment": true,
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"resetDiplomacy": true,
"general": [
{
"id": 1,
"values": {
"nation": 1,
"npc": 0,
"gold": 1000,
"rice": 2000,
"crew": 100,
"leadership": 50,
"strength": 40,
"intel": 30,
"experience": 100,
"dedication": 200,
"dex1": 1000,
"dex2": 0,
"dex3": 0,
"dex4": 0,
"dex5": 0
}
},
{
"id": 2,
"values": {
"nation": 2,
"npc": 2,
"gold": 3000,
"rice": 4000,
"crew": 200,
"leadership": 60,
"strength": 50,
"intel": 40,
"experience": 300,
"dedication": 400,
"dex1": 2000,
"dex2": 1000,
"dex3": 0,
"dex4": 0,
"dex5": 0
}
}
],
"rankData": [
{"generalId": 1, "type": "killcrew_person", "value": 100},
{"generalId": 1, "type": "deathcrew_person", "value": 0},
{"generalId": 2, "type": "killcrew_person", "value": 0},
{"generalId": 2, "type": "deathcrew_person", "value": 100}
],
"nation": [
{
"id": 1,
"values": {
"name": "갑국",
"gold": 10000,
"rice": 20000,
"tech": 100,
"level": 2,
"gennum": 9,
"power": 7
}
},
{
"id": 2,
"values": {
"name": "을국",
"gold": 2000,
"rice": 3000,
"tech": 50,
"level": 1,
"gennum": 8,
"power": 8
}
}
],
"city": [
{
"id": 1,
"values": {
"name": "갑성",
"nation": 1,
"level": 4,
"supply": 1,
"pop": 1000,
"pop_max": 2000,
"agri": 100,
"agri_max": 200,
"comm": 100,
"comm_max": 200,
"secu": 100,
"secu_max": 200,
"def": 100,
"def_max": 200,
"wall": 100,
"wall_max": 200
}
},
{
"id": 2,
"values": {
"name": "을성",
"nation": 2,
"level": 4,
"supply": 1,
"pop": 2000,
"pop_max": 4000,
"agri": 200,
"agri_max": 400,
"comm": 200,
"comm_max": 400,
"secu": 200,
"secu_max": 400,
"def": 200,
"def_max": 400,
"wall": 200,
"wall_max": 400
}
}
],
"nationEnvironment": [
{
"nationId": 1,
"key": "max_power",
"value": {
"maxPower": 999,
"maxCrew": 50,
"maxCities": ["옛도시", "옛도시2"]
}
},
{"nationId": 1, "key": "available_war_setting_cnt", "value": 1}
]
},
"observe": {
"generalIds": [1, 2],
"nationIds": [1, 2],
"cityIds": [1, 2],
"rankGeneralIds": [1, 2],
"rankTypes": ["killcrew_person", "deathcrew_person"],
"nationEnvironmentKeys": ["max_power", "available_war_setting_cnt"]
}
}
@@ -0,0 +1,128 @@
{
"action": "PostUpdateMonthly",
"environment": {
"year": 193,
"month": 2,
"startyear": 193,
"seedYear": 193,
"seedMonth": 1
},
"setup": {
"world": {
"hiddenSeed": "monthly-post-tail-2"
},
"syncEnvironment": true,
"clearNeutralAuctions": true,
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"resetDiplomacy": true,
"gameEnvironment": {
"tournament": 0,
"tnmt_trig": true,
"tnmt_pattern": [0, 1, 2, 3],
"prev_winner": null
},
"general": [
{
"id": 1,
"values": {
"name": "갑장",
"nation": 1,
"city": 1,
"officer_level": 12,
"npc": 0,
"gold": 5000,
"rice": 7000,
"crew": 100,
"leadership": 50,
"strength": 40,
"intel": 30,
"experience": 100,
"dedication": 200
}
},
{
"id": 2,
"values": {
"name": "을장",
"nation": 2,
"city": 2,
"officer_level": 12,
"npc": 0,
"gold": 6000,
"rice": 8000,
"crew": 200,
"leadership": 60,
"strength": 50,
"intel": 40,
"experience": 300,
"dedication": 400
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "갑국",
"capital": 1,
"gold": 10000,
"rice": 20000,
"tech": 100,
"level": 2,
"gennum": 1,
"power": 7
}
},
{
"id": 2,
"values": {
"name": "을국",
"capital": 2,
"gold": 2000,
"rice": 3000,
"tech": 50,
"level": 1,
"gennum": 1,
"power": 8
}
}
],
"city": [
{
"id": 1,
"values": {
"name": "갑성",
"nation": 1,
"level": 4,
"supply": 1,
"front": 3,
"pop": 1000,
"pop_max": 2000
}
},
{
"id": 2,
"values": {
"name": "을성",
"nation": 2,
"level": 4,
"supply": 1,
"front": 3,
"pop": 2000,
"pop_max": 4000
}
}
]
},
"observe": {
"generalIds": [1, 2],
"nationIds": [1, 2],
"cityIds": [1, 2]
}
}
@@ -0,0 +1,143 @@
{
"action": "PostUpdateMonthly",
"environment": {
"year": 195,
"month": 2,
"startyear": 193,
"seedYear": 195,
"seedMonth": 1
},
"setup": {
"world": {
"hiddenSeed": "monthly-post-wander-fixture"
},
"syncEnvironment": true,
"resetCities": true,
"city": [
{
"id": 1,
"values": {
"name": "방랑성",
"nation": 4,
"level": 4,
"front": 1
}
},
{
"id": 2,
"values": {
"name": "존속성",
"nation": 1,
"level": 4,
"front": 1
}
}
],
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2, 3],
"general": [
{
"id": 1,
"values": {
"name": "방랑주",
"nation": 4,
"city": 1,
"officer_level": 12,
"npc": 2,
"gold": 2000,
"rice": 3000,
"crew": 100,
"makelimit": 0,
"belong": 7,
"leadership": 50,
"strength": 40,
"intel": 30,
"experience": 100,
"dedication": 200
}
},
{
"id": 2,
"values": {
"name": "방랑객",
"nation": 4,
"city": 1,
"officer_level": 1,
"npc": 0,
"gold": 1500,
"rice": 4000,
"crew": 200,
"makelimit": 0,
"belong": 5,
"leadership": 60,
"strength": 50,
"intel": 40,
"experience": 300,
"dedication": 400
}
},
{
"id": 3,
"values": {
"name": "존속장",
"nation": 1,
"city": 2,
"officer_level": 12,
"npc": 2,
"gold": 500,
"rice": 500,
"crew": 50,
"leadership": 50,
"strength": 50,
"intel": 50,
"experience": 0,
"dedication": 0
}
}
],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 4],
"nation": [
{
"id": 1,
"values": {
"name": "존속국",
"gennum": 1,
"level": 1
}
},
{
"id": 4,
"values": {
"name": "방랑국",
"gennum": 2,
"level": 0
}
}
],
"resetDiplomacy": true,
"diplomacy": [
{
"fromNationId": 1,
"toNationId": 4,
"state": 2,
"term": 0,
"dead": 0
},
{
"fromNationId": 4,
"toNationId": 1,
"state": 2,
"term": 0,
"dead": 0
}
]
},
"observe": {
"generalIds": [1, 2, 3],
"nationIds": [1, 4],
"cityIds": [1, 2]
}
}
@@ -0,0 +1,49 @@
{
"action": "PreUpdateMonthly",
"environment": {
"year": 200,
"month": 12,
"startyear": 190
},
"setup": {
"syncEnvironment": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1, 2],
"general": [
{"id": 1, "values": {"makelimit": 2}},
{"id": 2, "values": {"makelimit": 0}}
],
"generalAccessLog": [
{"generalId": 1, "refreshScoreTotal": 101},
{"generalId": 2, "refreshScoreTotal": 1}
],
"nation": [
{
"id": 1,
"values": {
"rate": 35,
"rate_tmp": 10,
"strategic_cmd_limit": 2,
"surlimit": 1,
"spy": "{\"1\":1,\"2\":2}"
}
}
],
"city": [
{"id": 1, "values": {"state": 31, "term": 1, "conflict": {"1": 10}}},
{"id": 2, "values": {"state": 32, "term": 2, "conflict": {"1": 20}}},
{"id": 3, "values": {"state": 33, "term": 0, "conflict": {"1": 30}}},
{"id": 4, "values": {"state": 34, "term": 3, "conflict": {"1": 40}}},
{"id": 5, "values": {"state": 41, "term": 1, "conflict": {"1": 50}}},
{"id": 6, "values": {"state": 42, "term": 2, "conflict": {"1": 60}}},
{"id": 7, "values": {"state": 43, "term": 3, "conflict": {"1": 70}}}
]
},
"observe": {
"generalIds": [1, 2],
"nationIds": [1],
"cityIds": [1, 2, 3, 4, 5, 6, 7],
"accessGeneralIds": [1, 2]
}
}
@@ -0,0 +1,76 @@
{
"action": "ProcessIncome",
"args": ["gold"],
"environment": {
"year": 190,
"month": 7,
"startyear": 190
},
"setup": {
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"general": [
{
"id": 1,
"values": {
"nation": 1,
"city": 1,
"officer_level": 5,
"npc": 0,
"gold": 1000,
"rice": 1000,
"dedication": 100
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "갑국",
"capital": 1,
"gold": 10000,
"rice": 20000,
"level": 1,
"rate": 35,
"rate_tmp": 10
}
}
],
"city": [
{
"id": 1,
"values": {
"name": "갑성",
"nation": 1,
"level": 4,
"supply": 1,
"pop": 10000,
"pop_max": 20000,
"agri": 1000,
"agri_max": 2000,
"comm": 1000,
"comm_max": 2000,
"secu": 1000,
"secu_max": 2000,
"trust": 80,
"def": 500,
"def_max": 1000,
"wall": 500,
"wall_max": 1000
}
}
]
},
"observe": {
"generalIds": [1],
"nationIds": [1],
"cityIds": [1],
"nationEnvironmentKeys": ["prev_income_gold", "prev_income_rice"]
}
}
@@ -0,0 +1,106 @@
{
"action": "ProcessSemiAnnual",
"resource": "gold",
"environment": {
"year": 193,
"month": 1,
"startyear": 190
},
"setup": {
"resetCities": true,
"resetGenerals": true,
"nation": [
{
"id": 1,
"values": {
"name": "반기검증국",
"gold": 100001,
"rice": 7777,
"rate_tmp": 20,
"type": "che_도가"
}
}
],
"city": [
{
"id": 1,
"values": {
"nation": 1,
"supply": 1,
"pop": 10000,
"pop_max": 50000,
"agri": 1001,
"agri_max": 5000,
"comm": 1001,
"comm_max": 5000,
"secu": 1001,
"secu_max": 2000,
"trust": 55,
"def": 1001,
"def_max": 5000,
"wall": 1001,
"wall_max": 5000,
"dead": 123
}
},
{
"id": 2,
"values": {
"nation": 1,
"supply": 0,
"pop": 10000,
"pop_max": 50000,
"agri": 1001,
"agri_max": 5000,
"comm": 1001,
"comm_max": 5000,
"secu": 1001,
"secu_max": 2000,
"trust": 55,
"def": 1001,
"def_max": 5000,
"wall": 1001,
"wall_max": 5000,
"dead": 123
}
},
{
"id": 3,
"values": {
"nation": 0,
"supply": 1,
"pop": 10000,
"pop_max": 50000,
"agri": 1001,
"agri_max": 5000,
"comm": 1001,
"comm_max": 5000,
"secu": 1001,
"secu_max": 2000,
"trust": 55,
"def": 1001,
"def_max": 5000,
"wall": 1001,
"wall_max": 5000,
"dead": 123
}
}
],
"general": [
{
"id": 1,
"values": {
"nation": 1,
"city": 1,
"gold": 10001,
"rice": 8888
}
}
]
},
"observe": {
"generalIds": [1],
"cityIds": [1, 2, 3],
"nationIds": [1]
}
}
@@ -0,0 +1,65 @@
{
"action": "ProcessSemiAnnual",
"resource": "gold",
"environment": {
"year": 193,
"month": 1,
"startyear": 190
},
"setup": {
"resetCities": true,
"resetGenerals": true,
"nation": [
{
"id": 1,
"values": {
"name": "반기검증국",
"gold": 100001,
"rice": 7777,
"rate": 50,
"rate_tmp": 20,
"type": "che_중립"
}
}
],
"city": [
{
"id": 1,
"values": {
"nation": 1,
"supply": 1,
"pop": 10000,
"pop_max": 50000,
"agri": 1001,
"agri_max": 5000,
"comm": 1001,
"comm_max": 5000,
"secu": 1001,
"secu_max": 2000,
"trust": 55,
"def": 1001,
"def_max": 5000,
"wall": 1001,
"wall_max": 5000,
"dead": 123
}
}
],
"general": [
{
"id": 1,
"values": {
"nation": 1,
"city": 1,
"gold": 10001,
"rice": 8888
}
}
]
},
"observe": {
"generalIds": [1],
"cityIds": [1],
"nationIds": [1]
}
}
@@ -0,0 +1,96 @@
{
"action": "ProcessWarIncome",
"environment": {
"year": 193,
"month": 1,
"startyear": 190
},
"setup": {
"resetCities": true,
"nation": [
{
"id": 1,
"values": {
"name": "전쟁수입국",
"gold": 1000,
"level": 1,
"type": "che_중립"
}
},
{
"id": 2,
"values": {
"name": "비활성국",
"gold": 2000,
"level": 0,
"type": "che_중립"
}
},
{
"id": 3,
"values": {
"name": "법가국",
"gold": 3000,
"level": 1,
"type": "che_법가"
}
}
],
"city": [
{
"id": 1,
"values": {
"nation": 1,
"supply": 1,
"pop": 1000,
"pop_max": 2000,
"dead": 101
}
},
{
"id": 2,
"values": {
"nation": 1,
"supply": 0,
"pop": 1000,
"pop_max": 2000,
"dead": 999
}
},
{
"id": 3,
"values": {
"nation": 2,
"supply": 1,
"pop": 1000,
"pop_max": 2000,
"dead": 1000
}
},
{
"id": 4,
"values": {
"nation": 3,
"supply": 1,
"pop": 1000,
"pop_max": 2000,
"dead": 105
}
},
{
"id": 5,
"values": {
"nation": 0,
"supply": 1,
"pop": 999,
"pop_max": 1000,
"dead": 10
}
}
]
},
"observe": {
"cityIds": [1, 2, 3, 4, 5],
"nationIds": [1, 2, 3]
}
}
@@ -0,0 +1,105 @@
{
"action": "RaiseInvader",
"compactOutput": true,
"args": [10, 150, 100, 20],
"setup": {
"resetCities": true,
"resetGenerals": true,
"deleteOtherGenerals": true,
"keepGeneralIds": [1],
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1],
"city": [
{
"id": 1,
"values": {
"level": 3,
"nation": 1,
"pop": 1000,
"pop_max": 10000,
"agri": 2000,
"agri_max": 20000,
"comm": 3000,
"comm_max": 30000,
"secu": 4000,
"secu_max": 40000,
"def": 5000,
"def_max": 50000,
"wall": 6000,
"wall_max": 60000
}
},
{
"id": 48,
"values": {
"level": 4,
"nation": 0,
"pop": 1000,
"pop_max": 10000,
"agri": 2000,
"agri_max": 20000,
"comm": 3000,
"comm_max": 30000,
"secu": 4000,
"secu_max": 40000,
"def": 5000,
"def_max": 50000,
"wall": 6000,
"wall_max": 60000
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "기준국",
"capital": 1,
"gennum": 1,
"tech": 100,
"level": 2,
"type": "che_유가"
}
}
],
"general": [
{
"id": 1,
"values": {
"name": "군주",
"nation": 1,
"city": 1,
"officer_level": 12,
"npc": 0,
"leadership": 50,
"strength": 50,
"intel": 50,
"experience": 1000,
"dedication": 1000,
"dex1": 10,
"dex2": 20,
"dex3": 30,
"dex4": 40,
"dex5": 50,
"turntime": "0200-01-01 00:05:00"
}
}
],
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {
"generalIds": [1],
"cityIds": [1, 48],
"nationIds": [1]
}
}
@@ -0,0 +1,77 @@
{
"action": "RaiseNPCNation",
"setup": {
"resetCities": true,
"resetGenerals": true,
"resetNations": true,
"city": [
{
"id": 1,
"values": {
"name": "점유도시",
"level": 5,
"nation": 1,
"pop": 10001,
"pop_max": 50001,
"agri": 1001,
"agri_max": 5001,
"comm": 2001,
"comm_max": 6001,
"secu": 3001,
"secu_max": 7001,
"def": 4001,
"def_max": 8001,
"wall": 5001,
"wall_max": 9001
}
},
{
"id": 48,
"values": {
"name": "건국도시",
"level": 5,
"nation": 0,
"pop": 10048,
"pop_max": 50048,
"agri": 1048,
"agri_max": 5048,
"comm": 2048,
"comm_max": 6048,
"secu": 3048,
"secu_max": 7048,
"def": 4048,
"def_max": 8048,
"wall": 5048,
"wall_max": 9048
}
}
],
"nation": [
{
"id": 1,
"values": {
"name": "기준국",
"capital": 1,
"gennum": 1,
"tech": 120,
"level": 2,
"type": "che_유가"
}
}
],
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {
"cityIds": [1, 48],
"nationIds": [1]
}
}
@@ -0,0 +1,35 @@
{
"action": "RegNeutralNPC",
"args": [
0,
"등록재야",
null,
0,
33,
45,
55,
65,
180,
245,
null,
"무쌍",
""
],
"setup": {
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {
"generalIds": [],
"cityIds": [33],
"nationIds": [1]
}
}
+36
View File
@@ -0,0 +1,36 @@
{
"action": "RegNPC",
"args": [
0,
"등록장수",
null,
0,
33,
60,
50,
40,
7,
186,
240,
null,
"인덕",
"등록 대사"
],
"setup": {
"syncEnvironment": true
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190,
"turnterm": 10,
"turntime": "0200-01-01 00:00:00",
"show_img_level": 3,
"fiction": [0]
},
"observe": {
"generalIds": [],
"cityIds": [33],
"nationIds": [1]
}
}
@@ -0,0 +1,24 @@
{
"action": "UnblockScoutAction",
"args": [false],
"setup": {
"resetNations": true,
"deleteOtherNations": true,
"keepNationIds": [1, 2],
"nation": [
{ "id": 1, "values": { "name": "위", "level": 2, "scout": 1 } },
{ "id": 2, "values": { "name": "촉", "level": 2, "scout": 1 } }
],
"gameEnvironment": {
"block_change_scout": true
}
},
"environment": {
"year": 200,
"month": 1,
"startyear": 190
},
"observe": {
"nationIds": [1, 2]
}
}
@@ -0,0 +1,140 @@
{
"action": "UpdateCitySupply",
"environment": {
"year": 193,
"month": 1,
"startyear": 190
},
"setup": {
"nation": [
{
"id": 99,
"values": {
"name": "보급검증국",
"color": "#777777",
"capital": 1,
"level": 1,
"type": "che_중립"
}
},
{
"id": 98,
"values": {
"name": "불일치수도국",
"color": "#888888",
"capital": 2,
"level": 1,
"type": "che_중립"
}
}
],
"city": [
{
"id": 1,
"values": {
"nation": 99,
"supply": 0,
"front": 2,
"pop": 1001,
"agri": 501,
"comm": 499,
"secu": 99,
"trust": 50,
"def": 101,
"wall": 50,
"officer_set": 7,
"term": 2,
"conflict": {"98": 3}
}
},
{
"id": 9,
"values": {
"nation": 99,
"supply": 0,
"front": 2,
"pop": 1001,
"agri": 501,
"comm": 499,
"secu": 99,
"trust": 50,
"def": 101,
"wall": 50,
"officer_set": 7,
"term": 2,
"conflict": {"98": 3}
}
},
{
"id": 2,
"values": {
"nation": 99,
"supply": 1,
"front": 2,
"pop": 1001,
"agri": 501,
"comm": 499,
"secu": 99,
"trust": 33,
"def": 101,
"wall": 50,
"officer_set": 7,
"term": 2,
"conflict": {"98": 3}
}
},
{
"id": 3,
"values": {
"nation": 0,
"supply": 0,
"front": 0,
"trust": 50
}
}
],
"general": [
{
"id": 1,
"values": {
"nation": 99,
"city": 2,
"officer_level": 4,
"officer_city": 2,
"crew": 101,
"train": 51,
"atmos": 99
}
},
{
"id": 2,
"values": {
"nation": 99,
"city": 1,
"officer_level": 4,
"officer_city": 2,
"crew": 101,
"train": 51,
"atmos": 99
}
},
{
"id": 3,
"values": {
"nation": 98,
"city": 2,
"officer_level": 3,
"officer_city": 1,
"crew": 101,
"train": 51,
"atmos": 99
}
}
]
},
"observe": {
"generalIds": [1, 2, 3],
"cityIds": [1, 2, 3, 9],
"nationIds": [98, 99]
}
}
@@ -0,0 +1,85 @@
{
"action": "UpdateNationLevel",
"environment": {
"year": 193,
"month": 2,
"startyear": 190,
"killturn": 1000,
"turnterm": 10
},
"setup": {
"resetCities": true,
"resetGenerals": true,
"resetUniqueOccupancy": true,
"syncEnvironment": true,
"clearNationTurnIds": [1],
"clearInheritanceOwnerIds": [990061],
"nation": [
{
"id": 1,
"values": {
"name": "작위검증국",
"color": "#777777",
"capital": 1,
"gold": 10000,
"rice": 20000,
"level": 0,
"type": "che_중립",
"aux": {}
}
}
],
"city": [
{
"id": 1,
"values": {
"nation": 1,
"level": 4
}
},
{
"id": 2,
"values": {
"nation": 1,
"level": 4
}
}
],
"general": [
{
"id": 1,
"values": {
"name": "조조",
"nation": 1,
"city": 1,
"officer_level": 12,
"owner": 990061,
"npc": 0,
"killturn": 1000,
"belong": 10,
"horse": "None",
"weapon": "None",
"book": "None",
"item": "None",
"aux": {}
}
},
{
"id": 2,
"values": {
"nation": 0,
"city": 2,
"officer_level": 1,
"npc": 0,
"killturn": 0
}
}
]
},
"observe": {
"generalIds": [1],
"cityIds": [1, 2],
"nationIds": [1],
"ownerIds": [990061]
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace sammo;
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
require_once 'lib.php';
require_once 'func.php';
$input = stream_get_contents(STDIN);
$keys = Json::decode($input);
if (!is_array($keys)) {
fwrite(STDERR, "Expected a JSON array of item keys.\n");
exit(2);
}
$result = [];
foreach ($keys as $key) {
if (!is_string($key)) {
continue;
}
$item = buildItemClass($key);
$result[$key] = [
'rawName' => $item->getRawName(),
'name' => $item->getName(),
'info' => $item->getInfo(),
'cost' => $item->getCost(),
'buyable' => $item->isBuyable(),
'consumable' => $item->isConsumable(),
'reqSecu' => $item->getReqSecu(),
];
}
echo Json::encode($result);
+1579
View File
@@ -0,0 +1,1579 @@
<?php
declare(strict_types=1);
namespace sammo;
if (PHP_SAPI !== 'cli' || getenv('TURN_DIFFERENTIAL_ENABLED') !== '1') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
$_SERVER['REMOTE_ADDR'] ??= '127.0.0.1';
error_reporting(E_ALL & ~E_DEPRECATED);
require_once 'lib.php';
require_once 'func.php';
require_once __DIR__ . '/turn_state_snapshot.php';
/** @param array<string, mixed> $values */
function comparisonMonthlyPatch(string $table, int $id, array $values): void
{
$definitions = [
'city' => [
'idColumn' => 'city',
'allowed' => [
'name', 'level', 'nation', 'supply', 'front', 'pop', 'pop_max',
'agri', 'agri_max', 'comm', 'comm_max', 'secu', 'secu_max',
'trust', 'trade', 'def', 'def_max', 'wall', 'wall_max',
'officer_set', 'state', 'region', 'term', 'conflict', 'dead',
],
],
'nation' => [
'idColumn' => 'nation',
'allowed' => [
'name', 'color', 'capital', 'gennum', 'gold', 'rice', 'tech',
'power', 'level', 'type', 'bill', 'rate_tmp', 'scout', 'chief_set', 'aux',
'rate', 'strategic_cmd_limit', 'surlimit', 'spy',
],
],
'general' => [
'idColumn' => 'no',
'allowed' => [
'name', 'nation', 'city', 'officer_level', 'officer_city',
'crew', 'train', 'atmos', 'owner', 'npc', 'killturn', 'belong',
'gold', 'rice', 'horse', 'weapon', 'book', 'item', 'aux',
'leadership', 'strength', 'intel', 'experience', 'dedication',
'injury',
'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'personal', 'special',
'specage', 'special2', 'specage2', 'betray', 'age',
'bornyear', 'deadyear', 'turntime', 'makelimit',
],
],
];
$definition = $definitions[$table] ?? null;
if ($definition === null) {
throw new \InvalidArgumentException("unsupported setup table: {$table}");
}
$patch = [];
foreach ($values as $key => $value) {
if (!is_string($key) || !in_array($key, $definition['allowed'], true)) {
throw new \InvalidArgumentException("unsupported {$table} setup field");
}
if (in_array($key, ['conflict', 'aux'], true) && is_array($value)) {
$value = json_encode($value, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
}
$patch[$key] = $value;
}
if ($table === 'nation') {
$patch += [
'nation' => $id,
'name' => "fixture-nation-{$id}",
'color' => '#777777',
'capital' => 0,
'gold' => 0,
'rice' => 0,
'level' => 1,
'type' => 'che_중립',
'aux' => '{}',
];
DB::db()->insertUpdate('nation', $patch, $patch);
} elseif ($patch !== []) {
DB::db()->update($table, $patch, "`{$definition['idColumn']}` = %i", $id);
}
}
/** @param array<string, mixed> $observe */
function comparisonMonthlyDetails(array $observe, int $worldHistoryAfterId): array
{
$db = DB::db();
$generals = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'no',
'nationId' => 'nation',
'cityId' => 'city',
'officerLevel' => 'officer_level',
'officerCityId' => 'officer_city',
'crew' => 'crew',
'train' => 'train',
'atmos' => 'atmos',
'gold' => 'gold',
'rice' => 'rice',
'injury' => 'injury',
'leadership' => 'leadership',
'strength' => 'strength',
'intelligence' => 'intel',
'age' => 'age',
'specialDomestic' => 'special',
'specAge' => 'specage',
'specialWar' => 'special2',
'specAge2' => 'specage2',
'betray' => 'betray',
'makeLimit' => 'makelimit',
'horse' => 'horse',
'weapon' => 'weapon',
'book' => 'book',
'item' => 'item',
'dex1' => 'dex1',
'dex2' => 'dex2',
'dex3' => 'dex3',
'dex4' => 'dex4',
'dex5' => 'dex5',
'aux' => 'aux',
],
['aux'],
),
comparisonRowsById('general', 'no', comparisonIntegerList($observe['generalIds'] ?? [], 'generalIds')),
);
$cities = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'city',
'nationId' => 'nation',
'state' => 'state',
'supplyState' => 'supply',
'frontState' => 'front',
'officerSet' => 'officer_set',
'term' => 'term',
'dead' => 'dead',
'population' => 'pop',
'populationMax' => 'pop_max',
'agriculture' => 'agri',
'agricultureMax' => 'agri_max',
'commerce' => 'comm',
'commerceMax' => 'comm_max',
'security' => 'secu',
'securityMax' => 'secu_max',
'trust' => 'trust',
'trade' => 'trade',
'defence' => 'def',
'defenceMax' => 'def_max',
'wall' => 'wall',
'wallMax' => 'wall_max',
'conflict' => 'conflict',
],
['conflict'],
),
comparisonRowsById('city', 'city', comparisonIntegerList($observe['cityIds'] ?? [], 'cityIds')),
);
$nations = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'nation',
'gold' => 'gold',
'rice' => 'rice',
'rate' => 'rate_tmp',
'baseRate' => 'rate',
'power' => 'power',
'generalCount' => 'gennum',
'tech' => 'tech',
'typeCode' => 'type',
'scout' => 'scout',
'strategicCommandLimit' => 'strategic_cmd_limit',
'surrenderLimit' => 'surlimit',
'spy' => 'spy',
'chiefSet' => 'chief_set',
],
['spy'],
),
comparisonRowsById('nation', 'nation', comparisonIntegerList($observe['nationIds'] ?? [], 'nationIds')),
);
$worldHistory = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'id',
'nationId' => 'nation_id',
'year' => 'year',
'month' => 'month',
'text' => 'text',
],
),
$db->query(
'SELECT id, nation_id, year, month, text FROM world_history WHERE id > %i ORDER BY id',
$worldHistoryAfterId,
),
);
$inheritanceKeys = $observe['inheritanceKeys'] ?? ['unifier'];
if (!is_array($inheritanceKeys) || array_filter($inheritanceKeys, static fn($key): bool => !is_string($key))) {
throw new \InvalidArgumentException('inheritanceKeys must be an array of strings');
}
$inheritancePoints = [];
foreach (comparisonIntegerList($observe['ownerIds'] ?? [], 'ownerIds') as $ownerId) {
$entry = ['ownerId' => $ownerId];
foreach ($inheritanceKeys as $key) {
$value = $db->queryFirstField(
'SELECT value FROM storage WHERE namespace = %s AND `key` = %s',
"inheritance_{$ownerId}",
$key,
);
$entry[$key] = $value === null ? 0 : (comparisonJsonValue($value)[0] ?? 0);
}
$inheritancePoints[] = $entry;
}
$rankGeneralIds = comparisonIntegerList($observe['rankGeneralIds'] ?? [], 'rankGeneralIds');
$rankTypes = $observe['rankTypes'] ?? [];
if (!is_array($rankTypes) || array_filter($rankTypes, static fn($type): bool => !is_string($type))) {
throw new \InvalidArgumentException('rankTypes must be an array of strings');
}
$rankData = (!$rankGeneralIds || !$rankTypes)
? []
: iterator_to_array($db->query(
'SELECT general_id AS generalId, nation_id AS nationId, `type`, `value` FROM rank_data WHERE general_id IN %li AND `type` IN %ls ORDER BY general_id, `type`',
$rankGeneralIds,
$rankTypes,
));
$generalAccessLogs = [];
$accessGeneralIds = comparisonIntegerList($observe['accessGeneralIds'] ?? [], 'accessGeneralIds');
if ($accessGeneralIds) {
$generalAccessLogs = iterator_to_array($db->query(
'SELECT general_id AS generalId, refresh_score_total AS refreshScoreTotal FROM general_access_log WHERE general_id IN %li ORDER BY general_id',
$accessGeneralIds,
));
}
$nationEnvironment = [];
$nationEnvironmentKeys = $observe['nationEnvironmentKeys'] ?? [];
if (
!is_array($nationEnvironmentKeys)
|| array_filter($nationEnvironmentKeys, static fn($key): bool => !is_string($key))
) {
throw new \InvalidArgumentException('nationEnvironmentKeys must be an array of strings');
}
foreach (comparisonIntegerList($observe['nationIds'] ?? [], 'nationIds') as $nationId) {
$entry = ['nationId' => $nationId];
$storage = KVStorage::getStorage($db, $nationId, 'nation_env');
foreach ($nationEnvironmentKeys as $key) {
$entry[$key] = $storage->getValue($key);
}
$nationEnvironment[] = $entry;
}
return [
'generals' => $generals,
'cities' => $cities,
'nations' => $nations,
'worldHistory' => $worldHistory,
'inheritancePoints' => $inheritancePoints,
'rankData' => $rankData,
'generalAccessLogs' => $generalAccessLogs,
'nationEnvironment' => $nationEnvironment,
];
}
/**
* Exercise the dynamically-created invader events against one evolving database.
*
* @param array<string, mixed> $request
* @param array<string, mixed> $environment
* @return array<string, mixed>
*/
function comparisonInvaderLifecycleTrace(
array $request,
array $environment,
int $generalIdBeforeAction,
int $nationIdBeforeAction,
int $eventIdBeforeAction,
int $worldHistoryIdBeforeAction,
): array {
$db = DB::db();
$args = $request['args'] ?? [];
if (!is_array($args) || count($args) > 4) {
throw new \InvalidArgumentException('InvaderLifecycle args must have at most four entries');
}
$year = $environment['year'];
$month = $environment['month'];
$startYear = $environment['startyear'];
$raiseEnvironment = [
'year' => $year,
'month' => $month,
'startyear' => $startYear,
'turnterm' => $environment['turnterm'],
'turntime' => $environment['turntime'],
'show_img_level' => $environment['show_img_level'] ?? 3,
'stored_icons' => $environment['stored_icons'] ?? [],
'icon_path' => $environment['icon_path'] ?? '.',
'fiction' => $environment['fiction'] ?? [0],
];
(new \sammo\Event\Action\RaiseInvader(...$args))->run($raiseEnvironment);
$invaderNationIds = array_map(
'intval',
$db->queryFirstColumn('SELECT nation FROM nation WHERE nation > %i ORDER BY nation', $nationIdBeforeAction),
);
$existingNationId = (int)$db->queryFirstField(
'SELECT nation FROM nation WHERE nation <= %i ORDER BY nation LIMIT 1',
$nationIdBeforeAction,
);
$rulerIds = array_map(
'intval',
$db->queryFirstColumn(
'SELECT no FROM general WHERE nation IN %li AND officer_level = 12 ORDER BY nation',
$invaderNationIds,
),
);
if ($invaderNationIds === [] || $existingNationId <= 0 || count($rulerIds) !== count($invaderNationIds)) {
throw new \RuntimeException('InvaderLifecycle failed to create the expected entities');
}
$autoDeleteEvents = [];
$endingEventId = 0;
foreach ($db->query('SELECT id, action FROM event WHERE id > %i ORDER BY id', $eventIdBeforeAction) as $row) {
$action = comparisonJsonValue($row['action']);
$actionName = $action[0][0] ?? null;
if ($actionName === 'AutoDeleteInvader') {
$autoDeleteEvents[] = [
'eventId' => (int)$row['id'],
'nationId' => (int)($action[0][1] ?? 0),
];
} elseif ($actionName === 'InvaderEnding') {
$endingEventId = (int)$row['id'];
}
}
if (count($autoDeleteEvents) !== count($invaderNationIds) || $endingEventId <= 0) {
throw new \RuntimeException('InvaderLifecycle failed to create follow-up events');
}
$diplomacyRows = iterator_to_array($db->query(
'SELECT me, you, state, term FROM diplomacy WHERE (me IN %li AND you = %i) OR (me = %i AND you IN %li) ORDER BY me, you',
$invaderNationIds,
$existingNationId,
$existingNationId,
$invaderNationIds,
));
$diplomacyStates = array_values(array_unique(array_map(
static fn(array $row): string => "{$row['state']}:{$row['term']}",
$diplomacyRows,
)));
sort($diplomacyStates);
$generalCounts = array_map(
static fn(int $nationId): int => (int)DB::db()->queryFirstField(
'SELECT count(*) FROM general WHERE nation = %i',
$nationId,
),
$invaderNationIds,
);
$diplomacyCounts = array_map(
static fn(int $nationId): int => (int)DB::db()->queryFirstField(
'SELECT count(*) FROM diplomacy WHERE (me = %i AND you = %i) OR (me = %i AND you = %i)',
$nationId,
$existingNationId,
$existingNationId,
$nationId,
),
$invaderNationIds,
);
$gameStorage = KVStorage::getStorage($db, 'game_env');
$afterRaise = [
'createdNationCount' => count($invaderNationIds),
'createdGeneralCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM general WHERE no > %i',
$generalIdBeforeAction,
),
'followUpEventCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id > %i',
$eventIdBeforeAction,
),
'generalCountsPerNation' => array_values(array_unique($generalCounts)),
'diplomacyCountsPerNation' => array_values(array_unique($diplomacyCounts)),
'diplomacyStates' => $diplomacyStates,
'isunited' => (int)$gameStorage->isunited,
'blockChangeScout' => (bool)$gameStorage->block_change_scout,
];
$warResults = [];
foreach ($autoDeleteEvents as $autoDeleteEvent) {
$warResult = (new \sammo\Event\Action\AutoDeleteInvader($autoDeleteEvent['nationId']))->run([
'year' => $year,
'month' => $month + 1,
'startyear' => $startYear,
'currentEventID' => $autoDeleteEvent['eventId'],
]);
$warResults[] = $warResult[1] ?? null;
}
$atWar = [
'results' => array_values(array_unique($warResults)),
'autoDeleteEventCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id IN %li',
array_column($autoDeleteEvents, 'eventId'),
),
];
$db->update(
'diplomacy',
['state' => 2, 'term' => 0],
'me IN %li OR you IN %li',
$invaderNationIds,
$invaderNationIds,
);
$peaceResults = [];
foreach ($autoDeleteEvents as $autoDeleteEvent) {
$peaceResult = (new \sammo\Event\Action\AutoDeleteInvader($autoDeleteEvent['nationId']))->run([
'year' => $year,
'month' => $month + 2,
'startyear' => $startYear,
'currentEventID' => $autoDeleteEvent['eventId'],
]);
$peaceResults[] = $peaceResult[1] ?? null;
}
$atPeace = [
'results' => array_values(array_unique($peaceResults)),
'autoDeleteEventCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id IN %li',
array_column($autoDeleteEvents, 'eventId'),
),
'rulerWanderTurnCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM general_turn WHERE general_id IN %li AND action = %s',
$rulerIds,
'che_방랑',
),
'endingEventPresent' => (bool)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id = %i',
$endingEventId,
),
];
$invaderGeneralIds = array_map('intval', $db->queryFirstColumn(
'SELECT no FROM general WHERE nation IN %li',
$invaderNationIds,
));
if ($invaderGeneralIds !== []) {
$db->delete('general_turn', 'general_id IN %li', $invaderGeneralIds);
$db->delete('rank_data', 'general_id IN %li', $invaderGeneralIds);
$db->delete('troop', 'nation IN %li', $invaderNationIds);
$db->delete('general', 'no IN %li', $invaderGeneralIds);
}
$db->delete('nation_turn', 'nation_id IN %li', $invaderNationIds);
$db->delete('diplomacy', 'me IN %li OR you IN %li', $invaderNationIds, $invaderNationIds);
$db->delete('nation', 'nation IN %li', $invaderNationIds);
$db->update('city', ['nation' => $existingNationId], true);
$endingResult = (new \sammo\Event\Action\InvaderEnding())->run([
'year' => $year,
'month' => $month + 3,
'startyear' => $startYear,
'currentEventID' => $endingEventId,
]);
$gameStorage->resetCache();
$afterUserWin = [
'result' => $endingResult[1] ?? null,
'endingEventPresent' => (bool)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id = %i',
$endingEventId,
),
'isunited' => (int)$gameStorage->isunited,
'refreshLimit' => (int)$gameStorage->refreshLimit,
'logs' => array_values($db->queryFirstColumn(
'SELECT text FROM world_history WHERE id > %i AND nation_id = 0 AND year = %i AND month = %i ORDER BY id',
$worldHistoryIdBeforeAction,
$year,
$month + 3,
)),
];
return [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => 'InvaderLifecycle',
'phases' => [
'afterRaise' => $afterRaise,
'atWar' => $atWar,
'atPeace' => $atPeace,
'afterUserWin' => $afterUserWin,
],
];
}
/**
* Exercise NPC nation creation and the same-month troop leader follow-up.
*
* @param array<string, mixed> $environment
* @return array<string, mixed>
*/
function comparisonNpcNationLifecycleTrace(
array $environment,
int $generalIdBeforeAction,
int $nationIdBeforeAction,
int $worldHistoryIdBeforeAction,
): array {
$db = DB::db();
$actionEnvironment = [
'year' => $environment['year'],
'month' => $environment['month'],
'startyear' => $environment['startyear'],
'turnterm' => $environment['turnterm'],
'turntime' => $environment['turntime'],
'show_img_level' => $environment['show_img_level'] ?? 3,
'stored_icons' => $environment['stored_icons'] ?? [],
'icon_path' => $environment['icon_path'] ?? '.',
'fiction' => $environment['fiction'] ?? [0],
];
$gameStorage = KVStorage::getStorage($db, 'game_env');
$leaderCounterBefore = (int)($gameStorage->lastNPCTroopLeaderID ?? 0);
(new \sammo\Event\Action\RaiseNPCNation())->run($actionEnvironment);
$createdNationIds = array_map(
'intval',
$db->queryFirstColumn('SELECT nation FROM nation WHERE nation > %i ORDER BY nation', $nationIdBeforeAction),
);
if ($createdNationIds === []) {
throw new \RuntimeException('NpcNationLifecycle failed to create a nation');
}
$createdNationGeneralCounts = array_map(
static fn(int $nationId): int => (int)DB::db()->queryFirstField(
'SELECT count(*) FROM general WHERE nation = %i',
$nationId,
),
$createdNationIds,
);
$afterRaise = [
'createdNationCount' => count($createdNationIds),
'createdGeneralCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM general WHERE no > %i',
$generalIdBeforeAction,
),
'generalCountsPerCreatedNation' => array_values(array_unique($createdNationGeneralCounts)),
'historyLogs' => array_values($db->queryFirstColumn(
'SELECT text FROM world_history WHERE id > %i AND nation_id = 0 ORDER BY id',
$worldHistoryIdBeforeAction,
)),
];
(new \sammo\Event\Action\ProvideNPCTroopLeader())->run($actionEnvironment);
$leaderIds = array_map(
'intval',
$db->queryFirstColumn('SELECT no FROM general WHERE no > %i AND npc = 5 ORDER BY no', $generalIdBeforeAction),
);
if ($leaderIds === []) {
throw new \RuntimeException('NpcNationLifecycle failed to create troop leaders');
}
$leaderNationCounts = array_map(
static fn(int $nationId): int => (int)DB::db()->queryFirstField(
'SELECT count(*) FROM general WHERE nation = %i AND npc = 5',
$nationId,
),
array_map(
'intval',
$db->queryFirstColumn('SELECT nation FROM nation WHERE level > 0 ORDER BY nation'),
),
);
$gatherTurnCounts = array_map(
static fn(int $generalId): int => (int)DB::db()->queryFirstField(
'SELECT count(*) FROM general_turn WHERE general_id = %i AND action = %s',
$generalId,
'che_집합',
),
$leaderIds,
);
$gameStorage->resetCache();
$afterProvide = [
'createdLeaderCount' => count($leaderIds),
'leaderCountsPerActiveNation' => array_values(array_unique($leaderNationCounts)),
'troopCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM troop WHERE troop_leader IN %li',
$leaderIds,
),
'gatherTurnCounts' => array_values(array_unique($gatherTurnCounts)),
'leaderCounterDelta' => (int)$gameStorage->lastNPCTroopLeaderID - $leaderCounterBefore,
];
return [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => 'NpcNationLifecycle',
'phases' => [
'afterRaise' => $afterRaise,
'afterProvide' => $afterProvide,
],
];
}
/**
* Exercise nation betting from monthly open through real user bets and settlement.
*
* @param array<string, mixed> $request
* @param array<string, mixed> $environment
* @return array<string, mixed>
*/
function comparisonNationBettingLifecycleTrace(
array $request,
array $environment,
int $eventIdBeforeAction,
int $worldHistoryIdBeforeAction,
): array {
$db = DB::db();
$args = $request['args'] ?? [];
if (!is_array($args) || count($args) > 2) {
throw new \InvalidArgumentException('NationBettingLifecycle args must have at most two entries');
}
$bettorGeneralIds = comparisonIntegerList(
$request['bettorGeneralIds'] ?? [],
'bettorGeneralIds',
);
$bettorOwnerIds = comparisonIntegerList(
$request['bettorOwnerIds'] ?? [],
'bettorOwnerIds',
);
if (count($bettorGeneralIds) !== 2 || count($bettorOwnerIds) !== 2) {
throw new \InvalidArgumentException(
'NationBettingLifecycle requires exactly two bettorGeneralIds and bettorOwnerIds',
);
}
$year = $environment['year'];
$month = $environment['month'];
$startYear = $environment['startyear'];
(new \sammo\Event\Action\OpenNationBetting(...$args))->run([
'year' => $year,
'month' => $month,
'startyear' => $startYear,
]);
$gameStorage = KVStorage::getStorage($db, 'game_env');
$gameStorage->resetCache();
$bettingId = (int)$gameStorage->last_betting_id;
$betting = new Betting($bettingId);
$bettingInfo = $betting->getInfo();
$candidateNationIds = array_map(
static fn(\sammo\DTO\SelectItem $candidate): int => (int)($candidate->aux['nation'] ?? 0),
$bettingInfo->candidates,
);
if (count($candidateNationIds) !== 2) {
throw new \RuntimeException('NationBettingLifecycle requires exactly two candidates');
}
$finishEventCount = (int)$db->queryFirstField(
'SELECT count(*) FROM event WHERE id > %i AND action LIKE %s',
$eventIdBeforeAction,
"%FinishNationBetting%{$bettingId}%",
);
$afterOpen = [
'bettingId' => $bettingId,
'candidateNationIds' => $candidateNationIds,
'systemBonus' => (int)($db->queryFirstField(
'SELECT amount FROM ng_betting WHERE betting_id = %i AND general_id = 0',
$bettingId,
) ?? 0),
'finishEventCount' => $finishEventCount,
'historyLogs' => array_values($db->queryFirstColumn(
'SELECT text FROM world_history WHERE id > %i AND nation_id = 0 ORDER BY id',
$worldHistoryIdBeforeAction,
)),
];
$betting->bet($bettorGeneralIds[0], $bettorOwnerIds[0], [1], 100);
$betting->bet($bettorGeneralIds[1], $bettorOwnerIds[1], [0], 100);
$afterBets = [
'bets' => array_map(
static fn(array $row): array => [
'generalId' => (int)$row['general_id'],
'ownerId' => $row['user_id'] === null ? null : (int)$row['user_id'],
'selectionKey' => $row['betting_type'],
'amount' => (int)$row['amount'],
],
iterator_to_array($db->query(
'SELECT general_id, user_id, betting_type, amount FROM ng_betting WHERE betting_id = %i ORDER BY general_id',
$bettingId,
)),
),
'inheritancePrevious' => array_map(
static function (int $ownerId): int {
$value = KVStorage::getStorage(DB::db(), "inheritance_{$ownerId}")->getValue('previous');
return is_array($value) ? (int)($value[0] ?? 0) : 0;
},
$bettorOwnerIds,
),
'spentRank' => array_map(
static fn(int $generalId): int => (int)(DB::db()->queryFirstField(
'SELECT value FROM rank_data WHERE general_id = %i AND type = %s',
$generalId,
\sammo\Enums\RankColumn::inherit_point_spent_dynamic->value,
) ?? 0),
$bettorGeneralIds,
),
];
$db->update('nation', ['level' => 0], 'nation = %i', $candidateNationIds[1]);
$finishResult = (new \sammo\Event\Action\FinishNationBetting($bettingId))->run([
'year' => $year,
'month' => $month + 1,
'startyear' => $startYear,
]);
$settledInfo = (new Betting($bettingId))->getInfo();
$afterFinish = [
'result' => $finishResult[1] ?? null,
'finished' => $settledInfo->finished,
'winner' => $settledInfo->winner,
'inheritancePrevious' => array_map(
static function (int $ownerId): int {
$value = KVStorage::getStorage(DB::db(), "inheritance_{$ownerId}")->getValue('previous');
return is_array($value) ? (int)($value[0] ?? 0) : 0;
},
$bettorOwnerIds,
),
'earnedRank' => array_map(
static fn(int $generalId): int => (int)(DB::db()->queryFirstField(
'SELECT value FROM rank_data WHERE general_id = %i AND type = %s',
$generalId,
\sammo\Enums\RankColumn::inherit_point_earned_by_action->value,
) ?? 0),
$bettorGeneralIds,
),
'historyLogs' => array_values($db->queryFirstColumn(
'SELECT text FROM world_history WHERE id > %i AND nation_id = 0 ORDER BY id',
$worldHistoryIdBeforeAction,
)),
];
return [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => 'NationBettingLifecycle',
'phases' => [
'afterOpen' => $afterOpen,
'afterBets' => $afterBets,
'afterFinish' => $afterFinish,
],
];
}
function comparisonMonthlyEventTraceMain(): void
{
try {
$input = stream_get_contents(STDIN);
$request = json_decode($input === '' ? '{}' : $input, true, flags: JSON_THROW_ON_ERROR);
if (!is_array($request)) {
throw new \InvalidArgumentException('request must be an object');
}
$actionName = $request['action'] ?? null;
$supportedActions = [
'UpdateCitySupply',
'UpdateNationLevel',
'RaiseDisaster',
'ProcessSemiAnnual',
'ProcessWarIncome',
'CreateAdminNPC',
'CreateManyNPC',
'RegNPC',
'RegNeutralNPC',
'RaiseNPCNation',
'NpcNationLifecycle',
'RaiseInvader',
'InvaderLifecycle',
'AutoDeleteInvader',
'InvaderEnding',
'ChangeCity',
'ProvideNPCTroopLeader',
'NationBettingLifecycle',
'OpenNationBetting',
'FinishNationBetting',
'BlockScoutAction',
'UnblockScoutAction',
'AssignGeneralSpeciality',
'AddGlobalBetray',
'LostUniqueItem',
'MergeInheritPointRank',
'ProcessIncome',
'NoticeToHistoryLog',
'NewYear',
'ResetOfficerLock',
'PreUpdateMonthly',
'PostUpdateMonthly',
'MonthlyBoundary',
];
if (!in_array($actionName, $supportedActions, true)) {
throw new \InvalidArgumentException('unsupported monthly action');
}
$setup = $request['setup'] ?? [];
if (!is_array($setup)) {
throw new \InvalidArgumentException('setup must be an object');
}
foreach (['city', 'nation', 'general'] as $table) {
$rows = $setup[$table] ?? [];
if (!is_array($rows)) {
throw new \InvalidArgumentException("setup.{$table} must be an array");
}
foreach ($rows as $row) {
if (!is_array($row) || !is_int($row['id'] ?? null) || !is_array($row['values'] ?? null)) {
throw new \InvalidArgumentException("invalid setup.{$table} row");
}
comparisonMonthlyPatch($table, $row['id'], $row['values']);
}
}
if (($setup['resetCities'] ?? false) === true) {
DB::db()->query('UPDATE city SET nation = 0, level = 1');
foreach ($setup['city'] ?? [] as $row) {
comparisonMonthlyPatch('city', $row['id'], $row['values']);
}
}
if (($setup['deleteOtherCities'] ?? false) === true) {
$keepCityIds = comparisonIntegerList($setup['keepCityIds'] ?? [], 'keepCityIds');
if ($keepCityIds === []) {
throw new \InvalidArgumentException('deleteOtherCities requires keepCityIds');
}
DB::db()->query('DELETE FROM city WHERE city NOT IN %li', $keepCityIds);
}
if (($setup['resetGenerals'] ?? false) === true) {
DB::db()->query(
'UPDATE general SET nation = 0, officer_level = 1, npc = 2, killturn = 0, horse = %s, weapon = %s, book = %s, item = %s',
'None',
'None',
'None',
'None',
);
foreach ($setup['general'] ?? [] as $row) {
comparisonMonthlyPatch('general', $row['id'], $row['values']);
}
}
if (($setup['deleteOtherGenerals'] ?? false) === true) {
$keepGeneralIds = comparisonIntegerList($setup['keepGeneralIds'] ?? [], 'keepGeneralIds');
if (!$keepGeneralIds) {
throw new \InvalidArgumentException('deleteOtherGenerals requires keepGeneralIds');
}
DB::db()->query('DELETE FROM general_turn WHERE general_id NOT IN %li', $keepGeneralIds);
DB::db()->query('DELETE FROM rank_data WHERE general_id NOT IN %li', $keepGeneralIds);
DB::db()->query('DELETE FROM general WHERE no NOT IN %li', $keepGeneralIds);
}
if (($setup['resetNations'] ?? false) === true) {
DB::db()->query('UPDATE nation SET level = 0, gennum = 0, tech = 0');
foreach ($setup['nation'] ?? [] as $row) {
comparisonMonthlyPatch('nation', $row['id'], $row['values']);
}
}
if (($setup['deleteOtherNations'] ?? false) === true) {
$keepNationIds = comparisonIntegerList($setup['keepNationIds'] ?? [], 'keepNationIds');
if (!$keepNationIds) {
throw new \InvalidArgumentException('deleteOtherNations requires keepNationIds');
}
DB::db()->query(
'DELETE FROM diplomacy WHERE me NOT IN %li OR you NOT IN %li',
$keepNationIds,
$keepNationIds,
);
DB::db()->query('DELETE FROM nation_turn WHERE nation_id NOT IN %li', $keepNationIds);
DB::db()->query('DELETE FROM nation WHERE nation NOT IN %li', $keepNationIds);
}
if (($setup['resetUniqueOccupancy'] ?? false) === true) {
DB::db()->delete('ng_auction', '`type` = %s AND finished = 0', 'uniqueItem');
DB::db()->query('DELETE FROM storage WHERE namespace LIKE %s', 'ut\\_%');
}
if (($setup['clearNeutralAuctions'] ?? false) === true) {
DB::db()->delete(
'ng_auction',
'`type` IN %ls AND host_general_id = 0',
['buyRice', 'sellRice'],
);
}
foreach (comparisonIntegerList($setup['clearNationTurnIds'] ?? [], 'clearNationTurnIds') as $nationId) {
DB::db()->delete('nation_turn', 'nation_id = %i', $nationId);
}
foreach (comparisonIntegerList($setup['clearInheritanceOwnerIds'] ?? [], 'clearInheritanceOwnerIds') as $ownerId) {
DB::db()->delete('storage', 'namespace = %s', "inheritance_{$ownerId}");
}
if (($setup['clearBetting'] ?? false) === true) {
DB::db()->query('DELETE FROM ng_betting');
DB::db()->query('DELETE FROM storage WHERE namespace = %s', 'betting');
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
$gameStorage->setValue('last_betting_id', 0);
}
foreach ($setup['bettingInfo'] ?? [] as $rawBettingInfo) {
if (!is_array($rawBettingInfo) || !is_int($rawBettingInfo['id'] ?? null)) {
throw new \InvalidArgumentException('invalid setup.bettingInfo row');
}
KVStorage::getStorage(DB::db(), 'betting')->setValue(
"id_{$rawBettingInfo['id']}",
$rawBettingInfo,
);
}
foreach ($setup['bet'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['betting_id'] ?? null)
|| !is_int($row['general_id'] ?? null)
|| !is_string($row['betting_type'] ?? null)
|| !is_int($row['amount'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.bet row');
}
DB::db()->insert('ng_betting', [
'betting_id' => $row['betting_id'],
'general_id' => $row['general_id'],
'user_id' => $row['user_id'] ?? null,
'betting_type' => $row['betting_type'],
'amount' => $row['amount'],
]);
}
foreach ($setup['inheritancePrevious'] ?? [] as $ownerId => $value) {
if (!is_numeric($ownerId) || !is_int($value)) {
throw new \InvalidArgumentException('invalid setup.inheritancePrevious entry');
}
KVStorage::getStorage(DB::db(), "inheritance_{$ownerId}")->setValue('previous', [$value, null]);
}
foreach ($setup['inheritancePoints'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['ownerId'] ?? null)
|| !is_string($row['key'] ?? null)
|| !is_numeric($row['value'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.inheritancePoints row');
}
KVStorage::getStorage(DB::db(), "inheritance_{$row['ownerId']}")->setValue(
$row['key'],
[$row['value'], null],
);
}
foreach ($setup['rankData'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['generalId'] ?? null)
|| !is_string($row['type'] ?? null)
|| !is_int($row['value'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.rankData row');
}
$nationId = (int)(DB::db()->queryFirstField(
'SELECT nation FROM general WHERE no = %i',
$row['generalId'],
) ?? 0);
DB::db()->insertUpdate('rank_data', [
'general_id' => $row['generalId'],
'nation_id' => $nationId,
'type' => $row['type'],
'value' => $row['value'],
], [
'nation_id' => $nationId,
'value' => $row['value'],
]);
}
foreach ($setup['generalAccessLog'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['generalId'] ?? null)
|| !is_int($row['refreshScoreTotal'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.generalAccessLog row');
}
DB::db()->insertUpdate('general_access_log', [
'general_id' => $row['generalId'],
'refresh_score_total' => $row['refreshScoreTotal'],
], [
'refresh_score_total' => $row['refreshScoreTotal'],
]);
}
foreach ($setup['nationEnvironment'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['nationId'] ?? null)
|| !is_string($row['key'] ?? null)
|| !array_key_exists('value', $row)
) {
throw new \InvalidArgumentException('invalid setup.nationEnvironment row');
}
KVStorage::getStorage(DB::db(), $row['nationId'], 'nation_env')->setValue(
$row['key'],
$row['value'],
);
}
if (($setup['resetDiplomacy'] ?? false) === true) {
DB::db()->query('DELETE FROM diplomacy');
}
foreach ($setup['diplomacy'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['fromNationId'] ?? null)
|| !is_int($row['toNationId'] ?? null)
|| !is_int($row['state'] ?? null)
|| !is_int($row['term'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.diplomacy row');
}
$diplomacyPatch = [
'me' => $row['fromNationId'],
'you' => $row['toNationId'],
'state' => $row['state'],
'term' => $row['term'],
'dead' => $row['dead'] ?? 0,
];
DB::db()->insertUpdate('diplomacy', $diplomacyPatch, $diplomacyPatch);
}
if (($setup['resetEvents'] ?? false) === true) {
DB::db()->query('DELETE FROM event');
}
foreach ($setup['event'] ?? [] as $row) {
if (!is_array($row) || !is_int($row['id'] ?? null) || !is_array($row['action'] ?? null)) {
throw new \InvalidArgumentException('invalid setup.event row');
}
$eventPatch = [
'id' => $row['id'],
'target' => $row['target'] ?? 'month',
'priority' => $row['priority'] ?? 1000,
'condition' => Json::encode($row['condition'] ?? true),
'action' => Json::encode($row['action']),
];
DB::db()->insertUpdate('event', $eventPatch, $eventPatch);
}
$gameEnvironmentPatch = $setup['gameEnvironment'] ?? [];
if (!is_array($gameEnvironmentPatch)) {
throw new \InvalidArgumentException('setup.gameEnvironment must be an object');
}
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
$worldPatch = $setup['world'] ?? [];
if (!is_array($worldPatch)) {
throw new \InvalidArgumentException('setup.world must be an object');
}
if (array_key_exists('hiddenSeed', $worldPatch)) {
if (!is_string($worldPatch['hiddenSeed']) || $worldPatch['hiddenSeed'] === '') {
throw new \InvalidArgumentException('setup.world.hiddenSeed must be a non-empty string');
}
UniqueConst::$hiddenSeed = $worldPatch['hiddenSeed'];
}
foreach ([
'isunited',
'refreshLimit',
'block_change_scout',
'lastNPCTroopLeaderID',
'tournament',
'tnmt_trig',
'tnmt_pattern',
'prev_winner',
] as $key) {
if (array_key_exists($key, $gameEnvironmentPatch)) {
$gameStorage->setValue($key, $gameEnvironmentPatch[$key]);
}
}
if (($setup['setAllCitiesNation'] ?? null) !== null) {
if (!is_int($setup['setAllCitiesNation'])) {
throw new \InvalidArgumentException('setup.setAllCitiesNation must be an integer');
}
DB::db()->update('city', ['nation' => $setup['setAllCitiesNation']], true);
}
$db = DB::db();
$generalIdBeforeAction =
(int)($db->queryFirstField('SELECT COALESCE(MAX(no), 0) FROM general') ?? 0);
$nationIdBeforeAction =
(int)($db->queryFirstField('SELECT COALESCE(MAX(nation), 0) FROM nation') ?? 0);
$eventIdBeforeAction =
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM event') ?? 0);
$auctionIdBeforeAction =
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM ng_auction') ?? 0);
$snapshotRequest = ['observe' => $request['observe'] ?? []];
$snapshotRequest['observe']['logAfterId'] =
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM general_record') ?? 0);
$worldHistoryAfterId =
(int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM world_history') ?? 0);
$before = comparisonTurnStateSnapshot($snapshotRequest);
$beforeDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
$environment = $request['environment'] ?? [];
if (!is_array($environment)) {
throw new \InvalidArgumentException('environment must be an object');
}
$year = $environment['year'] ?? null;
$month = $environment['month'] ?? null;
$startYear = $environment['startyear'] ?? null;
if (!is_int($year) || !is_int($month) || !is_int($startYear)) {
throw new \InvalidArgumentException('environment year, month, and startyear must be integers');
}
if (($setup['syncEnvironment'] ?? false) === true) {
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
$environmentValues = [
'year' => $year,
'month' => $month,
'startyear' => $startYear,
'killturn' => $environment['killturn'] ?? $gameStorage->killturn,
'turnterm' => $environment['turnterm'] ?? $gameStorage->turnterm,
];
if (isset($environment['starttime'])) {
if (!is_string($environment['starttime']) || $environment['starttime'] === '') {
throw new \InvalidArgumentException('environment.starttime must be a non-empty string');
}
$environmentValues['starttime'] = $environment['starttime'];
}
foreach ($environmentValues as $key => $value) {
$gameStorage->setValue($key, $value);
}
if ($actionName === 'MonthlyBoundary') {
$before = comparisonTurnStateSnapshot($snapshotRequest);
$beforeDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
}
}
if ($actionName === 'InvaderLifecycle') {
foreach (['turnterm', 'turntime'] as $requiredEnvironmentKey) {
if (!array_key_exists($requiredEnvironmentKey, $environment)) {
throw new \InvalidArgumentException(
"InvaderLifecycle requires environment.{$requiredEnvironmentKey}",
);
}
}
echo json_encode(
comparisonInvaderLifecycleTrace(
$request,
$environment,
$generalIdBeforeAction,
$nationIdBeforeAction,
$eventIdBeforeAction,
$worldHistoryAfterId,
),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
return;
}
if ($actionName === 'NpcNationLifecycle') {
foreach (['turnterm', 'turntime'] as $requiredEnvironmentKey) {
if (!array_key_exists($requiredEnvironmentKey, $environment)) {
throw new \InvalidArgumentException(
"NpcNationLifecycle requires environment.{$requiredEnvironmentKey}",
);
}
}
echo json_encode(
comparisonNpcNationLifecycleTrace(
$environment,
$generalIdBeforeAction,
$nationIdBeforeAction,
$worldHistoryAfterId,
),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
return;
}
if ($actionName === 'NationBettingLifecycle') {
echo json_encode(
comparisonNationBettingLifecycleTrace(
$request,
$environment,
$eventIdBeforeAction,
$worldHistoryAfterId,
),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
return;
}
$actionClass = "\\sammo\\Event\\Action\\{$actionName}";
if (in_array($actionName, ['PreUpdateMonthly', 'PostUpdateMonthly', 'MonthlyBoundary'], true)) {
$action = null;
} elseif ($actionName === 'ProcessSemiAnnual') {
$resource = $request['resource'] ?? null;
if (!is_string($resource)) {
throw new \InvalidArgumentException('ProcessSemiAnnual requires resource');
}
$action = new $actionClass($resource);
} elseif (in_array($actionName, ['CreateManyNPC', 'RegNPC', 'RegNeutralNPC', 'RaiseInvader', 'AutoDeleteInvader', 'ChangeCity', 'OpenNationBetting', 'FinishNationBetting', 'BlockScoutAction', 'UnblockScoutAction', 'AddGlobalBetray', 'LostUniqueItem', 'ProcessIncome', 'NoticeToHistoryLog'], true)) {
$args = $request['args'] ?? [];
if (!is_array($args)) {
throw new \InvalidArgumentException("{$actionName} args must be an array");
}
if ($actionName === 'CreateManyNPC' && count($args) > 2) {
throw new \InvalidArgumentException('CreateManyNPC args must have at most two entries');
}
if ($actionName === 'RaiseInvader' && count($args) > 4) {
throw new \InvalidArgumentException('RaiseInvader args must have at most four entries');
}
if ($actionName === 'ChangeCity' && count($args) !== 2) {
throw new \InvalidArgumentException('ChangeCity args must have exactly two entries');
}
if ($actionName === 'OpenNationBetting' && count($args) > 2) {
throw new \InvalidArgumentException('OpenNationBetting args must have at most two entries');
}
if ($actionName === 'FinishNationBetting' && count($args) !== 1) {
throw new \InvalidArgumentException('FinishNationBetting args must have exactly one entry');
}
if (in_array($actionName, ['BlockScoutAction', 'UnblockScoutAction'], true) && count($args) > 1) {
throw new \InvalidArgumentException("{$actionName} args must have at most one entry");
}
if ($actionName === 'AddGlobalBetray' && count($args) > 2) {
throw new \InvalidArgumentException('AddGlobalBetray args must have at most two entries');
}
if ($actionName === 'LostUniqueItem' && count($args) > 1) {
throw new \InvalidArgumentException('LostUniqueItem args must have at most one entry');
}
if ($actionName === 'ProcessIncome' && count($args) !== 1) {
throw new \InvalidArgumentException('ProcessIncome args must have exactly one entry');
}
if ($actionName === 'NoticeToHistoryLog' && (count($args) < 1 || count($args) > 2)) {
throw new \InvalidArgumentException('NoticeToHistoryLog args must have one or two entries');
}
$action = new $actionClass(...$args);
} else {
$action = new $actionClass();
}
$actionEnvironment = [
'year' => $year,
'month' => $month,
'startyear' => $startYear,
];
if (isset($environment['currentEventID'])) {
if (!is_int($environment['currentEventID'])) {
throw new \InvalidArgumentException('currentEventID must be an integer');
}
$actionEnvironment['currentEventID'] = $environment['currentEventID'];
}
if ($actionName === 'UpdateNationLevel') {
$killturn = $environment['killturn'] ?? null;
$turnterm = $environment['turnterm'] ?? null;
if (!is_int($killturn) || !is_int($turnterm) || $turnterm <= 0) {
throw new \InvalidArgumentException('UpdateNationLevel requires integer killturn and positive turnterm');
}
$actionEnvironment['killturn'] = $killturn;
$actionEnvironment['turnterm'] = $turnterm;
}
if (in_array($actionName, ['CreateManyNPC', 'RegNPC', 'RegNeutralNPC', 'RaiseNPCNation', 'RaiseInvader', 'ProvideNPCTroopLeader'], true)) {
$turnterm = $environment['turnterm'] ?? null;
$turntime = $environment['turntime'] ?? null;
$showImgLevel = $environment['show_img_level'] ?? 3;
$fiction = $environment['fiction'] ?? [0];
if (
!is_int($turnterm)
|| $turnterm <= 0
|| !is_string($turntime)
|| !is_int($showImgLevel)
|| !is_array($fiction)
) {
throw new \InvalidArgumentException(
"{$actionName} requires positive turnterm, string turntime, integer show_img_level, and array fiction",
);
}
$actionEnvironment += [
'turnterm' => $turnterm,
'turntime' => $turntime,
'show_img_level' => $showImgLevel,
'stored_icons' => $environment['stored_icons'] ?? [],
'icon_path' => $environment['icon_path'] ?? '.',
'fiction' => $fiction,
];
}
if ($actionName === 'PreUpdateMonthly') {
if (!preUpdateMonthly()) {
throw new \RuntimeException('preUpdateMonthly failed');
}
} elseif ($actionName === 'PostUpdateMonthly') {
$seedYear = $environment['seedYear'] ?? null;
$seedMonth = $environment['seedMonth'] ?? null;
if (!is_int($seedYear) || !is_int($seedMonth)) {
throw new \InvalidArgumentException('PostUpdateMonthly requires seedYear and seedMonth');
}
postUpdateMonthly(new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'monthly',
$seedYear,
$seedMonth,
))));
} elseif ($actionName === 'MonthlyBoundary') {
$turntime = $environment['turntime'] ?? null;
if (!is_string($turntime) || $turntime === '') {
throw new \InvalidArgumentException('MonthlyBoundary requires turntime');
}
$gameStorage = KVStorage::getStorage($db, 'game_env');
$seedYear = (int)$gameStorage->year;
$seedMonth = (int)$gameStorage->month;
TurnExecutionHelper::runEventHandler($db, $gameStorage, Enums\EventTarget::PreMonth);
if (!preUpdateMonthly()) {
throw new \RuntimeException('preUpdateMonthly failed');
}
turnDate($turntime);
$gameStorage->resetCache();
if ((int)$gameStorage->month === 1) {
checkStatistic();
}
TurnExecutionHelper::runEventHandler($db, $gameStorage, Enums\EventTarget::Month);
postUpdateMonthly(new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'monthly',
$seedYear,
$seedMonth,
))));
} else {
$action->run($actionEnvironment);
}
unset($action);
gc_collect_cycles();
$after = comparisonTurnStateSnapshot($snapshotRequest);
$afterDetails = comparisonMonthlyDetails($snapshotRequest['observe'], $worldHistoryAfterId);
$createdGenerals = [];
if (in_array($actionName, ['CreateManyNPC', 'RegNPC', 'RegNeutralNPC', 'RaiseNPCNation', 'RaiseInvader', 'ProvideNPCTroopLeader'], true)) {
foreach ($db->query('SELECT * FROM general WHERE no > %i ORDER BY no', $generalIdBeforeAction) as $row) {
$generalId = (int)$row['no'];
$turnRows = $db->query(
'SELECT turn_idx, action, arg FROM general_turn WHERE general_id = %i ORDER BY turn_idx',
$generalId,
);
$createdGenerals[] = comparisonPickRow(
$row,
[
'id' => 'no',
'name' => 'name',
'nationId' => 'nation',
'cityId' => 'city',
'leadership' => 'leadership',
'strength' => 'strength',
'intelligence' => 'intel',
'experience' => 'experience',
'dedication' => 'dedication',
'officerLevel' => 'officer_level',
'gold' => 'gold',
'rice' => 'rice',
'crew' => 'crew',
'crewTypeId' => 'crewtype',
'train' => 'train',
'atmos' => 'atmos',
'turnTime' => 'turntime',
'killturn' => 'killturn',
'age' => 'age',
'npcState' => 'npc',
'npcOriginalState' => 'npc_org',
'affinity' => 'affinity',
'personality' => 'personal',
'specialDomestic' => 'special',
'specialWar' => 'special2',
'specAge' => 'specage',
'specAge2' => 'specage2',
'bornYear' => 'bornyear',
'deadYear' => 'deadyear',
'picture' => 'picture',
'dex1' => 'dex1',
'dex2' => 'dex2',
'dex3' => 'dex3',
'dex4' => 'dex4',
'dex5' => 'dex5',
],
) + [
'turnCount' => count($turnRows),
'turnActions' => array_values(array_unique(array_column($turnRows, 'action'))),
'rankCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM rank_data WHERE general_id = %i',
$generalId,
),
'nonZeroRankCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM rank_data WHERE general_id = %i AND value != 0',
$generalId,
),
'troop' => $db->queryFirstRow(
'SELECT troop_leader AS id, nation AS nationId, name FROM troop WHERE troop_leader = %i',
$generalId,
) ?: null,
];
}
}
$createdNations = [];
if (in_array($actionName, ['RaiseNPCNation', 'RaiseInvader'], true)) {
foreach ($db->query('SELECT * FROM nation WHERE nation > %i ORDER BY nation', $nationIdBeforeAction) as $row) {
$nationId = (int)$row['nation'];
$createdNations[] = comparisonPickRow(
$row,
[
'id' => 'nation',
'name' => 'name',
'color' => 'color',
'capitalCityId' => 'capital',
'generalCount' => 'gennum',
'gold' => 'gold',
'rice' => 'rice',
'tech' => 'tech',
'level' => 'level',
'typeCode' => 'type',
'bill' => 'bill',
'rate' => 'rate',
'scout' => 'scout',
'war' => 'war',
'strategicCommandLimit' => 'strategic_cmd_limit',
'surrenderLimit' => 'surlimit',
'aux' => 'aux',
],
['aux'],
) + [
'nationTurnCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM nation_turn WHERE nation_id = %i',
$nationId,
),
'diplomacyCount' => (int)$db->queryFirstField(
'SELECT count(*) FROM diplomacy WHERE me = %i OR you = %i',
$nationId,
$nationId,
),
];
}
}
$response = [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => $actionName,
'before' => $before,
'beforeDetails' => $beforeDetails,
'after' => $after,
'afterDetails' => $afterDetails,
];
if (in_array($actionName, ['CreateManyNPC', 'RegNPC', 'RegNeutralNPC'], true)) {
$response['createdGenerals'] = $createdGenerals;
}
if (in_array($actionName, ['RaiseNPCNation', 'RaiseInvader'], true)) {
$response['createdGenerals'] = $createdGenerals;
$response['createdNations'] = $createdNations;
}
if ($actionName === 'ProvideNPCTroopLeader') {
$response['createdGenerals'] = $createdGenerals;
$response['gameEnvironment'] = KVStorage::getStorage(DB::db(), 'game_env')->getValues([
'lastNPCTroopLeaderID',
]);
}
if ($actionName === 'PreUpdateMonthly') {
$response['gameEnvironment'] = KVStorage::getStorage(DB::db(), 'game_env')->getValues([
'develcost',
]);
}
if ($actionName === 'PostUpdateMonthly') {
$response['gameEnvironment'] = KVStorage::getStorage(DB::db(), 'game_env')->getValues([
'tournament',
'tnmt_trig',
'tnmt_pattern',
'tnmt_type',
'tnmt_auto',
'phase',
]);
$response['createdNeutralAuctions'] = array_map(
static fn(array $row): array => [
'id' => (int)$row['id'],
'type' => $row['type'],
'target' => $row['target'],
'detail' => Json::decode($row['detail']),
],
iterator_to_array(
$db->query(
'SELECT id, `type`, target, detail FROM ng_auction WHERE id > %i AND host_general_id = 0 ORDER BY id',
$auctionIdBeforeAction,
),
),
);
}
if (in_array($actionName, ['OpenNationBetting', 'FinishNationBetting'], true)) {
$bettingStorage = KVStorage::getStorage(DB::db(), 'betting');
$response['betting'] = $bettingStorage->getAll();
$response['bets'] = iterator_to_array(
$db->query(
'SELECT betting_id AS bettingId, general_id AS generalId, user_id AS userId, betting_type AS selectionKey, amount FROM ng_betting ORDER BY id',
),
);
$response['createdEvents'] = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'id',
'targetCode' => 'target',
'priority' => 'priority',
'condition' => 'condition',
'action' => 'action',
],
['condition', 'action'],
),
iterator_to_array(
$db->query(
'SELECT id, target, priority, `condition`, action FROM event WHERE id > %i ORDER BY id',
$eventIdBeforeAction,
),
),
);
$response['gameEnvironment'] = KVStorage::getStorage(DB::db(), 'game_env')->getValues([
'last_betting_id',
]);
$response['inheritancePrevious'] = [];
foreach (comparisonIntegerList($request['observe']['ownerIds'] ?? [], 'ownerIds') as $ownerId) {
$value = KVStorage::getStorage(DB::db(), "inheritance_{$ownerId}")->getValue('previous');
$response['inheritancePrevious'][(string)$ownerId] = is_array($value) ? ($value[0] ?? 0) : 0;
}
}
if (in_array($actionName, ['BlockScoutAction', 'UnblockScoutAction'], true)) {
$response['gameEnvironment'] = KVStorage::getStorage(DB::db(), 'game_env')->getValues([
'block_change_scout',
]);
}
if ($actionName === 'RaiseInvader') {
$response['createdEvents'] = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'id',
'targetCode' => 'target',
'priority' => 'priority',
'condition' => 'condition',
'action' => 'action',
],
['condition', 'action'],
),
iterator_to_array(
$db->query(
'SELECT id, target, priority, `condition`, action FROM event WHERE id > %i ORDER BY id',
$eventIdBeforeAction,
),
),
);
$response['createdDiplomacy'] = iterator_to_array(
$db->query(
'SELECT me AS fromNationId, you AS toNationId, state, term FROM diplomacy WHERE me > %i OR you > %i ORDER BY me, you',
$nationIdBeforeAction,
$nationIdBeforeAction,
),
);
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
$response['gameEnvironment'] = $gameStorage->getValues([
'isunited',
'turnterm',
'block_change_scout',
'refreshLimit',
]);
}
if (in_array($actionName, ['AutoDeleteInvader', 'InvaderEnding'], true)) {
$gameStorage = KVStorage::getStorage(DB::db(), 'game_env');
$response['gameEnvironment'] = $gameStorage->getValues([
'isunited',
'turnterm',
'block_change_scout',
'refreshLimit',
]);
}
if (($request['compactOutput'] ?? false) === true) {
$observedGeneralTurns = [];
foreach (comparisonIntegerList($request['observe']['generalIds'] ?? [], 'generalIds') as $generalId) {
$observedGeneralTurns[(string)$generalId] = iterator_to_array(
$db->query(
'SELECT turn_idx AS turnIndex, action, arg FROM general_turn WHERE general_id = %i ORDER BY turn_idx',
$generalId,
),
);
}
$response = [
'schemaVersion' => 1,
'engine' => 'ref',
'action' => $actionName,
'afterDetails' => $afterDetails,
'createdGeneralCount' => count($createdGenerals),
'firstCreatedGenerals' => array_slice($createdGenerals, 0, 3),
'createdNations' => $response['createdNations'] ?? [],
'createdEvents' => $response['createdEvents'] ?? [],
'createdDiplomacy' => $response['createdDiplomacy'] ?? [],
'gameEnvironment' => $response['gameEnvironment'] ?? [],
'logs' => $after['logs'],
'observedGeneralTurns' => $observedGeneralTurns,
'remainingEventIds' => array_map(
'intval',
$db->queryFirstColumn('SELECT id FROM event ORDER BY id'),
),
];
}
echo json_encode(
$response,
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
} catch (\Throwable $throwable) {
fwrite(STDERR, $throwable::class . ': ' . $throwable->getMessage() . PHP_EOL);
exit(1);
}
}
comparisonMonthlyEventTraceMain();
+40
View File
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace sammo;
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
require_once 'lib.php';
require_once 'func.php';
$groups = [
'nation' => ['ActionNationType', 'ActionNationType'],
'domestic' => ['ActionSpecialDomestic', 'ActionSpecialDomestic'],
'war' => ['ActionSpecialWar', 'ActionSpecialWar'],
'personality' => ['ActionPersonality', 'ActionPersonality'],
];
$result = [];
foreach ($groups as $kind => [$directory, $namespace]) {
foreach (glob(__DIR__ . "/../sammo/{$directory}/*.php") ?: [] as $path) {
$key = basename($path, '.php');
if ($key === 'None' || str_starts_with($key, 'che_event_') || $key === 'che_거상') {
continue;
}
$className = "\\sammo\\{$namespace}\\{$key}";
$trait = new $className();
$result[$kind][$key] = [
'name' => $trait->getName(),
'info' => $trait->getInfo(),
];
}
ksort($result[$kind]);
}
echo Json::encode($result);
+804
View File
@@ -0,0 +1,804 @@
<?php
declare(strict_types=1);
namespace sammo;
use sammo\Enums\RankColumn;
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
$_SERVER['REMOTE_ADDR'] ??= '127.0.0.1';
error_reporting(E_ALL & ~E_DEPRECATED);
require_once 'lib.php';
require_once 'func.php';
require_once __DIR__ . '/turn_state_snapshot.php';
final class TurnComparisonTracingRNG implements RNG
{
private int $sequence = 0;
/** @var list<array<string, mixed>> */
public array $calls = [];
public function __construct(private readonly RNG $inner)
{
}
public static function getMaxInt(): int
{
return LiteHashDRBG::getMaxInt();
}
public function nextBytes(int $bytes): string
{
$value = $this->inner->nextBytes($bytes);
$this->record('nextBytes', ['bytes' => $bytes], bin2hex($value));
return $value;
}
public function nextBits(int $bits): string
{
$value = $this->inner->nextBits($bits);
$this->record('nextBits', ['bits' => $bits], bin2hex($value));
return $value;
}
public function nextInt(?int $max = null): int
{
$value = $this->inner->nextInt($max);
$this->record('nextInt', ['maxInclusive' => $max], $value);
return $value;
}
public function nextFloat1(): float
{
$value = $this->inner->nextFloat1();
$this->record('nextFloat1', [], $value);
return $value;
}
private function record(string $operation, array $arguments, mixed $result): void
{
$this->calls[] = [
'seq' => $this->sequence++,
'operation' => $operation,
'arguments' => $arguments === [] ? (object)[] : $arguments,
'result' => $result,
];
}
}
/** @return array<string, mixed> */
function comparisonMappedPatch(array $row, array $mapping): array
{
$patch = [];
foreach ($mapping as $canonical => $legacy) {
if (array_key_exists($canonical, $row)) {
$patch[$legacy] = $row[$canonical];
}
}
return $patch;
}
function comparisonApplyTurnFixtureSetup(mixed $setup): void
{
if ($setup === null) {
return;
}
if (!is_array($setup)) {
throw new \InvalidArgumentException('setup must be an object');
}
$db = DB::db();
$world = $setup['world'] ?? null;
if ($world !== null) {
if (!is_array($world)) {
throw new \InvalidArgumentException('setup.world must be an object');
}
$game = KVStorage::getStorage($db, 'game_env');
foreach (['year', 'month', 'startyear', 'init_year', 'init_month'] as $key) {
$fixtureKey = match ($key) {
'startyear' => 'startYear',
'init_year' => 'initYear',
'init_month' => 'initMonth',
default => $key,
};
if (!array_key_exists($fixtureKey, $world)) {
continue;
}
$value = $world[$fixtureKey];
if (
!is_int($value)
|| $value < 1
|| (in_array($key, ['month', 'init_month'], true) && $value > 12)
) {
throw new \InvalidArgumentException("setup.world.{$fixtureKey} is invalid");
}
$game->setValue($key, $value);
}
$game->resetCache();
if (array_key_exists('hiddenSeed', $world)) {
$hiddenSeed = $world['hiddenSeed'];
if (!is_string($hiddenSeed) || $hiddenSeed === '' || strlen($hiddenSeed) > 256) {
throw new \InvalidArgumentException('setup.world.hiddenSeed is invalid');
}
UniqueConst::$hiddenSeed = $hiddenSeed;
}
// 비교 fixture는 전역 상태에 의존하지 않도록 effect 기본값을 null로 고정하고,
// 명시된 경우에만 해당 effect를 활성화합니다.
GameConst::$scenarioEffect = null;
if (array_key_exists('scenarioEffect', $world)) {
$scenarioEffect = $world['scenarioEffect'];
if ($scenarioEffect === '' || $scenarioEffect === 'None') {
$scenarioEffect = null;
}
if ($scenarioEffect !== null) {
if (!is_string($scenarioEffect) || getScenarioEffectClass($scenarioEffect) === null) {
throw new \InvalidArgumentException('setup.world.scenarioEffect is invalid');
}
}
GameConst::$scenarioEffect = $scenarioEffect;
}
if (array_key_exists('staticEventHandlers', $world)) {
$handlersByEvent = $world['staticEventHandlers'];
if (!is_array($handlersByEvent)) {
throw new \InvalidArgumentException('setup.world.staticEventHandlers must be an object');
}
foreach ($handlersByEvent as $eventType => $handlers) {
if (!is_string($eventType) || $eventType === '' || !is_array($handlers)) {
throw new \InvalidArgumentException('setup.world.staticEventHandlers is invalid');
}
foreach ($handlers as $handler) {
if (!is_string($handler) || $handler === '') {
throw new \InvalidArgumentException('setup.world.staticEventHandlers is invalid');
}
}
}
GameConst::$staticEventHandlers = $handlersByEvent;
}
}
foreach (['nations', 'cities', 'generals', 'troops', 'diplomacy'] as $collection) {
if (isset($setup[$collection]) && !is_array($setup[$collection])) {
throw new \InvalidArgumentException("setup.{$collection} must be an array");
}
}
$generalCooldowns = comparisonGeneralCooldownSelectors(
$setup['generalCooldowns'] ?? [],
'setup.generalCooldowns',
);
if ($generalCooldowns !== []) {
$nextExecuteStorage = KVStorage::getStorage($db, 'next_execute');
foreach ($setup['generalCooldowns'] as $entry) {
$nextAvailableTurn = $entry['nextAvailableTurn'] ?? null;
if (!is_int($nextAvailableTurn) || $nextAvailableTurn < 0) {
throw new \InvalidArgumentException(
'setup.generalCooldowns entries require a non-negative nextAvailableTurn',
);
}
$key = "next_execute_{$entry['generalId']}_{$entry['actionName']}";
$nextExecuteStorage->setValue($key, $nextAvailableTurn);
}
$nextExecuteStorage->resetCache();
}
if (isset($setup['randomFoundingCandidateCityIds'])) {
$candidateCityIds = comparisonIntegerList(
$setup['randomFoundingCandidateCityIds'],
'randomFoundingCandidateCityIds',
);
$db->update('city', ['level' => 4], '1 = 1');
if ($candidateCityIds !== []) {
$db->update('city', ['level' => 5], 'city IN %li', $candidateCityIds);
}
}
if (($setup['isolateWorld'] ?? false) === true) {
$generalIds = array_values(array_map(
static fn(array $row): int => (int)$row['id'],
$setup['generals'] ?? [],
));
$nationIds = array_values(array_map(
static fn(array $row): int => (int)$row['id'],
$setup['nations'] ?? [],
));
if ($generalIds === [] || $nationIds === []) {
throw new \InvalidArgumentException('isolateWorld requires generals and nations');
}
$generalTemplate = $db->queryFirstRow(
'SELECT * FROM general WHERE no IN %li ORDER BY no LIMIT 1',
$generalIds,
);
if ($generalTemplate === null) {
throw new \InvalidArgumentException('isolateWorld requires at least one existing fixture general');
}
$generalTemplateId = (int)$generalTemplate['no'];
$rankDataTemplate = $db->query(
'SELECT `type`, `value` FROM rank_data WHERE general_id = %i',
$generalTemplateId,
);
$db->delete('general_turn', 'general_id NOT IN %li', $generalIds);
$db->delete('rank_data', 'general_id NOT IN %li', $generalIds);
$db->delete('nation_turn', 'nation_id NOT IN %li', $nationIds);
$db->delete('troop', '1 = 1');
$db->delete('diplomacy', '1 = 1');
$db->delete('general', 'no NOT IN %li', $generalIds);
foreach ($generalIds as $generalId) {
if ($db->queryFirstField('SELECT no FROM general WHERE no = %i', $generalId) !== null) {
continue;
}
$newGeneral = $generalTemplate;
$newGeneral['no'] = $generalId;
$newGeneral['owner'] = 0;
$newGeneral['name'] = "fixture-general-{$generalId}";
$db->insert('general', $newGeneral);
}
foreach ($generalIds as $generalId) {
foreach ($rankDataTemplate as $rankRow) {
$rankData = [
'general_id' => $generalId,
'type' => $rankRow['type'],
'value' => $rankRow['value'],
];
$db->insertUpdate('rank_data', $rankData, $rankData);
}
}
$db->delete('nation', 'nation NOT IN %li', $nationIds);
$db->update('city', [
'nation' => 0,
'supply' => 0,
'front' => 0,
'state' => 0,
'term' => 0,
'conflict' => '{}',
'officer_set' => 0,
], '1 = 1');
}
foreach ($setup['nations'] ?? [] as $row) {
if (!is_array($row) || !is_int($row['id'] ?? null) || $row['id'] < 1) {
throw new \InvalidArgumentException('setup.nations requires positive integer ids');
}
$data = comparisonMappedPatch($row, [
'id' => 'nation',
'name' => 'name',
'color' => 'color',
'capitalCityId' => 'capital',
'gold' => 'gold',
'rice' => 'rice',
'tech' => 'tech',
'level' => 'level',
'typeCode' => 'type',
'war' => 'war',
'diplomacyLimit' => 'surlimit',
'generalCount' => 'gennum',
'power' => 'power',
'capitalRevision' => 'capset',
'strategicCommandLimit' => 'strategic_cmd_limit',
]);
if (isset($row['meta'])) {
$data['aux'] = Json::encode($row['meta']);
}
$data += [
'name' => "fixture-nation-{$row['id']}",
'color' => '#777777',
'capital' => 0,
'gold' => 0,
'rice' => 0,
'level' => 1,
'type' => 'che_중립',
'aux' => '{}',
];
$db->insertUpdate('nation', $data, $data);
$nationStor = KVStorage::getStorage($db, $row['id'], 'nation_env');
if (($setup['isolateWorld'] ?? false) === true) {
$nationStor->deleteValue('recv_assist');
$nationStor->deleteValue('resp_assist');
}
if (array_key_exists('nationEnv', $row)) {
if (!is_array($row['nationEnv'])) {
throw new \InvalidArgumentException('setup.nations.nationEnv must be an object');
}
foreach ($row['nationEnv'] as $key => $value) {
if (!is_string($key) || $key === '') {
throw new \InvalidArgumentException('setup.nations.nationEnv keys must be non-empty strings');
}
$nationStor->setValue($key, $value);
}
$nationStor->resetCache();
}
if (array_key_exists('turnLastByOfficerLevel', $row)) {
$turnLastByOfficerLevel = $row['turnLastByOfficerLevel'];
if (!is_array($turnLastByOfficerLevel)) {
throw new \InvalidArgumentException('setup.nations.turnLastByOfficerLevel must be an object');
}
foreach ($turnLastByOfficerLevel as $officerLevel => $lastTurn) {
$officerLevel = filter_var($officerLevel, FILTER_VALIDATE_INT);
if (
$officerLevel === false
|| $officerLevel < 5
|| $officerLevel > 12
|| !is_array($lastTurn)
) {
throw new \InvalidArgumentException(
'setup.nations.turnLastByOfficerLevel requires officer levels 5 through 12'
);
}
$nationStor->setValue("turn_last_{$officerLevel}", $lastTurn);
}
$nationStor->resetCache();
}
}
if (($setup['isolateWorld'] ?? false) === true && ($setup['nations'] ?? []) !== []) {
$maxNationId = max(array_map(
static fn(array $row): int => (int)$row['id'],
$setup['nations'],
));
$db->query('ALTER TABLE nation AUTO_INCREMENT = %i', $maxNationId + 1);
}
foreach ($setup['cities'] ?? [] as $row) {
if (!is_array($row) || !is_int($row['id'] ?? null) || $row['id'] < 1) {
throw new \InvalidArgumentException('setup.cities requires positive integer ids');
}
$patch = comparisonMappedPatch($row, [
'nationId' => 'nation',
'level' => 'level',
'population' => 'pop',
'populationMax' => 'pop_max',
'agriculture' => 'agri',
'agricultureMax' => 'agri_max',
'commerce' => 'comm',
'commerceMax' => 'comm_max',
'security' => 'secu',
'securityMax' => 'secu_max',
'supplyState' => 'supply',
'frontState' => 'front',
'defence' => 'def',
'defenceMax' => 'def_max',
'wall' => 'wall',
'wallMax' => 'wall_max',
'state' => 'state',
'term' => 'term',
'trust' => 'trust',
'trade' => 'trade',
'officerSet' => 'officer_set',
]);
if (array_key_exists('conflictEntries', $row)) {
if (!is_array($row['conflictEntries'])) {
throw new \InvalidArgumentException('setup.cities.conflictEntries must be an array');
}
$orderedConflict = [];
foreach ($row['conflictEntries'] as $entry) {
if (
!is_array($entry)
|| count($entry) !== 2
|| !is_int($entry[0] ?? null)
|| $entry[0] < 1
|| !is_numeric($entry[1] ?? null)
) {
throw new \InvalidArgumentException(
'setup.cities.conflictEntries requires [positive nation id, numeric value] pairs'
);
}
$orderedConflict[$entry[0]] = $entry[1];
}
$patch['conflict'] = Json::encode($orderedConflict);
} elseif (array_key_exists('conflict', $row)) {
if (!is_array($row['conflict'])) {
throw new \InvalidArgumentException('setup.cities.conflict must be an object');
}
$patch['conflict'] = Json::encode($row['conflict']);
}
if ($patch !== []) {
$db->update('city', $patch, 'city = %i', $row['id']);
}
}
foreach ($setup['generals'] ?? [] as $row) {
if (!is_array($row) || !is_int($row['id'] ?? null) || $row['id'] < 1) {
throw new \InvalidArgumentException('setup.generals requires positive integer ids');
}
$patch = comparisonMappedPatch($row, [
'name' => 'name',
'nationId' => 'nation',
'cityId' => 'city',
'troopId' => 'troop',
'leadership' => 'leadership',
'strength' => 'strength',
'intelligence' => 'intel',
'leadershipExp' => 'leadership_exp',
'strengthExp' => 'strength_exp',
'intelExp' => 'intel_exp',
'experience' => 'experience',
'dedication' => 'dedication',
'expLevel' => 'explevel',
'officerLevel' => 'officer_level',
'officerCityId' => 'officer_city',
'belong' => 'belong',
'permission' => 'permission',
'betray' => 'betray',
'makeLimit' => 'makelimit',
'injury' => 'injury',
'age' => 'age',
'gold' => 'gold',
'rice' => 'rice',
'crew' => 'crew',
'crewTypeId' => 'crewtype',
'train' => 'train',
'atmos' => 'atmos',
'dex1' => 'dex1',
'dex2' => 'dex2',
'dex3' => 'dex3',
'dex4' => 'dex4',
'dex5' => 'dex5',
'specAge' => 'specage',
'specAge2' => 'specage2',
'killTurn' => 'killturn',
'npcState' => 'npc',
'blockState' => 'block',
'specialDomestic' => 'special',
'specialWar' => 'special2',
'personality' => 'personal',
'itemHorse' => 'horse',
'itemWeapon' => 'weapon',
'itemBook' => 'book',
'itemExtra' => 'item',
]);
if (isset($row['meta'])) {
$patch['aux'] = Json::encode($row['meta']);
}
if (array_key_exists('penalty', $row)) {
if (!is_array($row['penalty'])) {
throw new \InvalidArgumentException('setup.generals.penalty must be an object');
}
$patch['penalty'] = Json::encode($row['penalty']);
}
if (isset($row['lastTurn']) && is_array($row['lastTurn'])) {
$patch['last_turn'] = Json::encode($row['lastTurn']);
}
if ($patch !== []) {
$db->update('general', $patch, 'no = %i', $row['id']);
}
if (array_key_exists('nationId', $row)) {
$db->update('rank_data', [
'nation_id' => $row['nationId'],
], 'general_id = %i', $row['id']);
}
}
foreach ($setup['rankData'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['generalId'] ?? null)
|| !is_string($row['type'] ?? null)
|| RankColumn::tryFrom($row['type']) === null
|| !is_int($row['value'] ?? null)
) {
throw new \InvalidArgumentException('invalid setup.rankData row');
}
$nationId = (int)($db->queryFirstField(
'SELECT nation FROM general WHERE no = %i',
$row['generalId'],
) ?? 0);
$db->insertUpdate('rank_data', [
'general_id' => $row['generalId'],
'nation_id' => $nationId,
'type' => $row['type'],
'value' => $row['value'],
], [
'nation_id' => $nationId,
'value' => $row['value'],
]);
}
if (($setup['isolateWorld'] ?? false) === true && ($setup['generals'] ?? []) !== []) {
$maxGeneralId = max(array_map(
static fn(array $row): int => (int)$row['id'],
$setup['generals'],
));
$db->query('ALTER TABLE general AUTO_INCREMENT = %i', $maxGeneralId + 1);
}
foreach ($setup['troops'] ?? [] as $row) {
if (
!is_array($row)
|| !is_int($row['id'] ?? null)
|| !is_int($row['nationId'] ?? null)
|| !is_string($row['name'] ?? null)
|| $row['id'] < 1
|| $row['nationId'] < 1
|| $row['name'] === ''
) {
throw new \InvalidArgumentException('setup.troops requires positive id/nationId and non-empty name');
}
$data = [
'troop_leader' => $row['id'],
'nation' => $row['nationId'],
'name' => $row['name'],
];
$db->insertUpdate('troop', $data, $data);
}
foreach ($setup['diplomacy'] ?? [] as $row) {
if (
!is_array($row) ||
!is_int($row['fromNationId'] ?? null) ||
!is_int($row['toNationId'] ?? null) ||
$row['fromNationId'] < 1 ||
$row['toNationId'] < 1
) {
throw new \InvalidArgumentException('setup.diplomacy requires positive integer nation ids');
}
$data = comparisonMappedPatch($row, [
'fromNationId' => 'me',
'toNationId' => 'you',
'state' => 'state',
'term' => 'term',
'dead' => 'dead',
]);
$data += ['state' => 3, 'term' => 0, 'dead' => 0];
$db->insertUpdate('diplomacy', $data, $data);
}
}
function comparisonRunTurnCommand(array $request): array
{
if (getenv('TURN_DIFFERENTIAL_ENABLED') !== '1') {
throw new \RuntimeException('TURN_DIFFERENTIAL_ENABLED=1 is required');
}
$kind = $request['kind'] ?? null;
if (!in_array($kind, ['general', 'nation', 'instantNation', 'troopJoinStaticEvent'], true)) {
throw new \InvalidArgumentException(
'kind must be general, nation, instantNation, or troopJoinStaticEvent',
);
}
$actorGeneralId = $request['actorGeneralId'] ?? null;
$action = $request['action'] ?? null;
$args = $request['args'] ?? null;
$includeLifecycle = $request['includeLifecycle'] ?? false;
if (!is_int($actorGeneralId) || $actorGeneralId < 1) {
throw new \InvalidArgumentException('actorGeneralId must be a positive integer');
}
if (!is_string($action) || $action === '') {
throw new \InvalidArgumentException('action must be a non-empty string');
}
if (!is_bool($includeLifecycle)) {
throw new \InvalidArgumentException('includeLifecycle must be a boolean');
}
if ($includeLifecycle && $kind !== 'general') {
throw new \InvalidArgumentException('includeLifecycle currently supports general commands only');
}
comparisonApplyTurnFixtureSetup($request['setup'] ?? null);
if ($includeLifecycle) {
DB::db()->insertUpdate('general_turn', [
'general_id' => $actorGeneralId,
'turn_idx' => 0,
'action' => $action,
'arg' => Json::encode($args),
'brief' => $action,
], [
'action' => $action,
'arg' => Json::encode($args),
'brief' => $action,
]);
}
$snapshotRequest = ['observe' => $request['observe'] ?? []];
$before = comparisonTurnStateSnapshot($snapshotRequest);
$db = DB::db();
$gameStorage = KVStorage::getStorage($db, 'game_env');
$gameStorage->resetCache();
$environment = $gameStorage->getAll();
if ($kind === 'troopJoinStaticEvent') {
if ($action !== \sammo\API\Troop\JoinTroop::class) {
throw new \InvalidArgumentException('troopJoinStaticEvent requires the JoinTroop API action');
}
$troopId = is_array($args) ? ($args['troopID'] ?? null) : null;
if (!is_int($troopId) || $troopId < 1) {
throw new \InvalidArgumentException('troopJoinStaticEvent requires a positive integer troopID');
}
$general = GeneralLite::createObjFromDB(
$actorGeneralId,
['troop'],
Enums\GeneralLiteQueryMode::Lite,
);
if ($general === null) {
throw new \RuntimeException('장수 정보를 불러올 수 없습니다.');
}
if ($general->getVar('troop') != 0) {
throw new \RuntimeException('이미 부대에 소속되어 있습니다.');
}
$nationId = $general->getNationID();
if ($nationId == 0) {
throw new \RuntimeException('국가에 소속되어 있지 않습니다.');
}
$troopExists = $db->queryFirstField(
'SELECT `troop_leader` FROM `troop` WHERE `troop_leader` = %i AND `nation` = %i',
$troopId,
$nationId,
);
if (!$troopExists) {
throw new \RuntimeException('부대가 올바르지 않습니다.');
}
GameConst::$staticEventHandlers = [
\sammo\API\Troop\JoinTroop::class => ['event_부대탑승즉시이동'],
];
$general->setVar('troop', $troopId);
StaticEventHandler::handleEvent($general, null, \sammo\API\Troop\JoinTroop::class, [], $args);
$general->applyDB($db);
$after = comparisonTurnStateSnapshot($snapshotRequest);
return [
'schemaVersion' => 1,
'engine' => 'ref',
'execution' => [
'kind' => $kind,
'actorGeneralId' => $actorGeneralId,
'action' => $action,
'args' => $args,
'seedDomain' => 'none',
'outcome' => ['completed' => true],
],
'before' => $before,
'after' => $after,
'rng' => [],
];
}
$general = General::createObjFromDB($actorGeneralId);
if ($kind === 'instantNation') {
$command = buildNationCommandClass($action, $general, $environment, new LastTurn(), $args);
if (!$command->hasFullConditionMet()) {
throw new \RuntimeException($command->getFailString());
}
$completed = $command->run(NoRNG::rngInstance());
$command->setNextAvailable();
$general->getLogger()->flush();
$after = comparisonTurnStateSnapshot($snapshotRequest);
return [
'schemaVersion' => 1,
'engine' => 'ref',
'execution' => [
'kind' => $kind,
'actorGeneralId' => $actorGeneralId,
'action' => $action,
'args' => $args,
'seedDomain' => 'none',
'outcome' => [
'lastTurn' => (object)[],
'commandName' => $command->getName(),
'completed' => $completed,
],
],
'before' => $before,
'after' => $after,
'rng' => [],
];
}
$turn = new TurnExecutionHelper($general);
$general->increaseInheritancePoint(Enums\InheritanceKey::lived_month, 1);
$preprocessRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'preprocess',
(int)$environment['year'],
(int)$environment['month'],
$actorGeneralId,
)));
$turn->preprocessCommand($preprocessRng, $environment);
$seedDomain = $kind === 'general' ? 'generalCommand' : 'nationCommand';
$seed = Util::simpleSerialize(
UniqueConst::$hiddenSeed,
$seedDomain,
(int)$environment['year'],
(int)$environment['month'],
$actorGeneralId,
$action,
);
$tracingRng = new TurnComparisonTracingRNG(new LiteHashDRBG($seed));
$rng = new RandUtil($tracingRng);
if ($kind === 'general' && $action === 'che_견문') {
\sammo\TextDecoration\SightseeingMessage::setComparisonRng($rng);
}
if ($kind === 'general') {
$previousLastTurn = $general->getLastTurn();
$previousLastTurnRaw = $previousLastTurn->toRaw();
$command = buildGeneralCommandClass($action, $general, $environment, $args);
$commandFullConditionMet = $command->hasFullConditionMet();
$resultTurn = $turn->processCommand($rng, $command, false);
} else {
$nationStor = KVStorage::getStorage($db, $general->getNationID(), 'nation_env');
$lastNationTurnKey = "turn_last_{$general->getVar('officer_level')}";
$previousLastTurn = LastTurn::fromRaw($nationStor->getValue($lastNationTurnKey));
$previousLastTurnRaw = $previousLastTurn->toRaw();
$command = buildNationCommandClass($action, $general, $environment, $previousLastTurn, $args);
$commandFullConditionMet = $command->hasFullConditionMet();
$resultTurn = $turn->processNationCommand($rng, $command);
$nationStor->setValue($lastNationTurnKey, $resultTurn->toRaw());
}
if ($includeLifecycle) {
pullGeneralCommand($general->getID());
$general->increaseVarWithLimit(
'myset',
GameConst::$incDefSettingChange,
null,
GameConst::$maxDefSettingChange,
);
$turn->updateTurnTime();
}
$general->getLogger()->flush();
$turn->applyDB();
unset($turn);
$after = comparisonTurnStateSnapshot($snapshotRequest);
$resultTurnRaw = $resultTurn->toRaw();
$resultTerm = (int)($resultTurnRaw['term'] ?? 0);
$preReqTurn = $command->getPreReqTurn();
$acceptScoutCompleted = (
$action === 'che_등용수락'
&& is_array($args)
&& is_int($args['destNationID'] ?? null)
&& $general->getNationID() === $args['destNationID']
);
$foundNationCompleted = (
in_array($action, ['che_건국', 'cr_건국', 'che_무작위건국'], true)
&& is_array($args)
&& is_string($args['nationName'] ?? null)
&& DB::db()->queryFirstField(
'SELECT name FROM nation WHERE nation = %i',
$general->getNationID(),
) === $args['nationName']
);
$completedByState = (
$action === 'che_접경귀환'
&& $tracingRng->calls !== []
) || $acceptScoutCompleted || $foundNationCompleted || (($resultTurnRaw['command'] ?? null) === $command->getName()
&& (
($preReqTurn === 0 && $resultTerm === 0)
|| (
$preReqTurn > 0
&& ($previousLastTurnRaw['command'] ?? null) === $command->getName()
&& ($previousLastTurnRaw['arg'] ?? null) === $command->getArg()
&& (int)($previousLastTurnRaw['term'] ?? 0) === $preReqTurn
)
));
$completed = $commandFullConditionMet && $completedByState;
return [
'schemaVersion' => 1,
'engine' => 'ref',
'execution' => [
'kind' => $kind,
'actorGeneralId' => $actorGeneralId,
'action' => $action,
'args' => $args,
'seedDomain' => $seedDomain,
'outcome' => [
'lastTurn' => $resultTurnRaw,
'commandName' => $command->getName(),
'completed' => $completed,
],
],
'before' => $before,
'after' => $after,
'rng' => $tracingRng->calls,
];
}
try {
$input = stream_get_contents(STDIN);
$request = json_decode($input === '' ? '{}' : $input, true, flags: JSON_THROW_ON_ERROR);
if (!is_array($request)) {
throw new \InvalidArgumentException('request must be an object');
}
echo json_encode(
comparisonRunTurnCommand($request),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
} catch (\Throwable $throwable) {
fwrite(STDERR, $throwable::class . ': ' . $throwable->getMessage() . PHP_EOL);
exit(1);
}
+643
View File
@@ -0,0 +1,643 @@
<?php
declare(strict_types=1);
namespace sammo;
use sammo\Enums\RankColumn;
if (PHP_SAPI !== 'cli') {
http_response_code(404);
exit;
}
chdir(dirname(__DIR__));
require_once 'lib.php';
require_once 'func.php';
/** @return list<int> */
function comparisonIntegerList(mixed $value, string $label): array
{
if ($value === null) {
return [];
}
if (!is_array($value)) {
throw new \InvalidArgumentException("{$label} must be an array");
}
$result = [];
foreach ($value as $entry) {
if (!is_int($entry) || $entry < 0) {
throw new \InvalidArgumentException("{$label} entries must be non-negative integers");
}
$result[$entry] = $entry;
}
ksort($result, SORT_NUMERIC);
return array_values($result);
}
function comparisonJsonValue(mixed $value): mixed
{
if (!is_string($value) || $value === '') {
return $value;
}
try {
return json_decode($value, true, flags: JSON_THROW_ON_ERROR);
} catch (\JsonException) {
return $value;
}
}
function comparisonOptionalCode(mixed $value): ?string
{
if (!is_string($value) || $value === '' || $value === 'None') {
return null;
}
return $value;
}
/** @return list<array{generalId: int, actionName: string}> */
function comparisonGeneralCooldownSelectors(mixed $value, string $label): array
{
if ($value === null) {
return [];
}
if (!is_array($value)) {
throw new \InvalidArgumentException("{$label} must be an array");
}
$result = [];
foreach ($value as $entry) {
if (!is_array($entry)) {
throw new \InvalidArgumentException("{$label} entries must be objects");
}
$generalId = $entry['generalId'] ?? null;
$actionName = $entry['actionName'] ?? null;
if (!is_int($generalId) || $generalId < 1 || !is_string($actionName) || $actionName === '') {
throw new \InvalidArgumentException(
"{$label} entries require a positive generalId and non-empty actionName",
);
}
$result["{$generalId}:{$actionName}"] = [
'generalId' => $generalId,
'actionName' => $actionName,
];
}
ksort($result, SORT_STRING);
return array_values($result);
}
/** @return list<array{nationId: int, actionName: string}> */
function comparisonNationCooldownSelectors(mixed $value, string $label): array
{
if ($value === null) {
return [];
}
if (!is_array($value)) {
throw new \InvalidArgumentException("{$label} must be an array");
}
$result = [];
foreach ($value as $entry) {
if (!is_array($entry)) {
throw new \InvalidArgumentException("{$label} entries must be objects");
}
$nationId = $entry['nationId'] ?? null;
$actionName = $entry['actionName'] ?? null;
if (!is_int($nationId) || $nationId < 1 || !is_string($actionName) || $actionName === '') {
throw new \InvalidArgumentException(
"{$label} entries require a positive nationId and non-empty actionName",
);
}
$result["{$nationId}:{$actionName}"] = [
'nationId' => $nationId,
'actionName' => $actionName,
];
}
ksort($result, SORT_STRING);
return array_values($result);
}
/** @return list<array{fromNationId: int, toNationId: int}> */
function comparisonDiplomacyPairSelectors(mixed $value, string $label): array
{
if ($value === null) {
return [];
}
if (!is_array($value)) {
throw new \InvalidArgumentException("{$label} must be an array");
}
$result = [];
foreach ($value as $entry) {
if (!is_array($entry)) {
throw new \InvalidArgumentException("{$label} entries must be objects");
}
$fromNationId = $entry['fromNationId'] ?? null;
$toNationId = $entry['toNationId'] ?? null;
if (!is_int($fromNationId) || $fromNationId < 1 || !is_int($toNationId) || $toNationId < 1) {
throw new \InvalidArgumentException(
"{$label} entries require positive fromNationId and toNationId",
);
}
$result["{$fromNationId}:{$toNationId}"] = [
'fromNationId' => $fromNationId,
'toNationId' => $toNationId,
];
}
ksort($result, SORT_STRING);
return array_values($result);
}
/** @param array<string, mixed> $row */
function comparisonPickRow(array $row, array $mapping, array $jsonKeys = []): array
{
$result = [];
foreach ($mapping as $canonical => $legacy) {
if (!array_key_exists($legacy, $row)) {
continue;
}
$value = $row[$legacy];
if (in_array($legacy, $jsonKeys, true)) {
$value = comparisonJsonValue($value);
}
$result[$canonical] = $value;
}
return $result;
}
/** @param list<int> $ids */
function comparisonRowsById(string $table, string $idColumn, array $ids): array
{
$db = DB::db();
$rows = [];
foreach ($ids as $id) {
$row = $db->queryFirstRow(
"SELECT * FROM `{$table}` WHERE `{$idColumn}` = %i",
$id,
);
if ($row !== null) {
$rows[] = $row;
}
}
return $rows;
}
function comparisonTurnStateSnapshot(array $request): array
{
$observe = $request['observe'] ?? [];
if (!is_array($observe)) {
throw new \InvalidArgumentException('observe must be an object');
}
$generalIds = comparisonIntegerList($observe['generalIds'] ?? [], 'generalIds');
$cityIds = comparisonIntegerList($observe['cityIds'] ?? [], 'cityIds');
$nationIds = comparisonIntegerList($observe['nationIds'] ?? [], 'nationIds');
$logAfterId = $observe['logAfterId'] ?? 0;
$messageAfterId = $observe['messageAfterId'] ?? 0;
$includeNationHistoryLogs = $observe['includeNationHistoryLogs'] ?? false;
$includeGlobalHistoryLogs = $observe['includeGlobalHistoryLogs'] ?? false;
$generalCooldownSelectors = comparisonGeneralCooldownSelectors(
$observe['generalCooldowns'] ?? [],
'generalCooldowns',
);
$nationCooldownSelectors = comparisonNationCooldownSelectors(
$observe['nationCooldowns'] ?? [],
'nationCooldowns',
);
$diplomacyPairSelectors = comparisonDiplomacyPairSelectors(
$observe['diplomacyPairs'] ?? [],
'diplomacyPairs',
);
if (
!is_int($logAfterId)
|| $logAfterId < 0
|| !is_int($messageAfterId)
|| $messageAfterId < 0
) {
throw new \InvalidArgumentException('logAfterId and messageAfterId must be non-negative integers');
}
if (!is_bool($includeNationHistoryLogs)) {
throw new \InvalidArgumentException('includeNationHistoryLogs must be a boolean');
}
if (!is_bool($includeGlobalHistoryLogs)) {
throw new \InvalidArgumentException('includeGlobalHistoryLogs must be a boolean');
}
$db = DB::db();
$game = KVStorage::getStorage($db, 'game_env');
$game->resetCache();
$worldValues = $game->getValues([
'year',
'month',
'turnterm',
'turntime',
'isunited',
'scenario',
'init_year',
'init_month',
'develcost',
'killturn',
]);
$nextExecuteStorage = KVStorage::getStorage($db, 'next_execute');
$nextExecuteStorage->resetCache();
$generalCooldowns = array_map(
static function (array $selector) use ($nextExecuteStorage): array {
$key = "next_execute_{$selector['generalId']}_{$selector['actionName']}";
$value = $nextExecuteStorage->getValue($key);
return [
...$selector,
'nextAvailableTurn' => is_int($value) ? $value : null,
];
},
$generalCooldownSelectors,
);
$nationCooldowns = array_map(
static function (array $selector) use ($db): array {
$nationStorage = KVStorage::getStorage($db, $selector['nationId'], 'nation_env');
$nationStorage->resetCache();
$value = $nationStorage->getValue("next_execute_{$selector['actionName']}");
return [
...$selector,
'nextAvailableTurn' => is_int($value) ? $value : null,
];
},
$nationCooldownSelectors,
);
$generals = array_map(
static function (array $row): array {
$result = comparisonPickRow(
$row,
[
'id' => 'no',
'name' => 'name',
'nationId' => 'nation',
'cityId' => 'city',
'troopId' => 'troop',
'leadership' => 'leadership',
'strength' => 'strength',
'intelligence' => 'intel',
'experience' => 'experience',
'dedication' => 'dedication',
'expLevel' => 'explevel',
'officerLevel' => 'officer_level',
'officerCityId' => 'officer_city',
'belong' => 'belong',
'permission' => 'permission',
'betray' => 'betray',
'makeLimit' => 'makelimit',
'injury' => 'injury',
'gold' => 'gold',
'rice' => 'rice',
'crew' => 'crew',
'crewTypeId' => 'crewtype',
'train' => 'train',
'atmos' => 'atmos',
'age' => 'age',
'npcState' => 'npc',
'turnTime' => 'turntime',
'recentWarTime' => 'recent_war',
'lastTurn' => 'last_turn',
'meta' => 'aux',
'penalty' => 'penalty',
'leadershipExp' => 'leadership_exp',
'strengthExp' => 'strength_exp',
'intelExp' => 'intel_exp',
'dex1' => 'dex1',
'dex2' => 'dex2',
'dex3' => 'dex3',
'dex4' => 'dex4',
'dex5' => 'dex5',
'specAge' => 'specage',
'specAge2' => 'specage2',
'killTurn' => 'killturn',
'mySet' => 'myset',
'specialDomestic' => 'special',
'specialWar' => 'special2',
'personality' => 'personal',
'itemHorse' => 'horse',
'itemWeapon' => 'weapon',
'itemBook' => 'book',
'itemExtra' => 'item',
],
['last_turn', 'aux', 'penalty'],
);
foreach ([
'specialDomestic',
'specialWar',
'personality',
'itemHorse',
'itemWeapon',
'itemBook',
'itemExtra',
] as $key) {
$result[$key] = comparisonOptionalCode($result[$key] ?? null);
}
$result['maxBelong'] = (int)($result['meta']['max_belong'] ?? 0);
$ownerId = (int)($row['owner'] ?? 0);
$activeActionPoints = 0;
if ($ownerId > 0) {
$inheritanceStorage = KVStorage::getStorage(DB::db(), "inheritance_{$ownerId}");
$inheritanceStorage->resetCache();
$stored = $inheritanceStorage->getValue('active_action');
if (is_array($stored) && (is_int($stored[0] ?? null) || is_float($stored[0] ?? null))) {
$activeActionPoints = $stored[0];
}
}
$result['hasOwner'] = $ownerId > 0;
$result['inheritActiveActionPoints'] = $activeActionPoints;
return $result;
},
comparisonRowsById('general', 'no', $generalIds),
);
$rankTypes = array_map(
static fn(RankColumn $column): string => $column->value,
RankColumn::cases(),
);
$rankData = $generalIds === []
? []
: iterator_to_array($db->query(
'SELECT general_id AS generalId, nation_id AS nationId, `type`, `value`'
. ' FROM rank_data WHERE general_id IN %li AND `type` IN %ls'
. ' ORDER BY general_id, `type`',
$generalIds,
$rankTypes,
));
$cities = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'city',
'name' => 'name',
'nationId' => 'nation',
'level' => 'level',
'population' => 'pop',
'populationMax' => 'pop_max',
'agriculture' => 'agri',
'agricultureMax' => 'agri_max',
'commerce' => 'comm',
'commerceMax' => 'comm_max',
'security' => 'secu',
'securityMax' => 'secu_max',
'supplyState' => 'supply',
'frontState' => 'front',
'defence' => 'def',
'defenceMax' => 'def_max',
'wall' => 'wall',
'wallMax' => 'wall_max',
'state' => 'state',
'term' => 'term',
'trust' => 'trust',
'trade' => 'trade',
'conflict' => 'conflict',
'officerSet' => 'officer_set',
],
['conflict'],
),
comparisonRowsById('city', 'city', $cityIds),
);
$nations = array_map(
static function (array $row) use ($db): array {
$projected = comparisonPickRow(
$row,
[
'id' => 'nation',
'name' => 'name',
'color' => 'color',
'capitalCityId' => 'capital',
'gold' => 'gold',
'rice' => 'rice',
'tech' => 'tech',
'level' => 'level',
'typeCode' => 'type',
'generalCount' => 'gennum',
'power' => 'power',
'war' => 'war',
'diplomacyLimit' => 'surlimit',
'capitalRevision' => 'capset',
'strategicCommandLimit' => 'strategic_cmd_limit',
'meta' => 'aux',
],
['aux'],
);
$nationStor = KVStorage::getStorage($db, (int)$row['nation'], 'nation_env');
$receivedAssist = $nationStor->getValue('recv_assist');
if (is_array($receivedAssist) && $receivedAssist !== []) {
$projected['meta']['recv_assist'] = $receivedAssist;
}
$respondedAssist = $nationStor->getValue('resp_assist');
if (is_array($respondedAssist) && $respondedAssist !== []) {
$projected['meta']['resp_assist'] = $respondedAssist;
}
return $projected;
},
comparisonRowsById('nation', 'nation', $nationIds),
);
$diplomacyPairs = [];
foreach ($nationIds as $fromNationId) {
foreach ($nationIds as $toNationId) {
if ($fromNationId === $toNationId) {
continue;
}
$diplomacyPairs["{$fromNationId}:{$toNationId}"] = [
'fromNationId' => $fromNationId,
'toNationId' => $toNationId,
];
}
}
foreach ($diplomacyPairSelectors as $pair) {
$diplomacyPairs["{$pair['fromNationId']}:{$pair['toNationId']}"] = $pair;
}
ksort($diplomacyPairs, SORT_STRING);
$diplomacy = [];
foreach ($diplomacyPairs as $pair) {
$row = $db->queryFirstRow(
'SELECT me, you, state, term, dead FROM diplomacy WHERE me = %i AND you = %i',
$pair['fromNationId'],
$pair['toNationId'],
);
if ($row !== null) {
$diplomacy[] = comparisonPickRow($row, [
'fromNationId' => 'me',
'toNationId' => 'you',
'state' => 'state',
'term' => 'term',
'dead' => 'dead',
]);
}
}
$generalTurns = [];
foreach ($generalIds as $generalId) {
foreach ($db->query(
'SELECT general_id, turn_idx, action, arg FROM general_turn WHERE general_id = %i ORDER BY turn_idx',
$generalId,
) as $row) {
$generalTurns[] = comparisonPickRow(
$row,
['generalId' => 'general_id', 'turnIndex' => 'turn_idx', 'action' => 'action', 'args' => 'arg'],
['arg'],
);
}
}
$nationTurns = [];
foreach ($nationIds as $nationId) {
foreach ($db->query(
'SELECT nation_id, officer_level, turn_idx, action, arg FROM nation_turn WHERE nation_id = %i ORDER BY officer_level, turn_idx',
$nationId,
) as $row) {
$nationTurns[] = comparisonPickRow(
$row,
[
'nationId' => 'nation_id',
'officerLevel' => 'officer_level',
'turnIndex' => 'turn_idx',
'action' => 'action',
'args' => 'arg',
],
['arg'],
);
}
}
$logs = [];
if ($generalIds !== []) {
foreach ($db->query(
'SELECT id, general_id, log_type, year, month, text FROM general_record WHERE id > %i ORDER BY id',
$logAfterId,
) as $row) {
if ((int)$row['general_id'] !== 0 && !in_array((int)$row['general_id'], $generalIds, true)) {
continue;
}
$generalId = (int)$row['general_id'];
$category = (string)$row['log_type'];
if ($category === 'battle') {
$category = 'battle_detail';
} elseif ($generalId === 0) {
$category = 'summary';
}
$logs[] = comparisonPickRow($row, [
'id' => 'id',
'generalId' => 'general_id',
'year' => 'year',
'month' => 'month',
'text' => 'text',
]) + [
'scope' => $generalId === 0 ? 'system' : 'general',
'category' => $category,
'nationId' => null,
];
}
}
if ($includeNationHistoryLogs && $nationIds !== []) {
foreach ($db->query(
'SELECT id, nation_id, year, month, text FROM world_history WHERE nation_id IN %li ORDER BY id',
$nationIds,
) as $row) {
$logs[] = comparisonPickRow($row, [
'id' => 'id',
'nationId' => 'nation_id',
'year' => 'year',
'month' => 'month',
'text' => 'text',
]) + [
'scope' => 'nation',
'category' => 'history',
'generalId' => null,
];
}
}
if ($includeGlobalHistoryLogs) {
foreach ($db->query(
'SELECT id, nation_id, year, month, text FROM world_history WHERE nation_id = 0 ORDER BY id',
) as $row) {
$logs[] = comparisonPickRow($row, [
'id' => 'id',
'nationId' => 'nation_id',
'year' => 'year',
'month' => 'month',
'text' => 'text',
]) + [
'scope' => 'system',
'category' => 'history',
'generalId' => null,
];
}
}
$messages = array_map(
static fn(array $row): array => comparisonPickRow(
$row,
[
'id' => 'id',
'mailbox' => 'mailbox',
'type' => 'type',
'sourceId' => 'src',
'destinationId' => 'dest',
'createdAt' => 'time',
'payload' => 'message',
],
['message'],
),
$db->query(
'SELECT id, mailbox, type, src, dest, time, message FROM message WHERE id > %i ORDER BY id',
$messageAfterId,
),
);
return [
'schemaVersion' => 1,
'engine' => 'ref',
'world' => [
'year' => (int)$worldValues['year'],
'month' => (int)$worldValues['month'],
'tickMinutes' => (int)$worldValues['turnterm'],
'turnTime' => (string)$worldValues['turntime'],
'isUnited' => (int)$worldValues['isunited'],
'scenarioId' => (int)$worldValues['scenario'],
'initYear' => (int)$worldValues['init_year'],
'initMonth' => (int)$worldValues['init_month'],
'develCost' => (int)$worldValues['develcost'],
'killTurn' => (int)$worldValues['killturn'],
'generalCooldowns' => $generalCooldowns,
'nationCooldowns' => $nationCooldowns,
],
'generals' => $generals,
'rankData' => $rankData,
'cities' => $cities,
'nations' => $nations,
'diplomacy' => $diplomacy,
'generalTurns' => $generalTurns,
'nationTurns' => $nationTurns,
'logs' => $logs,
'messages' => $messages,
'watermarks' => [
'logId' => (int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM general_record') ?? 0),
'historyLogId' => (int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM world_history') ?? 0),
'messageId' => (int)($db->queryFirstField('SELECT COALESCE(MAX(id), 0) FROM message') ?? 0),
],
];
}
function comparisonTurnStateSnapshotMain(): void
{
try {
$input = stream_get_contents(STDIN);
$request = json_decode($input === '' ? '{}' : $input, true, flags: JSON_THROW_ON_ERROR);
if (!is_array($request)) {
throw new \InvalidArgumentException('request must be an object');
}
echo json_encode(
comparisonTurnStateSnapshot($request),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION,
), PHP_EOL;
} catch (\Throwable $throwable) {
fwrite(STDERR, $throwable::class . ': ' . $throwable->getMessage() . PHP_EOL);
exit(1);
}
}
if (realpath((string)($_SERVER['SCRIPT_FILENAME'] ?? '')) === __FILE__) {
comparisonTurnStateSnapshotMain();
}
+17 -1
View File
@@ -51,6 +51,22 @@
display: none; display: none;
} }
.picture_choice {
margin: 8px auto;
}
.picture_choice label,
.event_picture label {
display: inline-flex;
align-items: center;
gap: 4px;
margin: 4px 8px;
}
.picture_choice img {
object-fit: cover;
}
.custom_picture { .custom_picture {
display: none; display: none;
} }
@@ -61,4 +77,4 @@
.custom_stat { .custom_stat {
display: none; display: none;
} }
+39 -22
View File
@@ -9,6 +9,7 @@ use sammo\Enums\GeneralAccessLogColumn;
use sammo\Enums\GeneralColumn; use sammo\Enums\GeneralColumn;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\InheritanceKey; use sammo\Enums\InheritanceKey;
use sammo\Enums\PenaltyKey;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
require_once 'process_war.php'; require_once 'process_war.php';
@@ -111,7 +112,7 @@ function GetImageURL($imgsvr, $filepath = '')
function checkLimit($refreshScore = null) function checkLimit($refreshScore = null)
{ {
$session = Session::getInstance(); $session = Session::getInstance();
if ($session->userGrade >= 4) { if ($session->userGrade >= 6) {
return 0; return 0;
} }
@@ -149,7 +150,7 @@ function getRandGenName(RandUtil $rng)
function cityInfo(General $generalObj) function cityInfo(GeneralLite $generalObj)
{ {
$db = DB::db(); $db = DB::db();
@@ -376,11 +377,11 @@ function myNationInfo(General $generalObj)
function checkSecretMaxPermission($penalty) function checkSecretMaxPermission($penalty)
{ {
$secretMax = 4; $secretMax = 4;
if ($penalty['noTopSecret'] ?? false) { if ($penalty[PenaltyKey::NoTopSecret->value] ?? false) {
$secretMax = 1; $secretMax = 1;
} else if ($penalty['noChief'] ?? false) { } else if ($penalty[PenaltyKey::NoChief->value] ?? false) {
$secretMax = 1; $secretMax = 1;
} else if ($penalty['noAmbassador'] ?? false) { } else if ($penalty[PenaltyKey::NoAmbassador->value] ?? false) {
$secretMax = 2; $secretMax = 2;
} }
return $secretMax; return $secretMax;
@@ -403,19 +404,19 @@ function checkSecretPermission(array $me, $checkSecretLimit = true)
} }
if ($penalty['noSecret'] ?? false) { if ($penalty[PenaltyKey::NoChief->value] ?? false) {
return 0; return 0;
} }
$secretMin = 0; $secretMin = 0;
$secretMax = checkSecretMaxPermission($me, $penalty); $secretMax = checkSecretMaxPermission($penalty);
if ($me['officer_level'] == 12) { if ($me['officer_level'] == 12) {
$secretMin = 4; $secretMin = 4;
} else if ($me['permission'] == 'ambassador') { } else if ($permission == 'ambassador') {
$secretMin = 4; $secretMin = 4;
} else if ($me['permission'] == 'auditor') { } else if ($permission == 'auditor') {
$secretMin = 3; $secretMin = 3;
} else if ($me['officer_level'] >= 5) { } else if ($me['officer_level'] >= 5) {
$secretMin = 2; $secretMin = 2;
@@ -1008,7 +1009,7 @@ function increaseRefresh($type = "", $cnt = 1)
$isunited = $gameStor->isunited; $isunited = $gameStor->isunited;
$opentime = $gameStor->opentime; $opentime = $gameStor->opentime;
if ($userGrade == 6) { if ($userGrade >= 6) {
return; return;
} }
if ($isunited == 2) { if ($isunited == 2) {
@@ -1046,7 +1047,7 @@ function increaseRefresh($type = "", $cnt = 1)
$logDB = FileDB::db($logPath, $serverPath . '/../f_install/sql/api_log.sql'); $logDB = FileDB::db($logPath, $serverPath . '/../f_install/sql/api_log.sql');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'local'; $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'local';
$date = date('Y-m-d H:i:s'); $date = date('Y-m-d H:i:s');
$logDB->insert('api_log', [ $logDB->insert('api_log', [
@@ -1054,10 +1055,10 @@ function increaseRefresh($type = "", $cnt = 1)
'ip' => $ip, 'ip' => $ip,
'date' => $date, 'date' => $date,
'path' => "refresh", 'path' => "refresh",
'arg' => JSON::encode([ 'arg' => Json::encode([
'type' => $type, 'type' => $type,
]), ]),
'aux' => JSON::encode([ 'aux' => Json::encode([
'generalID' => $generalID, 'generalID' => $generalID,
'generalName' => $session->generalName, 'generalName' => $session->generalName,
'userName' => $session->userName, 'userName' => $session->userName,
@@ -1070,7 +1071,7 @@ function updateTraffic()
$online = getOnlineNum(); $online = getOnlineNum();
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxonline', 'maxrefresh']); $admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxonline', 'maxrefresh', 'recentTraffic']);
/** @var array{year:int,month:int,refresh:int,maxonline:int,maxrefresh:int} $admin */ /** @var array{year:int,month:int,refresh:int,maxonline:int,maxrefresh:int} $admin */
if ($admin['maxrefresh'] < $admin['refresh']) { if ($admin['maxrefresh'] < $admin['refresh']) {
@@ -1083,6 +1084,19 @@ function updateTraffic()
$gameStor->maxrefresh = $admin['maxrefresh']; $gameStor->maxrefresh = $admin['maxrefresh'];
$gameStor->maxonline = $admin['maxonline']; $gameStor->maxonline = $admin['maxonline'];
$recentTraffic = $admin['recentTraffic'] ?? [];
if(count($recentTraffic) >= 5){
array_shift($recentTraffic);
}
$recentTraffic[] = [
'year'=>$admin['year'],
'month' => $admin['month'],
'refresh' => $admin['refresh'],
'online' => $online,
'date' => TimeUtil::now(),
];
$gameStor->recentTraffic = $recentTraffic;
$db->update('general_access_log', ['refresh' => 0], true); $db->update('general_access_log', ['refresh' => 0], true);
} }
@@ -1093,7 +1107,7 @@ function CheckOverhead()
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
[$turnterm, $refreshLimit] = $gameStor->getValuesAsArray(['turnterm', 'refreshLimit']); [$turnterm, $refreshLimit] = $gameStor->getValuesAsArray(['turnterm', 'refreshLimit']);
$nextRefreshLimit = Util::round(pow($turnterm, 0.6) * 3) * 10; $nextRefreshLimit = Util::round(pow($turnterm, 0.6) * 3) * GameConst::$refreshLimitCoef;
if ($nextRefreshLimit != $refreshLimit) { if ($nextRefreshLimit != $refreshLimit) {
@@ -1324,7 +1338,7 @@ function CheckHall($no)
["betrate", 'calc'], ["betrate", 'calc'],
]; ];
$generalObj = General::createGeneralObjFromDB($no); $generalObj = General::createObjFromDB($no);
$ttw = $generalObj->getRankVar(RankColumn::ttw); $ttw = $generalObj->getRankVar(RankColumn::ttw);
$ttd = $generalObj->getRankVar(RankColumn::ttd); $ttd = $generalObj->getRankVar(RankColumn::ttd);
@@ -1387,8 +1401,11 @@ function CheckHall($no)
foreach ($types as [$typeName, $valueType]) { foreach ($types as [$typeName, $valueType]) {
if ($valueType === 'natural') { if ($valueType === 'natural') {
$value = $generalObj->getVar($typeName); $value = $generalObj->getVar($typeName);
if (in_array($typeName, ['dex1', 'dex2', 'dex3', 'dex4', 'dex5'], true)) {
$value = CentennialAllStarGrowthService::recordableValue($generalObj, $typeName);
}
} else if ($valueType === 'rank') { } else if ($valueType === 'rank') {
$value = $generalObj->getRankVar(RankColumn::from($typeName)); $value = $generalObj->getRankVar(RankColumn::from($typeName));
} else if ($valueType === 'calc') { } else if ($valueType === 'calc') {
@@ -1655,8 +1672,6 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
$prob = 1 / ($genCount * $itemTypeCnt * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장 $prob = 1 / ($genCount * $itemTypeCnt * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장
} else if ($acquireType == '랜덤 임관') { } else if ($acquireType == '랜덤 임관') {
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?) $prob = 1 / ($genCount * $itemTypeCnt / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
} else if ($acquireType == '건국') {
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
} }
$prob *= GameConst::$uniqueTrialCoef; $prob *= GameConst::$uniqueTrialCoef;
@@ -1670,6 +1685,9 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
//포인트로 랜덤 유니크 획득 //포인트로 랜덤 유니크 획득
$prob = 1; $prob = 1;
} }
else if ($acquireType == '건국') {
$prob = 1; // 건국시 100%
}
foreach (Util::range($maxCnt) as $_idx) { foreach (Util::range($maxCnt) as $_idx) {
if ($rng->nextBool($prob)) { if ($rng->nextBool($prob)) {
@@ -1714,14 +1732,13 @@ function deleteNation(General $lord, bool $applyDB): array
$logger->pushGlobalHistoryLog("<R><b>【멸망】</b></><D><b>{$nationName}</b></>{$josaUn} <R>멸망</>했습니다."); $logger->pushGlobalHistoryLog("<R><b>【멸망】</b></><D><b>{$nationName}</b></>{$josaUn} <R>멸망</>했습니다.");
$nationGeneralList = General::createGeneralObjListFromDB( $nationGeneralList = General::createObjListFromDB(
$db->queryFirstColumn( $db->queryFirstColumn(
'SELECT `no` FROM general WHERE nation=%i AND no != %i', 'SELECT `no` FROM general WHERE nation=%i AND no != %i',
$nationID, $nationID,
$lordID $lordID
), ),
['npc', 'owner', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'], ['npc', 'owner', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
GeneralQueryMode::Lite,
); );
$nationGeneralList[$lordID] = $lord; $nationGeneralList[$lordID] = $lord;
+19 -4
View File
@@ -3,6 +3,7 @@ namespace sammo;
use sammo\Command\GeneralCommand; use sammo\Command\GeneralCommand;
use sammo\Command\NationCommand; use sammo\Command\NationCommand;
use sammo\Enums\PenaltyKey;
function getGeneralTurnBrief(General $generalObj, array $turnList) { function getGeneralTurnBrief(General $generalObj, array $turnList) {
$result = []; $result = [];
@@ -213,7 +214,7 @@ function _setGeneralCommand(GeneralCommand $command, array $turnList):void {
$db->update('general_turn', [ $db->update('general_turn', [
'action'=>$commandName, 'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT), 'arg'=>Json::encode($arg, Json::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief 'brief'=>$brief
], 'general_id = %i AND turn_idx IN %li', $generalID, $turnList); ], 'general_id = %i AND turn_idx IN %li', $generalID, $turnList);
} }
@@ -233,7 +234,7 @@ function _setNationCommand(NationCommand $command, array $turnList):void {
$db->update('nation_turn', [ $db->update('nation_turn', [
'action'=>$commandName, 'action'=>$commandName,
'arg'=>Json::encode($arg, JSON::EMPTY_ARRAY_IS_DICT), 'arg'=>Json::encode($arg, Json::EMPTY_ARRAY_IS_DICT),
'brief'=>$brief 'brief'=>$brief
], 'nation_id = %i AND officer_level = %i AND turn_idx IN %li', $nationID, $officerLevel, $turnList); ], 'nation_id = %i AND officer_level = %i AND turn_idx IN %li', $nationID, $officerLevel, $turnList);
} }
@@ -350,7 +351,7 @@ function setGeneralCommand(int $generalID, array $rawTurnList, string $command,
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll(); $env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
try{ try{
$commandObj = buildGeneralCommandClass($command, $general, $env, $arg); $commandObj = buildGeneralCommandClass($command, $general, $env, $arg);
@@ -425,7 +426,7 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getAll(); $env = $gameStor->getAll();
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
if($general->getVar('officer_level') < 5){ if($general->getVar('officer_level') < 5){
return [ return [
@@ -434,6 +435,13 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
]; ];
} }
if($general->hasPenalty(PenaltyKey::NoChiefTurnInput)){
return [
'result'=>false,
'reason'=>'수뇌 턴 입력 불가능'
];
}
try{ try{
$commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg); $commandObj = buildNationCommandClass($command, $general, $env, $general->getLastTurn(), $arg);
} }
@@ -473,6 +481,13 @@ function setNationCommand(int $generalID, array $turnList, string $command, ?arr
} }
_setNationCommand($commandObj, $turnList); _setNationCommand($commandObj, $turnList);
if($general->getNPCType() < 2){
//유저장인 경우에는 턴 리필
$general->updateVarWithLimit('killturn', $env['killturn'], $general->getVar('killturn'));
$general->applyDB($db);
}
return [ return [
'result'=>true, 'result'=>true,
'brief'=>$commandObj->getBrief(), 'brief'=>$commandObj->getBrief(),
+59 -1
View File
@@ -256,6 +256,41 @@ function buildItemClass(?string $type):BaseItem{
return $obj; return $obj;
} }
function getScenarioEffectClass(?string $type){
if($type === null || $type === ''){
$type = 'None';
}
static $basePath = __NAMESPACE__.'\\ActionScenarioEffect\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 시나리오 효과 클래스가 아님");
}
function buildScenarioEffectClass(?string $type):iAction{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getScenarioEffectClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getGeneralSpecialDomesticClass(?string $type){ function getGeneralSpecialDomesticClass(?string $type){
if($type === null || $type === ''){ if($type === null || $type === ''){
$type = GameConst::$defaultSpecialDomestic; $type = GameConst::$defaultSpecialDomestic;
@@ -422,6 +457,29 @@ function buildWarUnitTriggerClass(?string $type, WarUnit $unit, ?array $args = n
return $class->newInstanceArgs(array_merge([$unit], $args)); return $class->newInstanceArgs(array_merge([$unit], $args));
} }
function getStaticEventClass(string $type){
static $basePath = __NAMESPACE__.'\\StaticEvent\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 StaticEvent가 아님");
}
function buildStaticEventClass(?string $type):BaseStaticEvent{
static $cache = [];
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getStaticEventClass($type);
$obj = new $class();
$cache[$type] = $obj;
return $obj;
}
function getGeneralPoolClass(string $type){ function getGeneralPoolClass(string $type){
static $basePath = __NAMESPACE__.'\\GeneralPool\\'; static $basePath = __NAMESPACE__.'\\GeneralPool\\';
$classPath = ($basePath.$type); $classPath = ($basePath.$type);
@@ -628,7 +686,7 @@ function TechLimit($startYear, $year, $tech) : bool {
$relYear = $year - $startYear; $relYear = $year - $startYear;
$relMaxTech = Util::valueFit( $relMaxTech = Util::valueFit(
floor($relYear / 5) + 1, floor($relYear / GameConst::$techLevelIncYear) + GameConst::$initialAllowedTechLevel,
1, 1,
GameConst::$maxTechLevel GameConst::$maxTechLevel
); );
+20 -9
View File
@@ -372,7 +372,7 @@ function postUpdateMonthly(RandUtil $rng)
continue; continue;
} }
//양측 기간 모두 0이 되는 상황이면 //양측 기간 모두 0이 되는 상황이면
$nation1 = getNationStaticInfo($me); $nation1 = getNationStaticInfo($me);
$name1 = $nation1['name']; $name1 = $nation1['name'];
$nation2 = getNationStaticInfo($you); $nation2 = getNationStaticInfo($you);
@@ -381,7 +381,7 @@ function postUpdateMonthly(RandUtil $rng)
$josaWa = JosaUtil::pick($name1, '와'); $josaWa = JosaUtil::pick($name1, '와');
$josaYi = JosaUtil::pick($name2, '이'); $josaYi = JosaUtil::pick($name2, '이');
$globalLogger->pushGlobalHistoryLog("<R><b>【전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>전</>합니다."); $globalLogger->pushGlobalHistoryLog("<R><b>【전】</b></><D><b>$name1</b></>{$josaWa} <D><b>$name2</b></>{$josaYi} <S>전</>합니다.");
$db->update('diplomacy', [ $db->update('diplomacy', [
'state' => 2, 'state' => 2,
'term' => 0, 'term' => 0,
@@ -451,7 +451,7 @@ function checkWander(RandUtil $rng)
$wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12'); $wanderers = $db->queryFirstColumn('SELECT general.`no` FROM general LEFT JOIN nation ON general.nation = nation.nation WHERE nation.`level` = 0 AND general.`officer_level` = 12');
foreach (General::createGeneralObjListFromDB($wanderers) as $wanderer) { foreach (General::createObjListFromDB($wanderers) as $wanderer) {
$wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin); $wanderCmd = buildGeneralCommandClass('che_해산', $wanderer, $admin);
if ($wanderCmd->hasFullConditionMet()) { if ($wanderCmd->hasFullConditionMet()) {
$logger = $wanderer->getLogger(); $logger = $wanderer->getLogger();
@@ -559,7 +559,7 @@ function checkStatistic()
$nationHist = ''; $nationHist = '';
foreach (GameConst::$availableNationType as $nationType) { foreach (GameConst::$availableNationType as $nationType) {
if (!Util::array_get($nationHists[$nationType])) { if (!($nationHists[$nationType] ?? null)) {
$nationHists[$nationType] = '-'; $nationHists[$nationType] = '-';
} }
$nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), "; $nationHist .= getNationType($nationType) . "({$nationHists[$nationType]}), ";
@@ -743,7 +743,7 @@ function checkEmperior()
} }
$inheritPointManager = InheritancePointManager::getInstance(); $inheritPointManager = InheritancePointManager::getInstance();
$allUserGenerals = General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc < 2')); $allUserGenerals = General::createObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc < 2'));
foreach ($allUserGenerals as $genObj) { foreach ($allUserGenerals as $genObj) {
if ($genObj->getNationID() == $nationID) { if ($genObj->getNationID() == $nationID) {
if ($genObj->getVar('officer_level') > 4) { if ($genObj->getVar('officer_level') > 4) {
@@ -899,7 +899,7 @@ function checkEmperior()
'tiger' => $tigerstr, 'tiger' => $tigerstr,
'eagle' => $eaglestr, 'eagle' => $eaglestr,
'gen' => $gen, 'gen' => $gen,
'history' => JSON::encode($nationHistory), 'history' => Json::encode($nationHistory),
'aux' => $statGeneral['aux'] 'aux' => $statGeneral['aux']
]); ]);
@@ -951,8 +951,19 @@ function updateMaxDomesticCritical(General $general, $score)
} }
} }
function genGenericUniqueRNG(int $year, int $month, int $generalID): RandUtil function genGenericUniqueRNG(int $year, int $month, int $generalID, ?string $reason = null): RandUtil
{ {
if($reason){
return new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'unique',
$year,
$month,
$generalID,
$reason
)));
}
return new RandUtil(new LiteHashDRBG(Util::simpleSerialize( return new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed, UniqueConst::$hiddenSeed,
'unique', 'unique',
@@ -962,7 +973,7 @@ function genGenericUniqueRNG(int $year, int $month, int $generalID): RandUtil
))); )));
} }
function genGenericUniqueRNGFromGeneral(General $general): RandUtil function genGenericUniqueRNGFromGeneral(General $general, string $reason): RandUtil
{ {
$logger = $general->getLogger(); $logger = $general->getLogger();
if (!$logger) { if (!$logger) {
@@ -971,5 +982,5 @@ function genGenericUniqueRNGFromGeneral(General $general): RandUtil
$year = $logger->getYear(); $year = $logger->getYear();
$month = $logger->getMonth(); $month = $logger->getMonth();
$generalID = $general->getID(); $generalID = $general->getID();
return genGenericUniqueRNG($year, $month, $generalID); return genGenericUniqueRNG($year, $month, $generalID, $reason);
} }
+2 -2
View File
@@ -138,7 +138,7 @@ function JSCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): array{
$distanceList = searchDistance($cityNo, $maxDistance, true); $distanceList = searchDistance($cityNo, $maxDistance, true);
$result = []; $result = [];
for ($dist = 1; $dist <= $maxDistance; $dist++) { for ($dist = 1; $dist <= $maxDistance; $dist++) {
$result[$dist] = Util::array_get($distanceList[$dist], []); $result[$dist] = $distanceList[$dist] ?? [];
} }
return $result; return $result;
} }
@@ -152,7 +152,7 @@ function printCitiesBasedOnDistance(int $cityNo, int $maxDistance = 1): string
for ($dist = 1; $dist <= $maxDistance; $dist++) { for ($dist = 1; $dist <= $maxDistance; $dist++) {
$cityList = array_map(function ($cityID) { $cityList = array_map(function ($cityID) {
return CityConst::byID($cityID)->name; return CityConst::byID($cityID)->name;
}, Util::array_get($distanceList[$dist], [])); }, $distanceList[$dist] ?? []);
$cityStr = join(', ', $cityList); $cityStr = join(', ', $cityList);
-57
View File
@@ -148,63 +148,6 @@ function allButton(bool $seizeNPCMode, array $opts = [])
], $opts)); ], $opts));
} }
function commandButton(array $opts = [])
{
$session = Session::getInstance();
$userID = Session::getUserID();
if (!$session->isGameLoggedIn()) {
return '';
}
$db = DB::db();
$me = $db->queryFirstRow("select no,nation,officer_level,belong,permission,penalty from general where owner=%i", $userID);
$nation = $db->queryFirstRow("select nation,level,color,secretlimit from nation where nation=%i", $me['nation']) ?? [
'nation' => 0,
'level' => 0,
'secretlimit' => 99,
'color' => '#000000'
];
$bgColor = $nation['color'] ?? '#000000';
$fgColor = newColor($bgColor);
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
$showSecret = false;
$permission = checkSecretPermission($me);
$btnClassForTournament = $opts['btnClass'];
if ($opts['isTournamentApplicationOpen']) {
if ($btnClassForTournament != 'dropdown-item') {
$btnClassForTournament = 'toolbarButton2';
}
}
$btnClassForBetting = $opts['btnClass'];
if ($opts['isBettingActive']) {
if ($btnClassForTournament != 'dropdown-item') {
$btnClassForBetting = 'toolbarButton2';
}
}
if ($permission >= 1) {
$showSecret = true;
} else if ($me['officer_level'] == 0) {
$showSecret = false;
}
return $templates->render('commandButton', array_merge([
'bgColor' => $bgColor,
'fgColor' => $fgColor,
'meLevel' => $me['officer_level'],
'nationLevel' => $nation['level'],
'showSecret' => $showSecret,
'permission' => $permission,
'btnClassForTournament' => $btnClassForTournament,
'btnClassForBetting' => $btnClassForBetting,
], $opts));
}
function formatWounded(int $value, int $wound): string function formatWounded(int $value, int $wound): string
{ {
if ($wound == 0) { if ($wound == 0) {
+8 -1
View File
@@ -364,7 +364,14 @@ function disaster(RandUtil $rng) {
$logger->flush(); $logger->flush();
if (!$isGood) { if (!$isGood) {
$generalListByCity = Util::arrayGroupBy($db->query('SELECT no, name, nation, city, officer_level, injury, leadership, strength, intel, horse, weapon, book, item, crew, crewtype, atmos, train, special, special2 FROM general WHERE city IN %li', Util::squeezeFromArray($targetCityList, 'city')), 'city'); [$queryColumns,,] = General::mergeQueryColumn();
$generalListByCity = Util::arrayGroupBy(
$db->query(
'SELECT %l FROM general WHERE city IN %li',
Util::formatListOfBackticks($queryColumns),
Util::squeezeFromArray($targetCityList, 'city')
),
'city');
//NOTE: 쿼리 1번이지만 복잡하기 vs 쿼리 여러번이지만 조금 더 깔끔하기 //NOTE: 쿼리 1번이지만 복잡하기 vs 쿼리 여러번이지만 조금 더 깔끔하기
foreach ($targetCityList as $city) { foreach ($targetCityList as $city) {
$affectRatio = Util::valueFit($city['secu'] / $city['secu_max'] / 0.8, 0, 1); $affectRatio = Util::valueFit($city['secu'] / $city['secu_max'] / 0.8, 0, 1);
+9 -5
View File
@@ -882,7 +882,7 @@ function setGift($tnmt_type, $tnmt, $phase)
//포상 장수 이름, 금액 //포상 장수 이름, 금액
$resultHelper[$generalID]['reward'] += $cost; $resultHelper[$generalID]['reward'] += $cost;
$resultHelper[$generalID]['msg'] = "<span class='ev_highlight'>4강 진출</span>"; $resultHelper[$generalID]['msg'] = "<span class='ev_highlight'>4강 진출</span>";
General::createGeneralObjFromDB($generalID)->increaseInheritancePoint(InheritanceKey::tournament, 10); General::createObjFromDB($generalID)->increaseInheritancePoint(InheritanceKey::tournament, 10);
} }
//결승자 명성 돈 //결승자 명성 돈
$cost = $admin['develcost'] * 6; $cost = $admin['develcost'] * 6;
@@ -946,7 +946,7 @@ function setGift($tnmt_type, $tnmt, $phase)
$winnerLogger->pushGlobalHistoryLog("<B><b>【대회】</b></><C>{$tp}</> 대회에서 <Y>{$winner['name']}</>{$josaYiWinner} <C>우승</>, <Y>{$runnerUp['name']}</>{$josaYiRunnerUp} <C>준우승</>을 차지하여 천하에 이름을 떨칩니다!", ActionLogger::EVENT_YEAR_MONTH); $winnerLogger->pushGlobalHistoryLog("<B><b>【대회】</b></><C>{$tp}</> 대회에서 <Y>{$winner['name']}</>{$josaYiWinner} <C>우승</>, <Y>{$runnerUp['name']}</>{$josaYiRunnerUp} <C>준우승</>을 차지하여 천하에 이름을 떨칩니다!", ActionLogger::EVENT_YEAR_MONTH);
$winnerLogger->pushGlobalHistoryLog("<B><b>【대회】</b></><C>{$tp}</> 대회의 <S>우승자</>에게는 <C>{$winnerRewardText}</>, <S>준우승자</>에겐 <C>{$runnerUpRewardText}</>의 <S>상금</>과 약간의 <S>명성</>이 주어집니다!", ActionLogger::EVENT_YEAR_MONTH); $winnerLogger->pushGlobalHistoryLog("<B><b>【대회】</b></><C>{$tp}</> 대회의 <S>우승자</>에게는 <C>{$winnerRewardText}</>, <S>준우승자</>에겐 <C>{$runnerUpRewardText}</>의 <S>상금</>과 약간의 <S>명성</>이 주어집니다!", ActionLogger::EVENT_YEAR_MONTH);
$generalObjList = General::createGeneralObjListFromDB(array_keys($resultHelper)); $generalObjList = General::createObjListFromDB(array_keys($resultHelper));
foreach ($resultHelper as $generalID => $general) { foreach ($resultHelper as $generalID => $general) {
$rewardText = number_format($general['reward']); $rewardText = number_format($general['reward']);
@@ -1153,21 +1153,25 @@ function fight($tnmt_type, $tnmt, $phs, $group, $g1, $g2, $type)
]; ];
//막판 분노 //막판 분노
$factor1 = 1.0;
$factor2 = 1.0;
$ratio = rand() % 300; $ratio = rand() % 300;
if ($e1 / 5 > $energy1 && $damage1 > $damage2 && $gen1[$tp] >= $ratio) { if ($e1 / 5 > $energy1 && $damage1 > $damage2 && $gen1[$tp] >= $ratio) {
$damage2 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500% $factor2 = Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical1 = 1; $critical1 = 1;
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]); $str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen1['name']}</>의 분노의 <M>{$str}</> 공격!"; $log[] = "<S>●</> <Y>{$gen1['name']}</>의 분노의 <M>{$str}</> 공격!";
} }
$ratio = rand() % 300; $ratio = rand() % 300;
if ($e2 / 5 > $energy2 && $damage2 > $damage1 && $gen2[$tp] >= $ratio) { if ($e2 / 5 > $energy2 && $damage2 > $damage1 && $gen2[$tp] >= $ratio) {
$damage1 *= Util::round((rand() % 301 + 200) / 100); // 200 ~ 500% $factor1 = Util::round((rand() % 301 + 200) / 100); // 200 ~ 500%
$critical2 = 1; $critical2 = 1;
$str = Util::choiceRandom($crticialSkillMap[$tnmt_type]); $str = Util::choiceRandom($crticialSkillMap[$tnmt_type]);
$log[] = "<S>●</> <Y>{$gen2['name']}</>의 분노의 <M>{$str}</> 공격!"; $log[] = "<S>●</> <Y>{$gen2['name']}</>의 분노의 <M>{$str}</> 공격!";
} }
$damage1 *= $factor1;
$damage2 *= $factor2;
//1합 승부 //1합 승부
if ($phase == 1) { if ($phase == 1) {
+2 -2
View File
@@ -7,10 +7,10 @@ include "func.php";
$session = Session::requireLogin(); $session = Session::requireLogin();
if ($session->userGrade < 5) { if ($session->userGrade < 6) {
die('관리자 아님'); die('관리자 아님');
} }
if ($session->userGrade == 5) { if ($session->userGrade == 6) {
die('DB 리셋 권한을 가지고 있지 않습니다.'); die('DB 리셋 권한을 가지고 있지 않습니다.');
} }
+1 -1
View File
@@ -18,7 +18,7 @@ else{
$availableNextCall = $session->availableNextCallGetCityList??'2000-01-01 00:00:00'; $availableNextCall = $session->availableNextCallGetCityList??'2000-01-01 00:00:00';
$now = new \DateTimeImmutable(); $now = new \DateTimeImmutable();
if($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 5){ if($now <= new \DateTimeImmutable($availableNextCall) && $session->userGrade < 6){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>"도시 목록은 10초에 한번 갱신 가능합니다.\n다음 시간 : ".$availableNextCall 'reason'=>"도시 목록은 10초에 한번 갱신 가능합니다.\n다음 시간 : ".$availableNextCall
+24 -6
View File
@@ -10,7 +10,23 @@ function sortTokens(&$tokens){
}); });
} }
function putInfoText(&$info){ function putInfoText(&$info, ?array $currentTargetEnv){
if (($info['event100Growth'] ?? false) === true) {
if ($currentTargetEnv === null) {
$displayStats = CentennialAllStarGrowthService::calculateUserInitialStats($info);
$info['selectionStatLabel'] = '시작 능력치';
} else {
$displayStats = CentennialAllStarGrowthService::calculateUserCurrentTargetStats(
$info,
$currentTargetEnv
);
$info['selectionStatLabel'] = '현재 변경 기준 능력치';
}
$info['selectionLeadership'] = $displayStats['leadership'];
$info['selectionStrength'] = $displayStats['strength'];
$info['selectionIntel'] = $displayStats['intel'];
}
if(key_exists('specialDomestic', $info)){ if(key_exists('specialDomestic', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialDomestic']); $class = buildGeneralSpecialDomesticClass($info['specialDomestic']);
$info['specialDomesticName'] = $class->getName(); $info['specialDomesticName'] = $class->getName();
@@ -34,7 +50,8 @@ $now = $oNow->format('Y-m-d H:i:s');
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$npcmode = $gameStor->getValue('npcmode'); $eventEnv = $gameStor->getValues(['npcmode', 'startyear', 'year', 'month']);
$npcmode = $eventEnv['npcmode'];
if($npcmode!=2){ if($npcmode!=2){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
@@ -42,7 +59,8 @@ if($npcmode!=2){
]); ]);
} }
$rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID); $rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID);
$currentTargetEnv = $rawGeneral ? $eventEnv : null;
if($rawGeneral){ if($rawGeneral){
$generalAux = Json::decode($rawGeneral['aux']); $generalAux = Json::decode($rawGeneral['aux']);
if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){ if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){
@@ -62,7 +80,7 @@ if($tokens){
foreach($tokens as $token){ foreach($tokens as $token){
$valid_until = $token['reserved_until']; $valid_until = $token['reserved_until'];
$info = Json::decode($token['info']); $info = Json::decode($token['info']);
putInfoText($info); putInfoText($info, $currentTargetEnv);
$info['uniqueName'] = $token['unique_name']; $info['uniqueName'] = $token['unique_name'];
$pick[] = $info; $pick[] = $info;
} }
@@ -83,7 +101,7 @@ $valid_until = null;
foreach(pickGeneralFromPool($db, $rng, $userID, 14) as $pickObj){ foreach(pickGeneralFromPool($db, $rng, $userID, 14) as $pickObj){
$valid_until = $pickObj->getValidUntil(); $valid_until = $pickObj->getValidUntil();
$info = $pickObj->getInfo(); $info = $pickObj->getInfo();
putInfoText($info); putInfoText($info, $currentTargetEnv);
$pick[] = $info; $pick[] = $info;
} }
sortTokens($pick);//좀 무식하지만.. sortTokens($pick);//좀 무식하지만..
@@ -91,4 +109,4 @@ Json::die([
'result'=>true, 'result'=>true,
'pick'=>$pick, 'pick'=>$pick,
'validUntil'=>$valid_until 'validUntil'=>$valid_until
]); ]);
+22 -14
View File
@@ -199,17 +199,25 @@ if($reserve_open){
]); ]);
} }
Json::die(ResetHelper::buildScenario( try{
$turnterm, Json::die(ResetHelper::buildScenario(
$sync, $turnterm,
$scenario, $sync,
$fiction, $scenario,
$extend, $fiction,
$block_general_create, $extend,
$npcmode, $block_general_create,
$show_img_level, $npcmode,
!!$tournament_trig, $show_img_level,
$join_mode, !!$tournament_trig,
TimeUtil::now(), $join_mode,
$autorun_user TimeUtil::now(),
)); $autorun_user
));
}
catch(\Exception $e){
Json::die([
'result'=>false,
'reason'=>$e->getMessage()
]);
}
+29 -14
View File
@@ -53,22 +53,17 @@ if($fullReset){
} }
} }
function dbConnFail($params){ $db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4');
$db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$db->addHook('run_failed', function(){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'DB 접속에 실패했습니다.' 'reason'=>'DB 접속에 실패했습니다.'
]); ]);
} });
$mysqli_obj = $db->get();
$db = new \MeekroDB($host,$username,$password,$dbName,$port,'utf8mb4');
$db->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
$db->throw_exception_on_nonsql_error = false;
$db->nonsql_error_handler = 'dbConnFail';
$mysqli_obj = $db->get(); //로그인에 실패할 경우 자동으로 dbConnFail()이 실행됨.
$prefix = basename(__DIR__); $prefix = basename(__DIR__);
@@ -84,8 +79,6 @@ $result = Util::generateFileUsingSimpleTemplate(
], true ], true
); );
if($result !== true){ if($result !== true){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
@@ -93,7 +86,29 @@ if($result !== true){
]); ]);
} }
ResetHelper::clearDB(); //최소한의 테이블 처리를 위해 수동으로 초기화하도록 하자
if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/reset.sql'))){
while(true){
if (!$mysqli_obj->more_results()) {
break;
}
if(!$mysqli_obj->next_result()){
break;
}
}
}
if($mysqli_obj->multi_query(file_get_contents(__DIR__.'/sql/schema.sql'))){
while(true){
if (!$mysqli_obj->more_results()) {
break;
}
if(!$mysqli_obj->next_result()){
break;
}
}
}
ServConfig::getServerList()[$prefix]->closeServer(); ServConfig::getServerList()[$prefix]->closeServer();
+9 -1
View File
@@ -19,7 +19,15 @@ if(!prepareDir('data/file_cache')){
]); ]);
} }
$storage = new \Nette\Caching\Storages\FileStorage('data/file_cache'); $absolutePath = realpath('data/file_cache');
if(!$absolutePath){
Json::die([
'result'=>false,
'reason'=>'cache 불가'
]);
}
$storage = new \Nette\Caching\Storages\FileStorage($absolutePath);
$cache = new Cache($storage); $cache = new Cache($storage);
$serverID = UniqueConst::$serverID; $serverID = UniqueConst::$serverID;
+131 -104
View File
@@ -1,8 +1,12 @@
<?php <?php
namespace sammo; namespace sammo;
use sammo\Enums\GeneralColumn;
use sammo\Enums\GeneralLiteQueryMode;
use sammo\Enums\GeneralQueryMode; use sammo\Enums\GeneralQueryMode;
use sammo\Enums\MessageType; use sammo\Enums\MessageType;
use sammo\Enums\PenaltyKey;
include "lib.php"; include "lib.php";
include "func.php"; include "func.php";
@@ -20,97 +24,99 @@ $userID = Session::getUserID();
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['startyear','year','month','scenario']); $gameStor->cacheValues(['startyear', 'year', 'month', 'scenario', 'killturn']);
$me = $db->queryFirstRow('SELECT no,nation,officer_level from general where owner=%i', $userID); $me = $db->queryFirstRow('SELECT no,npc,nation,officer_level,penalty from general where owner=%i', $userID);
$myOfficerLevel = $me['officer_level']; $myOfficerLevel = $me['officer_level'];
$nationID = $me['nation']; $nationID = $me['nation'];
$myPenalty = Json::decode($me['penalty'] ?? '{}');
//수뇌가 아니면 아무것도 할 수 없음 //수뇌가 아니면 아무것도 할 수 없음
if($myOfficerLevel < 5){ if ($myOfficerLevel < 5) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'수뇌가 아닙니다.' 'reason' => '수뇌가 아닙니다.'
]); ]);
} }
if($action === '추방' && $destGeneralID==0){ if ($action === '추방' && $destGeneralID == 0) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'장수가 지정되지 않았습니다.' 'reason' => '장수가 지정되지 않았습니다.'
]); ]);
} }
if($destGeneralID==0){ if ($destGeneralID == 0) {
$general = new DummyGeneral(true); $general = new DummyGeneral(true);
$general->setVar('nation', $nationID); $general->setVar('nation', $nationID);
} } else {
else{ $general = General::createObjFromDB($destGeneralID);
$general = General::createGeneralObjFromDB($destGeneralID, [
'name', 'leadership', 'strength', 'intel', 'gold','rice',
'troop','officer_level','npc','picture','imgsvr',
'permission','penalty','belong', 'crewtype',
'experience', 'dedication', 'betray', 'dedlevel', 'explevel', 'makelimit', 'aux',
], GeneralQueryMode::Lite);
if($general instanceof DummyGeneral){ if ($general instanceof DummyGeneral) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'올바르지 않은 장수입니다.' 'reason' => '올바르지 않은 장수입니다.'
]); ]);
} }
if($nationID != $general->getNationID()){ if ($nationID != $general->getNationID()) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'아국 장수가 아닙니다' 'reason' => '아국 장수가 아닙니다'
]); ]);
} }
} }
if($officerLevel == 12){ if ($officerLevel == 12) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'군주를 대상으로 할 수 없습니다.' 'reason' => '군주를 대상으로 할 수 없습니다.'
]); ]);
} }
function do수뇌임명(General $general, int $targetOfficerLevel):?string{ function do수뇌임명(General $general, int $targetOfficerLevel): ?string
{
global $myPenalty;
if ($myPenalty[PenaltyKey::NoChiefChange->value] ?? false) {
return '수뇌를 임명할 수 없는 상태입니다.';
}
$generalID = $general->getID(); $generalID = $general->getID();
$nationID = $general->getNationID(); $nationID = $general->getNationID();
if($general->hasPenalty(PenaltyKey::NoChief)){
return '수뇌가 될 수 없는 상태입니다.';
}
$db = DB::db(); $db = DB::db();
[$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i',$nationID); [$chiefSet, $nationLevel] = $db->queryFirstList('SELECT chief_set,level FROM nation WHERE nation = %i', $nationID);
// 임명가능 레벨 // 임명가능 레벨
$lv = getNationChiefLevel($nationLevel); $lv = getNationChiefLevel($nationLevel);
if($targetOfficerLevel < $lv){ if ($targetOfficerLevel < $lv) {
return '임명불가능한 관직입니다.'; return '임명불가능한 관직입니다.';
} }
if(isOfficerSet($chiefSet, $targetOfficerLevel)){ if (isOfficerSet($chiefSet, $targetOfficerLevel)) {
return '지금은 임명할 수 없습니다.'; return '지금은 임명할 수 없습니다.';
} }
//기존 장수 일반으로 //기존 장수 일반으로
$db->update('general', [ $db->update('general', [
'officer_level'=>1, 'officer_level' => 1,
'officer_city'=>0, 'officer_city' => 0,
], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID); ], 'nation=%i AND officer_level=%i AND no!=%i', $nationID, $targetOfficerLevel, $generalID);
if($targetOfficerLevel === 11){ if ($targetOfficerLevel === 11) {
} else if ($targetOfficerLevel % 2 == 0) {
} if ($general->getVar('strength') < GameConst::$chiefStatMin) {
else if($targetOfficerLevel % 2 == 0){
if($general->getVar('strength') < GameConst::$chiefStatMin){
return '무력이 부족합니다.'; return '무력이 부족합니다.';
} }
} else {
} if ($general->getVar('intel') < GameConst::$chiefStatMin) {
else{
if($general->getVar('intel') < GameConst::$chiefStatMin){
return '지력이 부족합니다.'; return '지력이 부족합니다.';
} }
} }
@@ -119,52 +125,59 @@ function do수뇌임명(General $general, int $targetOfficerLevel):?string{
$general->setVar('officer_level', $targetOfficerLevel); $general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', 0); $general->setVar('officer_city', 0);
$db->update('nation', [ $db->update('nation', [
'chief_set'=> $db->sqleval('chief_set | %i', doOfficerSet(0, $targetOfficerLevel)), 'chief_set' => $db->sqleval('chief_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'nation=%i', $nationID); ], 'nation=%i', $nationID);
$general->applyDB($db); $general->applyDB($db);
return null; return null;
} }
function do도시임명(General $general, int $cityID, int $targetOfficerLevel):?string{ function do도시임명(General $general, int $cityID, int $targetOfficerLevel): ?string
{
global $myPenalty;
$nationID = $general->getNationID(); $nationID = $general->getNationID();
$db = DB::db(); $db = DB::db();
if(CityConst::byID($cityID) === null){ if (CityConst::byID($cityID) === null) {
return '올바르지 않은 도시입니다'; return '올바르지 않은 도시입니다';
} }
if ($general->getVar(GeneralColumn::officer_level) >= 4 && ($myPenalty[PenaltyKey::NoChiefChange->value] ?? false)) {
return '수뇌인 장수를 변경할 수 없는 상태입니다.';
}
$officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID); $officerSet = $db->queryFirstField('SELECT officer_set FROM city WHERE nation=%i AND city=%i', $nationID, $cityID);
if($officerSet === null){ if ($officerSet === null) {
return '아국 도시가 아닙니다'; return '아국 도시가 아닙니다';
} }
if(isOfficerSet($officerSet, $targetOfficerLevel)){ if (isOfficerSet($officerSet, $targetOfficerLevel)) {
return '이미 다른 장수가 임명되어있습니다'; return '이미 다른 장수가 임명되어있습니다';
} }
//기존 장수 일반으로 //기존 장수 일반으로
$db->update('general', [ $db->update('general', [
'officer_level'=>1, 'officer_level' => 1,
'officer_city'=>0, 'officer_city' => 0,
], 'officer_level=%i AND officer_city=%i AND no!=%i', $targetOfficerLevel, $cityID, $general->getID()); ], 'officer_level=%i AND officer_city=%i AND no!=%i', $targetOfficerLevel, $cityID, $general->getID());
if($general instanceof DummyGeneral){ if ($general instanceof DummyGeneral) {
return null; return null;
} }
if($targetOfficerLevel === 4 && $general->getVar('strength') < GameConst::$chiefStatMin){ if ($targetOfficerLevel === 4 && $general->getVar('strength') < GameConst::$chiefStatMin) {
return '무력이 부족합니다.'; return '무력이 부족합니다.';
} }
if($targetOfficerLevel === 3 && $general->getVar('intel') < GameConst::$chiefStatMin){ if ($targetOfficerLevel === 3 && $general->getVar('intel') < GameConst::$chiefStatMin) {
return '지력이 부족합니다.'; return '지력이 부족합니다.';
} }
//신임 장수 //신임 장수
$db->update('city', [ $db->update('city', [
'officer_set'=>$db->sqleval('officer_set | %i', doOfficerSet(0, $targetOfficerLevel)), 'officer_set' => $db->sqleval('officer_set | %i', doOfficerSet(0, $targetOfficerLevel)),
], 'city=%i AND nation=%i', $cityID, $nationID); ], 'city=%i AND nation=%i', $cityID, $nationID);
$general->setVar('officer_level', $targetOfficerLevel); $general->setVar('officer_level', $targetOfficerLevel);
$general->setVar('officer_city', $cityID); $general->setVar('officer_city', $cityID);
@@ -173,22 +186,25 @@ function do도시임명(General $general, int $cityID, int $targetOfficerLevel):
return null; return null;
} }
function do추방(General $general, int $myOfficerLevel):?string{ function do추방(General $general, int $myOfficerLevel): ?string
{
$generalID = $general->getID(); $generalID = $general->getID();
$generalName = $general->getVar('name'); $generalName = $general->getVar('name');
$nationID = $general->getNationID(); $nationID = $general->getNationID();
if ($myPenalty[PenaltyKey::NoBanGeneral->value] ?? false) {
return '추방할 수 없는 상태입니다.';
}
//추방할사람이 외교권자이면 불가 //추방할사람이 외교권자이면 불가
$permission = checkSecretPermission($general->getRaw()); $permission = checkSecretPermission($general->getRaw());
if($permission == 4){ if ($permission == 4) {
return '외교권자는 추방할 수 없습니다.'; return '외교권자는 추방할 수 없습니다.';
} }
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$env = $gameStor->getValues(['startyear','year','month','scenario']); $env = $gameStor->getValues(['startyear', 'year', 'month', 'scenario']);
$nation = $db->queryFirstRow('SELECT name,chief_set,color FROM nation WHERE nation=%i', $nationID); $nation = $db->queryFirstRow('SELECT name,chief_set,color FROM nation WHERE nation=%i', $nationID);
$nationName = $nation['name']; $nationName = $nation['name'];
@@ -196,17 +212,17 @@ function do추방(General $general, int $myOfficerLevel):?string{
$logger = $general->getLogger(); $logger = $general->getLogger();
//이미 지정했다면 무시 //이미 지정했다면 무시
if(isOfficerSet($nation['chief_set'], $myOfficerLevel) || ($myOfficerLevel == 0 && $myOfficerLevel == 12)) { if (isOfficerSet($nation['chief_set'], $myOfficerLevel) || ($myOfficerLevel == 0 && $myOfficerLevel == 12)) {
return '이미 추방 권한을 사용했습니다.'; return '이미 추방 권한을 사용했습니다.';
} }
$gold = 0; $gold = 0;
$rice = 0; $rice = 0;
// 금쌀1000이상은 남김 // 금쌀1000이상은 남김
if($general->getVar('gold') > GameConst::$defaultGold) { if ($general->getVar('gold') > GameConst::$defaultGold) {
$gold = $general->getVar('gold') - GameConst::$defaultGold; $gold = $general->getVar('gold') - GameConst::$defaultGold;
$general->setVar('gold', GameConst::$defaultGold); $general->setVar('gold', GameConst::$defaultGold);
} }
if($general->getVar('rice') > GameConst::$defaultRice) { if ($general->getVar('rice') > GameConst::$defaultRice) {
$rice = $general->getVar('rice') - GameConst::$defaultRice; $rice = $general->getVar('rice') - GameConst::$defaultRice;
$general->setVar('rice', GameConst::$defaultRice); $general->setVar('rice', GameConst::$defaultRice);
} }
@@ -224,27 +240,26 @@ function do추방(General $general, int $myOfficerLevel):?string{
$logger->pushGeneralActionLog("<D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.", ActionLogger::PLAIN); $logger->pushGeneralActionLog("<D><b>{$nationName}</b></>에서 <R>추방</>당했습니다.", ActionLogger::PLAIN);
// 명성/공헌 N*10%감소 // 명성/공헌 N*10%감소
if($env['year'] <= $env['startyear'] && $general->getNPCType() < 2){ if ($env['year'] <= $env['startyear'] && $general->getNPCType() < 2) {
$general->setVar('makelimit', $oldMakeLimit); $general->setVar('makelimit', $oldMakeLimit);
} } else {
else{
$betrayCnt = $general->getVar('betray'); $betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt); $general->addExperience(-$general->getVar('experience') * 0.15 * $betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt); $general->addDedication(-$general->getVar('dedication') * 0.15 * $betrayCnt);
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt); $general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
} }
//부대장일 경우 //부대장일 경우
if($general->getVar('troop') == $generalID){ if ($general->getVar('troop') == $generalID) {
// 모두 탈퇴 // 모두 탈퇴
$db->update('general', [ $db->update('general', [
'troop'=>0, 'troop' => 0,
], 'troop = %i', $generalID); ], 'troop = %i', $generalID);
$db->delete('troop', 'troop_leader=%i', $generalID); $db->delete('troop', 'troop_leader=%i', $generalID);
} }
$general->setVar('troop', 0); $general->setVar('troop', 0);
if($general->getNPCType() >= 2){ if ($general->getNPCType() >= 2) {
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize( $rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed, UniqueConst::$hiddenSeed,
'BanNPC', 'BanNPC',
@@ -283,24 +298,24 @@ function do추방(General $general, int $myOfficerLevel):?string{
} }
} }
if($env['year'] < $env['startyear']+3) { if ($env['year'] < $env['startyear'] + 3) {
//초반엔 군주 부상 증가(엔장 임관지양) //초반엔 군주 부상 증가(엔장 임관지양)
$db->update('general', [ $db->update('general', [
'injury'=>$db->sqleval('least(injury + 1, %i)', 80), 'injury' => $db->sqleval('least(injury + 1, %i)', 80),
], 'nation=%i AND officer_level=12', $nationID); ], 'nation=%i AND officer_level=12', $nationID);
$db->update('nation', [ $db->update('nation', [
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0), 'gennum' => $db->sqleval('gennum - %i', $general->getNPCType() != 5 ? 1 : 0),
'gold'=>$db->sqleval('gold + %i', $gold), 'gold' => $db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice), 'rice' => $db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID); ], 'nation = %i', $nationID);
} else { } else {
//이번분기는 추방불가(초반 제외) //이번분기는 추방불가(초반 제외)
$db->update('nation', [ $db->update('nation', [
'chief_set'=>$db->sqleval('chief_set | %i', doOfficerSet(0, $myOfficerLevel)), 'chief_set' => $db->sqleval('chief_set | %i', doOfficerSet(0, $myOfficerLevel)),
'gennum'=>$db->sqleval('gennum - %i', $general->getNPCType()!=5?1:0), 'gennum' => $db->sqleval('gennum - %i', $general->getNPCType() != 5 ? 1 : 0),
'gold'=>$db->sqleval('gold + %i', $gold), 'gold' => $db->sqleval('gold + %i', $gold),
'rice'=>$db->sqleval('rice + %i', $rice), 'rice' => $db->sqleval('rice + %i', $rice),
], 'nation = %i', $nationID); ], 'nation = %i', $nationID);
} }
@@ -312,62 +327,74 @@ function do추방(General $general, int $myOfficerLevel):?string{
if($action == "임명") { if ($action == "임명") {
if(2 <= $officerLevel && $officerLevel <= 4){ if (2 <= $officerLevel && $officerLevel <= 4) {
if(!$destCityID){ if (!$destCityID) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'도시가 지정되지 않았습니다.' 'reason' => '도시가 지정되지 않았습니다.'
]); ]);
} }
$result = do도시임명($general, $destCityID, $officerLevel); $result = do도시임명($general, $destCityID, $officerLevel);
if($result !== null){ if ($result !== null) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>$result 'reason' => $result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result' => true,
'reason'=>'success' 'reason' => 'success'
]); ]);
} }
if(5 <= $officerLevel && $officerLevel < 12){ if (5 <= $officerLevel && $officerLevel < 12) {
$result = do수뇌임명($general, $officerLevel); $result = do수뇌임명($general, $officerLevel);
if($result !== null){ if ($result !== null) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>$result 'reason' => $result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result' => true,
'reason'=>'success' 'reason' => 'success'
]); ]);
} }
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'올바르지 않은 지정입니다.' 'reason' => '올바르지 않은 지정입니다.'
]); ]);
} }
if($action == "추방") { if ($action == "추방") {
$result = do추방($general, $myOfficerLevel); $result = do추방($general, $myOfficerLevel);
if($result !== null){ if ($result !== null) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>$result 'reason' => $result
]); ]);
} }
//수뇌의 삭턴 리필
$db->update('general', [
'killturn' => $db->sqleval('GREATEST(%b, %i)', 'killturn', $gameStor->getValue('killturn')),
], 'no=%i', $me['no']);
Json::die([ Json::die([
'result'=>true, 'result' => true,
'reason'=>'success' 'reason' => 'success'
]); ]);
} }
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'올바르지 않은 명령입니다.' 'reason' => '올바르지 않은 명령입니다.'
]); ]);
+1 -1
View File
@@ -8,7 +8,7 @@ include('func.php');
$session = Session::requireLogin([])->setReadOnly(); $session = Session::requireLogin([])->setReadOnly();
if(Session::getInstance()->userGrade < 5){ if(Session::getInstance()->userGrade < 6){
Json::die([ Json::die([
'reason'=>'권한이 부족합니다.' 'reason'=>'권한이 부족합니다.'
]); ]);
+16 -4
View File
@@ -27,14 +27,25 @@ $rootDB = RootDB::db();
$oNow = new \DateTimeImmutable(); $oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s'); $now = $oNow->format('Y-m-d H:i:s');
$userNick = RootDB::db()->queryFirstField('SELECT `NAME` FROM member WHERE `NO`=%i',$userID); $member = $rootDB->queryFirstRow('SELECT `name`, `penalty` FROM member WHERE `NO`=%i', $userID);
if(!$userNick){ if(!$member){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.' 'reason'=>'멤버 정보를 가져오지 못했습니다.'
]); ]);
} }
$userNick = $member['name'];
$memberPenalty = Json::decode($member['penalty'] ?? '{}');
$penaltyInfo = array_merge($memberPenalty['any'] ?? [], $memberPenalty[DB::prefix()] ?? []);
$penalty = [];
foreach($penaltyInfo as $penaltyKey => $penaltyValue){
if(($penaltyValue['expire'] ?? 0) > TimeUtil::now()){
$penalty[$penaltyKey] = $penaltyValue['value'];
}
}
$pickResult = $db->queryFirstField('SELECT pick_result FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now); $pickResult = $db->queryFirstField('SELECT pick_result FROM select_npc_token WHERE `owner`=%i AND `valid_until`>=%s', $userID, $now);
if(!$pickResult){ if(!$pickResult){
Json::die([ Json::die([
@@ -86,10 +97,11 @@ $db->update('general', [
'defence_train'=>80, 'defence_train'=>80,
'permission'=>'normal', 'permission'=>'normal',
'owner'=>$userID, 'owner'=>$userID,
'aux'=>Json::encode($genAux) 'aux'=>Json::encode($genAux),
'penalty'=>Json::encode($penalty),
], 'owner <= 0 AND npc = 2 AND no = %i', $pick); ], 'owner <= 0 AND npc = 2 AND no = %i', $pick);
$db->insertIgnore('general_access_log', [ $db->insertIgnore('general_access_log', [
GeneralAccessLogColumn::generalID->value => $generalID, GeneralAccessLogColumn::generalID->value => $pick,
GeneralAccessLogColumn::userID->value => $userID, GeneralAccessLogColumn::userID->value => $userID,
GeneralAccessLogColumn::lastRefresh->value => $now, GeneralAccessLogColumn::lastRefresh->value => $now,
]); ]);
+88 -16
View File
@@ -8,10 +8,20 @@ WebUtil::requireAJAX();
$pick = Util::getPost('pick'); $pick = Util::getPost('pick');
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin); $leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$strength = Util::getPost('leadership', 'int', GameConst::$defaultStatMin); $isCentennialAllStar = CentennialAllStarGrowthService::isActive();
$intel = Util::getPost('leadership', 'int', GameConst::$defaultStatMin); $strength = Util::getPost(
$isCentennialAllStar ? 'strength' : 'leadership',
'int',
GameConst::$defaultStatMin
);
$intel = Util::getPost(
$isCentennialAllStar ? 'intel' : 'leadership',
'int',
GameConst::$defaultStatMin
);
$personal = Util::getPost('personal', 'string', null); $personal = Util::getPost('personal', 'string', null);
$use_own_picture = Util::getPost('use_own_picture', 'bool', false); $use_own_picture = Util::getPost('use_own_picture', 'bool', false);
$pictureSource = Util::getPost('picture_source', 'string', 'selected');
if(!$pick){ if(!$pick){
@@ -60,16 +70,39 @@ if(!$selectInfo){
} }
$selectInfo = Json::decode($selectInfo); $selectInfo = Json::decode($selectInfo);
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID); $ownerInfo = RootDB::db()->queryFirstRow(
if(!$ownerInfo){ 'SELECT `name`,`picture`,`imgsvr`,`grade` FROM member WHERE `NO`=%i',
$userID
);
if(!$ownerInfo){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.' 'reason'=>'멤버 정보를 가져오지 못했습니다.'
]); ]);
} }
if ($isCentennialAllStar) {
if (!in_array($pictureSource, ['selected', 'own'], true)) {
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2'); Json::die([
'result' => false,
'reason' => '올바르지 않은 전콘 선택입니다.',
]);
}
if ($pictureSource === 'own') {
$canUseOwnPicture = in_array('picture', GameConst::$generalPoolAllowOption, true)
&& $env['show_img_level'] >= 1
&& $ownerInfo['grade'] >= 1
&& $ownerInfo['picture'] !== '';
if (!$canUseOwnPicture) {
Json::die([
'result' => false,
'reason' => '사용할 수 있는 내 전콘이 없습니다.',
]);
}
}
}
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
if ($gencount >= $maxgeneral) { if ($gencount >= $maxgeneral) {
Json::die([ Json::die([
@@ -80,12 +113,25 @@ if ($gencount >= $maxgeneral) {
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool); $poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
/** @var AbsGeneralPool */ /** @var AbsGeneralPool */
$pickedGeneral = new $poolClass($db, $selectInfo, $now); if ($isCentennialAllStar) {
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'selectPickedGeneral',
$userID,
$pick
)));
$pickedGeneral = new $poolClass($db, $rng, $selectInfo, $now);
} else {
$pickedGeneral = new $poolClass($db, $selectInfo, $now);
}
$builder = $pickedGeneral->getGeneralBuilder(); $builder = $pickedGeneral->getGeneralBuilder();
if ($isCentennialAllStar) {
CentennialAllStarGrowthService::prepareInitialUser($builder, $selectInfo);
}
foreach(GameConst::$generalPoolAllowOption as $allowOption){ foreach(GameConst::$generalPoolAllowOption as $allowOption){
if($allowOption == 'stat'){ if($allowOption == 'stat' && !$isCentennialAllStar){
$leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax); $intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
@@ -98,14 +144,23 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){
} }
$builder->setStat($leadership, $strength, $intel); $builder->setStat($leadership, $strength, $intel);
} }
else if($allowOption == 'picture' && $use_own_picture){ else if(
$builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']); $allowOption == 'picture'
&& (
(!$isCentennialAllStar && $use_own_picture)
|| ($isCentennialAllStar && $pictureSource === 'own')
)
){
$builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']);
} }
else if($allowOption == 'ego'){ else if($allowOption == 'ego'){
if(!$personal || $personal == 'Random'){ if(!$personal || $personal == 'Random'){
$personal = Util::choiceRandom(GameConst::$availablePersonality); $personal = Util::choiceRandom(GameConst::$availablePersonality);
} }
if(!array_search($personal, GameConst::$availablePersonality)){ $invalidPersonal = $isCentennialAllStar
? !in_array($personal, GameConst::$availablePersonality, true)
: !array_search($personal, GameConst::$availablePersonality);
if($invalidPersonal){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'올바르지 않은 성격입니다.' 'reason'=>'올바르지 않은 성격입니다.'
@@ -113,7 +168,7 @@ foreach(GameConst::$generalPoolAllowOption as $allowOption){
} }
$builder->setEgo($personal); $builder->setEgo($personal);
} }
} }
$userNick = $ownerInfo['name']; $userNick = $ownerInfo['name'];
@@ -123,6 +178,23 @@ $builder->setKillturn(5);
$builder->setNPCType(0); $builder->setNPCType(0);
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm'])); $builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
$builder->fillRemainSpecAsZero($env); $builder->fillRemainSpecAsZero($env);
if ($isCentennialAllStar) {
$candidateCities = $db->queryFirstColumn(
'SELECT city FROM city WHERE level >= 5 AND level <= 6 AND nation = 0'
);
if (!$candidateCities) {
$candidateCities = $db->queryFirstColumn(
'SELECT city FROM city WHERE level >= 5 AND level <= 6'
);
}
if (!$candidateCities) {
Json::die([
'result' => false,
'reason' => '장수를 생성할 소·중성이 없습니다.',
]);
}
$builder->setCityID($rng->choice($candidateCities));
}
$builder->build($env); $builder->build($env);
$generalID = $builder->getGeneralID(); $generalID = $builder->getGeneralID();
if(!$generalID){ if(!$generalID){
@@ -167,4 +239,4 @@ $rootDB->insert('member_log', [
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
]); ]);
+44 -18
View File
@@ -1,4 +1,5 @@
<?php <?php
namespace sammo; namespace sammo;
include "lib.php"; include "lib.php";
@@ -24,29 +25,31 @@ if ($defence_train <= 40) {
$defence_train = 40; $defence_train = 40;
} }
if($defence_train <= 90){ if ($defence_train <= 90) {
$defence_train = Util::round($defence_train, -1); $defence_train = Util::round($defence_train, -1);
} } else {
else{
$defence_train = 999; $defence_train = 999;
} }
if($tnmt < 0 || $tnmt > 1){ if ($tnmt < 0 || $tnmt > 1) {
$tnmt = 1; $tnmt = 1;
} }
$db = DB::db(); $db = DB::db();
$me = General::createGeneralObjFromDB($generalID); $me = General::createObjFromDB($generalID);
if($defence_train !== $me->getVar('defence_train')){ if ($defence_train !== $me->getVar('defence_train')) {
if($defence_train == 999){ if ($defence_train == 999) {
$me->increaseVar('myset', -1); $me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train); $me->setVar('defence_train', $defence_train);
$me->increaseVarWithLimit('train', -3, 20); $affectedTrain = -3;
$me->increaseVarWithLimit('atmos', -6, 20); $affectedAtmos = -6;
} $affectedTrain = $me->onCalcDomestic('changeDefenceTrain', "train{$defence_train}", $affectedTrain);
else{ $affectedAtmos = $me->onCalcDomestic('changeDefenceTrain', "atmos{$defence_train}", $affectedAtmos);
$me->increaseVarWithLimit('train', $affectedTrain, 20, GameConst::$maxTrainByWar);
$me->increaseVarWithLimit('atmos', $affectedAtmos, 20, GameConst::$maxAtmosByWar);
} else {
$me->increaseVar('myset', -1); $me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train); $me->setVar('defence_train', $defence_train);
} }
@@ -56,21 +59,44 @@ $me->setAuxVar('use_treatment', Util::valueFit($use_treatment, 10, 100));
$me->setAuxVar('use_auto_nation_turn', $use_auto_nation_turn); $me->setAuxVar('use_auto_nation_turn', $use_auto_nation_turn);
$me->setVar('tnmt', $tnmt); $me->setVar('tnmt', $tnmt);
if($me->getNPCType() == 1 && $detachNPC){ if ($me->getNPCType() == 1 && $detachNPC) {
$turnterm = $gameStor->turnterm; $turnterm = $gameStor->turnterm;
if($turnterm < 10){ if ($turnterm < 10) {
$targetKillTurn = 30 / $turnterm; $targetKillTurn = 30 / $turnterm;
} } else {
else{
$targetKillTurn = 60 / $turnterm; $targetKillTurn = 60 / $turnterm;
} }
$me->setVar('killturn', $targetKillTurn); $me->setVar('killturn', $targetKillTurn);
} }
$rootDB = RootDB::db();
//회원 테이블에서 정보확인
$member = $rootDB->queryFirstRow('SELECT `no`, id, picture, grade, `name`, imgsvr, `penalty` FROM member WHERE no=%i', $userID);
if (!$member) {
//이런 경우가 있나?
//TODO: 로그 남겨둘 것
Json::die([
'result' => false,
'reason' => '회원 정보를 찾을 수 없습니다.'
]);
}
$memberPenalty = Json::decode($member['penalty'] ?? "{}");
$penaltyInfo = array_merge($memberPenalty['any'] ?? [], $memberPenalty[DB::prefix()] ?? []);
$penalty = [];
foreach ($penaltyInfo as $penaltyKey => $penaltyValue) {
if (($penaltyValue['expire'] ?? 0) > TimeUtil::now()) {
$penalty[$penaltyKey] = $penaltyValue['value'];
}
}
$me->setVar('penalty', Json::encode($penalty));
$me->applyDB($db); $me->applyDB($db);
Json::die([ Json::die([
'result'=>true, 'result' => true,
'reason'=>'success' 'reason' => 'success'
]); ]);
+78 -26
View File
@@ -7,6 +7,7 @@ include "func.php";
WebUtil::requireAJAX(); WebUtil::requireAJAX();
$pick = Util::getPost('pick'); $pick = Util::getPost('pick');
$pictureSource = Util::getPost('picture_source', 'string', 'selected');
if(!$pick){ if(!$pick){
Json::die([ Json::die([
@@ -35,10 +36,20 @@ if(!$generalID){
list( list(
$year, $year,
$month, $month,
$startYear,
$maxgeneral, $maxgeneral,
$npcmode, $npcmode,
$turnterm $turnterm,
) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode', 'turnterm']); $showImgLevel
) = $gameStor->getValuesAsArray([
'year',
'month',
'startyear',
'maxgeneral',
'npcmode',
'turnterm',
'show_img_level',
]);
if($npcmode!=2){ if($npcmode!=2){
Json::die([ Json::die([
@@ -55,7 +66,10 @@ if(!$info){
]); ]);
} }
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID); $ownerInfo = RootDB::db()->queryFirstRow(
'SELECT `name`,`picture`,`imgsvr`,`grade` FROM member WHERE `NO`=%i',
$userID
);
if(!$ownerInfo){ if(!$ownerInfo){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
@@ -64,9 +78,30 @@ if(!$ownerInfo){
} }
$info = Json::decode($info); $info = Json::decode($info);
$isCentennialAllStar = CentennialAllStarGrowthService::isActive();
if ($isCentennialAllStar) {
if (!in_array($pictureSource, ['current', 'own', 'selected'], true)) {
Json::die([
'result' => false,
'reason' => '올바르지 않은 전콘 선택입니다.',
]);
}
if ($pictureSource === 'own') {
$canUseOwnPicture = in_array('picture', GameConst::$generalPoolAllowOption, true)
&& $showImgLevel >= 1
&& $ownerInfo['grade'] >= 1
&& $ownerInfo['picture'] !== '';
if (!$canUseOwnPicture) {
Json::die([
'result' => false,
'reason' => '사용할 수 있는 내 전콘이 없습니다.',
]);
}
}
}
$generalObj = General::createGeneralObjFromDB($generalID); $generalObj = General::createObjFromDB($generalID);
$oldGeneralName = $generalObj->getName(); $oldGeneralName = $generalObj->getName();
$db->update('select_pool', [ $db->update('select_pool', [
'general_id'=>-$generalID, 'general_id'=>-$generalID,
@@ -101,34 +136,51 @@ $db->update('select_pool',[
'reserved_until'=>null, 'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now); ], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
if(key_exists('leadership', $info)){ if ($isCentennialAllStar) {
$generalObj->updateVar('leadership', $info['leadership']); CentennialAllStarGrowthService::prepareLegacyUserReselection($generalObj);
$generalObj->updateVar('strength', $info['strength']); CentennialAllStarGrowthService::applyTarget($generalObj, $info, [
$generalObj->updateVar('intel', $info['intel']); 'startyear' => $startYear,
'year' => $year,
'month' => $month,
]);
} else {
if(key_exists('leadership', $info)){
$generalObj->updateVar('leadership', $info['leadership']);
$generalObj->updateVar('strength', $info['strength']);
$generalObj->updateVar('intel', $info['intel']);
}
if(key_exists('dex', $info)){
$generalObj->updateVar('dex1', $info['dex'][0]);
$generalObj->updateVar('dex2', $info['dex'][1]);
$generalObj->updateVar('dex3', $info['dex'][2]);
$generalObj->updateVar('dex4', $info['dex'][3]);
$generalObj->updateVar('dex5', $info['dex'][4]);
}
if(key_exists('ego', $info)){
$generalObj->updateVar('personal', $info['ego']);
}
if(key_exists('specialDomestic', $info)){
$generalObj->updateVar('special', $info['specialDomestic']);
}
if(key_exists('specialWar', $info)){
$generalObj->updateVar('special2', $info['specialWar']);
}
} }
if(key_exists('picture', $info)){ if ($isCentennialAllStar) {
if ($pictureSource === 'own') {
$generalObj->updateVar('imgsvr', $ownerInfo['imgsvr']);
$generalObj->updateVar('picture', $ownerInfo['picture']);
} elseif ($pictureSource === 'selected' && key_exists('picture', $info)) {
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
} elseif(key_exists('picture', $info)){
$generalObj->updateVar('imgsvr', $info['imgsvr']); $generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']); $generalObj->updateVar('picture', $info['picture']);
} }
if(key_exists('generalName', $info)){ if(key_exists('generalName', $info)){
$generalObj->updateVar('name', $info['generalName']); $generalObj->updateVar('name', $info['generalName']);
} }
if(key_exists('dex', $info)){
$generalObj->updateVar('dex1', $info['dex'][0]);
$generalObj->updateVar('dex2', $info['dex'][1]);
$generalObj->updateVar('dex3', $info['dex'][2]);
$generalObj->updateVar('dex4', $info['dex'][3]);
$generalObj->updateVar('dex5', $info['dex'][4]);
}
if(key_exists('ego', $info)){
$generalObj->updateVar('personal', $info['ego']);
}
if(key_exists('specialDomestic', $info)){
$generalObj->updateVar('special', $info['specialDomestic']);
}
if(key_exists('specialWar', $info)){
$generalObj->updateVar('special2', $info['specialWar']);
}
$generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm)); $generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm));
$userNick = $ownerInfo['name']; $userNick = $ownerInfo['name'];
@@ -148,4 +200,4 @@ $generalObj->applyDB($db);
Json::die([ Json::die([
'result'=>true, 'result'=>true,
'reason'=>'success' 'reason'=>'success'
]); ]);
+3 -2
View File
@@ -51,8 +51,9 @@ function MessageBox($str)
function LogText($prefix, $variable) function LogText($prefix, $variable)
{ {
$text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable)); return;
file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND); //$text = sprintf('%s : %s'."\r\n", $prefix, TVarDumper::dump($variable));
//file_put_contents(ROOT.'/d_log/'.UniqueConst::$serverName.'_dbg_logs.txt', $text, FILE_APPEND);
} }
function prepareDir(string $dirPath, bool $forceCreate=true):bool{ function prepareDir(string $dirPath, bool $forceCreate=true):bool{
-455
View File
@@ -1,455 +0,0 @@
<?php
namespace sammo;
use sammo\DTO\VoteInfo;
use sammo\Enums\GeneralQueryMode;
include "lib.php";
include "func.php";
$session = Session::requireLogin()->loginGame()->setReadOnly();
$userID = Session::getUserID();
increaseRefresh("메인", 1);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
if (!$userID) {
header('Location:..');
die();
}
//턴 실행.
TurnExecutionHelper::executeAllCommand();
if (!$session->isGameLoggedIn()) {
header('Location:..');
die();
}
$me = $db->queryFirstRow(
'SELECT no,refresh_score,turntime,newmsg,newvote,`officer_level` FROM `general`
LEFT JOIN general_access_log AS l ON `general`.no = l.general_id WHERE owner = %i',
$userID
);
//그새 사망이면
if ($me === null) {
$session->logoutGame();
header('Location: ../');
die();
}
$gameStor->cacheAll(true);
if ($me['newmsg'] == 1 || $me['newvote'] == 1) {
$db->update('general', [
'newmsg' => 0,
'newvote' => 0
], 'owner=%i', $userID);
}
$plock = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1'));
$limitState = checkLimit($me['refresh_score']);
if ($limitState >= 2) {
printLimitMsg($me['turntime']);
exit();
}
$generalObj = General::createGeneralObjFromDB($me['no'], null, GeneralQueryMode::FullWithAccessLog);
$generalObj->setRawCity($db->queryFirstRow('SELECT * FROM city WHERE city = %i', $generalObj->getCityID()));
$scenario = $gameStor->scenario_text;
$nationID = $generalObj->getNationID();
if ($nationID) {
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->cacheAll();
}
if ($gameStor->extended_general == 0) {
$extend = "표준";
} else {
$extend = "확장";
}
if ($gameStor->fiction == 0) {
$fiction = "사실";
} else {
$fiction = "가상";
}
if ($gameStor->npcmode == 0) {
$npcmode = "불가능";
} else if ($gameStor->npcmode == 1) {
$npcmode = "가능";
} else {
$npcmode = "선택 생성";
}
$color = "cyan";
$serverName = UniqueConst::$serverName;
$serverCnt = $gameStor->server_cnt;
$auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0');
$isTournamentActive = $gameStor->tournament > 0;
$isTournamentApplicationOpen = $gameStor->tournament == 1;
$isBettingActive = $gameStor->tournament == 6;
$myNationStatic = getNationStaticInfo($generalObj->getNationID());
$nationColorType = substr($myNationStatic['color'] ?? '#000000', 1);
$autorunUser = ($gameStor->autorun_user) ?? [];
$otherTextInfo = [];
if ($gameStor->join_mode == 'onlyRandom') {
$otherTextInfo[] = '랜덤 임관 전용';
}
if ($autorunUser['limit_minutes'] ?? false) {
$otherTextInfo[] = getAutorunInfo($autorunUser);
}
if (!$otherTextInfo) {
$otherTextInfo = '표준';
} else {
$otherTextInfo = join(', ', $otherTextInfo);
}
$lastVoteID = $gameStor->lastVote;
$lastVote = null;
if ($lastVoteID) {
$voteStor = KVStorage::getStorage($db, 'vote');
$lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
$lastVote = null;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?= $serverName ?>: 메인</title>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=500" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS('d_shared/base_map.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printDist('vue', 'v_main', true) ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printCSS('css/map.css') ?>
<?= WebUtil::printStaticValues([
//deprecated, staticValues를 이용할 것
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'staticValues' => [
'serverName' => $serverName,
'serverCnt' => $serverCnt,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
]
]) ?>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
<body class="img_back sam-color-<?= $nationColorType ?>">
<div id="container" class="bg0">
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></button></div>
</div>
<div class="tb_layout row gx-0">
<div id="server_title" class="row py-2 center">
<h3>삼국지 모의전투 HiDCHe <?= $serverName . $serverCnt ?>기 <span class="avoid-wrap">(<font color=cyan><?= $scenario ?></font>)</span></h3>
</div>
<div class="row center gx-0">
<div class="s-border-t col py-2 col-8 col-lg-4" style="color:<?= $color ?>;">
<?= $scenario ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
NPC 수, 상성 : <?= $extend ?>,<?= $fiction ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
NPC선택 : <?= $npcmode ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
토너먼트 : <?= getTournamentTermText($gameStor->turnterm) ?>
</div>
<div class="s-border-t col py-2 col-4 col-lg-2" style="color:<?= $color ?>;">
기타 설정: <?= $otherTextInfo ?>
</div>
<div class="s-border-t col py-2 col-8 col-lg-4"><?= info(2) ?></div>
<div class="s-border-t col py-2 col-4 col-lg-2">전체 접속자 수 : <?= $gameStor->online_user_cnt ?> 명</div>
<div class="s-border-t col py-2 col-4 col-lg-2">턴당 갱신횟수 : <?= $gameStor->refreshLimit ?>회</div>
<div class="s-border-t col py-2 col-8 col-lg-4"><?= info(3) ?></div>
<div class="s-border-t py-2 col col-6 col-lg-4">
<?php if ($isTournamentActive) : ?>
↑<span style='color:cyan'><?= (['전력전', '통솔전', '일기토', '설전',])[$gameStor->tnmt_type] ?? '' ?> <?= getTournament($gameStor->tournament) ?> <?= getTournamentTime() ?></span>↑
<?php else : ?>
<span style='color:magenta'>현재 토너먼트 경기 없음</span>
<?php endif; ?>
</div>
<div class="s-border-t py-2 col col-6 col-lg-2">
<div style="display:inline-block;"><?= $plock ? ("<span style='color:magenta;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") : ("<span style='color:cyan;'>동작 시각: " . substr($gameStor->turntime, 5, 14) . "</span>") ?></div>
</div>
<div class="s-border-t py-2 col col-6 col-lg-2">
<?php if ($auctionCount > 0) : ?>
<span style='color:cyan'><?= $auctionCount ?>건</span> 거래 진행중
<?php else : ?>
<span style='color:magenta'>진행중 거래 없음</span>
<?php endif; ?>
</div>
<div class="s-border-t py-2 col col-6 col-lg-4 vote-cell">
<?php
?>
<?php if ($lastVote === null) : ?>
<span style='color:magenta'>진행중 설문 없음</span>
<?php else : ?>
<span style='color:cyan'>설문 진행중</span> : <span><?= $lastVote->title ?></span>
<?php endif; ?>
</div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">접속중인 국가: <?= $gameStor->online_nation ?></div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">운영자 메세지 : <span style='color:yellow;'><?= $gameStor->msg ?></span></div>
</div>
<div class="row gx-0">
<div class="col s-border-t py-2" id="nation-msg-position">
<div class="px-2">【 국가방침 】</div>
<div id='nation-msg-box'>
<div id='nation-msg'><?= nationMsg($generalObj) ?></div>
</div>
</div>
</div>
<div class="row gx-0">
<div class="col s-border-t px-2 py-2">
【 접속자 】<?= onlinegen($generalObj) ?>
</div>
</div>
<?php if ($session->userGrade >= 5) : ?>
<div class="row">
<div class="col">
<a href='_admin1.php' target='_blank'><button type='button'>게임관리</button></a>
<a href='_admin2.php' target='_blank'><button type='button'>회원관리</button></a>
<a href='_admin4.php' target='_blank'><button type='button'>멀티관리</button></a>
<a href='_admin5.php' target='_blank'><button type='button'>일제정보</button></a>
<a href='_admin7.php' target='_blank'><button type='button'>로그정보</button></a>
<a href='_admin8.php' target='_blank'><button type='button'>외교정보</button></a>
<a href='_119.php' target='_blank'><button type='button'>119</button></a>
</div>
</div>
<?php elseif ($session->userGrade == 4) : ?>
<div class="row">
<div class="col">
<a href='_119.php' target='_blank'><button type='button'>119</button></a>
</div>
</div>
<?php endif; ?>
<div id="map_view" class="gx-0">
<div id="mapZone" class="view-item"><?= getMapHtml() ?></div>
<div class="view-item" id="reservedCommandZone">
<div id="reservedCommandList"></div>
<div id="actionMiniPlate" class="gx-0 row">
<div class="col">
<div class="gx-1 row">
<div class="col-8 d-grid"><button type='button' class='btn btn-sammo-base2 refreshPage'>갱 신</button></div>
<div class="col-4 d-grid"><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></div>
</div>
</div>
</div>
</div>
<div id="cityInfo" class="view-item" style="border:none;text-align:center;"><?= cityInfo($generalObj) ?></div>
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
<div id="general-position"><?php generalInfo($generalObj); ?></div>
<div id="generalCommandButton" class="row gx-0">
<div class="buttonPlate bg2">
<?= commandButton([
'splitBtnBegin' => '<div class="btn-group">',
'splitBtnEnd' => '</div>',
'splitZoneSign' => '<button type="button" class="btn btn-sammo-nation dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Toggle Dropdown</span></button>',
'splitZoneBegin' => '<ul class="dropdown-menu dropdown-menu-end">',
'splitZoneEnd' => '</ul>',
'splitSubBtnBegin' => '<li>',
'splitSubBtnEnd' => '</li>',
'btnClass' => 'btn btn-sammo-nation',
'btnSplitClass' => 'dropdown-item',
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
'isBettingActive' => $isBettingActive
])
?></div>
</div>
</div>
</div>
<div id="actionMiniPlateSub" class="gx-0 row">
<div class="col">
<div class="gx-1 row">
<div class="col-3 d-grid"><button type='button' class="btn btn-dark" onclick="scrollHardTo('reservedCommandList')">명령으로</button></div>
<div class="col-5 d-grid"><button type='button' class='btn btn-sammo-base2 refreshPage'>갱 신</button></div>
<div class="col-4 d-grid"><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></div>
</div>
</div>
</div>
<div class="row gx-0">
<div class="col-lg-6" id="general_public_record-position">
<div class="bg1 center s-border-tb"><b>장수 동향</b></div>
<div id="general_public_record" style="text-align:left;"><?= formatHistoryToHTML(getGlobalActionLogRecent(15)) ?></div>
</div>
<div class="col-lg-6" id="general_log-position">
<div class="bg1 center s-border-tb"><b>개인 기록</b></div>
<div id="general_log" style="text-align:left;"><?= formatHistoryToHTML(getGeneralActionLogRecent($me['no'], 15)) ?></div>
</div>
<div class="col-12" id="world_history-position">
<div class="bg1 center s-border-tb"><b>중원 정세</b></div>
<div id="world_history" colspan=2 style="text-align:left;"><?= formatHistoryToHTML(getGlobalHistoryLogRecent(15)) ?></div>
</div>
</div>
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></div>
<div id="message_board" class="row gx-0">
<div class="message_input_form bg0 gx-0 row">
<div id="mailbox_list-col" class="col-6 col-lg-2 d-grid">
<select id="mailbox_list" size="1" class="form-control bg-dark text-white">
</select>
</div>
<div id="msg_input-col" class="col-12 col-lg-8 d-grid">
<input type="text" id="msg_input" maxlength="99" class="form-control">
</div>
<div id="msg_submit-col" class="col-6 col-lg-2 d-grid"><button id="msg_submit" class="btn btn-primary">서신전달&amp;갱신</button></div>
</div>
<div class="col-lg-6 board_side bg0"><a id="public_talk_position"></a>
<div class="board_header bg0">전체 메시지(최고99자)</div>
<section class="public_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="public">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="national_talk_position"></a>
<div class="board_header bg0">국가 메시지(최고99자)</div>
<section class="national_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="national">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="private_talk_position"></a>
<div class="board_header bg0">개인 메시지(최고99자)</div>
<section class="private_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="private">이전 메시지 불러오기</button></div>
</section>
</div>
<div class="col-lg-6 board_side bg0"><a id="diplomacy_talk_position"></a>
<div class="board_header bg0">외교 메시지(최고99자)</div>
<section class="diplomacy_message">
<div class="d-grid"><button type="button" class="load_old_message btn btn-secondary" data-msg_type="diplomacy">이전 메시지 불러오기</button></div>
</section>
</div>
</div>
<div class="row toolbars gx-0">
<div class="buttonPlate"><?= allButton($gameStor->npcmode == 1) ?></div><?= banner() ?>
</div>
</div>
<?php
if ($limitState == 1) {
MessageBox("접속제한이 얼마 남지 않았습니다!");
}
if ($me['newmsg'] == 1) {
MessageBox("새로운 서신이 도착했습니다!");
}
if ($me['newvote'] == 1) {
$develcost = $gameStor->develcost * 5;
MessageBox("설문조사에 참여하시면 금{$develcost}과 유니크템을 드립니다! (우측 상단 설문조사 메뉴)");
}
?>
</div>
<nav class="navbar navbar-expand fixed-bottom navbar-dark bg-dark d-sm-block d-lg-none p-0" id="navbar500">
<div class="container-fluid px-0">
<div class="collapse navbar-collapse">
<ul class="navbar-nav me-auto mx-auto">
<li class="nav-item dropup">
<div class="dropdown-toggle text-white btn btn-sammo-base2" id="navbarGlobal" role="button" data-bs-toggle="dropdown" aria-expanded="false">
외부 메뉴
</div>
<ul class="dropdown-menu dropdown-menu-start" aria-labelledby="navbarGlobal" id="navbarGlobalItems">
<?= allButton($gameStor->npcmode == 1, ['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item']) ?>
</ul>
</li>
<li class="nav-item dropup">
<div class="dropdown-toggle btn btn-sammo-nation" id="navbarNation" role="button" data-bs-toggle="dropdown" aria-expanded="false">
국가 메뉴
</div>
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
<?= commandButton([
'btnBegin' => '<li>',
'btnEnd' => '</li>',
'splitMainBegin' => '<div class="d-none">',
'splitMainEnd' => '</div>',
'splitSubBtnBegin' => '<li>',
'splitSubBtnEnd' => '</li>',
'btnClass' => 'dropdown-item',
'btnSplitClass' => 'dropdown-item',
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
'isBettingActive' => $isBettingActive
]) ?>
</ul>
</li>
<li class="nav-item dropup">
<div class="dropdown-toggle text-white btn btn-dark" id="navbarQuick" role="button" data-bs-toggle="dropdown" aria-expanded="false">
빠른 이동
</div>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown" id="navbarQuickItems">
<li><a class="dropdown-item disabled">국가 정보</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('nation-msg-position')" class="dropdown-item">방침</button></li>
<li><button type="button" onclick="scrollHardTo('reservedCommandList')" class="dropdown-item">명령</button></li>
<li><button type="button" onclick="scrollHardTo('nation-position')" class="dropdown-item">국가</button></li>
<li><button type="button" onclick="scrollHardTo('general-position')" class="dropdown-item">장수</button></li>
<li><button type="button" onclick="scrollHardTo('cityInfo')" class="dropdown-item">도시</button></li>
<li><a class="dropdown-item disabled">동향 정보</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('mapZone')" class="dropdown-item">지도</button></li>
<li><button type="button" onclick="scrollHardTo('general_public_record-position')" class="dropdown-item">동향</button></li>
<li><button type="button" onclick="scrollHardTo('general_log-position')" class="dropdown-item">개인</button></li>
<li><button type="button" onclick="scrollHardTo('world_history-position')" class="dropdown-item">정세</button></li>
<li><span>&nbsp;</span></li>
<li><a class="dropdown-item disabled">메시지</a></button></li>
<hr class="dropdown-divider">
</hr>
<li><button type="button" onclick="scrollHardTo('public_talk_position')" class="dropdown-item">전체</button></li>
<li><button type="button" onclick="scrollHardTo('national_talk_position')" class="dropdown-item">국가</button></li>
<li><button type="button" onclick="scrollHardTo('private_talk_position')" class="dropdown-item">개인</button></li>
<li><button type="button" onclick="scrollHardTo('diplomacy_talk_position')" class="dropdown-item">외교</button></li>
<li><button type='button' class='btn btn-sammo-base2' onclick="location.replace('../')">로비로</button></li>
</ul>
</li>
<li class="nav-item">
<a class="refreshPage btn btn-sammo-base2 text-white" role="button">갱신</a>
</li>
</ul>
</div>
</div>
</nav>
</body>
</html>
+9 -1
View File
@@ -8,4 +8,12 @@ $session = Session::getInstance()->setReadOnly();
$db = DB::db(); $db = DB::db();
TurnExecutionHelper::executeAllCommand(); $updated = false;
$locked = false;
$lastExecuted = TurnExecutionHelper::executeAllCommand($updated, $locked);
Json::die([
'result' => true,
'updated' => $updated,
'locked' => $locked,
'lastExecuted' => $lastExecuted,
]);
+136 -17
View File
@@ -37,12 +37,12 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear); $city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city')); $defenderCityGeneralIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0', $city->getVar('nation'), $city->getVar('city'));
$defenderGeneralList = General::createGeneralObjListFromDB($defenderIDList, null); $defenderCityGeneralList = General::createObjListFromDB($defenderCityGeneralIDList, null);
/** @var WarUnit[] */ /** @var WarUnit[] */
$defenderList = []; $defenderList = [];
foreach($defenderGeneralList as $defenderGeneral){ foreach($defenderCityGeneralList as $defenderGeneral){
$defenderGeneral->setRawCity($rawDefenderCity); $defenderGeneral->setRawCity($rawDefenderCity);
$defenderCandidate = new WarUnitGeneral($rng, $defenderGeneral, $rawDefenderNation, false); $defenderCandidate = new WarUnitGeneral($rng, $defenderGeneral, $rawDefenderNation, false);
if(extractBattleOrder($defenderCandidate, $attacker) <= 0){ if(extractBattleOrder($defenderCandidate, $attacker) <= 0){
@@ -186,7 +186,7 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
'year' => $year, 'year' => $year,
'month' => $month, 'month' => $month,
'join_mode' => $joinMode, 'join_mode' => $joinMode,
], $attacker->getGeneral(), $city->getRaw()); ], $attacker->getGeneral(), $city->getRaw(), $defenderCityGeneralList);
} }
function extractBattleOrder(WarUnit $defender, WarUnit $attacker) function extractBattleOrder(WarUnit $defender, WarUnit $attacker)
@@ -230,6 +230,7 @@ function processWar_NG(
WarUnitGeneral $attacker, WarUnitGeneral $attacker,
callable $getNextDefender, callable $getNextDefender,
WarUnitCity $city, WarUnitCity $city,
?callable $trace = null,
): bool { ): bool {
$templates = new \League\Plates\Engine(__DIR__ . '/templates'); $templates = new \League\Plates\Engine(__DIR__ . '/templates');
@@ -245,6 +246,26 @@ function processWar_NG(
/** @var WarUnit */ /** @var WarUnit */
$defender = ($getNextDefender)(null, true); $defender = ($getNextDefender)(null, true);
$conquerCity = false; $conquerCity = false;
$traceSeq = 0;
$emitTrace = function (string $event, ?WarUnit $currentDefender, array $details = []) use (
$trace,
&$traceSeq,
$attacker,
$city
): void {
if ($trace === null) {
return;
}
$trace([
'seq' => $traceSeq++,
'event' => $event,
'attacker' => buildWarTraceUnitSnapshot($attacker),
'defender' => $currentDefender === null ? null : buildWarTraceUnitSnapshot($currentDefender),
'city' => buildWarTraceUnitSnapshot($city),
'details' => $details,
]);
};
$emitTrace('battle_start', $defender, ['seed' => $warSeed]);
$josaRo = JosaUtil::pick($city->getName(), '로'); $josaRo = JosaUtil::pick($city->getName(), '로');
$josaYi = JosaUtil::pick($attacker->getName(), '이'); $josaYi = JosaUtil::pick($attacker->getName(), '이');
@@ -277,6 +298,7 @@ function processWar_NG(
$logger->pushGlobalHistoryLog("<M><b>【패퇴】</b></><D><b>{$defender->getNationVar('name')}</b></>{$josaYi} 병량 부족으로 <G><b>{$defender->getName()}</b></>{$josaUl} 뺏기고 말았습니다."); $logger->pushGlobalHistoryLog("<M><b>【패퇴】</b></><D><b>{$defender->getNationVar('name')}</b></>{$josaYi} 병량 부족으로 <G><b>{$defender->getName()}</b></>{$josaUl} 뺏기고 말았습니다.");
$conquerCity = true; $conquerCity = true;
$emitTrace('supply_retreat', $defender);
break; break;
} }
} }
@@ -332,18 +354,34 @@ function processWar_NG(
$initCaller->merge($defender->getGeneral()->getBattleInitSkillTriggerList($defender)); $initCaller->merge($defender->getGeneral()->getBattleInitSkillTriggerList($defender));
$initCaller->fire($attacker->rng, [], [$attacker, $defender]); $initCaller->fire($attacker->rng, [], [$attacker, $defender]);
$emitTrace('opponent_initialized', $defender);
} }
$attacker->beginPhase(); $attacker->beginPhase();
$defender->beginPhase(); $defender->beginPhase();
if ($trace !== null) {
$emitTrace('phase_power', $defender, [
'attackerAttack' => $attacker->getComputedAttack(),
'attackerDefence' => $attacker->getComputedDefence(),
'attackerTrain' => $attacker->getComputedTrain(),
'attackerAtmos' => $attacker->getComputedAtmos(),
'defenderAttack' => $defender->getComputedAttack(),
'defenderDefence' => $defender->getComputedDefence(),
'defenderTrain' => $defender->getComputedTrain(),
'defenderAtmos' => $defender->getComputedAtmos(),
]);
}
$battleCaller = $attacker->getGeneral()->getBattlePhaseSkillTriggerList($attacker); $battleCaller = $attacker->getGeneral()->getBattlePhaseSkillTriggerList($attacker);
$battleCaller->merge($defender->getGeneral()->getBattlePhaseSkillTriggerList($defender)); $battleCaller->merge($defender->getGeneral()->getBattlePhaseSkillTriggerList($defender));
$battleCaller->fire($attacker->rng, [], [$attacker, $defender]); $battleCaller->fire($attacker->rng, [], [$attacker, $defender]);
$emitTrace('phase_triggered', $defender);
$deadDefender = $attacker->calcDamage(); $deadDefender = $attacker->calcDamage();
$deadAttacker = $defender->calcDamage(); $deadAttacker = $defender->calcDamage();
$rawDeadAttacker = $deadAttacker;
$rawDeadDefender = $deadDefender;
$attackerHP = $attacker->getHP(); $attackerHP = $attacker->getHP();
$defenderHP = $defender->getHP(); $defenderHP = $defender->getHP();
@@ -371,6 +409,14 @@ function processWar_NG(
$attacker->increaseKilled($deadDefender); $attacker->increaseKilled($deadDefender);
$defender->increaseKilled($deadAttacker); $defender->increaseKilled($deadAttacker);
$emitTrace('phase_damage', $defender, [
'rawDeadAttacker' => $rawDeadAttacker,
'rawDeadDefender' => $rawDeadDefender,
'deadAttacker' => $deadAttacker,
'deadDefender' => $deadDefender,
'attackerHpBefore' => $attackerHP,
'defenderHpBefore' => $defenderHP,
]);
if($defender->getPhase() < 0){ if($defender->getPhase() < 0){
$phaseNickname = '先'; $phaseNickname = '先';
@@ -394,8 +440,10 @@ function processWar_NG(
$attacker->addPhase(); $attacker->addPhase();
$defender->addPhase(); $defender->addPhase();
$emitTrace('phase_end', $defender);
if (!$attacker->continueWar($noRice)) { if (!$attacker->continueWar($noRice)) {
$emitTrace('attacker_stopped', $defender, ['noRice' => (bool)$noRice]);
$logWritten = true; $logWritten = true;
$attacker->logBattleResult(); $attacker->logBattleResult();
@@ -420,6 +468,7 @@ function processWar_NG(
} }
if (!$defender->continueWar($noRice)) { if (!$defender->continueWar($noRice)) {
$emitTrace('defender_stopped', $defender, ['noRice' => (bool)$noRice]);
$logWritten = true; $logWritten = true;
$attacker->logBattleResult(); $attacker->logBattleResult();
@@ -462,6 +511,7 @@ function processWar_NG(
$defender->finishBattle(); $defender->finishBattle();
$defender = ($getNextDefender)($defender, true); $defender = ($getNextDefender)($defender, true);
$emitTrace('opponent_switched', $defender);
if ($defender !== null && !($defender instanceof WarUnitGeneral)) { if ($defender !== null && !($defender instanceof WarUnitGeneral)) {
throw new \RuntimeException('다음 수비자를 받아오는데 실패'); throw new \RuntimeException('다음 수비자를 받아오는데 실패');
@@ -497,10 +547,60 @@ function processWar_NG(
} }
($getNextDefender)($defender, false); ($getNextDefender)($defender, false);
$emitTrace('battle_end', $defender, ['conquered' => $conquerCity]);
return $conquerCity; return $conquerCity;
} }
function buildWarTraceUnitSnapshot(WarUnit $unit): array
{
$snapshot = [
'kind' => $unit instanceof WarUnitGeneral ? 'general' : 'city',
'id' => $unit instanceof WarUnitGeneral
? $unit->getGeneral()->getID()
: $unit->getVar('city'),
'name' => $unit->getName(),
'isAttacker' => $unit->isAttacker(),
'crewTypeId' => $unit->getCrewType()->id,
'phase' => $unit->getPhase(),
'realPhase' => $unit->getRealPhase(),
'maxPhase' => $unit->getMaxPhase(),
'hp' => $unit->getHP(),
'rawWarPower' => $unit->getRawWarPower(),
'warPower' => $unit->getWarPower(),
'warPowerMultiplier' => $unit->getWarPowerMultiply(),
'killed' => $unit->getKilled(),
'dead' => $unit->getDead(),
'activatedSkills' => $unit->getActivatedSkillLog(),
];
if ($unit instanceof WarUnitGeneral) {
$general = $unit->getGeneral();
$snapshot['general'] = [
'crew' => $general->getVar('crew'),
'rice' => $general->getVar('rice'),
'train' => $general->getVar('train'),
'atmos' => $general->getVar('atmos'),
'injury' => $general->getVar('injury'),
'experience' => $general->getVar('experience'),
'dedication' => $general->getVar('dedication'),
'dex1' => $general->getVar('dex1'),
'dex2' => $general->getVar('dex2'),
'dex3' => $general->getVar('dex3'),
'dex4' => $general->getVar('dex4'),
'dex5' => $general->getVar('dex5'),
];
} else {
$snapshot['cityState'] = [
'defence' => $unit->getVar('def'),
'wall' => $unit->getVar('wall'),
'population' => $unit->getVar('pop'),
];
}
return $snapshot;
}
function DeleteConflict($nation) function DeleteConflict($nation)
{ {
$db = DB::db(); $db = DB::db();
@@ -526,11 +626,12 @@ function DeleteConflict($nation)
function getConquerNation($city): int function getConquerNation($city): int
{ {
$conflict = Json::decode($city['conflict']); $conflict = Json::decode($city['conflict']);
return Util::array_first_key($conflict); return array_key_first($conflict);
} }
function ConquerCity(array $admin, General $general, array $city) function ConquerCity(array $admin, General $general, array $city, array $defenderCityGeneralList)
{ {
/** @var General[] $defenderCityGeneralList */
$db = DB::db(); $db = DB::db();
$year = $admin['year']; $year = $admin['year'];
@@ -585,6 +686,21 @@ function ConquerCity(array $admin, General $general, array $city)
if(TurnExecutionHelper::runEventHandler($db, $gameStor, EventTarget::OccupyCity)){ if(TurnExecutionHelper::runEventHandler($db, $gameStor, EventTarget::OccupyCity)){
$gameStor->cacheAll(); $gameStor->cacheAll();
} }
$rng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'ConquerCity',
$year,
$month,
$attackerNationID,
$attackerID,
$cityID
)));
foreach($defenderCityGeneralList as $defenderCityGeneral){
$defenderCityGeneral->onArbitraryAction($defenderCityGeneral, $rng, 'ConquerCity', null, [
'attacker' => $general
]);
$defenderCityGeneral->applyDB($db);
}
// 국가 멸망시 // 국가 멸망시
@@ -596,10 +712,10 @@ function ConquerCity(array $admin, General $general, array $city)
$lord = new General($db->queryFirstRow( $lord = new General($db->queryFirstRow(
'SELECT %l FROM general WHERE nation = %i AND officer_level = %i LIMIT 1', 'SELECT %l FROM general WHERE nation = %i AND officer_level = %i LIMIT 1',
Util::formatListOfBackticks(General::mergeQueryColumn(['npc', 'gold', 'rice', 'experience', 'explevel', 'belong', 'dedication', 'dedlevel', 'aux'], GeneralQueryMode::Lite)[0]), Util::formatListOfBackticks(General::mergeQueryColumn()[0]),
$defenderNationID, $defenderNationID,
12 12
), null, null, $city, $loseNation, $year, $month, false); ), null, null, $city, $loseNation, $year, $month);
$josaUl = JosaUtil::pick($defenderNationName, '을'); $josaUl = JosaUtil::pick($defenderNationName, '을');
$attackerLogger->pushNationalHistoryLog("<D><b>{$defenderNationName}</b></>{$josaUl} 정복"); $attackerLogger->pushNationalHistoryLog("<D><b>{$defenderNationName}</b></>{$josaUl} 정복");
@@ -702,14 +818,17 @@ function ConquerCity(array $admin, General $general, array $city)
$attackerLogger->pushGlobalHistoryLog("<M><b>【긴급천도】</b></><D><b>{$defenderNationName}</b></>{$josaYi} 수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} 긴급천도하였습니다."); $attackerLogger->pushGlobalHistoryLog("<M><b>【긴급천도】</b></><D><b>{$defenderNationName}</b></>{$josaYi} 수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} 긴급천도하였습니다.");
$moveLog = "수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} <M>긴급천도</>합니다."; $moveLog = "수도가 함락되어 <G><b>$minCityName</b></>{$josaRo} <M>긴급천도</>합니다.";
//아국 수뇌부에게 로그 전달 foreach ($db->queryAllLists(
foreach ($db->queryFirstColumn( 'SELECT no, officer_level FROM general WHERE nation=%i',
'SELECT no FROM general WHERE nation=%i AND officer_level>=5',
$defenderNationID $defenderNationID
) as $defenderChiefID) { ) as [$defenderGeneralID, $defenderGeneralChiefLevel]) {
$chiefLogger = new ActionLogger($defenderChiefID, $defenderNationID, $year, $month); $defenderLogger = new ActionLogger($defenderGeneralID, $defenderNationID, $year, $month);
$chiefLogger->pushGeneralActionLog($moveLog, ActionLogger::PLAIN); $defenderLogger->pushGeneralActionLog($moveLog, ActionLogger::PLAIN);
$chiefLogger->flush(); if($defenderGeneralChiefLevel >= 5){
$defenderLogger->pushGeneralActionLog("수뇌는 <G><b>{$minCityName}</b></>{$josaRo} 집합되었습니다.");
}
$defenderLogger->flush();
} }
//천도 //천도
@@ -766,8 +885,8 @@ function ConquerCity(array $admin, General $general, array $city)
'officer_set' => 0, 'officer_set' => 0,
]; ];
if ($city['level'] > 3) { if ($city['level'] > 3) {
$query['def'] = 1000; $query['def'] = GameConst::$defaultCityWall;
$query['wall'] = 1000; $query['wall'] = GameConst::$defaultCityWall;
} else { } else {
$query['def'] = $db->sqleval('def_max/2'); $query['def'] = $db->sqleval('def_max/2');
$query['wall'] = $db->sqleval('wall_max/2'); $query['wall'] = $db->sqleval('wall_max/2');
+1 -1
View File
@@ -39,7 +39,7 @@ class BidBuyRiceAuction extends \sammo\BaseAPI
$amount = $this->args['amount']; $amount = $this->args['amount'];
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$auction = new AuctionBuyRice($auctionID, $general); $auction = new AuctionBuyRice($auctionID, $general);
$result = $auction->bid($amount, true); $result = $auction->bid($amount, true);
+1 -1
View File
@@ -38,7 +38,7 @@ class BidSellRiceAuction extends \sammo\BaseAPI
$amount = $this->args['amount']; $amount = $this->args['amount'];
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$auction = new AuctionSellRice($auctionID, $general); $auction = new AuctionSellRice($auctionID, $general);
$result = $auction->bid($amount, true); $result = $auction->bid($amount, true);
+1 -1
View File
@@ -41,7 +41,7 @@ class BidUniqueAuction extends \sammo\BaseAPI
$tryExtendCloseDate = $this->args['extendCloseDate'] ?? false; $tryExtendCloseDate = $this->args['extendCloseDate'] ?? false;
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$auction = new AuctionUniqueItem($auctionID, $general); $auction = new AuctionUniqueItem($auctionID, $general);
$result = $auction->bid($amount, $tryExtendCloseDate); $result = $auction->bid($amount, $tryExtendCloseDate);
@@ -77,7 +77,7 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
$inheritMgr = InheritancePointManager::getInstance(); $inheritMgr = InheritancePointManager::getInstance();
//preveious라서 column을 최대한 비울 수 있다. //preveious라서 column을 최대한 비울 수 있다.
$remainPoint = $inheritMgr->getInheritancePoint( $remainPoint = $inheritMgr->getInheritancePoint(
General::createGeneralObjFromDB($generalID, ['owner'], GeneralQueryMode::Core), General::createObjFromDB($generalID),
InheritanceKey::previous InheritanceKey::previous
); );
+1 -1
View File
@@ -66,7 +66,7 @@ class OpenBuyRiceAuction extends \sammo\BaseAPI
$finishBidAmount = $this->args['finishBidAmount']; $finishBidAmount = $this->args['finishBidAmount'];
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
@@ -66,7 +66,7 @@ class OpenSellRiceAuction extends \sammo\BaseAPI
$finishBidAmount = $this->args['finishBidAmount']; $finishBidAmount = $this->args['finishBidAmount'];
$generalID = $session->generalID; $generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
+1 -1
View File
@@ -57,7 +57,7 @@ class OpenUniqueAuction extends \sammo\BaseAPI
$generalID = $session->generalID; $generalID = $session->generalID;
$itemObj = buildItemClass($itemID); $itemObj = buildItemClass($itemID);
$general = General::createGeneralObjFromDB($generalID); $general = General::createObjFromDB($generalID);
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\GameConst;
use sammo\Json; use sammo\Json;
use sammo\KVStorage; use sammo\KVStorage;
use sammo\TimeUtil; use sammo\TimeUtil;
@@ -32,8 +33,18 @@ class GetReservedCommand extends \sammo\BaseAPI
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$generalID = $session->generalID; $generalID = $session->generalID;
$invalidTurnList = 0;
$rawTurn = $db->queryAllLists('SELECT turn_idx, action, arg, brief FROM general_turn WHERE general_id = %i ORDER BY turn_idx ASC', $generalID); $rawTurn = $db->queryAllLists('SELECT turn_idx, action, arg, brief FROM general_turn WHERE general_id = %i ORDER BY turn_idx ASC', $generalID);
foreach ($rawTurn as [$turn_idx, $action, $arg, $brief]) { foreach ($rawTurn as [$turn_idx, $action, $arg, $brief]) {
if($turn_idx < 0) {
$invalidTurnList = -1;
$turn_idx += GameConst::$maxTurn;
}
else if($turn_idx >= GameConst::$maxTurn) {
$invalidTurnList = 1;
$turn_idx -= GameConst::$maxTurn;
}
$commandList[$turn_idx] = [ $commandList[$turn_idx] = [
'action' => $action, 'action' => $action,
'brief' => $brief, 'brief' => $brief,
@@ -41,6 +52,19 @@ class GetReservedCommand extends \sammo\BaseAPI
]; ];
} }
if($invalidTurnList != 0){
if($invalidTurnList > 0){
$db->update('general_turn', [
'turn_idx' => $db->sqleval('turn_idx - %i', GameConst::$maxTurn)
], 'general_id=%i AND turn_idx >= %i', $generalID, GameConst::$maxTurn);
}
else{
$db->update('general_turn', [
'turn_idx' => $db->sqleval('turn_idx + %i', GameConst::$maxTurn)
], 'general_id=%i AND turn_idx < 0', $generalID);
}
}
[$turnTerm, $year, $month, $lastExecute] = $gameStor->getValuesAsArray(['turnterm', 'year', 'month', 'turntime']); [$turnTerm, $year, $month, $lastExecute] = $gameStor->getValuesAsArray(['turnterm', 'year', 'month', 'turntime']);
@@ -59,7 +59,7 @@ class BuildNationCandidate extends \sammo\BaseAPI
$env = $gameStor->getAll(); $env = $gameStor->getAll();
$generalObj = General::createGeneralObjFromDB($general['no']); $generalObj = General::createObjFromDB($general['no']);
$validCmd = false; $validCmd = false;
foreach(GameConst::$availableGeneralCommand as $cmdList){ foreach(GameConst::$availableGeneralCommand as $cmdList){
@@ -90,6 +90,9 @@ class BuildNationCandidate extends \sammo\BaseAPI
return '거병을 실패했습니다.'; return '거병을 실패했습니다.';
} }
$generalObj->setVar('killturn', $env['killturn']);
$generalObj->applyDB($db);
return null; return null;
} }
} }

Some files were not shown because too many files have changed in this diff Show More