Compare commits

..
357 Commits
Author SHA1 Message Date
Hide_D 256326f5d4 game: 정란, 벽력거 설명 추가 2023-05-12 00:07:01 +09:00
Hide_D 505f615203 game: 성벽선제인 경우에만 성벽도 선제공격 2023-05-12 00:07:01 +09:00
Hide_D 4e504e9679 game: 성벽이 선제공격 2023-05-12 00:07:01 +09:00
Hide_D 18f9d87a29 fix: 성벽 선제가 호출조차 되지 않는 버그 수정 2023-05-12 00:07:01 +09:00
Hide_D 2ad0c6e509 fix: 도시 관련 전투 제어 2023-05-12 00:07:00 +09:00
Hide_D 74b9e0b4a5 feat: CrewType에 iAction 개념을 넣고 처리할 수 있도록
- GameUnitDetail에 iAction 리스트 추가

fix: 누락분 수정

fix: crewtype 미지정시 기본 병종
2023-05-12 00:05:25 +09:00
Hide_D 486ac65767 wip: process_war에서 defenderList 변경
- defenderList를 General[] 에서 WarUnit[]으로 변경
- extractBattleOrder를 WarUnit을 받도록 변경
2023-05-10 02:31:43 +09:00
Hide_D 483641bcd5 feat: extractBattleOrder 함수가 공격자를 받아서 처리할 수 있도록 변경 2023-05-10 01:28:00 +09:00
Hide_D ffdacc2cfb game: 차병종 상성 변경
- 정란: 현행 유지
- 충차: 현행 유지
- 벽력거: 받는 피해 44% 증가
  - 정란의 상성과 동일하게 변경
- 목우: 주는 피해 20% 감소
2023-05-10 00:59:56 +09:00
Hide_D 4eac86da58 game: 저지시 쌀을 소모하도록 변경
- 오르는 숙련 대비 0.25배
- 즉, 일반 공격력 대비 0.9 * 0.25만큼
2023-05-10 00:39:10 +09:00
Hide_D 77fc38c899 misc: 세력장수에서 숫자 셀에는 숫자 대소비교 필터 설정 2023-04-30 19:37:52 +09:00
Hide_D 0bf49ebfb9 game: 능력치가 상한에 도달하면 더이상 오르지 않음 2023-04-30 00:29:15 +09:00
Hide_D 93f0516121 Revert "game: 스탯 제한을 순수 스탯 대상으로만 변경"
This reverts commit 71a3ffa21c.
2023-04-30 00:22:14 +09:00
Hide_D 36406c8001 game: 물자조달도 전방 내정 감소가 적용 2023-04-30 00:15:41 +09:00
Hide_D 836adcfe3c game: 전방 내정시, 수도가 전방이어도 감쇠되도록 설정
- 185년까지는 해당 없음(디버프 * 0%)
- 이후 1년마다 실제 적용량 대비 5%씩 가산 적용됨
- 205년이 되면 수도여도 전방 내정 감쇠가 그대로 적용됨
2023-04-30 00:15:17 +09:00
Hide_D 71a3ffa21c game: 스탯 제한을 순수 스탯 대상으로만 변경 2023-04-29 23:47:47 +09:00
Hide_D 38f10b5f09 game: 최대 레벨, 능력치 제한을 255로 변경 2023-04-29 23:46:22 +09:00
Hide_D da6b1fe7f1 game: 내부 스탯 제한을 2중으로 2023-04-29 23:40:30 +09:00
Hide_D 034e6374cc game: 최대 환산 능력치를 300으로 제한 2023-04-29 23:30:11 +09:00
Hide_D 9b95163f24 fix: 명성 최대 레벨 지정이 없었음 2023-04-29 23:18:55 +09:00
Hide_D 91b7934ee3 fix: KakaoUtil의 저장 키 문제 2023-04-25 23:09:01 +09:00
Hide_D 41216893a1 fix: 감찰부 대상 API 순서에 따라 잘못 표기 되는 문제
- API 결과값과 현재 대상 비교하는 코드 추가
2023-04-23 16:53:17 +09:00
Hide_D 3553b87748 fix: 지도 제목에 툴팁 표기 고장 수정
- 동작하지 않는 vMyTooltip 제거
2023-03-30 02:39:57 +09:00
Hide_D 3e5e584fce fix: 오타 수정
- 영향받는 코드는 없었을 것으로.
2023-03-30 01:19:52 +09:00
Hide_D afb53d121b fix: 특기 초기화시 가득차면 사용 풀이 리셋되지 않는 버그 수정 2023-03-28 10:05:48 +09:00
Hide_D 1780122936 fix: 모든 내특/전특 사용시 에러나는 문제 수정 2023-03-28 09:54:24 +09:00
sars 64aa5d041f Revert "긴급 버그 패치, 내특 줄 수 있는게 하나도 없으면 강제로 상재로 주고 턴 넘기는것으로 긴급패치, 히데님이 알아서 제대로 고칠것, (2로 해두면 상재가 아니라 아에 버그가 떠서 그냥 롤백시키고 히데님이 다 고치는걸로 방치하기로 결정)"
This reverts commit fbccfbb65e.
2023-03-27 09:54:37 -07:00
sars fbccfbb65e 긴급 버그 패치, 내특 줄 수 있는게 하나도 없으면 강제로 상재로 주고 턴 넘기는것으로 긴급패치, 히데님이 알아서 제대로 고칠것 2023-03-27 09:49:00 -07:00
Hide_D 13eb0d4eae fix: 토너먼트 표기 문구 수정 2023-03-26 15:56:04 +09:00
Hide_D 3969c47f07 Revert "fix: 임시로 대문에서 로그인 체크를 직접 하도록 변경"
This reverts commit c7e0d6d2cb.
2023-03-26 15:55:38 +09:00
Hide_D c7e0d6d2cb fix: 임시로 대문에서 로그인 체크를 직접 하도록 변경 2023-03-26 15:52:06 +09:00
Hide_D 9e997a7ee2 feat: 도시 장수 정의에 nationID를 추가 2023-03-26 00:58:53 +09:00
Hide_D 9a8f70d87b fix: 감찰부 안보이는 버그 수정
- query로 옮겨서 생기는 문제
2023-03-26 00:58:32 +09:00
Hide_D 7132aeab0c fix: installVue3Components() 호출부 통일 2023-03-26 00:48:05 +09:00
Hide_D 994c73adb2 feat: 설문조사 정보도 DB정보를 이용하여 한번만 처리 2023-03-25 03:07:38 +09:00
Hide_D 9206b74500 feat: 이미 읽은 메시지를 DB에서 처리 2023-03-25 02:09:23 +09:00
Hide_D 5294aefbbd misc: 동향 변경 안내 시간 단축 2023-03-24 03:03:50 +09:00
Hide_D 8f0f586af9 fix: 버그 수정 2023-03-24 02:44:14 +09:00
Hide_D 9121533b93 fix: 국가 승급을 Event로 떼내어야 함
- 부대장 지급보다 앞으로
2023-03-24 02:43:07 +09:00
Hide_D 90bff7b210 misc: 연도 업데이트 2023-03-22 23:22:46 +09:00
Hide_D 55f7b87ced misc: GetConst의 cache key를 getVersion으로 2023-03-22 23:19:28 +09:00
Hide_D bee4de377a feat: 버전 정보 페이지 추가 2023-03-22 23:09:53 +09:00
Hide_D b02911038b fix: 갱신시마다 커맨드 테이블을 다시 불러줘야 함 2023-03-22 22:58:05 +09:00
Hide_D 9b4d5455e5 feat: GetConst에서 버전 정보 반환 2023-03-22 22:54:47 +09:00
Hide_D ca3e64f3b9 feat: MenuItem에 funcCall 타입 추가후 처리 2023-03-22 22:44:42 +09:00
Hide_D 4d2b5ced82 feat: 메뉴 구성에 line 추가 2023-03-22 22:04:35 +09:00
Hide_D e385820301 fix: classMap에서 orig.php만 있고, 본 php는 없는 케이스 고려 2023-03-22 21:50:55 +09:00
Hide_D ec7c97d696 feat: hightlight btn, 토너먼트/베팅장 강조 2023-03-22 02:23:14 +09:00
Hide_D aae730d39c fix: gatewayButton 2023-03-21 01:51:39 +09:00
Hide_D 3c412f2803 fix: cr 시나리오 병종을 현재 버전에 맞게 수정 2023-03-21 01:44:27 +09:00
Hide_D 25769a9435 fix: sqlite3 db ignore 대상 추가 2023-03-21 01:42:25 +09:00
Hide_D 6c76d688b5 fix: 메시지 삭제 안되는 버그
- GetRecentMessage에서 keepRecent 관련 오동작 수정
  - 왜 이걸 넣었는지 생각해보기로..
2023-03-21 01:38:58 +09:00
Hide_D 790c58f2b6 feat: 메시지 빠른 답장 대상 지정 2023-03-20 02:12:57 +09:00
Hide_D 1eba863cc4 misc: 폰트 설정이 다르더라도 툴바 버튼 줄 수 유지 2023-03-20 01:13:21 +09:00
Hide_D fbe5739d82 feat: 메시지 응답시, 읽음 처리 2023-03-20 01:06:53 +09:00
Hide_D f8f8ef7dd3 misc: MainControlBar에 붙은 class 정리 2023-03-20 01:02:41 +09:00
Hide_D ecc375ef41 fix: customize scss에 맞게 다시 수정 2023-03-20 00:16:32 +09:00
Hide_D 9e17e58ecb dep: package update
- decl type 변경 포함
2023-03-20 00:02:04 +09:00
Hide_D 18f7e7b7c1 dep: package update 2023-03-19 23:12:09 +09:00
Hide_D b15b09cc1e dep: package update 2023-03-19 22:59:00 +09:00
Hide_D 49f2f85f79 dep: package-update 2023-03-19 17:45:17 +09:00
Hide_D 2245383d9e dep: remove bootstrap-vue-3 2023-03-19 17:17:45 +09:00
Hide_D e619a6b509 misc: 내무부에서 에디터 폼 최소 높이 높임 2023-03-19 16:59:13 +09:00
Hide_D fb9e750fe2 game: 외교권자가 아니면 외교 메시지 알림 없음 2023-03-19 16:51:06 +09:00
Hide_D 457aa0e4a5 misc: getNewMsgToast 힌트에 따라 수정 2023-03-19 15:38:49 +09:00
Hide_D 761b91b7db fix, refac: bvn에 맞게 tooltip directive 변경
- installVue3Component로 통합
- boostrap-vue-next 0.7.3 directive 문제 우회
2023-03-19 14:41:09 +09:00
Hide_D 31f4472a8a dep: upgrade bv3 bvn 2023-03-19 13:29:58 +09:00
Hide_D a79585f8de fix: 메시지 보러가기를 누르더라도 이미 읽음 처리를 해야함 2023-03-19 12:56:55 +09:00
Hide_D 69fbbbb51a feat: 개인/외교 메시지 수신시 버튼 추가 2023-03-19 12:54:53 +09:00
Hide_D 5eecbfc6f8 misc: package.json 요구로 임시 처리 2023-03-19 12:54:29 +09:00
Hide_D 9121780d82 feat: is1000pxMode에 widthMode 통합 2023-03-18 09:03:37 +09:00
Hide_D 6691aa3526 feat: PageFront에 토너먼트 베팅장 활성시 색 변경 2023-03-18 02:10:13 +09:00
Hide_D 582163ab46 fix: 부대장의 특기를 없앰.
- 특기 수령 년도를 999년으로 변경
2023-03-17 13:28:23 +09:00
Hide_D 394a70319f game: cr 시나리오에서 '척사'를 3등급 병종 문제로 제거 2023-03-17 02:18:23 +09:00
Hide_D 4d340abdcf feat: BaseAPI의 launch()에 타입 지정
- APIRecoveryType이 명시
2023-03-17 01:39:10 +09:00
Hide_D 6b9cfe46a0 feat: APIHelper에서 recovery 반환 타입 경로 추가 2023-03-17 01:18:20 +09:00
Hide_D 1d4707fb20 fix: recovery를 typescript API와 매칭 2023-03-17 01:16:55 +09:00
Hide_D d673024a10 feat: APIRecoveryType을 포함한 리턴 방법 2023-03-17 01:10:59 +09:00
Hide_D 3513aae088 fix: 지도 도시 민감도 문제 수정
- touchend는 touchmove와는 별개이므로 함께 처리
2023-03-17 00:30:22 +09:00
Hide_D 83c43d0261 fix: ProvideNPCTroopLeader 2023-03-16 23:59:24 +09:00
Hide_D 53cd8aeb5d fix: cr 시나리오에 선포가 없는 버그 수정 2023-03-16 19:27:28 +09:00
Hide_D 65b861d7ee fix: cr맵 배경 500px 2023-03-16 12:22:23 +09:00
Hide_D a5432e59d0 fix: CreateManyNPC 경고 제거 2023-03-16 03:49:19 +09:00
Hide_D e67b45e9cd game: 거울세계 구조 수정 2023-03-16 03:20:14 +09:00
Hide_D 8a8d9db7f9 game: 910 이벤트 시나리오 추가 수정
- 기본 이벤트 로직 오버라이드
  - 깃 끊김 없음
