Compare commits

..
69 Commits
Author SHA1 Message Date
Hide_D e0d1a0a612 아이템 효과 텍스트 수정 2021-04-30 22:36:24 +09:00
Hide_D 3040996671 무쌍 누락분 수정 2021-04-30 16:35:34 +09:00
Hide_D dd830e7500 TypeCode 추가 2021-04-29 22:38:46 +09:00
Hide_D d2dfe2c418 전투 수비 파트 약 상향 2021-04-29 21:10:47 +09:00
Hide_D 139fb6b6e0 국가 규모 승급시 아이템 습득 방식 변경 2021-04-29 20:31:32 +09:00
Hide_D c4f6976c42 유니크 아이템에 효과 추가 2021-04-29 19:50:12 +09:00
Hide_D ab428fc104 유니크 기본 획득 확률 변경 2021-04-29 18:49:19 +09:00
Hide_D aa97f78acd 무쌍 초반 버프, 후반 너프 2021-04-29 18:47:55 +09:00
Hide_D dbce900aeb 유니크 중복 획득 가능 2021-04-29 18:44:09 +09:00
Hide_D 30b382e2e7 초반 등록 NPC 30명 2021-04-29 18:30:46 +09:00
Hide_D 433c4abb86 fix: 이민족 종료 시점 2021-04-11 23:17:47 +09:00
Hide_D 64404e4092 fix: 이민족 종료조건 추가 2021-04-11 21:22:06 +09:00
Hide_D 08d483af8a fix: 후방 워프 인구 충분 판단 기준 수정 2021-04-10 16:01:21 +09:00
Hide_D fa19c17941 fix: AI 발령 턴 오류 수정 2021-04-10 15:39:03 +09:00
Hide_D c896a999ad fix: 전방 도시가 '관'처럼 인구가 적은 경우 후방 워프하지 않는 버그 수정
feat: 후방 발령 관련 로직도 후방 워프와 유사하게 재 적용
2021-04-10 11:51:10 +09:00
Hide_D f9bca935ac fix: 장수수 카운트에 "의병장"을 포함하여 계산하는 버그 수정 2021-04-02 14:39:57 +09:00
Hide_D 7abf274d89 이민족 난이도 기본 수치 변경 2021-03-29 22:45:43 +09:00
Hide_D e2ad417306 feat: 이민족 등장 2021-03-28 16:31:01 +09:00
Hide_D 2ea9655f6b fix: 이민족 2021-03-28 05:57:53 +09:00
Hide_D f450d5d9de fix: 수비자 도시 버그
fix: RaiseInvader 버그 수정 중
2021-03-28 04:12:10 +09:00
Hide_D f8f4b73a09 feat: RaiserInvader 초기 구현 2021-03-28 03:13:03 +09:00
Hide_D 926d96732d fix: 가상 역사 모드에서 후계자 지정이 사실 모드 설정을 따라가는 버그 수정 2021-03-23 13:24:34 +09:00
Hide_D 167113d6a3 fix: 빙의 해제시 owner 값 버그 수정 2021-03-23 13:19:40 +09:00
Hide_D 911cb614a5 fix: RegNPC 버그 수정, event handler 규격 버그 수정 2021-03-19 18:09:53 +09:00
Hide_D 7a939b7024 fix: RegNPC 버그 수정 2021-03-19 17:44:34 +09:00
Hide_D 6e57a60997 RegNPC 버그 수정 2021-03-19 17:36:13 +09:00
Hide_D 9f1151e699 fix: can부대구출발령 없음 2021-03-19 17:22:48 +09:00
Hide_D 3fbe1fb63d 디버그2 2021-02-28 01:39:47 +09:00
Hide_D d4906eec5a 디버그 코드 추가 2021-02-28 01:33:58 +09:00
Hide_D ebe0663e74 에러 로그용 추가 2021-02-28 01:05:27 +09:00
Hide_D 04c89b9711 긴급 호출 대비 2021-02-21 00:40:49 +09:00
Hide_D 4f2bc874e5 initFull을 할 필요가 없었던 것! 2021-02-10 21:24:04 +09:00
Hide_D 316ac5c3c8 불가침인데도 선포 가능한 버그 수정 2021-01-12 17:14:36 +09:00
Hide_D 7882aa667e 관리자 도구 수정 2021-01-07 22:22:04 +09:00
Hide_D 8b8d5eecbf 모반시도 버그 수정 2021-01-07 01:12:06 +09:00
Hide_D 65b76643ee feat: 빙의일람에 장수 선택 내역
fix: 장수 선택 내역에서 owner_name 미반영 버그 수정
fix: 온라인 장수에서 npc가 뜨는 버그 수정
2021-01-03 18:31:18 +09:00
Hide_D f33e645113 초반 m장 스탯 관련 문제 해결, 장수 선택 term 해결 2021-01-01 21:09:43 +09:00
Hide_D 528d30c317 의병모집 버그 수정 2021-01-01 19:56:29 +09:00
Hide_D 7f0a3d320c 버그 수정
- 의병 모집
- 장수 변경 시 생성 폼 남음
2021-01-01 19:54:28 +09:00
Hide_D 8e940aeb65 버그 수정. 시간 변경 2020-12-31 16:21:57 +09:00
Hide_D a77ee60809 버그.. 2020-12-31 13:34:37 +09:00
Hide_D 83383c29cd 버그 수정2 2020-12-31 13:33:45 +09:00
Hide_D b6393141e8 버그 수정 2020-12-31 13:29:57 +09:00
Hide_D 10ce1827d8 버그 수정 2020-12-31 13:27:11 +09:00
Hide_D 605f3a12ff select pool 수 증가 2020-12-31 13:24:33 +09:00
Hide_D a33539e75f 턴 변경을 합리적으로 변경 2020-12-31 08:09:23 +09:00
Hide_D b2cca3687a 버그 수정 2020-12-31 07:49:33 +09:00
Hide_D 628c54044f general_pool 에서 장수 선택 기능 추가 2020-12-31 07:43:56 +09:00
Hide_D c0e7a3eece readme 수정 2020-12-27 19:49:39 +09:00
Hide_D c7c13c19c1 일부 수정
composer update, README.md 업데이트
2020-12-27 02:11:53 +09:00
Hide_D d5f71b5878 DummySession 준비 2020-12-26 15:48:05 +09:00
Hide_D cb589e9e26 종전수락 버그 수정 2020-12-13 22:05:07 +09:00
Hide_D eaeed47297 도시 정보 출력 순서 변경 2020-11-11 23:34:53 +09:00
Hide_D e00e5c5cd7 이벤트 빼빼로 추가 2020-11-11 23:04:08 +09:00
Hide_D b3719f7166 수극 연속 사용 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D 337896974b 피장파장 로그 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D bb7d1fc9ab 수몰을 아무 국가에나 쓸 수 있는 버그 수정 2020-09-09 14:20:15 +09:00
Hide_D 07765c8d44 훈사 제한 버그 2020-08-17 09:21:37 +09:00
Hide_D 85cb91071e 기본 도시 정보 데이터 대폭 추가 2020-08-15 03:46:43 +09:00
Hide_D d41839845a 귀병 첫 페이즈 매우 높은 확률로 계략 시도 2020-08-11 22:43:45 +09:00
Hide_D c3d12aa55f 전쟁/선포 중인 국가에 선포 확률 대폭 감소 2020-08-11 22:36:26 +09:00
Hide_D a781e4b84c 인탐 성공 시 확률따라 추가 보정, 인탐/의병 지장 버그 수정 2020-08-11 22:33:50 +09:00
Hide_D 1fc0989fd2 계략 강화, 탈취량 시간에 따라 증가 2020-08-11 22:33:00 +09:00
Hide_D 14752260d3 회피 필살 중첩 가능 2020-07-24 14:19:05 +09:00
Hide_D 84675c874f 이호경식 버그 수정 2020-07-21 22:38:53 +09:00
Hide_D f30e6057be 버그 테스트 2020-07-21 22:34:10 +09:00
Hide_D ba8b629f0e 격노비급 버그 수정 2020-07-21 03:41:27 +09:00
Hide_D a0a45ff2aa 격노 비급 버그 수정 2020-07-21 03:32:37 +09:00
Hide_D 325f890a0b 방랑시 버그 수정 2020-07-20 23:24:15 +09:00
143 changed files with 7518 additions and 2066 deletions
+1
View File
@@ -29,6 +29,7 @@ d_shared
d_pic/*.jpg
d_pic/*.gif
d_pic/*.png
d_pic/*.webp
d_pic/uploaded_image
d_setting/*.php
+5 -5
View File
@@ -9,18 +9,18 @@
* <code>mpm_event</code> 권장
* PHP 7.3 이상
* <code>php-fpm</code> 권장
* php에서 curl, pdo-sqlite을 실행가능해야 합니다. (기본값: 지원)
* mysqlnd가 지원되어야합니다. (기본값: 지원)
* mysqli
* php에서 curl, pdo-sqlite을 실행가능해야 합니다.
* mysqli, mysqlnd
* gd
* mbstring
* MariaDB 10.2.1 이상
* 현재 MySQL은 지원하지 않습니다.
* <code>git</code>
* <code>curl</code>
Linux는 Ubuntu 16.04, 18.04, Windows는 Windows 10에서 XAMPP를 사용한 환경에서 테스트되었습니다.
Linux는 Ubuntu 18.04, 20.04, Windows는 Windows 10에서 XAMPP, WSL2를 사용한 환경에서 테스트되었습니다.
Docker를 이용한 설치는 계획중입니다.
Docker를 이용한 설치는 테스트버전만 제공됩니다.
## Docker를 이용한 설치
Regular → Executable
BIN
View File
Binary file not shown.
+240 -181
View File
@@ -1,182 +1,241 @@
@charset "utf-8";
body {
color:white; background-color:black; font-family: '맑은 고딕';
}
table {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
th, td {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
a.just_link {
text-decoration: none;
}
.with_border{
margin:0;
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
}
.section_title {
height:50px;
line-height:50px;
font-size: 30px; font-weight: bold;
text-align: center;
color:white;
padding:0;
}
.legacy_layout div {
border: solid 1px; border-spacing: 0px; border-collapse: separate; border-top-color: gray; border-left-color: gray; border-right-color: black; border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';;
}
.obj_fill{
display:block;
width:100%;
height:100%;
}
button.with_skin {
padding:0 4px;
background-color: black; color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
button.with_skin:disabled {
background-color:#333333;
}
input.with_skin {
background-color: black; color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
input.with_skin:disabled {
background-color: #333333;
}
.font0 { font-size: 10px; }
.font1 { font-size: 13px; }
.font2 { font-size: 15px; }
.font3 { font-size: 20px; }
.font4 { font-size: 30px; }
.font5 { font-size: 50px; }
caption.section_title {
caption-side:top;
}
.samButton{
float:left;
display:block;
padding:0;
margin:0;
text-decoration: none;
position:relative;
}
a.samButton.disabled {
pointer-events: none;
cursor: default;
}
.samButtonOuter{
display: table;
border: outset 2px white;
box-sizing: border-box;
font-weight:bold;
padding: 1px 6px;
width:125px;
height:30px;
background-color:#000000;
color:#ffffff;
}
.samButtonOuter:active{
border: inset 2px white;
}
.samButtonInner{
display: table-cell;
vertical-align: middle;
width: 100%;
margin: 0 auto;
text-align: center;
user-select: none;
}
.samToolbarButton > .samButtonOuter{
width:125px;
height:30px;
background-color:#225500;
color:white;
}
.samToolbarButton2 > .samButtonOuter{
width:125px;
height:30px;
background-color:#225500;
color:magenta;
}
.samCommandButton > .samButtonOuter{
width:111px;
height:30px;
}
.samCommandButton.disabled > .samButtonOuter{
background-color:transparent !important;
color:gray !important;
border-color:transparent !important;
}
.samCommandButton.disabled > .samButtonOuter > .samButtonInner::before{
content:'【'
}
.samCommandButton.disabled > .samButtonOuter > .samButtonInner::after{
content:'】'
}
.tooltip_copyable_info .tooltiptext{
display: inline;
color: rgba(0,0,0,0);
font-size: 0;
}
.tooltiptext {
display: none;
}
.hidden_but_copyable{
color: rgba(0,0,0,0);
font-size: 0;
@charset "utf-8";
body {
color: white;
background-color: black;
font-family: '맑은 고딕';
}
table {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
th,
td {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
}
a.just_link {
text-decoration: none;
}
.with_border {
margin: 0;
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
}
.section_title {
height: 50px;
line-height: 50px;
font-size: 30px;
font-weight: bold;
text-align: center;
color: white;
padding: 0;
}
.legacy_layout div {
border: solid 1px;
border-spacing: 0px;
border-collapse: separate;
border-top-color: gray;
border-left-color: gray;
border-right-color: black;
border-bottom-color: black;
padding: 0px;
font-size: 13px;
word-break: break-all;
text-align: center;
font-family: '맑은 고딕';
;
}
.obj_fill {
display: block;
width: 100%;
height: 100%;
}
button.with_skin {
padding: 0 4px;
background-color: black;
color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
button.with_skin:disabled {
background-color: #333333;
}
input.with_skin {
background-color: black;
color: white;
font-family: '맑은 고딕';
font-size: 13px;
}
input.with_skin:disabled {
background-color: #333333;
}
.font0 {
font-size: 10px;
}
.font1 {
font-size: 13px;
}
.font2 {
font-size: 15px;
}
.font3 {
font-size: 20px;
}
.font4 {
font-size: 30px;
}
.font5 {
font-size: 50px;
}
caption.section_title {
caption-side: top;
}
.samButton {
float: left;
display: block;
padding: 0;
margin: 0;
text-decoration: none;
position: relative;
}
a.samButton.disabled {
pointer-events: none;
cursor: default;
}
.samButtonOuter {
display: table;
border: outset 2px white;
box-sizing: border-box;
font-weight: bold;
padding: 1px 6px;
width: 125px;
height: 30px;
background-color: #000000;
color: #ffffff;
}
.samButtonOuter:active {
border: inset 2px white;
}
.samButtonInner {
display: table-cell;
vertical-align: middle;
width: 100%;
margin: 0 auto;
text-align: center;
user-select: none;
}
.samToolbarButton>.samButtonOuter {
width: 125px;
height: 30px;
background-color: #225500;
color: white;
}
.samToolbarButton2>.samButtonOuter {
width: 125px;
height: 30px;
background-color: #225500;
color: magenta;
}
.samCommandButton>.samButtonOuter {
width: 111px;
height: 30px;
}
.samCommandButton.disabled>.samButtonOuter {
background-color: transparent !important;
color: gray !important;
border-color: transparent !important;
}
.samCommandButton.disabled>.samButtonOuter>.samButtonInner::before {
content: '【'
}
.samCommandButton.disabled>.samButtonOuter>.samButtonInner::after {
content: '】'
}
.tooltip_copyable_info .tooltiptext {
display: inline;
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.tooltiptext {
display: none;
}
.hidden_but_copyable {
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.vertical_flex {
height: 100%;
display: flex;
align-content: center;
flex-direction: column;
align-items: stretch;
}
.vertical_flex .item {
display: block;
flex-grow: 1;
}
.fill_box {
display: block;
width: 100%;
height: 100%;
}
+155 -140
View File
@@ -1,141 +1,156 @@
@charset "utf-8";
body{
line-height: 1.3;
}
#server_notice {
margin:10px 0;
border: none;
text-align:center;
}
#server_list_container{
width:800px;
position:absolute;
left:50%;
margin-left:-400px;
}
#server_list_table{
width:100%;
}
#server_list tr{
height:66px;
}
#server_list .server_create_and_select .general_create,
#server_list .server_create_and_select .general_select {
width: 120px; height: 33px;
float: left;
}
#server_list .general_create,
#server_list .general_login {
width: 120px; height: 66px;
float: left;
}
.ignore_border{
border:0;
margin:0;
padding:0;
}
#user_info {
margin-top:20px;
width: 800px; height: 130px;
}
#user_info button{
width: 200px;
height: 50px;
margin: 10px 50px;
}
.center_ordered_items{
text-align:center;
}
.Entrance_ServerList {
width: 800px; height: 64px;
border: none;
float: left;
}
.Entrance_ServerListServer {
width: 98px; height: 64px;
float: left;
}
.Entrance_ServerListDown {
width: 698px; height: 64px;
float: left;
}
.Entrance_ServerListInfo {
width: 398px; height: 64px;
float: left;
}
.Entrance_ServerListBlock {
width: 298px; height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListCharacter {
width: 64px; height: 64px;
float: left;
}
.Entrance_ServerListName {
width: 112px; height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListSelect {
width: 120px; height: 32px;
float: left;
}
#Entrance_000003 {
width: 798px; height: 155px;
text-align: left;
}
.Entrance_Alert {
color: red; font-size: 15px; font-weight: bold;
}
.Entrance_Che {
color: white; font-size: 15px; font-weight: bold;
}
.Entrance_Kwe {
color: yellow; font-size: 15px; font-weight: bold;
}
.Entrance_Pwe {
color: orange; font-size: 15px; font-weight: bold;
}
.Entrance_Twe {
color: magenta; font-size: 15px; font-weight: bold;
}
.Entrance_Nya {
color: #e67e22; font-size: 15px; font-weight: bold;
}
.Entrance_Pya {
color: #9b59b6; font-size: 15px; font-weight: bold;
}
.Entrance_Hwe {
color: red; font-size: 15px; font-weight: bold;
@charset "utf-8";
body {
line-height: 1.3;
}
#server_notice {
margin: 10px 0;
border: none;
text-align: center;
}
#server_list_container {
width: 800px;
position: absolute;
left: 50%;
margin-left: -400px;
}
#server_list_table {
width: 100%;
}
#server_list tr {
height: 66px;
}
.ignore_border {
border: 0;
margin: 0;
padding: 0;
}
#user_info {
margin-top: 20px;
width: 800px;
height: 130px;
}
#user_info button {
width: 200px;
height: 50px;
margin: 10px 50px;
}
.center_ordered_items {
text-align: center;
}
.Entrance_ServerList {
width: 800px;
height: 64px;
border: none;
float: left;
}
.Entrance_ServerListServer {
width: 98px;
height: 64px;
float: left;
}
.Entrance_ServerListDown {
width: 698px;
height: 64px;
float: left;
}
.Entrance_ServerListInfo {
width: 398px;
height: 64px;
float: left;
}
.Entrance_ServerListBlock {
width: 298px;
height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListCharacter {
width: 64px;
height: 64px;
float: left;
}
.Entrance_ServerListName {
width: 112px;
height: 64px;
float: left;
line-height: 64px;
}
.Entrance_ServerListSelect {
width: 120px;
height: 32px;
float: left;
}
#Entrance_000003 {
width: 798px;
height: 155px;
text-align: left;
}
.Entrance_Alert {
color: red;
font-size: 15px;
font-weight: bold;
}
.Entrance_Che {
color: white;
font-size: 15px;
font-weight: bold;
}
.Entrance_Kwe {
color: yellow;
font-size: 15px;
font-weight: bold;
}
.Entrance_Pwe {
color: orange;
font-size: 15px;
font-weight: bold;
}
.Entrance_Twe {
color: magenta;
font-size: 15px;
font-weight: bold;
}
.Entrance_Nya {
color: #e67e22;
font-size: 15px;
font-weight: bold;
}
.Entrance_Pya {
color: #9b59b6;
font-size: 15px;
font-weight: bold;
}
.Entrance_Hwe {
color: red;
font-size: 15px;
font-weight: bold;
}
.BtnPlate {
height: inherit;
}
+1 -1
View File
@@ -117,7 +117,7 @@ function logError(string $err, string $errstr, string $errpath, array $trace)
]);
}
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext)
function logErrorByCustomHandler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext=null)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting, so let it fall
+6 -1
View File
@@ -59,8 +59,13 @@ foreach (getAllNationStaticInfo() as $nation) {
$nationName[$nation['nation']] = $nation['name'];
}
$generalList = $db->query('SELECT npc,nation,name,owner_name,special,special2,personal,leadership,strength,intel,leadership+strength+intel as sum,explevel,experience,dedication from general where npc=1');
$generalListFromPool = $db->query('SELECT npc,nation,name,owner_name,special,special2,personal,leadership,strength,intel,leadership+strength+intel as sum,explevel,experience,dedication from general JOIN select_pool on general.no = select_pool.general_id where npc=0');
if($generalListFromPool){
$generalList = array_merge($generalListFromPool, $generalList);
}
$sortType = [
1 => ['name', true],
2 => ['nation', true],
+65 -11
View File
@@ -148,8 +148,31 @@ echo "
unset($city);
// 첩보된 도시까지만 허용
if($valid == 0 && $userGrade < 5) {
$showDetailedInfo = false;
if($valid){
$showDetailedInfo = true;
}
if(!key_exists($citylist, CityConst::all())){
$citylist = $me['city'];
$showDetailedInfo = true;
$valid = 1;
}
if($userGrade >= 5){
$valid = true;
$showDetailedInfo = true;
}
if(!$valid) {
$ownCities = Util::convertArrayToSetLike($db->queryFirstColumn('SELECT city FROM city WHERE nation = %i AND nation != 0', $me['nation']));
foreach(array_keys(CityConst::byID($citylist)->path) as $pathID){
if(key_exists($pathID, $ownCities)){
$showDetailedInfo = true;
break;
}
}
}
@@ -172,11 +195,35 @@ if($city['trade'] === null) {
}
$dbColumns = General::mergeQueryColumn(['npc', 'defence_train', 'no', 'picture', 'imgsvr', 'name', 'injury', 'leadership', 'strength', 'intel', 'officer_level', 'nation', 'crewtype', 'crew', 'train', 'atmos'], 2)[0];
$generals = $db->query(
'SELECT %l from general where city=%i order by name',
Util::formatListOfBackticks($dbColumns),
$city['city']
);
if($showDetailedInfo){
$generals = $db->query(
'SELECT %l from general where city=%i order by turntime',
Util::formatListOfBackticks($dbColumns),
$city['city']
);
}
else{
$generals = [];
}
if($valid){
$city['trustText'] = round($city['trust'], 1);
$city['popRateText'] = round($city['pop']/$city['pop_max']*100, 2);
}
else{
$city['agri'] = '?';
$city['comm'] = '?';
$city['pop'] = '?';
$city['secu'] = '?';
$city['trustText'] = '?';
$city['popRateText'] = '?';
if($city['nation'] != 0){
$city['def'] = '?';
$city['wall'] = '?';
}
}
$generalTurnList = [];
@@ -257,6 +304,10 @@ foreach($generals as $general){
$crew = $general['crew'];
$train = -1;
$atmos = -1;
if(!$valid){
$crew = -1;
}
}
$nation = $general['nation'];
@@ -331,7 +382,9 @@ foreach($generalsFormat as $general){
}
if($general['nation'] != $myNation['nation']){
$enemyCnt += 1;
$enemyCrew += $general['crew'];
if($general['crew'] >= 0){
$enemyCrew += $general['crew'];
}
if($general['crew'] > 0){
$enemyArmedCnt += 1;
}
@@ -402,11 +455,11 @@ foreach($generalsFormat as $general){
</tr>
<tr>
<td align=center class=bg1>민심</td>
<td align=center><?=round($city['trust'], 1)?></td>
<td align=center><?=$city['trustText']?></td>
<td align=center class=bg1>시세</td>
<td align=center><?=$city['trade']?>%</td>
<td align=center class=bg1>인구</td>
<td align=center><?=round($city['pop']/$city['pop_max']*100, 2)?>%</td>
<td align=center><?=$city['popRateText']?>%</td>
<td align=center class=bg1>태수</td>
<td align=center><?=$officer[4]['name']?></td>
<td align=center class=bg1>군사</td>
@@ -430,11 +483,12 @@ foreach($generalsFormat as $general){
</tr>
<tr>
<td align=center class=bg1>장수</td>
<td colspan=11><?=join(', ', $generalsName)?></td>
<td colspan=11><?=$showDetailedInfo?join(', ', $generalsName):'<span style="color:gray">알 수 없음</span>'?></td>
</tr>
</table>
<br>
<?php if($showDetailedInfo): ?>
<table align=center class='tb_layout bg0'>
<thead>
<tr>
@@ -459,7 +513,7 @@ foreach($generalsFormat as $general){
?>
</tbody>
</table>
<?php endif; ?>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td><?=backButton()?></td></tr>
<tr><td><?=banner()?> </td></tr>
+6 -1
View File
@@ -14,7 +14,7 @@ $generalID = $session->generalID;
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user']);
$gameStor->cacheValues(['turntime', 'opentime', 'autorun_user', 'npcmode']);
increaseRefresh("내정보", 1);
@@ -113,6 +113,11 @@ var availableDieImmediately = <?=$availableDieImmediately?'true':'false'?>;
<a href="c_die_immediately.php" id='die_immediately'><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>장수 삭제</button></a><br><br>
<?php endif; ?>
<?php if($gameStor->npcmode==2 && $me->getNPCType()==0): ?>
다른 장수 선택 (<?=substr($me->getAuxVar('next_change')??TimeUtil::now(), 0, 19)?> 부터)<br>
<a href="select_general_from_pool.php" id='select_general_from_pool'><button type="button" style=background-color:<?=GameConst::$basecolor2?>;color:white;width:160px;height:30px;font-size:13px;>다른 장수 선택</button></a><br><br>
<?php endif; ?>
개인용 CSS<br>
<textarea id='custom_css' style='color:white;background-color:black;width:420px;height:150px;'></textarea>
</td>
+155 -135
View File
@@ -1,40 +1,56 @@
@charset "UTF-8";
/* font-boostring Block */
html * {max-height:1000000px;}
html, body{
background-color:black;
color:white;
line-height:1.3;
font-family:'맑은 고딕';
font-size:13px;
html * {
max-height: 1000000px;
}
table { font-family:'맑은 고딕'; }
font { font-family:'맑은 고딕'; }
input { font-family:'맑은 고딕'; font-size:13px; }
select { font-family:'굴림'; line-height:100%; }
.center{
text-align:center;
html,
body {
background-color: black;
color: white;
line-height: 1.3;
font-family: '맑은 고딕';
font-size: 13px;
}
table.mimic_flex{
table {
font-family: '맑은 고딕';
}
font {
font-family: '맑은 고딕';
}
input {
font-family: '맑은 고딕';
font-size: 13px;
}
select {
font-family: '굴림';
line-height: 100%;
}
.center {
text-align: center;
}
table.mimic_flex {
border-collapse: collapse;
border:none;
padding:0;
border: none;
padding: 0;
}
.mimic_flex td, .mimic_flex th {
border:none !important;
.mimic_flex td,
.mimic_flex th {
border: none !important;
padding: 0px;
word-break: break-all;
}
table.tb_layout {
table.tb_layout {
border-collapse: collapse;
padding: 0px;
font-size: 13px;
@@ -42,159 +58,161 @@ table.tb_layout {
font-family: '맑은 고딕';
}
.tb_layout td, .tb_layout th {
border:solid 1px gray;
.tb_layout td,
.tb_layout th {
border: solid 1px gray;
padding: 0px;
word-break: break-all;
font-family: '맑은 고딕';;
font-family: '맑은 고딕';
;
}
div.bar_out{
position:relative;
border-top:solid 1px #888888;
border-bottom:solid 1px #333333;
padding:0;
margin:0;
width:100%;
div.bar_out {
position: relative;
border-top: solid 1px #888888;
border-bottom: solid 1px #333333;
padding: 0;
margin: 0;
width: 100%;
overflow: hidden;
}
div.bar_out div{
position:absolute;
left:0;
top:0;
height:100%;
div.bar_out div {
position: absolute;
left: 0;
top: 0;
height: 100%;
}
div.bar_out div.bar_in{
width:100%;
div.bar_out div.bar_in {
width: 100%;
}
/* */
.ev_warning{
color:orangered;
.ev_warning {
color: orangered;
}
.ev_notice{
color:orangered;
.ev_notice {
color: orangered;
}
.ev_succes{
color:lightgreen;
.ev_succes {
color: lightgreen;
}
.ev_sell{
color:orange;
.ev_sell {
color: orange;
}
.ev_failed{
color:orangered;
.ev_failed {
color: orangered;
}
.ev_highlight{
color:orangered;
.ev_highlight {
color: orangered;
}
/* TODO: 색상값이 아니라 의미에 따라 클래스 지정 */
.o_bullet::before{
color:cyan;
content:"●";
.o_bullet::before {
color: cyan;
content: "●";
}
.o_diamond::before{
color:orangered;
content:"◆";
.o_diamond::before {
color: orangered;
content: "◆";
}
.small_war_log{
display:inline-block;
.small_war_log {
display: inline-block;
}
.small_war_log .war_type_attack{
color:cyan;
.small_war_log .war_type_attack {
color: cyan;
}
.small_war_log .war_type_defense{
color:magenta;
.small_war_log .war_type_defense {
color: magenta;
}
.small_war_log .war_type_siege{
color:white;
.small_war_log .war_type_siege {
color: white;
}
.small_war_log .name_plate{
.small_war_log .name_plate {
font-size: 0.75em;
}
.small_war_log .name_plate_cover{
color:yellow;
.small_war_log .name_plate_cover {
color: yellow;
}
.small_war_log .crew_plate{
color:orangered;
font-size:90%;
.small_war_log .crew_plate {
color: orangered;
font-size: 90%;
}
.t_date{
.t_date {
font-size: 0.75em;
}
.t_red{
color:red;
.t_red {
color: red;
}
.t_blue{
color:blue;
.t_blue {
color: blue;
}
.t_green{
color:green;
.t_green {
color: green;
}
.t_magenta{
color:magenta;
.t_magenta {
color: magenta;
}
.t_cyan{
color:cyan;
.t_cyan {
color: cyan;
}
.t_limegreen{
color:limegreen;
.t_limegreen {
color: limegreen;
}
.t_skyblue{
color:skyblue;
.t_skyblue {
color: skyblue;
}
.t_orangered{
color:orangered;
.t_orangered {
color: orangered;
}
.t_yellow{
color:yellow;
.t_yellow {
color: yellow;
}
.t_white{
color:white;
.t_white {
color: white;
}
.float_left{
float:left;
.float_left {
float: left;
}
.tooltip{
font-size:12px;
.tooltip {
font-size: 12px;
font-family: '맑은 고딕';
}
.tooltip_copyable_info .tooltiptext{
.tooltip_copyable_info .tooltiptext {
display: inline;
color: rgba(0,0,0,0);
color: rgba(0, 0, 0, 0);
font-size: 0;
}
@@ -202,67 +220,69 @@ div.bar_out div.bar_in{
display: none;
}
.hidden_but_copyable{
color: rgba(0,0,0,0);
.hidden_but_copyable {
color: rgba(0, 0, 0, 0);
font-size: 0;
}
.btn-group-xs > .btn, .btn-xs {
padding : .25rem .4rem;
font-size : .875rem;
line-height : .5;
border-radius : .2rem;
.btn-group-xs>.btn,
.btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: .5;
border-radius: .2rem;
}
.edit_form.viewer{
max-height:200px;
overflow-y:auto;
.edit_form.viewer {
max-height: 200px;
overflow-y: auto;
}
.trumbowyg-box{
margin:0;
border-left:none;
border-right:none;
.trumbowyg-box {
margin: 0;
border-left: none;
border-right: none;
}
.edit_form.trumbowyg-editor{
margin:0;
padding:0;
.edit_form.trumbowyg-editor {
margin: 0;
padding: 0;
}
.commandBasic{
background-color:black;
color:white;
.commandBasic {
background-color: black;
color: white;
}
.compensatePositive{
color:skyblue;
.compensatePositive {
color: skyblue;
}
.compensateNegative{
color:orange;
.compensateNegative {
color: orange;
}
.compensateNeutral{
color:white;
.compensateNeutral {
color: white;
}
.commandBasic.commandImpossible{
background-color:red;
color:white;
.commandBasic.commandImpossible {
background-color: red;
color: white;
}
.select2-selection--single.simple-select2-align-center .select2-selection__rendered {
text-align: center;
}
.select2-dropdown.simple-select2-align-center li.select2-results__option{
.select2-dropdown.simple-select2-align-center li.select2-results__option {
text-align: center;
}
.select2-container--bootstrap4 .select2-selection--single.text-secondary .select2-selection__rendered{
color:white;
.select2-container--bootstrap4 .select2-selection--single.text-secondary .select2-selection__rendered {
color: white;
}
.select2-container--bootstrap4 .text-secondary .select2-results__option[aria-selected=false]{
color:white;
}
.select2-container--bootstrap4 .text-secondary .select2-results__option[aria-selected=false] {
color: white;
}
+64
View File
@@ -0,0 +1,64 @@
@charset "UTF-8";
.container {
width: 1000px;
margin: 0 auto;
}
.card_holder {
text-align: center;
}
.general_card {
width: 125px;
display: inline-block;
}
.general_card h4 {
margin: 0;
}
.general_card p {
margin: 0;
}
.general_card .select_btn {
width: 100%;
}
.general_card label {
display: block;
padding-left: 15px;
text-indent: -15px;
}
.general_card input {
width: 13px;
height: 13px;
padding: 0;
margin: 0;
vertical-align: bottom;
position: relative;
top: -1px;
*overflow: hidden;
}
#outdate_token {
color: red;
display: none;
}
#left_pad button {
display: none;
}
.custom_picture {
display: none;
}
.custom_personality {
display: none;
}
.custom_stat {
display: none;
}
+47 -15
View File
@@ -1224,7 +1224,7 @@ function updateOnline()
//동접수
$before5Min = TimeUtil::nowAddMinutes(-5);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh > %s', $before5Min);
$onlineUser = $db->query('SELECT no,name,nation FROM general WHERE lastrefresh > %s AND npc < 2', $before5Min);
$onlineNum = count($onlineUser);
$onlineNationUsers = Util::arrayGroupBy($onlineUser, 'nation');
@@ -1537,7 +1537,18 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
//일단은 '획득' 시에만 동작하므로 이대로 사용하기로...
$occupiedUnique = [];
$invalidItemType = [];
foreach(array_keys(GameConst::$allItems) as $itemType){
$ownItem = $general->getItems()[$itemType]??null;
if($ownItem !== null && !$ownItem->isBuyable()){
$invalidItemType[$itemType] = true;
}
}
foreach (array_keys(GameConst::$allItems) as $itemType) {
if(key_exists($itemType, $invalidItemType)){
continue;
}
foreach ($db->queryAllLists('SELECT %b, count(*) as cnt FROM general GROUP BY %b', $itemType, $itemType) as [$itemCode, $cnt]) {
$itemClass = buildItemClass($itemCode);
if (!$itemClass) {
@@ -1551,6 +1562,9 @@ function giveRandomUniqueItem(General $general, string $acquireType): bool
}
foreach (GameConst::$allItems as $itemType => $itemCategories) {
if(key_exists($itemType, $invalidItemType)){
continue;
}
foreach ($itemCategories as $itemCode => $cnt) {
if (!key_exists($itemCode, $occupiedUnique)) {
$availableUnique[] = [[$itemType, $itemCode], $cnt];
@@ -1604,38 +1618,56 @@ function tryUniqueItemLottery(General $general, string $acquireType = '아이템
return false;
}
$itemTypeCnt = count(GameConst::$allItems);
$trialCnt = $itemTypeCnt;
foreach ($general->getItems() as $item) {
if (!$item) {
continue;
}
if (!$item->isBuyable()) {
return false;
$trialCnt -= 1;
}
}
if($trialCnt <= 0){
LogText("{$general->getName()}, {$general->getID()} 모든 아이템", $trialCnt);
return false;
}
$scenario = $gameStor->scenario;
$genCount = $db->queryFirstField('SELECT count(*) FROM general WHERE npc<2');
if ($scenario < 100) {
$prob = 1 / ($genCount * 5); // 5~6개월에 하나씩 등장
$prob = 1 / ($genCount * 3 * $itemTypeCnt); // 3~4개월에 하나씩 등장
} else {
$prob = 1 / $genCount; // 1~2개월에 하나씩 등장
$prob = 1 / ($genCount * $itemTypeCnt); // 1~2개월에 하나씩 등장
}
if ($acquireType == '설문조사') {
$prob = 1 / ($genCount * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장
$prob = 1 / ($genCount * $itemTypeCnt * 0.7 / 3); // 투표율 70%, 설문조사 한번에 2~3개 등장
} else if ($acquireType == '랜덤 임관') {
$prob = 1 / ($genCount / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 2); // 랜임시 2개(10%) 등장(200명중 20명 랜임시도?)
} else if ($acquireType == '건국') {
$prob = 1 / ($genCount / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
$prob = 1 / ($genCount * $itemTypeCnt / 10 / 4); // 건국시 4개(20%) 등장(200명시 20국 정도 됨)
}
$prob = Util::valueFit($prob, null, 1 / 3);
$prob = Util::valueFit($prob, null, 1 / 4);//최대치 감소
$result = false;
if (!Util::randBool($prob)) {
foreach(Util::range($trialCnt) as $_idx){
if (Util::randBool($prob)) {
$result = true;
break;
}
}
if(!$result){
LogText("{$general->getName()}, {$general->getID()} 유니크 실패 {$trialCnt}", $prob);
return false;
}
LogText("{$general->getName()}, {$general->getID()} 유니크 성공 {$trialCnt}", $prob);
return giveRandomUniqueItem($general, $acquireType);
}
@@ -1736,7 +1768,7 @@ function nextRuler(General $general)
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month] = $gameStor->getValuesAsArray(['year', 'month']);
[$year, $month, $fiction] = $gameStor->getValuesAsArray(['year', 'month', 'fiction']);
$nation = $general->getStaticNation();
$nationName = $nation['name'];
$nationID = $nation['nation'];
@@ -1744,7 +1776,7 @@ function nextRuler(General $general)
$candidate = null;
//npc or npc유저인 경우 후계 찾기
if ($general->getNPCType() > 0) {
if (!$fiction && $general->getNPCType() > 0) {
$candidate = $db->queryFirstRow(
'SELECT no,name,officer_level,IF(ABS(affinity-%i)>75,150-ABS(affinity-%i),ABS(affinity-%i)) as npcmatch2 from general where nation=%i and officer_level!=12 and 1 <= npc and npc<=3 order by npcmatch2,rand() LIMIT 1',
$general->getVar('affinity'),
+24
View File
@@ -378,6 +378,30 @@ function buildWarUnitTriggerClass(?string $type, WarUnit $unit, ?array $args = n
return $class->newInstanceArgs(array_merge([$unit], $args));
}
function getGeneralPoolClass(string $type){
static $basePath = __NAMESPACE__.'\\GeneralPool\\';
$classPath = ($basePath.$type);
if(class_exists($classPath)){
return $classPath;
}
throw new \InvalidArgumentException("{$type}은 GeneralPool이 아님");
}
/**
* @param \MeekroDB $db
* @param int $owner
* @param int $pickCnt
* @param null|string $prefix
* @return AbsGeneralPool[]
*/
function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{
/** @var AbsGeneralPool */
$class = getGeneralPoolClass(GameConst::$targetGeneralPool);
return $class::pickGeneralFromPool($db, $owner, $pickCnt, $prefix);
}
function countPureGeneralFromRawList(?array $rawGeneralList=null):int{
if(!$rawGeneralList){
return 0;
+17 -22
View File
@@ -627,14 +627,15 @@ function updateNationState()
$uniqueLotteryWeightList = [];
foreach ($nationGenList as $nationGen) {
$hasUnique = false;
$trialCnt = count(GameConst::$allItems);
foreach ($nationGen->getItems() as $item) {
if (!$item->isBuyable()) {
$hasUnique = true;
break;
$trialCnt -= 1;
}
}
if ($hasUnique) {
if ($trialCnt <= 0) {
continue;
}
@@ -647,6 +648,9 @@ function updateNationState()
} else if ($nationGen->getVar('officer_level') > 4) {
$score += 35;
}
$score *= $trialCnt;
$uniqueLotteryWeightList[$nationGen->getID()] = [$nationGen, $score];
}
@@ -680,31 +684,22 @@ function updateNationState()
while ($assemblerCnt < $maxAssemblerCnt) {
$lastAssemblerID += 1;
$npcObj = new Scenario\NPC(
999,
$npcObj = new Scenario\GeneralBuilder(
sprintf('부대장%4d', $lastAssemblerID),
0,
null,
$nation['nation'],
null,
10,
10,
10,
1,
$admin['year'] - 15,
$admin['year'] + 15,
'은둔',
'척사'
$nation['nation']
);
$npcObj->killturn = 70;
$npcObj->gold = 0;
$npcObj->rice = 0;
$npcObj->npc = 5;
$npcObj->setAffinity(999)->setStat(10, 10, 10)
->setSpecialSingle('척사')->setEgo('che_은둔')
->setKillturn(70)->setGoldRice(0, 0)
->setNPCType(5)->fillRemainSpecAsZero($admin);
$npcObj->build($admin);
$npcID = $npcObj->generalID;
$npcID = $npcObj->getGeneralID();
$db->insert('troop', [
'troop_leader' => $npcID,
'name' => $npcObj->realName,
'name' => $npcObj->getGeneralName(),
'nation' => $nation['nation'],
]);
$db->update('general', [
+6 -4
View File
@@ -79,9 +79,11 @@ if ($gameStor->fiction == 0) {
}
if ($gameStor->npcmode == 0) {
$npcmode = "불가능";
} else {
} else if($gameStor->npcmode == 1){
$npcmode = "가능";
$valid = 1;
} else {
$npcmode = "선택 생성";
}
$color = "cyan";
$mapTheme = $gameStor->map_theme;
@@ -134,7 +136,7 @@ $(function(){
<body class="img_back">
<div id="container">
<div><?=allButton($gameStor->npcmode!=0)?></div>
<div><?=allButton($gameStor->npcmode==1)?></div>
<table class="tb_layout bg0" style="width:1000px;">
<tr height=50>
<td colspan=5 id="server_title" align=center><font size=4>삼국지 모의전투 HiDCHe <?=$serverName.$serverCnt?>기 (<font color=cyan><?=$scenario?></font>)</font></td>
@@ -341,7 +343,7 @@ else if($session->userGrade == 4){
<button id="msg_submit">서신전달&amp;갱신</button><br>
내용 없이 '서신전달&amp;갱신'을 누르면 메세지창이 갱신됩니다.
</div>
<div><?=allButton($gameStor->npcmode!=0)?></div>
<div><?=allButton($gameStor->npcmode==1)?></div>
<div id="message_board"><div style="left:0;" class="board_side bg0">
<div class="board_header bg0" id='public_talk_position'>전체 메시지(최고99자)</div>
<section class="public_message">
@@ -361,7 +363,7 @@ else if($session->userGrade == 4){
<button type="button" class="load_old_message btn btn-secondary btn-block" data-msg_type="diplomacy">이전 메시지 불러오기</button>
</section>
</div></div>
<div style="clear:left;"><?=allButton($gameStor->npcmode!=0)?><?=banner()?></div>
<div style="clear:left;"><?=allButton($gameStor->npcmode==1)?><?=banner()?></div>
</div>
<?php
if ($con == 1) {
+18 -1
View File
@@ -102,7 +102,7 @@ if($session->userGrade < 5 && !$allowReset){
</div>
<div class="form-group row">
<label for="confirm_password" class="col-sm-3 col-form-label">시나리오 선택</label>
<label for="scenario_sel" class="col-sm-3 col-form-label">시나리오 선택</label>
<div class="col-sm-9">
<select class="form-control" name="scenario" size="1" id="scenario_sel">
</select>
@@ -138,6 +138,20 @@ if($session->userGrade < 5 && !$allowReset){
</div>
</div>
<div class="form-group row">
<label for="block_general_create" class="col-sm-3 col-form-label">장수 임의 생성</label>
<div class="col-sm-9">
<div id="block_general_create" class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-secondary">
<input type="radio" name="block_general_create" value="0" checked>가능
</label>
<label class="btn btn-secondary active">
<input type="radio" name="block_general_create" value="1">불가
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="npcmode" class="col-sm-3 col-form-label">NPC 빙의</label>
<div class="col-sm-9">
@@ -148,6 +162,9 @@ if($session->userGrade < 5 && !$allowReset){
<label class="btn btn-secondary active">
<input type="radio" name="npcmode" value="0" checked>불가
</label>
<label class="btn btn-secondary">
<input type="radio" name="npcmode" value="2">선택 생성 가능
</label>
</div>
</div>
</div>
+1
View File
@@ -85,6 +85,7 @@ $result = ResetHelper::buildScenario(
$options['scenario'],
$options['fiction'],
$options['extend'],
$options['block_general_create'],
$options['npcmode'],
$options['show_img_level'],
$options['tournament_trig'],
+1 -1
View File
@@ -37,7 +37,7 @@ list(
$npcmode
) = $gameStor->getValuesAsArray(['maxgeneral', 'turnterm', 'npcmode']);
if(!$npcmode){
if($npcmode!=1){
Json::die([
'result'=>false,
'reason'=>'빙의 가능한 서버가 아닙니다'
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
function sortTokens(&$tokens){
usort($tokens, function($lhs, $rhs){
return array_sum($lhs['dex'])<=>array_sum($rhs['dex']);
});
}
function putInfoText(&$info){
if(key_exists('specialDomestic', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialDomestic']);
$info['specialDomesticName'] = $class->getName();
$info['specialDomesticInfo'] = $class->getInfo();
}
if(key_exists('specialWar', $info)){
$class = buildGeneralSpecialDomesticClass($info['specialWar']);
$info['specialWarName'] = $class->getName();
$info['specialWarInfo'] = $class->getInfo();
}
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$npcmode = $gameStor->getValue('npcmode');
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$rawGeneral = $db->queryFirstRow('SELECT no, aux FROM general WHERE `owner` = %i', $userID);
if($rawGeneral){
$generalAux = Json::decode($rawGeneral['aux']);
if(key_exists('next_change', $generalAux)&& $generalAux['next_change'] > $now){
Json::die([
'result'=>false,
'reason'=>'아직 다시 고를 수 없습니다'
]);
}
}
$tokens = $db->query('SELECT unique_name, reserved_until, info FROM `select_pool` WHERE `owner`=%i AND `reserved_until`>=%s', $userID, $now);
if($tokens){
$pick = [];
$valid_until = null;
$specialInfo = [];
foreach($tokens as $token){
$valid_until = $token['reserved_until'];
$info = Json::decode($token['info']);
putInfoText($info);
$info['uniqueName'] = $token['unique_name'];
$pick[] = $info;
}
sortTokens($pick);//좀 무식하지만..
Json::die([
'result'=>true,
'pick'=>$pick,
'validUntil'=>$valid_until
]);
}
$pick = [];
$valid_until = null;
foreach(pickGeneralFromPool($db, $userID, 14) as $pickObj){
$valid_until = $pickObj->getValidUntil();
$info = $pickObj->getInfo();
putInfoText($info);
$pick[] = $info;
}
sortTokens($pick);//좀 무식하지만..
Json::die([
'result'=>true,
'pick'=>$pick,
'validUntil'=>$valid_until
]);
+6
View File
@@ -57,6 +57,7 @@ $v->rule('required', [
'scenario',
'fiction',
'extend',
'block_general_create',
'join_mode',
'npcmode',
'show_img_level',
@@ -67,6 +68,7 @@ $v->rule('required', [
'scenario',
'fiction',
'extend',
'block_general_create',
'npcmode',
'show_img_level',
'tournament_trig',
@@ -109,11 +111,13 @@ $scenario = (int)$_POST['scenario'];
$fiction = (int)$_POST['fiction'];
$extend = (int)$_POST['extend'];
$npcmode = (int)$_POST['npcmode'];
$block_general_create = (bool)$_POST['block_general_create'];
$show_img_level = (int)$_POST['show_img_level'];
$tournament_trig = (int)$_POST['tournament_trig'];
$join_mode = $_POST['join_mode'];
$autorun_user_minutes = (int)$_POST['autorun_user_minutes'];
$autorun_user_options = [];
foreach(Util::getPost('autorun_user', 'array_string', []) as $autorun_option){
$autorun_user_options[$autorun_option] = 1;
}
@@ -165,6 +169,7 @@ if($reserve_open){
'scenarioName'=>$scenarioObj->getTitle(),
'fiction'=>$fiction,
'extend'=>$extend,
'block_general_create'=>$block_general_create,
'npcmode'=>$npcmode,
'show_img_level'=>$show_img_level,
'tournament_trig'=>$tournament_trig,
@@ -200,6 +205,7 @@ Json::die(ResetHelper::buildScenario(
$scenario,
$fiction,
$extend,
$block_general_create,
$npcmode,
$show_img_level,
$tournament_trig,
+1 -1
View File
@@ -59,7 +59,7 @@ list(
$npcmode
) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode']);
if(!$npcmode){
if($npcmode!=1){
Json::die([
'result'=>false,
'reason'=>'빙의 가능한 서버가 아닙니다'
+170
View File
@@ -0,0 +1,170 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$pick = Util::getPost('pick');
$leadership = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$strength = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$intel = Util::getPost('leadership', 'int', GameConst::$defaultStatMin);
$personal = Util::getPost('personal', 'string', null);
$use_own_picture = Util::getPost('use_own_picture', 'bool', false);
if(!$pick){
Json::die([
'result'=>false,
'reason'=>'장수를 선택하지 않았습니다'
]);
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$hasGeneralID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if($hasGeneralID){
Json::die([
'result'=>false,
'reason'=>'이미 장수를 생성했습니다.'
]);
}
$env = $gameStor->getValues(['startyear', 'year', 'month', 'maxgeneral', 'npcmode', 'show_img_level', 'icon_path', 'turnterm', 'turntime']);
$env['fiction'] = false;
$npcmode = $env['npcmode'];
$maxgeneral = $env['maxgeneral'];
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$selectInfo = $db->queryFirstField('SELECT info FROM select_pool WHERE `owner` = %i AND `reserved_until`>=%s AND `unique_name`=%s', $userID, $now, $pick);
if(!$selectInfo){
Json::die([
'result'=>false,
'reason'=>'유효한 장수 목록이 없습니다.'
]);
}
$selectInfo = Json::decode($selectInfo);
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
if(!$ownerInfo){
Json::die([
'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.'
]);
}
$gencount = $db->queryFirstField('SELECT count(`no`) FROM general WHERE npc<2');
if ($gencount >= $maxgeneral) {
Json::die([
'result'=>false,
'reason'=>'더 이상 등록 할 수 없습니다.'
]);
}
$poolClass = getGeneralPoolClass(GameConst::$targetGeneralPool);
/** @var AbsGeneralPool */
$pickedGeneral = new $poolClass($db, $selectInfo, $now);
$builder = $pickedGeneral->getGeneralBuilder();
foreach(GameConst::$generalPoolAllowOption as $allowOption){
if($allowOption == 'stat'){
$leadership = Util::valueFit($leadership, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$strength = Util::valueFit($strength, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
$intel = Util::valueFit($intel, GameConst::$defaultStatMin, GameConst::$defaultStatMax);
if($leadership + $strength + $intel > GameConst::$defaultStatTotal){
Json::die([
'result'=>false,
'reason'=>'스탯의 총 합이 올바르지 않습니다.'
]);
}
$builder->setStat($leadership, $strength, $intel);
}
else if($allowOption == 'picture' && $use_own_picture){
$builder->setPicture($ownerInfo['imgsvr'], $ownerInfo['picture']);
}
else if($allowOption == 'ego'){
if(!$personal || $personal == 'Random'){
$personal = Util::choiceRandom(GameConst::$availablePersonality);
}
if(!array_search($personal, GameConst::$availablePersonality)){
Json::die([
'result'=>false,
'reason'=>'올바르지 않은 성격입니다.'
]);
}
$builder->setEgo($personal);
}
}
$userNick = $ownerInfo['name'];
$builder->setOwner($userID);
$builder->setOwnerName($userNick);
$builder->setKillturn(5);
$builder->setNPCType(0);
$builder->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $env['turnterm']));
$builder->fillRemainSpecAsZero($env);
$builder->build($env);
$generalID = $builder->getGeneralID();
if(!$generalID){
Json::die([
'result'=>false,
'reason'=>'장수 등록에 실패했습니다.'
]);
}
$pickedGeneral->occupyGeneralName();
$db->update('select_pool',[
'owner'=>null,
'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
$josaYi = JosaUtil::pick($userNick, '이');
$generalName = $builder->getGeneralName();
$josaRo = JosaUtil::pick($generalName, '로');
$cityName = CityConst::byID($builder->getCityID())->name;
$logger = new ActionLogger($generalID, 0, $env['year'], $env['month']);
$logger->pushGeneralHistoryLog("<Y>{$generalName}</>, <G>{$cityName}</>에서 등장");
$logger->pushGlobalActionLog("<G><b>{$cityName}</b></>에서 <Y>{$userNick}</>{$josaYi} <Y>{$generalName}</>{$josaRo} 등장합니다.");
$logger->flush();
pushAdminLog(["가입 : {$userID} // {$session->userName} // {$pick} // ".getenv("REMOTE_ADDR")]);
$rootDB->insert('member_log', [
'member_no' => $userID,
'date'=>TimeUtil::now(),
'action_type'=>'make_general',
'action'=>Json::encode([
'server'=>DB::prefix(),
'type'=>'select',
'generalID'=>$generalID,
'generalName'=>$generalName
])
]);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+6 -5
View File
@@ -43,7 +43,7 @@ $session = Session::requireLogin([
'game'=>null,
'me'=>null
])->setReadOnly();
$userID = Session::getUserID();
$userID = $session->userID;
if(!class_exists('\\sammo\\DB')){
Json::die([
@@ -91,7 +91,8 @@ if(file_exists(__DIR__.'/.htaccess')){
'scenarioName'=>$options['scenarioName'],
'turnterm'=>$options['turnterm'],
'fictionMode'=>($options['fiction']?'가상':'사실'),
'npcMode'=>($options['npcmode']?'가능':'불가'),
'block_general_create'=>(!!$options['block_general_create']),
'npcMode'=>([0=>'불가',1=>'가능',2=>'선택 생성'][$options['npcmode']]),
'openDatetime'=>$reserved['date'],
'starttime'=>$options['starttime'],
'gameConf'=>$options['gameConf'],
@@ -104,7 +105,7 @@ if(file_exists(__DIR__.'/.htaccess')){
//TODO: 천통시에도 예약 오픈 알림이 필요..?
$admin = $gameStor->getValues(['isunited', 'npcmode', 'year', 'month', 'scenario', 'scenario_text', 'maxgeneral', 'turnterm', 'opentime', 'turntime', 'join_mode', 'fiction', 'autorun_user']);
$admin = $gameStor->getValues(['isunited', 'npcmode', 'year', 'month', 'scenario', 'scenario_text', 'maxgeneral', 'turnterm', 'opentime', 'turntime', 'join_mode', 'fiction', 'block_general_create', 'autorun_user']);
$admin['maxUserCnt'] = $admin['maxgeneral'];
$admin['npcMode'] = $admin['npcmode'];
$admin['turnTerm'] = $admin['turnterm'];
@@ -124,8 +125,8 @@ $admin['scenario'] = $admin['scenario_text'];
$admin['userCnt'] = $genCnt;
$admin['npcCnt'] = $npcCnt;
$admin['nationCnt'] = $nationCnt;
$admin['npcMode'] = $admin['npcMode']?'가능':'불가';
$admin['block_general_create'] = !!$admin['block_general_create'];
$admin['npcMode'] = [0=>'불가',1=>'가능',2=>'선택 생성'][$admin['npcMode']];
$admin['fictionMode'] = $admin['fiction']?'가상':'사실';
$otherTextInfo = [];
+2 -2
View File
@@ -43,8 +43,8 @@ if($defence_train != $me->getVar('defence_train')){
if($defence_train == 999){
$me->increaseVar('myset', -1);
$me->setVar('defence_train', $defence_train);
$me->increaseVar('train', -3);
$me->increaseVar('atmos', -3);
$me->increaseVarWithLimit('train', -3, 20);
$me->increaseVarWithLimit('atmos', -3, 20);
}
else{
$me->increaseVar('myset', -1);
+151
View File
@@ -0,0 +1,151 @@
<?php
namespace sammo;
include "lib.php";
include "func.php";
WebUtil::requireAJAX();
$pick = Util::getPost('pick');
if(!$pick){
Json::die([
'result'=>false,
'reason'=>'장수를 선택하지 않았습니다'
]);
}
$session = Session::requireLogin([])->setReadOnly();
$userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$rootDB = RootDB::db();
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$generalID = $db->queryFirstField('SELECT no FROM general WHERE owner = %i', $userID);
if(!$generalID){
Json::die([
'result'=>false,
'reason'=>'장수가 생성하지 않았습니다. 이미 사망하지 않았는지 확인해보세요.'
]);
}
list(
$year,
$month,
$maxgeneral,
$npcmode,
$turnterm
) = $gameStor->getValuesAsArray(['year', 'month', 'maxgeneral', 'npcmode', 'turnterm']);
if($npcmode!=2){
Json::die([
'result'=>false,
'reason'=>'선택 가능한 서버가 아닙니다'
]);
}
$info = $db->queryFirstField('SELECT info FROM select_pool WHERE `owner` = %i AND `reserved_until`>=%s AND `unique_name`=%s', $userID, $now, $pick);
if(!$info){
Json::die([
'result'=>false,
'reason'=>'유효한 장수 목록이 없습니다.'
]);
}
$ownerInfo = RootDB::db()->queryFirstRow('SELECT `name`,`picture`,`imgsvr` FROM member WHERE `NO`=%i',$userID);
if(!$ownerInfo){
Json::die([
'result'=>false,
'reason'=>'멤버 정보를 가져오지 못했습니다.'
]);
}
$info = Json::decode($info);
$generalObj = General::createGeneralObjFromDB($generalID);
$oldGeneralName = $generalObj->getName();
$db->update('select_pool', [
'general_id'=>-$generalID,
'owner'=>null,
'reserved_until'=>null
], 'unique_name=%s AND `reserved_until` IS NOT NULL AND owner = %i', $info['uniqueName'], $userID);
if($db->affectedRows()==0){
Json::die([
'result'=>false,
'reason'=>'동시성 제어에 문제가 발생했습니다. 버그 제보를 부탁드립니다.'
]);
}
$db->update('select_pool', [
'general_id'=>null,
'owner'=>null,
'reserved_until'=>null,
], 'unique_name != %s AND general_id = %i', $info['uniqueName'], $generalID);
$db->update('select_pool', [
'general_id'=>$generalID,
], 'general_id=%i', -$generalID);
if($db->affectedRows()==0){
Json::die([
'result'=>false,
'reason'=>'장수 선택 과정에 문제가 발생했습니다.. 버그 제보를 부탁드립니다.'
]);
}
$db->update('select_pool',[
'owner'=>null,
'reserved_until'=>null,
], '(owner=%i or reserved_until < %s) AND general_id is NULL', $userID, $now);
if(key_exists('leadership', $info)){
$generalObj->updateVar('leadership', $info['leadership']);
$generalObj->updateVar('strength', $info['strength']);
$generalObj->updateVar('intel', $info['intel']);
}
if(key_exists('picture', $info)){
$generalObj->updateVar('imgsvr', $info['imgsvr']);
$generalObj->updateVar('picture', $info['picture']);
}
if(key_exists('generalName', $info)){
$generalObj->updateVar('name', $info['generalName']);
}
if(key_exists('dex', $info)){
$generalObj->updateVar('dex1', $info['dex'][0]);
$generalObj->updateVar('dex2', $info['dex'][1]);
$generalObj->updateVar('dex3', $info['dex'][2]);
$generalObj->updateVar('dex4', $info['dex'][3]);
$generalObj->updateVar('dex5', $info['dex'][4]);
}
if(key_exists('ego', $info)){
$generalObj->updateVar('personal', $info['ego']);
}
if(key_exists('specialDomestic', $info)){
$generalObj->updateVar('special', $info['specialDomestic']);
}
if(key_exists('specialWar', $info)){
$generalObj->updateVar('special2', $info['specialWar']);
}
$generalObj->setAuxVar('next_change', TimeUtil::nowAddMinutes(12 * $turnterm));
$userNick = $ownerInfo['name'];
$generalObj->setVar('owner_name', $userNick);
$josaYi = JosaUtil::pick($userNick, '이');
$generalName = $info['generalName'];
$josaRo = JosaUtil::pick($generalName, '로');
$logger = $generalObj->getLogger();
$logger->pushGeneralHistoryLog("장수를 <Y>{$oldGeneralName}</>에서 <Y>{$generalName}</>{$josaRo} 변경");
$logger->pushGlobalActionLog("<Y>{$userNick}</>{$josaYi} 장수를 <Y>{$oldGeneralName}</>에서 <Y>{$generalName}</>{$josaRo} 변경합니다.");
$generalObj->applyDB($db);
Json::die([
'result'=>true,
'reason'=>'success'
]);
+6 -2
View File
@@ -24,7 +24,12 @@ if (!$member) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$admin = $gameStor->getValues(['block_general_create','show_img_level','maxgeneral']);
if($admin['block_general_create']){
MessageBox("잘못된 접근입니다!!!");
echo "<script>history.go(-1);</script>";
exit(1);
}
?>
<!DOCTYPE html>
<html>
@@ -66,7 +71,6 @@ echo Json::encode((object)$charInfoText);
<tr><td align=center><?=info(0)?></td></tr>
</table>
<?php
$admin = $gameStor->getValues(['show_img_level','maxgeneral']);
$gencount = $db->queryFirstField('SELECT count(no) FROM general WHERE npc<2');
+2 -2
View File
@@ -185,10 +185,10 @@ if($relYear < 3){
$experience = 0;
}
else{
$expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 5');
$expGenCount = $db->queryFirstField('SELECT count(*) FROM general WHERE nation != 0 AND npc < 4');
$targetGenOrder = Util::round($expGenCount * 0.2);
$experience = $db->queryFirstField(
'SELECT experience FROM general WHERE nation != 0 AND npc < 5 ORDER BY experience ASC LIMIT %i, 1',
'SELECT experience FROM general WHERE nation != 0 AND npc < 4 ORDER BY experience ASC LIMIT %i, 1',
$targetGenOrder - 1
);
$experience *= 0.8;
+42
View File
@@ -372,4 +372,46 @@ function getNpcColor(npcType) {
return 'skyblue';
}
return null;
}
function initTooltip($obj) {
if ($obj === undefined) {
$obj = $('.obj_tooltip');
} else if (!$obj.hasClass('obj_tooltip')) {
$obj = $obj.find('.obj_tooltip');
}
console.log($obj);
$obj.each(function() {
$target = $(this);
if ($target.data('installHandler')) {
return true;
}
$target.data('installHandler', true);
$target.mouseover(function() {
var $objTooltip = $(this);
if ($objTooltip.data('setObjTooltip')) {
return true;
}
var tooltipClassText = $objTooltip.data('tooltip-class');
if (!tooltipClassText) {
tooltipClassText = '';
}
var template = '<div class="tooltip {0}" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
.format(tooltipClassText);
$objTooltip.tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
template: template,
html: true
}).tooltip('show');
$objTooltip.data('setObjTooltip', true);
});
});
}
+74 -76
View File
@@ -1,4 +1,3 @@
/*
function showCityGeneral(cityIdx){
@@ -21,13 +20,13 @@ function loadScenarioPreview(scenarioIdx){
function loadScenarios(){
function loadScenarios() {
$.ajax({
method:'post',
url:'j_load_scenarios.php',
dataType:'json'
}).then(function(result){
if(!result.result){
method: 'post',
url: 'j_load_scenarios.php',
dataType: 'json'
}).then(function(result) {
if (!result.result) {
var deferred = $.Deferred();
deferred.reject('fail');
return deferred.promise();
@@ -37,18 +36,18 @@ function loadScenarios(){
var list = {};
$.each(result.scenario, function(idx, value){
$.each(result.scenario, function(idx, value) {
var title = value.title || "-";
var pat = /【(.*?)[0-9\-_\.a-zA-Z]*】/;
var category = pat.exec(title);
category = category?category[1]:'-';
category = category ? category[1] : '-';
value.title = title;
value.category = category;
value.idx = idx;
value.year = value.year || 180;
if(!(category in list)){
if (!(category in list)) {
list[category] = {};
}
@@ -56,12 +55,12 @@ function loadScenarios(){
});
var $select = $('#scenario_sel');
$.each(list, function(category, items){
$.each(list, function(category, items) {
var $optgroup = $('<optgroup>').attr('label', category);
$.each(items, function(idx, scenario){
$.each(items, function(idx, scenario) {
var $option = $('<option>')
.data('scenario',scenario)
.data('scenario', scenario)
.val(idx)
.html(scenario.title);
$optgroup.append($option);
@@ -75,7 +74,7 @@ function loadScenarios(){
});
}
function scenarioPreview(){
function scenarioPreview() {
var $select = $(this);
var $option = $select.find('option:selected');
@@ -89,125 +88,124 @@ function scenarioPreview(){
$year.html('{0}년'.format(scenario.year));
$npc.html('{0}명'.format(scenario.npc_cnt));
if(scenario.npcEx_cnt == 0){
if (scenario.npcEx_cnt == 0) {
$npcEx.html('');
}
else{
} else {
$npcEx.html('+{0}명'.format(scenario.npcEx_cnt));
}
$nation.html('');
$.each(scenario.nation, function(idx, nation){
$.each(scenario.nation, function(idx, nation) {
$nation.append('<span style="color:{0}">{1}</span> {2}명. {3}<br>'.format(
nation.color, nation.name, nation.generals, nation.cities.join(', ')
));
});
}
function formSetup(){
$.validator.addMethod("autorun_user", function(value,element){
function formSetup() {
$.validator.addMethod("autorun_user", function(value, element) {
var parent = $(element).parent('.input-group');
var checkCnt = parent.find('input:checked').length;
if(value <= 0){
if(checkCnt > 0){
if (value <= 0) {
if (checkCnt > 0) {
return false;
}
return true;
}
if(checkCnt == 0){
if (checkCnt == 0) {
return false;
}
return true;
}, "유효 시간과 옵션은 동시에 설정해야합니다.");
$('#game_form').validate({
rules:{
turnterm:"required",
sync:"required",
scenario:"required",
fiction:"required",
extend:"required",
npcmode:"required",
show_img_level:"required",
tournament_trig:"required",
join_mode:'required',
autorun_user_minutes:{required: true, autorun_user: true, min:0}
rules: {
turnterm: "required",
sync: "required",
scenario: "required",
fiction: "required",
extend: "required",
npcmode: "required",
show_img_level: "required",
tournament_trig: "required",
join_mode: 'required',
autorun_user_minutes: { required: true, autorun_user: true, min: 0 }
},
errorElement: "div",
errorPlacement: function ( error, element ) {
errorPlacement: function(error, element) {
// Add the `help-block` class to the error element
error.addClass( "invalid-feedback" );
error.addClass("invalid-feedback");
if ( element.prop( "type" ) === "checkbox" ) {
error.insertAfter( element.parent( "label" ) );
if (element.prop("type") === "checkbox") {
error.insertAfter(element.parent("label"));
} else {
error.insertAfter( element );
error.insertAfter(element);
}
},
highlight: function ( element, errorClass, validClass ) {
$( element ).addClass( "is-invalid" ).removeClass( "is-valid" );
highlight: function(element, errorClass, validClass) {
$(element).addClass("is-invalid").removeClass("is-valid");
},
unhighlight: function (element, errorClass, validClass) {
$( element ).addClass( "is-valid" ).removeClass( "is-invalid" );
unhighlight: function(element, errorClass, validClass) {
$(element).addClass("is-valid").removeClass("is-invalid");
}
});
$('#game_form').submit(function(e){
$('#game_form').submit(function(e) {
e.preventDefault();
if(!$("#game_form").valid()){
if (!$("#game_form").valid()) {
return;
}
var autorun_user_minutes = parseInt($('#autorun_user_minutes').val());
var autorun_user = [];
if(autorun_user_minutes > 0){
$('.autorun_user_chk:checked').each(function(){
if (autorun_user_minutes > 0) {
$('.autorun_user_chk:checked').each(function() {
autorun_user.push($(this).data('key'));
});
}
$.ajax({
cache:false,
type:'post',
url:'j_install.php',
dataType:'json',
data:{
turnterm:$('#turnterm input:radio:checked').val(),
sync:$('#sync input:radio:checked').val(),
scenario:$('#scenario_sel').val(),
fiction:$('#fiction input:radio:checked').val(),
extend:$('#extend input:radio:checked').val(),
npcmode:$('#npcmode input:radio:checked').val(),
show_img_level:$('#show_img_level input:radio:checked').val(),
tournament_trig:$('#tournament_trig input:radio:checked').val(),
reserve_open:$('#reserve_open').val(),
pre_reserve_open:$('#pre_reserve_open').val(),
join_mode:$('#join_mode input:radio:checked').val(),
autorun_user_minutes:autorun_user_minutes,
autorun_user:autorun_user
cache: false,
type: 'post',
url: 'j_install.php',
dataType: 'json',
data: {
turnterm: $('#turnterm input:radio:checked').val(),
sync: $('#sync input:radio:checked').val(),
scenario: $('#scenario_sel').val(),
fiction: $('#fiction input:radio:checked').val(),
extend: $('#extend input:radio:checked').val(),
block_general_create: $('#block_general_create input:radio:checked').val(),
npcmode: $('#npcmode input:radio:checked').val(),
show_img_level: $('#show_img_level input:radio:checked').val(),
tournament_trig: $('#tournament_trig input:radio:checked').val(),
reserve_open: $('#reserve_open').val(),
pre_reserve_open: $('#pre_reserve_open').val(),
join_mode: $('#join_mode input:radio:checked').val(),
autorun_user_minutes: autorun_user_minutes,
autorun_user: autorun_user
}
}).then(function(result){
}).then(function(result) {
var deferred = $.Deferred();
if(!result.result){
if (!result.result) {
alert(result.reason);
deferred.reject('fail');
}
else{
} else {
alert('게임이 리셋되었습니다.');
deferred.resolve();
}
return deferred.promise();
}).then(function(){
}).then(function() {
location.href = '..';
});
});
}
$(function(){
$(function() {
loadScenarios();
$('#scenario_sel').change(scenarioPreview);
formSetup();
})
})
+2 -2
View File
@@ -235,10 +235,10 @@ function reloadWorldMap(option, drawTarget) {
}
function mergeClickable(city) {
//clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
//clickable = (defaultCity << 4 ) | (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
var id = city.id;
var nationId = city.nationId;
var clickable = 0;
var clickable = 16;
if (id in spyList) {
clickable |= spyList[id] << 3;
}
+210
View File
@@ -0,0 +1,210 @@
var templateGeneralCard = '<div class="general_card">\
<h4 class="bg1 with_border"><%generalName%></h4>\
<h4><img src="<%iconPath%>" height=64 width=64></h4><p>\
<%if(leadership){%>\
<%leadership%> / <%strength%> / <%intel%><br>\
<%}%>\
<%if(personalText){%><%personalText%><br><%}%>\
<%if(specialDomesticText||specialWarText){%>\
<%specialDomesticText%> / <%specialWarText%><br>\
<%}%>\
<%if(dex){%><br>\
보병: <%parseInt(dex[0]/1000)%>K<br>\
궁병: <%parseInt(dex[1]/1000)%>K<br>\
기병: <%parseInt(dex[2]/1000)%>K<br>\
귀병: <%parseInt(dex[3]/1000)%>K<br>\
차병: <%parseInt(dex[4]/1000)%>K<br>\
<%}%>\
</p>\
<button type="subject" class="with_skin with_border select_btn" data-name="<%generalName%>" value="<%uniqueName%>" name="pick">선택하기</button>\
</div>';
var templateSpecial =
'<span class="obj_tooltip" data-toggle="tooltip" data-placement="top"><%text%>\
<span class="tooltiptext">\
<%info%>\
</span>\
</span>\
';
function pickGeneral() {
$btn = $(this);
if (hasGeneralID) {
if (!confirm('이 장수를 선택할까요? : {0}'.format($btn.data('name')))) {
return false;
}
$.post({
url: 'j_update_picked_general.php',
dataType: 'json',
data: {
pick: $btn.val()
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
alert('선택한 장수로 변경했습니다.');
location.href = './';
});
return false;
}
currentGeneralInfo = cards[$btn.val()];
var $card = $btn.closest('.general_card');
var $leftPad = $('#left_pad');
$leftPad.empty();
$card.clone().appendTo($leftPad);
initTooltip($leftPad);
return false;
}
function buildGeneral() {
if (!currentGeneralInfo) {
alert('장수를 선택해주세요!');
return false;
}
if (!confirm('이 장수로 생성할까요?')) {
return false;
}
$.post({
url: 'j_select_picked_general.php',
dataType: 'json',
data: {
pick: currentGeneralInfo.uniqueName,
use_own_picture: $('#use_own_picture').is(':checked'),
leadership: parseInt($('#leadership').val()),
strength: parseInt($('#leadership').val()),
intel: parseInt($('#leadership').val()),
personal: $('#selChar').val()
}
}).then(function(result) {
if (!result.result) {
alert(result.reason);
location.refresh();
}
alert('선택한 장수로 생성했습니다.');
location.href = './';
});
return false;
}
function updateOutdateTimer() {
var $validUntilText = $('#valid_until_text');
var now = Date.now();
var validUntil = $validUntilText.data('until');
if (validUntil <= 0) {
return;
} else if (validUntil < now) {
$validUntilText.data('until', 0);
$('#valid_until').hide();
$('#outdate_token').show();
return;
} else if (validUntil - now <= 30000) {
$validUntilText.css('color', "rgb(255, {0}, {0})".format(255 * (validUntil - now) / 30000));
}
setTimeout(updateOutdateTimer, 1000);
}
function printGenerals(value) {
$('.card_holder').empty();
$('#valid_until').show();
$('#valid_until_text').html(value.validUntil).data('until', (new Date(value.validUntil)).getTime()).css('color', 'white');
$('#outdate_token').hide();
var pick = $.map(value.pick, function(value, key) {
return value;
});
var emptyCard = {
'leadership': null,
'strength': null,
'intel': null,
'personalText': null,
'specialDomesticText': null,
'specialWarText': null,
'dex': null
};
$.each(pick, function(idx, cardData) {
cardData.iconPath = getIconPath(cardData.imgsvr, cardData.picture);
if (cardData.specialDomestic !== undefined) {
cardData.specialDomesticText = TemplateEngine(templateSpecial, {
text: cardData.specialDomesticName,
info: cardData.specialDomesticInfo
});
cardData.specialWarText = '-';
}
if (cardData.specialWar !== undefined) {
cardData.specialWarText = TemplateEngine(templateSpecial, {
text: cardData.specialWarName,
info: cardData.specialWarInfo
});
if (cardData.specialDomesticText === undefined) {
cardData.specialDomesticText = '-';
}
}
//FIXME: ego로 적었던것 같음!
if (cardData.personal in characterInfo) {
cardData.personalText = TemplateEngine(templateSpecial, {
text: characterInfo[cardData.personal].name,
info: characterInfo[cardData.personal].info
});
} else {
cardData.personalText = cardData.personal;
}
cards[cardData.uniqueName] = cardData;
var $card = $(TemplateEngine(templateGeneralCard, $.extend({}, emptyCard, cardData)));
$('.card_holder').append($card);
$card.find('.select_btn').click(pickGeneral);
$card.find('.obj_tooltip').tooltip({
title: function() {
return $.trim($(this).find('.tooltiptext').html());
},
html: true
});
});
updateOutdateTimer();
}
$(function($) {
$.post('j_get_select_pool.php').then(function(value) {
if (!value.result) {
alert(value.reason);
return;
}
console.log(value);
printGenerals(value);
});
if (hasGeneralID) {
$('#create_plate').hide();
}
$('#build_general').on('click', buildGeneral);
$.each(validCustomOption, function(idx, value) {
if (value == 'picture') {
$('.custom_picture').show();
} else if (value == 'ego') {
$('.custom_personality').show();
} else if (value == 'stat') {
$('.custom_stat').show();
}
});
});
+2 -1
View File
@@ -43,7 +43,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind();
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $db) {
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $rawDefenderNation, $rawDefenderCity, $db) {
if($prevDefender !== null){
$prevDefender->applyDB($db);
}
@@ -57,6 +57,7 @@ function processWar(General $attackerGeneral, array $rawAttackerNation, array $r
}
$nextDefender = $iterDefender->current();
$nextDefender->setRawCity($rawDefenderCity);
if(extractBattleOrder($nextDefender) <= 0){
return null;
}
+72
View File
@@ -0,0 +1,72 @@
<?php
namespace sammo;
use sammo\AbsGeneralPool;
use sammo\GameConst;
use sammo\Json;
use sammo\Util;
abstract class AbsFromUserPool extends AbsGeneralPool{
public function occupyGeneralName(): bool
{
$generalID = $this->getGeneralBuilder()->getGeneralID();
if($generalID === null){
throw new \RuntimeException('build되지 않음');
}
$db= $this->db;
$db->update('select_pool', [
'general_id'=>$generalID,
'owner'=>null,
'reserved_until'=>null,
], 'unique_name = %s AND owner IS NOT NULL', $this->uniqueName);
return $db->affectedRows()!=0;
}
static public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array{
$oNow = new \DateTimeImmutable();
$now = $oNow->format('Y-m-d H:i:s');
$db->update('select_pool', [
'reserved_until'=>null,
'owner'=>null,
],'reserved_until < %s AND general_id IS NULL', $now);
$pool = [];
foreach($db->query('SELECT id, unique_name, info FROM select_pool WHERE reserved_until IS NULL AND general_id IS NULL', $pickCnt) as $cand){
$cand['info'] = Json::decode($cand['info']);
$dexTotal = array_sum($cand['info']['dex']);
$pool[] = [$cand, $dexTotal];
}
if(count($pool) < $pickCnt){
throw new \RuntimeException('pool 부족');
}
$gameStor = KVStorage::getStorage($db, 'game_env');
$result = [];
$validUntil = TimeUtil::nowAddMinutes(2 * $gameStor->turnterm);
while(count($result) < $pickCnt){
$cand = Util::choiceRandomUsingWeightPair($pool);
$poolID = $cand['id'];
if(key_exists($poolID, $result)){
continue;
}
$candInfo = $cand['info'];
$candInfo['uniqueName'] = $cand['unique_name'];
//하나씩 한다.
$db->update('select_pool', [
'owner'=>$owner,
'reserved_until'=>$validUntil,
], 'id = %i AND reserved_until IS NULL AND owner IS NULL and general_id IS NULL', $poolID);
if($db->affectedRows()==0){
continue;
}
$result[$poolID] = new static($db, $candInfo, $validUntil);
}
return array_values($result);
}
}
+111
View File
@@ -0,0 +1,111 @@
<?php
namespace sammo;
use MeekroDB;
use sammo\GameConst;
use sammo\Scenario\GeneralBuilder;
use sammo\Util;
abstract class AbsGeneralPool{
protected $builder;
protected $info;
protected $db=null;
protected $uniqueName;
protected $generalName;
protected $validUntil;
/*
* info = [
* uniqueName
* generalName
* imgsvr
* picture
*
* leadership
* strength
* intel
*
* experience
* dedication
*
* dex[5]
*
* specialDomestic
* specialWar
*/
public function __construct(\MeekroDB $db, array $info, string $validUntil)
{
$this->db = $db;
$this->info = $info;
$this->uniqueName = $info['uniqueName'];
$this->generalName = $info['generalName'];
$this->builder = new GeneralBuilder(
$info['generalName'],
$info['imgsvr'],
$info['picture'],
0
);
$this->validUntil = $validUntil;
$builder = $this->builder;
if(key_exists('leadership', $info)){
$builder->setStat($info['leadership'], $info['strength'], $info['intel']);
}
if(key_exists('experience', $info)){
$builder->setExpDed($info['experience'], $info['dedication']);
}
if(key_exists('dex', $info)){
$builder->setDex($info['dex'][0], $info['dex'][1], $info['dex'][2], $info['dex'][3], $info['dex'][4]);
}
if(key_exists('specialDomestic', $info) || key_exists('specialWar', $info)){
$builder->setSpecial($info['specialDomestic']??GameConst::$defaultSpecialDomestic, $info['specialWar']??GameConst::$defaultSpecialWar);
}
}
public function getUniqueName():string{
return $this->uniqueName;
}
public function getInfo():array{
return $this->info;
}
static protected function checkDuplicatedCnt(\MeekroDB $db, string $name):int{
$duplicateCnt = 0;
foreach(GeneralBuilder::$prefixList as $npcPrefix){
$testName = "{$npcPrefix}{$name}";
$duplicateCnt += $db->queryFirstField('SELECT count(no) FROM general WHERE name LIKE %s', $testName.'%');
}
return $duplicateCnt;
}
public function getGeneralBuilder():GeneralBuilder{
if(!$this->generalName){
throw new \RuntimeException('generalName not picked');
}
return $this->builder;
}
public function getValidUntil():string{
return $this->validUntil;
}
/**
* @param \MeekroDB $db
* @param int $owner
* @param int $pickCnt
* @param null|string $prefix
* @return AbsGeneralPool[]
*/
static abstract public function pickGeneralFromPool(\MeekroDB $db, int $owner, int $pickCnt, ?string $prefix=null):array;
abstract public function occupyGeneralName():bool;
abstract public static function getPoolName():string;
abstract public static function initPool(\MeekroDB $db);
}
@@ -6,4 +6,17 @@ use \sammo\General;
class che_명마_07_기주마 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 공격 시 페이즈 +1";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'initWarPhase'){
return $value + 1;
}
return $value;
}
}
@@ -1,9 +1,26 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_퇴각부상무효;
use sammo\WarUnitTriggerCaller;
class che_명마_07_백마 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 전투 종료로 인한 부상 없음";
}
public function getBattleInitSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_퇴각부상무효($unit, BaseWarUnitTrigger::TYPE_ITEM),
);
}
}
@@ -1,9 +1,27 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_퇴각부상무효;
use sammo\WarUnitTriggerCaller;
class che_명마_12_사륜거 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 전투 종료로 인한 부상 없음";
}
public function getBattleInitSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_퇴각부상무효($unit, BaseWarUnitTrigger::TYPE_ITEM),
);
}
}
@@ -2,9 +2,26 @@
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_저격발동;
use sammo\WarUnitTrigger\che_저격시도;
use sammo\WarUnitTriggerCaller;
class che_무기_02_단궁 extends \sammo\BaseStatItem{
protected $cost = 3000;
protected $buyable = true;
protected $reqSecu = 2000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 새로운 상대와 전투 시 1% 확률로 저격 발동, 성공 시 사기+10";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM + che_저격시도::TYPE_DEDUP_TYPE_BASE * 102, 0.01, 10, 30),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
}
@@ -2,8 +2,25 @@
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_저격발동;
use sammo\WarUnitTrigger\che_저격시도;
use sammo\WarUnitTriggerCaller;
class che_무기_07_맥궁 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 새로운 상대와 전투 시 20% 확률로 저격 발동, 성공 시 사기+10";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM + che_저격시도::TYPE_DEDUP_TYPE_BASE * 107, 0.2, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
}
@@ -2,8 +2,25 @@
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_저격발동;
use sammo\WarUnitTrigger\che_저격시도;
use sammo\WarUnitTriggerCaller;
class che_무기_09_동호비궁 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 새로운 상대와 전투 시 20% 확률로 저격 발동, 성공 시 사기+10";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM + che_저격시도::TYPE_DEDUP_TYPE_BASE * 109, 0.15, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
}
@@ -2,8 +2,25 @@
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_저격발동;
use sammo\WarUnitTrigger\che_저격시도;
use sammo\WarUnitTriggerCaller;
class che_무기_11_이광궁 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 새로운 상대와 전투 시 10% 확률로 저격 발동, 성공 시 사기+10";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM + che_저격시도::TYPE_DEDUP_TYPE_BASE * 111, 0.10, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
}
@@ -2,8 +2,25 @@
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_저격발동;
use sammo\WarUnitTrigger\che_저격시도;
use sammo\WarUnitTriggerCaller;
class che_무기_13_양유기궁 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 새로운 상대와 전투 시 10% 확률로 저격 발동, 성공 시 사기+10";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM + che_저격시도::TYPE_DEDUP_TYPE_BASE * 113, 0.05, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
}
@@ -21,8 +21,8 @@ class che_반계_백우선 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_NONE, false, '계략약화'),
new che_반계시도($unit),
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_ITEM +BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*301, false, '계략약화'),
new che_반계시도($unit, BaseWarUnitTrigger::TYPE_ITEM +BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*301),
new che_반계발동($unit)
);
}
@@ -21,8 +21,8 @@ class che_반계_파초선 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_NONE, false, '계략약화'),
new che_반계시도($unit),
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_ITEM +BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*302, false, '계략약화'),
new che_반계시도($unit, BaseWarUnitTrigger::TYPE_ITEM +BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*302),
new che_반계발동($unit)
);
}
@@ -7,4 +7,17 @@ class che_서적_01_효경전 extends \sammo\BaseStatItem{
protected $cost = 1000;
protected $buyable = true;
protected $reqSecu = 1000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +1%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.01;
}
return $value;
}
}
@@ -7,4 +7,17 @@ class che_서적_02_회남자 extends \sammo\BaseStatItem{
protected $cost = 3000;
protected $buyable = true;
protected $reqSecu = 2000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +1%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.01;
}
return $value;
}
}
@@ -7,4 +7,17 @@ class che_서적_03_변도론 extends \sammo\BaseStatItem{
protected $cost = 6000;
protected $buyable = true;
protected $reqSecu = 3000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +2%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.02;
}
return $value;
}
}
@@ -7,4 +7,17 @@ class che_서적_04_건상역주 extends \sammo\BaseStatItem{
protected $cost = 10000;
protected $buyable = true;
protected $reqSecu = 4000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +2%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.02;
}
return $value;
}
}
@@ -7,4 +7,17 @@ class che_서적_05_여씨춘추 extends \sammo\BaseStatItem{
protected $cost = 15000;
protected $buyable = true;
protected $reqSecu = 5000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +3%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.03;
}
return $value;
}
}
@@ -7,4 +7,17 @@ class che_서적_06_사민월령 extends \sammo\BaseStatItem{
protected $cost = 21000;
protected $buyable = true;
protected $reqSecu = 6000;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +3%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.03;
}
return $value;
}
}
@@ -1,9 +1,26 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\WarActivateSkills;
use sammo\WarUnitTriggerCaller;
class che_서적_07_논어 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 상대의 계략 성공 확률 -10%p";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*207, false, '계략약화')
);
}
}
@@ -1,9 +1,28 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_반계발동;
use sammo\WarUnitTrigger\che_반계시도;
use sammo\WarUnitTriggerCaller;
class che_서적_07_사마법 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 상대의 계략을 20% 확률로 되돌림";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_반계시도($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*207, 0.2),
new che_반계발동($unit)
);
}
}
@@ -6,4 +6,17 @@ use \sammo\General;
class che_서적_07_위료자 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 시도 확률 +20%p";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.2;
}
return $value;
}
}
@@ -6,4 +6,17 @@ use \sammo\General;
class che_서적_08_전론 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 계략 성공 시 대미지 +20%";
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessDamage'){
return $value * 1.2;
}
return $value;
}
}
@@ -1,9 +1,26 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\WarActivateSkills;
use sammo\WarUnitTriggerCaller;
class che_서적_11_춘추전 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 상대의 계략 성공 확률 -10%p";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*211, false, '계략약화')
);
}
}
@@ -1,9 +1,28 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use sammo\WarUnit;
use sammo\WarUnitTrigger\che_반계발동;
use sammo\WarUnitTrigger\che_반계시도;
use sammo\WarUnitTriggerCaller;
class che_서적_12_산해경 extends \sammo\BaseStatItem{
protected $cost = 200;
protected $buyable = false;
public function __construct()
{
parent::__construct();
$this->info .= "<br>[전투] 상대의 계략을 20% 확률로 되돌림";
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_반계시도($unit, BaseWarUnitTrigger::TYPE_ITEM, 0.2),
new che_반계발동($unit)
);
}
}
@@ -27,7 +27,7 @@ class che_의술_상한잡병론 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(\sammo\WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM),
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*301),
new che_전투치료발동($unit, BaseWarUnitTrigger::TYPE_ITEM)
);
@@ -27,7 +27,7 @@ class che_의술_청낭서 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(\sammo\WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM),
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*302),
new che_전투치료발동($unit, BaseWarUnitTrigger::TYPE_ITEM)
);
@@ -27,7 +27,7 @@ class che_의술_태평청령 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(\sammo\WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM),
new che_전투치료시도($unit, BaseWarUnitTrigger::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*303),
new che_전투치료발동($unit, BaseWarUnitTrigger::TYPE_ITEM)
);
@@ -1,5 +1,7 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
@@ -19,7 +21,7 @@ class che_저격_매화수전 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM, 0.5, 20, 40),
new che_저격시도($unit, che_저격시도::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*304, 0.5, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
+3 -1
View File
@@ -1,5 +1,7 @@
<?php
namespace sammo\ActionItem;
use sammo\BaseWarUnitTrigger;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
@@ -19,7 +21,7 @@ class che_저격_비도 extends \sammo\BaseItem{
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_ITEM, 0.5, 20, 40),
new che_저격시도($unit, che_저격시도::TYPE_ITEM+BaseWarUnitTrigger::TYPE_DEDUP_TYPE_BASE*305, 0.5, 20, 40),
new che_저격발동($unit, che_저격발동::TYPE_ITEM)
);
}
+8 -1
View File
@@ -22,7 +22,14 @@ class che_저격_수극 extends \sammo\BaseItem{
public function getBattleInitSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, BaseWarUnitTrigger::TYPE_CONSUMABLE_ITEM, 0.5, 20, 40),
new che_저격발동($unit)
new che_저격발동($unit, BaseWarUnitTrigger::TYPE_CONSUMABLE_ITEM)
);
}
function isConsumableNow(string $actionType, string $command):bool{
if($actionType == 'GeneralTrigger' && $command == 'che_아이템치료'){
return true;
}
return false;
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace sammo\ActionItem;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use sammo\WarUnitTrigger\che_격노시도;
use sammo\WarUnitTrigger\che_격노발동;
class event_빼빼로 extends \sammo\BaseItem{
protected $id = 75;
protected $rawName = '빼빼로';
protected $name = '빼빼로';
protected $info = '1의 상징입니다.<br>통솔 +1, 무력 +1, 지력 +1';
protected $cost = 1500;
protected $buyable = true;
protected $consumable = false;
protected $reqSecu = 12000;
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(in_array($statName, ['leadership', 'strength', 'intel'] )){
return $value + 1;
}
return $value;
}
}
@@ -18,12 +18,16 @@ class event_전투특기_격노 extends \sammo\BaseItem{
protected $buyable = true;
protected $consumable = false;
protected $reqSecu = 3000;
public function getWarPowerMultiplier(WarUnit $unit):array{
$activatedCnt = $unit->hasActivatedSkillOnLog('격노');
return [1 + 0.2*$activatedCnt, 1];
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_격노시도($unit),
new che_격노발동($unit)
new che_격노시도($unit, che_격노시도::TYPE_ITEM),
new che_격노발동($unit, che_격노발동::TYPE_ITEM)
);
}
}
@@ -11,7 +11,7 @@ class event_전투특기_무쌍 extends \sammo\BaseItem{
protected $id = 61;
protected $rawName = '비급';
protected $name = '비급(무쌍)';
protected $info = '[전투] 대미지 +10%, 공격 시 필살 확률 +10%p, <br>승리 수만큼 대미지 0.20%씩 추가 상승(최대40%)<br>승리 수만큼 피해 0.05%씩 감소(최대50%)';
protected $info = '[전투] 대미지 +10%, 피해 -5%, 공격 시 필살 확률 +10%p, <br>승리 수만큼 대미지 0.20%씩 추가 상승(최대40%)<br>승리 수만큼 피해 0.05%씩 감소(최대30%)';
protected $cost = 100;
protected $buyable = true;
protected $consumable = false;
@@ -26,10 +26,10 @@ class event_전투특기_무쌍 extends \sammo\BaseItem{
public function getWarPowerMultiplier(WarUnit $unit):array{
$attackMultiplier = 1.1;
$defenceMultiplier = 1;
$defenceMultiplier = 0.95;
$killnum = $unit->getGeneral()->getRankVar('killnum');
$attackMultiplier += Util::valueFit($killnum * 0.01 * 0.2, null, 0.4);
$defenceMultiplier -= Util::valueFit($killnum * 0.01 * 0.05, null, 0.5);
$defenceMultiplier -= Util::valueFit($killnum * 0.01 * 0.05, null, 0.3);
return [$attackMultiplier, $defenceMultiplier];
}
}
@@ -0,0 +1,34 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use sammo\WarUnitTrigger\che_격노시도;
use sammo\WarUnitTrigger\che_격노발동;
class che_event_격노 extends \sammo\BaseSpecial{
protected $id = 74;
protected $name = '격노';
protected $info = '[전투] 상대방 필살 시 격노(필살) 발동, 회피 시도시 25% 확률로 격노 발동, 공격 시 일정 확률로 진노(1페이즈 추가), 격노마다 대미지 20% 추가 중첩';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_STRENGTH,
];
public function getWarPowerMultiplier(WarUnit $unit):array{
$activatedCnt = $unit->hasActivatedSkillOnLog('격노');
return [1 + 0.2*$activatedCnt, 1];
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_격노시도($unit),
new che_격노발동($unit)
);
}
}
@@ -0,0 +1,40 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use sammo\BaseWarUnitTrigger;
use sammo\WarUnitTrigger\che_부상무효;
use sammo\WarUnitTrigger\WarActivateSkills;
class che_event_견고 extends \sammo\BaseSpecial{
protected $id = 62;
protected $name = '견고';
protected $info = '[전투] 상대 필살, 저격 불가, 상대 계략 시도시 성공 확률 -10%p, 부상 없음, 아군 피해 -10%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_STRENGTH
];
public function getBattleInitSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_부상무효($unit, BaseWarUnitTrigger::TYPE_NONE),
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_NONE, false, '저격불가')
);
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_NONE, false, '필살불가', '계략약화', '저격불가')
);
}
public function getWarPowerMultiplier(WarUnit $unit):array{
return [1, 0.9];
}
}
@@ -0,0 +1,50 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
use \sammo\WarUnit;
use \sammo\WarUnitCity;
class che_event_공성 extends \sammo\BaseSpecial{
protected $id = 53;
protected $name = '공성';
protected $info = '[군사] 차병 계통 징·모병비 -10%<br>[전투] 성벽 공격 시 대미지 +100%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 차병 숙련을 가산';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_SIEGE,
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost' && $aux['armType'] == GameUnitConst::T_SIEGE) return $value * 0.9;
}
return $value;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
if($unit->getOppose() instanceof WarUnitCity){
return [2, 1];
}
return [1, 1];
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_SIEGE;
$opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){
return $value + $general->getVar($myArmType);
}
if(!$aux['isAttacker'] && $myArmType === $statName){
return $value + $general->getVar($myArmType);
}
}
return $value;
}
}
@@ -0,0 +1,46 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
class che_event_궁병 extends \sammo\BaseSpecial{
protected $id = 51;
protected $name = '궁병';
protected $info = '[군사] 궁병 계통 징·모병비 -10%<br>[전투] 회피 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 궁병 숙련을 가산';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_ARCHER | SpecialityHelper::STAT_NOT_INTEL,
SpecialityHelper::STAT_STRENGTH | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_ARCHER
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost' && $aux['armType'] == GameUnitConst::T_ARCHER) return $value * 0.9;
}
return $value;
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warAvoidRatio'){
return $value + 0.2;
}
if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_ARCHER;
$opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){
return $value + $general->getVar($myArmType);
}
if(!$aux['isAttacker'] && $myArmType === $statName){
return $value + $general->getVar($myArmType);
}
}
return $value;
}
}
@@ -0,0 +1,45 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
use \sammo\WarUnit;
class che_event_귀병 extends \sammo\BaseSpecial{
protected $id = 40;
protected $name = '귀병';
protected $info = '[군사] 귀병 계통 징·모병비 -10%<br>[전투] 계략 성공 확률 +20%p,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 귀병 숙련을 가산';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_INTEL | SpecialityHelper::ARMY_WIZARD | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::STAT_NOT_STRENGTH
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost' && $aux['armType'] == GameUnitConst::T_WIZARD) return $value * 0.9;
}
return $value;
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessProb'){
return $value + 0.2;
}
if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_WIZARD;
$opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){
return $value + $general->getVar($myArmType);
}
if(!$aux['isAttacker'] && $myArmType === $statName){
return $value + $general->getVar($myArmType);
}
}
return $value;
}
}
@@ -0,0 +1,50 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
use \sammo\WarUnit;
class che_event_기병 extends \sammo\BaseSpecial{
protected $id = 52;
protected $name = '기병';
protected $info = '[군사] 기병 계통 징·모병비 -10%<br>[전투] 수비 시 대미지 +10%, 공격 시 대미지 +20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 기병 숙련을 가산';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_CAVALRY | SpecialityHelper::STAT_NOT_INTEL,
SpecialityHelper::STAT_STRENGTH | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_CAVALRY
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost' && $aux['armType'] == GameUnitConst::T_CAVALRY) return $value * 0.9;
}
return $value;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
if($unit->isAttacker()){
return [1.2, 1];
}
return [1.1, 1];
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_CAVALRY;
$opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){
return $value + $general->getVar($myArmType);
}
if(!$aux['isAttacker'] && $myArmType === $statName){
return $value + $general->getVar($myArmType);
}
}
return $value;
}
}
@@ -0,0 +1,42 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use \sammo\BaseWarUnitTrigger;
use \sammo\WarUnitTriggerCaller;
use sammo\WarUnitTrigger\WarActivateSkills;
use \sammo\WarUnitTrigger\che_돌격지속;
class che_event_돌격 extends \sammo\BaseSpecial{
protected $id = 60;
protected $name = '돌격';
protected $info = '[전투] 공격 시 대등/유리한 병종에게는 퇴각 전까지 전투, 공격 시 페이즈 + 2, 공격 시 대미지 +5%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_STRENGTH
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'initWarPhase'){
return $value + 2;
}
return $value;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
if($unit->isAttacker()){
return [1.05, 1];
}
return [1, 1];
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_돌격지속($unit)
);
}
}
@@ -0,0 +1,36 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use \sammo\Util;
class che_event_무쌍 extends \sammo\BaseSpecial{
protected $id = 61;
protected $name = '무쌍';
protected $info = '[전투] 대미지 +10%, 피해 -5%, 공격 시 필살 확률 +10%p, <br>승리 수만큼 대미지 0.20%씩 추가 상승(최대40%)<br>승리 수만큼 피해 0.05%씩 감소(최대30%)';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_STRENGTH
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warCriticalRatio' && $aux['isAttacker']??false){
return $value += 0.1;
}
return $value;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
$attackMultiplier = 1.1;
$defenceMultiplier = 1;
$killnum = $unit->getGeneral()->getRankVar('killnum');
$attackMultiplier += Util::valueFit($killnum * 0.01 * 0.2, null, 0.4);
$defenceMultiplier -= Util::valueFit($killnum * 0.01 * 0.05, null, 0.3);
return [$attackMultiplier, $defenceMultiplier];
}
}
@@ -0,0 +1,39 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use \sammo\BaseWarUnitTrigger;
use \sammo\WarUnitTrigger\WarActivateSkills;
use \sammo\WarUnitTrigger\che_반계시도;
use \sammo\WarUnitTrigger\che_반계발동;
class che_event_반계 extends \sammo\BaseSpecial{
protected $id = 45;
protected $name = '반계';
protected $info = '[전투] 상대의 계략 성공 확률 -10%p, 상대의 계략을 40% 확률로 되돌림, 반목 성공시 대미지 추가(+60% → +150%)';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_INTEL,
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessDamage' && $aux === '반목'){
return $value + 0.9;
}
return $value;
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new WarActivateSkills($unit, BaseWarUnitTrigger::TYPE_NONE, false, '계략약화'),
new che_반계시도($unit),
new che_반계발동($unit)
);
}
}
@@ -0,0 +1,50 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\GameUnitConst;
use \sammo\WarUnit;
class che_event_보병 extends \sammo\BaseSpecial{
protected $id = 50;
protected $name = '보병';
protected $info = '[군사] 보병 계통 징·모병비 -10%<br>[전투] 공격 시 아군 피해 -10%, 수비 시 아군 피해 -20%,<br>공격시 상대 병종에/수비시 자신 병종 숙련에 보병 숙련을 가산';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_FOOTMAN | SpecialityHelper::STAT_NOT_INTEL,
SpecialityHelper::STAT_STRENGTH | SpecialityHelper::REQ_DEXTERITY | SpecialityHelper::ARMY_FOOTMAN
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost' && $aux['armType'] == GameUnitConst::T_FOOTMAN) return $value * 0.9;
}
return $value;
}
public function getWarPowerMultiplier(WarUnit $unit):array{
if($unit->isAttacker()){
return [1, 0.9];
}
return [1, 0.8];
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if(\sammo\Util::starts_with($statName, 'dex')){
$myArmType = 'dex'.GameUnitConst::T_FOOTMAN;
$opposeArmType = 'dex'.$aux['opposeType']->armType;;
if($aux['isAttacker'] && $opposeArmType === $statName){
return $value + $general->getVar($myArmType);
}
if(!$aux['isAttacker'] && $myArmType === $statName){
return $value + $general->getVar($myArmType);
}
}
return $value;
}
}
@@ -0,0 +1,37 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_신산 extends \sammo\BaseSpecial{
protected $id = 41;
protected $name = '신산';
protected $info = '[계략] 화계·탈취·파괴·선동 : 성공률 +10%p<br>[전투] 계략 시도 확률 +20%p, 계략 성공 확률 +20%p';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_INTEL,
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if($turnType == '계략'){
if($varType == 'success') return $value + 0.1;
}
return $value;
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicTrialProb'){
return $value + 0.2;
}
if($statName === 'warMagicSuccessProb'){
return $value + 0.2;
}
return $value;
}
}
@@ -0,0 +1,26 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_신중 extends \sammo\BaseSpecial{
protected $id = 44;
protected $name = '신중';
protected $info = '[전투] 계략 성공 확률 100%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_INTEL,
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessProb'){
return $value + 1;
}
return $value;
}
}
@@ -0,0 +1,29 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use \sammo\WarUnitTrigger\che_위압시도;
use \sammo\WarUnitTrigger\che_위압발동;
class che_event_위압 extends \sammo\BaseSpecial{
protected $id = 63;
protected $name = '위압';
protected $info = '[전투] 첫 페이즈 위압 발동(적 공격, 회피 불가, 사기 5 감소)';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_STRENGTH
];
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_위압시도($unit),
new che_위압발동($unit)
);
}
}
@@ -0,0 +1,41 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use sammo\BaseGeneralTrigger;
use sammo\SpecialityHelper;
use \sammo\General;
use \sammo\GeneralTrigger;
use \sammo\GeneralTriggerCaller;
use \sammo\WarUnit;
use sammo\WarUnitTrigger\che_전투치료발동;
use sammo\WarUnitTrigger\che_전투치료시도;
use sammo\WarUnitTriggerCaller;
class che_event_의술 extends \sammo\BaseSpecial{
protected $id = 73;
protected $name = '의술';
protected $info = '[군사] 매 턴마다 자신(100%)과 소속 도시 장수(적 포함 50%) 부상 회복<br>[전투] 페이즈마다 40% 확률로 치료 발동(아군 피해 1/3 감소, 부상 회복)';
static $selectWeightType = SpecialityHelper::WEIGHT_PERCENT;
static $selectWeight = 2;
static $type = [
SpecialityHelper::STAT_LEADERSHIP,
SpecialityHelper::STAT_STRENGTH,
SpecialityHelper::STAT_INTEL
];
public function getPreTurnExecuteTriggerList(General $general):?GeneralTriggerCaller{
return new GeneralTriggerCaller(
new GeneralTrigger\che_도시치료($general)
);
}
public function getBattlePhaseSkillTriggerList(\sammo\WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(
new che_전투치료시도($unit),
new che_전투치료발동($unit)
);
}
}
@@ -0,0 +1,31 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use \sammo\WarUnitTrigger\che_저격시도;
use \sammo\WarUnitTrigger\che_저격발동;
class che_event_저격 extends \sammo\BaseSpecial{
protected $id = 70;
protected $name = '저격';
protected $info = '[전투] 새로운 상대와 전투 시 50% 확률로 저격 발동, 성공 시 사기+10';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP,
SpecialityHelper::STAT_STRENGTH,
SpecialityHelper::STAT_INTEL
];
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_저격시도($unit, che_저격시도::TYPE_NONE, 0.5, 20, 40),
new che_저격발동($unit)
);
}
}
@@ -0,0 +1,26 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_집중 extends \sammo\BaseSpecial{
protected $id = 43;
protected $name = '집중';
protected $info = '[전투] 계략 성공 시 대미지 +50%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_INTEL,
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessDamage'){
return $value * 1.5;
}
return $value;
}
}
@@ -0,0 +1,36 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_징병 extends \sammo\BaseSpecial{
protected $id = 72;
protected $name = '징병';
protected $info = '[군사] 징·모병비 -50%, 통솔 순수 능력치 보정 +25%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP,
SpecialityHelper::STAT_STRENGTH,
SpecialityHelper::STAT_INTEL
];
public function onCalcDomestic(string $turnType, string $varType, float $value, $aux=null):float{
if(in_array($turnType, ['징병', '모병'])){
if($varType == 'cost') return $value * 0.5;
}
return $value;
}
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'leadership'){
return $value + $general->getVar('leadership') * 0.25;
}
return $value;
}
}
@@ -0,0 +1,29 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_척사 extends \sammo\BaseSpecial{
protected $id = 75;
protected $name = '척사';
protected $info = '[전투] 지역·도시 병종 상대로 대미지 +15%, 아군 피해 -15%';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP,
SpecialityHelper::STAT_STRENGTH,
SpecialityHelper::STAT_INTEL
];
public function getWarPowerMultiplier(WarUnit $unit):array{
$opposeCrewType = $unit->getOppose()->getCrewType();
if($opposeCrewType->reqCities || $opposeCrewType->reqRegions){
return [1.15, 0.85];
}
return [1, 1];
}
}
@@ -0,0 +1,36 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
use sammo\WarUnitTriggerCaller;
use sammo\WarUnitTrigger\che_필살강화_회피불가;
class che_event_필살 extends \sammo\BaseSpecial{
protected $id = 71;
protected $name = '필살';
protected $info = '[전투] 필살 확률 +30%p, 필살 발동시 대상 회피 불가';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
static $type = [
SpecialityHelper::STAT_LEADERSHIP,
SpecialityHelper::STAT_STRENGTH,
SpecialityHelper::STAT_INTEL
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warCriticalRatio'){
return $value + 0.30;
}
return $value;
}
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{
return new WarUnitTriggerCaller(
new che_필살강화_회피불가($unit)
);
}
}
@@ -0,0 +1,29 @@
<?php
namespace sammo\ActionSpecialDomestic;
use \sammo\iAction;
use \sammo\General;
use \sammo\SpecialityHelper;
use \sammo\WarUnit;
class che_event_환술 extends \sammo\BaseSpecial{
protected $id = 42;
protected $name = '환술';
protected $info = '[전투] 계략 성공 확률 +10%p, 계략 성공 시 대미지 +30%';
static $selectWeightType = SpecialityHelper::WEIGHT_PERCENT;
static $selectWeight = 5;
static $type = [
SpecialityHelper::STAT_INTEL,
];
public function onCalcStat(General $general, string $statName, $value, $aux=null){
if($statName === 'warMagicSuccessProb'){
return $value + 0.1;
}
if($statName === 'warMagicSuccessDamage'){
return $value * 1.3;
}
return $value;
}
}
+3 -3
View File
@@ -10,7 +10,7 @@ class che_무쌍 extends \sammo\BaseSpecial{
protected $id = 61;
protected $name = '무쌍';
protected $info = '[전투] 대미지 +10%, 공격 시 필살 확률 +10%p, <br>승리 수만큼 대미지 0.20%씩 추가 상승(최대40%)<br>승리 수만큼 피해 0.05%씩 감소(최대50%)';
protected $info = '[전투] 대미지 +10%, 피해 -5%, 공격 시 필살 확률 +10%p, <br>승리 수만큼 대미지 0.20%씩 추가 상승(최대40%)<br>승리 수만큼 피해 0.05%씩 감소(최대30%)';
static $selectWeightType = SpecialityHelper::WEIGHT_NORM;
static $selectWeight = 1;
@@ -27,10 +27,10 @@ class che_무쌍 extends \sammo\BaseSpecial{
public function getWarPowerMultiplier(WarUnit $unit):array{
$attackMultiplier = 1.1;
$defenceMultiplier = 1;
$defenceMultiplier = 0.95;
$killnum = $unit->getGeneral()->getRankVar('killnum');
$attackMultiplier += Util::valueFit($killnum * 0.01 * 0.2, null, 0.4);
$defenceMultiplier -= Util::valueFit($killnum * 0.01 * 0.05, null, 0.5);
$defenceMultiplier -= Util::valueFit($killnum * 0.01 * 0.05, null, 0.3);
return [$attackMultiplier, $defenceMultiplier];
}
}
+2
View File
@@ -120,6 +120,7 @@ class AutorunGeneralPolicy{
$priority = [];
foreach($serverPolicy['priority'] as $priorityItem){
if(!property_exists($this, $priorityItem)){
trigger_error ("{$priorityItem}이 없음", E_USER_NOTICE );
continue;
}
$priority[] = $priorityItem;
@@ -133,6 +134,7 @@ class AutorunGeneralPolicy{
$priority = [];
foreach($nationPolicy['priority'] as $priorityItem){
if(!property_exists($this, $priorityItem)){
trigger_error ("{$priorityItem}이 없음", E_USER_NOTICE );
continue;
}
$priority[] = $priorityItem;
+3
View File
@@ -85,6 +85,7 @@ class AutorunNationPolicy {
public $can부대전방발령 = true;
public $can부대후방발령 = true;
public $can부대구출발령 = true;
public $can부대유저장후방발령 = true;
public $can유저장후방발령 = true;
@@ -180,6 +181,7 @@ class AutorunNationPolicy {
if($serverPolicy){
foreach($serverPolicy['values']??[] as $policy=>$value){
if(!property_exists($this, $policy)){
trigger_error ("{$policy}이 없음", E_USER_NOTICE );
continue;
}
$this->{$policy} = $value;
@@ -194,6 +196,7 @@ class AutorunNationPolicy {
if($nationPolicy){
foreach($nationPolicy['values']??[] as $policy=>$value){
if(!property_exists($this, $policy)){
trigger_error ("{$policy}이 없음", E_USER_NOTICE );
continue;
}
$this->{$policy} = $value;
+1
View File
@@ -7,6 +7,7 @@ abstract class BaseWarUnitTrigger extends ObjectTrigger{
const TYPE_NONE = 0;
const TYPE_ITEM = 1;
const TYPE_CONSUMABLE_ITEM = 1 | 2;
const TYPE_DEDUP_TYPE_BASE = 1024;
protected $raiseType = self::TYPE_NONE;
@@ -178,14 +178,14 @@ class che_랜덤임관 extends Command\GeneralCommand{
$generalsCnt = [];
if($notIn){
$rawGeneralsCnt = $db->query(
'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 5 AND nation.gennum < %i AND nation.scout=0 AND nation.nation NOT IN %li GROUP BY general.nation, general.npc',
'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 4 AND nation.gennum < %i AND nation.scout=0 AND nation.nation NOT IN %li GROUP BY general.nation, general.npc',
$genLimit,
$notIn
);
}
else{
$rawGeneralsCnt = $db->query(
'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 5 AND nation.gennum < %i AND nation.scout=0 GROUP BY general.nation, general.npc',
'SELECT general.nation as nation, nation.gennum, nation.name, npc, count(*) as cnt FROM general JOIN nation ON general.nation = nation.nation WHERE npc < 4 AND nation.gennum < %i AND nation.scout=0 GROUP BY general.nation, general.npc',
$genLimit
);
}
@@ -81,7 +81,7 @@ class che_모반시도 extends Command\GeneralCommand{
$nationName = $this->nation['name'];
$logger = $general->getLogger();
$lordLogger = $this->destGeneralObj->getLogger();
$lordLogger = $lordGeneral->getLogger();
$general->setVar('officer_level', 12);
$general->setVar('officer_city', 0);
+134 -134
View File
@@ -1,135 +1,135 @@
<?php
namespace sammo\Command\General;
use \sammo\{
DB, Util, JosaUtil,
General,
ActionLogger,
GameConst, GameUnitConst,
LastTurn,
Command
};
use function \sammo\{
tryUniqueItemLottery
};
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\CityConst;
use function sammo\DeleteConflict;
use function sammo\refreshNationStaticInfo;
class che_방랑 extends Command\GeneralCommand{
static protected $actionName = '방랑';
protected function argTest():bool{
$this->arg = null;
return true;
}
protected function init(){
$general = $this->generalObj;
$env = $this->env;
$this->setCity();
$this->setNation();
$relYear = $env['year'] - $env['startyear'];
$this->fullConditionConstraints=[
ConstraintHelper::BeLord(),
ConstraintHelper::NotWanderingNation(),
ConstraintHelper::NotOpeningPart($relYear),
ConstraintHelper::AllowDiplomacyStatus($this->generalObj->getNationID(), [
2, 7
], '방랑할 수 없는 외교상태입니다.'),
];
}
public function getCost():array{
return [0, 0];
}
public function getPreReqTurn():int{
return 0;
}
public function getPostReqTurn():int{
return 0;
}
public function run():bool{
if(!$this->hasFullConditionMet()){
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$date = $general->getTurnTime($general::TURNTIME_HM);
$generalName = $general->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$josaUn = JosaUtil::pick($generalName, '은');
$nationID = $general->getNationID();
$nationName = $this->nation['name'];
$josaUl = JosaUtil::pick($nationName, '을');
$logger = $general->getLogger();
$logger->pushGeneralActionLog("영토를 버리고 방랑의 길을 떠납니다. <1>$date</>");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} 방랑의 길을 떠납니다.");
$logger->pushGlobalHistoryLog("<R><b>【방랑】</b></><D><b>{$generalName}</b></>{$josaUn} <R>방랑</>의 길을 떠납니다.");
$logger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaUl} 버리고 방랑");
//분쟁기록 모두 지움
DeleteConflict($nationID);
// 국명, 색깔 바꿈 국가 레벨 0, 성향리셋, 기술0
$db->update('nation', [
'name'=>$generalName,
'color'=>'#330000', //TODO: 기본 방랑군색 별도 지정
'level'=>0,
'type'=>0,
'tech'=>0,
'capital'=>0
], 'nation=%i', $nationID);
$db->update('general', [
'makelimit'=>12
], 'nation=%i', $nationID);
$general->setVar('makelimit', 12);
$general->setVar('officer_city', 0);
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'nation=%i AND officer_level < 12', $nationID);
$db->update('city', [
'nation'=>0,
'front'=>0,
'conflict'=>'{}'
], 'nation=%i', $nationID);
$db->update('diplomacy', [
'state'=>2,
'term'=>0,
], 'me=%i OR you=%i', $nationID, $nationID);
refreshNationStaticInfo();
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
$general->applyDB($db);
return true;
}
<?php
namespace sammo\Command\General;
use \sammo\{
DB, Util, JosaUtil,
General,
ActionLogger,
GameConst, GameUnitConst,
LastTurn,
Command
};
use function \sammo\{
tryUniqueItemLottery
};
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
use sammo\CityConst;
use function sammo\DeleteConflict;
use function sammo\refreshNationStaticInfo;
class che_방랑 extends Command\GeneralCommand{
static protected $actionName = '방랑';
protected function argTest():bool{
$this->arg = null;
return true;
}
protected function init(){
$general = $this->generalObj;
$env = $this->env;
$this->setCity();
$this->setNation();
$relYear = $env['year'] - $env['startyear'];
$this->fullConditionConstraints=[
ConstraintHelper::BeLord(),
ConstraintHelper::NotWanderingNation(),
ConstraintHelper::NotOpeningPart($relYear),
ConstraintHelper::AllowDiplomacyStatus($this->generalObj->getNationID(), [
2, 7
], '방랑할 수 없는 외교상태입니다.'),
];
}
public function getCost():array{
return [0, 0];
}
public function getPreReqTurn():int{
return 0;
}
public function getPostReqTurn():int{
return 0;
}
public function run():bool{
if(!$this->hasFullConditionMet()){
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$date = $general->getTurnTime($general::TURNTIME_HM);
$generalName = $general->getName();
$josaYi = JosaUtil::pick($generalName, '이');
$josaUn = JosaUtil::pick($generalName, '은');
$nationID = $general->getNationID();
$nationName = $this->nation['name'];
$josaUl = JosaUtil::pick($nationName, '을');
$logger = $general->getLogger();
$logger->pushGeneralActionLog("영토를 버리고 방랑의 길을 떠납니다. <1>$date</>");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} 방랑의 길을 떠납니다.");
$logger->pushGlobalHistoryLog("<R><b>【방랑】</b></><D><b>{$generalName}</b></>{$josaUn} <R>방랑</>의 길을 떠납니다.");
$logger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaUl} 버리고 방랑");
//분쟁기록 모두 지움
DeleteConflict($nationID);
// 국명, 색깔 바꿈 국가 레벨 0, 성향리셋, 기술0
$db->update('nation', [
'name'=>$generalName,
'color'=>'#330000', //TODO: 기본 방랑군색 별도 지정
'level'=>0,
'type'=>'None',
'tech'=>0,
'capital'=>0
], 'nation=%i', $nationID);
$db->update('general', [
'makelimit'=>12
], 'nation=%i', $nationID);
$general->setVar('makelimit', 12);
$general->setVar('officer_city', 0);
$db->update('general', [
'officer_level'=>1,
'officer_city'=>0,
], 'nation=%i AND officer_level < 12', $nationID);
$db->update('city', [
'nation'=>0,
'front'=>0,
'conflict'=>'{}'
], 'nation=%i', $nationID);
$db->update('diplomacy', [
'state'=>2,
'term'=>0,
], 'me=%i OR you=%i', $nationID, $nationID);
refreshNationStaticInfo();
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
$general->applyDB($db);
return true;
}
}
+23 -83
View File
@@ -19,7 +19,8 @@ use function\sammo\{
CriticalRatioDomestic,
CriticalScoreEx,
tryUniqueItemLottery,
getAllNationStaticInfo
getAllNationStaticInfo,
pickGeneralFromPool,
};
use \sammo\Constraint\Constraint;
@@ -134,7 +135,8 @@ class che_인재탐색 extends Command\GeneralCommand
$totalGenCnt = $db->queryFirstField('SELECT count(no) FROM general WHERE npc <= 2');
$totalNpcCnt = $db->queryFirstField('SELECT count(`no`) FROM general WHERE 3 <= npc AND npc <= 4');
$foundNpc = Util::randBool($this->calcFoundProp($env['maxgeneral'], $totalGenCnt, $totalNpcCnt));
$foundProp = $this->calcFoundProp($env['maxgeneral'], $totalGenCnt, $totalNpcCnt);
$foundNpc = Util::randBool($foundProp);
$logger = $general->getLogger();
@@ -164,101 +166,39 @@ class che_인재탐색 extends Command\GeneralCommand
}
//인간적으로 너무 길어서 끊었다!
$exp = 200;
$ded = 300;
$pickTypeList = ['무' => 6, '지' => 6, '무지' => 3];
$pickType = Util::choiceRandomUsingWeight($pickTypeList);
$totalStat = GameConst::$defaultStatNPCTotal;
$minStat = GameConst::$defaultStatNPCMin;
$mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, GameConst::$defaultStatNPCMin);
$otherStat = $minStat + Util::randRangeInt(0, Util::toInt(GameConst::$defaultStatNPCMin/2));
$subStat = $totalStat - $mainStat - $otherStat;
if ($subStat < $minStat) {
$subStat = $otherStat;
$otherStat = $minStat;
$mainStat = $totalStat - $subStat - $otherStat;
if ($mainStat) {
throw new \LogicException('기본 스탯 설정값이 잘못되어 있음');
}
}
$avgGen = $db->queryFirstRow(
'SELECT avg(dedication) as ded,avg(experience) as exp,
avg(dex1+dex2+dex3+dex4) as dex_t, avg(age) as age, avg(dex5) as dex5
from general where npc < 5',
$nationID
);
$dexTotal = $avgGen['dex_t'];
if ($pickType == '무') {
$leadership = $subStat;
$strength = $mainStat;
$intel = $otherStat;
$dexVal = Util::choiceRandom([
[$dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8, $dexTotal / 8],
[$dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8],
[$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8],
]);
} else if ($pickType == '지') {
$leadership = $subStat;
$strength = $otherStat;
$intel = $mainStat;
$dexVal = [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8];
} else {
$leadership = $otherStat;
$strength = $subStat;
$intel = $mainStat;
$dexVal = [$dexTotal / 4, $dexTotal / 4, $dexTotal / 4, $dexTotal / 4];
}
$leadership = Util::round($leadership);
$strength = Util::round($strength);
$intel = Util::round($intel);
$exp = 100 * (sqrt(1 / $foundProp) + 1);
$ded = 150 * (sqrt(1 / $foundProp) + 1);
$scoutType = "발견";
$scoutLevel = 0;
$scoutNation = 0;
$age = Util::randRangeInt(20, 25);
$birthYear = $env['year'] - $age;
$deathYear = $env['year'] + Util::randRangeInt(10, 50);
$cityID = Util::choiceRandom(array_keys(\sammo\CityConst::all()));
$newNPC = new \sammo\Scenario\NPC(
Util::randRangeInt(1, 150),
\sammo\getRandGenName(),
null,
$scoutNation,
$cityID,
$leadership,
$strength,
$intel,
$scoutLevel,
$birthYear,
$deathYear,
null,
null
$avgGen = $db->queryFirstRow(
'SELECT avg(dedication) as ded,avg(experience) as exp,
avg(dex1+dex2+dex3+dex4) as dex_t, avg(age) as age, avg(dex5) as dex5
from general where npc < 4'
);
$newNPC->npc = 3;
$pickTypeList = ['무' => 6, '지' => 6, '무지' => 3];
$pickedNPC = pickGeneralFromPool($db, 0, 1)[0];
$newNPC = $pickedNPC->getGeneralBuilder();
$newNPC->setSpecial('None', 'None');
$newNPC->setNPCType(3);
$newNPC->setMoney(1000, 1000);
$newNPC->setExpDed($avgGen['exp'], $avgGen['ded']);
$newNPC->setLifeSpan($birthYear, $deathYear);
$newNPC->setSpecYear(
Util::round((GameConst::$retirementYear - $age) / 12) + $age,
Util::round((GameConst::$retirementYear - $age) / 6) + $age
);
$newNPC->setDex(
$dexVal[0],
$dexVal[1],
$dexVal[2],
$dexVal[3],
$avgGen['dex5']
);
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
$newNPC->build($this->env);
$npcName = $newNPC->realName;
$pickedNPC->occupyGeneralName();
$npcName = $newNPC->getGeneralName();
$josaRa = JosaUtil::pick($npcName, '라');
$generalName = $general->getName();
+99 -98
View File
@@ -1,99 +1,100 @@
<?php
namespace sammo\Command\General;
use \sammo\{
DB, Util, JosaUtil,
General,
ActionLogger,
GameConst, GameUnitConst,
Command
};
class che_탈취 extends che_화계{
static protected $actionName = '탈취';
static protected $statType = 'strength';
static protected $injuryGeneral = false;
protected function affectDestCity(int $injuryCount){
$general = $this->generalObj;
$nationID = $general->getNationID();
$date = $general->getTurnTime($general::TURNTIME_HM);
$logger = $general->getLogger();
$destCity = $this->destCity;
$destCityName = $destCity['name'];
$destCityID = $destCity['city'];
$destNationID = $destCity['nation'];
$commandName = $this->getName();
$db = DB::db();
// 탈취 최대 400 * 8
$gold = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'];
$rice = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'];
if($destCity['supply']){
[$destNationGold, $destNationRice] = $db->queryFirstList('SELECT gold,rice FROM nation WHERE nation=%i', $destNationID);
$destNationGold -= $gold;
$destNationRice -= $rice;
if($destNationGold < GameConst::$minNationalGold) {
$gold += $destNationGold - GameConst::$minNationalGold;
$destNationGold = GameConst::$minNationalGold;
}
if($destNationRice < GameConst::$minNationalRice) {
$rice += $destNationRice - GameConst::$minNationalRice;
$destNationRice = GameConst::$minNationalRice;
}
$db->update('nation', [
'gold'=>$destNationGold,
'rice'=>$destNationRice
], 'nation=%i', $destNationID);
$db->update('city', [
'state'=>34
], 'city=%i', $destCityID);
}
else{
$db->update('city', [
'comm'=>Util::valueFit($destCity['comm'] - $gold / 12, 0),
'agri'=>Util::valueFit($destCity['agri'] - $rice / 12, 0),
'state'=>34
], 'city=%i', $destCityID);
}
// 본국으로 일부 회수, 재야이면 본인이 전량 소유
if($nationID != 0) {
$db->update('nation', [
'gold' => $db->sqleval('gold + %i', Util::round($gold * 0.7)),
'rice' => $db->sqleval('rice + %i', Util::round($rice * 0.7))
], 'nation=%i', $nationID);
$general->increaseVar('gold', $gold - Util::round($gold * 0.7));
$general->increaseVar('rice', $rice - Util::round($rice * 0.7));
} else {
$general->increaseVar('gold', $gold);
$general->increaseVar('rice', $rice);
}
$db->update('city', [
'state'=>32,
'agri'=>$destCity['agri'],
'comm'=>$destCity['comm']
], 'city=%i', $destCityID);
$goldText = number_format($gold);
$riceText = number_format($rice);
$josaYi = JosaUtil::pick($destCityName, '이');
$logger->pushGlobalActionLog("<G><b>{$destCityName}</b></>에서 금과 쌀을 도둑맞았습니다.");
$josaYi = JosaUtil::pick($commandName, '이');
$logger->pushGeneralActionLog("<G><b>{$destCityName}</b></>에 {$commandName}{$josaYi} 성공했습니다. <1>$date</>");
$logger->pushGeneralActionLog("금<C>{$goldText}</> 쌀<C>{$riceText}</>을 획득했습니다.", ActionLogger::PLAIN);
}
<?php
namespace sammo\Command\General;
use \sammo\{
DB, Util, JosaUtil,
General,
ActionLogger,
GameConst, GameUnitConst,
Command
};
class che_탈취 extends che_화계{
static protected $actionName = '탈취';
static protected $statType = 'strength';
static protected $injuryGeneral = false;
protected function affectDestCity(int $injuryCount){
$general = $this->generalObj;
$nationID = $general->getNationID();
$date = $general->getTurnTime($general::TURNTIME_HM);
$logger = $general->getLogger();
$destCity = $this->destCity;
$destCityName = $destCity['name'];
$destCityID = $destCity['city'];
$destNationID = $destCity['nation'];
$commandName = $this->getName();
$db = DB::db();
// 탈취 최대 800 * 8 * sqrt(1 + (year - startyear) / 5) / 2
$yearCoef = sqrt(1 + ($this->env['year'] - $this->env['startyear']) / 5) / 2;
$gold = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef;
$rice = Util::randRangeInt(GameConst::$sabotageDamageMin, GameConst::$sabotageDamageMax) * $destCity['level'] * $yearCoef;
if($destCity['supply']){
[$destNationGold, $destNationRice] = $db->queryFirstList('SELECT gold,rice FROM nation WHERE nation=%i', $destNationID);
$destNationGold -= $gold;
$destNationRice -= $rice;
if($destNationGold < GameConst::$minNationalGold) {
$gold += $destNationGold - GameConst::$minNationalGold;
$destNationGold = GameConst::$minNationalGold;
}
if($destNationRice < GameConst::$minNationalRice) {
$rice += $destNationRice - GameConst::$minNationalRice;
$destNationRice = GameConst::$minNationalRice;
}
$db->update('nation', [
'gold'=>$destNationGold,
'rice'=>$destNationRice
], 'nation=%i', $destNationID);
$db->update('city', [
'state'=>34
], 'city=%i', $destCityID);
}
else{
$db->update('city', [
'comm'=>Util::valueFit($destCity['comm'] - $gold / 12, 0),
'agri'=>Util::valueFit($destCity['agri'] - $rice / 12, 0),
'state'=>34
], 'city=%i', $destCityID);
}
// 본국으로 일부 회수, 재야이면 본인이 전량 소유
if($nationID != 0) {
$db->update('nation', [
'gold' => $db->sqleval('gold + %i', Util::round($gold * 0.7)),
'rice' => $db->sqleval('rice + %i', Util::round($rice * 0.7))
], 'nation=%i', $nationID);
$general->increaseVar('gold', $gold - Util::round($gold * 0.7));
$general->increaseVar('rice', $rice - Util::round($rice * 0.7));
} else {
$general->increaseVar('gold', $gold);
$general->increaseVar('rice', $rice);
}
$db->update('city', [
'state'=>32,
'agri'=>$destCity['agri'],
'comm'=>$destCity['comm']
], 'city=%i', $destCityID);
$goldText = number_format($gold);
$riceText = number_format($rice);
$josaYi = JosaUtil::pick($destCityName, '이');
$logger->pushGlobalActionLog("<G><b>{$destCityName}</b></>에서 금과 쌀을 도둑맞았습니다.");
$josaYi = JosaUtil::pick($commandName, '이');
$logger->pushGeneralActionLog("<G><b>{$destCityName}</b></>에 {$commandName}{$josaYi} 성공했습니다. <1>$date</>");
$logger->pushGeneralActionLog("금<C>{$goldText}</> 쌀<C>{$riceText}</>을 획득했습니다.", ActionLogger::PLAIN);
}
}
@@ -95,6 +95,7 @@ class che_선전포고 extends Command\NationCommand
ConstraintHelper::DisallowDiplomacyBetweenStatus([
0 => '아국과 이미 교전중입니다.',
1 => '아국과 이미 선포중입니다.',
7 => '불가침국입니다.'
]),
];
}
+13 -71
View File
@@ -152,81 +152,23 @@ class che_의병모집 extends Command\NationCommand
from general where nation=%i',
$nationID
);
$dexTotal = $avgGen['dex_t'];
foreach(\sammo\pickGeneralFromPool($db, 0, $createGenCnt) as $pickedNPC){
$newNPC = $pickedNPC->getGeneralBuilder();
for (; $createGenIdx <= $lastCreatGenIdx; $createGenIdx++) {
$pickType = Util::choiceRandomUsingWeight($pickTypeList);
$newNPC->setCityID($general->getCityID());
$newNPC->setNationID($general->getNationID());
$totalStat = GameConst::$defaultStatNPCMax * 2 + 10;
$minStat = 10;
$mainStat = GameConst::$defaultStatNPCMax - Util::randRangeInt(0, 10);
//TODO: defaultStatNPCTotal, defaultStatNPCMin 추가
$otherStat = $minStat + Util::randRangeInt(0, 5);
$subStat = $totalStat - $mainStat - $otherStat;
if ($subStat < $minStat) {
$subStat = $otherStat;
$otherStat = $minStat;
$mainStat = $totalStat - $subStat - $otherStat;
if ($mainStat) {
throw new \LogicException('기본 스탯 설정값이 잘못되어 있음');
}
}
if ($pickType == '무') {
$leadership = $subStat;
$strength = $mainStat;
$intel = $otherStat;
$dexVal = Util::choiceRandom([
[$dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8, $dexTotal / 8],
[$dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8, $dexTotal / 8],
[$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8],
]);
} else if ($pickType == '지') {
$leadership = $subStat;
$strength = $otherStat;
$intel = $mainStat;
$dexVal = [$dexTotal / 8, $dexTotal / 8, $dexTotal * 5 / 8, $dexTotal / 8];
} else {
$leadership = $otherStat;
$strength = $subStat;
$intel = $mainStat;
$dexVal = [$dexTotal / 4, $dexTotal / 4, $dexTotal / 4, $dexTotal / 4];
}
$leadership = Util::round($leadership);
$strength = Util::round($strength);
$intel = Util::round($intel);
$age = $avgGen['age'];
$newNPC = new \sammo\Scenario\NPC(
Util::randRangeInt(1, 150),
"의병장{$createGenIdx}",
null,
$nationID,
$general->getCityID(),
$leadership,
$strength,
$intel,
1,
$env['year'] - 20,
$env['year'] + 6,
null,
null
);
$newNPC->killturn = Util::randRangeInt(64, 70);
$newNPC->npc = 4;
$newNPC->setSpecial('None', 'None');
$newNPC->setLifeSpan($env['year']-20, $env['year']+10);
$newNPC->setKillturn(Util::randRangeInt(64, 70));
$newNPC->setNPCType(4);
$newNPC->setMoney(1000, 1000);
$newNPC->setExpDed($avgGen['exp'], $avgGen['ded']);
$newNPC->setDex(
$dexVal[0],
$dexVal[1],
$dexVal[2],
$dexVal[3],
$avgGen['dex5']
);
$newNPC->setSpecYear(19, 19);
$newNPC->fillRemainSpecAsRandom($pickTypeList, $avgGen, $env);
$newNPC->build($this->env);
$pickedNPC->occupyGeneralName();
}
$gameStor->npccount = $lastCreatGenIdx;
@@ -176,7 +176,7 @@ class che_이호경식 extends Command\NationCommand
$broadcastMessage = "아국에 <M>{$commandName}</>{$josaYiCommand} 발동되었습니다.";
$destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID);
$destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $destNationID, $generalID);
foreach ($destNationGeneralList as $destNationGeneralID) {
$destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month);
$destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN);
@@ -197,6 +197,10 @@ class che_이호경식 extends Command\NationCommand
'state' => 1,
], '(me = %i AND you = %i) OR (you = %i AND me = %i)', $nationID, $destNationID, $nationID, $destNationID);
\sammo\SetNationFront($nationID);
\sammo\SetNationFront($destNationID);
$this->setResultTurn(new LastTurn(static::getName(), $this->arg));
$general->applyDB($db);
+198 -195
View File
@@ -1,195 +1,198 @@
<?php
namespace sammo\Command\Nation;
use\sammo\{
DB,
Util,
JosaUtil,
General,
DummyGeneral,
ActionLogger,
GameConst,
LastTurn,
GameUnitConst,
Command,
MessageTarget,
DiplomaticMessage,
Message,
};
use function\sammo\{
getDomesticExpLevelBonus,
CriticalRatioDomestic,
CriticalScoreEx,
getAllNationStaticInfo,
getNationStaticInfo,
GetImageURL
};
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
class che_종전수락 extends Command\NationCommand
{
static protected $actionName = '종전 수락';
static public $reqArg = true;
protected function argTest(): bool
{
if ($this->arg === null) {
return false;
}
if (!key_exists('destNationID', $this->arg)) {
return false;
}
$destNationID = $this->arg['destNationID'];
if (!is_int($destNationID)) {
return false;
}
if ($destNationID < 1) {
return false;
}
if (!key_exists('destGeneralID', $this->arg)) {
return false;
}
$destGeneralID = $this->arg['destGeneralID'];
if (!is_int($destGeneralID)) {
return false;
}
if ($destGeneralID <= 0) {
return false;
}
if ($destGeneralID == $this->generalObj->getID()) {
return false;
}
$this->arg = [
'destNationID' => $destNationID,
'destGeneralID' => $destGeneralID,
];
return true;
}
protected function init()
{
$general = $this->generalObj;
$env = $this->env;
$relYear = $env['year'] - $env['startyear'];
$this->setCity();
$this->setNation();
$nationID = $this->nation['nation'];
$this->permissionConstraints = [
ConstraintHelper::AlwaysFail('예약 불가능 커맨드')
];
}
protected function initWithArg()
{
$destGeneral = General::createGeneralObjFromDB($this->arg['destGeneralID'], [], 1);
$this->setDestGeneral($destGeneral);
$this->setDestNation($this->arg['destNationID']);
$this->fullConditionConstraints = [
ConstraintHelper::BeChief(),
ConstraintHelper::NotBeNeutral(),
ConstraintHelper::ExistsDestNation(),
ConstraintHelper::ExistsDestGeneral(),
ConstraintHelper::ReqDestNationValue('nation', '소속', '==', $this->destGeneralObj->getNationID(), '제의 장수가 국가 소속이 아닙니다'),
ConstraintHelper::AllowDiplomacyBetweenStatus(
[0, 1],
'상대국과 선포, 전쟁중이지 않습니다.'
),
];
}
public function canDisplay():bool{
return false;
}
public function getCost(): array
{
return [0, 0];
}
public function getPreReqTurn(): int
{
return 0;
}
public function getPostReqTurn(): int
{
return 0;
}
public function getBrief(): string
{
$commandName = $this->getName();
$destNationName = getNationStaticInfo($this->arg['destNationID'])['name'];
return "{$destNationName}국과 종전 합의";
}
public function run(): bool
{
if (!$this->hasFullConditionMet()) {
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$generalName = $general->getName();
$nation = $this->nation;
$nationID = $nation['nation'];
$nationName = $nation['name'];
$destNation = $this->destNation;
$destNationID = $destNation['nation'];
$destNationName = $destNation['name'];
$logger = $general->getLogger();
$destLogger = $this->destGeneralObj->getLogger();
$db->update(
'diplomacy',
[
'state' => 2,
'term' => 0
],
'(me=%i AND you=%i) OR (you=%i AND me=%i)',
$nationID,
$destNationID,
$nationID,
$destNationID
);
$josaYiGeneral = JosaUtil::pick($generalName, '이');
$josaYiNation = JosaUtil::pick($nationName, '이');
$josaWa = JosaUtil::pick($destNationName, '');
$logger->pushGeneralActionLog("<D><b>{$destNationName}</b></>{$josaWa} 종전에 합의했습니다.", ActionLogger::PLAIN);
$logger->pushGeneralHistoryLog("<D><b>{$destNationName}</b></>{$josaWa} 종전 수락");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYiGeneral} <D><b>{$destNationName}</b></>{$josaWa} <M>종전 합의</> 하였습니다.");
$logger->pushGlobalHistoryLog("<Y><b>【종전】</b></><D><b>{$nationName}</b></>{$josaYiNation} <D><b>{$destNationName}</b></>{$josaWa} <M>종전 합의</> 하였습니다.");
$josaWa = JosaUtil::pick($nationName, '와');
$destLogger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaWa} 종전에 성공했습니다.", ActionLogger::PLAIN);
$destLogger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaWa} 종전 성공");
$general->applyDB($db);
$destLogger->flush();
return true;
}
}
<?php
namespace sammo\Command\Nation;
use\sammo\{
DB,
Util,
JosaUtil,
General,
DummyGeneral,
ActionLogger,
GameConst,
LastTurn,
GameUnitConst,
Command,
MessageTarget,
DiplomaticMessage,
Message,
};
use function\sammo\{
getDomesticExpLevelBonus,
CriticalRatioDomestic,
CriticalScoreEx,
getAllNationStaticInfo,
getNationStaticInfo,
GetImageURL
};
use \sammo\Constraint\Constraint;
use \sammo\Constraint\ConstraintHelper;
class che_종전수락 extends Command\NationCommand
{
static protected $actionName = '종전 수락';
static public $reqArg = true;
protected function argTest(): bool
{
if ($this->arg === null) {
return false;
}
if (!key_exists('destNationID', $this->arg)) {
return false;
}
$destNationID = $this->arg['destNationID'];
if (!is_int($destNationID)) {
return false;
}
if ($destNationID < 1) {
return false;
}
if (!key_exists('destGeneralID', $this->arg)) {
return false;
}
$destGeneralID = $this->arg['destGeneralID'];
if (!is_int($destGeneralID)) {
return false;
}
if ($destGeneralID <= 0) {
return false;
}
if ($destGeneralID == $this->generalObj->getID()) {
return false;
}
$this->arg = [
'destNationID' => $destNationID,
'destGeneralID' => $destGeneralID,
];
return true;
}
protected function init()
{
$general = $this->generalObj;
$env = $this->env;
$relYear = $env['year'] - $env['startyear'];
$this->setCity();
$this->setNation();
$nationID = $this->nation['nation'];
$this->permissionConstraints = [
ConstraintHelper::AlwaysFail('예약 불가능 커맨드')
];
}
protected function initWithArg()
{
$destGeneral = General::createGeneralObjFromDB($this->arg['destGeneralID'], [], 1);
$this->setDestGeneral($destGeneral);
$this->setDestNation($this->arg['destNationID']);
$this->fullConditionConstraints = [
ConstraintHelper::BeChief(),
ConstraintHelper::NotBeNeutral(),
ConstraintHelper::ExistsDestNation(),
ConstraintHelper::ExistsDestGeneral(),
ConstraintHelper::ReqDestNationValue('nation', '소속', '==', $this->destGeneralObj->getNationID(), '제의 장수가 국가 소속이 아닙니다'),
ConstraintHelper::AllowDiplomacyBetweenStatus(
[0, 1],
'상대국과 선포, 전쟁중이지 않습니다.'
),
];
}
public function canDisplay():bool{
return false;
}
public function getCost(): array
{
return [0, 0];
}
public function getPreReqTurn(): int
{
return 0;
}
public function getPostReqTurn(): int
{
return 0;
}
public function getBrief(): string
{
$commandName = $this->getName();
$destNationName = getNationStaticInfo($this->arg['destNationID'])['name'];
return "{$destNationName}국과 종전 합의";
}
public function run(): bool
{
if (!$this->hasFullConditionMet()) {
throw new \RuntimeException('불가능한 커맨드를 강제로 실행 시도');
}
$db = DB::db();
$env = $this->env;
$general = $this->generalObj;
$generalName = $general->getName();
$nation = $this->nation;
$nationID = $nation['nation'];
$nationName = $nation['name'];
$destNation = $this->destNation;
$destNationID = $destNation['nation'];
$destNationName = $destNation['name'];
$logger = $general->getLogger();
$destLogger = $this->destGeneralObj->getLogger();
$db->update(
'diplomacy',
[
'state' => 2,
'term' => 0
],
'(me=%i AND you=%i) OR (you=%i AND me=%i)',
$nationID,
$destNationID,
$nationID,
$destNationID
);
\sammo\SetNationFront($nationID);
\sammo\SetNationFront($destNationID);
$josaYiGeneral = JosaUtil::pick($generalName, '');
$josaYiNation = JosaUtil::pick($nationName, '이');
$josaWa = JosaUtil::pick($destNationName, '와');
$logger->pushGeneralActionLog("<D><b>{$destNationName}</b></>{$josaWa} 종전 합의습니다.", ActionLogger::PLAIN);
$logger->pushGeneralHistoryLog("<D><b>{$destNationName}</b></>{$josaWa} 종전 수락");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYiGeneral} <D><b>{$destNationName}</b></>{$josaWa} <M>종전 합의</> 하였습니다.");
$logger->pushGlobalHistoryLog("<Y><b>【종전】</b></><D><b>{$nationName}</b></>{$josaYiNation} <D><b>{$destNationName}</b></>{$josaWa} <M>종전 합의</> 하였습니다.");
$josaWa = JosaUtil::pick($nationName, '와');
$destLogger->pushGeneralActionLog("<D><b>{$nationName}</b></>{$josaWa} 종전에 성공했습니다.", ActionLogger::PLAIN);
$destLogger->pushGeneralHistoryLog("<D><b>{$nationName}</b></>{$josaWa} 종전 성공");
$general->applyDB($db);
$destLogger->flush();
return true;
}
}
@@ -199,7 +199,7 @@ class che_피장파장 extends Command\NationCommand{
$broadcastMessage = "아국에 <G><b>{$cmd->getName()}</b></> 전략의 <M>{$commandName}</>{$josaYiCommand} 발동되었습니다.";
$destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $nationID, $generalID);
$destNationGeneralList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND no != %i', $destNationID, $generalID);
foreach($destNationGeneralList as $destNationGeneralID){
$destNationGeneralLogger = new ActionLogger($destNationGeneralID, $destNationID, $year, $month);
$destNationGeneralLogger->pushGeneralActionLog($broadcastMessage, ActionLogger::PLAIN);
+2 -6
View File
@@ -29,18 +29,14 @@ class BattleGroundCity extends Constraint{
$this->tested = true;
$nationID = $this->general['nation'];
$destNationID = $this->city['nation'];
$destNationID = $this->destCity['nation'];
if($destNationID == 0){
return true;
}
if($this->arg && $destNationID == $nationID){
return true;
}
$db = DB::db();
$diplomacy = $db->queryFirstField('SELECT state FROM diplomacy WHERE me = %i AND you = %i', $nationID, $destNationID);
if($diplomacy === 0){
if($diplomacy == 0){
return true;
}

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