- 특수 커맨드(제한없는 건국, 인구이동, 맹훈련)
- 특수맵에 규모 적용
2023-03-16 01:24:06 +09:00
Hide_D 602cf3bf13 game: cr_건국,맹훈련,인구이동 추가
- 특수 맵 커맨드에 맞춤
- 건국: 소,중성 제한 없음
- 맹훈련: 훈련/사기진작의 2/3를 동시에
- 인구이동: 도시의 인구를 다른 곳으로 이동
2023-03-16 01:12:46 +09:00
Hide_D ab2e43e8dd fix: 국가가 하나도 없을 땐 CreateManyNPC가 동작하지 않아야 함 2023-03-16 00:07:04 +09:00
Hide_D 49b39c34eb fix: ProvideNPCTroopLeader는 국가가 없을땐 동작하지 않아야함 2023-03-16 00:04:33 +09:00
Hide_D fb5946fba5 feat: 소재 도시가 공백지여야하는 조건 작성 2023-03-15 23:19:01 +09:00
Hide_D 3ff4d51778 fix: 명령 선택시 지도의 배경이 안보이는 버그 수정 2023-03-15 04:11:50 +09:00
Hide_D 49d1bf4bad game: CR 맵 초기화 2023-03-15 03:48:37 +09:00
Hide_D 6a67a7de98 misc: 도시 렌더러에서 배경 클래스 지정 2023-03-15 02:11:47 +09:00
Hide_D f132d285e9 game: 랜덤임관 모드에서 초기 장수 제한 해제
- 사전 거병이 가능하므로, 시간에 따른 제한은 필요없을 것으로 판단
2023-03-15 01:15:10 +09:00
Hide_D f97b6e10d3 fix: 삼성 브라우저 다크모드 색상 틀어짐 수정 시도 2023-03-13 03:03:05 +09:00
Hide_D 90509516dd fix: Json::decode에서 빈줄은 array조차 아님 2023-03-13 02:44:58 +09:00
Hide_D 0a35505fa4 fix: 트래픽 일람에서 새 줄 파싱 문제 2023-03-13 02:43:44 +09:00
Hide_D 80a674436a fix: PageFront에서 부대 탑승여부가 보이지 않는 버그 2023-03-13 02:32:14 +09:00
Hide_D 50bf2a4614 fix: 도시 상인 % 표기 문제 수정 2023-03-13 00:00:01 +09:00
Hide_D 2f69be49e1 fix: 도시 정보에서 민심을 소수점 한자리로 제한 2023-03-12 18:48:50 +09:00
Hide_D 40fb8a4836 dep: lodash를 lodash-es 로 변경 2023-03-12 17:47:03 +09:00
Hide_D 0da9ffee9b fix: 일부 메인페이지 색상값을 옮겨오지 않은 버그 수정 2023-03-12 17:38:16 +09:00
Hide_D c88e3d1bfe fix: 메인, 사령부의 alert를 toast로 이동 2023-03-12 17:32:00 +09:00
Hide_D ae76ce0abd fix: PageFront 능력치 상승 기준이 엉뚱하게 잡혀있던 버그 수정 2023-03-12 17:17:53 +09:00
Hide_D d17b2518df 전역 하드코드 이벤트를 동적 변경 영역으로 이동 (#230)
기존에 작성해두었던 EventHandler 시스템으로 하드코드 이벤트 이동
- 매달
  - 보급선 설정
  - 전쟁 단기 수입 설정
  - 부대장 부여
- 1월
  - 유산 포인트 계산
  - 도시 인구 변화
  - 수입
  - 관직 제한 해제
  - 재난
  - 상인
  - 새해 알림
  - 특기 부여
- 4월
  - 관직 제한 해제
  - 재난
- 7월
  - 유산 포인트 계산
  - 도시 인구 변화
  - 수입
  - 관직 제한 해제
  - 재난
  - 상인
- 10월
  - 관직 제한 해제
  - 재난
- 천통 시
  - 유산 포인트 계산

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/230
2023-03-12 17:14:49 +09:00
Hide_D 4901a2d384 fix: 거병 시 인구 정보를 0이 아니라 null로 보내는 문제 수정 2023-03-12 16:38:32 +09:00
Hide_D 47bf5cdd17 misc: PageFront 로딩 직후에는 갱신 완료 메시지 없음 2023-03-09 20:32:10 +09:00
Hide_D 076c0cd604 fix: 메인 페이지 로그인, _119 페이지 링크 복구 2023-03-09 20:15:40 +09:00
Hide_D c4ccc451ec fix: 첫 건국 시 국가방침이 null임 2023-03-09 03:03:18 +09:00
Hide_D 3d9bb9c2e0 fix: index.php인경우 Session에 gameLogin 필요 2023-03-09 02:49:28 +09:00
Hide_D 4472cd0bdc fix: 가오픈 기간에 PageFront에 안오는 정보 수정 2023-03-09 02:48:21 +09:00
Hide_D efc36e223c misc: v_front -> index 2023-03-09 02:40:15 +09:00
Hide_D af2b82616f misc: index->old_index.php 2023-03-09 02:39:56 +09:00
Hide_D 6f5d7ff84b feat: Vue3로 새롭게 작성한 메인 페이지 (#229)
- v_front.php
- API 추가
  - General/GetFrontInfo
  - Global/GetGlobalMenu
- DTO 추가
  - MenuItem, MenuMulti, MenuSplit
- 글로벌 메뉴 출력 방식 변경
  - d_setting/GlobalMenu.php

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/229
2023-03-09 02:25:31 +09:00
Hide_D 4ba9468fae fix: 임시 토스트 본문 색상 변경 2023-03-09 02:18:04 +09:00
Hide_D 7905ddb7bf feat: scrollToSelector 2023-03-09 02:17:55 +09:00
Hide_D fdef4caa65 feat: 외부 호출이 불가능한 API 타입 정의 2023-03-09 02:17:41 +09:00
Hide_D ebaf63d541 feat: 10단위 column 분리 2023-03-09 02:17:00 +09:00
Hide_D 0e92973a05 fix: 누락된 메시지 def 수정 2023-03-09 02:16:05 +09:00
Hide_D 6a4fa8ee0d feat: Message 정의를 좀더 상세히 2023-03-09 02:15:42 +09:00
Hide_D 0081c86d1e fix: 국방 줄바꿈 수정 2023-03-05 00:09:59 +09:00
Hide_D 051fdee9b9 fix: MeekroDB에서 바뀐 설정 반영
- 설정하는 옵션이 기본값으로 변경
2023-03-04 14:16:14 +09:00
Hide_D 20330e19df fix: 불가침파기제의 warning 2023-03-01 12:43:30 +09:00
Hide_D bb5c9d8fd6 fix: CityConstBase warning 2023-03-01 12:38:45 +09:00
Hide_D 18ae530edf dep: php package update 2023-03-01 12:38:42 +09:00
Hide_D 294897df54 fix: Test 코드 변경 2023-03-01 12:38:33 +09:00
Hide_D 4fcafe88a7 fix: Session은 singleton이므로 생성자가 public이면 안됨 2023-03-01 04:33:13 +09:00
Hide_D 968e4afc8f fix: DummySession이 login 상태로 취급되지 않음 2023-03-01 04:29:37 +09:00
Hide_D 4193b884b0 fix: APIHelper DummySession 초기화 문제 2023-03-01 04:08:52 +09:00
Hide_D 9371de1b4a feat: PartialReservedCommand에 reloadCommandList 노출 2023-03-01 02:31:13 +09:00
Hide_D c5c7f96c1a feat, refac: 메인 페이지에서 커맨드 리스트를 동적으로 받아옴 2023-03-01 02:17:09 +09:00
Hide_D e721642a10 fix: timeout, retry 지정 2023-02-28 00:44:59 +09:00
Hide_D 4f0b18cc3c fix: DummySession, Session singleton 문제
- DummySession 호출 후 Session 호출시에도 DummySession이 나와야 함
- 함수 상속 관계 재 설정
2023-02-28 00:43:56 +09:00
Hide_D 904e26f56e fix: 토너먼트 자동개최모드 설정 관련 2023-02-24 20:02:58 +09:00
Hide_D 7a3642296a feat: 전투 시뮬레이터에 히든 버프 반영 가능 2023-02-24 00:25:29 +09:00
Hide_D 87e57aea0e feat: 전투 시뮬레이터에 시드 값 입력 가능
- 시드 값 입력시 반복 횟수는 1회로 고정
- 스킬 성공 여부는 동일하나, 실제 수치가 조금 다른 경우가 관측 이유는 추후 확인
- 히든 버프는 아직 미 반영
2023-02-23 23:48:09 +09:00
Hide_D ea256790ec game: 계략에서 도시 인구별 방어 계산식을 제곱근에서 로그로 변경
- (log(장수수 + 1, 2) - 1.25) * 0.04
- 8명까지는 기존 계산식과 큰 차이 없음
2023-02-23 22:59:10 +09:00
Hide_D 4cbd824ee0 fix: 초기 갱신 없이 국가 삭제시 버그 수정 2023-02-23 00:30:42 +09:00
Hide_D 4db1a4b32e fix: 접속자, 접속량 계산에 문제가 있던 부분 수정 2023-02-23 00:25:44 +09:00
Hide_D c060e05553 refac: 메시지 전달 j_ 코드를 API로 변경
- 메시지 전송
- 최근 메시지 수신
- 이전 메시지 수신
- 메시지 응답
- 연락처 수신
- 메시지 삭제
2023-02-22 01:29:00 +09:00
Hide_D 92cd195276 fix: 사령부 타 수뇌 텍스트 복사의 턴 순서도 수정 2023-02-21 02:32:18 +09:00
Hide_D f9b270fef3 fix: 텍스트 복사에서 턴 번호가 제대로 옮겨지지 않는 버그 수정 2023-02-21 02:29:23 +09:00
Hide_D 3f12dfd8ba feat: 턴 조작기에 '텍스트 복사' 추가 2023-02-21 02:26:52 +09:00
Hide_D d7e57f30eb fix: 사령부 복사하기 순서 지연 수정 시도 2023-02-21 02:04:03 +09:00
Hide_D ff822561cd game: 기병의 수비시 전투력 향상
- 기존 대비 전투력 5% 향상
2023-02-21 01:59:59 +09:00
Hide_D 273973f4b6 fix: Uri 기본 사용 방법 변경 2023-02-20 02:23:54 +09:00
Hide_D c648e2df85 fix: WebUtil Namespace 2023-02-20 01:27:52 +09:00
Hide_D 9b7e0ef169 fix, dep: 사용불가능한 phpuri를 league/uri로 대체
- 테스트 아직 없음
2023-02-20 01:02:18 +09:00
Hide_D 6eccd248ea dep: composer 2.5.4 2023-02-20 00:28:04 +09:00
Hide_D eaaa1c5da8 game: 초토화가 치안, 수비, 성벽도 낮추도록 변경 2023-02-05 15:59:33 +09:00
Hide_D 95776cda5c fix: 궁병이 아닌 경우에도 '맞 선제'가 정상 작동하도록 수정
- 궁병선제사격을 선제사격시도, 선제사격발동으로 분리
- 맞선제의 기준을 궁병이 아니라 '선제'의 활성화 여부로 구분
2023-01-28 03:09:44 +09:00
Hide_D 8ae0323dcc fix: 선제 사격에 저격을 쓰지 못하게 해야함 2023-01-28 02:56:35 +09:00
Hide_D f2d0020d92 fix: 피장파장은 피장파장을 대상으로 할 수 없음 2023-01-27 00:51:12 +09:00
Hide_D 67f3004eb0 fix: 이미 다른 부위에 입찰중인 경우 경매가 열리다 마는 버그 수정 2023-01-27 00:43:11 +09:00
Hide_D f933c0616b fix: 턴시간 고정이 0분만 가능한 버그 수정 2023-01-26 14:36:59 +09:00
Hide_D a240c6f901 game: 아시아 명장전(빙의전용) 생성 2023-01-02 20:05:07 +09:00
Hide_D e2c2ae0360 feat, refact: 메시지 응답 2022-12-05 01:55:38 +09:00
Hide_D bcd0117cdd misc: 메시지 삭제 API 정리 2022-12-05 01:42:54 +09:00
Hide_D 83f233cc99 feat, refac: 메시지 삭제 2022-12-05 01:40:12 +09:00
Hide_D 4f21eab7b1 feat, refact: 메시지 연락 리스트 수신 2022-12-05 01:10:41 +09:00
Hide_D 864ddf7efe feat, refac: 메시지 전송 2022-12-05 00:46:16 +09:00
Hide_D 9d3636cc49 misc: APIHelper에서 array가 반환된 경우 result: true 자동 삽입 2022-12-05 00:42:09 +09:00
Hide_D ce4f656030 fix: 정상 깃수 기준을 1 이상으로 변경 2022-12-02 00:43:43 +09:00
Hide_D a94f080cde fix: 미접속 유산 포인트 부여에서 '이벤트 깃수'를 카운트하는 버그 수정 2022-12-02 00:41:44 +09:00
Hide_D 71ca873c7a fix: msgOption은 null을 허용해야함. 2022-12-02 00:23:07 +09:00
Hide_D 6e0d13e1fb fix: 장수 생성시 보너스 스탯 표기 오류 2022-12-01 22:24:09 +09:00
Hide_D 059c4d999a game: 맞 선제시 이전 패치에서 변경된 전투력 반영 2022-12-01 01:13:43 +09:00
Hide_D f52e357e8a fix: 디버그용 코드 수정 2022-12-01 01:02:13 +09:00
Hide_D 761496be5c game: 정란, 벽력에 선제사격 추가, 벽력 공격력 약화
- 6페이즈 전투 기준으론 공격력 유지
- 벽력기준 돌격, 수비전 등에서 상대적 약화
2022-12-01 01:00:30 +09:00
Hide_D 551972d876 feat, refac: 오래된 메시지 불러오기 2022-11-30 01:32:17 +09:00
Hide_D 81c2fc4d43 game: 궁병의 선제 사격을 일반 공격력의 50%에서 2/3로 변경 2022-11-30 00:14:24 +09:00
Hide_D 3e542fcbfa game: 궁기병의 보병 상성 상향 수준 억제
- 공격력: 12.5% 향상
- 방어력: 9.1% 향상
2022-11-30 00:10:44 +09:00
Hide_D c9ab2c593d game: 궁기병의 보병 상대 전투력 향상
- 공격력 25% 향상 (20% 열세)
- 방어력 20% 향상 (25% 열세)
2022-11-30 00:07:46 +09:00
Hide_D 0c9e00e90a game: 목우의 수비 상성 약화
- 1.2(초기) -> 0.8(무상성) -> 1(현재)
- 25% 아군 피해 증가
2022-11-30 00:04:24 +09:00
Hide_D ea17972478 fix: 제거한 troop.ts 파일 빌드 수정 2022-11-29 02:13:43 +09:00
Hide_D 3d40df9755 feat, refac: 최근 메시지 API 2022-11-29 02:06:57 +09:00
Hide_D b4ac348645 Refac: 메시지 타입 지정으로 MessageType Enum 사용 2022-11-29 01:53:55 +09:00
Hide_D 374611f66c refac: MessageType enum 2022-11-29 01:49:19 +09:00
Hide_D 39b66fd626 misc: 사용되지 않는 구버전 부대편성 코드 제거 2022-11-28 23:51:21 +09:00
Hide_D 75dca322b4 fix: UserID가 null인 경우 대응 2022-11-10 17:14:21 +09:00
Hide_D cfdae1ddfa misc: 관리를 위해 mkdir에 group permission 부여 2022-11-05 15:17:57 +09:00
Hide_D 054a6c7073 feat: 모든 API를 기록하는 시스템
- sqlite3에 기록
- 느려지지 않기를...
2022-11-05 15:00:13 +09:00
Hide_D e93d9e6cf5 feat: API에서 민감한 argument 지정 2022-11-05 14:59:52 +09:00
Hide_D 30d99c6fc3 fix: DummySession에서 get이 잘못됨. 2022-11-05 14:58:22 +09:00
Hide_D 56c9b44c93 game: 이벤트 유니크 분실 메시지를 흥미롭게 변경 2022-11-02 21:17:04 +09:00
Hide_D 919ae5a863 game: 무작위 세계 이벤트 시나리오 가오픈 재생성 주기 단축 2022-11-01 23:00:59 +09:00
Hide_D 43b8e546f6 feat: 시나리오 별 사전 생성 시 재 생성 주기 결정 가능 2022-11-01 23:00:25 +09:00
Hide_D b90aef662b game: 무작위 세계 시나리오 초기 등록 2022-10-30 22:13:39 +09:00
Hide_D 1da47863ae feat: 전역 아이템 망실 이벤트 추가 2022-10-30 22:13:25 +09:00
Hide_D 81bd5c1914 feat: 무작위건국, 무작위수도이전 커맨드 추가 2022-10-30 21:47:24 +09:00
Hide_D b14f9a638f fix: 무작위장수명 모드에서 장수명이 제대로 지정되지 않음 2022-10-30 21:41:12 +09:00
Hide_D 8ff3a5a7a8 feat: GameConst에서 유니크 획득 확률 조정 가능 2022-10-30 21:29:48 +09:00
Hide_D 48c77bd6a2 feat: 장수명 무작위 생성 모드 가능 2022-10-30 15:16:40 +09:00
35a017c1dc fix: 천통 후 서버시드 출력 시 괄호를 열지 않고 닫았던 문제 수정 (#227)
Co-authored-by: Jinhyun Kim <lewha0@gmail.com>
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/227
Reviewed-by: Hide_D <hided62@gmail.com>
Co-authored-by: lewha0 <lewha0@noreply.storage.hided.net>
Co-committed-by: lewha0 <lewha0@noreply.storage.hided.net>
2022-10-10 03:29:48 +09:00
Hide_D a3e8a10da9 game: 건국 시점 유산 포인트 베팅 제공량 상향 2022-10-10 01:39:42 +09:00
Hide_D 142b96836e refac: 신규/복귀 유저 유산 포인트 지급 로직을 조금더 최적화 2022-10-05 00:26:04 +09:00
Hide_D 9be0d2ec2d refac: storeOldGeneral을 General::kill로 이동 2022-10-04 20:38:18 +09:00
Hide_D fd817650e7 fix: 지급 버그 수정 2022-10-04 11:32:52 +09:00
Hide_D 3c6cb96a9b feat: 신규/복귀 유저에게 장수 생성 시 유산 포인트 제공
- 이벤트 깃수 제외 500포인트
- 8기까지 적립
2022-10-04 11:25:40 +09:00
Hide_D c4537454f9 fix: 최대 임관년도 수 계산 버그 재 수정 2022-10-04 10:02:39 +09:00
Hide_D 82cdaa433e fix: 최대 임관년도 수 계산 버그 2022-10-04 01:07:11 +09:00
Hide_D 32dd3ff43f misc: AI에서 삭턴NPC 구분 기준을 1턴 추가 2022-10-04 00:13:52 +09:00
Hide_D 6a5840faaa fix: AI 후방 발령 누락분 수정 2022-10-03 23:38:53 +09:00
Hide_D 5b0a3b064d fix: AI 후방 발령 로직 버그 수정
- 징병시 인구 소모가 없는 경우 후방 발령 제외
- NPC 수뇌일때와 유저 수뇌일 때 도시 인구 계산식 다른 버그 수정
2022-10-03 23:37:07 +09:00
Hide_D 14b8bb9790 fix: 2번 연속 멸망 시 유산 포인트 계산 오류 2022-10-03 11:32:22 +09:00
Hide_D 650f4a5903 fix: 구조상 베팅 당첨 포인트는 은퇴시 반영되어야 함 2022-10-03 00:37:18 +09:00
Hide_D c50410a6da game: 은퇴시 토너먼트 보정치를 100%로
- 실수였음!
2022-10-02 23:27:41 +09:00
Hide_D b2a676cd8b game: 옥란백용구 향상 최대 30% -> 50% 2022-10-02 23:25:00 +09:00
Hide_D 50a75e4543 refac, game: 은퇴 시 포인트 반영 방식 변경
- 반영하지 않고 은퇴 이후로 넘기는 포인트 추가
- 은퇴시 계수를 Obj로 이동
2022-10-02 19:41:38 +09:00
Hide_D 22172ac66f fix: null coalesing 수정 2022-10-02 19:39:35 +09:00
Hide_D 392aaa343d fix: calcGenType을 updateInstance()로 이동 2022-10-02 19:36:17 +09:00
Hide_D d924f47d58 fix: warning 발생 제거 2022-10-02 19:35:05 +09:00
Hide_D 3b70cbe724 fix: GeneralAI env 설정 관련 버그 수정 2022-10-02 17:46:20 +09:00
Hide_D 5c3233f883 misc: 서버 리셋 페이지에서 기본 설정값 변경
- 자율 행동 전부 선택
- 자율 행동 기본 시간 24시간
- 사실모드: 가상
2022-10-02 17:43:40 +09:00
Hide_D b570bfa9d4 fix: NPC선전포고, 긴급포상에서 내부 NPC 국가 상태를 업데이트하도록 수정 2022-10-02 17:37:40 +09:00
Hide_D 270cb25285 refac: GeneralAI에서 상태를 추가 업데이트할 수 있도록 구조 변경 2022-10-02 17:33:23 +09:00
Hide_D 7d3b0db924 game: 계략 성공률을 5%p 하향
- 계략 성공률에 인구수를 반영하기 이전과 비교하여 1명있을 때에는 동일
- 한명도 없을때는 5%p 상승
- 두명 이상일 때에는 이전 대비 성공률 하향
2022-10-02 15:59:30 +09:00
Hide_D 74d310e113 fix: 불가침에서 '까지'는 해당 월을 포함하여야 함 2022-10-02 15:55:31 +09:00
Hide_D 45afb1c090 fix: 수동 은퇴 시 명예의전당에 등록되지 않는 버그 2022-09-27 10:00:44 +09:00
Hide_D 40fc2f8bbf fix: NPC 순간이동이 보급이 끊긴 도시에도 갈 수 있는 버그 수정 2022-09-24 22:29:58 +09:00
Hide_D a9de5a92e1 build: pre-commit에 lint 제거 2022-09-24 20:58:56 +09:00
Hide_D c592b00c3f game: 피장파장에 추가되었던 글로벌 전략 1턴 제거 2022-09-24 20:57:44 +09:00
Hide_D 2c81be4d12 game: 계략 방어 확률에 도시 거주 장수 수 반영
- sqrt(장수 수) * 5%p
2022-09-23 21:59:51 +09:00
Hide_D f10289f7b6 game: 피장파장은 이제 전략
- 글로벌 쿨 1턴
- 피장파장 쿨 8턴
2022-09-23 21:56:15 +09:00
Hide_D c1f06b4ce5 fix: 최대 임관 년도 수 제어 규약 우회 2022-09-22 11:54:47 +09:00
Hide_D 9ad3dbba90 game: 배신 관련 최종 수정, 20%부터, +10%p씩
- 공지 추가
2022-09-21 23:25:20 +09:00
Hide_D 12c62f87f7 game: 초기 배신 수치 추가 보정
- 배신 수치를 '2'로 변경.
- 명성 패널티를 30%로 시작해서 45%, 60%
2022-09-21 23:16:29 +09:00
Hide_D 635f1ae077 feat, game: 초반 '배신 수치' 1 증가, 배신 패널티 증가
- 184년 1월부터 배신수치 1 증가.
- 배신 패널티 당 15%, 최대 6회
2022-09-21 23:12:56 +09:00
Hide_D c89bd2f63f fix: 하야, 망명 시 최대 임관 년수가 반영되지 않는 버그 수정 2022-09-21 22:48:55 +09:00
Hide_D 2f94a8a2ca fix: 가오픈 기간 중 사망 메시지에서 조사가 중복되어 나오던 문제 수정 (#226)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/226
Reviewed-by: Hide_D <hided62@gmail.com>
2022-09-14 12:07:08 +09:00
Jinhyun Kim 85b0d35af0 fix: 가오픈 기간 중 사망 메시지에서 조사가 중복되어 나오던 문제 수정 2022-09-14 11:42:19 +09:00
Hide_D b25acacb1e fix: 징병 특기에 '비용 감소' 제거 누락 2022-09-10 19:04:46 +09:00
Hide_D c05a43f3b1 fix(oauth): 이메일 변경 시 oauthID를 받아오지 못하는 분기 수정 2022-09-09 03:28:18 +09:00
Hide_D d99976daa9 fix(oauth): 카카오로그인에서 이메일만 바뀐 경우 이메일 갱신 2022-09-09 03:11:34 +09:00
Hide_D 62f53d09bf feat, game: 징병 전특 리밸런싱, 징병/소집해제시 인구 변동 트리거 설정 2022-09-06 19:48:52 +09:00
Hide_D 88c78ec892 game, misc: 작위 상승 메시지 변경 2022-09-01 02:49:20 +09:00
Hide_D 006ca76922 refac: ExecuteEngine 반환 타입 변경 2022-08-30 22:51:14 +09:00
Hide_D 8cb2e2a447 fix: OAuth Redirect UTI가 사전 값과 다른 경우 domain 보정 2022-08-28 18:00:53 +09:00
Hide_D 517c85d003 misc: oauth.php 에러 상세 표기 2022-08-28 17:37:55 +09:00
Hide_D 83556b710c fix, feat: HTTP_HOST가 다른 경우에도 oauth redirect 허용
- oauth 대상에서 redirect 허용 host를 설정해야함.
2022-08-28 17:24:25 +09:00
Hide_D a43b9091f8 feat: WebUtil::replaceDomain 2022-08-28 17:21:37 +09:00
Hide_D e83a1bef49 fix, misc: 사이시옷 수정 2022-08-28 15:45:44 +09:00
Hide_D 1147a8262c fix: 아이템 이름 오기 2022-08-28 15:41:50 +09:00
Hide_D 8a987cc55e fix: 조사 관련 문제 수정 2022-08-28 15:40:52 +09:00
Hide_D b28ca864f9 dep: package update 2022-08-28 15:30:35 +09:00
Hide_D 4bf77a5c55 game: 궁병 공격 시도, 추가페이즈 선제 공격
- 수비 선제와 구조적으로 동일
- 첫번째 상대에게 선제 사격
- 궁병과 궁병의 대결인 경우 항상 맞 선제 사격
2022-08-28 14:35:14 +09:00
Hide_D 4ebc20f182 game: 전투 첫 페이즈 계략시도 보정은 무장 제외 2022-08-28 14:17:09 +09:00
Hide_D 9eff1ccaed fix: 경매장 이름 풀 난수 생성기에 seed 초기화값 문제 수정 2022-08-27 12:15:12 +09:00
Hide_D 66170c98dd game: 수비 끔 시 사기 감소량 -3 => -6 2022-08-27 03:00:16 +09:00
Hide_D 397c054c66 game: 유니크 경매 제한 시간 감소
- 1분턴 마감시간 기준 1시간 -> 30분
2022-08-27 02:57:01 +09:00
Hide_D 0611551dc0 game: 의병모집 생성량 변경
- 3 + 연감 기준 평균 장수수 / 8 (반올림)
- 국가별 장수수가 평균 80명부터 역전
2022-08-27 02:46:44 +09:00
Hide_D 008f88d995 game: 전투시 얻는 기술량에서 공격자 상향
- 공격자 기술: 공격자가 입은 피해 * 0.012 (구 0.01)
- 수비자 기술: 수비자가 입은 피해 * 0.009 (구 0.01)
2022-08-27 02:39:47 +09:00
Hide_D 7fe450bc07 Revert "revert: LazyVarUpdater에 \BackedEnum 롤백"
This reverts commit a88ec71b44.
2022-08-26 22:16:06 +09:00
Hide_D a88ec71b44 revert: LazyVarUpdater에 \BackedEnum 롤백 2022-08-26 17:30:24 +09:00
Hide_D 8a5a3b67f7 refac: utilGame/getNPCColor 2022-08-26 01:06:43 +09:00
Hide_D 63771da876 misc: utilGame/index.ts 2022-08-26 00:34:56 +09:00
Hide_D 68891fafdb misc: CityColumn enum 2022-08-26 00:34:45 +09:00
Hide_D df31300a0b refac: GeneralBasicCard의 부대장 요구 정보를 간소화 2022-08-26 00:34:42 +09:00
Hide_D 16fb782bbf refac: LazyVarUpdater의 key로 BackedEnum 허용 2022-08-26 00:34:39 +09:00
Hide_D ed3e013a53 misc: GeneralColumn enum 추가 2022-08-26 00:34:32 +09:00
Hide_D 0bf568a655 feat: 국방 설정 시, 작성자와 작성 일시를 기록 2022-08-26 00:34:15 +09:00
Hide_D a5e481af96 fix: utilGame format에서 한단계 다르게 차이나는 버그 수정 2022-08-21 18:53:55 +09:00
Hide_D 78a9641c14 dep: lodash -> lodash-es 2022-08-21 18:14:36 +09:00
Hide_D b517000650 game: 성벽 공격 시 소모 쌀 20% 감소 2022-08-21 17:52:25 +09:00
Hide_D 1d20eb3c3e game: 초반 M장 생성 시 무지장 대량 생성 2022-08-21 17:42:33 +09:00
Hide_D 8248ccbcd5 game: 시간이 지남에 따라 성벽 강화
- 183년 기준 동일.
- 220년 기준 40% 전투력 상승
2022-08-20 15:03:58 +09:00
Hide_D b880b9bace game: NPC가 조금 더 상위병종을 시도할 확률을 높임 2022-08-20 14:39:51 +09:00
Hide_D 2da374410b game: 필살 계수 향상 방식 너프 2022-08-20 14:29:54 +09:00
Hide_D fff8f9493b game: 유니크 아이템 경매 시 현재가보다 1% 더 높아야 함 2022-08-20 14:15:49 +09:00
Hide_D 987baaa307 misc: 아시아 명장전 장수 구성 수정 2022-08-19 21:11:02 +09:00
Hide_D 9512ea9b52 feat: APICoveryType에 맞게 InvalidResponse 확장 2022-08-18 01:08:38 +09:00
Hide_D b0f3c1c97d feat: APIRecoveryType Enum 생성 2022-08-18 01:08:35 +09:00
Hide_D e823b97cf2 fix: 세션 관리 api 에러 2022-08-18 01:08:28 +09:00
Hide_D 203859ee5f dep: denque 추가 2022-08-16 23:58:21 +09:00
Hide_D 4870e2fa30 feat: GetRecentRecord 추가
- 메인페이지 최신 로그
2022-08-16 23:57:47 +09:00
Hide_D 970b702a2b fix: 빙의장은 제대로 유산을 받지 못하는 버그 수정 2022-08-13 03:18:31 +09:00
Hide_D 053288b227 fix: applyDB시 rankVarRead 처리 오류 (=은퇴 버그 수정)
- 은퇴는 applyDB 이후에 실행됨
- applyDB 코드 오류로 이후 key값 문제로 은퇴가 실행되지 않음
2022-08-13 03:12:09 +09:00
Hide_D e9b975bea7 fix: 의병모집에서 명성, 계급이 설정되지 않는 버그 수정 2022-08-12 02:25:12 +09:00
Hide_D 89fda44db8 game: 목우 상향, 무상성화 2022-08-10 23:53:19 +09:00
Hide_D fac8536095 fix: 도시 비중 계산식에서 '종사' 누락 2022-08-09 02:04:39 +09:00
Hide_D c79e65b6b7 misc: 아시아 명장전 유저장 스탯 수정 2022-08-08 21:38:02 +09:00
Hide_D 677e65ff6d dep: npm package update 2022-08-06 20:26:35 +09:00
Hide_D 0c7589d524 fix,misc: phan 검사 수준 복구 2022-08-05 23:45:31 +09:00
Hide_D da27ae2bad dep,refac: DTO를 composer 외부로 이동 2022-08-05 23:43:38 +09:00
Hide_D f8cd58bcb3 refac: conv_general_stat을 xlrd대신 opnepyxl로 변경
- 국가명 - 수뇌는 아직 테스트 안 해 보았음...
2022-08-03 00:53:41 +09:00
sarsandHide_D 3671a289b8 아시아 명장전 시나리오(비급) 추가 (#225)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/225
Reviewed-by: Hide_D <hided62@gmail.com>
Co-authored-by: sars <sarsntony@gmail.com>
Co-committed-by: sars <sarsntony@gmail.com>
2022-08-02 16:47:41 +09:00
Hide_D 48f4dbec50 misc: 부대편성 1000px 버튼의 위치를 명확히 2022-07-31 22:34:33 +09:00
Hide_D bdb29006e9 refac: 부대편성에서 1000px 모드 버튼을 좌하단으로 2022-07-31 22:20:29 +09:00
Hide_D 5ea324f103 fix: v-b-tooltip에서 undefined -> string type 초기화 생략 2022-07-31 20:34:18 +09:00
Hide_D 2f0cd32c18 fix: 부대 편성에서 부대장 집합 순서로 정렬 필요 2022-07-31 19:50:52 +09:00
Hide_D e8911d40df fix: 부대 편성에서 부대장과 다른 도시 표기가 안됨 2022-07-31 12:08:40 +09:00
Hide_D 89f173e7e3 fix: 베팅 최소 한도가 10이 아니라 1로 된 버그 수정 2022-07-30 21:13:00 +09:00
Hide_D b0ab3f6ace fix: css 누락, 로딩 누락 2022-07-30 20:48:31 +09:00
Hide_D 641af435d4 fix: 리셋 페이지 css 2022-07-30 20:45:27 +09:00
Hide_D 16a2f20af0 fix: 장수 카드에서 '남은 시간'이 제대로 표기 안됨 2022-07-30 20:16:08 +09:00
Hide_D 79734a6dcf fix: 부대명 변경이 아무에게나 보임 2022-07-30 19:44:30 +09:00
Hide_D 2e2ff1b150 feat: 감찰부에서 '이전', '다음' 버튼 2022-07-30 19:34:34 +09:00
Hide_D 5ce899ee6e fix: 장수 카드에 부상스탯 미반영 2022-07-30 14:25:23 +09:00
Hide_D e041080773 fix: 유산 포인트가 0이어도 동작 2022-07-30 12:15:07 +09:00
Hide_D f8448fbb51 fix: 자동 해산에 필요한 변수를 제공하지 않음 2022-07-30 10:34:40 +09:00
Hide_D 8defcd29a4 fix: 인자 오류 수정 2022-07-30 10:31:31 +09:00
Hide_D fba60df9d1 fix: binarysearch 상한 에러 2022-07-29 01:24:09 +09:00
Hide_D a4ff1f44ba build: source-map 활성화(디버그용) 2022-07-29 01:13:51 +09:00
Hide_D 7b75f4e01b misc: GeneralLiteCard grid 조정 2022-07-27 23:02:35 +09:00
Hide_D a9fc69e70f game: 벽력거 비용 약 상승, 목우 비용 하향 2022-07-27 22:52:02 +09:00
Hide_D a06c574327 fix: non vue page css 누락 2022-07-27 22:37:27 +09:00
Hide_D 420ae2f45b fix: 동일 부위 제한일 때, 무한히 알림오는 버그
- 의도대로라면 1턴마다 한번씩이어야함
2022-07-27 22:33:12 +09:00
Hide_D 850073a096 game: 유니크 낙찰 시 연장될 때 '상인' 전환
- 개최자와 낙찰자가 다를때에만
2022-07-27 22:30:22 +09:00
Hide_D e40aa88253 misc: 유니크 경매장에서 아이템 효과 툴팁 2022-07-27 22:21:25 +09:00
Hide_D ff92b0149a game: 벽력거 방어력 약 하향 2022-07-27 22:08:12 +09:00
Hide_D e6049a17a2 fix: 강행이 훈련,사기가 떨어지지 않는 문제 2022-07-27 21:59:29 +09:00
Hide_D 9bc1bc13f2 fix: 누락된 토너먼트 css 2022-07-27 21:57:58 +09:00
Hide_D b9cda08a4e fix: 천하통일 후에는 유산 포인트 사용 방지 2022-07-27 21:54:49 +09:00
Hide_D 4e2193fe6f fix: 불가침 파기시 header 수정 2022-07-27 21:49:45 +09:00
Hide_D 155af45378 refac: bootstrap.scss 분리 후 별도 빌드 2022-07-27 21:44:24 +09:00
Hide_D 66d6bbc772 feat: 경량 base.scss 2022-07-27 20:53:44 +09:00
Hide_D 066a6d4e6a build: bootstrap.scss 분리 2022-07-27 20:48:43 +09:00
Hide_D 94f5834b61 fix: 시나리오 생성시 성격에 class prefix 없음 2022-07-27 19:44:05 +09:00
Hide_D 947286bd09 game: npc 징병 쌀 기준 낮춤 2022-07-27 18:48:37 +09:00
Hide_D a0dee353b5 feat: 새 부대편성 페이지 (#223)
Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/223
2022-07-27 18:01:41 +09:00
Hide_D 308b1f2348 fix: 감찰부 장수 변경시 tooltip 빈칸 버그 2022-07-26 23:56:50 +09:00
Hide_D 897780cf1c dep: package update 2022-07-26 23:32:43 +09:00
Hide_D 0f8a8011be fix: 중복되는 WarUnitTrigger의 priority 정정 2022-07-25 00:29:20 +09:00
Hide_D 7ebfd960b1 fix: 도시 관직 수치 조회 권한이 잘못됨 2022-07-24 17:23:20 +09:00
Hide_D 7b3d64996d fix: 감찰부 도시 관직명 누락 2022-07-24 17:15:06 +09:00
Hide_D e578a2f310 fix: 아이템 경매 버그 수정 2022-07-19 21:24:55 +09:00
Hide_D eecb4f699b game: 이미 같은 부위에 다른 유니크가 있는 경우, 경매 진행 방지 2022-07-17 22:34:05 +09:00
Hide_D 9f4f7a759e fix: 원조를 같은 국가로 지정할 수 있는 버그 수정 2022-07-17 16:40:40 +09:00
Hide_D 11a98eb184 fix: 장수 카드 부대 집합지가 항상 주황색 2022-07-17 16:40:35 +09:00
Hide_D ed0bc5e19f fix,refac: Nation/GetGeneralList에서 부대정보는 공개되어야 함 2022-07-17 01:37:07 +09:00
Hide_D 020a2d2668 fix: 감찰부 표기(*), 이름순 정렬 2022-07-16 16:39:12 +09:00
Hide_D 27cdd3ee4b misc: 구 감찰부 제거 2022-07-16 15:56:39 +09:00
Hide_D 43a95979e1 refac: 감찰부 vue3 재 작성 (#222)
- 장수 정보, 추가 정보 vue3 component
- b_battleCenter -> v_battleCenter

Reviewed-on: https://storage.hided.net/gitea/devsam/core/pulls/222
2022-07-16 15:49:23 +09:00
Hide_D 800106f9cb fix: 등용 버그 수정 시도 2022-07-14 11:40:30 +09:00
Hide_D e5c50e48d3 refac: defineComponent => vue3 setup 2022-07-13 22:37:37 +09:00
Hide_D 08e43bed71 fix: 서버 오픈 첫 턴에는 해산 불가 2022-07-13 22:07:25 +09:00
Hide_D 6773b8cddb fix: dependency 변경에 따른 오류 수정 2022-07-13 01:17:46 +09:00
Hide_D 23c030fd00 dep: package update 2022-07-12 21:47:01 +09:00
Hide_D d5e67bb16d refac: defineComponent => vue3 setup 2022-07-12 01:48:59 +09:00
Hide_D 188e3a0fa6 refac: defindComponent => vue3 setup 2022-07-12 01:26:33 +09:00
Hide_D b31ee022af refac: defineComponent => vue3 setup 2022-07-12 00:28:08 +09:00
Hide_D 87e063e03e fix,refac: 회의실에서 줄 바꿈이 표기 안되는 버그 수정 2022-07-12 00:09:58 +09:00
Hide_D 48fe26e4b1 refac: 숫자 입력기 재작성
- 입력마다 min, max clamp 작업 취소
2022-07-11 21:55:26 +09:00
Hide_D 88fcc64537 game: NPC 요양 기준 설정 가능 2022-07-11 20:23:55 +09:00
Hide_D d9beabbbbc feat: 발령시 장수 목록에 부대장 추가 표기 2022-07-10 21:58:30 +09:00
Hide_D 3da0a7d950 feat: 부대장인 경우 부대이름으로 검색 가능 2022-07-10 21:52:54 +09:00
Hide_D 50b1db75f0 fix: 본인이 아닌 수뇌자리에도 부대장 발령 표기 2022-07-10 21:27:34 +09:00
Hide_D 94bb96d208 feat: 부대장 발령 시 부대장 대신 부대 이름 표기 2022-07-10 20:50:33 +09:00
Hide_D 93490276fd misc: 집합에서 불필요한 조사 제거 2022-07-10 17:12:12 +09:00
Hide_D 73a7bf5a61 fix: 내정 도구 유니크가 동작하지 않는 버그 수정 2022-07-09 23:09:09 +09:00
Hide_D 8a1f8f8e2c fix: JsonString이 string->int auto casting하는 버그 수정 2022-07-09 13:02:13 +09:00
Hide_D 39c88c11c4 misc: 에러 확인을 위해 추가 메시지 2022-07-09 12:26:50 +09:00
Hide_D c2e956a639 misc: DTO 에러에서 name을 포함하여 알림 2022-07-09 12:13:15 +09:00
Hide_D 368f31d1fa fix: 유니크 옥션 인자 빠짐 수정 2022-07-09 12:12:15 +09:00
Hide_D d3390dc490 fix: 상인 등록 경매에서 warning 수정 2022-07-09 12:00:00 +09:00
Hide_D eb36b6a52f fix: vue script ts error 2022-07-08 21:47:13 +09:00
Hide_D be882000ad fix: 183년 이전 선포된 경우 공백지 출병을 시도하는 버그 수정 2022-07-08 15:53:37 +09:00
Hide_D 266c1c6a5b fix: 깃수 종료 시 열린 경매 자동 닫기 2022-07-07 22:00:12 +09:00
544 changed files with 28495 additions and 15610 deletions
-15
View File
@@ -1,15 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3,
"modules": false
}
]
],
"plugins": [
"lodash"
]
}
+4
View File
@@ -10,8 +10,10 @@
*.log
logs/*.txt
api_log.db
d_log/*.txt
d_log/*.zip
d_log/*.db
sess_*
*/logs/*.txt
*/logs/*/*.txt
@@ -65,3 +67,5 @@ ingame/js/*
ingame/css/*
gateway/js/*
gateway/css/*
*.db-journal
-9
View File
@@ -45,7 +45,6 @@ return [
'hwe/api.php',
'hwe/a_traffic.php',
'hwe/battle_simulator.php',
'hwe/b_battleCenter.php',
'hwe/b_betting.php',
'hwe/v_chiefCenter.php',
'hwe/b_currentCity.php',
@@ -58,7 +57,6 @@ return [
'hwe/b_myPage.php',
'hwe/v_processing.php',
'hwe/b_tournament.php',
'hwe/b_troop.php',
'hwe/c_tournament.php',
'hwe/func_auction.php',
'hwe/func_command.php',
@@ -100,12 +98,6 @@ return [
'hwe/j_load_scenarios.php',
'hwe/j_map.php',
'hwe/j_map_recent.php',
'hwe/j_msg_contact_list.php',
'hwe/j_msg_decide_opt.php',
'hwe/j_msg_delete.php',
'hwe/j_msg_get_old.php',
'hwe/j_msg_get_recent.php',
'hwe/j_msg_submit.php',
'hwe/j_myBossInfo.php',
'hwe/j_raise_event.php',
'hwe/j_select_npc.php',
@@ -114,7 +106,6 @@ return [
'hwe/j_set_my_setting.php',
'hwe/j_set_npc_control.php',
'hwe/j_simulate_battle.php',
'hwe/j_troop.php',
'hwe/j_update_picked_general.php',
'hwe/j_vacation.php',
'hwe/lib.php',
+1
View File
@@ -2,6 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="dark">
<title>닫혀 있습니다.</title>
<script>
setTimeout(function(){
+1 -1
View File
@@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2022 Hide_D, 62che
Copyright (c) 2023 Hide_D, 62che
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+12 -12
View File
@@ -8,26 +8,26 @@
],
"config": {
"platform": {
"php": "8.1"
"php": "8.2"
}
},
"require": {
"brandonwamboldt/utilphp": "^1.1",
"sergeytsalkov/meekrodb": "^2.3",
"league/plates": "^3.3",
"league/plates": "^3.5",
"vlucas/valitron": "^1.4",
"php-extended/php-tail": "^2.1",
"pguardiario/phpuri": "^1.0",
"symfony/lock": "^6.0",
"php-extended/php-tail": "^5.0",
"symfony/lock": "^6.2",
"ezyang/htmlpurifier": "^4.10",
"xemlock/htmlpurifier-html5": "^0.1.7",
"catfan/medoo": "^2.1",
"phan/phan": "^5.3",
"nette/caching": "^3.0",
"illuminate/database": "^9.12",
"illuminate/events": "^9.12",
"spatie/data-transfer-object": "^3.7",
"php-ds/php-ds": "^1.4"
"phan/phan": "^5.4",
"nette/caching": "^3.2",
"illuminate/database": "^10.0",
"illuminate/events": "^10.0",
"php-ds/php-ds": "^1.4",
"hided62/ldto": "^1.0",
"league/uri": "^6.8"
},
"autoload": {
"psr-4": {
@@ -48,6 +48,6 @@
]
},
"require-dev": {
"phpunit/phpunit": "^9.5"
"phpunit/phpunit": "^10.0"
}
}
Generated
+1079 -875
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1
View File
@@ -10,6 +10,7 @@ require(__DIR__ . '/../vendor/autoload.php');
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>설치</title>
+4 -4
View File
@@ -90,19 +90,19 @@ if (
//기본 파일 생성
if (!file_exists(AppConf::getUserIconPathFS())) {
mkdir(AppConf::getUserIconPathFS());
mkdir(AppConf::getUserIconPathFS(), 0775);
}
if (!file_exists(ROOT . '/d_log')) {
mkdir(ROOT . '/d_log');
mkdir(ROOT . '/d_log', 0775);
}
if (!file_exists(ROOT . '/d_setting')) {
mkdir(ROOT . '/d_setting');
mkdir(ROOT . '/d_setting', 0775);
}
if (!file_exists(ROOT . '/d_shared')) {
mkdir(ROOT . '/d_shared');
mkdir(ROOT . '/d_shared', 0775);
}
}
+17
View File
@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS "api_log" (
"id" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL,
"ip" TEXT NOT NULL,
"date" TEXT NOT NULL,
"path" TEXT NOT NULL,
"arg" TEXT,
"aux" TEXT,
PRIMARY KEY("id" AUTOINCREMENT)
);
CREATE INDEX IF NOT EXISTS "by_date" ON "api_log" (
"date" DESC
);
CREATE INDEX IF NOT EXISTS "by_user" ON "api_log" (
"user_id" ASC,
"date" DESC
);
-5
View File
@@ -61,11 +61,6 @@ class RootDB
if (self::$uDB === null) {
self::$uDB = new \MeekroDB(self::$host, self::$user, self::$password, self::$dbName, self::$port, self::$encoding);
self::$uDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
self::$uDB->error_handler = function () {
};
self::$uDB->throw_exception_on_error = true;
self::$uDB->throw_exception_on_nonsql_error = true;
}
return self::$uDB;
}
+58
View File
@@ -165,3 +165,61 @@
background: url('_tK_gameImagePath_/map/pokemon_v1/back_pal8.png') no-repeat;
background-size: 700px 500px;
}
/*CR 지도*/
.map_theme_cr .map_bglayer1{
background: url('_tK_gameImagePath_/map/cr/bg-fs8.png') no-repeat;
background-size: 700px 500px;
}
.map_theme_cr.map_detail .city_base .city_bg {
background-image: none !important;
width: 39.5px !important;
height: 39.5px !important;
left: 1px !important;
top: -4px !important;
opacity: 0.5;
}
.map_theme_cr.map_detail.small_width_map .city_base .city_bg {
background-image: none !important;
width: 28.5px !important;
height: 28.5px !important;
left: 6px !important;
top: 4px !important;
opacity: 0.5;
}
.map_theme_cr.map_detail .city_bg.bFF0000 { background-color: #FF0000; }
.map_theme_cr.map_detail .city_bg.b800000 { background-color: #800000; }
.map_theme_cr.map_detail .city_bg.bA0522D { background-color: #A0522D; }
.map_theme_cr.map_detail .city_bg.bFF6347 { background-color: #FF6347; }
.map_theme_cr.map_detail .city_bg.bFFA500 { background-color: #FFA500; }
.map_theme_cr.map_detail .city_bg.bFFDAB9 { background-color: #FFDAB9; }
.map_theme_cr.map_detail .city_bg.bFFD700 { background-color: #FFD700; }
.map_theme_cr.map_detail .city_bg.bFFFF00 { background-color: #FFFF00; }
.map_theme_cr.map_detail .city_bg.b7CFC00 { background-color: #7CFC00; }
.map_theme_cr.map_detail .city_bg.b00FF00 { background-color: #00FF00; }
.map_theme_cr.map_detail .city_bg.b808000 { background-color: #808000; }
.map_theme_cr.map_detail .city_bg.b008000 { background-color: #008000; }
.map_theme_cr.map_detail .city_bg.b2E8B57 { background-color: #2E8B57; }
.map_theme_cr.map_detail .city_bg.b008080 { background-color: #008080; }
.map_theme_cr.map_detail .city_bg.b20B2AA { background-color: #20B2AA; }
.map_theme_cr.map_detail .city_bg.b6495ED { background-color: #6495ED; }
.map_theme_cr.map_detail .city_bg.b7FFFD4 { background-color: #7FFFD4; }
.map_theme_cr.map_detail .city_bg.bAFEEEE { background-color: #AFEEEE; }
.map_theme_cr.map_detail .city_bg.b87CEEB { background-color: #87CEEB; }
.map_theme_cr.map_detail .city_bg.b00FFFF { background-color: #00FFFF; }
.map_theme_cr.map_detail .city_bg.b00BFFF { background-color: #00BFFF; }
.map_theme_cr.map_detail .city_bg.b0000FF { background-color: #0000FF; }
.map_theme_cr.map_detail .city_bg.b000080 { background-color: #000080; }
.map_theme_cr.map_detail .city_bg.b483D8B { background-color: #483D8B; }
.map_theme_cr.map_detail .city_bg.b7B68EE { background-color: #7B68EE; }
.map_theme_cr.map_detail .city_bg.bBA55D3 { background-color: #BA55D3; }
.map_theme_cr.map_detail .city_bg.b800080 { background-color: #800080; }
.map_theme_cr.map_detail .city_bg.bFF00FF { background-color: #FF00FF; }
.map_theme_cr.map_detail .city_bg.bFFC0CB { background-color: #FFC0CB; }
.map_theme_cr.map_detail .city_bg.bF5F5DC { background-color: #F5F5DC; }
.map_theme_cr.map_detail .city_bg.bE0FFFF { background-color: #E0FFFF; }
.map_theme_cr.map_detail .city_bg.bFFFFFF { background-color: #FFFFFF; }
.map_theme_cr.map_detail .city_bg.bA9A9A9 { background-color: #A9A9A9; }
+1
View File
@@ -21,6 +21,7 @@ $plock = $db->queryFirstField('SELECT plock FROM plock WHERE `type` ="GAME"');
<head>
<title>삼국지 모의전투 HiDCHe</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=1024" />
<?=WebUtil::printCSS('../d_shared/common.css')?>
+1 -2
View File
@@ -19,6 +19,7 @@ $admin = getAdmin();
<head>
<title>게임관리</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=1024" />
<?=WebUtil::printCSS('../d_shared/common.css')?>
@@ -40,8 +41,6 @@ $admin = getAdmin();
<tr>
<td width=110 align=right>시작시간변경</td>
<td width=285><input type=text size=20 maxlength=20 style=color:white;background-color:black;text-align:right; name=starttime value='<?=substr($admin['starttime'], 0, 19)?>'><input type=submit name=btn value=변경1></td>
<td width=110 align=right>현재도시훈사</td>
<td width=285><?=$admin['city_rate']?></td>
</tr>
<tr>
<td width=110 align=right>최대 장수</td>
+1
View File
@@ -20,6 +20,7 @@ $db = DB::db();
<head>
<title>회원관리</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+10 -8
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -111,7 +113,7 @@ switch ($btn) {
case "경험치1000":
$text = $btn . " 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -122,7 +124,7 @@ switch ($btn) {
case "공헌치1000":
$text = $btn . " 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -133,7 +135,7 @@ switch ($btn) {
case "보숙10000":
$text = "보병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -143,7 +145,7 @@ switch ($btn) {
case "궁숙10000":
$text = "궁병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -154,7 +156,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "기병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -165,7 +167,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "귀병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -176,7 +178,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
$text = "차병숙련도+10000 지급!";
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
$db->update('general', [
@@ -196,7 +198,7 @@ switch ($btn) {
case "메세지 전달":
$text = $msg ?? '';
foreach ($genlist as $generalID) {
$msg = new Message(Message::MSGTYPE_PRIVATE, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg = new Message(MessageType::private, $src, MessageTarget::buildQuick($generalID), $text, new \DateTime(), new \DateTime('9999-12-31'), []);
$msg->send(true);
}
break;
+1
View File
@@ -38,6 +38,7 @@ function colorBlockedName($general)
<head>
<title>멀티관리</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+4 -2
View File
@@ -2,6 +2,8 @@
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
//로그인 검사
@@ -18,7 +20,7 @@ $msg = Util::getPost('msg', 'string', '메시지');
$db = DB::db();
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
//NOTE: 왜 기능이 admin2와 admin4가 같이 있는가?
//NOTE: 왜 블럭 시 admin4에선 금쌀을 없애지 않는가?
switch ($btn) {
case "블럭 해제":
@@ -66,7 +68,7 @@ switch ($btn) {
$src = MessageTarget::buildQuick($session->generalID);
foreach($genlist as $generalID){
$msgObj = new Message(
Message::MSGTYPE_PRIVATE,
MessageType::private,
$src,
MessageTarget::buildQuick($generalID),
$msg,
+1
View File
@@ -38,6 +38,7 @@ $sel2[$type2] = "selected";
<head>
<title>일제정보</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+1
View File
@@ -83,6 +83,7 @@ $generalObj = General::createGeneralObjFromDB($gen);
<head>
<title>로그정보</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+1
View File
@@ -30,6 +30,7 @@ $sel[$type] = "selected";
<head>
<title>외교정보</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+1 -2
View File
@@ -27,7 +27,6 @@ foreach ($db->queryFirstColumn(
$inheritPointManager = InheritancePointManager::getInstance();
foreach(General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc = 0')) as $genObj){
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->mergeTotalInheritancePoint($genObj);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
+2
View File
@@ -28,12 +28,14 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
<head>
<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" />
<title><?= UniqueConst::$serverName ?>: 명장일람</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'bestGeneral']) ?>
</head>
+2
View File
@@ -14,12 +14,14 @@ increaseRefresh("왕조일람", 1);
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 왕조일람</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', 'common') ?>
</head>
+2
View File
@@ -24,10 +24,12 @@ $serverID = $emperior['server_id'] ?? ($emperior['serverID'] ?? null);
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 왕조일람</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', 'common', true) ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
+2
View File
@@ -41,12 +41,14 @@ if ($gameStor->isunited) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 장수일람</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', 'common') ?>
</head>
+2
View File
@@ -43,12 +43,14 @@ if ($scenarioIdx && key_exists($scenarioIdx, $scenarioList[$seasonIdx] ?? [])) {
<head>
<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" />
<title><?= UniqueConst::$serverName ?>: 명예의 전당</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'hallOfFame']) ?>
</head>
+2
View File
@@ -26,12 +26,14 @@ if ($con >= 2) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 세력일람</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'extKingdoms']) ?>
<?= WebUtil::printStaticValues($gameStor->getValues(['killturn', 'autorun_user', 'turnterm'])) ?>
</head>
+2
View File
@@ -24,12 +24,14 @@ $sel[$type] = "selected";
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 빙의일람</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common']) ?>
</head>
+9 -1
View File
@@ -8,7 +8,7 @@ include "func.php";
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("갱신정보", 2);
increaseRefresh("갱신정보", 1);
$admin = $gameStor->getValues(['year', 'month', 'refresh', 'maxrefresh', 'maxonline']);
@@ -23,6 +23,12 @@ $online = [];
$curonline = getOnlineNum();
foreach ($log as $i => $value) {
$parse = Json::decode($value);
if(is_array($parse) === false){
continue;
}
if(count($parse) < 5){
continue;
}
$date[$i] = $parse[0];
$year[$i] = $parse[1];
$month[$i] = $parse[2];
@@ -52,6 +58,7 @@ if ($admin['maxonline'] < $curonline) {
<head>
<title><?= UniqueConst::$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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
@@ -83,6 +90,7 @@ if ($admin['maxonline'] < $curonline) {
}
</style>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common']) ?>
</head>
-208
View File
@@ -1,208 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
$v = new Validator($_POST + $_GET);
$v->rule('required', 'gen')
->rule('integer', 'gen');
$btn = Util::getReq('btn');
$gen = Util::getReq('gen', 'int', 0);
$reqQueryType = Util::getReq('query_type', 'string', null);
// $queryTypeText, $reqArgType(0=>None, 1=>AdditionalColumn, 2=>rankVal, 3=>aux), $comp
$queryMap = [
'turntime' => ['최근턴', 0, function ($lhs, $rhs) {
return - ($lhs['turntime'] <=> $rhs['turntime']);
}],
'recent_war' => ['최근전투', 1, function ($lhs, $rhs) {
return - ($lhs['recent_war'] <=> $rhs['recent_war']);
}],
'name' => ['장수명', 0, function ($lhs, $rhs) {
if ($lhs['npc'] !== $rhs['npc']) {
return $lhs['npc'] <=> $rhs['npc'];
}
return $lhs['name'] <=> $rhs['name'];
}],
'warnum' => ['전투수', 2, function ($lhs, $rhs) {
return - ($lhs['warnum'] <=> $rhs['warnum']);
}]
];
if ($reqQueryType === null || !key_exists($reqQueryType, $queryMap)) {
$reqQueryType = Util::array_first_key($queryMap);
}
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("감찰부", 2);
//전투 추진을 위해 갱신
TurnExecutionHelper::executeAllCommand();
$gameStor->resetCache();
$testGeneralNationID = $db->queryFirstField('SELECT nation FROM general WHERE no = %i', $gen);
$me = $db->queryFirstRow('SELECT no,nation,officer_level,con,turntime,belong,permission,penalty from general where owner=%i', $userID);
$nationID = $me['nation'];
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
$permission = checkSecretPermission($me);
if ($permission < 0) {
echo '국가에 소속되어있지 않습니다.';
die();
} else if ($permission < 1) {
echo "권한이 부족합니다. 수뇌부가 아니거나 사관년도가 부족합니다.";
die();
}
//잘못된 접근
if ($testGeneralNationID != $nationID) {
$gen = 0;
}
if ($btn == '정렬') {
$gen = 0;
}
[$queryTypeText, $reqArgType, $comp] = $queryMap[$reqQueryType];
if ($reqArgType === 0) {
$generalBasicList = $db->query('SELECT no, name, npc, turntime, officer_level FROM general WHERE nation = %i', $nationID);
} else if ($reqArgType === 1) {
$generalBasicList = $db->query('SELECT no, name, npc, turntime, officer_level, %b FROM general WHERE nation = %i', $reqQueryType, $nationID);
} else if ($reqArgType === 2) {
$generalBasicList = $db->query(
'SELECT no, name, npc, turntime, officer_level, value as %b
FROM general LEFT JOIN rank_data
ON general.no = rank_data.general_id
WHERE rank_data.type = %s AND general.nation = %i',
$reqQueryType,
$reqQueryType,
$nationID
);
} else if ($reqArgType === 3) {
$generalBasicList = array_map(function ($arr) {
$arr['aux'] = Json::decode($arr['aux']);
return $arr;
}, $db->query('SELECT no, name, npc, turntime, officer_level, aux FROM general WHERE nation = %i', $nationID));
} else {
throw new \sammo\MustNotBeReachedException();
}
usort($generalBasicList, $comp);
if (!$gen) {
$gen = $generalBasicList[0]['no'];
}
$showGeneral = General::createGeneralObjFromDB($gen);
?>
<!DOCTYPE html>
<html>
<head>
<title><?= UniqueConst::$serverName ?>: 감찰부</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=500" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('ts', ['common', 'battleCenter']) ?>
</head>
<body>
<div id="container" class="bg0">
<div class="row gx-0">
<div class="col">감 찰 부<br><?= closeButton() ?></div>
</div>
<div class="row gx-0">
<div class="col-12" style="border-left: solid 1px gray; border-right:solid 1px gray;">
<form name=form1 method=get>
정렬순서 :
<select name='query_type' size=1>
<?php foreach ($queryMap as $queryType => [$queryTypeText,]) : ?>
<option <?= $queryType == $reqQueryType ? 'selected' : '' ?> value='<?= $queryType ?>'><?= $queryTypeText ?></option>
<?php endforeach; ?>
</select>
<input type=submit name=btn value='정렬'>
대상장수 :
<select name=gen size=1>
<?php foreach ($generalBasicList as $general) : ?>
<option <?= $gen == $general['no'] ? 'selected' : '' ?> value='<?= $general['no'] ?>'><?= $general['officer_level'] > 4 ? "*{$general['name']}*" : $general['name'] ?> (<?= substr($general['turntime'], 14, 5) ?>)</option>
<?php endforeach; ?>
</select>
<input type=submit name=btn value='조회'>
</form>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell" style="color:skyblue">장수 정보</div>
</div>
<div class="row">
<div class="col"><?php generalInfo($showGeneral); ?><?php generalInfo2($showGeneral); ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">장수 열전</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getGeneralHistoryLogAll($gen)) ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">전투 기록</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getBattleDetailLogRecent($gen, 24)) ?></div>
</div>
</div>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">전투 결과</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getBattleResultRecent($gen, 24)) ?></div>
</div>
</div>
<?php if ($showGeneral->getNPCType() > 1 || $permission >= 2) : ?>
<div class="col col-12 col-md-6">
<div class="row mx-0">
<div class="col bg1 header-cell">개인 기록</div>
</div>
<div class="row">
<div class="col"><?= formatHistoryToHTML(getGeneralActionLogRecent($gen, 24)) ?></div>
</div>
</div>
<?php endif; ?>
</div>
<div class="row gx-0">
<div class="col "><?= closeButton() ?></div>
</div>
<div class="row bg0 gx-0">
<div class="col bg0"><?= banner() ?></div>
</div>
</div>
</body>
</html>
+2
View File
@@ -113,12 +113,14 @@ if ($str3) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 베팅장</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'betting']) ?>
<?= WebUtil::printStaticValues([
'staticValues'=>[
+2
View File
@@ -34,6 +34,7 @@ $templates = new \League\Plates\Engine('templates');
<head>
<title><?= UniqueConst::$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=1024" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
@@ -55,6 +56,7 @@ $templates = new \League\Plates\Engine('templates');
font-size: x-small;
}
</style>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'currentCity']) ?>
</head>
+2
View File
@@ -51,12 +51,14 @@ $templates = new \League\Plates\Engine('templates');
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 암행부</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common']) ?>
</head>
+2
View File
@@ -42,6 +42,7 @@ if ($meLevel >= 5) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 인사부</title>
@@ -54,6 +55,7 @@ if ($meLevel >= 5) {
var chiefStatMin = <?= GameConst::$chiefStatMin ?>;
var myLevel = <?= $meLevel ?>;
</script>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'bossInfo']) ?>
<?php
+2
View File
@@ -33,12 +33,14 @@ $sel = [$type => "selected"];
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 세력도시</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'extExpandCity']) ?>
</head>
+2
View File
@@ -42,12 +42,14 @@ if ($gameStor->isunited) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 세력장수</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common']) ?>
</head>
+2
View File
@@ -25,12 +25,14 @@ if ($nationID == 0) {
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 세력정보</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common']) ?>
</head>
+4 -2
View File
@@ -29,7 +29,7 @@ if ($myset > 0) {
$submit = 'hidden';
}
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, 2);
$targetTime = addTurn($me->getVar('lastrefresh'), $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if ($gameStor->turntime <= $gameStor->opentime) {
//서버 가오픈시 할 수 있는 행동
if ($me->getNPCType() == 0 && $me->getNationID() == 0) {
@@ -52,6 +52,7 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<head>
<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" />
<title><?= UniqueConst::$serverName ?>: 내정보</title>
@@ -70,6 +71,7 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['myPage']) ?>
</head>
@@ -115,7 +117,7 @@ $use_auto_nation_turn = $me->getAuxVar('use_auto_nation_turn') ?? 1;
<?php foreach ([90, 80, 60, 40] as $targetDefenceTrain) : ?>
<option value='<?= $targetDefenceTrain ?>' <?= $me->getVar('defence_train') == $targetDefenceTrain ? "selected" : ""; ?>><?= formatDefenceTrain($targetDefenceTrain) ?>(훈사<?= $targetDefenceTrain ?>)</option>
<?php endforeach; ?>
<option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>[훈련, 사기 -3]</option>
<option value=999 <?= $me->getVar('defence_train') == 999 ? "selected" : ""; ?>><?= formatDefenceTrain(999) ?>[훈련 -3, 사기 -6]</option>
</select>
】<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>
+3 -1
View File
@@ -106,10 +106,12 @@ $globalBetTotal = array_sum($globalBet);
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 토너먼트</title>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', 'common', true) ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
</head>
@@ -130,7 +132,7 @@ $globalBetTotal = array_sum($globalBet);
<td colspan=8>
<button type="button" class="btn btn-secondary" onclick='location.reload()'>갱신</button>
<?php if ($admin['tournament'] == 0) : ?>
<select name=auto size=1 style=color:white;background-color:black;>
<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>
-251
View File
@@ -1,251 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
//로그인 검사
$session = Session::requireGameLogin()->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
increaseRefresh("부대편성", 1);
$me = $db->queryFirstRow('SELECT no,nation,troop,`officer_level`,permission,penalty FROM general WHERE owner=%i', $userID);
$permission = checkSecretPermission($me, false);
$troops = [];
foreach ($db->query('SELECT troop_leader,name FROM troop WHERE nation = %i', $me['nation']) as $rawTroop) {
$troops[$rawTroop['troop_leader']] = [
'name' => $rawTroop['name'],
'users' => []
];
}
foreach ($db->query(
'SELECT no,name,turntime,troop,city FROM general WHERE troop!=0 AND nation = %i ORDER BY turntime ASC',
$me['nation']
) as $general) {
if (!key_exists($general['troop'], $troops)) {
trigger_error("올바르지 않은 부대 소속 {$general['no']}, {$general['name']} : {$general['troop']}");
continue;
}
$general['cityText'] = CityConst::byID($general['city'])->name;
$troops[$general['troop']]['users'][] = $general;
}
if ($troops) {
$troopLeaders = $db->query(
'SELECT no,name,picture,imgsvr,turntime,city,troop FROM general WHERE no IN %li',
array_keys($troops)
);
$generalTurnList = [];
foreach ($db->queryAllLists(
'SELECT general_id, turn_idx, brief FROM general_turn WHERE general_id IN %li AND turn_idx < 5 ORDER BY general_id ASC, turn_idx ASC',
array_column($troopLeaders, 'no')
) as [$generalID, $turnIdx, $brief]) {
if (!key_exists($generalID, $generalTurnList)) {
$generalTurnList[$generalID] = [];
}
$generalTurnList[$generalID][$turnIdx] = $brief;
}
foreach ($troopLeaders as $troopLeader) {
$imageTemp = GetImageURL($troopLeader['imgsvr']);
$troopLeader['pictureFullPath'] = "$imageTemp/{$troopLeader['picture']}";
$troopLeader['cityText'] = CityConst::byID($troopLeader['city'])->name;
$turnText = [];
foreach ($generalTurnList[$troopLeader['no']] as $rawTurnIdx => $brief) {
if ($brief != '집합') {
$brief = '~';
}
$turnIdx = $rawTurnIdx + 1;
$turnText[] = "{$turnIdx} : {$brief}";
}
$troopLeader['turnText'] = join('<br>', $turnText);
$troops[$troopLeader['troop']]['leader'] = $troopLeader;
}
}
uasort($troops, function ($lhs, $rhs) {
return $lhs['leader']['turntime'] <=> $rhs['leader']['turntime'];
})
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" />
<title><?= UniqueConst::$serverName ?>: 부대편성</title>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('ts', ['common', 'troop'], true) ?>
</head>
<body>
<div style="width:1000px;margin:auto;">
<table width=1000 class='tb_layout bg0'>
<tr>
<td>부 대 편 성<br><?= backButton() ?></td>
</tr>
</table>
<table id="troop_list" class='tb_layout bg0'>
<thead>
<tr>
<td width=64 class='bg1 center'>선 택</td>
<td width=130 class='bg1 center'>부 대 정 보</td>
<td width=100 class='bg1 center'>부 대 장</td>
<td width=576 class='bg1 center' style=table-layout:fixed;word-break:break-all;>장 수</td>
<td width=130 class='bg1 center' style=table-layout:fixed;word-break:break-all;>부대장행동</td>
</tr>
</thead>
<tfoot>
<tr>
<td colspan='5'>
<?php if (!$troops) : ?>
<?php elseif ($me['troop'] == 0) : ?>
<input type=button id='btnJoinTroop' value='부 대 가 입'>
<?php else : ?>
<input type=button id="btnLeaveTroop" value='부 대 탈 퇴'>
<?php endif; ?>
</td>
</tr>
</tfoot>
<tbody>
<?php
foreach ($troops as $troopNo => $troop) {
$troopLeader = $troop['leader'];
$genlistText = [];
$cityText = $troopLeader['cityText'];
$cityID = $troopLeader['city'];
$leaderID = $troopLeader['no'];
foreach ($troop['users'] as $troopUser) {
$spanClass = 'troopUser';
if ($troopUser['city'] !== $cityID) {
$spanClass .= ' diffCity';
}
if ($troopUser['no'] == $leaderID) {
$spanClass .= ' leader';
}
$genlistText[] = "<span class='$spanClass' data-general-id='{$troopUser['no']}'
><span class='generalName'>{$troopUser['name']}</span><span class='cityText'>【{$troopUser['cityText']}】</span
></span>";
}
$genlistText = sprintf('%s (%d명)', join(', ', $genlistText), count($genlistText)); ?>
<?php if ($me['troop'] == 0) : ?>
<tr>
<td align=center rowspan=2><input type='radio' class='troopId' name='troop' value='<?= $troopNo ?>'></td>
<td align=center><?= $troop['name'] ?><br>【 <?= $cityText ?> 】</td>
<td height=64 class='generalIcon' style='background:no-repeat center url("<?= $troopLeader['pictureFullPath'] ?>");background-size:64px;'>&nbsp;</td>
<td rowspan=2 width=62><?= $genlistText ?></td>
<td rowspan=2><?= $troopLeader['turnText'] ?></td>
</tr>
<tr>
<td align=center>
<font size=2>【턴】 <?= substr($troopLeader['turntime'], 14, 5) ?></font>
</td>
<td align=center>
<font size=1><?= $troopLeader['name'] ?></font>
</td>
</tr>
<tr>
<td colspan=5>
<?php else : ?>
<tr>
<td align=center rowspan=2>&nbsp;</td>
<td align=center><?= $troop['name'] ?><br>【 <?= $cityText ?> 】</td>
<td height=64 class='generalIcon' style='background:no-repeat center url("<?= $troopLeader['pictureFullPath'] ?>");background-size:64px;'>&nbsp;</td>
<td rowspan=2 width=62><?= $genlistText ?></td>
<td rowspan=2>
<?php if ($me['no'] == $troopLeader['no']) : ?>
<select id='genNo' name=gen size=3 style=color:white;background-color:black;font-size:14px;width:128px;>";
<?php foreach ($troop['users'] as $troopUser) : ?>
<?php if ($troopUser['no'] == $me['no']) {
continue;
} ?>
<option value='<?= $troopUser['no'] ?>'><?= $troopUser['name'] ?></option>
<?php endforeach; ?>
</select><br>
<input type=button id='btnKickTroop' value='부 대 추 방' style=width:130px;height:25px;>
<?php else : ?>
<?= $troopLeader['turnText'] ?>
<?php endif; ?>
</td>
</tr>
<tr>
<td align=center>
<font size=2>【턴】 <?= substr($troopLeader['turntime'], 14, 5) ?></font>
</td>
<td align=center>
<font size=1><?= $troopLeader['name'] ?></font>
</td>
</tr>
<tr>
<td colspan=5></td>
</tr>
<?php endif;
} //foreach ($troops as $troopNo=>$troop) {
?>
</tbody>
</table>
<br>
<div class="row">
<?php if($me['troop'] == 0): ?>
<div class="col-6"><?php /*TODO: 모바일 */ ?>
<div class="row gx-0 bg0">
<div class="bg1 col d-grid"><span class="align-self-center center">부대명</span></div>
<div class="col d-grid"><input type=text style=color:white;background-color:black; size=18 maxlength=18 id='newTroopName'></div>
<div class="col d-grid"><button type='button' id="btnCreateTroop" class='btn btn-sm btn-secondary'>부대 창설</button></div>
</div>
</div>
<?php endif; ?>
<?php if($troops && ($me['troop'] == $me['no'] || $permission == 4)): ?>
<div class="col-6">
<div class="row gx-0 bg0">
<div class="bg1 col d-grid"><span class="align-self-center center">부대명</span></div>
<div class="col d-grid"><select class="form-select" id="changeNameTroopID">
<?php if($permission != 4): ?>
<option value="<?=$me['troop']?>"><?=$troops[$me['troop']]['name']?></option>
<?php else: ?>
<?php foreach ($troops as $troopNo => $troop): ?>
<option value="<?=$troopNo?>"><?=$troop['name']?></option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>
<div class="col d-grid"><input type=text style=color:white;background-color:black; size=18 maxlength=18 id='changeTroopName'></div>
<div class="col d-grid"><button type='button' id="btnChangeTroopName" class='btn btn-sm btn-secondary'>이름 변경</button></div>
</div>
</div>
<?php endif; ?>
</div>
<table width=1000 class='tb_layout bg0'>
<tr>
<td><?= backButton() ?></td>
</tr>
<tr>
<td><?= banner() ?> </td>
</tr>
</table>
</div>
</body>
</html>
+32 -3
View File
@@ -43,6 +43,7 @@ if ($nationID) {
<head>
<title><?= UniqueConst::$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=1100" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
@@ -54,6 +55,7 @@ if ($nationID) {
var city = <?= Json::encode($city) ?>;
var nation = <?= Json::encode($nation) ?>;
</script>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'battle_simulator']) ?>
</head>
@@ -64,8 +66,8 @@ if ($nationID) {
전역 설정
</div>
<div class="card-body dragpad_battle">
<div class="row">
<div class="col-sm-6">
<div class="row gx-0">
<div class="col-sm-4">
<div class="input-group">
<input type="number" class="form-control" aria-describedby="text_year" value="<?= $startYear ?>" disabled>
<div class="input-group-text"> 년 시작 </div>
@@ -75,9 +77,13 @@ if ($nationID) {
<div class="input-group-text"> 월 </div>
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-5 px-2">
<div class="btn-toolbar" role="toolbar">
<div class="input-group me-2" role="group">
<div class="input-group-text">
시드
</div>
<input type="text" class="form-control" id="seed" aria-describedby="text_seed">
<div class="input-group-text">
반복 횟수
</div>
@@ -86,6 +92,10 @@ if ($nationID) {
<option value="1000">1000회 (요약 표기)</option>
</select>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="btn-toolbar" role="toolbar">
<div class="btn-group me-2" role="group">
<button type="button" class="btn btn-danger btn-begin_battle">전투</button>
</div>
@@ -425,6 +435,25 @@ if ($nationID) {
</div>
<input type="number" class="form-control form_killcrew" value="0" step="1">
</div>
<div class="input-group mb-0">
<div class="input-group-text">자신</div>
<div class="input-group-text">회피 확률</div>
<input type="number" class="form-control form_war_avoid_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">필살 확률</div>
<input type="number" class="form-control form_war_critical_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">계략 시도 확률</div>
<input type="number" class="form-control form_war_magic_trial_prob" value="0" step="1" min="0" max="5">
</div>
<div class="input-group mb-1">
<div class="input-group-text">상대</div>
<div class="input-group-text">회피 확률</div>
<input type="number" class="form-control form_oppose_war_avoid_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">필살 확률</div>
<input type="number" class="form-control form_oppose_war_critical_ratio" value="0" step="1" min="0" max="5">
<div class="input-group-text">계략 시도 확률</div>
<input type="number" class="form-control form_oppose_war_magic_trial_prob" value="0" step="1" min="0" max="5">
</div>
</div>
</div>
+2 -7
View File
@@ -52,8 +52,8 @@ class DB
/**
* DB 객체 생성
*
* @return \MeekroDB
*
* @return \MeekroDB
* @suppress PhanTypeMismatchProperty
*/
public static function db()
@@ -61,11 +61,6 @@ class DB
if (self::$uDB === null) {
self::$uDB = new \MeekroDB(self::$host, self::$user, self::$password, self::$dbName, self::$port, self::$encoding);
self::$uDB->connect_options[MYSQLI_OPT_INT_AND_FLOAT_NATIVE] = true;
self::$uDB->error_handler = function () {
};
self::$uDB->throw_exception_on_error = true;
self::$uDB->throw_exception_on_nonsql_error = true;
}
return self::$uDB;
}
+53
View File
@@ -0,0 +1,53 @@
<?php
namespace sammo;
use sammo\DTO\MenuItem;
use sammo\DTO\MenuMulti;
use sammo\DTO\MenuSplit;
//변경을 원한다면 파일을 복제 후 수정
class GlobalMenu {
/** @var (MenuItem|MenuMulti|MenuSplit)[] */
const version = 3;
static ?array $menu = null;
public static function getMenu(): array{
if(static::$menu !== null){
return static::$menu;
}
static::$menu = [
new MenuItem('천통국 베팅', 'v_nationBetting.php', condHighlightVar: 'nationBetting'),
new MenuMulti('게임정보', [
new MenuItem('세력일람', 'a_kingdomList.php', newTab: true),
new MenuItem('장수일람', 'a_genList.php', newTab: true),
new MenuItem('명장일람', 'a_bestGeneral.php', newTab: true),
new MenuItem('명예의전당', 'a_hallOfFame.php', newTab: true),
new MenuItem('왕조일람', 'a_emperior.php', newTab: true),
]),
new MenuItem('연감', 'v_history.php', newTab: true),
new MenuSplit(
new MenuItem('게시판', '/board/community', newTab: true),
[
new MenuItem('건의/제안', '/board/request', newTab: true),
new MenuItem('팁/강좌', '/board/tip', newTab: true),
new MenuItem('패치 내역', '/board/patch', newTab: true),
]
),
new MenuSplit(
new MenuItem('공식 오픈 톡', 'https://open.kakao.com/o/', newTab: true),
[
new MenuItem('잡담 오픈 톡', 'https://open.kakao.com/o/', newTab: true)
],
),
new MenuItem('전투 시뮬레이터', 'battle_simulator.php', newTab: true),
new MenuMulti('기타 정보', [
new MenuItem('접속량정보', 'a_traffic.php', newTab: true),
new MenuItem('빙의일람', 'a_npcList', newTab: true, condShowVar: 'npcMode'),
]),
new MenuItem('설문조사', 'v_vote.php', newTab: true, condHighlightVar: 'vote'),
];
return static::$menu;
}
}
+40 -132
View File
@@ -7,7 +7,6 @@ use Ds\Set;
use sammo\Enums\AuctionType;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
use sammo\Event\Action;
require_once 'process_war.php';
require_once 'func_gamerule.php';
@@ -886,7 +885,7 @@ function generalInfo2(General $generalObj)
function getOnlineNum(): int
{
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online') ?? 0;
return KVStorage::getStorage(DB::db(), 'game_env')->getValue('online_user_cnt') ?? 0;
}
function onlinegen(General $general)
@@ -906,7 +905,7 @@ function nationMsg(General $general)
$nationID = $general->getNationID();
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
return $nationStor->notice ?? '';
return $nationStor->nationNotice['msg'] ?? '';
}
function banner()
@@ -1003,19 +1002,31 @@ function increaseRefresh($type = "", $cnt = 1)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
$isunited = $gameStor->isunited;
$opentime = $gameStor->opentime;
if ($isunited != 2 && $generalID && $userGrade < 6 && $opentime <= TimeUtil::now()) {
$db->update('general', [
'lastrefresh' => $date,
'con' => $db->sqleval('con + %i', $cnt),
'connect' => $db->sqleval('connect + %i', $cnt),
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
'refresh' => $db->sqleval('refresh + %i', $cnt)
], 'owner=%i', $userID);
if($userGrade == 6){
return;
}
if($isunited == 2){
return;
}
if(!$generalID){
return;
}
if($opentime > $date){
return;
}
$gameStor->refresh = $gameStor->refresh + $cnt; //TODO: +로 증가하는 값은 별도로 분리
$db->update('general', [
'lastrefresh' => $date,
'con' => $db->sqleval('con + %i', $cnt),
'connect' => $db->sqleval('connect + %i', $cnt),
'refcnt' => $db->sqleval('refcnt + %i', $cnt),
'refresh' => $db->sqleval('refresh + %i', $cnt)
], 'owner=%i', $userID);
$date = date('Y_m_d H:i:s');
$date2 = substr($date, 0, 10);
@@ -1033,42 +1044,6 @@ function increaseRefresh($type = "", $cnt = 1)
),
FILE_APPEND
);
$proxy_headers = array(
'HTTP_VIA',
'HTTP_X_FORWARDED_FOR',
'HTTP_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED',
'HTTP_CLIENT_IP',
'HTTP_FORWARDED_FOR_IP',
'VIA',
'X_FORWARDED_FOR',
'FORWARDED_FOR',
'X_FORWARDED',
'FORWARDED',
'CLIENT_IP',
'FORWARDED_FOR_IP',
'HTTP_PROXY_CONNECTION'
);
$str = "";
foreach ($proxy_headers as $x) {
if (isset($_SERVER[$x])) $str .= "//{$x}:{$_SERVER[$x]}";
}
if ($str != "") {
file_put_contents(
__DIR__ . "/logs/" . UniqueConst::$serverID . "/_{$date2}_ipcheck.txt",
sprintf(
"%s, %s, %s%s\n",
$session->userName,
$session->generalName,
$_SERVER['REMOTE_ADDR'],
$str
),
FILE_APPEND
);
}
}
function updateTraffic()
@@ -1223,10 +1198,9 @@ function updateOnline()
$nationname[$nation['nation']] = $nation['name'];
}
//동접수
$before5Min = TimeUtil::nowAddMinutes(-5);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh > %s AND npc < 2', $before5Min);
$startTurn = cutTurn($gameStor->turntime, $gameStor->turnterm, false);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh >= %s AND npc < 2', $startTurn);
$onlineNum = count($onlineUser);
$onlineNationUsers = Util::arrayGroupBy($onlineUser, 'nation');
@@ -1249,76 +1223,6 @@ function updateOnline()
$gameStor->online_nation = join(', ', $onlineNation);
}
function addAge(RandUtil $rng)
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//나이와 호봉 증가
$db->update('general', [
'age' => $db->sqleval('age+1'),
], true);
$db->update('general', [
'belong' => $db->sqleval('belong+1')
], 'nation != 0');
[$startYear, $year, $month] = $gameStor->getValuesAsArray(['startyear', 'year', 'month']);
if ($year >= $startYear + 3) {
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,aux from general where specage<=age and special=%s', GameConst::$defaultSpecialDomestic) as $general) {
$generalID = $general['no'];
$special = SpecialityHelper::pickSpecialDomestic(
$rng,
$general,
(Json::decode($general['aux'])['prev_types_special']) ?? []
);
$specialClass = buildGeneralSpecialDomesticClass($special);
$specialText = $specialClass->getName();
$db->update('general', [
'special' => $special
], 'no=%i', $generalID);
$logger = new ActionLogger($generalID, $general['nation'], $year, $month);
$josaUl = JosaUtil::pick($specialText, '을');
$logger->pushGeneralActionLog("특기 【<b><L>{$specialText}</></b>】{$josaUl} 익혔습니다!", ActionLogger::PLAIN);
$logger->pushGeneralHistoryLog("특기 【<b><C>{$specialText}</></b>】{$josaUl} 습득");
}
foreach ($db->query('SELECT no,name,nation,leadership,strength,intel,npc,dex1,dex2,dex3,dex4,dex5,aux from general where specage2<=age and special2=%s', GameConst::$defaultSpecialWar) as $general) {
$generalID = $general['no'];
$generalAux = Json::decode($general['aux']);
$updateVars = [];
if (key_exists('inheritSpecificSpecialWar', $generalAux)) {
$special2 = $generalAux['inheritSpecificSpecialWar'];
unset($generalAux['inheritSpecificSpecialWar']);
$updateVars['aux'] = Json::encode($generalAux);
} else {
$special2 = SpecialityHelper::pickSpecialWar(
$rng,
$general,
($generalAux['prev_types_special2']) ?? []
);
}
$specialClass = buildGeneralSpecialWarClass($special2);
$specialText = $specialClass->getName();
$updateVars['special2'] = $special2;
$db->update('general', $updateVars, 'no=%i', $general['no']);
$logger = new ActionLogger($generalID, $general['nation'], $year, $month);
$josaUl = JosaUtil::pick($specialText, '을');
$logger->pushGeneralActionLog("특기 【<b><L>{$specialText}</></b>】{$josaUl} 익혔습니다!", ActionLogger::PLAIN);
$logger->pushGeneralHistoryLog("특기 【<b><C>{$specialText}</></b>】{$josaUl} 습득");
}
}
}
function turnDate($curtime)
{
$db = DB::db();
@@ -1745,7 +1649,8 @@ function tryUniqueItemLottery(RandUtil $rng, General $general, string $acquireTy
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
}
$prob = Util::valueFit($prob, null, 1 / 4); //최대치 감소
$prob *= GameConst::$uniqueTrialCoef;
$prob = Util::valueFit($prob, null, GameConst::$maxUniqueTrialProb); //최대치 감소
$result = false;
$prob /= sqrt(7);
@@ -1805,16 +1710,16 @@ function deleteNation(General $lord, bool $applyDB): array
$nationID,
$lordID
),
['npc', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
['npc', 'owner', 'gold', 'rice', 'experience', 'explevel', 'dedication', 'dedlevel', 'belong', 'aux'],
1
);
$nationGeneralList[$lordID] = $lord;
$nation['generals'] = array_keys($nationGeneralList);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['aux'] += $nationStor->max_power ?? [];
$nation['history'] = getNationHistoryLogAll($nationID);
$josaYi = JosaUtil::pick($nationName, '이');
@@ -1823,13 +1728,16 @@ function deleteNation(General $lord, bool $applyDB): array
// 전 장수 재야로
foreach ($nationGeneralList as $general) {
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
if($general->getNPCType() < 2){
$general->setAuxVar(
InheritanceKey::max_belong->value,
max(
$general->getVar('belong'),
$general->getAuxVar(InheritanceKey::max_belong->value) ?? 0
)
);
}
$general->setVar('belong', 0);
$general->setVar('troop', 0);
$general->setVar('officer_level', 0);
+2 -2
View File
@@ -18,7 +18,7 @@ function registerAuction(RandUtil $rng)
[AuctionType::BuyRice->value, AuctionType::SellRice->value],
));
$neutralbuyRiceCnt = $neutralAuctionCnt[AuctionType::BuyRice->value];
$neutralbuyRiceCnt = $neutralAuctionCnt[AuctionType::BuyRice->value] ?? 0;
// 판매건 등록
if ($rng->nextBool(1 / ($neutralbuyRiceCnt + 5))) {
@@ -38,7 +38,7 @@ function registerAuction(RandUtil $rng)
AuctionBuyRice::openResourceAuction($dummyGeneral, $amount, $term, $cost, $topv);
}
$neutralSellRiceCnt = $neutralAuctionCnt[AuctionType::SellRice->value];
$neutralSellRiceCnt = $neutralAuctionCnt[AuctionType::SellRice->value] ?? 0;
// 구매건 등록
if ($rng->nextBool(1 / ($neutralSellRiceCnt + 5))) {
//평균 쌀의 5% ~ 25%
+37
View File
@@ -326,6 +326,41 @@ function buildGeneralSpecialWarClass(?string $type):BaseSpecial{
return $obj;
}
function getActionCrewTypeClass(?string $type){
if($type === null || $type === ''){
$type = 'None';
}
static $basePath = __NAMESPACE__.'\\ActionCrewType\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
$classPath = ($basePath.'che_'.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 올바른 병종 효과가 아님");
}
function buildActionCrewTypeClass(?string $type):iAction{
static $cache = [];
if($type === null){
$type = 'None';
}
if(key_exists($type, $cache)){
return $cache[$type];
}
$class = getActionCrewTypeClass($type);
$obj = new $class();
$cache[$type]= $obj;
return $obj;
}
function getGeneralCommandClass(?string $type){
if($type === null || $type === ''){
$type = '휴식';
@@ -542,6 +577,8 @@ function getExpLevel($experience) {
$level = Util::toInt(sqrt($experience/10));
}
$level = Util::clamp($level, 0, GameConst::$maxLevel);
return $level;
}
+21 -332
View File
@@ -2,6 +2,9 @@
namespace sammo;
use sammo\DTO\AuctionInfo;
use sammo\Enums\AuctionType;
use sammo\Enums\EventTarget;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
@@ -182,27 +185,6 @@ function updateGeneralNumber()
refreshNationStaticInfo();
}
function updateYearly()
{
//통계
checkStatistic();
}
//관직 변경 해제
function updateQuaterly()
{
$db = DB::db();
//천도 제한 해제, 관직 변경 제한 해제
$db->update('nation', [
'chief_set' => 0,
], true);
//관직 변경 제한 해제
$db->update('city', [
'officer_set' => 0,
], true);
}
// 벌점 감소와 건국제한-1 전턴제한-1 외교제한-1, 1달마다 실행, 병사 있는 장수의 군량 감소, 수입비율 조정
function preUpdateMonthly()
{
@@ -218,58 +200,6 @@ function preUpdateMonthly()
$admin = $gameStor->getValues(['startyear', 'year', 'month']);
$logger = new ActionLogger(0, 0, $admin['year'], $admin['month']);
//보급선 체크
checkSupply();
//미보급도시 10% 감소
$db->update('city', [
'pop' => $db->sqleval('pop * 0.9'),
'trust' => $db->sqleval('trust * 0.9'),
'agri' => $db->sqleval('agri * 0.9'),
'comm' => $db->sqleval('comm * 0.9'),
'secu' => $db->sqleval('secu * 0.9'),
'def' => $db->sqleval('def * 0.9'),
'wall' => $db->sqleval('wall * 0.9'),
], 'supply = 0');
//미보급도시 장수 병 훈 사 5%감소
//NOTE: update inner join도 가능하지만, meekrodb 기준으로 깔끔하게.
$unsuppliedCities = $db->query('SELECT city, nation, trust, name FROM city WHERE supply = 0');
foreach (Util::arrayGroupBy($unsuppliedCities, 'nation') as $nationID => $cityList) {
$cityIDList = Util::squeezeFromArray($cityList, 'city');
$db->update('general', [
'crew' => $db->sqleval('crew*0.95'),
'atmos' => $db->sqleval('atmos*0.95'),
'train' => $db->sqleval('train*0.95'),
], 'city IN %li AND nation = %i', $cityIDList, $nationID);
}
//민심30이하 공백지 처리
$lostCities = [];
foreach ($unsuppliedCities as $unsuppliedCity) {
if ($unsuppliedCity['trust'] >= 30) {
continue;
}
$lostCities[$unsuppliedCity['city']] = $unsuppliedCity;
}
if ($lostCities) {
foreach ($lostCities as $lostCity) {
$josaYi = JosaUtil::pick($lostCity['name'], '이');
$logger->pushGlobalHistoryLog("<R><b>【고립】</b></><G><b>{$lostCity['name']}</b></>{$josaYi} 보급이 끊겨 <R>미지배</> 도시가 되었습니다.");
}
$db->update('general', [
'officer_level' => 1,
'officer_city' => 0
], 'officer_city IN %li', array_keys($lostCities));
$db->update('city', [
'nation' => 0,
'officer_set' => 0,
'conflict' => '{}',
'term' => 0,
'front' => 0
], 'city IN %li', array_keys($lostCities));
}
//접률감소, 건국제한-1
$db->update('general', [
@@ -283,18 +213,10 @@ function preUpdateMonthly()
'rate_tmp' => $db->sqleval('rate')
], true);
//도시훈사 180년 60, 220년 87, 240년 100
$rate = Util::round(($admin['year'] - $admin['startyear']) / 1.5) + 60;
if ($rate > 100) $rate = 100;
// 20 ~ 140원
$develcost = ($admin['year'] - $admin['startyear'] + 10) * 2;
$gameStor->city_rate = $rate;
$gameStor->develcost = $develcost;
//매달 사망자 수입 결산
processWarIncome();
//계략, 전쟁표시 해제
$db->update('city', [
'state' => $db->sqleval(<<<EOD
@@ -501,8 +423,6 @@ function postUpdateMonthly(RandUtil $rng)
if ($admin['year'] >= $admin['startyear'] + 2) {
checkWander($rng);
}
// 작위 업데이트
updateNationState();
updateGeneralNumber();
refreshNationStaticInfo();
// 천통여부 검사
@@ -526,7 +446,7 @@ function checkWander(RandUtil $rng)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['year', 'month']);
$admin = $gameStor->getValues(['year', 'month', 'init_year', 'init_month']);
$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');
@@ -545,248 +465,6 @@ function checkWander(RandUtil $rng)
}
}
function updateNationState()
{
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$history = array();
$admin = $gameStor->getValues(['killturn', 'year', 'month', 'fiction', 'startyear', 'show_img_level', 'turnterm', 'turntime']);
$year = $admin['year'];
$month = $admin['month'];
$startYear = $admin['startyear'];
$assemblerCnts = [];
foreach ($db->queryAllLists('SELECT nation,count(no) FROM general WHERE npc = 5 GROUP BY nation') as [$nationID, $assemblerCnt]) {
$assemblerCnts[$nationID] = $assemblerCnt;
};
foreach ($db->query('SELECT nation,name,level,tech,aux FROM nation') as $nation) {
//TODO: level이 진관수이소중대특 체계를 벗어날 수 있음
$nationID = $nation['nation'];
$citycount = $db->queryFirstField('SELECT count(*) FROM city WHERE nation=%i AND level>=4', $nationID);
if ($citycount == 0) {
$nationlevel = 0; // 방랑군
} elseif ($citycount == 1) {
$nationlevel = 1; // 호족
} elseif ($citycount <= 4) {
$nationlevel = 2; // 군벌
} elseif ($citycount <= 7) {
$nationlevel = 3; // 주자사
} elseif ($citycount <= 10) {
$nationlevel = 4; // 주목
} elseif ($citycount <= 15) {
$nationlevel = 5; // 공
} elseif ($citycount <= 20) {
$nationlevel = 6; // 왕
} else {
$nationlevel = 7; // 황제
}
if ($nationlevel > $nation['level']) {
$levelDiff = $nationlevel - $nation['level'];
$oldLevel = $nation['level'];
$nation['level'] = $nationlevel;
$updateVals = [
'level' => $nationlevel,
'gold' => $db->sqleval('gold + %i', $nationlevel * 1000),
'rice' => $db->sqleval('rice + %i', $nationlevel * 1000),
];
switch ($nationlevel) {
case 7:
$josaUl = JosaUtil::pick(getNationLevel($nationlevel), '을');
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>{$josaUl} 자칭"]);
$auxVal = Json::decode($nation['aux']);
$auxVal['can_국기변경'] = 1;
$auxVal['can_국호변경'] = 1;
$updateVals['aux'] = Json::encode($auxVal);
break;
case 6:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극하였습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 등극"]);
break;
case 5:
case 4:
case 3:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명되었습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>에 임명됨"]);
break;
case 2:
$history[] = "<C>●</>{$year}{$month}월:<Y><b>【작위】</b></><D><b>{$nation['name']}</b></>의 군주가 독립하여 <Y>" . getNationLevel($nationlevel) . "</>로 나섰습니다.";
pushNationHistoryLog($nation['nation'], ["<C>●</>{$year}{$month}월:<D><b>{$nation['name']}</b></>의 군주가 <Y>" . getNationLevel($nationlevel) . "</>로 나서다"]);
break;
}
$db->update('nation', $updateVals, 'nation=%i', $nation['nation']);
$turnRows = [];
foreach (Util::range(getNationChiefLevel($nation['level']), 12) as $chiefLevel) {
foreach (Util::range(GameConst::$maxChiefTurn) as $turnIdx) {
$turnRows[] = [
'nation_id' => $nation['nation'],
'officer_level' => $chiefLevel,
'turn_idx' => $turnIdx,
'action' => '휴식',
'arg' => null,
'brief' => '휴식'
];
}
}
$db->insertIgnore('nation_turn', $turnRows);
if ($levelDiff) {
//유니크 아이템 하나 돌리자
$targetKillTurn = $admin['killturn'];
$targetKillTurn -= 24 * 60 / $admin['turnterm'];
$nationGenIDList = $db->queryFirstColumn(
'SELECT no FROM general WHERE nation = %i AND killturn >= %i AND npc < 2',
$nation['nation'],
$targetKillTurn
);
$nationGenList = General::createGeneralObjListFromDB($nationGenIDList, ['belong', 'npc', 'aux'], 2);
$chiefID = null;
$uniqueLotteryWeightList = [];
$relYear = $year - $startYear;
$maxTrialCountByYear = 1;
foreach (GameConst::$maxUniqueItemLimit as $tmpVals) {
[$targetYear, $targetTrialCnt] = $tmpVals;
if ($relYear < $targetYear) {
break;
}
$maxTrialCountByYear = $targetTrialCnt;
}
foreach ($nationGenList as $nationGen) {
if ($nationGen->getVar('officer_level') == 12) {
$chiefID = $nationGen->getID();
}
$trialCnt = min($maxTrialCountByYear, count(GameConst::$allItems));
foreach ($nationGen->getItems() as $item) {
if (!$item->isBuyable()) {
$trialCnt -= 1;
}
}
if ($trialCnt <= 0) {
continue;
}
$score = $nationGen->getVar('belong') + 10;
if ($nationGen->getVar('officer_level') == 12) {
$score += 60;
} else if ($nationGen->getVar('officer_level') == 11) {
$score += 30;
} else if ($nationGen->getVar('officer_level') > 4) {
$score += 15;
}
$score *= 2 ** $trialCnt;
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
}
$nationLevelUpRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'nationLevelUp',
$year,
$month,
$nationID
)));
foreach (Util::range($levelDiff) as $idx) {
if (!$uniqueLotteryWeightList) {
break;
}
/** @var General */
$winnerObj = $nationLevelUpRNG->choiceUsingWeightPair($uniqueLotteryWeightList);
unset($uniqueLotteryWeightList[$winnerObj->getID()]);
$givenUniqueRNG = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'givenUnique',
$year,
$month,
$nationID,
$winnerObj->getID(),
)));
giveRandomUniqueItem($givenUniqueRNG, $winnerObj, '작위보상');
$winnerObj->applyDB($db);
}
if ($chiefID) {
$chiefObj = General::createGeneralObjFromDB($chiefID, ['belong', 'npc', 'aux'], 2);
$chiefObj->increaseInheritancePoint(InheritanceKey::unifier, 250 * $levelDiff);
$chiefObj->applyDB($db);
}
}
}
$assemblerCnt = $assemblerCnts[$nation['nation']] ?? 0;
$maxAssemblerCnt = [
1 => 0,
2 => 1,
3 => 3,
4 => 4,
5 => 6,
6 => 7,
7 => 9
][$nationlevel] ?? 0;
if ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID = $gameStor->assembler_id ?? 0;
$troopLeaderRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
UniqueConst::$hiddenSeed,
'troopLeader',
$year,
$month,
$nationID
)));
while ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID += 1;
$npcObj = new Scenario\GeneralBuilder(
$troopLeaderRng,
sprintf('부대장%4d', $lastAssemblerID),
false,
null,
$nation['nation']
);
$npcObj->setAffinity(999)->setStat(10, 10, 10)
->setSpecialSingle('척사')->setEgo('che_은둔')
->setKillturn(70)->setGoldRice(0, 0)
->setNPCType(5)->fillRemainSpecAsZero($admin);
$npcObj->build($admin);
$npcID = $npcObj->getGeneralID();
$db->insert('troop', [
'troop_leader' => $npcID,
'name' => $npcObj->getGeneralName(),
'nation' => $nation['nation'],
]);
$db->update('general', [
'troop' => $npcID
], 'no=%i', $npcID);
$cmd = buildGeneralCommandClass('che_집합', General::createGeneralObjFromDB($npcID), $admin);
_setGeneralCommand($cmd, iterator_to_array(Util::range(GameConst::$maxTurn)));
$assemblerCnt += 1;
$gameStor->assembler_id = $lastAssemblerID;
}
}
}
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
}
function checkStatistic()
{
$db = DB::db();
@@ -1053,6 +731,16 @@ function checkEmperior()
$nationLogger = new ActionLogger(0, $nationID, $admin['year'], $admin['month']);
$nationLogger->pushNationalHistoryLog("<D><b>{$nationName}</b></>{$josaYi} 전토를 통일");
/** @var int[] */
$auctionList = $db->queryFirstColumn(
'SELECT `id` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0 ORDER BY `close_date` ASC',
AuctionType::UniqueItem->value
);
foreach($auctionList as $auctionID){
$auction = new AuctionUniqueItem($auctionID, new DummyGeneral(true));
$auction->closeAuction(true);
}
$inheritPointManager = InheritancePointManager::getInstance();
$allUserGenerals = General::createGeneralObjListFromDB($db->queryFirstColumn('SELECT `no` FROM general WHERE npc < 2'));
foreach ($allUserGenerals as $genObj) {
@@ -1062,11 +750,12 @@ function checkEmperior()
};
}
}
processSumInheritPointRank();
TurnExecutionHelper::runEventHandler($db, $gameStor, EventTarget::United);
foreach ($allUserGenerals as $genObj) {
$inheritPointManager->mergeTotalInheritancePoint($genObj, true);
$inheritPointManager->mergeTotalInheritancePoint($genObj);
$inheritPointManager->applyInheritanceUser($genObj->getVar('owner'));
$inheritPointManager->clearInheritancePoint($genObj);
}
$gameStor->isunited = 2;
@@ -1135,9 +824,9 @@ function checkEmperior()
$nation = $nation;
$nation['generals'] = $db->queryFirstColumn('SELECT `no` FROM general WHERE nation=%i', $nation['nation']);
$nation['aux'] = Json::decode($nation['aux']);
$nation['msg'] = $nationStor->notice;
$nation['msg'] = $nationStor->nationNotice['msg'] ?? '';;
$nation['scout_msg'] = $nationStor->scout_msg;
$nation['aux'] += $nationStor->max_power;
$nation['aux'] += $nationStor->max_power ?? [];
$nation['history'] = getNationHistoryLogAll($nation['nation']);
storeOldGenerals(0, $admin['year'], $admin['month']);
@@ -1214,7 +903,7 @@ function checkEmperior()
]);
$hiddenSeed = UniqueConst::$hiddenSeed;
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다. <span class='hidden_but_copyable'>(서버시드: $hiddenSeed})</span>"];
$history = ["<C>●</>{$admin['year']}{$admin['month']}월:<Y><b>【통일】</b></><D><b>{$nation['name']}</b></>{$josaYi} 전토를 통일하였습니다. <span class='hidden_but_copyable'>(서버시드: {$hiddenSeed})</span>"];
pushGlobalHistoryLog($history, $admin['year'], $admin['month']);
//연감 월결산
+10
View File
@@ -254,6 +254,7 @@ function pushGeneralHistoryLog(int $generalID, ?array $history, $year=null, $mon
}
/** @deprecated */
function getGeneralHistoryLogAll(int $generalID):array {
$db = DB::db();
@@ -263,6 +264,15 @@ function getGeneralHistoryLogAll(int $generalID):array {
);
}
function getGeneralHistoryLogWithLogID(int $generalID):array {
$db = DB::db();
return Util::convertPairArrayToDict($db->queryAllLists(
'SELECT `id`, `text` from general_record WHERE general_id = %i AND log_type = "history" order by id desc',
$generalID
));
}
function pushNationHistoryLog(int $nationID, ?array $history, ?int $year=null, ?int $month=null) {
if(!$history){
+6
View File
@@ -12,6 +12,7 @@ function printLimitMsg($turntime)
<head>
<title>접속제한</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
@@ -118,6 +119,11 @@ function backButton()
return "<button type='button' class='btn btn-primary back_btn' onclick=location.replace('./')>돌아가기</button><br>";
}
function gatewayButton()
{
return "<button type='button' class='btn btn-primary back_btn' onclick=location.replace('../')>돌아가기</button><br>";
}
function CoreBackButton()
{
return "<button type='button' class='btn btn-primary back_btn' onclick=location.replace('v_chiefCenter.php')>돌아가기</button><br>";
+1
View File
@@ -25,6 +25,7 @@ function requireAdminPermissionHTML()
<head>
<title>관리메뉴</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=1024" />
<?= WebUtil::printCSS('../d_shared/common.css') ?>
+16 -281
View File
@@ -4,173 +4,32 @@ namespace sammo;
use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn;
use Ds\Map;
use sammo\Enums\ResourceType;
use sammo\Event\Action;
/**
* 시간 단위로 일어나는 이벤트들에 대한 함수 모음
*/
/** @deprecated */
function processSumInheritPointRank(){
$db = DB::db();
$generals = General::createGeneralObjListFromDB(null, null, 2);
$points = new Map();
$points->allocate(count($generals));
foreach($generals as $general){
$generalID = $general->getID();
$points[$generalID] = 0;
}
foreach(InheritanceKey::cases() as $key){
if($key === InheritanceKey::previous){
continue;
}
$subPoints = InheritancePointManager::getInstance()->getInheritancePointFromAll($generals, $key);
foreach($generals as $general){
$generalID = $general->getID();
$points[$generalID] += $subPoints[$generalID] ?? 0;
}
}
$pointsPairs = [];
foreach($points as $generalID => $point){
$pointsPairs[] = [
'nation_id' => $generals[$generalID]->getNationID(),
'general_id' => $generalID,
'type' => RankColumn::inherit_point_earned_by_merge->value,
'value' => $point,
];
}
//XXX: multiple batch update가 제공되지 않으므로..
$db->delete('rank_data', '`type` = %s', RankColumn::inherit_point_earned_by_merge->value);
$db->insert('rank_data', $pointsPairs);
$db->query(
'UPDATE `rank_data` D SET `value` = (SELECT SUM(`value`) FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` IN %ls) WHERE D.`type` = %s',
[RankColumn::inherit_point_earned_by_action->value, RankColumn::inherit_point_earned_by_merge->value],
RankColumn::inherit_point_earned->value
);
$db->query(
'UPDATE `rank_data` D SET `value` = (SELECT `value` FROM `rank_data` S WHERE S.general_id = D.general_id AND S.`type` = %s) WHERE D.`type` = %s',
RankColumn::inherit_point_spent_dynamic->value,
RankColumn::inherit_point_spent->value
);
}
//1월마다 실행
function processSpring() {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
// 1월엔 무조건 내정 1% 감소
$db->update('city',[
'dead'=>0,
'agri'=>$db->sqleval('agri * 0.99'),
'comm'=>$db->sqleval('comm * 0.99'),
'secu'=>$db->sqleval('secu * 0.99'),
'def'=>$db->sqleval('def * 0.99'),
'wall'=>$db->sqleval('wall * 0.99'),
],true);
//인구 증가
popIncrease();
// > 10000 유지비 3%, > 1000 유지비 1%
// 유지비 1%
$db->update('general', [
'gold'=>$db->sqleval('IF(gold > 10000, gold * 0.97, gold * 0.99)')
], 'gold > 1000');
// > 100000 유지비 5%, > 100000 유지비 3%, > 1000 유지비 1%
$db->update('nation', [
'gold'=>$db->sqleval('IF(gold > 100000, gold * 0.95, IF(gold > 10000, gold * 0.97, gold * 0.99))')
], 'gold > 1000');
$admin = $gameStor->getValues(['year', 'month']);
pushGlobalHistoryLog(["<R>★</>{$admin['year']}{$admin['month']}월: <S>모두들 즐거운 게임 하고 계신가요? ^^ <Y>매너 있는 플레이</> 부탁드리고, <M>지나친 훼접</>은 삼가주세요~</>"], $admin['year'], $admin['month']);
$e_env = $gameStor->getValues(['startyear', 'year', 'month']);
$e_env['currentEventID'] = 0;
Action::build(["ProcessIncome", ResourceType::rice->value])->run($e_env);
}
/** @deprecated */
function processGoldIncome() {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
$adminLog = [];
$nationList = $db->query('SELECT name,nation,capital,gold,level,rate_tmp,bill,type from nation');
$cityListByNation = Util::arrayGroupBy($db->query('SELECT * FROM city'), 'nation');
$generalRawListByNation = Util::arrayGroupBy($db->query('SELECT no,name,nation,gold,officer_level,dedication,city FROM general WHERE npc != 5'), 'nation');
//국가별 처리
foreach($nationList as $nation) {
$nationID = $nation['nation'];
$generalRawList = $generalRawListByNation[$nationID];
$income = getGoldIncome($nationID, $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID]??[]);
$originoutcome = getOutcome(100, $generalRawList);
$outcome= Util::round($nation['bill'] / 100 * $originoutcome);
// 실제 지급량 계산
$nation['gold'] += $income;
// 기본량도 안될경우
if($nation['gold'] < GameConst::$basegold) {
$realoutcome = 0;
// 실지급률
$ratio = 0;
//기본량은 넘지만 요구량이 안될경우
} elseif($nation['gold'] - GameConst::$basegold < $outcome) {
$realoutcome = $nation['gold'] - GameConst::$basegold;
$nation['gold'] = GameConst::$basegold;
// 실지급률
$ratio = $realoutcome / $originoutcome;
} else {
$realoutcome = $outcome;
$nation['gold'] -= $realoutcome;
// 실지급률
$ratio = $realoutcome / $originoutcome;
}
$nation['gold'] = Util::valueFit($nation['gold'], GameConst::$basegold);
$adminLog[] = StringUtil::padStringAlignRight((string)$nation['name'],12," ")
." // 세금 : ".StringUtil::padStringAlignRight((string)$income,6," ")
." // 세출 : ".StringUtil::padStringAlignRight((string)$originoutcome,6," ")
." // 실제 : ".tab2((string)$realoutcome,6," ")
." // 지급률 : ".tab2((string)round($ratio*100,2),5," ")
." % // 결과금 : ".tab2((string)$nation['gold'],6," ");
$incomeText = number_format($income);
$incomeLog = "이번 수입은 금 <C>$incomeText</>입니다.";
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->prev_income_gold = $income;
$db->update('nation', [
'gold'=>$nation['gold']
], 'nation=%i', $nationID);
// 각 장수들에게 지급
foreach ($generalRawList as $rawGeneral) {
$generalObj = new General($rawGeneral, null, null, null, $year, $month, false);
$gold = Util::round(getBill($generalObj->getVar('dedication'))*$ratio);
$generalObj->increaseVar('gold', $gold);
$logger = $generalObj->getLogger();
if($generalObj->getVar('officer_level') > 4){
$logger->pushGeneralActionLog($incomeLog, $logger::PLAIN);
}
$goldText = number_format($gold);
$logger->pushGeneralActionLog("봉급으로 금 <C>$goldText</>을 받았습니다.", $logger::PLAIN);
$generalObj->applyDB($db);
}
}
$logger = new ActionLogger(0, 0, $year, $month);
$logger->pushGlobalHistoryLog('<W><b>【지급】</b></>봄이 되어 봉록에 따라 자금이 지급됩니다.');
$logger->flush();
pushAdminLog($adminLog);
$e_env = $gameStor->getValues(['startyear', 'year', 'month']);
$e_env['currentEventID'] = 0;
Action::build(["ProcessIncome", ResourceType::gold->value])->run($e_env);
}
function popIncrease() {
@@ -304,29 +163,6 @@ function getGoldIncome(int $nationID, int $nationLevel, float $taxRate, int $cap
return $cityIncome;
}
function processWarIncome() {
$db = DB::db();
$cityListByNation = Util::arrayGroupBy($db->query('SELECT * FROM city'), 'nation');
foreach(getAllNationStaticInfo() as $nation){
if($nation['level'] <= 0){
continue;
}
$nationID = $nation['nation'];
$income = getWarGoldIncome($nation['type'], $cityListByNation[$nationID]??[]);
$db->update('nation', [
'gold'=>$db->sqleval('gold + %i', $income)
], 'nation=%i', $nationID);
}
// 10%수입, 20%부상병
$db->update('city', [
'pop'=>$db->sqleval('pop + dead * %d', 0.2),
'dead'=>0
], true);
}
function getWarGoldIncome(string $nationType, array $cityList){
$nationTypeObj = buildNationTypeClass($nationType);
@@ -338,115 +174,14 @@ function getWarGoldIncome(string $nationType, array $cityList){
return $cityIncome;
}
//7월마다 실행
function processFall() {
$db = DB::db();
// 7월엔 무조건 내정 1% 감소
$db->update('city',[
'dead'=>0,
'agri'=>$db->sqleval('agri * 0.99'),
'comm'=>$db->sqleval('comm * 0.99'),
'secu'=>$db->sqleval('secu * 0.99'),
'def'=>$db->sqleval('def * 0.99'),
'wall'=>$db->sqleval('wall * 0.99'),
],true);
//인구 증가
popIncrease();
// > 10000 유지비 3%, > 1000 유지비 1%
// 유지비 1%
$db->update('general', [
'rice'=>$db->sqleval('IF(rice > 10000, rice * 0.97, rice * 0.99)')
], 'rice > 1000');
// > 100000 유지비 5%, > 100000 유지비 3%, > 1000 유지비 1%
$db->update('nation', [
'rice'=>$db->sqleval('IF(rice > 100000, rice * 0.95, IF(rice > 10000, rice * 0.97, rice * 0.99))')
], 'rice > 1000');
}
/** @deprecated */
function processRiceIncome() {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
$adminLog = [];
$nationList = $db->query('SELECT name,level,nation,capital,rice,rate_tmp,bill,type from nation');
$cityListByNation = Util::arrayGroupBy($db->query('SELECT * FROM city'), 'nation');
$generalRawListByNation = Util::arrayGroupBy($db->query('SELECT no,name,nation,rice,officer_level,dedication,city FROM general WHERE npc != 5'), 'nation');
//국가별 처리
foreach($nationList as $nation) {
$nationID = $nation['nation'];
$generalRawList = $generalRawListByNation[$nationID];
$income = getRiceIncome($nation['nation'], $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID]??[]);
$income += getWallIncome($nation['nation'], $nation['level'], $nation['rate_tmp'], $nation['capital'], $nation['type'], $cityListByNation[$nationID]??[]);
$originoutcome = getOutcome(100, $generalRawList);
$outcome= Util::round($nation['bill'] / 100 * $originoutcome);
// 실제 지급량 계산
$nation['rice'] += $income;
// 기본량도 안될경우
if($nation['rice'] < GameConst::$baserice) {
$realoutcome = 0;
// 실지급률
$ratio = 0;
//기본량은 넘지만 요구량이 안될경우
} elseif($nation['rice'] - GameConst::$baserice < $outcome) {
$realoutcome = $nation['rice'] - GameConst::$baserice;
$nation['rice'] = GameConst::$baserice;
// 실지급률
$ratio = $realoutcome / $originoutcome;
} else {
$realoutcome = $outcome;
$nation['rice'] -= $realoutcome;
// 실지급률
$ratio = $realoutcome / $originoutcome;
}
$nation['rice'] = Util::valueFit($nation['rice'], GameConst::$baserice);
$adminLog[] = StringUtil::padStringAlignRight($nation['name'],12," ")
." // 세곡 : ".StringUtil::padStringAlignRight((string)$income,6," ")
." // 세출 : ".StringUtil::padStringAlignRight((string)$originoutcome,6," ")
." // 실제 : ".tab2((string)$realoutcome,6," ")
." // 지급률 : ".tab2((string)round($ratio*100,2),5," ")
." % // 결과곡 : ".tab2((string)$nation['rice'],6," ");
$incomeText = number_format($income);
$incomeLog = "이번 수입은 쌀 <C>$incomeText</>입니다.";
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
$nationStor->prev_income_rice = $income;
$db->update('nation', [
'rice'=>$nation['rice']
], 'nation=%i', $nationID);
// 각 장수들에게 지급
foreach ($generalRawList as $rawGeneral) {
$generalObj = new General($rawGeneral, null, null, null, $year, $month, false);
$rice = Util::round(getBill($generalObj->getVar('dedication'))*$ratio);
$generalObj->increaseVar('rice', $rice);
$logger = $generalObj->getLogger();
if($generalObj->getVar('officer_level') > 4){
$logger->pushGeneralActionLog($incomeLog, $logger::PLAIN);
}
$riceText = number_format($rice);
$logger->pushGeneralActionLog("봉급으로 쌀 <C>$riceText</>을 받았습니다.", $logger::PLAIN);
$generalObj->applyDB($db);
}
}
$logger = new ActionLogger(0, 0, $year, $month);
$logger->pushGlobalHistoryLog('<W><b>【지급】</b></>가을이 되어 봉록에 따라 군량이 지급됩니다.');
$logger->flush();
pushAdminLog($adminLog);
$e_env = $gameStor->getValues(['startyear', 'year', 'month']);
$e_env['currentEventID'] = 0;
Action::build(["ProcessIncome", ResourceType::rice->value])->run($e_env);
}
function getRiceIncome(int $nationID, int $nationLevel, float $taxRate, int $capitalID, string $nationType, ?array $cityList) {
+21 -429
View File
@@ -2,452 +2,44 @@
namespace sammo;
use sammo\DTO\VoteInfo;
include "lib.php";
include "func.php";
Session::requireLogin()->loginGame()->setReadOnly();
$session = Session::requireLogin()->loginGame()->setReadOnly();
$userID = Session::getUserID();
$mapName = GameConst::$mapName;
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,con,turntime,newmsg,newvote,`officer_level` from general 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'));
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
$generalObj = General::createGeneralObjFromDB($me['no']);
$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') ?>
<title><?= UniqueConst::$serverName ?>: 메인</title>
<?= 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,
'commandList' => getCommandTable($generalObj),
'serverNow' => TimeUtil::now(false),
'lastExecuted' => $gameStor->turntime,
'isLocked' => $plock,
'isTournamentActive' => $isTournamentActive,
'isBettingActive' => $isBettingActive,
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
'serverName' => UniqueConst::$serverName,
'serverNick' => DB::prefix(),
'serverID' => UniqueConst::$serverID,
'mapName' => GameConst::$mapName,
'unitSet' => GameConst::$unitSet,
'maxTurn' => GameConst::$maxTurn,
'maxPushTurn' => 12,
'serverNow' => TimeUtil::now(false),
]
]) ?>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
], false) ?>
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printJS("js/map/theme_{$mapName}.js") ?>
<?= WebUtil::printCSS('../d_shared/common.css') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" />
<?= WebUtil::printDist('vue', 'v_front', true) ?>
</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-md-4" style="color:<?= $color ?>;">
<?= $scenario ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
NPC 수, 상성 : <?= $extend ?>,<?= $fiction ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
NPC선택 : <?= $npcmode ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
토너먼트 : <?= getTournamentTermText($gameStor->turnterm) ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
기타 설정: <?= $otherTextInfo ?>
</div>
<div class="s-border-t col py-2 col-8 col-md-4"><?= info(2) ?></div>
<div class="s-border-t col py-2 col-4 col-md-2">전체 접속자 수 : <?= $gameStor->online_user_cnt ?> 명</div>
<div class="s-border-t col py-2 col-4 col-md-2">턴당 갱신횟수 : <?= $gameStor->conlimit ?>회</div>
<div class="s-border-t col py-2 col-8 col-md-4"><?= info(3) ?></div>
<div class="s-border-t py-2 col col-6 col-md-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-md-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-md-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-md-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-md-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-md-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-md-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-md-8 d-grid">
<input type="text" id="msg_input" maxlength="99" class="form-control">
</div>
<div id="msg_submit-col" class="col-6 col-md-2 d-grid"><button id="msg_submit" class="btn btn-primary">서신전달&amp;갱신</button></div>
</div>
<div class="col-md-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-md-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-md-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-md-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 ($con == 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-md-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>
<div id="app"></div>
</body>
</html>
+13 -10
View File
@@ -28,10 +28,12 @@ if ($session->userGrade < 5 && !$allowReset) {
<head>
<title>설치</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=device-width, initial-scale=1" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
<?= WebUtil::printCSS('css/install.css') ?>
<?= WebUtil::printDist('vue', [], true) ?>
<?= WebUtil::printDist('ts', ['common', 'install']) ?>
</head>
@@ -92,8 +94,8 @@ if ($session->userGrade < 5 && !$allowReset) {
<label for="fiction" class="col-sm-3 col-form-label">NPC 상성</label>
<div class="col-sm-9">
<div id="fiction" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0" checked><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1"><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
<input type="radio" id="fiction_0" class="btn-check" name="fiction" value="0"><label for="fiction_0" class="btn btn-secondary"> 연의 </label>
<input type="radio" id="fiction_1" class="btn-check" name="fiction" value="1" checked><label for="fiction_1" class="btn btn-secondary"> 가상 </label>
</div>
</div>
</div>
@@ -113,6 +115,7 @@ if ($session->userGrade < 5 && !$allowReset) {
<div class="col-sm-9">
<div id="block_general_create" class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="radio" class="btn-check" id="block_general_create_0" name="block_general_create" value="0" checked><label for="block_general_create_0" class="btn btn-secondary">가능</label>
<input type="radio" class="btn-check" id="block_general_create_2" name="block_general_create" value="2"><label for="block_general_create_2" class="btn btn-secondary">장수명무작위</label>
<input type="radio" class="btn-check" id="block_general_create_1" name="block_general_create" value="1"><label for="block_general_create_1" class="btn btn-secondary">불가</label>
</div>
</div>
@@ -134,13 +137,13 @@ if ($session->userGrade < 5 && !$allowReset) {
<div class="col-sm-9">
<div class="input-group">
<div class="btn-group btn-group-toggle" data-bs-toggle="buttons">
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop"><label class="btn btn-secondary" for="autorun_develop">내정</label>
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp"><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit"><label class="btn btn-secondary" for="autorun_recruit">징병</label>
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high"><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train"><label class="btn btn-secondary" for="autorun_train">훈사</label>
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle"><label class="btn btn-secondary" for="autorun_battle">출병</label>
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief"><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
<input type="checkbox" id="autorun_develop" class="autorun_user_chk btn-check" data-key="develop" name="autorun_user[]" value="develop" checked><label class="btn btn-secondary" for="autorun_develop">내정</label>
<input type="checkbox" id="autorun_warp" class="autorun_user_chk btn-check" data-key="warp" name="autorun_user[]" value="warp" checked><label class="btn btn-secondary" for="autorun_warp">순간이동</label>
<input type="checkbox" id="autorun_recruit" class="autorun_user_chk btn-check" data-key="recruit" name="autorun_user[]" value="recruit" checked><label class="btn btn-secondary" for="autorun_recruit">징병</label>
<input type="checkbox" id="autorun_recruit_high" class="autorun_user_chk btn-check" data-key="recruit_high" name="autorun_user[]" value="recruit_high" checked><label class="btn btn-secondary" for="autorun_recruit_high">모병</label>
<input type="checkbox" id="autorun_train" class="autorun_user_chk btn-check" data-key="train" name="autorun_user[]" value="train" checked><label class="btn btn-secondary" for="autorun_train">훈사</label>
<input type="checkbox" id="autorun_battle" class="autorun_user_chk btn-check" data-key="battle" name="autorun_user[]" value="battle" checked><label class="btn btn-secondary" for="autorun_battle">출병</label>
<input type="checkbox" id="autorun_chief" class="autorun_user_chk btn-check" data-key="chief" name="autorun_user[]" value="chief" checked><label class="btn btn-secondary" for="autorun_chief">기본 사령턴</label>
</div>
</div>
</div>
@@ -162,7 +165,7 @@ if ($session->userGrade < 5 && !$allowReset) {
<option value="480">8시간</option>
<option value="600">10시간</option>
<option value="720">12시간</option>
<option value="1440">24시간</option>
<option value="1440" selected>24시간</option>
<option value="2160">36시간</option>
<option value="2880">48시간</option>
<option value="3600">60시간</option>
+1
View File
@@ -21,6 +21,7 @@ if ($session->userGrade == 5) {
<head>
<title>설치</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=device-width, initial-scale=1" />
<?= WebUtil::printJS('../d_shared/common_path.js') ?>
+5 -3
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -100,7 +102,7 @@ if(in_array($stateOpt, ['try_destroy_src', 'try_destroy_dest'])){
'reason'=>'파기'
];
}
$msgText = "외교 서신 #{$letterNo} 파기했습니다.";
$msgText = "외교 서신(#{$letterNo})을 파기했습니다.";
$lastState = 'cancelled';
}
else{
@@ -114,12 +116,12 @@ else{
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 파기 요청합니다.";
$msgText = "외교 서신(#{$letterNo})을 파기 요청합니다.";
$lastState = 'activated';
}
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+6 -4
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -85,7 +87,7 @@ if($isAgree){
], 'no=%i', $prevLetterNo);
$prevLetterNo = $db->queryFirstField('SELECT prev_no FROM ng_diplomacy WHERE state != \'cancelled\' AND no = %i', $prevLetterNo);
}
$msgText = "외교 서신 #{$letterNo} 승인되었습니다.";
$msgText = "외교 서신( #{$letterNo})이 승인되었습니다.";
}
else{
$aux['reason'] = [
@@ -97,14 +99,14 @@ else{
'state'=>'cancelled',
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 거부되었습니다.";
$msgText = "외교 서신(#{$letterNo})이 거부되었습니다.";
if($reason){
$msgText .= ' 이유 : '.$reason;
}
}
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
@@ -115,7 +117,7 @@ $msg = new Message(
$msgID = $msg->send();
$msg = new Message(
Message::MSGTYPE_NATIONAL,
MessageType::national,
$src,
$dest,
$msgText,
+4 -2
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -70,10 +72,10 @@ $db->update('ng_diplomacy', [
'state'=>'cancelled',
'aux'=>Json::encode($aux)
], 'no=%i', $letterNo);
$msgText = "외교 서신 #{$letterNo} 회수되었습니다.";
$msgText = "외교 서신(#{$letterNo})이 회수되었습니다.";
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+3 -1
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -176,7 +178,7 @@ else{
$msg = new Message(
Message::MSGTYPE_DIPLOMACY,
MessageType::diplomacy,
$src,
$dest,
$msgText,
+1 -1
View File
@@ -109,7 +109,7 @@ $scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$block_general_create = (bool)$_POST['block_general_create'];
$block_general_create = (int)$_POST['block_general_create'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = !!(int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
-19
View File
@@ -1,19 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([])->setReadOnly();
if(!Session::getInstance()->generalID){
Json::die([
"nation"=>[]
]);
}
//NOTE: 모든 국가, 모든 장수에 대해서 같은 결과라면 캐싱 가능하지 않을까?
Json::die([
"nation"=>getMailboxList()
]);
-63
View File
@@ -1,63 +0,0 @@
<?php
namespace sammo;
include 'lib.php';
include 'func.php';
WebUtil::requireAJAX();
//{msgID: 1206, response: true}
$session = Session::requireGameLogin([])->setReadOnly();
$generalID = Session::getInstance()->generalID;
if (!$generalID) {
Json::die([
'result'=>false,
'reason'=>'로그인하지 않음'
]);
}
$jsonPost = Json::decode(Util::getPost('data', 'string', '{}'));
$msgID = Util::toInt($jsonPost['msgID']??null);
$msgResponse = $jsonPost['response']??null;
if ($msgID === null || !is_bool($msgResponse)) {
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 인자'
]);
}
$general = DB::db()->queryFirstRow('SELECT `no`, `name`, `nation`, `officer_level`, `npc`, `gold`, `rice`, `troop`, `aux` from `general` where `no` = %i', $generalID);
if(!$general){
Json::die([
'result'=>false,
'reason'=>'존재하지 않는 장수'
]);
}
$msg = Message::getMessageByID($msgID);
if($msg === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 메시지'
]);
}
$reason = 'success';
$gameStor = KVStorage::getStorage(DB::db(), 'game_env');
$gameStor->cacheAll();
if($msgResponse){
$result = $msg->agreeMessage($general['no'], $reason);
}
else{
$result = $msg->declineMessage($general['no'], $reason);
}
Json::die([
'result' => $result!==DiplomaticMessage::INVALID,
'reason' => $reason
]);
-74
View File
@@ -1,74 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
WebUtil::requireAJAX();
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$msgID = Util::getPost('msgID', 'int');
if($msgID === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 범위 입니다.'
]);
}
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if($lastMsgGet[0] !== 'string'){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 5){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = $now;
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
sleep(1);
}
$session->setReadOnly();
list($generalID, $nationID, $generalName) = DB::db()->queryFirstList(
'select `no`, `nation`, `name` from `general` where owner = %i',
$userID
);
if($nationID === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
$reason = Message::deleteMsg($msgID, $generalID);
if($reason === null){
$result = [
'result'=>true,
'reason'=>'success'
];
}
else{
$result = [
'result'=>false,
'reason'=>$reason
];
}
Json::die($result);
-118
View File
@@ -1,118 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$reqTo = Util::getPost('to', 'int');
$reqType = Util::getPost('type', 'string');
if($reqTo === null){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 범위 입니다.'
]);
}
if($reqType === null || !in_array($reqType, ['private', 'public', 'national', 'diplomacy'])){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 타입입니다.'
]);
}
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if($lastMsgGet[0] !== 'string'){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = $now;
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
sleep(1);
}
$session->setReadOnly();
$me = DB::db()->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if($me === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$result = [
'private'=>[],
'public'=>[],
'national'=>[],
'diplomacy'=>[],
'result'=>true,
'keepRecent'=>true,
'sequence'=>0,
'nationID'=>$nationID,
'generalName'=>$generalName,
];
$result['result'] = true;
$nextSequence = $reqTo;
if($reqType == 'private'){
$result['private'] = array_map(function(Message $msg) use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld($generalID, Message::MSGTYPE_PRIVATE, $reqTo, 15));
}
else if($reqType == 'public'){
$result['public'] = array_map(function(Message $msg)use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, $reqTo, 15));
}
else if($reqType == 'national'){
$result['national'] = array_map(function(Message $msg)use (&$nextSequence){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
return $msg->toArray();
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, $reqTo, 15));
}
else{
$result['diplomacy'] = array_map(function(Message $msg)use (&$nextSequence, $permission){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
$values = $msg->toArray();
if($msg->dest->nationID != 0 && $permission < 3){
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBoxOld(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, $reqTo, 15));
}
Json::die($result);
-120
View File
@@ -1,120 +0,0 @@
<?php
namespace sammo;
include('lib.php');
include('func.php');
$session = Session::requireGameLogin([]);
$userID = Session::getUserID();
$reqSequence = Util::getPost('sequence', 'int', -1);
$lastMsgGet = Json::decode($session->lastMsgGet)??[];
$now = new \DateTime();
$delayTime = false;
if(count($lastMsgGet) >= 10){
try{
if(!is_string($lastMsgGet[0])){
throw new \Exception('Why not string?');
}
$first = new \DateTime($lastMsgGet[0]);
$diff = $first->diff($now);
if($diff->days == 0 && $diff->h > 0 && $diff->i == 0 && $diff->s <= 1){
$delayTime = true;
}
array_shift($lastMsgGet);
}
catch(\Exception $e){
$lastMsgGet = [];
}
}
$lastMsgGet[] = TimeUtil::now();
$session->lastMsgGet = Json::encode($lastMsgGet);
if($delayTime){
usleep(200);
}
$session->setReadOnly();
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission FROM general WHERE `owner`=%i', $userID);
if($me === null){
Json::die([
'result'=>false,
'reason'=>'장수가 사망했습니다.'
]);
}
[$generalID, $nationID, $generalName] = [$me['no'], $me['nation'], $me['name']];
$permission = checkSecretPermission($me, false);
$result = [];
$result['result'] = true;
$result['keepRecent'] = false;
$nextSequence = $reqSequence;
$minSequence = $reqSequence;
$lastType = null;
$result['private'] = array_map(function(Message $msg) use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'private';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox($generalID, Message::MSGTYPE_PRIVATE, 15, $reqSequence));
$result['public'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'public';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_PUBLIC, Message::MSGTYPE_PUBLIC, 15, $reqSequence));
$result['national'] = array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'national';
}
return $msg->toArray();
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_NATIONAL, 15, $reqSequence));
$result['diplomacy']= array_map(function(Message $msg)use (&$nextSequence, &$minSequence, &$lastType, $permission){
if($msg->id > $nextSequence){
$nextSequence = $msg->id;
}
if($msg->id <= $minSequence){
$minSequence = $msg->id;
$lastType = 'diplomacy';
}
$values = $msg->toArray();
if($msg->dest->nationID != 0 && $permission < 3){
$values['text'] = '(외교 메시지입니다)';//TODO: 외교서신이라 읽을 수 없음을 보여줘야함
$values['option']['invalid'] = true;
}
return $values;
}, Message::getMessagesFromMailBox(Message::MAILBOX_NATIONAL + $nationID, Message::MSGTYPE_DIPLOMACY, 15, $reqSequence));
if($lastType !== null){
array_pop($result[$lastType]);
$result['keepRecent'] = true;
}
else if($reqSequence <= 0){
$result['keepRecent'] = true;
}
$result['sequence'] = $nextSequence;
$result['nationID'] = $nationID;
$result['generalName'] = $generalName;
Json::die($result);
-206
View File
@@ -1,206 +0,0 @@
<?php
namespace sammo;
include 'lib.php';
include 'func.php';
WebUtil::requireAJAX();
$post = Json::decode(Util::getPost('data', 'string', '{}'));
'@phan-var mixed[] $post';
$v = new Validator($post);
$v->rule('required', ['mailbox','text']);
$v->rule('integer', 'mailbox');
$v->rule('lengthMin', 'text', 1);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>$v->errorStr(),
'msgID'=>null
]);
}
$mailbox = (int)$post['mailbox'];
$text = trim(StringUtil::cutStringForWidth($post['text'], 199, ''));
$session = Session::requireGameLogin([
'msgID'=>null
]);
$userID = Session::getUserID();
//NOTE: 전송 메시지 시간 계산을 위해 Session을 쓰기 가능 상태로 열어둠.
increaseRefresh('서신전달', 1);
if(getBlockLevel() == 1 || getBlockLevel() == 3) {
Json::die([
'result' => false,
'reason' => '차단되었습니다.',
'msgID'=>null
]);
}
/**
* 메시지 전송 코드.
*
* TODO: 장기적으로 ajax는 한곳에 모을 필요가 있을 듯.
*/
$now = new \DateTime();
$unlimited = new \DateTime('9999-12-31');
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,penalty,permission,belong FROM general WHERE `owner`=%i', $userID);
if(!$me){
$session->logoutGame();
Json::die([
'result' => false,
'reason' => '로그인되지 않았습니다.',
'msgID' => null
]);
}
$con = checkLimit($me['con']);
if($con >= 2) {
Json::die([
'result' => false,
'reason' => '접속 제한입니다.',
'msgID' => null
]);
}
$me['icon'] = GetImageURL($me['imgsvr'], $me['picture']);
$permission = checkSecretPermission($me);
$srcNation = getNationStaticInfo($me['nation']);
$src = new MessageTarget($me['no'], $me['name'], $srcNation['nation'], $srcNation['name'], $srcNation['color'], $me['icon']);
// 전체 메세지
if($mailbox == Message::MAILBOX_PUBLIC) {
$msg = new Message(
Message::MSGTYPE_PUBLIC,
$src,
$src,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
// 국가 메세지
if($mailbox >= Message::MAILBOX_NATIONAL) {
if($permission < 4){
$destNationID = $me['nation'];
}
else{
$destNationID = $mailbox - Message::MAILBOX_NATIONAL;
}
if($destNationID == $me['nation']){
$msgType = Message::MSGTYPE_NATIONAL;
}
else{
$msgType = Message::MSGTYPE_DIPLOMACY;
}
$destNation = getNationStaticInfo($destNationID);
$dest = new MessageTarget(0, '', $destNation['nation'], $destNation['name'], $destNation['color']);
$msg = new Message(
$msgType,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
// 개인 메세지
if($mailbox > 0) {
$lastMsg = new \DateTime($session->lastMsg??'0000-00-00');
$msg_interval = $now->getTimestamp() - $lastMsg->getTimestamp();
//NOTE: 여기서 유저 레벨을 구별할 코드가 필요할까?
if($msg_interval < 2){
Json::die([
'result' => false,
'reason' => '개인메세지는 2초당 1건만 보낼 수 있습니다!',
'msgID' => null
]);
}
$session->lastMsg = $now->format('Y-m-d H:i:s');
$destUser = $db->queryFirstRow('SELECT `no`,`name`,`nation`,`officer_level`,`con`,`picture`,`imgsvr`,permission,penalty FROM general WHERE `no`=%i',$mailbox);
if(!$destUser){
Json::die([
'result' => false,
'reason' => '존재하지 않는 유저입니다.',
'msgID' => null
]);
}
$destPermission = checkSecretPermission($destUser, false);
if($permission == 4 && $destPermission == 4 && $destUser['nation'] != $me['nation']){
Json::die([
'result' => false,
'reason' => '외교권자끼리는 메시지를 보낼 수 없습니다.',
'msgID' => null
]);
}
$destNation = getNationStaticInfo($destUser['nation']);
$dest = new MessageTarget(
$destUser['no'],
$destUser['name'],
$destNation['nation'],
$destNation['name'],
$destNation['color'],
GetImageURL($destUser['imgsvr'], $destUser['picture'])
);
$msg = new Message(
Message::MSGTYPE_PRIVATE,
$src,
$dest,
$text,
$now,
$unlimited,
[]
);
$msgID = $msg->send();
Json::die([
'result' => true,
'reason' => 'SUCCESS',
'msgID' => $msgID
]);
}
Json::die([
'result' => false,
'reason' => '알 수 없는 에러',
'msgID' => null
]);
+5 -3
View File
@@ -1,6 +1,8 @@
<?php
namespace sammo;
use sammo\Enums\MessageType;
include "lib.php";
include "func.php";
@@ -226,8 +228,8 @@ function do추방(General $general, int $myOfficerLevel):?string{
}
else{
$betrayCnt = $general->getVar('betray');
$general->addExperience(-$general->getVar('experience')*0.1*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.1*$betrayCnt);
$general->addExperience(-$general->getVar('experience')*0.15*$betrayCnt);
$general->addDedication(-$general->getVar('dedication')*0.15*$betrayCnt);
$general->increaseVarWithLimit('betray', 1, null, GameConst::$maxBetrayCnt);
}
@@ -268,7 +270,7 @@ function do추방(General $general, int $myOfficerLevel):?string{
GetImageURL($general->getVar('imgsvr'), $general->getVar('picture'))
);
$msg = new Message(
Message::MSGTYPE_PUBLIC,
MessageType::public,
$src,
$src,
$str,
+2 -2
View File
@@ -56,7 +56,7 @@ if(file_exists(__DIR__.'/.htaccess')){
'scenarioName'=>$options['scenarioName'],
'turnterm'=>$options['turnterm'],
'fictionMode'=>($options['fiction']?'가상':'사실'),
'block_general_create'=>(!!$options['block_general_create']),
'block_general_create'=>Util::toInt($options['block_general_create']),
'npcMode'=>([0=>'불가',1=>'가능',2=>'선택 생성'][$options['npcmode']]),
'openDatetime'=>$reserved['date'],
'starttime'=>$options['starttime'],
@@ -90,7 +90,7 @@ $admin['scenario'] = $admin['scenario_text'];
$admin['userCnt'] = $genCnt;
$admin['npcCnt'] = $npcCnt;
$admin['nationCnt'] = $nationCnt;
$admin['block_general_create'] = !!$admin['block_general_create'];
$admin['block_general_create'] = $admin['block_general_create'];
$admin['npcMode'] = [0=>'불가',1=>'가능',2=>'선택 생성'][$admin['npcMode']];
$admin['fictionMode'] = $admin['fiction']?'가상':'사실';
+1 -1
View File
@@ -44,7 +44,7 @@ if($defence_train !== $me->getVar('defence_train')){
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
$me->increaseVarWithLimit('train', -3, 20);
$me->increaseVarWithLimit('atmos', -3, 20);
$me->increaseVarWithLimit('atmos', -6, 20);
}
else{
$me->increaseVar('myset', -1);
+1 -1
View File
@@ -82,7 +82,7 @@ function applyNationPolicy($policy, $nationID, $generalName): ?string
return "{$troopID}는 국가의 부대가 아닙니다.";
}
if ($troopCache[$troopID] != 'Neutral') {
return "부대({$troopID}는 하나의 역할만 지정할 수 있습니다.";
return "부대({$troopID})는 하나의 역할만 지정할 수 있습니다.";
}
if (!is_array($troopTarget) || count($troopTarget) != 2) {
return "{$troopID}의 입력양식이 올바르지 않습니다.";
+318 -214
View File
@@ -1,4 +1,5 @@
<?php
namespace sammo;
use Ds\Map;
@@ -15,48 +16,48 @@ $userID = Session::getUserID();
increaseRefresh("시뮬레이터", 0);
$query = Util::getPost('query');
if($query === null){
if ($query === null) {
Json::die([
'result'=>false,
'reason'=>'입력값이 없습니다.'
'result' => false,
'reason' => '입력값이 없습니다.'
]);
}
$action = Util::getPost('action');
if($action === null || !in_array($action, ['reorder', 'battle'])){
if ($action === null || !in_array($action, ['reorder', 'battle'])) {
Json::die([
'result'=>false,
'reason'=>'원하는 동작이 지정되지 않았습니다.'
'result' => false,
'reason' => '원하는 동작이 지정되지 않았습니다.'
]);
}
$query = Json::decode($query);
if($query === null){
if ($query === null) {
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 JSON입니다.'
'result' => false,
'reason' => '올바르지 않은 JSON입니다.'
]);
}
$defaultCheck = [
'required'=>[
'required' => [
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation',
'year', 'month', 'repeatCnt'
],
'integer'=>[
'year','month','repeatCnt'
'integer' => [
'year', 'month', 'repeatCnt'
],
'between'=>[
'between' => [
['month', [1, 12]]
],
'in'=>[
'in' => [
['repeatCnt', [1, 1000]]
],
'min'=>[
'min' => [
['year', 0]
],
'array'=>[
'array' => [
'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation'
],
@@ -64,10 +65,10 @@ $defaultCheck = [
$v = new Validator($query);
$v->rules($defaultCheck);
if(!$v->validate()){
if (!$v->validate()) {
Json::die([
'result'=>false,
'reason'=>$v->errorStr()
'result' => false,
'reason' => $v->errorStr()
]);
}
@@ -84,21 +85,112 @@ $rawDefenderList = $query['defenderGenerals'];
$rawDefenderCity = $query['defenderCity'];
$rawDefenderNation = $query['defenderNation'];
$warSeed = $query['seed'] ?? '';
$cityCheck = [
'required' => [
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
],
'numeric' => [
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer' => [
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min' => [
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in' => [
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[출병도시]' . $v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[수비도시]' . $v->errorStr()
]);
}
$nationCheck = [
'required' => [
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer' => [
'level', 'capital', 'nation', 'gennum',
],
'numeric' => [
'tech', 'gold', 'rice'
],
'min' => [
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in' => [
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[출병국]' . $v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[수비국]' . $v->errorStr()
]);
}
$generalCheck = [
'required'=>[
'required' => [
'no', 'name', 'nation', 'turntime', 'personal', 'special2', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'book', 'strength', 'strength_exp', 'weapon', 'injury', 'leadership', 'leadership_exp', 'horse', 'item',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'recent_war', 'warnum', 'killnum', 'killcrew',
],
'integer'=>[
'integer' => [
'no', 'nation', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'warnum', 'killnum', 'killcrew',
],
'min'=>[
'min' => [
['no', 1],
['nation', 1],
['crew', 0],
@@ -117,14 +209,14 @@ $generalCheck = [
['killnum', 0],
['killcrew', 0],
],
'between'=>[
'between' => [
['train', [40, GameConst::$maxTrainByWar]],
['atmos', [40, GameConst::$maxAtmosByWar]],
['explevel', [0, 300]],
['injury', [0, 80]],
['officer_level', [1, 12]]
],
'in'=>[
'in' => [
['personal', array_merge(GameConst::$availablePersonality, GameConst::$optionalPersonality)],
['special2', array_merge(GameConst::$availableSpecialWar, GameConst::$optionalSpecialWar)],
['crewtype', array_keys(GameUnitConst::all())],
@@ -132,162 +224,138 @@ $generalCheck = [
['weapon', array_merge(array_keys(GameConst::$allItems['weapon']), ['None'])],
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
],
'array' => ['inheritBuff'],
];
$inheritBuffCheck = [
'between' => [
[TriggerInheritBuff::WAR_AVOID_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_CRITICAL_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_MAGIC_TRIAL_PROB, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_AVOID_RATIO, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_CRITICAL_RATIO, [0, 5]],
[TriggerInheritBuff::OPPOSE_WAR_MAGIC_TRIAL_PROB, [0, 5]],
]
];
if(!$warSeed){
$warSeed = bin2hex(random_bytes(16));
}
else {
$repeatCnt = 1;
}
$tmpRNG = new RandUtil(new LiteHashDRBG($warSeed));
$v = new Validator($rawAttacker);
$v->rules($generalCheck);
if(!$v->validate()){
if (!$v->validate()) {
Json::die([
'result'=>false,
'reason'=>'[출병자]'.$v->errorStr()
'result' => false,
'reason' => '[출병자]' . $v->errorStr()
]);
}
$rawAttacker['owner'] = 0;
$defenderList = [];
foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
$v = new Validator($rawDefenderGeneral);
$v->rules($generalCheck);
if(!$v->validate()){
$idx+=1;
$rawAttacker['aux'] = [];
if (key_exists('inheritBuff', $rawAttacker)) {
$v = new Validator($rawAttacker['inheritBuff']);
$v->rules($inheritBuffCheck);
if (!$v->validate()) {
Json::die([
'result'=>false,
'reason'=>"[수비자{$idx}]".$v->errorStr()
'result' => false,
'reason' => '[출병자]' . $v->errorStr()
]);
}
$rawAttacker['aux']['inheritBuff'] = $rawAttacker['inheritBuff'];
}
$rawAttacker['aux'] = Json::encode($rawAttacker['aux']);
$rawAttacker['owner'] = 0;
$attackerGeneral = new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month);
$attacker = new WarUnitGeneral(
$tmpRNG,
$attackerGeneral,
$rawAttackerNation,
true
);
/** @var WarUnit[] */
$defenderList = [];
foreach ($rawDefenderList as $idx => $rawDefenderGeneral) {
$v = new Validator($rawDefenderGeneral);
$v->rules($generalCheck);
if (!$v->validate()) {
$idx += 1;
Json::die([
'result' => false,
'reason' => "[수비자{$idx}]" . $v->errorStr()
]);
}
$rawDefenderGeneral['aux'] = [];
if (key_exists('inheritBuff', $rawDefenderGeneral)) {
$v = new Validator($rawDefenderGeneral['inheritBuff']);
$v->rules($inheritBuffCheck);
if (!$v->validate()) {
$idx += 1;
Json::die([
'result' => false,
'reason' => "[수비자{$idx}]" . $v->errorStr()
]);
}
$rawDefenderGeneral['aux']['inheritBuff'] = $rawDefenderGeneral['inheritBuff'];
}
$rawDefenderGeneral['aux'] = Json::encode($rawDefenderGeneral['aux']);
$rawDefenderGeneral['owner'] = 0;
$defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
$defenderGeneral = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
$defenderList[] = new WarUnitGeneral(
$tmpRNG,
$defenderGeneral,
$rawDefenderNation,
false
);
}
if ($action == 'reorder') {
$noRng = NoRNG::rngInstance();
$cityCheck = [
'required'=>[
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
],
'numeric'=>[
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer'=>[
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min'=>[
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in'=>[
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병도시]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비도시]'.$v->errorStr()
]);
}
$nationCheck = [
'required'=>[
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer'=>[
'level', 'capital', 'nation', 'gennum',
],
'numeric'=>[
'tech', 'gold', 'rice'
],
'min'=>[
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in'=>[
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병국]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비국]'.$v->errorStr()
]);
}
if($action == 'reorder'){
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
});
$order = [];
foreach($defenderList as $defenderGeneral){
$order[] = $defenderGeneral->getID();
foreach ($defenderList as $defender) {
$order[] = $defender->getGeneral()->getID();
}
Json::die([
'result'=>true,
'reason'=>'success',
'order'=>$order
'result' => true,
'reason' => 'success',
'order' => $order
]);
}
usort($defenderList, function(General $lhs, General $rhs){
return -(extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
});
$rawDefenderList = array_map(function(General $general){
return $general->getRaw();
}, $defenderList);
$rawDefenderList = [];
foreach($defenderList as $unit){
if(extractBattleOrder($unit, $attacker) <= 0){
continue;
}
$rawDefenderList[] = $unit->getRaw();
}
unset($defenderList);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear;
$cityRate = Util::round(($year - $startYear) / 1.5) + 60;
function extractRankVar(array $rawVal):Map{
function extractRankVar(array $rawVal): Map
{
$rankVars = new Map;
foreach($rawVal as $rawKey=>$rawVal){
foreach ($rawVal as $rawKey => $rawVal) {
$key = RankColumn::tryFrom($rawKey);
if($key === null){
if ($key === null) {
continue;
}
$rankVars[$key] = $rawVal;
@@ -296,86 +364,113 @@ function extractRankVar(array $rawVal):Map{
}
function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
){
$rawAttacker,
$rawAttackerCity,
$rawAttackerNation,
$rawDefenderList,
$rawDefenderCity,
$rawDefenderNation,
$startYear,
$year,
$month,
$warSeed
) {
if (!$warSeed) {
$warSeed = bin2hex(random_bytes(16));
}
$warSeed = bin2hex(random_bytes(16));
$warRng = new RandUtil(new LiteHashDRBG($warSeed));
$attackerGeneral = new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month);
$attacker = new WarUnitGeneral(
$warRng,
new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month),
$attackerGeneral,
$rawAttackerNation,
true
);
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$iterDefender = new \ArrayIterator($rawDefenderList);
/** @var WarUnit[] */
$defenderList = [];
foreach ($rawDefenderList as $rawDefenderGeneral) {
$defenderGeneral = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
$defenderList[] = new WarUnitGeneral(
$warRng,
$defenderGeneral,
$rawDefenderNation,
false
);
}
if(count($defenderList) && extractBattleOrder($city, $attacker) > 0){
$defenderList[] = $city;
}
usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
});
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind();
$battleResult = [];
$attackerRice = $rawAttacker['rice'];
$attackerRice = $attacker->getGeneral()->getVar('rice');
$defenderRice = 0;
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext)
use ($warRng, $iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice) {
if($prevDefender !== null){
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext)
use ($iterDefender, &$battleResult, &$defenderRice, $attacker): ?WarUnit {
if ($prevDefender !== null) {
$prevDefender->getLogger()->rollback();
$battleResult[] = $prevDefender;
if($prevDefender instanceof WarUnitGeneral){
if ($prevDefender instanceof WarUnitGeneral) {
$defenderRice -= $prevDefender->getVar('rice');
}
}
if(!$reqNext){
if (!$reqNext) {
return null;
}
if(!$iterDefender->valid()){
if (!$iterDefender->valid()) {
return null;
}
$defenderObj = new General($iterDefender->current(), extractRankVar($iterDefender->current()), $rawDefenderCity, $rawDefenderNation, $year, $month);
if(extractBattleOrder($defenderObj) <= 0){
/** @var WarUnit */
$defender = $iterDefender->current();
if (extractBattleOrder($defender, $attacker) <= 0) {
return null;
}
$defenderRice += $defenderObj->getVar('rice');
if($defender instanceof WarUnitGeneral){
$defenderRice += $defender->getVar('rice');
}
$retVal = new WarUnitGeneral(
$warRng,
$defenderObj,
$rawDefenderNation,
false
);
$iterDefender->next();
return $retVal;
return $defender;
};
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear);
$rawDefenderCity = $city->getRaw();
$updateAttackerNation = [];
$updateDefenderNation = [];
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city);
$attackerRice -= $attacker->getVar('rice');
if($city->getPhase() > 0){
if ($city->getPhase() > 0) {
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
$rice *= getTechCost($city->getRawNation()['tech']);
$rice *= $city->getCityTrainAtmos() / 100 - 0.2;
Util::setRound($rice);
$defenderRice += $rice;
}
$totalDead = $attacker->getKilled() + $attacker->getDead();
$attackerCityDead = $totalDead * 0.4;
$defenderCityDead = $totalDead * 0.6;
//$attackerCityDead = $totalDead * 0.4;
//$defenderCityDead = $totalDead * 0.6;
return [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice];
}
@@ -401,14 +496,26 @@ $avgWar = 0;
$attackerActivatedSkills = [];
$defendersActivatedSkills = [];
foreach(Util::range($repeatCnt) as $repeatIdx){
foreach (Util::range($repeatCnt) as $repeatIdx) {
if($repeatIdx > 0){
$warSeed = bin2hex(random_bytes(16));
}
/** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation,
$startYear, $year, $month, $cityRate
$rawAttacker,
$rawAttackerCity,
$rawAttackerNation,
$rawDefenderList,
$rawDefenderCity,
$rawDefenderNation,
$startYear,
$year,
$month,
$warSeed
);
$lastWarLog = Util::mapWithKey(function($key, $values){
$lastWarLog = Util::mapWithKey(function ($key, $values) {
return ConvertLog(join('<br>', $values));
}, $attacker->getLogger()->rollback());
@@ -431,48 +538,45 @@ foreach(Util::range($repeatCnt) as $repeatIdx){
$avgWar += count($battleResult) / $repeatCnt;
foreach($attacker->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $attackerActivatedSkills)){
foreach ($attacker->getActivatedSkillLog() as $skillName => $skillCnt) {
if (!key_exists($skillName, $attackerActivatedSkills)) {
$attackerActivatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
} else {
$attackerActivatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
foreach($battleResult as $idx=>$defender){
while($idx >= count($defendersActivatedSkills)){
foreach ($battleResult as $idx => $defender) {
while ($idx >= count($defendersActivatedSkills)) {
$defendersActivatedSkills[] = [];
}
$activatedSkills = &$defendersActivatedSkills[$idx];
foreach($defender->getActivatedSkillLog() as $skillName => $skillCnt){
if(!key_exists($skillName, $activatedSkills)){
foreach ($defender->getActivatedSkillLog() as $skillName => $skillCnt) {
if (!key_exists($skillName, $activatedSkills)) {
$activatedSkills[$skillName] = $skillCnt / $repeatCnt;
}
else{
} else {
$activatedSkills[$skillName] += $skillCnt / $repeatCnt;
}
}
}
}
Json::die([
'result'=>true,
'datetime'=>$rawAttacker['turntime'],
'reason'=>'success',
'lastWarLog'=>$lastWarLog,
'avgWar'=>$avgWar,
'phase'=>$avgPhase,
'killed'=>$attackerKilled,
'maxKilled'=>$attackerMaxKilled,
'minKilled'=>$attackerMinKilled,
'dead'=>$attackerDead,
'maxDead'=>$attackerMaxDead,
'minDead'=>$attackerMinDead,
'attackerRice'=>$attackerAvgRice,
'defenderRice'=>$defenderAvgRice,
'attackerSkills'=>$attackerActivatedSkills,
'defendersSkills'=>$defendersActivatedSkills,
'result' => true,
'datetime' => $rawAttacker['turntime'],
'reason' => 'success',
'lastWarLog' => $lastWarLog,
'avgWar' => $avgWar,
'phase' => $avgPhase,
'killed' => $attackerKilled,
'maxKilled' => $attackerMaxKilled,
'minKilled' => $attackerMinKilled,
'dead' => $attackerDead,
'maxDead' => $attackerMaxDead,
'minDead' => $attackerMinDead,
'attackerRice' => $attackerAvgRice,
'defenderRice' => $defenderAvgRice,
'attackerSkills' => $attackerActivatedSkills,
'defendersSkills' => $defendersActivatedSkills,
]);
-146
View File
@@ -1,146 +0,0 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
// $btn, $name, $troop
$action = Util::getPost('action');
$name = Util::getPost('name');
$gen = Util::getPost('gen', 'int');
$troop = Util::getPost('troop', 'int');
//로그인 검사
$session = Session::requireGameLogin([])->setReadOnly();
$userID = $session::getUserID();
increaseRefresh("부대명령", 0);
$db = DB::db();
$me = $db->queryFirstRow('SELECT `no`, name, nation, troop FROM general WHERE `owner`=%i', $userID);
$generalID = $me['no'];
$nationID = $me['nation'];
if($action == '부대창설'){
$name = StringUtil::neutralize($name);
if(!$name){
Json::die([
'result'=>false,
'reason'=>'부대 이름이 없습니다.'
]);
}
if($me['troop'] != 0){
Json::die([
'result'=>false,
'reason'=>'이미 부대에 가입해있습니다.'
]);
}
$db->insert('troop',[
'troop_leader'=>$generalID,
'name'=>$name,
'nation'=>$nationID,
]);
$db->update('general', [
'troop'=>$generalID,
], 'no=%i',$generalID);
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if($action == '부대추방'){
if (!$gen){
Json::die([
'result'=>false,
'reason'=>'장수를 지정해야 합니다.'
]);
}
$db->update('general', [
'troop'=>0
], 'no=%i AND troop = %i', $gen, $generalID);
if($db->affectedRows() == 0){
Json::die([
'result'=>false,
'reason'=>'부대장이 아니거나, 장수를 잘못 지정했습니다.'
]);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if ($action == '부대가입') {
if(!$troop){
Json::die([
'result'=>false,
'reason'=>'부대를 지정해야 합니다.'
]);
}
if($me['troop'] === $generalID){
Json::die([
'result'=>false,
'reason'=>'부대장입니다.'
]);
}
$troopExists = $db->queryFirstField('SELECT `troop_leader` FROM `troop` WHERE `troop_leader` = %i AND `nation` = %i', $troop, $nationID);
if (!$troopExists) {
Json::die([
'result'=>false,
'reason'=>'올바른 부대장이 아닙니다.'
]);
}
$db->update('general', [
'troop'=>$troop
], 'no=%i', $generalID);
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
if($action == "부대탈퇴") {
if($me['troop'] == 0){
Json::die([
'result'=>false,
'reason'=>'부대에 속해있지 않습니다.'
]);
}
//부대장일 경우
if($me['troop'] === $generalID){
$db->update('general', [
'troop'=>0
], 'troop=%i',$generalID);
$db->delete('troop', 'troop_leader=%i', $generalID);
}
else{
$db->update('general', [
'troop'=>0
], 'no=%i', $generalID);
}
Json::die([
'result'=>true,
'reason'=>'success'
]);
}
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 명령입니다.'
]);
+22
View File
@@ -0,0 +1,22 @@
function getCityPosition(){
return {"1":["서량",127,101],"2":["무도",127,222],"3":["성도",127,344],"4":["건녕",127,384],"5":["안정",167,141],"6":["한중",167,222],"7":["검각",167,263],"8":["자동",167,303],"9":["강주",167,344],"10":["장안",208,182],"11":["영안",208,384],"12":["홍농",248,182],"13":["완",248,222],"14":["양양",248,303],"15":["강릉",248,344],"16":["무릉",248,384],"17":["영릉",248,425],"18":["낙양",289,182],"19":["신야",289,263],"20":["강하",289,344],"21":["장사",289,384],"22":["계양",289,425],"23":["남해",289,465],"24":["업",329,101],"25":["진유",329,141],"26":["허창",329,182],"27":["여남",329,222],"28":["시상",329,344],"29":["평원",370,60],"30":["복양",370,101],"31":["초",370,141],"32":["수춘",370,222],"33":["단양",370,263],"34":["여강",370,303],"35":["계",410,20],"36":["남피",410,60],"37":["소패",410,141],"38":["건업",410,222],"39":["북평",451,20],"40":["북해",451,101],"41":["하비",451,141],"42":["광릉",451,182],"43":["오",451,263],"44":["회계",451,303],"45":["양평",491,20],"46":["국내",532,20],"47":["한",532,60],"48":["사비",532,101],"49":["매소",572,60],"50":["서라벌",572,101],"51":["운남",127,425],"52":["천수",127,182],"53":["졸본",572,20]};
}
function formatCityInfo(city) {
var regionMap = {"하북":1,"1":"하북","중원":2,"2":"중원","서북":3,"3":"서북","서촉":4,"4":"서촉","남중":5,"5":"남중","초":6,"6":"초","오월":7,"7":"오월","동이":8,"8":"동이"};
var levelMap = {"수":1,"1":"수","진":2,"2":"진","관":3,"3":"관","이":4,"4":"이","소":5,"5":"소","중":6,"6":"중","대":7,"7":"대","특":8,"8":"특"};
var region_str = regionMap[city.region];
var level_str = levelMap[city.level];
city.text = '【' + region_str + '|' + level_str + '】' + city.name;
city.region_str = region_str;
city.level_str = level_str;
return city;
}
+5 -2
View File
@@ -9,6 +9,9 @@ $loader->addClassMap((function () {
$d_settingMap = [];
foreach (glob(__DIR__.'/d_setting/*.orig.php') as $filepath) {
$filepath = str_replace('.orig.php', '.php', $filepath);
if(!file_exists($filepath)) {
continue;
}
$filename = basename($filepath);
$classname = explode('.', $filename)[0];
$d_settingMap['sammo\\'.$classname] = $filepath;
@@ -63,8 +66,8 @@ function prepareDir(string $dirPath, bool $forceCreate=true):bool{
if(!unlink($dirPath)){
return false;
}
return mkdir($dirPath);
return mkdir($dirPath, 0775);
}
return mkdir($dirPath, 0777, true);
return mkdir($dirPath, 0775, true);
}
+453
View File
@@ -0,0 +1,453 @@
<?php
namespace sammo;
use sammo\DTO\VoteInfo;
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,con,turntime,newmsg,newvote,`officer_level` from general 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'));
$con = checkLimit($me['con']);
if ($con >= 2) {
printLimitMsg($me['turntime']);
exit();
}
$generalObj = General::createGeneralObjFromDB($me['no']);
$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-md-4" style="color:<?= $color ?>;">
<?= $scenario ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
NPC 수, 상성 : <?= $extend ?>,<?= $fiction ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
NPC선택 : <?= $npcmode ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
토너먼트 : <?= getTournamentTermText($gameStor->turnterm) ?>
</div>
<div class="s-border-t col py-2 col-4 col-md-2" style="color:<?= $color ?>;">
기타 설정: <?= $otherTextInfo ?>
</div>
<div class="s-border-t col py-2 col-8 col-md-4"><?= info(2) ?></div>
<div class="s-border-t col py-2 col-4 col-md-2">전체 접속자 수 : <?= $gameStor->online_user_cnt ?> 명</div>
<div class="s-border-t col py-2 col-4 col-md-2">턴당 갱신횟수 : <?= $gameStor->conlimit ?>회</div>
<div class="s-border-t col py-2 col-8 col-md-4"><?= info(3) ?></div>
<div class="s-border-t py-2 col col-6 col-md-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-md-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-md-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-md-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-md-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-md-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-md-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-md-8 d-grid">
<input type="text" id="msg_input" maxlength="99" class="form-control">
</div>
<div id="msg_submit-col" class="col-6 col-md-2 d-grid"><button id="msg_submit" class="btn btn-primary">서신전달&amp;갱신</button></div>
</div>
<div class="col-md-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-md-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-md-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-md-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 ($con == 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-md-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>
+67 -66
View File
@@ -2,6 +2,7 @@
namespace sammo;
use sammo\Enums\EventTarget;
function processWar(string $warSeed, General $attackerGeneral, array $rawAttackerNation, array $rawDefenderCity)
{
@@ -29,23 +30,39 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
}
$gameStor = KVStorage::getStorage($db, 'game_env');
[$startYear, $year, $month, $cityRate, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'city_rate', 'join_mode']);
[$startYear, $year, $month, $joinMode] = $gameStor->getValuesAsArray(['startyear', 'year', 'month', 'join_mode']);
$attacker = new WarUnitGeneral($rng, $attackerGeneral,$rawAttackerNation, true);
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $cityRate);
$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'));
$defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
$defenderGeneralList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
usort($defenderList, function (General $lhs, General $rhs) {
return - (extractBattleOrder($lhs) <=> extractBattleOrder($rhs));
/** @var WarUnit[] */
$defenderList = [];
foreach($defenderGeneralList as $defenderGeneral){
$defenderCandidate = new WarUnitGeneral($rng, $defenderGeneral, $rawDefenderNation, false);
if(extractBattleOrder($defenderCandidate, $attacker) <= 0){
continue;
}
$defenderList[] = $defenderCandidate;
}
if(count($defenderList) && extractBattleOrder($city, $attacker) > 0){
$defenderList[] = $city;
}
usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
});
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind();
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($rng, $iterDefender, $rawDefenderNation, $rawDefenderCity, $db) {
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $db, $attacker) {
if ($prevDefender !== null) {
$prevDefender->applyDB($db);
}
@@ -58,24 +75,16 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
return null;
}
/** @var WarUnit */
$nextDefender = $iterDefender->current();
$nextDefender->setRawCity($rawDefenderCity);
if (extractBattleOrder($nextDefender) <= 0) {
if (extractBattleOrder($nextDefender, $attacker) <= 0) {
return null;
}
$retVal = new WarUnitGeneral(
$rng,
$nextDefender,
$rawDefenderNation,
false
);
$iterDefender->next();
return $retVal;
return $nextDefender;
};
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear);
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city);
$attacker->applyDB($db);
@@ -90,7 +99,7 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']);
$rice *= $cityRate / 100 - 0.2;
$rice *= $city->getCityTrainAtmos() / 100 - 0.2;
Util::setRound($rice);
$updateDefenderNation['rice'] = max(0, $rawDefenderNation['rice'] - $rice);
@@ -113,8 +122,8 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
'dead' => $db->sqleval('dead + %i', $totalDead * 0.6)
], 'city=%i', $rawDefenderCity['city']);
$attackerIncTech = buildNationTypeClass($rawAttackerNation['type'])->onCalcDomestic('기술', 'score', $attacker->getDead() * 0.01);
$defenderIncTech = buildNationTypeClass($rawDefenderNation['type'])->onCalcDomestic('기술', 'score', $attacker->getKilled() * 0.01);
$attackerIncTech = buildNationTypeClass($rawAttackerNation['type'])->onCalcDomestic('기술', 'score', $attacker->getDead() * 0.012);
$defenderIncTech = buildNationTypeClass($rawDefenderNation['type'])->onCalcDomestic('기술', 'score', $attacker->getKilled() * 0.009);
$attackerGenCnt = $rawAttackerNation['gennum'];
$defenderGenCnt = $rawDefenderNation['gennum'];
@@ -175,13 +184,21 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
'startyear' => $startYear,
'year' => $year,
'month' => $month,
'city_rate' => $cityRate,
'join_mode' => $joinMode,
], $attacker->getGeneral(), $city->getRaw());
}
function extractBattleOrder(General $general)
function extractBattleOrder(WarUnit $defender, WarUnit $attacker)
{
if($defender instanceof WarUnitCity){
if(!($attacker instanceof WarUnitGeneral)){
return 0;
}
$attackerGeneral = $attacker->getGeneral();
return $attackerGeneral->onCalcOpposeStat($defender->getGeneral(), 'cityBattleOrder', -1);
}
$general = $defender->getGeneral();
if ($general->getVar('crew') == 0) {
return 0;
}
@@ -212,7 +229,6 @@ function processWar_NG(
WarUnitGeneral $attacker,
callable $getNextDefender,
WarUnitCity $city,
int $relYear
): bool {
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
@@ -225,6 +241,7 @@ function processWar_NG(
$attackerNationUpdate = [];
$defenderNationUpdate = [];
/** @var WarUnit */
$defender = ($getNextDefender)(null, true);
$conquerCity = false;
@@ -240,6 +257,7 @@ function processWar_NG(
$logWritten = false;
if ($defender === null) {
$defender = $city;
$defender->setSiege();
if ($city->getNationVar('rice') <= 0 && $city->getVar('supply')) {
//병량 패퇴
@@ -406,21 +424,28 @@ function processWar_NG(
$attacker->logBattleResult();
$defender->logBattleResult();
$attacker->addWin();
$defender->addLose();
if (!($defender instanceof WarUnitCity) || $defender->isSiege()){
$attacker->addWin();
$defender->addLose();
$attacker->tryWound();
$defender->tryWound();
$attacker->tryWound();
$defender->tryWound();
if ($defender === $city) {
$attacker->addLevelExp(1000);
$conquerCity = true;
break;
if ($defender === $city) {
$attacker->addLevelExp(1000);
$conquerCity = true;
break;
}
}
$josaYi = JosaUtil::pick($defender->getCrewTypeName(), '이');
if ($noRice) {
if ($defender instanceof WarUnitCity && !$defender->isSiege()){
//실제 공성을 위해 다시 초기화
$defender->setOppose(null);
}
else if ($noRice) {
$logger->pushGlobalActionLog("<Y>{$defender->getName()}</>의 {$defender->getCrewTypeName()}{$josaYi} 패퇴했습니다.");
$attacker->getLogger()->pushGeneralActionLog("<Y>{$defender->getName()}</>의 {$defender->getCrewTypeName()}{$josaYi} 패퇴했습니다.", ActionLogger::PLAIN);
$defender->getLogger()->pushGeneralActionLog("군량 부족으로 패퇴합니다.", ActionLogger::PLAIN);
@@ -455,6 +480,11 @@ function processWar_NG(
$attacker->finishBattle();
$defender->finishBattle();
if($city->getDead()){
$city->setSiege();
$city->finishBattle();
}
if ($defender instanceof WarUnitCity) {
$newConflict = $defender->addConflict();
if ($newConflict) {
@@ -550,23 +580,10 @@ function ConquerCity(array $admin, General $general, array $city)
$gameStor = KVStorage::getStorage($db, 'game_env');
// 이벤트 핸들러 동작
$e_env = null;
foreach (DB::db()->query('SELECT * FROM event WHERE target = "OCCUPY_CITY" ORDER BY `priority` DESC, `id` ASC') as $rawEvent) {
if ($e_env === null) {
$e_env = $gameStor->getAll(false);
}
$eventID = $rawEvent['id'];
$cond = Json::decode($rawEvent['condition']);
$action = Json::decode($rawEvent['action']);
$event = new Event\EventHandler($cond, $action);
$e_env['currentEventID'] = $eventID;
$event->tryRunEvent($e_env);
if(TurnExecutionHelper::runEventHandler($db, $gameStor, EventTarget::OccupyCity)){
$gameStor->cacheAll();
}
if ($e_env !== null) {
$gameStor->resetCache();
}
// 국가 멸망시
if ($defenderNationID && $db->queryFirstField('SELECT count(city) FROM city WHERE nation = %i', $defenderNationID) === 1) {
@@ -662,27 +679,11 @@ function ConquerCity(array $admin, General $general, array $city)
}
// 이벤트 핸들러 동작
$e_env = null;
foreach (DB::db()->query('SELECT * FROM event WHERE target = "DESTROY_NATION" ORDER BY `priority` DESC, `id` ASC') as $rawEvent) {
if ($e_env === null) {
$e_env = $gameStor->getAll(false);
}
$eventID = $rawEvent['id'];
$cond = Json::decode($rawEvent['condition']);
$action = Json::decode($rawEvent['action']);
$event = new Event\EventHandler($cond, $action);
$e_env['currentEventID'] = $eventID;
$event->tryRunEvent($e_env);
}
if ($e_env !== null) {
$gameStor->resetCache();
}
TurnExecutionHelper::runEventHandler($db, $gameStor, EventTarget::DestroyNation);
// 멸망이 아니면
} else {
// 태수,군사,종사 일반으로...
// 태수,군사,종사 일반으로...
$db->update('general', [
'officer_level' => 1,
'officer_city' => 0,
+2
View File
@@ -11,6 +11,7 @@ include "func.php";
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>최근 지도</title>
@@ -27,6 +28,7 @@ include "func.php";
<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::printDist('ts', ['common', 'recent_map'], true) ?>
<?= WebUtil::printDist('vue', [], true) ?>
<style>
html {
width: 700px;
+2 -1
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\AuctionBuyRice;
use sammo\AuctionUniqueItem;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\General;
@@ -32,7 +33,7 @@ class BidBuyRiceAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$auctionID = $this->args['auctionID'];
$amount = $this->args['amount'];
+2 -1
View File
@@ -5,6 +5,7 @@ namespace sammo\API\Auction;
use sammo\Session;
use DateTimeInterface;
use sammo\AuctionSellRice;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\General;
@@ -31,7 +32,7 @@ class BidSellRiceAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$auctionID = $this->args['auctionID'];
$amount = $this->args['amount'];
+3 -2
View File
@@ -5,6 +5,7 @@ namespace sammo\API\Auction;
use sammo\Session;
use DateTimeInterface;
use sammo\AuctionUniqueItem;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\GameConst;
use sammo\General;
@@ -33,11 +34,11 @@ class BidUniqueAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$auctionID = $this->args['auctionID'];
$amount = $this->args['amount'];
$tryExtendCloseDate = $this->arg['extendCloseDate'] ?? false;
$tryExtendCloseDate = $this->args['extendCloseDate'] ?? false;
$generalID = $session->generalID;
$general = General::createGeneralObjFromDB($generalID);
@@ -8,6 +8,7 @@ use sammo\AuctionSellRice;
use sammo\DB;
use sammo\DTO\AuctionBidItem;
use sammo\DTO\AuctionInfo;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\AuctionType;
use sammo\Validator;
use sammo\General;
@@ -29,7 +30,7 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
@@ -8,6 +8,7 @@ use sammo\AuctionUniqueItem;
use sammo\DB;
use sammo\DTO\AuctionBidItem;
use sammo\DTO\AuctionInfo;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\AuctionType;
use sammo\Enums\InheritanceKey;
use sammo\InheritancePointManager;
@@ -37,7 +38,7 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
@@ -8,6 +8,7 @@ use sammo\AuctionUniqueItem;
use sammo\DB;
use sammo\DTO\AuctionBidItem;
use sammo\DTO\AuctionInfo;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\AuctionType;
use sammo\TimeUtil;
use sammo\Util;
@@ -24,7 +25,7 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
+2 -1
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\AuctionBuyRice;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\GameConst;
use sammo\General;
@@ -52,7 +53,7 @@ class OpenBuyRiceAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
/** @var int */
$amount = $this->args['amount'];
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\AuctionSellRice;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\GameConst;
use sammo\General;
@@ -52,7 +53,7 @@ class OpenSellRiceAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
/** @var int */
$amount = $this->args['amount'];
+2 -1
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\AuctionUniqueItem;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\GameConst;
use sammo\General;
@@ -49,7 +50,7 @@ class OpenUniqueAuction extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$itemID = $this->args['itemID'];
$amount = $this->args['amount'];
+3 -2
View File
@@ -7,6 +7,7 @@ use DateTimeInterface;
use sammo\Betting;
use sammo\DB;
use sammo\DTO\BettingItem;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\GameConst;
use sammo\KVStorage;
@@ -26,7 +27,7 @@ class Bet extends \sammo\BaseAPI
->rule('int', 'bettingID')
->rule('integerArray', 'bettingType')
->rule('int', 'amount')
->rule('min', 'amount', 1);
->rule('min', 'amount', 10);
if (!$v->validate()) {
return $v->errorStr();
@@ -39,7 +40,7 @@ class Bet extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
/** @var int */
$bettingID = $this->args['bettingID'];
+2 -1
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\DTO\BettingInfo;
use sammo\Enums\APIRecoveryType;
use sammo\KVStorage;
use sammo\Util;
use sammo\Validator;
@@ -32,7 +33,7 @@ class GetBettingDetail extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
+2 -1
View File
@@ -6,6 +6,7 @@ use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\DTO\BettingInfo;
use sammo\Enums\APIRecoveryType;
use sammo\KVStorage;
use sammo\Validator;
@@ -29,7 +30,7 @@ class GetBettingList extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
+2 -1
View File
@@ -5,6 +5,7 @@ namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Json;
use sammo\KVStorage;
use sammo\TimeUtil;
@@ -23,7 +24,7 @@ class GetReservedCommand extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
+2 -1
View File
@@ -4,6 +4,7 @@ namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use function sammo\pushGeneralCommand;
@@ -31,7 +32,7 @@ class PushCommand extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$amount = $this->args['amount'];
if($amount == 0){
+2 -1
View File
@@ -4,6 +4,7 @@ namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use function sammo\repeatGeneralCommand;
@@ -31,7 +32,7 @@ class RepeatCommand extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$amount = $this->args['amount'];
+2 -1
View File
@@ -4,6 +4,7 @@ namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\Enums\APIRecoveryType;
use sammo\GameConst;
use sammo\Util;
use sammo\Validator;
@@ -36,7 +37,7 @@ class ReserveBulkCommand extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$briefList = [];
foreach ($this->args as $idx => $turn) {
+2 -1
View File
@@ -4,6 +4,7 @@ namespace sammo\API\Command;
use sammo\Session;
use DateTimeInterface;
use sammo\Enums\APIRecoveryType;
use sammo\GameConst;
use sammo\Util;
use sammo\Validator;
@@ -33,7 +34,7 @@ class ReserveCommand extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$action = $this->args['action'];
$turnList = $this->args['turnList'];
@@ -4,6 +4,7 @@ namespace sammo\API\General;
use sammo\Command\General\che_거병;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\Session;
@@ -30,7 +31,7 @@ class BuildNationCandidate extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$userID = $session->userID;
+5 -4
View File
@@ -4,7 +4,8 @@ namespace sammo\API\General;
use sammo\DB;
use sammo\DummyGeneral;
use sammo\Enums\APIRecoveryType;
use sammo\GameConst;
use sammo\Session;
use sammo\General;
use sammo\JosaUtil;
@@ -26,7 +27,7 @@ class DieOnPrestart extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
//로그인 검사
$userID = $session->userID;
@@ -54,7 +55,7 @@ class DieOnPrestart extends \sammo\BaseAPI
}
//서버 가오픈시 할 수 있는 행동
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, 2);
$targetTime = addTurn($general['lastrefresh'], $gameStor->turnterm, GameConst::$minTurnDieOnPrestart);
if ($targetTime > TimeUtil::now()) {
$targetTimeShort = substr($targetTime, 0, 19);
return "아직 삭제할 수 없습니다. {$targetTimeShort} 부터 가능합니다.";
@@ -67,7 +68,7 @@ class DieOnPrestart extends \sammo\BaseAPI
$generalName = $generalObj->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
$generalObj->kill($db, true, "<Y>{$generalName}</>{$josaYi} 홀연히 모습을 <R>감추었습니다</>");
$session->logoutGame();
return null;
+2 -1
View File
@@ -4,6 +4,7 @@ namespace sammo\API\General;
use Ds\Set;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Validator;
use sammo\Session;
@@ -33,7 +34,7 @@ class DropItem extends \sammo\BaseAPI
return static::REQ_GAME_LOGIN;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag)
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$generalID = $session->generalID;
$me = General::createGeneralObjFromDB($generalID);
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace sammo\API\General;
use sammo\Enums\APIRecoveryType;
use sammo\General;
use sammo\Session;
use function sammo\getCommandTable;
//getCommandTable 호출을 대신하는 API
class GetCommandTable extends \sammo\BaseAPI{
public function validateArgs(): ?string{
return null;
}
public function getRequiredSessionMode(): int{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$generalID = $session->generalID;
$me = General::createGeneralObjFromDB($generalID);
$commandTable = getCommandTable($me);
return [
'result'=>true,
'commandTable' => $commandTable,
];
}
}
+591
View File
@@ -0,0 +1,591 @@
<?php
namespace sammo\API\General;
use DateTimeInterface;
use MeekroDB;
use sammo\CityConst;
use sammo\DB;
use sammo\DTO\VoteInfo;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\CityColumn;
use sammo\Enums\GeneralColumn;
use sammo\Enums\RankColumn;
use sammo\GameConst;
use sammo\General;
use sammo\KVStorage;
use sammo\LastTurn;
use sammo\Validator;
use sammo\Session;
use sammo\TimeUtil;
use sammo\Util;
use function sammo\buildNationCommandClass;
use function sammo\checkLimit;
use function sammo\getTournamentTermText;
use function sammo\buildNationTypeClass;
use function sammo\calcLeadershipBonus;
use function sammo\checkSecretPermission;
use function sammo\getBillByLevel;
use function sammo\getDed;
use function sammo\getHonor;
use function sammo\getNationStaticInfo;
use function sammo\getOfficerLevelText;
use function sammo\increaseRefresh;
/**
* 통째로 메인페이지의 주요 정보를 반환하는 날로먹는 API
*/
class GetFrontInfo extends \sammo\BaseAPI
{
const ROW_LIMIT = 15;
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function validateArgs(): ?string
{
$v = new Validator($this->args);
$v->rule('lengthMin', 'lastNationNoticeDate', 19)
->rule('integer', 'lastGeneralRecordID')
->rule('integer', 'lastWorldHistoryID');
if (!$v->validate()) {
return $v->errorStr();
}
$this->args['lastGeneralRecordID'] = (int)($this->args['lastGeneralRecordID'] ?? 0);
$this->args['lastWorldHistoryID'] = (int)($this->args['lastWorldHistoryID'] ?? 0);
return null;
}
private function getGlobalRecord(int $lastRecordID): array
{
$db = DB::db();
$globalRecord = $db->queryAllLists(
'SELECT id, `text` FROM general_record WHERE `general_id` = 0 AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i',
'history',
$lastRecordID,
static::ROW_LIMIT + 1,
);
return $globalRecord;
}
private function getGeneralRecord(int $generalID, int $lastRecordID): array
{
$db = DB::db();
$generalRecord = $db->queryAllLists(
'SELECT id, `text` FROM general_record WHERE `general_id` = %i AND log_type = %s AND id >= %i ORDER BY `id` DESC LIMIT %i',
$generalID,
'action',
$lastRecordID,
static::ROW_LIMIT + 1,
);
return $generalRecord;
}
private function getHistory(int $lastHistoryID): array
{
$db = DB::db();
$history = $db->queryAllLists(
'SELECT id, `text` FROM world_history WHERE nation_id = 0 AND id >= %i ORDER BY `id` DESC LIMIT %i',
$lastHistoryID,
static::ROW_LIMIT + 1,
);
return $history;
}
private function generateRecentRecord(int $generalID){
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['isunited', 'opentime', 'refresh']);
$lastHistoryID = $this->args['lastWorldHistoryID'];
$lastRecordID = $this->args['lastGeneralRecordID'];
$history = $this->getHistory($lastHistoryID);
$globalRecord = $this->getGlobalRecord($lastRecordID);
$generalRecord = $this->getGeneralRecord($generalID, $lastRecordID);
$flushHistory = false;
$flushGlobalRecord = false;
$flushGeneralRecord = false;
if (!$history) {
$flushHistory = false;
} else if (Util::array_last($history)[0] <= $lastHistoryID) {
$flushHistory = false;
array_pop($history);
} else if (count($history) > static::ROW_LIMIT) {
array_pop($history);
}
if (!$globalRecord) {
$flushGlobalRecord = false;
} else if (Util::array_last($globalRecord)[0] == $lastRecordID) {
$flushGlobalRecord = false;
array_pop($globalRecord);
} else if (count($globalRecord) > static::ROW_LIMIT) {
array_pop($globalRecord);
}
if (!$generalRecord) {
$flushGeneralRecord = false;
} else if (Util::array_last($generalRecord)[0] == $lastRecordID) {
$flushGeneralRecord = false;
array_pop($generalRecord);
} else if (count($generalRecord) > static::ROW_LIMIT) {
array_pop($generalRecord);
}
return [
'history' => $history,
'global' => $globalRecord,
'general' => $generalRecord,
'flushHistory' => $flushHistory ? 1 : 0,
'flushGlobal' => $flushGlobalRecord ? 1 : 0,
'flushGeneral' => $flushGeneralRecord ? 1 : 0,
];
}
private function generateGlobalInfo(MeekroDB $db): array
{
$gameStor = KVStorage::getStorage($db, 'game_env');
[
$scenarioText, $extendedGeneral, $isFiction, $npcMode,
$joinMode, $autorunUser, $turnterm, $lastExecuted,
$lastVoteID, $develCost, $noticeMsg,
$onlineNations, $onlineUserCnt,
$year, $month, $startYear,
$generalCntLimit,
$apiLimit,
$serverCnt,
] = $gameStor->getValuesAsArray([
'scenario_text', 'extended_general', 'fiction', 'npcmode',
'join_mode', 'autorun_user', 'turnterm', 'turntime',
'lastVote', 'develcost', 'msg',
'online_nation', 'online_user_cnt',
'year', 'month', 'startyear',
'maxgeneral',
'conlimit',
'server_cnt',
]);
$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;
}
}
$auctionCount = $db->queryFirstField('SELECT count(*) FROM ng_auction WHERE finished = 0');
$isTournamentActive = $gameStor->tournament > 0;
$isTournamentApplicationOpen = $gameStor->tournament == 1;
$isBettingActive = $gameStor->tournament == 6;
$tournamentType = $gameStor->tnmt_type;
$tournamentState = $gameStor->tournament;
$tournamentTime = $gameStor->tnmt_time;
$isLocked = boolval($db->queryFirstField('SELECT plock FROM plock WHERE `type`="GAME" LIMIT 1'));
$globalGenCount = $db->queryAllLists('SELECT npc, count(no) FROM general GROUP BY npc');
return [
'scenarioText' => $scenarioText,
'extendedGeneral' => $extendedGeneral,
'isFiction' => $isFiction,
'npcMode' => $npcMode,
'joinMode' => $joinMode,
'startyear' => $startYear,
'year' => $year,
'month' => $month,
'autorunUser' => $autorunUser,
'turnterm' => $turnterm,
'lastExecuted' => $lastExecuted,
'lastVoteID' => $lastVoteID,
'develCost' => $develCost,
'noticeMsg' => $noticeMsg,
'onlineNations' => $onlineNations,
'onlineUserCnt' => $onlineUserCnt,
'apiLimit' => $apiLimit,
'auctionCount' => $auctionCount,
'isTournamentActive' => $isTournamentActive,
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
'isBettingActive' => $isBettingActive,
'isLocked' => $isLocked,
'tournamentType' => $tournamentType,
'tournamentState' => $tournamentState,
'tournamentTime' => $tournamentTime,
'genCount' => $globalGenCount,
'generalCntLimit' => $generalCntLimit,
'serverCnt' => $serverCnt,
'lastVote' => $lastVote === null ? null : $lastVote->toArray(),
];
}
public function generateNationInfo(MeekroDB $db, General $general, array $rawNation): array
{
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getAll(true);
$lastNationNoticeDate = $this->args['lastNationNoticeDate'] ?? '2022-08-19 00:00:00';
$nationID = $general->getNationID();
//XXX: 매번 더하는가?
$nationPopulation = $db->queryFirstRow(
'SELECT COUNT(*) as cityCnt, CAST(SUM(pop) AS INTEGER) as `now`, CAST(SUM(pop_max) AS INTEGER) as `max` from city where nation=%i',
$nationID
);
if($nationPopulation['cityCnt'] == 0){
$nationPopulation = [
'cityCnt' => 0,
'now' => 0,
'max' => 0
];
}
//XXX: 매번 더하는가?
$nationCrew = $db->queryFirstRow(
'SELECT COUNT(*) as generalCnt, CAST(SUM(crew) AS INTEGER) as `now`,CAST(SUM(leadership)*100 AS INTEGER) as `max` from general where nation=%i AND npc != 5',
$nationID
);
$nationStor = KVStorage::getStorage($db, $nationID, 'nation_env');
[$nationNotice, $onlineGen] = $nationStor->getValuesAsArray(['nationNotice', 'online_genenerals']);
if (!$nationNotice || ($nationNotice['date'] ?? '') <= $lastNationNoticeDate) {
$nationNotice = null;
}
$topChiefs = Util::convertArrayToDict($db->query(
'SELECT officer_level, no, name, npc FROM general WHERE nation = %i AND officer_level >= 11',
$nationID
), 'officer_level');
$impossibleStrategicCommandLists = [];
$strategicCommandLists = GameConst::$availableChiefCommand['전략'];
$yearMonth = Util::joinYearMonth($admin['year'], $admin['month']);
foreach ($strategicCommandLists as $command) {
$cmd = buildNationCommandClass($command, $general, $admin, new LastTurn());
$nextAvailableTurn = $cmd->getNextAvailableTurn();
if ($nextAvailableTurn > $yearMonth) {
$impossibleStrategicCommandLists[] = [$cmd->getName(), $nextAvailableTurn - $yearMonth];
}
}
$nationClass = buildNationTypeClass($rawNation['type']);
return [
'id' => $nationID,
'full' => true,
'name' => $rawNation['name'],
'population' => $nationPopulation,
'crew' => $nationCrew,
'type' => [
'raw' => $rawNation['type'],
'name' => $nationClass->getName(),
'pros' => $nationClass::$pros,
'cons' => $nationClass::$cons,
],
'color' => $rawNation['color'],
'level' => $rawNation['level'],
'capital' => $rawNation['capital'],
'gold' => $rawNation['gold'],
'rice' => $rawNation['rice'],
'tech' => $rawNation['tech'],
'gennum' => $rawNation['gennum'],
'power' => $rawNation['power'],
'bill' => $rawNation['bill'],
'taxRate' => $rawNation['rate'],
'onlineGen' => $onlineGen,
'notice' => $nationNotice,
'topChiefs' => $topChiefs,
'diplomaticLimit' => $rawNation['surlimit'],
'strategicCmdLimit' => $rawNation['strategic_cmd_limit'],
'impossibleStrategicCommand' => $impossibleStrategicCommandLists,
'prohibitScout' => $rawNation['scout'],
'prohibitWar' => $rawNation['war'],
];
}
public function generateDummyNationInfo(MeekroDB $db, General $general, array $rawNation): array
{
$staticInfo = getNationStaticInfo(0);
return [
'id' => 0,
'full' => false,
'name' => $staticInfo['name'],
'population' => [
'cityCnt' => 0,
'now' => 0,
'max' => 0,
],
'crew' => [
'generalCnt' => 0,
'now' => 0,
'max' => 0,
],
'type' => [
'raw' => 'None',
'name' => '-',
'pros' => '',
'cons' => '',
],
'color' => $staticInfo['color'],
'level' => $staticInfo['level'],
'capital' => $staticInfo['capital'],
'gold' => $staticInfo['gold'],
'rice' => $staticInfo['rice'],
'tech' => $staticInfo['tech'],
'gennum' => $staticInfo['gennum'],
'power' => $staticInfo['power'],
'onlineGen' => '', //TODO 접속자
'notice' => '',
'topChiefs' => [],
'impossibleStrategicCommand' => [],
];
}
public function generateGeneralInfo(MeekroDB $db, General $general, array $rawNation): array
{
$permission = checkSecretPermission($general->getRaw());
$result = [
'no' => $general->getID(), // number;
'name' => $general->getName(), // string;
'nation' => $general->getNationID(), // number;
'npc' => $general->getNPCType(), // number;
'injury' => $general->getVar(GeneralColumn::injury), // number;
'leadership' => $general->getVar(GeneralColumn::leadership), // number;
'strength' => $general->getVar('strength'), // number;
'intel' => $general->getVar('intel'), // number;
'explevel' => $general->getVar('explevel'), // number;
'dedlevel' => $general->getVar('dedlevel'), // number;
'gold' => $general->getVar('gold'), // number;
'rice' => $general->getVar('rice'), // number;
'killturn' => $general->getVar(GeneralColumn::killturn), // number;
'picture' => $general->getVar(GeneralColumn::picture), // string;
'imgsvr' => $general->getVar(GeneralColumn::imgsvr), // 0 | 1;
'age' => $general->getVar(GeneralColumn::age), // number;
'specialDomestic' => $general->getVar(GeneralColumn::special), // GameObjClassKey;
'specialWar' => $general->getVar(GeneralColumn::special2), // GameObjClassKey;
'personal' => $general->getVar(GeneralColumn::personal), // GameObjClassKey;
'belong' => $general->getVar(GeneralColumn::belong), // number;
'connect' => $general->getVar(GeneralColumn::connect), // number;
'officerLevel' => $general->getVar(GeneralColumn::officer_level), // number;
'officerLevelText' => getOfficerLevelText($general->getVar(GeneralColumn::officer_level), $rawNation['level']), // string;
'lbonus' => calcLeadershipBonus($general->getVar(GeneralColumn::officer_level), $rawNation['level']), // number;
'ownerName' => $general->getVar(GeneralColumn::owner_name), // string | null;
'honorText' => getHonor($general->getVar(GeneralColumn::experience)), // string;
'dedLevelText' => getDed($general->getVar(GeneralColumn::dedication)), // string;
'bill' => getBillByLevel($general->getVar(GeneralColumn::dedlevel)), // number;
'reservedCommand' => null, // TurnObj[] | null;
'autorun_limit' => $general->getAuxVar('autorun_limit') ?? 0, // number;
'city' => $general->getVar(GeneralColumn::city), // number;
'troop' => $general->getVar(GeneralColumn::troop), // number;
//P0 End
'con' => $general->getVar(GeneralColumn::con), // number;
'specage' => $general->getVar(GeneralColumn::specage), // number;
'specage2' => $general->getVar(GeneralColumn::specage2), // number;
'leadership_exp' => $general->getVar(GeneralColumn::leadership_exp), // number;
'strength_exp' => $general->getVar(GeneralColumn::strength_exp), // number;
'intel_exp' => $general->getVar(GeneralColumn::intel_exp), // number;
'dex1' => $general->getVar(GeneralColumn::dex1), // number;
'dex2' => $general->getVar(GeneralColumn::dex2), // number;
'dex3' => $general->getVar(GeneralColumn::dex3), // number;
'dex4' => $general->getVar(GeneralColumn::dex4), // number;
'dex5' => $general->getVar(GeneralColumn::dex5), // number;
'experience' => $general->getVar(GeneralColumn::experience), // number;
'dedication' => $general->getVar(GeneralColumn::dedication), // number;
'officer_level' => $general->getVar(GeneralColumn::officer_level), // number;
'officer_city' => $general->getVar(GeneralColumn::officer_city), // number;
'defence_train' => $general->getVar(GeneralColumn::defence_train), // number;
'crewtype' => $general->getVar(GeneralColumn::crewtype), // GameObjClassKey;
'crew' => $general->getVar(GeneralColumn::crew), // number;
'train' => $general->getVar(GeneralColumn::train), // number;
'atmos' => $general->getVar(GeneralColumn::atmos), // number;
'turntime' => $general->getVar(GeneralColumn::turntime), // string;
'recent_war' => $general->getVar(GeneralColumn::recent_war), // string;
'horse' => $general->getVar(GeneralColumn::horse), // GameObjClassKey;
'weapon' => $general->getVar(GeneralColumn::weapon), // GameObjClassKey;
'book' => $general->getVar(GeneralColumn::book), // GameObjClassKey;
'item' => $general->getVar(GeneralColumn::item), // GameObjClassKey;
'warnum' => $general->getRankVar(RankColumn::warnum), // number;
'killnum' => $general->getRankVar(RankColumn::killnum), // number;
'deathnum' => $general->getRankVar(RankColumn::deathnum), // number;
'killcrew' => $general->getRankVar(RankColumn::killcrew), // number;
'deathcrew' => $general->getRankVar(RankColumn::deathcrew), // number;
'firenum' => $general->getRankVar(RankColumn::firenum), // number;
//P1 End
'permission' => $permission,
];
$nationID = $general->getNationID();
$troopID = $general->getVar(GeneralColumn::troop);
if (!$troopID) {
return $result;
}
$troopName = $db->queryFirstField(
'SELECT `name` FROM troop WHERE nation = %i AND troop_leader = %i',
$nationID,
$troopID
);
if (!$troopName) {
return $result;
}
$troopCityID = $db->queryFirstField(
'SELECT city FROM general WHERE nation = %i AND `no` = %i',
$nationID,
$troopID
);
if (!$troopCityID) {
return $result;
}
$troopReservedCommand = $db->query(
'SELECT action, arg, brief FROM general_turn WHERE general_id = %i AND turn_idx < 5 ORDER BY turn_idx asc',
$troopID
);
if (!$troopReservedCommand) {
return $result;
}
$result['troopInfo'] = [
'leader' => [
'city' => $troopCityID,
'reservedCommand' => $troopReservedCommand,
],
'name' => $troopName,
];
return $result;
}
public function generateCityInfo(MeekroDB $db, General $general, array $rawNation): array
{
$rawCity = $general->getRawCity() ?? [];
$cityID = $rawCity[CityColumn::city->value];
$nationID = $rawCity[CityColumn::nation->value];
if ($nationID == $general->getNationID()) {
$nationName = $rawNation['name'];
$nationColor = $rawNation['color'];
} else {
$staticNation = getNationStaticInfo($nationID);
$nationName = $staticNation['name'];
$nationColor = $staticNation['color'];
}
$rawOfficerList = $db->query('SELECT officer_level, name, npc FROM general WHERE officer_city = %i AND officer_level IN (4,3,2)', $cityID);
$officerList = [4 => null, 3 => null, 2 => null];
foreach ($rawOfficerList as $officer) {
$officerLevel = $officer['officer_level'];
$officerList[$officerLevel] = $officer;
}
$result = [
'id' => $rawCity[CityColumn::city->value],
'name' => $rawCity[CityColumn::name->value],
'nationInfo' => [
'id' => $nationID,
'name' => $nationName,
'color' => $nationColor,
],
'level' => $rawCity[CityColumn::level->value],
'trust' => $rawCity[CityColumn::trust->value],
'pop' => [$rawCity[CityColumn::pop->value], $rawCity[CityColumn::pop_max->value]],
'agri' => [$rawCity[CityColumn::agri->value], $rawCity[CityColumn::agri_max->value]],
'comm' => [$rawCity[CityColumn::comm->value], $rawCity[CityColumn::comm_max->value]],
'secu' => [$rawCity[CityColumn::secu->value], $rawCity[CityColumn::secu_max->value]],
'def' => [$rawCity[CityColumn::def->value], $rawCity[CityColumn::def_max->value]],
'wall' => [$rawCity[CityColumn::wall->value], $rawCity[CityColumn::wall_max->value]],
'trade' => $rawCity[CityColumn::trade->value],
'officerList' => $officerList,
];
return $result;
}
public function launch(Session $session, ?DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$generalID = $session->generalID;
//NOTE: 이 경우 staticNation 정보를 조회한다.
$general = General::createGeneralObjFromDB($generalID);
$nationID = $general->getNationID();
$cityID = $general->getCityID();
$con = checkLimit($general->getVar('con'));
if ($con >= 2) {
return [
'result' => false,
'reason' => '접속 제한중입니다.',
'recovery' => APIRecoveryType::GameQuota,
'recovery_arg' => $general->getVar('turntime'),
];
}
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheAll(true);
increaseRefresh("General/GetFrontInfo", 1);
$rawCity = $db->queryFirstRow('SELECT * FROM city WHERE city = %i', $cityID);
$general->setRawCity($rawCity);
if ($nationID == 0) {
$rawNation = getNationStaticInfo(0);
} else {
$rawNation = $db->queryFirstRow('SELECT * FROM nation WHERE nation = %i', $nationID);
}
$globalInfo = $this->generateGlobalInfo($db);
$nationInfo = $nationID != 0 ?
$this->generateNationInfo($db, $general, $rawNation) :
$this->generateDummyNationInfo($db, $general, $rawNation);
$generalInfo = $this->generateGeneralInfo($db, $general, $rawNation);
$cityInfo = $this->generateCityInfo($db, $general, $rawNation);
//TODO: 마지막 투표, 토너먼트, 베팅을 했는지 정보를 별도로 가져와야 함. aux?
$auxInfo = [];
if ($globalInfo['lastVote']) {
$myLastVoteID = $db->queryFirstField('SELECT vote_id FROM vote WHERE general_id = %i ORDER BY vote_id DESC LIMIT 1', $generalID);
if($myLastVoteID) {
$auxInfo['myLastVote'] = $myLastVoteID;
}
}
return [
'result' => true,
'recentRecord' => $this->generateRecentRecord($generalID),
'global' => $globalInfo,
'nation' => $nationInfo,
'general' => $generalInfo,
'city' => $cityInfo,
'aux' => $auxInfo,
];
}
}

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