From 2b086239f3124adf3ed98d42e20ca3fd1b7b9925 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 17:13:58 +0100 Subject: [PATCH 01/32] Adding ware workflow, buildings and menus for leather addon --- .../assets/addons/0x01000001/AFR_ICON.LST | Bin 0 -> 2418 bytes data/RTTR/assets/addons/0x01000001/AFR_Z.LST | Bin 0 -> 20711 bytes .../assets/addons/0x01000001/JAP_ICON.LST | Bin 0 -> 2288 bytes data/RTTR/assets/addons/0x01000001/JAP_Z.LST | Bin 0 -> 20671 bytes .../assets/addons/0x01000001/ROM_ICON.LST | Bin 0 -> 2368 bytes data/RTTR/assets/addons/0x01000001/ROM_Z.LST | Bin 0 -> 22039 bytes .../assets/addons/0x01000001/VIK_ICON.LST | Bin 0 -> 2378 bytes data/RTTR/assets/addons/0x01000001/VIK_Z.LST | Bin 0 -> 22633 bytes data/RTTR/assets/addons/0x01000001/WAFR_Z.LST | Bin 0 -> 20610 bytes data/RTTR/assets/addons/0x01000001/WJAP_Z.LST | Bin 0 -> 20833 bytes data/RTTR/assets/addons/0x01000001/WROM_Z.LST | Bin 0 -> 22098 bytes data/RTTR/assets/addons/0x01000001/WVIK_Z.LST | Bin 0 -> 22709 bytes .../assets/addons/0x01000001/bab_icon.lst | Bin 0 -> 2538 bytes data/RTTR/assets/addons/0x01000001/bab_z.lst | Bin 0 -> 22098 bytes data/RTTR/assets/addons/0x01000001/wbab_z.lst | Bin 0 -> 22112 bytes data/RTTR/assets/base/leather_bobs.lst | Bin 0 -> 110210 bytes libs/s25main/GlobalGameSettings.cpp | 3 +- libs/s25main/LeatherLoader.cpp | 89 ++++++++++++++++++ libs/s25main/LeatherLoader.h | 74 +++++++++++++++ libs/s25main/Loader.cpp | 31 ++++++ libs/s25main/SerializedGameData.cpp | 8 ++ libs/s25main/Ware.h | 3 + libs/s25main/addons/AddonLeather.h | 20 ++++ libs/s25main/addons/Addons.h | 1 + libs/s25main/addons/const_addons.h | 2 +- libs/s25main/ai/aijh/AIPlayerJH.cpp | 14 ++- libs/s25main/desktops/dskCredits.cpp | 6 +- libs/s25main/factories/JobFactory.cpp | 12 +++ libs/s25main/figures/noFigure.cpp | 10 ++ libs/s25main/figures/nofLeatherWorker.cpp | 65 +++++++++++++ libs/s25main/figures/nofLeatherWorker.h | 33 +++++++ libs/s25main/figures/nofSkinner.cpp | 40 ++++++++ libs/s25main/figures/nofSkinner.h | 33 +++++++ libs/s25main/figures/nofTanner.cpp | 48 ++++++++++ libs/s25main/figures/nofTanner.h | 33 +++++++ libs/s25main/gameData/BuildingConsts.cpp | 33 +++++-- libs/s25main/gameData/BuildingConsts.h | 50 +++++----- libs/s25main/gameData/BuildingProperties.cpp | 3 - libs/s25main/gameData/DoorConsts.h | 16 ++-- libs/s25main/gameData/GoodConsts.cpp | 3 + libs/s25main/gameData/JobConsts.cpp | 3 + libs/s25main/gameData/SettingTypeConv.cpp | 6 +- libs/s25main/gameTypes/BuildingType.h | 8 +- libs/s25main/gameTypes/GO_Type.h | 5 +- libs/s25main/gameTypes/GoodTypes.h | 7 +- libs/s25main/gameTypes/JobTypes.h | 5 +- libs/s25main/gameTypes/SettingsTypes.cpp | 4 + libs/s25main/gameTypes/SettingsTypes.h | 2 +- libs/s25main/ingameWindows/iwAction.cpp | 13 ++- libs/s25main/ingameWindows/iwBuildOrder.cpp | 10 ++ .../iwBuildingProductivities.cpp | 8 +- .../ingameWindows/iwBuildingProductivities.h | 2 +- libs/s25main/ingameWindows/iwBuildings.cpp | 12 ++- libs/s25main/ingameWindows/iwShip.cpp | 13 +++ libs/s25main/ingameWindows/iwWares.cpp | 66 ++++++------- libs/s25main/lua/LuaInterfaceGame.cpp | 9 ++ tests/s25Main/integration/testGamePlayer.cpp | 2 +- tests/s25Main/lua/testLuaConstants.cpp | 15 ++- 58 files changed, 704 insertions(+), 116 deletions(-) create mode 100644 data/RTTR/assets/addons/0x01000001/AFR_ICON.LST create mode 100644 data/RTTR/assets/addons/0x01000001/AFR_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/JAP_ICON.LST create mode 100644 data/RTTR/assets/addons/0x01000001/JAP_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/ROM_ICON.LST create mode 100644 data/RTTR/assets/addons/0x01000001/ROM_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/VIK_ICON.LST create mode 100644 data/RTTR/assets/addons/0x01000001/VIK_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/WAFR_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/WJAP_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/WROM_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/WVIK_Z.LST create mode 100644 data/RTTR/assets/addons/0x01000001/bab_icon.lst create mode 100644 data/RTTR/assets/addons/0x01000001/bab_z.lst create mode 100644 data/RTTR/assets/addons/0x01000001/wbab_z.lst create mode 100644 data/RTTR/assets/base/leather_bobs.lst create mode 100644 libs/s25main/LeatherLoader.cpp create mode 100644 libs/s25main/LeatherLoader.h create mode 100644 libs/s25main/addons/AddonLeather.h create mode 100644 libs/s25main/figures/nofLeatherWorker.cpp create mode 100644 libs/s25main/figures/nofLeatherWorker.h create mode 100644 libs/s25main/figures/nofSkinner.cpp create mode 100644 libs/s25main/figures/nofSkinner.h create mode 100644 libs/s25main/figures/nofTanner.cpp create mode 100644 libs/s25main/figures/nofTanner.h diff --git a/data/RTTR/assets/addons/0x01000001/AFR_ICON.LST b/data/RTTR/assets/addons/0x01000001/AFR_ICON.LST new file mode 100644 index 0000000000000000000000000000000000000000..28f9cd934941adfd0c3d9d8583e312802ab61086 GIT binary patch literal 2418 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 literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/JAP_ICON.LST b/data/RTTR/assets/addons/0x01000001/JAP_ICON.LST new file mode 100644 index 0000000000000000000000000000000000000000..c2f0d375c2f904b77a56b162f872f092e948cbdf GIT binary patch literal 2288 zcmY*bO>84c6|QRAN&h(P{OnG;s^XdUa+wVXbyi~816oZodq6@nX}9el?Wwz+xgZdB zcRS9ooDd*!VConN#9^dN2(WuZ0_}k?Xe16uTje-Ta$*@~cCH-Q8rRrl^LnMlBfATY=h51OEXfvlBXGNSkgg;zkqr(QdtIcZq6>uh=C`U zi!(x*1U5&W6i(zoEZ*$r<%7kUfYtai!w27fx(}u_VM!_%5WCXLP!VcMaU)@FfC;me z0aTF~0K z@!UIKy0hmNI?GuU@<`!Cbc<5QP&HOg&pUQv$In-vuO78MmIYdYiYaZk#+1ee6iC^a zo;Nx#R@EE)6ZeSOEOHo_q81-(KIZ0Rt^>4k{^jR;t54fq*N$zR9eB79JDh0=NR3H( z+St4K^bHnunB8Jdc)YI!yRRfVUwlojPABTc&34?i86Pvj7*oUAj5t>$9#^IvE|80B zU;92jaHr1D$f@XZ!*5kWUqeD}RZ6C4MQG@9_Wy%YpFakKVNm{J5%MN^o7^JbB=3>$ zkRM`DeorRkU*rl6>0SC=`ZM|=)$}vUtaq%;`muFj{m~+v3RJXQk$fK|yt*K{uNlMJ z%dQL+W190&0r7<;3A+kIrSzI+uy~hY30deHjKUQ%C}xo|dX=No&~)Lmx zteOPQLn>OY?{41v(^)(?*y-6p>4_t^En4{S`?eVj%dssHZ{Hi;J34c--e#5-fw$s4 z_Jl)7(vJ+LlC2q{-uCWJy#b=4L^4lo)t`VU={o>blgLS^h`l`9_Riv<*OXBcnC{~( z;iTvu$xw8oj}CwRn>?GkS=JMFo<7@qQtt}ewjF1_Q!bS&CurgJyJ_p`^P7L)%Pe=Z z`16slBRiEixav}oy?qUbIDNMI>5I*U+Gdf?H`+oaFR-!yr*b3ji?0N4uJk5Z#`8x| z`d7$T$vTP2x5-b*Z^_3{xlg}N6Z#{1NdHRzNnf?zvc6?~4=VqK^`S);tlmQgnOU;9 zQjzIHsIgX)d63Jcnv{cn0zFr4nU{Hy2hw)twtmt#JFw!(Ji~^>mJDQNY3@qkG8ZId zHQ+Aupv(aQ0%R{=kP*EB;sT%xk_;JMM)Z^UO6nmPs36Y*lM0OTB_iMK8|%inXIxoO zWLa*C4YFW(!R0fbJtec|;q;)%fr1x)scv4j096xKWg4>5PTq{y2&pA3P`> z--z@9#qD!#}%L5Z8(L ziS~IKIgfnDSdZV`;Ps}B4579kIe6i}j3s${!$aVSV!j>Ku_`NZGoh7<)>z^H0a+mR AqW}N^ literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/JAP_Z.LST b/data/RTTR/assets/addons/0x01000001/JAP_Z.LST new file mode 100644 index 0000000000000000000000000000000000000000..a187e7cbed41e7a12bc14ce3479e3f1473ddd105 GIT binary patch literal 20671 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 literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/ROM_ICON.LST b/data/RTTR/assets/addons/0x01000001/ROM_ICON.LST new file mode 100644 index 0000000000000000000000000000000000000000..2d2a7b8fd9b9b47751ee3d1d9b9ff2523af1c0c6 GIT binary patch literal 2368 zcmYjS+iM%k9iEw3_U>qvoJLw%JG*kVD;eT6g_UH=NuOeSrH2+N+Fi+q^R`+!550kN zDfFRzD3k*&#rxD23Zin&>_B4fF%_GjxLfi2jBszKOqvzlnd0 zL;QRE7n~v$vPFFIL-K3#TQVV^lYbJFN$m}G1_53OrpaV+h9qfk(C_;&C{&{$1rwQI z03)VGtP>T2g&CsPIQLF$vM4UFYGlIPQkKuL0*hG8m>DrvWxrCgNRd&JRDgy{=1sGs85zpL6>?RC=7~-K7 z2K`hS3lPWmXxiCl(bT*w4FsqJr4@6I2h%fG@f2qo^O*mZXNsu+j@4k2Od-XE-Ay1v z1RN7OV5VXVc%}u(bfRe!+NEhoz&ofi(^Q1c1?vEuOyDy~w1mP6U^i5V>nMT;1$p#z zGSN6XQM=SlprRNthjkRD%%h#tSCeFts4Pm;uH7-C2v)1u5IwJbx-Fhg)t8Z|PzT`1 zjG5*zL1ltjh2&0eANED*cv07O9RW7}MPe&rty-&cm_Ab?r`JLI5w*LHpu7-Ot!7s1 z=BK6#@aeYGrOyQ9nRU^HK#xD&^3ZpE>}`o6z_UxWG<7L^CFAjSm8n22Hq6h$-<<9LCnF^rZlTf*>T z_W$O%hNMe#6u=yR2XmNc1NG2%&ilJ_yTXK)F>HT)JnHfq2l(D z2B9Ur6dDSEBGvVf;59VE5-#XtD*EFiRWEsH-w&A}((u4PFfdtz5-i=5^noZo9UDW~ z-(9~ANp%0h>lg&z1iUA;Br1xPry<~;=Z}nmaR9n6L4q%pfgq(@v?qz>imoHCf1rnb zXQcNp9t?F%Za{`2HPS7qCsoRN=nqGShlc_+$|ECZEv~HHf*u8|mW@`cC(#l|hk7VD zBcmqEM`PDod`qZ|pO&RoPXzSfzHbP$CfkafJvti08h8e^Jbp^umSZ1W^i?1@vi-}H zZ7bO$*e6b4Wm+k>B&pK}*ZI0YWk*rA8j2!^mjsu(YG%Fch`jfj_+9(mpSZR?I<)h1 z0%MNru(Hs7Pt;4$UAg@TCLTVr6$SGOS?0Qw<)|Pzwk)s7Qmg$4r(DN%ZNl*!#LG<1 zuJ^V(dAW8Y*f|6Op%gTfqAtsSHJ2&7otq0+9^DO=z!R9^#hiRj&pX%tX9ey7epkG6 zX@@T&1;+mXJJi4qUGy!m!(()YK0*IN48M!t$KS`l!oS0xK#)#0$$pU7Vc zO4C8Z(m-#8Cjp%y@#>(_Y&IH=`b)D=5CU++()B^JxZY?q`KzgLT=xUGP*V9pIDLO* zrP#dQOaa>5aMqX^1L_)>!)|`4%^|*CED+2KJs>tSFdJPnk!alwBNoQT`Wjc zTJ?5MK3Y94wX6^zc#QVl%TOyL(R4p^a$FIN%p4m*umfi|x}psNXvE5%rKQzO`Ngne zjM|1_lscjyh}>l>gTR^_-m+Y`*D^}&4B!`{zzIGWc_nCY*K>|#ojGZ#GOjox$3@cGJqhq zk71?hArQRXWkcpAa+_!alEB(V(A({kQv292fUw&)<=UK(+cZaarBSyoLy27d`S@g% zu3x~xuq@|+Pz-WC+m>(FWtKMuLC$51>#{5>P@*q$0bnJN4#a#;-q_qQ#UKc7*K=|{ wC*1G*aK_?vAlWo8%PR7M)M9WupO<}5A)#;_?*-N-+hAD`<&|J-Q=ZNK4YYN!8~^|S literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/ROM_Z.LST b/data/RTTR/assets/addons/0x01000001/ROM_Z.LST new file mode 100644 index 0000000000000000000000000000000000000000..9ad39472587a4e0e0ed67bb3a4de0f9674276024 GIT binary patch literal 22039 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 T>QPZoleMFY9{l$6qoe-^3;qr- literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/VIK_ICON.LST b/data/RTTR/assets/addons/0x01000001/VIK_ICON.LST new file mode 100644 index 0000000000000000000000000000000000000000..6c1fb17c3df1c4c8fa877d4aea7d01de307e563b GIT binary patch literal 2378 zcmYjSU2G#)6~6a6PG+2RH(@sobFc07c!S;ui!mQx|mOp3(Y zZnqV@Bc!TG%v)DNJZ!UcXA?^N!b7FL6loQONQIfX9?y@9P=B^XNWcS6@PIkjDS~TR zzCPzW-#Pc(bMC2ZFQWf0j0n06AF;~t!RT)Up%;*bzKgo(`{;-0P4oc0heGsMRKPdz z7XAT#6aNZ-i2sf+lR9aWSIN(aN8TrAgp-tfO3)lR$d)H)ZYCRN&Xoz8ojXX<>^yOn zU@woeUYca*sdIUP@(Ty0IEzoud)!x@XFzZ%i?ghk+>X=n{=VnTPteTLL7I-wvk%hj zY?P+^nditLy^^Kr%UP5pXGt#`$LV?MIdc<~TRs?f&XVr|oSAP2zK)>!xvclqP=l`p{9RpEv~c#W?GM)qXdH9E?k+aj4Ky zFjRt8Fm&;xeDLy<^lZPEWO4U=oZL=hUk-<(NTISHMlPC^v-BhI8)xIw(tdgxgS|{y z5Ehgj-!H}pTqwI)_dFgaqh2z~(xmHCsUR~&3fhFU6oJ4UyaGw@^&r_j2m?5FnWFd# z-641fPw3~J`+GZS@}&F0Xq@b4pqN+cL0t)Cg45eV9clOX$WZc>Yn^?s-~gB z3v3;10|-yJpT!-r1k{}!76oh`XsJ(SxEvWs7uGsEl+mC~Lux|_EJ%C5{A3hR*($&v zu*|)q+*p{POE`j(E9B#}l$KyOpO4ZwE?t^T{=XL%zwCv|v=?5?iC)mrE%ZHf2mJ*7 z0{sU49{m~3;4=O;-ovlqxA1#-jQ@>QqLEj~8|0XLNd7`*bEVujbI<3{)tqfUhI(C^ zbse+WG+=wF;6CuSOvBK%iUeUi<2vPL$<%dCZ)gpW$cwJI)igm5tI=p^;#6~Aam(K^ zGy^0T(#Gbd5ML>;H=BB66L4Z_n~hBysy)B#mO1ApFiwSlhRx_LtZqs2BiU{`3^5q#Sm?kqnM z+^)hX>T3;1n%UG%=&Wm?Hw{SXCNQuf4>YP7x&b0xHvxnvmFAYVWo`k!X)tPPimrhc zbO12`I-GFQh2xgeI^+wYa_tykNxEWw+Xa*!O^r1XS zX}DW3s1ADgf*P>mqLd&~0;)_AQG2&NY@%j!YpMlg!`B0!7JYbV1VXqe>_(_>P*93E zLQR2^mRgM7_b*6jd$%y`qyCV!4O3~b(4q>LWGM=7ygfx=mylhCS1gO}7TQ#?tngnJ z4W%6^`gpA`{LEsSTOJA?`{IDsgl1E@rbcjUy&ph zNHl^P3nBRY@^%qmEzW{god;4eidoSQpwnhnAdeEO`vLU>3Enpr^C*IM2$GOfLd%wE z(DEs81+dwOX_5MMza_>Cqt?-}E%Bfw1z=zIB{1FKz(aj8VT#V<_;w=RFlow8eF%p~ zb(j&R`pBb{ZJ*S>wmPU*s$Rc;S6vewbM5%K+P!N3~xMYO9W_s#SGJH>#_HTCJx(?)NRrRzC#{u6+J*tuF;~ zt@=oK$ z?qR>v>Q^1FTA>vV<$LR`r?nGRV34&2=bBk`=VkwT)!Srx!*;e`-zM@Gt7=ttoYzG4 Z=NIN>sj60V$~U&%xf$p6yYRwI{sW0TLGAzm literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/VIK_Z.LST b/data/RTTR/assets/addons/0x01000001/VIK_Z.LST new file mode 100644 index 0000000000000000000000000000000000000000..26b0e7cfb715b52e7d3bf8b91ef421acd381b511 GIT binary patch literal 22633 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 literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/WAFR_Z.LST b/data/RTTR/assets/addons/0x01000001/WAFR_Z.LST new file mode 100644 index 0000000000000000000000000000000000000000..79949da700edff7cedd28fb06150d159b58c92e3 GIT binary patch literal 20610 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�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 literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/WROM_Z.LST b/data/RTTR/assets/addons/0x01000001/WROM_Z.LST new file mode 100644 index 0000000000000000000000000000000000000000..52e36819256140ec18df90f081afaf47c0cd0d14 GIT binary patch literal 22098 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

SB^KFk`sC#^ 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 yvNh)$O!PHJ@3F%MZL@1u7;77oAw literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/bab_icon.lst b/data/RTTR/assets/addons/0x01000001/bab_icon.lst new file mode 100644 index 0000000000000000000000000000000000000000..4086ed42f6c42000cbd953d48369a7c88ed4439c GIT binary patch literal 2538 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 literal 0 HcmV?d00001 diff --git a/data/RTTR/assets/addons/0x01000001/wbab_z.lst b/data/RTTR/assets/addons/0x01000001/wbab_z.lst new file mode 100644 index 0000000000000000000000000000000000000000..9b6fa243a4f3438f480bd43258d82de727b8129e GIT binary patch literal 22112 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 literal 0 HcmV?d00001 diff --git a/libs/s25main/GlobalGameSettings.cpp b/libs/s25main/GlobalGameSettings.cpp index 730af63fe2..29faf78075 100644 --- a/libs/s25main/GlobalGameSettings.cpp +++ b/libs/s25main/GlobalGameSettings.cpp @@ -101,7 +101,8 @@ void GlobalGameSettings::registerAllAddons() AddonToolOrdering, AddonTrade, AddonAutoFlags, - AddonWine + AddonWine, + AddonLeather >; // clang-format on using namespace boost::mp11; diff --git a/libs/s25main/LeatherLoader.cpp b/libs/s25main/LeatherLoader.cpp new file mode 100644 index 0000000000..34c34c929b --- /dev/null +++ b/libs/s25main/LeatherLoader.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +/////////////////////////////////////////////////////////////////////////////// + +#include "LeatherLoader.h" +#include "GlobalGameSettings.h" +#include "Loader.h" +#include "addons/const_addons.h" +#include "ogl/glArchivItem_Bitmap.h" +#include "ogl/glTexturePacker.h" +#include "world/GameWorldBase.h" + +namespace leatheraddon { + +bool isLeatherAddonBuildingType(BuildingType bld) +{ + return bld == BuildingType::Skinner || bld == BuildingType::Tannery || bld == BuildingType::LeatherWorks; +} + +bool isLeatherAddonGoodType(GoodType good) +{ + return good == GoodType::Skins || good == GoodType::Leather || good == GoodType::Armor; +} + +bool isLeatherAddonJobType(Job job) +{ + return job == Job::Skinner || job == Job::Tanner || job == Job::LeatherWorker; +} + +helpers::EnumArray bobIndex = {0, 21, 69, 117, 125, 173, 189, 222, 270, 286, 293, + 301, 307, 313, 336, 354, 355, 356, 356, 357, 357, 358, + 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369}; + +ITexture* GetWareTex(const GoodType good) +{ + switch(good) + { + case GoodType::Skins: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::SKINS_WARE_ICON]); + case GoodType::Leather: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::LEATHER_WARE_ICON]); + case GoodType::Armor: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::ARMOR_WARE_ICON]); + default: return nullptr; + } +} + +ITexture* GetWareStackTex(const GoodType good) +{ + switch(good) + { + case GoodType::Skins: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::SKINS_WARE_ON_GROUND_OF_FLAG]); + case GoodType::Leather: + return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::LEATHER_WARE_ON_GROUND_OF_FLAG]); + case GoodType::Armor: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::ARMOR_WARE_ON_GROUND_OF_FLAG]); + default: return nullptr; + } +} + +ITexture* GetWareDonkeyTex(const GoodType good) +{ + switch(good) + { + case GoodType::Skins: + return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::DONKEY_BOAT_CARRYING_SKINS_WARE]); + case GoodType::Leather: + return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::DONKEY_BOAT_CARRYING_LEATHER_WARE]); + case GoodType::Armor: + return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::DONKEY_BOAT_CARRYING_ARMOR_WARE]); + default: return nullptr; + } +} + +ITexture* GetJobTex(Job job) +{ + switch(job) + { + case Job::Skinner: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::SKINNER_JOB_ICON]); + case Job::Tanner: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::TANNER_JOB_ICON]); + case Job::LeatherWorker: return LOADER.GetImageN("leather_bobs", bobIndex[BobTypes::LEATHERWORKER_JOB_ICON]); + default: return nullptr; + } +} + +bool isAddonActive(const GameWorldBase& gwb) +{ + return gwb.GetGGS().isEnabled(AddonId::LEATHER); +} + +} // namespace leatheraddon \ No newline at end of file diff --git a/libs/s25main/LeatherLoader.h b/libs/s25main/LeatherLoader.h new file mode 100644 index 0000000000..a921a48d9d --- /dev/null +++ b/libs/s25main/LeatherLoader.h @@ -0,0 +1,74 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +/////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "helpers/EnumArray.h" +#include "ogl/glSmartBitmap.h" +#include "gameTypes/BuildingType.h" +#include "gameTypes/GoodTypes.h" +#include "gameTypes/JobTypes.h" + +class glArchivItem_Bitmap; +class glTexturePacker; +class GameWorldBase; + +namespace leatheraddon { + +bool isLeatherAddonBuildingType(BuildingType bld); +bool isLeatherAddonGoodType(GoodType good); +bool isLeatherAddonJobType(Job job); + +enum class BobTypes +{ + SKINNER_SKINNING_ANIMAL_CARCASS_ANIMATION, + SKINNER_WALKING, + SKINNER_CARRYING_SKINS, + TANNERY_WORK_WINDOW_ANIMATION, + TANNER_WALKING, + TANNER_CARRYING_LEATHER_IN_OUT, + LEATHERWORKS_WORK_WINDOW_ANIMATION, + LEATHERWORKER_WALKING, + LEATHERWORKER_CARRYING_ARMOR_IN_OUT, + THIN_CARRIER_CARRYING_SKINS, + FAT_CARRIER_CARRYING_SKINS, + THIN_CARRIER_CARRYING_LEATHER, + FAT_CARRIER_CARRYING_LEATHER, + THIN_CARRIER_CARRYING_ARMOR, + FAT_CARRIER_CARRYING_ARMOR, + DISTRIBUTION_OF_PIGS_ICON, + SKINS_WARE_ICON, + LEATHER_WARE_ICON, + LEATHERWORKING_WARES_TRANSPORT_PRIORITY_TREE_ICON, + ARMOR_WARE_ICON, + ARMOR_DELIVER_ICON, + DISABLE_DELIVERY_ARMOR_ICON, + SKINNER_JOB_ICON, + TANNER_JOB_ICON, + LEATHERWORKER_JOB_ICON, + SKINS_WARE_ON_GROUND_OF_FLAG, + DONKEY_BOAT_CARRYING_SKINS_WARE, + LEATHER_WARE_ON_GROUND_OF_FLAG, + DONKEY_BOAT_CARRYING_LEATHER_WARE, + ARMOR_WARE_ON_GROUND_OF_FLAG, + DONKEY_BOAT_CARRYING_ARMOR_WARE, + STOP_COINS_X_SIGN_OVERRIDE, + STOP_ARMOR_X_SIGN +}; + +constexpr auto maxEnumValue(BobTypes) +{ + return BobTypes::STOP_ARMOR_X_SIGN; +} + +extern helpers::EnumArray bobIndex; + +ITexture* GetWareTex(GoodType good); +ITexture* GetWareStackTex(GoodType good); +ITexture* GetWareDonkeyTex(GoodType good); +ITexture* GetJobTex(Job job); +bool isAddonActive(const GameWorldBase& gwb); + +} // namespace leatheraddon diff --git a/libs/s25main/Loader.cpp b/libs/s25main/Loader.cpp index 38ae4cdfd9..13073395d1 100644 --- a/libs/s25main/Loader.cpp +++ b/libs/s25main/Loader.cpp @@ -5,6 +5,7 @@ /////////////////////////////////////////////////////////////////////////////// #include "Loader.h" +#include "LeatherLoader.h" #include "ListDir.h" #include "RttrConfig.h" #include "Settings.h" @@ -185,6 +186,8 @@ ITexture* Loader::GetWareTex(GoodType ware) { if(wineaddon::isWineAddonGoodType(ware)) return wineaddon::GetWareTex(ware); + else if(leatheraddon::isLeatherAddonGoodType(ware)) + return leatheraddon::GetWareTex(ware); else return GetMapTexture(WARES_TEX_MAP_OFFSET + rttr::enum_cast(ware)); } @@ -193,6 +196,8 @@ ITexture* Loader::GetWareStackTex(GoodType ware) { if(wineaddon::isWineAddonGoodType(ware)) return wineaddon::GetWareStackTex(ware); + else if(leatheraddon::isLeatherAddonGoodType(ware)) + return leatheraddon::GetWareStackTex(ware); else return GetMapTexture(WARE_STACK_TEX_MAP_OFFSET + rttr::enum_cast(ware)); } @@ -201,6 +206,8 @@ ITexture* Loader::GetWareDonkeyTex(GoodType ware) { if(wineaddon::isWineAddonGoodType(ware)) return wineaddon::GetWareDonkeyTex(ware); + if(leatheraddon::isLeatherAddonGoodType(ware)) + return leatheraddon::GetWareDonkeyTex(ware); else return GetMapTexture(WARES_DONKEY_TEX_MAP_OFFSET + rttr::enum_cast(ware)); } @@ -209,6 +216,8 @@ ITexture* Loader::GetJobTex(Job job) { if(wineaddon::isWineAddonJobType(job)) return wineaddon::GetJobTex(job); + else if(leatheraddon::isLeatherAddonJobType(job)) + return leatheraddon::GetJobTex(job); else return (job == Job::CharBurner) ? GetTextureN("io_new", 5) : GetMapTexture(2300 + rttr::enum_cast(job)); } @@ -512,6 +521,9 @@ bool Loader::LoadFilesAtGame(const std::string& mapGfxPath, bool isWinterGFX, co if(!LoadResources({"wine_bobs"})) return false; + if(!LoadResources({"leather_bobs"})) + return false; + const bfs::path mapGFXFile = config_.ExpandPath(mapGfxPath); if(!Load(mapGFXFile, pal5)) return false; @@ -875,6 +887,7 @@ void Loader::fillCaches() throw std::runtime_error("carrier not found"); libsiedler2::Archiv wine_bob_carrier = GetArchive("wine_bobs"); + libsiedler2::Archiv leather_bob_carrier = GetArchive("leather_bobs"); for(bool fat : {true, false}) { @@ -907,6 +920,24 @@ void Loader::fillCaches() wineaddon::bobIndex[fat ? wineaddon::BobTypes::FAT_CARRIER_CARRYING_WINE : wineaddon::BobTypes::THIN_CARRIER_CARRYING_WINE] + static_cast(imgDir)))); + } else if(leatheraddon::isLeatherAddonGoodType(ware)) + { + leatheraddon::BobTypes carrierEnum; + if(ware == GoodType::Skins) + carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS : + leatheraddon::BobTypes::THIN_CARRIER_CARRYING_SKINS; + + if(ware == GoodType::Leather) + carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_LEATHER : + leatheraddon::BobTypes::THIN_CARRIER_CARRYING_LEATHER; + + if(ware == GoodType::Armor) + carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_ARMOR : + leatheraddon::BobTypes::THIN_CARRIER_CARRYING_ARMOR; + + bmp.add(dynamic_cast(bob_carrier->getBody(fat, imgDir, ani_step))); + bmp.add(dynamic_cast(leather_bob_carrier.get( + leatheraddon::bobIndex[carrierEnum] + static_cast(imgDir)))); } else { bmp.add(dynamic_cast(bob_carrier->getBody(fat, imgDir, ani_step))); diff --git a/libs/s25main/SerializedGameData.cpp b/libs/s25main/SerializedGameData.cpp index 46bd358ff7..25c33d1a10 100644 --- a/libs/s25main/SerializedGameData.cpp +++ b/libs/s25main/SerializedGameData.cpp @@ -40,6 +40,7 @@ #include "figures/nofGeologist.h" #include "figures/nofHunter.h" #include "figures/nofIronfounder.h" +#include "figures/nofLeatherWorker.h" #include "figures/nofMetalworker.h" #include "figures/nofMiller.h" #include "figures/nofMiner.h" @@ -51,7 +52,9 @@ #include "figures/nofScout_Free.h" #include "figures/nofScout_LookoutTower.h" #include "figures/nofShipWright.h" +#include "figures/nofSkinner.h" #include "figures/nofStonemason.h" +#include "figures/nofTanner.h" #include "figures/nofTempleServant.h" #include "figures/nofTradeDonkey.h" #include "figures/nofTradeLeader.h" @@ -102,6 +105,7 @@ /// 9: Drop serialization of node BQ /// 10: troop_limits state introduced to military buildings /// 11:: wineaddon added, three new building types and two new goods +/// 12:: leatheraddon added, three new building types and three new goods static const unsigned currentGameDataVersion = 11; // clang-format on @@ -180,6 +184,10 @@ std::unique_ptr SerializedGameData::Create_GameObject(const GO_Type RTTR_CREATE_GO(GO_Type::NofTempleservant, nofTempleServant); RTTR_CREATE_GO(GO_Type::Grapefield, noGrapefield); RTTR_CREATE_GO(GO_Type::NobTemple, nobTemple); + RTTR_CREATE_GO(GO_Type::NofSkinner, nofSkinner); + RTTR_CREATE_GO(GO_Type::NofTanner, nofTanner); + RTTR_CREATE_GO(GO_Type::NofLeatherWorker, nofLeatherWorker); + case GO_Type::Nothing: RTTR_Assert(false); break; #undef RTTR_CREATE_GO } diff --git a/libs/s25main/Ware.h b/libs/s25main/Ware.h index 1a4c820b40..be25c94634 100644 --- a/libs/s25main/Ware.h +++ b/libs/s25main/Ware.h @@ -113,6 +113,7 @@ class Ware : public GameObject { switch(value) { + case GoodType::Armor: return ("GoodType::Armor"); case GoodType::Axe: return ("GoodType::Axe"); case GoodType::Beer: return ("GoodType::Beer"); case GoodType::Boards: return ("GoodType::Boards"); @@ -132,6 +133,7 @@ class Ware : public GameObject case GoodType::Hammer: return ("GoodType::Hammer"); case GoodType::Iron: return ("GoodType::Iron"); case GoodType::IronOre: return ("GoodType::IronOre"); + case GoodType::Leather: return ("GoodType::Leather"); case GoodType::Meat: return ("GoodType::Meat"); case GoodType::Nothing: return ("GoodType::Nothing"); case GoodType::PickAxe: return ("GoodType::PickAxe"); @@ -144,6 +146,7 @@ class Ware : public GameObject case GoodType::ShieldRomans: return ("GoodType::ShieldRomans"); case GoodType::ShieldVikings: return ("GoodType::ShieldVikings"); case GoodType::Shovel: return ("GoodType::Shovel"); + case GoodType::Skins: return ("GoodType::Skins"); case GoodType::Stones: return ("GoodType::Stones"); case GoodType::Sword: return ("GoodType::Sword"); case GoodType::Tongs: return ("GoodType::Tongs"); diff --git a/libs/s25main/addons/AddonLeather.h b/libs/s25main/addons/AddonLeather.h new file mode 100644 index 0000000000..c8d868fce4 --- /dev/null +++ b/libs/s25main/addons/AddonLeather.h @@ -0,0 +1,20 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "AddonBool.h" +#include "mygettext/mygettext.h" + +/** + * Addon for a leather industry + */ +class AddonLeather : public AddonBool +{ +public: + AddonLeather() + : AddonBool(AddonId::LEATHER, AddonGroup::Economy, _("Enable leather economy"), + _("Allows to build the leather economy buildings.")) + {} +}; diff --git a/libs/s25main/addons/Addons.h b/libs/s25main/addons/Addons.h index f46b2a607d..c98f52a127 100644 --- a/libs/s25main/addons/Addons.h +++ b/libs/s25main/addons/Addons.h @@ -61,4 +61,5 @@ #include "addons/AddonAutoFlags.h" +#include "addons/AddonLeather.h" #include "addons/AddonWine.h" diff --git a/libs/s25main/addons/const_addons.h b/libs/s25main/addons/const_addons.h index fbb3245090..69462cd488 100644 --- a/libs/s25main/addons/const_addons.h +++ b/libs/s25main/addons/const_addons.h @@ -74,7 +74,7 @@ ENUM_WITH_STRING(AddonId, LIMIT_CATAPULTS = 0x00000000, INEXHAUSTIBLE_MINES = 0x AUTOFLAGS = 0x00F00000, - WINE = 0x01000000) + WINE = 0x01000000, LEATHER = 0x01000001) //-V:AddonId:801 enum class AddonGroup : unsigned diff --git a/libs/s25main/ai/aijh/AIPlayerJH.cpp b/libs/s25main/ai/aijh/AIPlayerJH.cpp index 9bd836dfb2..bc0252c333 100644 --- a/libs/s25main/ai/aijh/AIPlayerJH.cpp +++ b/libs/s25main/ai/aijh/AIPlayerJH.cpp @@ -2112,12 +2112,16 @@ void AIPlayerJH::InitDistribution() goodSettings[18] = 10; // boards new buildings goodSettings[19] = 4; // boards metalworks goodSettings[20] = 2; // boards shipyard + goodSettings[21] = 1; // boards tannery - goodSettings[21] = 10; // water bakery - goodSettings[22] = 10; // water brewery - goodSettings[23] = 10; // water pigfarm - goodSettings[24] = 10; // water donkeybreeder - goodSettings[25] = 2; // water vineyard + goodSettings[22] = 10; // water bakery + goodSettings[23] = 10; // water brewery + goodSettings[24] = 10; // water pigfarm + goodSettings[25] = 10; // water donkeybreeder + goodSettings[26] = 2; // water vineyard + + goodSettings[27] = 8; // ham slaughterhouse + goodSettings[28] = 3; // ham skinner aii.ChangeDistribution(goodSettings); } diff --git a/libs/s25main/desktops/dskCredits.cpp b/libs/s25main/desktops/dskCredits.cpp index 573b70924b..46438a5bce 100644 --- a/libs/s25main/desktops/dskCredits.cpp +++ b/libs/s25main/desktops/dskCredits.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "dskCredits.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "controls/ctrlButton.h" @@ -358,7 +359,7 @@ void dskCredits::DrawCredit() template T randEnum() { - return T(rand() % (helpers::NumEnumValues_v - 2)); + return T(rand() % (helpers::NumEnumValues_v - 5)); } void dskCredits::DrawBobs() @@ -400,7 +401,8 @@ void dskCredits::DrawBobs() // exclude "headless" bobs if(job == Job::Miller || job == Job::Baker || job == Job::Brewer || job == Job::Armorer - || job == Job::CharBurner /* Comes from another file */ || wineaddon::isWineAddonJobType(job)) + || job == Job::CharBurner /* Comes from another file */ || wineaddon::isWineAddonJobType(job) + || leatheraddon::isLeatherAddonJobType(job)) { const auto ware = randEnum(); // Japanese shield is missing diff --git a/libs/s25main/factories/JobFactory.cpp b/libs/s25main/factories/JobFactory.cpp index 521ad3a0fb..e25cc4606c 100644 --- a/libs/s25main/factories/JobFactory.cpp +++ b/libs/s25main/factories/JobFactory.cpp @@ -28,6 +28,7 @@ #include "figures/nofGeologist.h" #include "figures/nofHunter.h" #include "figures/nofIronfounder.h" +#include "figures/nofLeatherWorker.h" #include "figures/nofMetalworker.h" #include "figures/nofMiller.h" #include "figures/nofMiner.h" @@ -39,7 +40,9 @@ #include "figures/nofScout_Free.h" #include "figures/nofScout_LookoutTower.h" #include "figures/nofShipWright.h" +#include "figures/nofSkinner.h" #include "figures/nofStonemason.h" +#include "figures/nofTanner.h" #include "figures/nofTempleServant.h" #include "figures/nofVintner.h" #include "figures/nofWellguy.h" @@ -179,6 +182,15 @@ std::unique_ptr JobFactory::CreateJob(const Job job_id, const MapPoint case Job::TempleServant: RTTR_Assert(dynamic_cast(goal)); return std::make_unique(pt, player, static_cast(goal)); + case Job::Skinner: + RTTR_Assert(dynamic_cast(goal)); + return std::make_unique(pt, player, static_cast(goal)); + case Job::Tanner: + RTTR_Assert(dynamic_cast(goal)); + return std::make_unique(pt, player, static_cast(goal)); + case Job::LeatherWorker: + RTTR_Assert(dynamic_cast(goal)); + return std::make_unique(pt, player, static_cast(goal)); case Job::BoatCarrier: throw std::logic_error("Cannot create a boat carrier job (try creating Job::Helper)."); break; diff --git a/libs/s25main/figures/noFigure.cpp b/libs/s25main/figures/noFigure.cpp index f85b9609dd..43ffbb6074 100644 --- a/libs/s25main/figures/noFigure.cpp +++ b/libs/s25main/figures/noFigure.cpp @@ -6,6 +6,7 @@ #include "EventManager.h" #include "FindWhConditions.h" #include "GamePlayer.h" +#include "LeatherLoader.h" #include "Loader.h" #include "SerializedGameData.h" #include "WineLoader.h" @@ -809,6 +810,15 @@ void noFigure::DrawWalking(DrawPoint drawPt) case Job::TempleServant: DrawWalking(drawPt, "wine_bobs", wineaddon::bobIndex[wineaddon::BobTypes::TEMPLESERVANT_WALKING]); break; + case Job::Skinner: + DrawWalking(drawPt, "leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::SKINNER_WALKING]); + break; + case Job::Tanner: + DrawWalking(drawPt, "leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::TANNER_WALKING]); + break; + case Job::LeatherWorker: + DrawWalking(drawPt, "leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::LEATHERWORKER_WALKING]); + break; default: DrawWalkingBobJobs(drawPt, job_); break; } } diff --git a/libs/s25main/figures/nofLeatherWorker.cpp b/libs/s25main/figures/nofLeatherWorker.cpp new file mode 100644 index 0000000000..754e2841e6 --- /dev/null +++ b/libs/s25main/figures/nofLeatherWorker.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "nofLeatherWorker.h" +#include "GamePlayer.h" +#include "LeatherLoader.h" +#include "Loader.h" +#include "SoundManager.h" +#include "buildings/nobUsual.h" +#include "network/GameClient.h" +#include "ogl/glArchivItem_Bitmap_Player.h" +#include "world/GameWorld.h" + +using namespace leatheraddon; + +nofLeatherWorker::nofLeatherWorker(const MapPoint pos, const unsigned char player, nobUsual* workplace) + : nofWorkman(Job::LeatherWorker, pos, player, workplace) +{} + +nofLeatherWorker::nofLeatherWorker(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) {} + +void nofLeatherWorker::DrawWorking(DrawPoint drawPt) +{ + constexpr helpers::EnumArray offsets = {{{11, -41}, {21, -20}, {21, -17}, {24, -13}, {22, -14}}}; + + const unsigned now_id = GAMECLIENT.Interpolate(230, current_ev); + + LOADER.GetPlayerImage("leather_bobs", bobIndex[BobTypes::LEATHERWORKS_WORK_WINDOW_ANIMATION] + (now_id % 23)) + ->DrawFull(drawPt + offsets[workplace->GetNation()], COLOR_WHITE, world->GetPlayer(workplace->GetPlayer()).color); + + // hammer sound + if(now_id % 23 == 3 || now_id % 23 == 7) + { + world->GetSoundMgr().playNOSound(72, *this, now_id, 100); + was_sounding = true; + } + // saw sound 1 + else if(now_id % 23 == 9) + { + world->GetSoundMgr().playNOSound(54, *this, now_id); + was_sounding = true; + } else if(now_id % 23 == 17) + { + world->GetSoundMgr().playNOSound(55, *this, now_id); + was_sounding = true; + } + + last_id = now_id; +} + +unsigned short nofLeatherWorker::GetCarryID() const +{ + throw std::logic_error("Must not be called. Handled by custom DrawWalkingWithWare"); +} + +void nofLeatherWorker::DrawWalkingWithWare(DrawPoint drawPt) +{ + DrawWalking(drawPt, "leather_bobs", bobIndex[BobTypes::LEATHERWORKER_CARRYING_ARMOR_IN_OUT]); +} + +helpers::OptionalEnum nofLeatherWorker::ProduceWare() +{ + return GoodType::Armor; +} diff --git a/libs/s25main/figures/nofLeatherWorker.h b/libs/s25main/figures/nofLeatherWorker.h new file mode 100644 index 0000000000..351f6f4af7 --- /dev/null +++ b/libs/s25main/figures/nofLeatherWorker.h @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "nofWorkman.h" + +class SerializedGameData; +class nobUsual; + +#ifdef _MSC_VER +# pragma warning(disable : 4646) // function declared with [[noreturn]] has non-void return type +#endif + +class nofLeatherWorker : public nofWorkman +{ + /// Draw worker at work + void DrawWorking(DrawPoint drawPt) override; + /// Id in jobs.bob or carrier.bob when carrying a ware + [[noreturn]] unsigned short GetCarryID() const override; + /// Der Arbeiter erzeugt eine Ware + helpers::OptionalEnum ProduceWare() override; + + /// Draws the figure while returning home / entering the building (often carrying wares) + void DrawWalkingWithWare(DrawPoint drawPt) override; + +public: + nofLeatherWorker(MapPoint pos, unsigned char player, nobUsual* workplace); + nofLeatherWorker(SerializedGameData& sgd, unsigned obj_id); + + GO_Type GetGOT() const final { return GO_Type::NofLeatherWorker; } +}; diff --git a/libs/s25main/figures/nofSkinner.cpp b/libs/s25main/figures/nofSkinner.cpp new file mode 100644 index 0000000000..772948287e --- /dev/null +++ b/libs/s25main/figures/nofSkinner.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "nofSkinner.h" +#include "GamePlayer.h" +#include "LeatherLoader.h" +#include "Loader.h" +#include "SoundManager.h" +#include "buildings/nobUsual.h" +#include "network/GameClient.h" +#include "ogl/glArchivItem_Bitmap_Player.h" +#include "world/GameWorld.h" + +using namespace leatheraddon; + +nofSkinner::nofSkinner(const MapPoint pos, const unsigned char player, nobUsual* workplace) + : nofWorkman(Job::Skinner, pos, player, workplace) +{} + +nofSkinner::nofSkinner(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) {} + +void nofSkinner::DrawWorking(DrawPoint /*drawPt*/) +{ +} + +unsigned short nofSkinner::GetCarryID() const +{ + throw std::logic_error("Must not be called. Handled by custom DrawWalkingWithWare"); +} + +void nofSkinner::DrawWalkingWithWare(DrawPoint drawPt) +{ + DrawWalking(drawPt, "leather_bobs", bobIndex[BobTypes::SKINNER_CARRYING_SKINS]); +} + +helpers::OptionalEnum nofSkinner::ProduceWare() +{ + return GoodType::Skins; +} diff --git a/libs/s25main/figures/nofSkinner.h b/libs/s25main/figures/nofSkinner.h new file mode 100644 index 0000000000..1a216b7a7b --- /dev/null +++ b/libs/s25main/figures/nofSkinner.h @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "nofWorkman.h" + +class SerializedGameData; +class nobUsual; + +#ifdef _MSC_VER +# pragma warning(disable : 4646) // function declared with [[noreturn]] has non-void return type +#endif + +class nofSkinner : public nofWorkman +{ + /// Draw worker at work + void DrawWorking(DrawPoint drawPt) override; + /// Id in jobs.bob or carrier.bob when carrying a ware + [[noreturn]] unsigned short GetCarryID() const override; + /// Der Arbeiter erzeugt eine Ware + helpers::OptionalEnum ProduceWare() override; + + /// Draws the figure while returning home / entering the building (often carrying wares) + void DrawWalkingWithWare(DrawPoint drawPt) override; + +public: + nofSkinner(MapPoint pos, unsigned char player, nobUsual* workplace); + nofSkinner(SerializedGameData& sgd, unsigned obj_id); + + GO_Type GetGOT() const final { return GO_Type::NofSkinner; } +}; diff --git a/libs/s25main/figures/nofTanner.cpp b/libs/s25main/figures/nofTanner.cpp new file mode 100644 index 0000000000..3a2b5a8ef6 --- /dev/null +++ b/libs/s25main/figures/nofTanner.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "nofTanner.h" +#include "GamePlayer.h" +#include "LeatherLoader.h" +#include "Loader.h" +#include "SoundManager.h" +#include "buildings/nobUsual.h" +#include "network/GameClient.h" +#include "ogl/glArchivItem_Bitmap_Player.h" +#include "world/GameWorld.h" + +using namespace leatheraddon; + +nofTanner::nofTanner(const MapPoint pos, const unsigned char player, nobUsual* workplace) + : nofWorkman(Job::Tanner, pos, player, workplace) +{} + +nofTanner::nofTanner(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) {} + +void nofTanner::DrawWorking(DrawPoint drawPt) +{ + constexpr helpers::EnumArray offsets = {{{28, -14}, {28, -8}, {-14, -22}, {-5, -25}, {17, -35}}}; + + unsigned now_id = GAMECLIENT.Interpolate(136, current_ev); + + LOADER.GetPlayerImage("leather_bobs", bobIndex[BobTypes::TANNERY_WORK_WINDOW_ANIMATION] + (now_id) % 8) + ->DrawFull(drawPt + offsets[workplace->GetNation()], COLOR_WHITE, world->GetPlayer(workplace->GetPlayer()).color); + + last_id = now_id; +} + +unsigned short nofTanner::GetCarryID() const +{ + throw std::logic_error("Must not be called. Handled by custom DrawWalkingWithWare"); +} + +void nofTanner::DrawWalkingWithWare(DrawPoint drawPt) +{ + DrawWalking(drawPt, "leather_bobs", bobIndex[BobTypes::TANNER_CARRYING_LEATHER_IN_OUT]); +} + +helpers::OptionalEnum nofTanner::ProduceWare() +{ + return GoodType::Leather; +} diff --git a/libs/s25main/figures/nofTanner.h b/libs/s25main/figures/nofTanner.h new file mode 100644 index 0000000000..f0da952188 --- /dev/null +++ b/libs/s25main/figures/nofTanner.h @@ -0,0 +1,33 @@ +// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org) +// +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "nofWorkman.h" + +class SerializedGameData; +class nobUsual; + +#ifdef _MSC_VER +# pragma warning(disable : 4646) // function declared with [[noreturn]] has non-void return type +#endif + +class nofTanner : public nofWorkman +{ + /// Draw worker at work + void DrawWorking(DrawPoint drawPt) override; + /// Id in jobs.bob or carrier.bob when carrying a ware + [[noreturn]] unsigned short GetCarryID() const override; + /// Der Arbeiter erzeugt eine Ware + helpers::OptionalEnum ProduceWare() override; + + /// Draws the figure while returning home / entering the building (often carrying wares) + void DrawWalkingWithWare(DrawPoint drawPt) override; + +public: + nofTanner(MapPoint pos, unsigned char player, nobUsual* workplace); + nofTanner(SerializedGameData& sgd, unsigned obj_id); + + GO_Type GetGOT() const final { return GO_Type::NofTanner; } +}; diff --git a/libs/s25main/gameData/BuildingConsts.cpp b/libs/s25main/gameData/BuildingConsts.cpp index 60500fbe75..c09aed8805 100644 --- a/libs/s25main/gameData/BuildingConsts.cpp +++ b/libs/s25main/gameData/BuildingConsts.cpp @@ -10,19 +10,19 @@ const helpers::EnumArray BUILDING_NAMES = { gettext_noop("Headquarters"), gettext_noop("Barracks"), gettext_noop("Guardhouse"), - "", + gettext_noop("Skinner"), gettext_noop("Watchtower"), gettext_noop("Vineyard"), gettext_noop("Winery"), gettext_noop("Temple"), - "", + gettext_noop("Tannery"), gettext_noop("Fortress"), gettext_noop("Granite mine"), gettext_noop("Coal mine"), gettext_noop("Iron mine"), gettext_noop("Gold mine"), gettext_noop("Lookout tower"), - "", + gettext_noop("Leatherworks"), gettext_noop("Catapult"), gettext_noop("Woodcutter"), gettext_noop("Fishery"), @@ -92,8 +92,11 @@ const helpers::EnumArray BUILDING_HELP_STRINGS = {{ "gold coins the soldiers here can " "not train and improve their " "skills."), - // Nothing - "", + // Skinner building + gettext_noop("Skins are gathered from animal carcasses " + "by the skinner. They are sent to the tannery " + "for leather production. The skinner can also " + "be supplied with pigs for extra skins."), // Watchtower gettext_noop("The watchtower with its large " "amount of space is best suited " @@ -126,8 +129,11 @@ const helpers::EnumArray BUILDING_HELP_STRINGS = {{ "working when mines become exhausted. The " "desired mineral can be selected by " "toggling the output button."), - "", - // Nothing + // Tannery building + gettext_noop("The tanner works animals skins to form leather. " + "Before tanning; the skins are cured, scraped and " + "stretched on wooden frames made from boards. " + "Leather is used to produce armor at the leatherworks."), // Fortress gettext_noop("The defensive capabilities and " "size of the fortress are " @@ -168,8 +174,10 @@ const helpers::EnumArray BUILDING_HELP_STRINGS = {{ gettext_noop("From the lookout tower you can " "see far into previously " "unexplored lands."), - // Nothing - "", + // Leatherworks building + gettext_noop("The leatherworker makes armor from finely " + "tanned leather. This is used to bolster " + "your soldiers' defence."), // Catapult gettext_noop("Thanks to its immense strength, " "the catapults represents an " @@ -320,6 +328,8 @@ const helpers::MultiEnumArray BUILDING_SMOKE_C africans[BuildingType::Charburner] = SmokeConst(2, {-18, -52}); africans[BuildingType::Bakery] = SmokeConst(4, {27, -39}); africans[BuildingType::Mint] = SmokeConst(1, {17, -52}); + africans[BuildingType::Skinner] = SmokeConst(3, {5, -45}); + africans[BuildingType::Tannery] = SmokeConst(2, {24, -39}); auto& japanese = result[Nation::Japanese]; japanese[BuildingType::Armory] = SmokeConst(1, {-22, -43}); japanese[BuildingType::Charburner] = SmokeConst(2, {-32, -55}); @@ -332,6 +342,8 @@ const helpers::MultiEnumArray BUILDING_SMOKE_C romans[BuildingType::Charburner] = SmokeConst(2, {-36, -38}); romans[BuildingType::Bakery] = SmokeConst(4, {-15, -26}); romans[BuildingType::Mint] = SmokeConst(4, {20, -50}); + romans[BuildingType::Skinner] = SmokeConst(2, {6, -41}); + romans[BuildingType::Tannery] = SmokeConst(3, {-23, -42}); auto& vikings = result[Nation::Vikings]; vikings[BuildingType::Woodcutter] = SmokeConst(1, {2, -36}); vikings[BuildingType::Fishery] = SmokeConst(1, {4, -36}); @@ -352,6 +364,9 @@ const helpers::MultiEnumArray BUILDING_SMOKE_C vikings[BuildingType::DonkeyBreeder] = SmokeConst(4, {-27, -40}); vikings[BuildingType::Vineyard] = SmokeConst(1, {18, -48}); vikings[BuildingType::Winery] = SmokeConst(1, {-14, -32}); + vikings[BuildingType::Skinner] = SmokeConst(1, {7, -39}); + vikings[BuildingType::Tannery] = SmokeConst(3, {-12, -46}); + vikings[BuildingType::LeatherWorks] = SmokeConst(2, {-15, -37}); auto& babylonians = result[Nation::Babylonians]; babylonians[BuildingType::Brewery] = SmokeConst(2, {-18, -43}); babylonians[BuildingType::Armory] = SmokeConst(1, {-22, -47}); diff --git a/libs/s25main/gameData/BuildingConsts.h b/libs/s25main/gameData/BuildingConsts.h index 515df3bc24..307843d173 100644 --- a/libs/s25main/gameData/BuildingConsts.h +++ b/libs/s25main/gameData/BuildingConsts.h @@ -14,40 +14,40 @@ extern const helpers::EnumArray BUILDING_NAMES; constexpr helpers::EnumArray SUPPRESS_UNUSED BUILDING_COSTS = { - {{0, 0}, {2, 0}, {2, 3}, {0, 0}, {3, 5}, {4, 4}, {2, 3}, {4, 7}, {0, 0}, {4, 7}, {4, 0}, {4, 0}, {4, 0}, {4, 0}, - {4, 0}, {0, 0}, {4, 2}, {2, 0}, {2, 0}, {2, 0}, {2, 0}, {2, 2}, {2, 0}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {4, 3}, + {{0, 0}, {2, 0}, {2, 3}, {2, 0}, {3, 5}, {4, 4}, {2, 3}, {4, 7}, {2, 2}, {4, 7}, {4, 0}, {4, 0}, {4, 0}, {4, 0}, + {4, 0}, {2, 2}, {4, 2}, {2, 0}, {2, 0}, {2, 0}, {2, 0}, {2, 2}, {2, 0}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {4, 3}, {3, 3}, {4, 3}, {0, 0}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 0}, {2, 3}, {3, 3}, {3, 3}, {4, 6}}}; // Bauqualitäten der Gebäude constexpr helpers::EnumArray SUPPRESS_UNUSED BUILDING_SIZE = { - {BuildingQuality::Castle, BuildingQuality::Hut, BuildingQuality::Hut, BuildingQuality::Nothing, - BuildingQuality::House, BuildingQuality::Castle, BuildingQuality::House, BuildingQuality::Castle, - BuildingQuality::Nothing, BuildingQuality::Castle, BuildingQuality::Mine, BuildingQuality::Mine, - BuildingQuality::Mine, BuildingQuality::Mine, BuildingQuality::Hut, BuildingQuality::Nothing, - BuildingQuality::House, BuildingQuality::Hut, BuildingQuality::Hut, BuildingQuality::Hut, - BuildingQuality::Hut, BuildingQuality::House, BuildingQuality::Hut, BuildingQuality::House, - BuildingQuality::House, BuildingQuality::House, BuildingQuality::House, BuildingQuality::Castle, - BuildingQuality::Castle, BuildingQuality::House, BuildingQuality::Nothing, BuildingQuality::House, - BuildingQuality::House, BuildingQuality::House, BuildingQuality::House, BuildingQuality::Hut, - BuildingQuality::House, BuildingQuality::Castle, BuildingQuality::Castle, BuildingQuality::Harbor}}; + {BuildingQuality::Castle, BuildingQuality::Hut, BuildingQuality::Hut, BuildingQuality::Hut, + BuildingQuality::House, BuildingQuality::Castle, BuildingQuality::House, BuildingQuality::Castle, + BuildingQuality::House, BuildingQuality::Castle, BuildingQuality::Mine, BuildingQuality::Mine, + BuildingQuality::Mine, BuildingQuality::Mine, BuildingQuality::Hut, BuildingQuality::House, + BuildingQuality::House, BuildingQuality::Hut, BuildingQuality::Hut, BuildingQuality::Hut, + BuildingQuality::Hut, BuildingQuality::House, BuildingQuality::Hut, BuildingQuality::House, + BuildingQuality::House, BuildingQuality::House, BuildingQuality::House, BuildingQuality::Castle, + BuildingQuality::Castle, BuildingQuality::House, BuildingQuality::Nothing, BuildingQuality::House, + BuildingQuality::House, BuildingQuality::House, BuildingQuality::House, BuildingQuality::Hut, + BuildingQuality::House, BuildingQuality::Castle, BuildingQuality::Castle, BuildingQuality::Harbor}}; const helpers::EnumArray SUPPRESS_UNUSED BLD_WORK_DESC = {{ {}, // HQ {Job::Private, boost::none, WaresNeeded(GoodType::Coins), 1}, {Job::Private, boost::none, WaresNeeded(GoodType::Coins), 2}, - {}, + {Job::Skinner, GoodType::Skins, WaresNeeded(GoodType::Ham), 3}, {Job::Private, boost::none, WaresNeeded(GoodType::Coins), 4}, {Job::Winegrower, GoodType::Grapes, WaresNeeded(GoodType::Wood, GoodType::Water)}, {Job::Vintner, GoodType::Wine, WaresNeeded(GoodType::Grapes)}, {Job::TempleServant, GoodType::Gold, WaresNeeded(GoodType::Wine, GoodType::Meat, GoodType::Bread)}, - {}, + {Job::Tanner, GoodType::Leather, WaresNeeded(GoodType::Skins, GoodType::Boards)}, {Job::Private, boost::none, WaresNeeded(GoodType::Coins), 6}, {Job::Miner, GoodType::Stones, WaresNeeded(GoodType::Fish, GoodType::Meat, GoodType::Bread), 2, false}, {Job::Miner, GoodType::Coal, WaresNeeded(GoodType::Fish, GoodType::Meat, GoodType::Bread), 2, false}, {Job::Miner, GoodType::IronOre, WaresNeeded(GoodType::Fish, GoodType::Meat, GoodType::Bread), 2, false}, {Job::Miner, GoodType::Gold, WaresNeeded(GoodType::Fish, GoodType::Meat, GoodType::Bread), 2, false}, {Job::Scout}, // No production, just existence - {}, + {Job::LeatherWorker, GoodType::Armor, WaresNeeded(GoodType::Leather)}, {Job::Helper, boost::none, WaresNeeded(GoodType::Stones), 4}, {Job::Woodcutter, GoodType::Wood}, {Job::Fisher, GoodType::Fish}, @@ -81,28 +81,28 @@ extern const helpers::MultiEnumArray BUILDING_ /// Offset of the production-/gold- stop signs per building constexpr helpers::MultiEnumArray SUPPRESS_UNUSED BUILDING_SIGN_CONSTS = { {// Nubier - {{{0, 0}, {19, -4}, {19, -3}, {0, 0}, {23, -19}, {22, -7}, {-8, -10}, {9, -24}, {0, 0}, {29, -23}, - {-2, -15}, {2, -13}, {-5, -16}, {-5, -15}, {0, 0}, {0, 0}, {0, 0}, {4, -16}, {9, -12}, {7, -10}, + {{{0, 0}, {19, -4}, {19, -3}, {-14, -1}, {23, -19}, {22, -7}, {-8, -10}, {9, -24}, {-16, -10}, {29, -23}, + {-2, -15}, {2, -13}, {-5, -16}, {-5, -15}, {0, 0}, {22, 6}, {0, 0}, {4, -16}, {9, -12}, {7, -10}, {28, -18}, {-6, -16}, {-3, -15}, {21, -11}, {14, -7}, {-14, -9}, {11, -9}, {-5, -24}, {-18, -34}, {0, 0}, {0, 0}, {3, -13}, {13, -13}, {-4, -20}, {7, -14}, {15, -4}, {0, 0}, {-22, -16}, {-14, -8}, {0, 0}}}, // Japaner - {{{0, 0}, {12, -10}, {13, -10}, {0, 0}, {25, -22}, {-26, -13}, {-8, -8}, {9, -10}, {0, 0}, {10, -14}, - {20, -2}, {12, -14}, {14, -13}, {13, -14}, {0, 0}, {0, 0}, {0, 0}, {-8, -6}, {0, 0}, {-13, -7}, + {{{0, 0}, {12, -10}, {13, -10}, {13, -1}, {25, -22}, {-26, -13}, {-8, -8}, {9, -10}, {-6, 2}, {10, -14}, + {20, -2}, {12, -14}, {14, -13}, {13, -14}, {0, 0}, {4, -18}, {0, 0}, {-8, -6}, {0, 0}, {-13, -7}, {14, -11}, {15, -10}, {-13, -7}, {16, -11}, {21, -3}, {-6, -2}, {14, -14}, {-26, -17}, {30, -25}, {0, 0}, {0, 0}, {0, -22}, {-30, -13}, {35, -20}, {13, -34}, {19, -15}, {-22, -10}, {37, -13}, {-15, -36}, {0, 0}}}, // Römer - {{{0, 0}, {15, -3}, {14, -2}, {0, 0}, {0, 0}, {36, -12}, {-8, -8}, {12, -19}, {0, 0}, {20, -39}, - {15, -2}, {26, 4}, {21, 4}, {21, 4}, {0, 0}, {0, 0}, {0, 0}, {-29, -10}, {0, 0}, {-4, 4}, + {{{0, 0}, {15, -3}, {14, -2}, {13, -7}, {0, 0}, {36, -12}, {-8, -8}, {12, -19}, {-6, -2}, {20, -39}, + {15, -2}, {26, 4}, {21, 4}, {21, 4}, {0, 0}, {-15, -8}, {0, 0}, {-29, -10}, {0, 0}, {-4, 4}, {7, -20}, {3, -13}, {0, 0}, {22, -8}, {18, -11}, {6, -14}, {23, -10}, {-28, -12}, {35, -27}, {0, 0}, {0, 0}, {2, -21}, {15, -13}, {11, -30}, {23, -5}, {10, -9}, {0, -25}, {41, -43}, {-34, -19}, {0, 0}}}, // Wikinger - {{{0, 0}, {-5, 0}, {-5, 0}, {0, 0}, {-7, -5}, {-7, -32}, {-10, -1}, {-4, 5}, {0, 0}, {17, -10}, - {20, 2}, {20, 0}, {20, -2}, {20, 0}, {0, 0}, {0, 0}, {13, -5}, {15, -6}, {-7, 2}, {17, -8}, + {{{0, 0}, {-5, 0}, {-5, 0}, {-7, -4}, {-7, -5}, {-7, -32}, {-10, -1}, {-4, 5}, {-7, 1}, {17, -10}, + {20, 2}, {20, 0}, {20, -2}, {20, 0}, {0, 0}, {-15, -8}, {13, -5}, {15, -6}, {-7, 2}, {17, -8}, {-5, 0}, {-3, 2}, {-6, 0}, {-7, 0}, {-32, -2}, {-13, -3}, {-8, -2}, {-22, -18}, {-25, -8}, {0, 0}, {0, 0}, {-8, -2}, {-17, -4}, {28, -16}, {-1, 0}, {8, -9}, {16, -15}, {-2, -25}, {-29, -9}, {0, 0}}}, // Babylonier - {{{0, 0}, {19, -6}, {19, -20}, {0, 0}, {5, -15}, {-32, -20}, {4, -16}, {10, -18}, {0, 0}, {20, -10}, - {15, -10}, {15, -10}, {15, -10}, {15, -10}, {0, 0}, {0, 0}, {13, -5}, {-5, -13}, {15, -20}, {15, -1}, + {{{0, 0}, {19, -6}, {19, -20}, {-7, -3}, {5, -15}, {-32, -20}, {4, -16}, {10, -18}, {3, -18}, {20, -10}, + {15, -10}, {15, -10}, {15, -10}, {15, -10}, {0, 0}, {5, -4}, {13, -5}, {-5, -13}, {15, -20}, {15, -1}, {11, -7}, {1, -22}, {7, -12}, {14, -16}, {21, -18}, {13, -11}, {5, -17}, {-2, -29}, {18, -20}, {0, 0}, {0, 0}, {14, -13}, {3, -17}, {0, -18}, {12, -10}, {16, 0}, {4, -16}, {-15, -11}, {-24, -9}, {0, 0}}}}}; diff --git a/libs/s25main/gameData/BuildingProperties.cpp b/libs/s25main/gameData/BuildingProperties.cpp index b987e8dd0a..6a35a26a1d 100644 --- a/libs/s25main/gameData/BuildingProperties.cpp +++ b/libs/s25main/gameData/BuildingProperties.cpp @@ -62,9 +62,6 @@ bool BuildingProperties::IsValid(BuildingType bld) { switch(bld) { - case BuildingType::Nothing2: - case BuildingType::Nothing6: - case BuildingType::Nothing7: case BuildingType::Nothing9: return false; default: return true; } diff --git a/libs/s25main/gameData/DoorConsts.h b/libs/s25main/gameData/DoorConsts.h index 8734043863..9166a0c712 100644 --- a/libs/s25main/gameData/DoorConsts.h +++ b/libs/s25main/gameData/DoorConsts.h @@ -12,17 +12,17 @@ /// Y-value for the point where the carrier disappears inside the building for each nation and building constexpr helpers::MultiEnumArray DOOR_CONSTS = { {// Nubier - {5, 10, 13, 0, 10, 0, 11, 19, 0, 6, 8, 8, 8, 8, 6, 0, 10, 10, 12, 14, - 9, 5, 11, 19, 19, 12, 18, 0, -6, 19, 0, 12, 11, 6, 10, 0, 0, -1, 4, 13}, + {5, 10, 13, 12, 10, 0, 11, 19, 4, 6, 8, 8, 8, 8, 6, 10, 10, 10, 12, 14, + 9, 5, 11, 19, 19, 12, 18, 0, -6, 19, 0, 12, 11, 6, 10, 0, 0, -1, 4, 13}, // Japaner - {9, 1, 5, 0, 12, -6, 9, -4, 0, 7, 8, 8, 8, 8, 5, 0, 10, 9, 5, 3, - 9, 10, 3, 12, 10, 13, 7, 0, -8, 14, 0, 11, 10, 9, 11, 0, 15, -7, -5, 16}, + {9, 1, 5, 9, 12, -6, 9, -4, 9, 7, 8, 8, 8, 8, 5, 13, 10, 9, 5, 3, + 9, 10, 3, 12, 10, 13, 7, 0, -8, 14, 0, 11, 10, 9, 11, 0, 15, -7, -5, 16}, // Römer - {4, 6, 8, 0, 12, 8, 16, 4, 0, -3, 8, 8, 8, 8, 6, 0, 10, 12, 14, 12, - 9, 12, 12, 16, 19, 14, 16, 0, -8, 17, 0, 6, 9, 8, 14, 6, 4, -13, -8, 2}, + {4, 6, 8, 11, 12, 8, 16, 4, 8, -3, 8, 8, 8, 8, 6, 12, 10, 12, 14, 12, + 9, 12, 12, 16, 19, 14, 16, 0, -8, 17, 0, 6, 9, 8, 14, 6, 4, -13, -8, 2}, // Wikinger - {10, 12, 11, 0, 11, -5, 9, 19, 0, 14, 9, 9, 9, 9, 4, 0, 10, 10, 10, 12, + {10, 12, 11, 12, 11, -5, 9, 19, 17, 14, 9, 9, 9, 9, 4, 8, 10, 10, 10, 12, 12, 19, 11, 13, 6, 11, 14, 0, -3, 11, 0, 9, 11, 10, 16, 0, 16, -6, -2, 10}, // Babylonians - {9, 5, 5, 0, 12, -8, 11, 16, 0, 7, 8, 8, 8, 8, 5, 0, 10, 9, 5, 3, + {9, 5, 5, 8, 12, -8, 11, 16, 9, 7, 8, 8, 8, 8, 5, 12, 10, 9, 5, 3, 9, 10, 3, 12, 10, 13, 7, 0, -8, 14, 0, 11, 10, 9, 11, 11, 15, -7, -5, 16}}}; diff --git a/libs/s25main/gameData/GoodConsts.cpp b/libs/s25main/gameData/GoodConsts.cpp index 0b02801f4c..e55eeb3236 100644 --- a/libs/s25main/gameData/GoodConsts.cpp +++ b/libs/s25main/gameData/GoodConsts.cpp @@ -43,4 +43,7 @@ const helpers::EnumArray WARE_NAMES = {{ /* 34 */ "", // Schild /* 35 */ gettext_noop("Grapes"), /* 36 */ gettext_noop("Wine"), + /* 37 */ gettext_noop("Skins"), + /* 38 */ gettext_noop("Leather"), + /* 39 */ gettext_noop("Armor"), }}; diff --git a/libs/s25main/gameData/JobConsts.cpp b/libs/s25main/gameData/JobConsts.cpp index be2f056baf..6f33cc38b8 100644 --- a/libs/s25main/gameData/JobConsts.cpp +++ b/libs/s25main/gameData/JobConsts.cpp @@ -53,6 +53,9 @@ const std::array> fullJobData = {{ {{GoodType::Shovel, 117, 106, 5}, {false, 37}, gettext_noop("Winegrower")}, {{GoodType::Nothing, 470, 95, 5}, {false, 37}, gettext_noop("Vintner")}, {{GoodType::Crucible, 470, 95, 5}, {false, 37}, gettext_noop("Temple Servant")}, + {{GoodType::Cleaver, 1, 300, 5}, {false, 37}, gettext_noop("Skinner")}, + {{GoodType::Saw, 470, 95, 5}, {false, 37}, gettext_noop("Tanner")}, + {{GoodType::Tongs, 470, 95, 5}, {false, 37}, gettext_noop("Leatherworker")}, // End data }}; diff --git a/libs/s25main/gameData/SettingTypeConv.cpp b/libs/s25main/gameData/SettingTypeConv.cpp index d67f48ec22..9f118b2b6e 100644 --- a/libs/s25main/gameData/SettingTypeConv.cpp +++ b/libs/s25main/gameData/SettingTypeConv.cpp @@ -10,9 +10,9 @@ /// Max value for each setting. /// Note: We skip the first 2 steppings for the occupation (last 4 values) as they had no effect in S2 const MilitarySettings SUPPRESS_UNUSED MILITARY_SETTINGS_SCALE = {{10, 5, 5, 5, 8, 8, 8, 8}}; -const TransportPriorities STD_TRANSPORT_PRIO = {{2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, - 12, 12, 13, 1, 3, 11, 11, 11, 1, 9, 7, 8, 1, - 1, 11, 0, 4, 5, 6, 11, 11, 1, 11, 11}}; +const TransportPriorities STD_TRANSPORT_PRIO = {{2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, + 12, 13, 1, 3, 11, 11, 11, 1, 9, 7, 8, 1, 1, 11, + 0, 4, 5, 6, 11, 11, 1, 11, 11, 12, 12, 12}}; unsigned GetTransportPrioFromOrdering(const TransportOrders& ordering, GoodType good) { diff --git a/libs/s25main/gameTypes/BuildingType.h b/libs/s25main/gameTypes/BuildingType.h index 0ac98c0144..ef1ca3d0b3 100644 --- a/libs/s25main/gameTypes/BuildingType.h +++ b/libs/s25main/gameTypes/BuildingType.h @@ -11,19 +11,19 @@ enum class BuildingType : uint8_t Headquarters, // 0 Barracks, // 1 Guardhouse, // 2 - Nothing2, // 3 + Skinner, // 3 Watchtower, // 4 Vineyard, // 5 Winery, // 6 Temple, // 7 - Nothing6, // 8 + Tannery, // 8 Fortress, // 9 GraniteMine, // 10 CoalMine, // 11 IronMine, // 12 GoldMine, // 13 LookoutTower, // 14 - Nothing7, // 15 + LeatherWorks, // 15 Catapult, // 16 Woodcutter, // 17 Fishery, // 18 @@ -56,4 +56,4 @@ constexpr auto maxEnumValue(BuildingType) } /// Number of NOTHING entries (currently unused buildings) -const unsigned NUM_UNUSED_BLD_TYPES = 4; +const unsigned NUM_UNUSED_BLD_TYPES = 1; diff --git a/libs/s25main/gameTypes/GO_Type.h b/libs/s25main/gameTypes/GO_Type.h index cf21c443fa..877f47c75b 100644 --- a/libs/s25main/gameTypes/GO_Type.h +++ b/libs/s25main/gameTypes/GO_Type.h @@ -80,8 +80,11 @@ enum class GO_Type : uint16_t NofTempleservant, Grapefield, NobTemple, + NofSkinner, + NofTanner, + NofLeatherWorker, }; constexpr auto maxEnumValue(GO_Type) { - return GO_Type::NobTemple; + return GO_Type::NofLeatherWorker; } diff --git a/libs/s25main/gameTypes/GoodTypes.h b/libs/s25main/gameTypes/GoodTypes.h index fd4c2978c7..b23cfb55c1 100644 --- a/libs/s25main/gameTypes/GoodTypes.h +++ b/libs/s25main/gameTypes/GoodTypes.h @@ -49,11 +49,14 @@ enum class GoodType : uint8_t /* 34 */ ShieldJapanese, // Schild /* 35 */ Grapes, /* 36 */ Wine, - /* 37 */ Nothing // Nothing. Is not counted as a good. TODO: Remove + /* 37 */ Skins, + /* 38 */ Leather, + /* 39 */ Armor, + /* 40 */ Nothing // Nothing. Is not counted as a good. TODO: Remove }; constexpr auto maxEnumValue(GoodType) { - return GoodType::Wine; + return GoodType::Armor; } /// List of all tools (correspond to buttons at IO:140-163) diff --git a/libs/s25main/gameTypes/JobTypes.h b/libs/s25main/gameTypes/JobTypes.h index f6a66b4619..61ee929fac 100644 --- a/libs/s25main/gameTypes/JobTypes.h +++ b/libs/s25main/gameTypes/JobTypes.h @@ -45,11 +45,14 @@ enum class Job : uint8_t Winegrower, // 32 Vintner, // 33 TempleServant, // 34 + Skinner, // 35 + Tanner, // 36 + LeatherWorker, // 37 }; constexpr auto maxEnumValue(Job) { - return Job::TempleServant; + return Job::LeatherWorker; } constexpr unsigned NUM_SOLDIER_RANKS = 5; diff --git a/libs/s25main/gameTypes/SettingsTypes.cpp b/libs/s25main/gameTypes/SettingsTypes.cpp index 2cd0308e80..a9fa3e52d7 100644 --- a/libs/s25main/gameTypes/SettingsTypes.cpp +++ b/libs/s25main/gameTypes/SettingsTypes.cpp @@ -31,10 +31,14 @@ const DistributionMap distributionMap = {{ DistributionMapping(GoodType::Boards, BuildingType::Headquarters, 10), DistributionMapping(GoodType::Boards, BuildingType::Metalworks, 4), DistributionMapping(GoodType::Boards, BuildingType::Shipyard, 2), + DistributionMapping(GoodType::Boards, BuildingType::Tannery, 1), DistributionMapping(GoodType::Water, BuildingType::Bakery, 6), DistributionMapping(GoodType::Water, BuildingType::Brewery, 3), DistributionMapping(GoodType::Water, BuildingType::PigFarm, 2), DistributionMapping(GoodType::Water, BuildingType::DonkeyBreeder, 2), DistributionMapping(GoodType::Water, BuildingType::Vineyard, 2), + + DistributionMapping(GoodType::Ham, BuildingType::Slaughterhouse, 8), + DistributionMapping(GoodType::Ham, BuildingType::Skinner, 3), }}; diff --git a/libs/s25main/gameTypes/SettingsTypes.h b/libs/s25main/gameTypes/SettingsTypes.h index 8a18589ebc..6bb34c5e14 100644 --- a/libs/s25main/gameTypes/SettingsTypes.h +++ b/libs/s25main/gameTypes/SettingsTypes.h @@ -16,7 +16,7 @@ /// 1 mapping of a required good to its building and default setting using DistributionMapping = std::tuple; /// List of all possible distribution mappings ordered by GoodType -using DistributionMap = std::array; +using DistributionMap = std::array; extern const DistributionMap distributionMap; /// List of the percentage a building should get from a specific ware using Distributions = std::array::value>; diff --git a/libs/s25main/ingameWindows/iwAction.cpp b/libs/s25main/ingameWindows/iwAction.cpp index afb5c2be12..280c42b245 100644 --- a/libs/s25main/ingameWindows/iwAction.cpp +++ b/libs/s25main/ingameWindows/iwAction.cpp @@ -100,11 +100,11 @@ iwAction::iwAction(GameInterface& gi, GameWorldView& gwv, const Tabs& tabs, MapP // Linebreak {{BuildingType::Woodcutter, BuildingType::Forester, BuildingType::Quarry, BuildingType::Fishery, BuildingType::Hunter, BuildingType::Barracks, BuildingType::Guardhouse, BuildingType::LookoutTower, - BuildingType::Well}, + BuildingType::Well, BuildingType::Skinner}, {BuildingType::Sawmill, BuildingType::Slaughterhouse, BuildingType::Mill, BuildingType::Bakery, BuildingType::Ironsmelter, BuildingType::Metalworks, BuildingType::Armory, BuildingType::Mint, - BuildingType::Shipyard, BuildingType::Brewery, BuildingType::Winery, BuildingType::Storehouse, - BuildingType::Watchtower, BuildingType::Catapult}, + BuildingType::Shipyard, BuildingType::Brewery, BuildingType::Winery, BuildingType::Tannery, + BuildingType::LeatherWorks, BuildingType::Storehouse, BuildingType::Watchtower, BuildingType::Catapult}, {BuildingType::Farm, BuildingType::PigFarm, BuildingType::DonkeyBreeder, BuildingType::Charburner, BuildingType::Vineyard, BuildingType::Temple, BuildingType::Fortress, BuildingType::HarborBuilding}, {BuildingType::GoldMine, BuildingType::IronMine, BuildingType::CoalMine, BuildingType::GraniteMine}}}; @@ -148,6 +148,13 @@ iwAction::iwAction(GameInterface& gi, GameWorldView& gwv, const Tabs& tabs, MapP building_available[BuildingType::Temple] = false; } + if(!gwv.GetWorld().GetGGS().isEnabled(AddonId::LEATHER)) + { + building_available[BuildingType::Skinner] = false; + building_available[BuildingType::Tannery] = false; + building_available[BuildingType::LeatherWorks] = false; + } + constexpr helpers::EnumArray NUM_TABS = {1, 2, 3, 1, 3}; for(unsigned char i = 0; i < NUM_TABS[tabs.build_tabs]; ++i) diff --git a/libs/s25main/ingameWindows/iwBuildOrder.cpp b/libs/s25main/ingameWindows/iwBuildOrder.cpp index bdc8544570..6b09ecca99 100644 --- a/libs/s25main/ingameWindows/iwBuildOrder.cpp +++ b/libs/s25main/ingameWindows/iwBuildOrder.cpp @@ -5,6 +5,7 @@ #include "iwBuildOrder.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "WineLoader.h" @@ -28,6 +29,8 @@ void iwBuildOrder::fillBuildOrder() return true; if(!gwv.GetWorld().GetGGS().isEnabled(AddonId::CHARBURNER) && bld == BuildingType::Charburner) return true; + if(!leatheraddon::isAddonActive(gwv.GetWorld()) && leatheraddon::isLeatherAddonBuildingType(bld)) + return true; return false; }; helpers::erase_if(pendingBuildOrder, isUnused); @@ -97,6 +100,13 @@ void iwBuildOrder::TransmitSettings() if(!gwv.GetWorld().GetGGS().isEnabled(AddonId::CHARBURNER)) transmitPendingBuildOrder[i++] = BuildingType::Charburner; + if(!leatheraddon::isAddonActive(gwv.GetWorld())) + { + transmitPendingBuildOrder[i++] = BuildingType::Skinner; + transmitPendingBuildOrder[i++] = BuildingType::Tannery; + transmitPendingBuildOrder[i++] = BuildingType::LeatherWorks; + } + if(GAMECLIENT.ChangeBuildOrder(useCustomBuildOrder, transmitPendingBuildOrder)) { GAMECLIENT.visual_settings.build_order = transmitPendingBuildOrder; diff --git a/libs/s25main/ingameWindows/iwBuildingProductivities.cpp b/libs/s25main/ingameWindows/iwBuildingProductivities.cpp index 8870e984be..85ac1361ca 100644 --- a/libs/s25main/ingameWindows/iwBuildingProductivities.cpp +++ b/libs/s25main/ingameWindows/iwBuildingProductivities.cpp @@ -5,6 +5,7 @@ #include "iwBuildingProductivities.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WineLoader.h" #include "addons/const_addons.h" @@ -15,7 +16,7 @@ #include "gameData/const_gui_ids.h" #include "s25util/colors.h" -const std::array iwBuildingProductivities::allIcons = { +const std::array iwBuildingProductivities::allIcons = { // clang-format off BuildingType::Woodcutter, BuildingType::Slaughterhouse, BuildingType::Forester, BuildingType::Metalworks, @@ -30,7 +31,8 @@ const std::array iwBuildingProductivities::allIcons = { BuildingType::PigFarm, BuildingType::GraniteMine, BuildingType::DonkeyBreeder, BuildingType::Charburner, BuildingType::Vineyard, BuildingType::Winery, - BuildingType::Temple, + BuildingType::Temple, BuildingType::Skinner, + BuildingType::Tannery, BuildingType::LeatherWorks, // clang-format on }; @@ -43,6 +45,8 @@ void iwBuildingProductivities::setBuildingOrder() return true; if(!player.GetGameWorld().GetGGS().isEnabled(AddonId::CHARBURNER) && bld == BuildingType::Charburner) return true; + if(!leatheraddon::isAddonActive(player.GetGameWorld()) && leatheraddon::isLeatherAddonBuildingType(bld)) + return true; return false; }; helpers::erase_if(usedIcons, isUnused); diff --git a/libs/s25main/ingameWindows/iwBuildingProductivities.h b/libs/s25main/ingameWindows/iwBuildingProductivities.h index c216dadb8d..da0c56f831 100644 --- a/libs/s25main/ingameWindows/iwBuildingProductivities.h +++ b/libs/s25main/ingameWindows/iwBuildingProductivities.h @@ -20,7 +20,7 @@ class iwBuildingProductivities : public IngameWindow public: iwBuildingProductivities(const GamePlayer& player); - static const std::array allIcons; + static const std::array allIcons; private: void UpdatePercents(); diff --git a/libs/s25main/ingameWindows/iwBuildings.cpp b/libs/s25main/ingameWindows/iwBuildings.cpp index f68a3d1fd6..83f958d796 100644 --- a/libs/s25main/ingameWindows/iwBuildings.cpp +++ b/libs/s25main/ingameWindows/iwBuildings.cpp @@ -5,6 +5,7 @@ #include "iwBuildings.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "WineLoader.h" @@ -44,8 +45,9 @@ void iwBuildings::setBuildingOrder() BuildingType::Mill, BuildingType::Bakery, BuildingType::Sawmill, BuildingType::Mint, BuildingType::Well, BuildingType::Shipyard, BuildingType::Farm, BuildingType::DonkeyBreeder, BuildingType::Charburner, - BuildingType::HarborBuilding, // entry 31 - BuildingType::Vineyard, BuildingType::Winery, BuildingType::Temple, // entry 34 + BuildingType::HarborBuilding, // entry 31 + BuildingType::Vineyard, BuildingType::Winery, BuildingType::Temple, // entry 34 + BuildingType::Skinner, BuildingType::Tannery, BuildingType::LeatherWorks, // entry 37 }; const auto isUnused = [&](BuildingType const& bld) { @@ -53,6 +55,8 @@ void iwBuildings::setBuildingOrder() return true; if(!gwv.GetWorld().GetGGS().isEnabled(AddonId::CHARBURNER) && bld == BuildingType::Charburner) return true; + if(!leatheraddon::isAddonActive(gwv.GetWorld()) && leatheraddon::isLeatherAddonBuildingType(bld)) + return true; return false; }; helpers::erase_if(bts, isUnused); @@ -91,7 +95,7 @@ iwBuildings::iwBuildings(GameWorldView& gwv, GameCommandFactory& gcFactory) // "Help" button Extent btSize = Extent(30, 32); - AddImageButton(35, GetFullSize() - DrawPoint(14, 20) - btSize, btSize, TextureColor::Grey, + AddImageButton(38, GetFullSize() - DrawPoint(14, 20) - btSize, btSize, TextureColor::Grey, LOADER.GetImageN("io", 225), _("Help")); } @@ -123,7 +127,7 @@ void iwBuildings::Msg_PaintAfter() void iwBuildings::Msg_ButtonClick(const unsigned ctrl_id) { - if(ctrl_id == 35) // Help button + if(ctrl_id == 38) // Help button { WINDOWMANAGER.ReplaceWindow( std::make_unique(_("The building statistics window gives you an insight into " diff --git a/libs/s25main/ingameWindows/iwShip.cpp b/libs/s25main/ingameWindows/iwShip.cpp index 30e2afaaf3..0f8beb2ccc 100644 --- a/libs/s25main/ingameWindows/iwShip.cpp +++ b/libs/s25main/ingameWindows/iwShip.cpp @@ -6,6 +6,7 @@ #include "DrawPoint.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "Ware.h" #include "WindowManager.h" @@ -265,6 +266,18 @@ void iwShip::DrawCargo() .GetPlayerImage("wine_bobs", wineaddon::bobIndex[type] + static_cast(libsiedler2::ImgDir::SW) * 8) ->DrawFull(drawPt, COLOR_WHITE, owner.color); + } else if(leatheraddon::isLeatherAddonJobType(job)) + { + leatheraddon::BobTypes type = leatheraddon::BobTypes::SKINNER_WALKING; + if(job == Job::Tanner) + type = leatheraddon::BobTypes::TANNER_WALKING; + if(job == Job::LeatherWorker) + type = leatheraddon::BobTypes::LEATHERWORKER_WALKING; + + LOADER + .GetPlayerImage("leather_bobs", + leatheraddon::bobIndex[type] + static_cast(libsiedler2::ImgDir::SW) * 8) + ->DrawFull(drawPt, COLOR_WHITE, owner.color); } else { const auto& spriteData = JOB_SPRITE_CONSTS[job]; diff --git a/libs/s25main/ingameWindows/iwWares.cpp b/libs/s25main/ingameWindows/iwWares.cpp index f6d8fa8a4c..e7036af4fa 100644 --- a/libs/s25main/ingameWindows/iwWares.cpp +++ b/libs/s25main/ingameWindows/iwWares.cpp @@ -5,6 +5,7 @@ #include "iwWares.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "WineLoader.h" @@ -88,45 +89,36 @@ iwWares::iwWares(unsigned id, const DrawPoint& pos, unsigned additionalYSpace, c GoodType::Shovel, GoodType::Crucible, GoodType::RodAndLine, GoodType::Scythe, GoodType::Cleaver, GoodType::Rollingpin, GoodType::Bow, GoodType::Sword, GoodType::ShieldRomans /* nation specific */, - GoodType::Boat, GoodType::Grapes, GoodType::Wine}; - - std::vector JOB_DISPLAY_ORDER{Job::Helper, - Job::Builder, - Job::Planer, - Job::Woodcutter, - Job::Forester, - Job::Stonemason, - Job::Fisher, - Job::Hunter, - Job::Carpenter, - Job::Farmer, - Job::PigBreeder, - Job::DonkeyBreeder, - Job::Miller, - Job::Baker, - Job::Butcher, - Job::Brewer, - Job::Miner, - Job::IronFounder, - Job::Armorer, - Job::Minter, - Job::Metalworker, - Job::Shipwright, - Job::Geologist, - Job::Scout, - Job::PackDonkey, - Job::CharBurner, - Job::Winegrower, - Job::Vintner, - Job::TempleServant, - Job::Private, - Job::PrivateFirstClass, - Job::Sergeant, - Job::Officer, + GoodType::Boat, GoodType::Grapes, GoodType::Wine, + GoodType::Skins, GoodType::Leather, GoodType::Armor, + }; + + std::vector JOB_DISPLAY_ORDER{Job::Helper, Job::Builder, + Job::Planer, Job::Woodcutter, + Job::Forester, Job::Stonemason, + Job::Fisher, Job::Hunter, + Job::Carpenter, Job::Farmer, + Job::PigBreeder, Job::DonkeyBreeder, + Job::Miller, Job::Baker, + Job::Butcher, Job::Brewer, + Job::Miner, Job::IronFounder, + Job::Armorer, Job::Minter, + Job::Metalworker, Job::Shipwright, + Job::Geologist, Job::Scout, + Job::PackDonkey, Job::CharBurner, + Job::Winegrower, Job::Vintner, + Job::TempleServant, Job::Skinner, + Job::Tanner, Job::LeatherWorker, + Job::Private, Job::PrivateFirstClass, + Job::Sergeant, Job::Officer, Job::General}; const auto isUnusedWare = [&](GoodType const& type) { - return !wineaddon::isAddonActive(player.GetGameWorld()) && wineaddon::isWineAddonGoodType(type); + if(!wineaddon::isAddonActive(player.GetGameWorld()) && wineaddon::isWineAddonGoodType(type)) + return true; + if(!leatheraddon::isAddonActive(player.GetGameWorld()) && leatheraddon::isLeatherAddonGoodType(type)) + return true; + return false; }; auto isUnusedJob = [&](Job const& job) { @@ -134,6 +126,8 @@ iwWares::iwWares(unsigned id, const DrawPoint& pos, unsigned additionalYSpace, c return true; if(!player.GetGameWorld().GetGGS().isEnabled(AddonId::CHARBURNER) && job == Job::CharBurner) return true; + if(!leatheraddon::isAddonActive(player.GetGameWorld()) && leatheraddon::isLeatherAddonJobType(job)) + return true; return false; }; diff --git a/libs/s25main/lua/LuaInterfaceGame.cpp b/libs/s25main/lua/LuaInterfaceGame.cpp index 18c4d46cf7..3ae2d0623c 100644 --- a/libs/s25main/lua/LuaInterfaceGame.cpp +++ b/libs/s25main/lua/LuaInterfaceGame.cpp @@ -59,6 +59,9 @@ LuaInterfaceGame::LuaInterfaceGame(Game& gameInstance, ILocalGameState& localGam ADD_LUA_CONST(Vineyard); ADD_LUA_CONST(Winery); ADD_LUA_CONST(Temple); + ADD_LUA_CONST(Skinner); + ADD_LUA_CONST(Tannery); + ADD_LUA_CONST(LeatherWorks); #undef ADD_LUA_CONST #define ADD_LUA_CONST(name) lua["JOB_" + s25util::toUpper(#name)] = Job::name @@ -97,6 +100,9 @@ LuaInterfaceGame::LuaInterfaceGame(Game& gameInstance, ILocalGameState& localGam ADD_LUA_CONST(Winegrower); ADD_LUA_CONST(Vintner); ADD_LUA_CONST(TempleServant); + ADD_LUA_CONST(Skinner); + ADD_LUA_CONST(Tanner); + ADD_LUA_CONST(LeatherWorker); #undef ADD_LUA_CONST #define ADD_LUA_CONST(name) lua["STAT_" + s25util::toUpper(#name)] = StatisticType::name @@ -145,6 +151,9 @@ LuaInterfaceGame::LuaInterfaceGame(Game& gameInstance, ILocalGameState& localGam ADD_LUA_CONST(Ham); ADD_LUA_CONST(Grapes); ADD_LUA_CONST(Wine); + ADD_LUA_CONST(Skins); + ADD_LUA_CONST(Leather); + ADD_LUA_CONST(Armor); #undef ADD_LUA_CONST #define ADD_LUA_CONST(name) lua["RES_" + s25util::toUpper(#name)] = ResourceType::name diff --git a/tests/s25Main/integration/testGamePlayer.cpp b/tests/s25Main/integration/testGamePlayer.cpp index 438e0131fe..640c164983 100644 --- a/tests/s25Main/integration/testGamePlayer.cpp +++ b/tests/s25Main/integration/testGamePlayer.cpp @@ -53,7 +53,7 @@ RTTR_ATTRIBUTE_NO_UBSAN(vptr) void setProductivity(nobUsual* bld, unsigned short } } // namespace -using WorldFixtureEmpty1P = WorldFixture + 6, 4>; +using WorldFixtureEmpty1P = WorldFixture + 14, 4>; BOOST_FIXTURE_TEST_CASE(ProductivityStats, WorldFixtureEmpty1P) { using boost::test_tools::per_element; diff --git a/tests/s25Main/lua/testLuaConstants.cpp b/tests/s25Main/lua/testLuaConstants.cpp index 55c47fd926..0d1f2a4b05 100644 --- a/tests/s25Main/lua/testLuaConstants.cpp +++ b/tests/s25Main/lua/testLuaConstants.cpp @@ -76,7 +76,10 @@ BOOST_AUTO_TEST_CASE(AllGoodTypesWork) GD_MEAT, GD_HAM, GD_GRAPES, - GD_WINE + GD_WINE, + GD_SKINS, + GD_LEATHER, + GD_ARMOR ) )LUA"); executeLua(R"LUA( @@ -129,7 +132,10 @@ BOOST_AUTO_TEST_CASE(AllBuildingTypesWork) BLD_HARBORBUILDING, BLD_VINEYARD, BLD_WINERY, - BLD_TEMPLE + BLD_TEMPLE, + BLD_SKINNER, + BLD_TANNERY, + BLD_LEATHERWORKS ) )LUA"); executeLua(R"LUA( @@ -180,7 +186,10 @@ BOOST_AUTO_TEST_CASE(AllJobTypesWork) JOB_CHARBURNER, JOB_WINEGROWER, JOB_VINTNER, - JOB_TEMPLESERVANT + JOB_TEMPLESERVANT, + JOB_SKINNER, + JOB_TANNER, + JOB_LEATHERWORKER ) )LUA"); executeLua(R"LUA( From 327aba107688570a9dcaefc4843cdb2ca17914b1 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 18:30:47 +0100 Subject: [PATCH 02/32] Fix formatting --- libs/s25main/figures/nofSkinner.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/s25main/figures/nofSkinner.cpp b/libs/s25main/figures/nofSkinner.cpp index 772948287e..95f14a5253 100644 --- a/libs/s25main/figures/nofSkinner.cpp +++ b/libs/s25main/figures/nofSkinner.cpp @@ -20,9 +20,7 @@ nofSkinner::nofSkinner(const MapPoint pos, const unsigned char player, nobUsual* nofSkinner::nofSkinner(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) {} -void nofSkinner::DrawWorking(DrawPoint /*drawPt*/) -{ -} +void nofSkinner::DrawWorking(DrawPoint /*drawPt*/) {} unsigned short nofSkinner::GetCarryID() const { From 56790b6a0092e8214d3b4ff7c4a74be2d8a891a7 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 18:31:40 +0100 Subject: [PATCH 03/32] Add distribution tab for ham and make gui more general --- libs/s25main/ingameWindows/iwDistribution.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/libs/s25main/ingameWindows/iwDistribution.cpp b/libs/s25main/ingameWindows/iwDistribution.cpp index e03c85b1c8..98c2a9a96e 100644 --- a/libs/s25main/ingameWindows/iwDistribution.cpp +++ b/libs/s25main/ingameWindows/iwDistribution.cpp @@ -5,6 +5,7 @@ #include "iwDistribution.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "WineLoader.h" @@ -24,6 +25,7 @@ /// Dertermines width of the progress bars: distance to the window borders const unsigned PROGRESS_BORDER_DISTANCE = 20; +const unsigned TAB_ICON_SIZE = 36; iwDistribution::iwDistribution(const GameWorldViewer& gwv, GameCommandFactory& gcFactory) : TransmitSettingsIgwAdapter(CGI_DISTRIBUTION, IngameWindow::posLastOrCenter, Extent(290, 312), @@ -32,8 +34,10 @@ iwDistribution::iwDistribution(const GameWorldViewer& gwv, GameCommandFactory& g { CreateGroups(); + Resize(Extent(groups.size() * TAB_ICON_SIZE + TAB_ICON_SIZE / 2 + 20, 312)); + // Tab Control - ctrlTab* tab = AddTabCtrl(0, DrawPoint(10, 20), 270); + ctrlTab* tab = AddTabCtrl(0, DrawPoint(10, 20), groups.size() * TAB_ICON_SIZE + TAB_ICON_SIZE / 2); DrawPoint txtPos(GetSize().x / 2, 60); DrawPoint progPos(PROGRESS_BORDER_DISTANCE - tab->GetPos().x, txtPos.y); const Extent progSize(GetSize().x - 2 * PROGRESS_BORDER_DISTANCE, 20); @@ -176,10 +180,15 @@ void iwDistribution::CreateGroups() case GoodType::Wood: img = LOADER.GetImageN("io", 89); break; case GoodType::Boards: img = LOADER.GetImageN("io", 82); break; case GoodType::Water: img = LOADER.GetImageN("io", 92); break; + case GoodType::Ham: + img = LOADER.GetImageN("leather_bobs", + leatheraddon::bobIndex[leatheraddon::BobTypes::DISTRIBUTION_OF_PIGS_ICON]); + break; default: break; } if(!img) throw std::runtime_error("Unexpected good in distribution"); + groups.push_back(DistributionGroup(_(name), img)); } // HQ = Construction @@ -195,6 +204,8 @@ void iwDistribution::CreateGroups() return true; if(!gwv.GetWorld().GetGGS().isEnabled(AddonId::CHARBURNER) && buildingType == BuildingType::Charburner) return true; + if(!leatheraddon::isAddonActive(gwv.GetWorld()) && leatheraddon::isLeatherAddonBuildingType(buildingType)) + return true; return false; }; for(auto& group : groups) From 131f46454cdc0d35f789dda054062c9de1d89eec Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 19:12:22 +0100 Subject: [PATCH 04/32] Add compatibilty code --- libs/s25main/BuildingRegister.cpp | 4 +++ libs/s25main/GamePlayer.cpp | 33 ++++++++++++++++----- libs/s25main/SerializedGameData.cpp | 2 +- libs/s25main/buildings/nobBaseWarehouse.cpp | 9 ++++++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/libs/s25main/BuildingRegister.cpp b/libs/s25main/BuildingRegister.cpp index 4d6cae9bc6..d6173d76f7 100644 --- a/libs/s25main/BuildingRegister.cpp +++ b/libs/s25main/BuildingRegister.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "BuildingRegister.h" +#include "LeatherLoader.h" #include "SerializedGameData.h" #include "WineLoader.h" #include "buildings/noBuildingSite.h" @@ -41,6 +42,9 @@ void BuildingRegister::Deserialize(SerializedGameData& sgd) if(sgd.GetGameDataVersion() < 11 && wineaddon::isWineAddonBuildingType(bld)) continue; + if(sgd.GetGameDataVersion() < 12 && leatheraddon::isLeatherAddonBuildingType(bld)) + continue; + if(BuildingProperties::IsUsual(bld)) sgd.PopObjectContainer(buildings[bld], GO_Type::NobUsual); } diff --git a/libs/s25main/GamePlayer.cpp b/libs/s25main/GamePlayer.cpp index d00de03b98..fe3c7b0353 100644 --- a/libs/s25main/GamePlayer.cpp +++ b/libs/s25main/GamePlayer.cpp @@ -7,6 +7,7 @@ #include "FindWhConditions.h" #include "GameInterface.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "RoadSegment.h" #include "SerializedGameData.h" #include "TradePathCache.h" @@ -264,6 +265,9 @@ void GamePlayer::Deserialize(SerializedGameData& sgd) if(sgd.GetGameDataVersion() < 11 && wineaddon::isWineAddonGoodType(i)) continue; + if(sgd.GetGameDataVersion() < 12 && leatheraddon::isLeatherAddonGoodType(i)) + continue; + Distribution& dist = distribution[i]; helpers::popContainer(sgd, dist.percent_buildings); if(sgd.GetGameDataVersion() < 7) @@ -282,15 +286,24 @@ void GamePlayer::Deserialize(SerializedGameData& sgd) useCustomBuildOrder_ = sgd.PopBool(); - if(sgd.GetGameDataVersion() < 11) + if(sgd.GetGameDataVersion() < 12) { - std::vector build_order_raw(build_order.size() - 3); + auto countOfNotAvailableBuildingsInSaveGame = sgd.GetGameDataVersion() < 11 ? 6 : 3; + std::vector build_order_raw(build_order.size() - countOfNotAvailableBuildingsInSaveGame); helpers::popContainer(sgd, build_order_raw, true); - build_order_raw.insert(build_order_raw.end(), - {BuildingType::Vineyard, BuildingType::Winery, BuildingType::Temple}); + + if(sgd.GetGameDataVersion() < 11) + build_order_raw.insert(build_order_raw.end(), + {BuildingType::Vineyard, BuildingType::Winery, BuildingType::Temple}); + + if(sgd.GetGameDataVersion() < 12) + build_order_raw.insert(build_order_raw.end(), + {BuildingType::Skinner, BuildingType::Tannery, BuildingType::LeatherWorks}); + std::copy(build_order_raw.begin(), build_order_raw.end(), build_order.begin()); - std::vector transportPrio_raw(transportPrio.size() - 2); + auto countOfNotAvailableGoodsInSaveGame = sgd.GetGameDataVersion() < 11 ? 5 : 3; + std::vector transportPrio_raw(transportPrio.size() - countOfNotAvailableGoodsInSaveGame); helpers::popContainer(sgd, transportPrio_raw, true); std::copy(transportPrio_raw.begin(), transportPrio_raw.end(), transportPrio.begin()); } else @@ -306,13 +319,17 @@ void GamePlayer::Deserialize(SerializedGameData& sgd) helpers::popContainer(sgd, tools_ordered); tools_ordered_delta = {}; - if(sgd.GetGameDataVersion() < 11) + if(sgd.GetGameDataVersion() < 12) { - std::vector global_inventory_good_raw(global_inventory.goods.size() - 2); + auto countOfNotAvailableGoodsInSaveGame = sgd.GetGameDataVersion() < 11 ? 5 : 3; + std::vector global_inventory_good_raw(global_inventory.goods.size() + - countOfNotAvailableGoodsInSaveGame); helpers::popContainer(sgd, global_inventory_good_raw, true); std::copy(global_inventory_good_raw.begin(), global_inventory_good_raw.end(), global_inventory.goods.begin()); - std::vector global_inventory_people_raw(global_inventory.people.size() - 3); + auto countOfNotAvailableJobsInSaveGame = sgd.GetGameDataVersion() < 11 ? 6 : 3; + std::vector global_inventory_people_raw(global_inventory.people.size() + - countOfNotAvailableJobsInSaveGame); helpers::popContainer(sgd, global_inventory_people_raw, true); std::copy(global_inventory_people_raw.begin(), global_inventory_people_raw.end(), global_inventory.people.begin()); diff --git a/libs/s25main/SerializedGameData.cpp b/libs/s25main/SerializedGameData.cpp index 25c33d1a10..4c58ae9431 100644 --- a/libs/s25main/SerializedGameData.cpp +++ b/libs/s25main/SerializedGameData.cpp @@ -106,7 +106,7 @@ /// 10: troop_limits state introduced to military buildings /// 11:: wineaddon added, three new building types and two new goods /// 12:: leatheraddon added, three new building types and three new goods -static const unsigned currentGameDataVersion = 11; +static const unsigned currentGameDataVersion = 12; // clang-format on std::unique_ptr SerializedGameData::Create_GameObject(const GO_Type got, const unsigned obj_id) diff --git a/libs/s25main/buildings/nobBaseWarehouse.cpp b/libs/s25main/buildings/nobBaseWarehouse.cpp index a624a56dfd..05c9975d4b 100644 --- a/libs/s25main/buildings/nobBaseWarehouse.cpp +++ b/libs/s25main/buildings/nobBaseWarehouse.cpp @@ -8,6 +8,7 @@ #include "FindWhConditions.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "SerializedGameData.h" #include "Ware.h" #include "WineLoader.h" @@ -170,6 +171,10 @@ nobBaseWarehouse::nobBaseWarehouse(SerializedGameData& sgd, const unsigned obj_i { if(sgd.GetGameDataVersion() < 11 && wineaddon::isWineAddonGoodType(i)) continue; + + if(sgd.GetGameDataVersion() < 12 && leatheraddon::isLeatherAddonGoodType(i)) + continue; + inventory.visual[i] = sgd.PopUnsignedInt(); inventory.real[i] = sgd.PopUnsignedInt(); inventorySettings[i] = inventorySettingsVisual[i] = static_cast(sgd.PopUnsignedChar()); @@ -178,6 +183,10 @@ nobBaseWarehouse::nobBaseWarehouse(SerializedGameData& sgd, const unsigned obj_i { if(sgd.GetGameDataVersion() < 11 && wineaddon::isWineAddonJobType(i)) continue; + + if(sgd.GetGameDataVersion() < 12 && leatheraddon::isLeatherAddonJobType(i)) + continue; + inventory.visual[i] = sgd.PopUnsignedInt(); inventory.real[i] = sgd.PopUnsignedInt(); inventorySettings[i] = inventorySettingsVisual[i] = static_cast(sgd.PopUnsignedChar()); From dddc8939bd1631a12d0daecb175813430d7606c0 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 19:22:22 +0100 Subject: [PATCH 05/32] Add direct transport route --- libs/s25main/GamePlayer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/s25main/GamePlayer.cpp b/libs/s25main/GamePlayer.cpp index fe3c7b0353..b39537436d 100644 --- a/libs/s25main/GamePlayer.cpp +++ b/libs/s25main/GamePlayer.cpp @@ -137,6 +137,8 @@ void GamePlayer::LoadStandardDistribution() distribution[GoodType::Stones].client_buildings.push_back(BuildingType::Catapult); distribution[GoodType::Grapes].client_buildings.push_back(BuildingType::Winery); distribution[GoodType::Wine].client_buildings.push_back(BuildingType::Temple); + distribution[GoodType::Skins].client_buildings.push_back(BuildingType::Tannery); + distribution[GoodType::Leather].client_buildings.push_back(BuildingType::LeatherWorks); // Waren mit mehreren möglichen Zielen erstmal nullen, kann dann im Fenster eingestellt werden for(const auto i : helpers::enumRange()) From 94f562552ce7affea8edaa7dfb17ba055a57f2ca Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 1 Dec 2024 20:43:58 +0100 Subject: [PATCH 06/32] Add fixed animations from leather_bobs.lst --- data/RTTR/assets/base/leather_bobs.lst | Bin 110210 -> 196430 bytes libs/s25main/LeatherLoader.cpp | 6 +++--- libs/s25main/Loader.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/RTTR/assets/base/leather_bobs.lst b/data/RTTR/assets/base/leather_bobs.lst index b7deded5aaf4998960c06de7763d19a8a4f3cc3d..4df82f2ad71d927b7af44c6114dcca8ac739deb6 100644 GIT binary patch literal 196430 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 aJ&n)9hpYa+~R@b?DhiWzX4*wr8J@z#K delta 13968 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 Mw%zp)!JW(h4=SdX*#H0l diff --git a/libs/s25main/LeatherLoader.cpp b/libs/s25main/LeatherLoader.cpp index 34c34c929b..4088c8a0d7 100644 --- a/libs/s25main/LeatherLoader.cpp +++ b/libs/s25main/LeatherLoader.cpp @@ -29,9 +29,9 @@ bool isLeatherAddonJobType(Job job) return job == Job::Skinner || job == Job::Tanner || job == Job::LeatherWorker; } -helpers::EnumArray bobIndex = {0, 21, 69, 117, 125, 173, 189, 222, 270, 286, 293, - 301, 307, 313, 336, 354, 355, 356, 356, 357, 357, 358, - 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369}; +helpers::EnumArray bobIndex = {0, 21, 69, 117, 125, 173, 221, 244, 292, 340, 388, + 436, 484, 532, 582, 628, 629, 630, 630, 631, 631, 632, + 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643}; ITexture* GetWareTex(const GoodType good) { diff --git a/libs/s25main/Loader.cpp b/libs/s25main/Loader.cpp index 13073395d1..0ca63a50f6 100644 --- a/libs/s25main/Loader.cpp +++ b/libs/s25main/Loader.cpp @@ -935,9 +935,9 @@ void Loader::fillCaches() carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_ARMOR : leatheraddon::BobTypes::THIN_CARRIER_CARRYING_ARMOR; - bmp.add(dynamic_cast(bob_carrier->getBody(fat, imgDir, ani_step))); - bmp.add(dynamic_cast(leather_bob_carrier.get( - leatheraddon::bobIndex[carrierEnum] + static_cast(imgDir)))); + const unsigned bodyIdx = static_cast(imgDir) * 8 + ani_step; + bmp.add(dynamic_cast( + leather_bob_carrier.get(leatheraddon::bobIndex[carrierEnum] + bodyIdx))); } else { bmp.add(dynamic_cast(bob_carrier->getBody(fat, imgDir, ani_step))); From 4c45d1015e44afd41f05f5c383b4ff39f77de341 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sat, 7 Dec 2024 15:57:57 +0100 Subject: [PATCH 07/32] Skinner goes out to get skins from carcass if he has no pigs (naturally died our died by the hunter) --- libs/s25main/figures/nofBuildingWorker.cpp | 6 +- libs/s25main/figures/nofBuildingWorker.h | 6 +- libs/s25main/figures/nofHunter.cpp | 15 +- libs/s25main/figures/nofSkinner.cpp | 210 ++++++++++++++++++++- libs/s25main/figures/nofSkinner.h | 18 +- libs/s25main/gameData/JobConsts.cpp | 2 +- libs/s25main/nodeObjs/noAnimal.cpp | 61 +++++- libs/s25main/nodeObjs/noAnimal.h | 11 ++ 8 files changed, 310 insertions(+), 19 deletions(-) diff --git a/libs/s25main/figures/nofBuildingWorker.cpp b/libs/s25main/figures/nofBuildingWorker.cpp index 7a9c2ec657..ce5a39d738 100644 --- a/libs/s25main/figures/nofBuildingWorker.cpp +++ b/libs/s25main/figures/nofBuildingWorker.cpp @@ -84,11 +84,13 @@ void nofBuildingWorker::Draw(DrawPoint drawPt) case State::FigureWork: case State::HunterChasing: case State::HunterWalkingToCadaver: - case State::HunterFindingShootingpoint: DrawWalking(drawPt); break; + case State::HunterFindingShootingpoint: + case State::SkinnerWalkingToCarcass: DrawWalking(drawPt); break; case State::Work: case State::HunterShooting: case State::HunterEviscerating: case State::HunterWaitingForAnimalReady: + case State::SkinnerSkinningCarcass: case State::CatapultTargetBuilding: case State::CatapultBackoff: DrawWorking(drawPt); break; case State::CarryoutWare: DrawWalkingWithWare(drawPt); break; @@ -246,6 +248,7 @@ void nofBuildingWorker::LostWork() case State::HunterShooting: case State::HunterEviscerating: case State::HunterWaitingForAnimalReady: + case State::SkinnerSkinningCarcass: case State::CatapultTargetBuilding: case State::CatapultBackoff: { @@ -272,6 +275,7 @@ void nofBuildingWorker::LostWork() case State::HunterChasing: case State::HunterFindingShootingpoint: case State::HunterWalkingToCadaver: + case State::SkinnerWalkingToCarcass: { // Bescheid sagen, dass Arbeit abgebrochen wurde WorkAborted(); diff --git a/libs/s25main/figures/nofBuildingWorker.h b/libs/s25main/figures/nofBuildingWorker.h index bc27e89df5..65015287a8 100644 --- a/libs/s25main/figures/nofBuildingWorker.h +++ b/libs/s25main/figures/nofBuildingWorker.h @@ -37,8 +37,10 @@ class nofBuildingWorker : public noFigure CatapultBackoff, /// Katapult: beendet schießen und dreht Katapult in die Ausgangsstellung zurück HunterWaitingForAnimalReady, /// Hunter: Arrived at shooting pos and waiting for animal to be ready to /// be shot + SkinnerWalkingToCarcass, /// Skinner: walk to carcass + SkinnerSkinningCarcass, /// Skinner: get skin from carcass }; - friend constexpr auto maxEnumValue(State) { return State::HunterWaitingForAnimalReady; } + friend constexpr auto maxEnumValue(State) { return State::SkinnerSkinningCarcass; } protected: State state; @@ -59,7 +61,7 @@ class nofBuildingWorker : public noFigure void AbrogateWorkplace() override; /// Tries to start working. /// Checks preconditions (production enabled, wares available...) and starts the pre-Work-Waiting period if ok - void TryToWork(); + virtual void TryToWork(); /// Returns true, when there are enough wares available for working. /// Note: On false, we will wait for the next ware or production change till checking again virtual bool AreWaresAvailable() const; diff --git a/libs/s25main/figures/nofHunter.cpp b/libs/s25main/figures/nofHunter.cpp index 3e77c256d3..f0276accce 100644 --- a/libs/s25main/figures/nofHunter.cpp +++ b/libs/s25main/figures/nofHunter.cpp @@ -376,12 +376,17 @@ void nofHunter::HandleStateEviscerating() world->GetSoundMgr().stopSounds(*this); was_sounding = false; } - // Tier verschwinden lassen - auto ownedAnimal = world->RemoveFigure(pos, *animal); + + animal->Eviscerated(); + if(!animal->IsSkinned()) + { + // Tier verschwinden lassen + auto ownedAnimal = world->RemoveFigure(pos, *animal); + // Tier vernichten + ownedAnimal->Destroy(); + } animal = nullptr; - // Tier vernichten - ownedAnimal->Eviscerated(); - ownedAnimal->Destroy(); + // Fleisch in die Hand nehmen ware = GoodType::Meat; // und zurück zur Hütte diff --git a/libs/s25main/figures/nofSkinner.cpp b/libs/s25main/figures/nofSkinner.cpp index 95f14a5253..af7a080fbf 100644 --- a/libs/s25main/figures/nofSkinner.cpp +++ b/libs/s25main/figures/nofSkinner.cpp @@ -3,24 +3,55 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "nofSkinner.h" +#include "EventManager.h" #include "GamePlayer.h" #include "LeatherLoader.h" #include "Loader.h" +#include "SerializedGameData.h" #include "SoundManager.h" #include "buildings/nobUsual.h" #include "network/GameClient.h" +#include "notifications/BuildingNote.h" #include "ogl/glArchivItem_Bitmap_Player.h" +#include "random/Random.h" #include "world/GameWorld.h" +#include "nodeObjs/noAnimal.h" +#include "gameData/JobConsts.h" using namespace leatheraddon; +const MapCoord MAX_SKINNING_DISTANCE = 50; + nofSkinner::nofSkinner(const MapPoint pos, const unsigned char player, nobUsual* workplace) : nofWorkman(Job::Skinner, pos, player, workplace) {} -nofSkinner::nofSkinner(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) {} +nofSkinner::nofSkinner(SerializedGameData& sgd, const unsigned obj_id) : nofWorkman(sgd, obj_id) +{ + if(state != State::FigureWork && state != State::Waiting1) + animal = sgd.PopObject(GO_Type::Animal); + else + animal = nullptr; +} + +void nofSkinner::Serialize(SerializedGameData& sgd) const +{ + nofBuildingWorker::Serialize(sgd); + + if(state != State::FigureWork && state != State::Waiting1) + { + sgd.PushObject(animal, true); + } +} -void nofSkinner::DrawWorking(DrawPoint /*drawPt*/) {} +void nofSkinner::WorkAborted() +{ + if(animal) + { + animal->StopSkinning(); + animal = nullptr; + } +} unsigned short nofSkinner::GetCarryID() const { @@ -32,6 +63,181 @@ void nofSkinner::DrawWalkingWithWare(DrawPoint drawPt) DrawWalking(drawPt, "leather_bobs", bobIndex[BobTypes::SKINNER_CARRYING_SKINS]); } +void nofSkinner::HandleDerivedEvent(unsigned id) +{ + switch(state) + { + case State::Waiting1: TryStartSkinning(); break; + case State::Work: HandleStateWork(); break; + case State::Waiting2: HandleStateWaiting2(); break; + case State::SkinnerSkinningCarcass: HandleStateSkinningCarcass(); break; + default: break; + } +} + +void nofSkinner::DrawWorking(DrawPoint drawPt) +{ + const GamePlayer& owner = world->GetPlayer(player); + switch(state) + { + default: break; + case State::SkinnerSkinningCarcass: + { + unsigned short id = GAMECLIENT.Interpolate(45, current_ev); + unsigned short draw_id = + leatheraddon::bobIndex[leatheraddon::BobTypes::SKINNER_SKINNING_ANIMAL_CARCASS_ANIMATION]; + + if(id < 4) + draw_id = draw_id + id; + else if(id < 36) + draw_id = (draw_id + 4) + (id - 4) % 8; + else + draw_id = (draw_id + 12) + id - 36; + + LOADER.GetPlayerImage("leather_bobs", draw_id)->drawForPlayer(drawPt, owner.color); + } + break; + } +} + +void nofSkinner::HandleStateSkinningCarcass() +{ + animal->Skinned(); + if(!animal->IsHunted()) + { + // Tier verschwinden lassen + auto ownedAnimal = world->RemoveFigure(pos, *animal); + // Tier vernichten + ownedAnimal->Destroy(); + } + animal = nullptr; + + ware = ProduceWare(); + StartWalkingHome(); +} + +void nofSkinner::StartWalkingHome() +{ + WorkAborted(); + state = State::WalkingHome; + // We may be still walking in which case we delay finding a path home until we reached the next node + if(!IsMoving()) + HandleStateWalkingHome(); +} + +void nofSkinner::HandleStateWalkingHome() +{ + // We reached our home? (exactly at the flag !!) + MapPoint homeFlagPos = world->GetNeighbour(workplace->GetPos(), Direction::SouthEast); + if(pos == homeFlagPos) + { + // Redirect to nofBuildingWorker + WorkingReady(); + return; + } + + // Search for way if we can go home (add tolerance to avoid dying, if he walked some fields to far away) + const auto dir = world->FindHumanPath(pos, homeFlagPos, MAX_SKINNING_DISTANCE + MAX_SKINNING_DISTANCE / 4); + if(dir) + { + StartWalking(*dir); + } else + { + // no way to home + AbrogateWorkplace(); + StartWandering(); + Wander(); + } +} + +void nofSkinner::TryStartSkinning() +{ + // pigs have higher priority then going skinning dead animals + if(AreWaresAvailable()) + HandleStateWaiting1(); + else + { + std::vector available_animals; + Position curPos; + for(curPos.y = pos.y - MAX_SKINNING_DISTANCE; curPos.y <= pos.y + MAX_SKINNING_DISTANCE; ++curPos.y) + { + for(curPos.x = pos.x - MAX_SKINNING_DISTANCE; curPos.x <= pos.x + MAX_SKINNING_DISTANCE; ++curPos.x) + { + MapPoint curMapPos = world->MakeMapPoint(curPos); + for(auto& figure : world->GetFigures(curMapPos)) + { + if(figure.GetType() != NodalObjectType::Animal) + continue; + + auto& animal = static_cast(figure); + if(!animal.CanSkinned()) + continue; + + if(pos == animal.GetPos() || world->FindHumanPath(pos, animal.GetPos(), MAX_SKINNING_DISTANCE)) + { + available_animals.push_back(&animal); + } + } + } + } + + if(!available_animals.empty()) + { + animal = RANDOM_ELEMENT(available_animals); + state = State::SkinnerWalkingToCarcass; + workplace->is_working = true; + animal->BeginSkinning(this); + StartWalking(Direction::SouthEast); + workplace->StopNotWorking(); + } else + { + current_ev = GetEvMgr().AddEvent(this, JOB_CONSTS[job_].wait1_length, 1); + workplace->StartNotWorking(); + } + } +} + +void nofSkinner::TryToWork() +{ + if(AreWaresAvailable()) + nofBuildingWorker::TryToWork(); + else + { + state = State::Waiting1; + current_ev = GetEvMgr().AddEvent(this, JOB_CONSTS[job_].wait1_length, 1); + workplace->StartNotWorking(); + } +} + +void nofSkinner::WalkedDerived() +{ + switch(state) + { + default: break; + case State::SkinnerWalkingToCarcass: + { + if(pos == animal->GetPos()) + { + state = State::SkinnerSkinningCarcass; + current_ev = GetEvMgr().AddEvent(this, 80, 1); + } else + { + const auto dir = world->FindHumanPath(pos, animal->GetPos(), MAX_SKINNING_DISTANCE); + if(dir) + { + StartWalking(*dir); + } else + { + // no way --> go home + StartWalkingHome(); + } + } + break; + } + case State::WalkingHome: HandleStateWalkingHome(); break; + } +} + helpers::OptionalEnum nofSkinner::ProduceWare() { return GoodType::Skins; diff --git a/libs/s25main/figures/nofSkinner.h b/libs/s25main/figures/nofSkinner.h index 1a216b7a7b..e5f4d5b13f 100644 --- a/libs/s25main/figures/nofSkinner.h +++ b/libs/s25main/figures/nofSkinner.h @@ -8,6 +8,7 @@ class SerializedGameData; class nobUsual; +class noAnimal; #ifdef _MSC_VER # pragma warning(disable : 4646) // function declared with [[noreturn]] has non-void return type @@ -15,19 +16,34 @@ class nobUsual; class nofSkinner : public nofWorkman { + /// animal, which is skinned + noAnimal* animal; + /// Draw worker at work void DrawWorking(DrawPoint drawPt) override; /// Id in jobs.bob or carrier.bob when carrying a ware [[noreturn]] unsigned short GetCarryID() const override; - /// Der Arbeiter erzeugt eine Ware helpers::OptionalEnum ProduceWare() override; /// Draws the figure while returning home / entering the building (often carrying wares) void DrawWalkingWithWare(DrawPoint drawPt) override; + void HandleDerivedEvent(unsigned id) override; + void TryToWork() override; + void WalkedDerived() override; + + void TryStartSkinning(); + void HandleStateSkinningCarcass(); + void StartWalkingHome(); + void HandleStateWalkingHome(); + public: nofSkinner(MapPoint pos, unsigned char player, nobUsual* workplace); nofSkinner(SerializedGameData& sgd, unsigned obj_id); + void Serialize(SerializedGameData& sgd) const override; + GO_Type GetGOT() const final { return GO_Type::NofSkinner; } + + void WorkAborted() override; }; diff --git a/libs/s25main/gameData/JobConsts.cpp b/libs/s25main/gameData/JobConsts.cpp index 6f33cc38b8..4a0b862f3c 100644 --- a/libs/s25main/gameData/JobConsts.cpp +++ b/libs/s25main/gameData/JobConsts.cpp @@ -53,7 +53,7 @@ const std::array> fullJobData = {{ {{GoodType::Shovel, 117, 106, 5}, {false, 37}, gettext_noop("Winegrower")}, {{GoodType::Nothing, 470, 95, 5}, {false, 37}, gettext_noop("Vintner")}, {{GoodType::Crucible, 470, 95, 5}, {false, 37}, gettext_noop("Temple Servant")}, - {{GoodType::Cleaver, 1, 300, 5}, {false, 37}, gettext_noop("Skinner")}, + {{GoodType::Cleaver, 470, 95, 5}, {false, 37}, gettext_noop("Skinner")}, {{GoodType::Saw, 470, 95, 5}, {false, 37}, gettext_noop("Tanner")}, {{GoodType::Tongs, 470, 95, 5}, {false, 37}, gettext_noop("Leatherworker")}, diff --git a/libs/s25main/nodeObjs/noAnimal.cpp b/libs/s25main/nodeObjs/noAnimal.cpp index 2ee56503f7..1fa374b9cd 100644 --- a/libs/s25main/nodeObjs/noAnimal.cpp +++ b/libs/s25main/nodeObjs/noAnimal.cpp @@ -9,6 +9,7 @@ #include "SoundManager.h" #include "drivers/VideoDriverWrapper.h" #include "figures/nofHunter.h" +#include "figures/nofSkinner.h" #include "helpers/random.h" #include "network/GameClient.h" #include "ogl/SoundEffectItem.h" @@ -29,7 +30,7 @@ auto& getAnimalRng() noAnimal::noAnimal(const Species species, const MapPoint pos) : noMovable(NodalObjectType::Animal, pos), species(species), state(State::Walking), pause_way(5 + RANDOM_RAND(15)), - hunter(nullptr), sound_moment(0) + hunter(nullptr), skinner(nullptr), sound_moment(0) {} void noAnimal::Serialize(SerializedGameData& sgd) const @@ -40,12 +41,16 @@ void noAnimal::Serialize(SerializedGameData& sgd) const sgd.PushEnum(state); sgd.PushUnsignedShort(pause_way); sgd.PushObject(hunter, true); + sgd.PushObject(skinner, true); } noAnimal::noAnimal(SerializedGameData& sgd, const unsigned obj_id) : noMovable(sgd, obj_id), species(sgd.Pop()), state(sgd.Pop()), pause_way(sgd.PopUnsignedShort()), - hunter(sgd.PopObject(GO_Type::NofHunter)), sound_moment(0) -{} + hunter(sgd.PopObject(GO_Type::NofHunter)), skinner(nullptr), sound_moment(0) +{ + if(sgd.GetGameDataVersion() >= 12) + skinner = {sgd.PopObject(GO_Type::NofSkinner)}; +} void noAnimal::StartLiving() { @@ -154,9 +159,16 @@ void noAnimal::HandleEvent(const unsigned id) // Sterbe-Event case 2: { - // nun verschwinden - current_ev = GetEvMgr().AddEvent(this, 30, 3); - state = State::Disappearing; + // we stay in dead state until skinner has done his work, otherwise he has no change to reach the animal in + // time + if(skinner) + current_ev = GetEvMgr().AddEvent(this, 30, 2); + else + { + // nun verschwinden + current_ev = GetEvMgr().AddEvent(this, 30, 3); + state = State::Disappearing; + } // Jäger ggf. Bescheid sagen (falls der es nicht mehr rechtzeitig schafft, bis ich verwest bin) if(hunter) @@ -297,12 +309,46 @@ helpers::OptionalEnum noAnimal::FindDir() return boost::none; } +bool noAnimal::CanSkinned() const +{ + return (species != Species::Duck && state == State::Dead); +} + +bool noAnimal::IsSkinned() const +{ + return skinner != nullptr; +} + +void noAnimal::Skinned() +{ + // Event abmelden + if(!hunter) + GetEvMgr().RemoveEvent(current_ev); + // Reset skinner + skinner = nullptr; +} + +void noAnimal::BeginSkinning(nofSkinner* skinner) +{ + this->skinner = skinner; +} + +void noAnimal::StopSkinning() +{ + skinner = nullptr; +} + bool noAnimal::CanHunted() const { // Enten sowie Tiere, die bereits gejagt werden, oder schon tot daliegen, können nicht gejagt werden return (species != Species::Duck && state != State::Dead && state != State::Disappearing && !hunter); } +bool noAnimal::IsHunted() const +{ + return hunter != nullptr; +} + void noAnimal::BeginHunting(nofHunter* hunter) { this->hunter = hunter; @@ -370,7 +416,8 @@ void noAnimal::Die() void noAnimal::Eviscerated() { // Event abmelden - GetEvMgr().RemoveEvent(current_ev); + if(!IsSkinned()) + GetEvMgr().RemoveEvent(current_ev); // Reset hunter hunter = nullptr; } diff --git a/libs/s25main/nodeObjs/noAnimal.h b/libs/s25main/nodeObjs/noAnimal.h index b763b35a2a..28ec63539e 100644 --- a/libs/s25main/nodeObjs/noAnimal.h +++ b/libs/s25main/nodeObjs/noAnimal.h @@ -9,6 +9,7 @@ #include "gameTypes/AnimalTypes.h" class nofHunter; +class nofSkinner; class SerializedGameData; /// Klasse für die Tiere (ausgenommen Esel und Schweine natürlich) @@ -33,6 +34,8 @@ class noAnimal : public noMovable unsigned short pause_way; /// Jäger, der das Tier jagt (0, falls nicht gejagt) nofHunter* hunter; + /// Skinner, skinning the animal (0, if not skinned) + nofSkinner* skinner; /// Nächster Zeitpunkt, ab wann der Sound gespielt werden soll (bei Enten und Schafen) unsigned sound_moment; @@ -56,6 +59,7 @@ class noAnimal : public noMovable void Destroy() override { RTTR_Assert(!hunter); + RTTR_Assert(!skinner); noMovable::Destroy(); } @@ -70,8 +74,15 @@ class noAnimal : public noMovable /// Wird aufgerufen, nachdem das Tier erzeugt wurde und zur Figurenliste hinzugefügt wurde void StartLiving(); + bool CanSkinned() const; + bool IsSkinned() const; + void BeginSkinning(nofSkinner* skinner); + void StopSkinning(); + void Skinned(); + /// Kann das Tier noch vom Jäger gejagt werden? bool CanHunted() const; + bool IsHunted() const; /// Ein Jäger geht das Tier jagen void BeginHunting(nofHunter* hunter); From 245cb1b863e0033ce5dcd39e35369f484bc24970 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 15:27:30 +0100 Subject: [PATCH 08/32] LeatherAddon military (1): Add SetArmorAllowed game command --- libs/s25main/GameCommand.cpp | 1 + libs/s25main/GameCommand.h | 3 ++- libs/s25main/GameCommands.cpp | 7 +++++++ libs/s25main/GameCommands.h | 19 +++++++++++++++++++ libs/s25main/factories/GameCommandFactory.cpp | 5 +++++ libs/s25main/factories/GameCommandFactory.h | 1 + 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/libs/s25main/GameCommand.cpp b/libs/s25main/GameCommand.cpp index 250eab1a01..0603675a24 100644 --- a/libs/s25main/GameCommand.cpp +++ b/libs/s25main/GameCommand.cpp @@ -37,6 +37,7 @@ GameCommandPtr GameCommand::Deserialize(Deserializer& ser) case GCType::Attack: gc = new Attack(ser); break; case GCType::SeaAttack: gc = new SeaAttack(ser); break; case GCType::SetCoinsAllowed: gc = new SetCoinsAllowed(ser); break; + case GCType::SetArmorAllowed: gc = new SetArmorAllowed(ser); break; case GCType::SetProductionEnabled: gc = new SetProductionEnabled(ser); break; case GCType::SetInventorySetting: gc = new SetInventorySetting(ser); break; case GCType::SetAllInventorySettings: gc = new SetAllInventorySettings(ser); break; diff --git a/libs/s25main/GameCommand.h b/libs/s25main/GameCommand.h index 8f80360c29..faa1d662c9 100644 --- a/libs/s25main/GameCommand.h +++ b/libs/s25main/GameCommand.h @@ -62,10 +62,11 @@ enum class GCType : uint8_t SetTroopLimit, NotifyAlliesOfLocation, SetTempleProductionMode, + SetArmorAllowed, }; constexpr auto maxEnumValue(GCType) { - return GCType::SetTempleProductionMode; + return GCType::SetArmorAllowed; } class GameCommand diff --git a/libs/s25main/GameCommands.cpp b/libs/s25main/GameCommands.cpp index 90c321460c..3e9e673976 100644 --- a/libs/s25main/GameCommands.cpp +++ b/libs/s25main/GameCommands.cpp @@ -173,6 +173,13 @@ void SetCoinsAllowed::Execute(GameWorld& world, uint8_t playerId) bld->SetCoinsAllowed(enabled); } +void SetArmorAllowed::Execute(GameWorld& world, uint8_t playerId) +{ + auto* const bld = world.GetSpecObj(pt_); + if(bld && bld->GetPlayer() == playerId) + bld->SetArmorAllowed(enabled); +} + void SetTroopLimit::Execute(GameWorld& world, uint8_t playerId) { auto* const bld = world.GetSpecObj(pt_); diff --git a/libs/s25main/GameCommands.h b/libs/s25main/GameCommands.h index 1825ce15ae..87e8e0c155 100644 --- a/libs/s25main/GameCommands.h +++ b/libs/s25main/GameCommands.h @@ -405,6 +405,25 @@ class SetCoinsAllowed : public Coords void Execute(GameWorld& world, uint8_t playerId) override; }; +/// Allow/stop armor delivery to building +class SetArmorAllowed : public Coords +{ + GC_FRIEND_DECL; + const bool enabled; + +protected: + SetArmorAllowed(const MapPoint pt, bool enabled) : Coords(GCType::SetArmorAllowed, pt), enabled(enabled) {} + SetArmorAllowed(Serializer& ser) : Coords(GCType::SetArmorAllowed, ser), enabled(ser.PopBool()) {} + +public: + void Serialize(Serializer& ser) const override + { + Coords::Serialize(ser); + ser.PushBool(enabled); + } + void Execute(GameWorld& world, uint8_t playerId) override; +}; + /// Produktivität in einem Gebäude deaktivieren/aktivieren class SetProductionEnabled : public Coords { diff --git a/libs/s25main/factories/GameCommandFactory.cpp b/libs/s25main/factories/GameCommandFactory.cpp index 10774bd82d..c49979f5a3 100644 --- a/libs/s25main/factories/GameCommandFactory.cpp +++ b/libs/s25main/factories/GameCommandFactory.cpp @@ -92,6 +92,11 @@ bool GameCommandFactory::SetCoinsAllowed(const MapPoint pt, bool enabled) return AddGC(new gc::SetCoinsAllowed(pt, enabled)); } +bool GameCommandFactory::SetArmorAllowed(const MapPoint pt, bool enabled) +{ + return AddGC(new gc::SetArmorAllowed(pt, enabled)); +} + bool GameCommandFactory::SetProductionEnabled(const MapPoint pt, bool enabled) { return AddGC(new gc::SetProductionEnabled(pt, enabled)); diff --git a/libs/s25main/factories/GameCommandFactory.h b/libs/s25main/factories/GameCommandFactory.h index 1609ebe6d8..6a3faf3507 100644 --- a/libs/s25main/factories/GameCommandFactory.h +++ b/libs/s25main/factories/GameCommandFactory.h @@ -54,6 +54,7 @@ class GameCommandFactory bool SeaAttack(MapPoint pt, unsigned soldiers_count, bool strong_soldiers); /// Toggles coin delivery on/off for a military building bool SetCoinsAllowed(MapPoint pt, bool enabled); + bool SetArmorAllowed(MapPoint pt, bool enabled); /// Stops/starts production of a producer bool SetProductionEnabled(MapPoint pt, bool enabled); bool NotifyAlliesOfLocation(MapPoint pt); From f0adbcff2a112adea1e062e4a565ff08c83f2cf0 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 15:33:04 +0100 Subject: [PATCH 09/32] fixup! Skinner goes out to get skins from carcass if he has no pigs (naturally died our died by the hunter) fix clang tidy --- libs/s25main/figures/nofSkinner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/s25main/figures/nofSkinner.cpp b/libs/s25main/figures/nofSkinner.cpp index af7a080fbf..14b992f134 100644 --- a/libs/s25main/figures/nofSkinner.cpp +++ b/libs/s25main/figures/nofSkinner.cpp @@ -63,7 +63,7 @@ void nofSkinner::DrawWalkingWithWare(DrawPoint drawPt) DrawWalking(drawPt, "leather_bobs", bobIndex[BobTypes::SKINNER_CARRYING_SKINS]); } -void nofSkinner::HandleDerivedEvent(unsigned id) +void nofSkinner::HandleDerivedEvent(unsigned) { switch(state) { From 4173c0887d05dc56b2073ada8e6533bf21e837b5 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 17:32:57 +0100 Subject: [PATCH 10/32] LeatherAddon military (2): Add logic for armor in military building as for coins - Order, upgrade, enable/disable - Add armor member to nofSoldier, reduce first armor before hitpoints --- libs/s25main/GamePlayer.cpp | 36 +++- libs/s25main/GamePlayer.h | 1 + libs/s25main/buildings/nobMilitary.cpp | 248 ++++++++++++++++++++-- libs/s25main/buildings/nobMilitary.h | 17 ++ libs/s25main/figures/nofActiveSoldier.cpp | 6 +- libs/s25main/figures/nofSoldier.cpp | 24 ++- libs/s25main/figures/nofSoldier.h | 9 +- libs/s25main/gameData/BuildingConsts.cpp | 30 +++ libs/s25main/gameData/BuildingConsts.h | 3 + libs/s25main/gameData/MilitaryConsts.h | 3 + 10 files changed, 347 insertions(+), 30 deletions(-) diff --git a/libs/s25main/GamePlayer.cpp b/libs/s25main/GamePlayer.cpp index b39537436d..941fd2ec1c 100644 --- a/libs/s25main/GamePlayer.cpp +++ b/libs/s25main/GamePlayer.cpp @@ -992,9 +992,11 @@ struct ClientForWare noBaseBuilding* GamePlayer::FindClientForWare(const Ware& ware) { - // Wenn es eine Goldmünze ist, wird das Ziel auf eine andere Art und Weise berechnet + // If the ware is a coin or an armor, the goal is determined by another logic if(ware.type == GoodType::Coins) return FindClientForCoin(ware); + else if(ware.type == GoodType::Armor) + return FindClientForArmor(ware); // Warentyp herausfinden GoodType gt = ware.type; @@ -1171,6 +1173,38 @@ nobBaseMilitary* GamePlayer::FindClientForCoin(const Ware& ware) const return bb; } +nobBaseMilitary* GamePlayer::FindClientForArmor(const Ware& ware) const +{ + nobBaseMilitary* bb = nullptr; + unsigned best_points = 0, points; + + for(nobMilitary* milBld : buildings.GetMilitaryBuildings()) + { + unsigned way_points; + + points = milBld->CalcArmorPoints(); + // If 0, it does not want any armor (armor delivery stopped) + if(points) + { + // Find the nearest building + if(world.FindPathForWareOnRoads(*ware.GetLocation(), *milBld, &way_points) != RoadPathDirection::None) + { + points -= way_points; + if(points > best_points) + { + best_points = points; + bb = milBld; + } + } + } + } + + if(!bb) + bb = FindWarehouseForWare(ware); + + return bb; +} + unsigned GamePlayer::GetBuidingSitePriority(const noBuildingSite* building_site) { if(useCustomBuildOrder_) diff --git a/libs/s25main/GamePlayer.h b/libs/s25main/GamePlayer.h index 59ee843473..6dbd5b6b4c 100644 --- a/libs/s25main/GamePlayer.h +++ b/libs/s25main/GamePlayer.h @@ -153,6 +153,7 @@ class GamePlayer : public GamePlayerInfo /// Sucht einen Abnehmer (sprich Militärgebäude), wenn es keinen findet, wird ein Warenhaus zurückgegeben bzw. 0 nobBaseMilitary* FindClientForCoin(const Ware& ware) const; + nobBaseMilitary* FindClientForArmor(const Ware& ware) const; /// Gibt Priorität der Baustelle zurück (entscheidet selbständig, welche Reihenfolge usw) /// je kleiner die Rückgabe, destro größer die Priorität! diff --git a/libs/s25main/buildings/nobMilitary.cpp b/libs/s25main/buildings/nobMilitary.cpp index 781eff0e83..dba81a6d42 100644 --- a/libs/s25main/buildings/nobMilitary.cpp +++ b/libs/s25main/buildings/nobMilitary.cpp @@ -7,6 +7,7 @@ #include "FindWhConditions.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "Point.h" #include "SerializedGameData.h" @@ -40,8 +41,9 @@ nobMilitary::nobMilitary(const BuildingType type, const MapPoint pos, const unsigned char player, const Nation nation) : nobBaseMilitary(type, pos, player, nation), new_built(true), numCoins(0), coinsDisabled(false), - coinsDisabledVirtual(false), capturing(false), capturing_soldiers(0), goldorder_event(nullptr), - upgrade_event(nullptr), is_regulating_troops(false) + coinsDisabledVirtual(false), numArmor(0), armorDisabled(false), armorDisabledVirtual(false), capturing(false), + capturing_soldiers(0), goldorder_event(nullptr), armororder_event(nullptr), upgrade_event(nullptr), + armor_upgrade_event(nullptr), is_regulating_troops(false) { // Gebäude entsprechend als Militärgebäude registrieren und in ein Militärquadrat eintragen world->GetMilitarySquares().Add(this); @@ -123,7 +125,9 @@ void nobMilitary::DestroyBuilding() // Events ggf. entfernen GetEvMgr().RemoveEvent(goldorder_event); + GetEvMgr().RemoveEvent(armororder_event); GetEvMgr().RemoveEvent(upgrade_event); + GetEvMgr().RemoveEvent(armor_upgrade_event); // übriggebliebene Goldmünzen in der Inventur abmelden world->GetPlayer(player).DecreaseInventoryWare(GoodType::Coins, numCoins); @@ -154,6 +158,12 @@ void nobMilitary::Serialize(SerializedGameData& sgd) const sgd.PushObjectContainer(troops, true); sgd.PushObjectContainer(far_away_capturers, true); helpers::pushContainer(sgd, troop_limits); + + sgd.PushUnsignedChar(numArmor); + sgd.PushBool(armorDisabled); + sgd.PushEvent(armororder_event); + sgd.PushEvent(armor_upgrade_event); + sgd.PushObjectContainer(ordered_armor, true); } nobMilitary::nobMilitary(SerializedGameData& sgd, const unsigned obj_id) @@ -172,6 +182,21 @@ nobMilitary::nobMilitary(SerializedGameData& sgd, const unsigned obj_id) else helpers::popContainer(sgd, troop_limits); + if(sgd.GetGameDataVersion() >= 12) + { + numArmor = sgd.PopUnsignedChar(); + armorDisabledVirtual = armorDisabled = sgd.PopBool(); + armororder_event = sgd.PopEvent(); + armor_upgrade_event = sgd.PopEvent(); + sgd.PopObjectContainer(ordered_armor, GO_Type::Ware); + } else + { + numArmor = 0; + armorDisabledVirtual = armorDisabled = false; + armororder_event = nullptr; + armor_upgrade_event = nullptr; + } + // ins Militärquadrat einfügen world->GetMilitarySquares().Add(this); @@ -220,9 +245,25 @@ void nobMilitary::Draw(DrawPoint drawPt) if(bitmap) bitmap->DrawFull(drawPt + BORDER_FLAG_OFFSET[nation][size]); + // If coins or armor delivery disabled, show sign at building + if(leatheraddon::isAddonActive(world->GetPlayer(player).GetGameWorld())) + { + if(coinsDisabledVirtual) + LOADER + .GetImageN("leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::STOP_COINS_X_SIGN_OVERRIDE]) + ->DrawFull(drawPt + BUILDING_SIGN_CONSTS[nation][bldType_]); + + if(armorDisabledVirtual) + LOADER.GetImageN("leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::STOP_ARMOR_X_SIGN]) + ->DrawFull(drawPt + BUILDING_SIGN_CONSTS[nation][bldType_] + + BUILDING_ARMOR_SIGN_OFFSET_CONSTS[nation][bldType_]); + } // Wenn Goldzufuhr gestoppt ist, Schild außen am Gebäude zeichnen zeichnen - if(coinsDisabledVirtual) - LOADER.GetMapTexture(46)->DrawFull(drawPt + BUILDING_SIGN_CONSTS[nation][bldType_]); + else + { + if(coinsDisabledVirtual) + LOADER.GetMapTexture(46)->DrawFull(drawPt + BUILDING_SIGN_CONSTS[nation][bldType_]); + } } void nobMilitary::HandleEvent(const unsigned id) @@ -315,6 +356,33 @@ void nobMilitary::HandleEvent(const unsigned id) } } break; + // Order armor event + case 3: + { + armororder_event = nullptr; + SearchArmor(); + } + break; + // Armor upgrade event + case 4: + { + armor_upgrade_event = nullptr; + + auto canidate = std::find_if(troops.begin(), troops.end(), + [](OwnedSortedTroops::value_type& troop) { return !troop->HasArmor(); }); + + if(canidate != troops.end()) + { + (*canidate)->SetArmor(true); + + --numArmor; + world->GetPlayer(player).DecreaseInventoryWare(GoodType::Armor, 1); + + PrepareArmorUpgrading(); + SearchArmor(); + } + } + break; } } @@ -328,6 +396,11 @@ unsigned nobMilitary::GetMaxCoinCt() const return NUM_GOLDS[nation][size]; } +unsigned nobMilitary::GetMaxArmorCt() const +{ + return NUM_ARMOR[nation][size]; +} + unsigned nobMilitary::GetMaxTroopsCt() const { return NUM_TROOPS[nation][size]; @@ -604,31 +677,58 @@ bool nobMilitary::IsInTroops(const nofPassiveSoldier& soldier) const void nobMilitary::TakeWare(Ware* ware) { // Goldmünze in Bestellliste aufnehmen - RTTR_Assert(!helpers::contains(ordered_coins, ware)); - ordered_coins.push_back(ware); + if(ware->type == GoodType::Coins) + { + RTTR_Assert(!helpers::contains(ordered_coins, ware)); + ordered_coins.push_back(ware); + } else if(ware->type == GoodType::Armor) + { + RTTR_Assert(!helpers::contains(ordered_armor, ware)); + ordered_armor.push_back(ware); + } } void nobMilitary::AddWare(std::unique_ptr ware) { - // Ein Golstück mehr - ++numCoins; - // aus der Bestellliste raushaun - RTTR_Assert(helpers::contains(ordered_coins, ware.get())); - ordered_coins.remove(ware.get()); - - // Ware vernichten - world->GetPlayer(player).RemoveWare(*ware); - ware.reset(); - - // Evtl. Soldaten befördern - PrepareUpgrading(); + if(ware->type == GoodType::Coins) + { + // Ein Golstück mehr + ++numCoins; + // aus der Bestellliste raushaun + RTTR_Assert(helpers::contains(ordered_coins, ware.get())); + ordered_coins.remove(ware.get()); + + // Ware vernichten + world->GetPlayer(player).RemoveWare(*ware); + ware.reset(); + + // Evtl. Soldaten befördern + PrepareUpgrading(); + } else if(ware->type == GoodType::Armor) + { + ++numArmor; + RTTR_Assert(helpers::contains(ordered_armor, ware.get())); + ordered_armor.remove(ware.get()); + + world->GetPlayer(player).RemoveWare(*ware); + ware.reset(); + + PrepareArmorUpgrading(); + } } void nobMilitary::WareLost(Ware& ware) { - // Ein Goldstück konnte nicht kommen --> aus der Bestellliste entfernen - RTTR_Assert(helpers::contains(ordered_coins, &ware)); - ordered_coins.remove(&ware); + if(ware.type == GoodType::Coins) + { + // Ein Goldstück konnte nicht kommen --> aus der Bestellliste entfernen + RTTR_Assert(helpers::contains(ordered_coins, &ware)); + ordered_coins.remove(&ware); + } else if(ware.type == GoodType::Armor) + { + RTTR_Assert(helpers::contains(ordered_armor, &ware)); + ordered_armor.remove(&ware); + } } bool nobMilitary::FreePlaceAtFlag() @@ -656,6 +756,11 @@ void nobMilitary::CancelOrders() WareNotNeeded(ordered_coin); ordered_coins.clear(); + + for(auto* ordered_armor : ordered_armor) + WareNotNeeded(ordered_armor); + + ordered_armor.clear(); } void nobMilitary::AddActiveSoldier(std::unique_ptr soldier) @@ -713,10 +818,12 @@ void nobMilitary::AddPassiveSoldier(std::unique_ptr soldier) { // Evtl. Soldaten befördern PrepareUpgrading(); + PrepareArmorUpgrading(); } // Goldmünzen suchen, evtl sinds ja neue Soldaten SearchCoins(); + SearchArmor(); } void nobMilitary::SoldierLost(nofSoldier* soldier) @@ -1140,6 +1247,33 @@ void nobMilitary::SetCoinsAllowed(const bool enabled) } } +void nobMilitary::SetArmorAllowed(const bool enabled) +{ + if(armorDisabled == !enabled) + return; + + armorDisabled = !enabled; + if(GAMECLIENT.GetPlayerId() != player || GAMECLIENT.IsReplayModeOn()) + armorDisabledVirtual = armorDisabled; + + if(!armorDisabled) + SearchArmor(); + else + { + // send armor back if just deactivated + for(auto it = ordered_armor.begin(); it != ordered_armor.end();) + { + // But only those, that are not just Being carried in + if((*it)->GetLocation() != this) + { + WareNotNeeded(*it); + it = ordered_armor.erase(it); + } else + ++it; + } + } +} + unsigned nobMilitary::CalcCoinsPoints() const { // Will ich überhaupt Goldmünzen, wenn nich, sofort raus @@ -1168,6 +1302,28 @@ unsigned nobMilitary::CalcCoinsPoints() const return static_cast(points); } +unsigned nobMilitary::CalcArmorPoints() const +{ + if(!WantArmor()) + return 0; + + // choose 10000 as basic, so we can stil subtract something + int points = 10000; + + // If we have already armor in house or ordered, our request is less important + points -= (numArmor + ordered_armor.size()) * 30; + + auto numberOfUpgradeSoldier = + helpers::count_if(troops, [](OwnedSortedTroops::value_type const& troop) { return !troop->HasArmor(); }); + + points += static_cast(numberOfUpgradeSoldier * 20); + + if(points < 0) + throw std::logic_error("Negative points are not allowed"); + + return static_cast(points); +} + bool nobMilitary::WantCoins() const { // Wenn die Goldzufuhr gestoppt wurde oder Münzvorrat voll ist, will ich gar keine Goldmünzen @@ -1203,6 +1359,40 @@ void nobMilitary::SearchCoins() } } +bool nobMilitary::WantArmor() const +{ + // If armor delivery stopped or stock already full, we do not want any armor + return (!armorDisabled && numArmor + ordered_armor.size() != GetMaxArmorCt() && !new_built); +} + +void nobMilitary::SearchArmor() +{ + if(!leatheraddon::isAddonActive(world->GetPlayer(player).GetGameWorld())) + return; + + if(WantArmor() && !armororder_event) + { + nobBaseWarehouse* wh = + world->GetPlayer(player).FindWarehouse(*this, FW::HasMinWares(GoodType::Armor), false, false); + if(wh) + { + Ware* ware = wh->OrderWare(GoodType::Armor, this); + + if(!ware) + { + RTTR_Assert(false); + LOG.write("nobMilitary::SearchArmor: WARNING: ware = nullptr. Bug alarm!\n"); + return; + } + + RTTR_Assert(helpers::contains(ordered_armor, ware)); + + // After some time, try to order new armor + armororder_event = GetEvMgr().AddEvent(this, 200 + RANDOM_RAND(400), 3); + } + } +} + void nobMilitary::PrepareUpgrading() { // Goldmünzen da? @@ -1234,6 +1424,22 @@ void nobMilitary::PrepareUpgrading() upgrade_event = GetEvMgr().AddEvent(this, UPGRADE_TIME + RANDOM_RAND(UPGRADE_TIME_RANDOM), 2); } +void nobMilitary::PrepareArmorUpgrading() +{ + if(!numArmor) + return; + + if(armor_upgrade_event) + return; + + if(std::none_of(troops.begin(), troops.end(), + [](OwnedSortedTroops::value_type& troop) { return !troop->HasArmor(); })) + return; + + // All here --> Trigger armor upgrade event + armor_upgrade_event = GetEvMgr().AddEvent(this, UPGRADE_TIME + RANDOM_RAND(UPGRADE_TIME_RANDOM), 4); +} + void nobMilitary::HitOfCatapultStone() { // Ein Soldat weniger, falls es noch welche gibt diff --git a/libs/s25main/buildings/nobMilitary.h b/libs/s25main/buildings/nobMilitary.h index 9e5fece1c4..52b3862d20 100644 --- a/libs/s25main/buildings/nobMilitary.h +++ b/libs/s25main/buildings/nobMilitary.h @@ -48,6 +48,8 @@ class nobMilitary : public nobBaseMilitary unsigned char numCoins; /// Gibt an, ob Goldmünzen gesperrt worden (letzteres nur visuell, um Netzwerk-Latenzen zu verstecken) bool coinsDisabled, coinsDisabledVirtual; + unsigned char numArmor; + bool armorDisabled, armorDisabledVirtual; /// Entfernung zur freindlichen Grenze (woraus sich dann die Besatzung ergibt) von 0-3, 0 fern, 3 nah, 2 Hafen! FrontierDistance frontier_distance; /// Größe bzw Typ des Militärgebäudes (0 = Baracke, 3 = Festung) @@ -56,6 +58,7 @@ class nobMilitary : public nobBaseMilitary SortedTroops ordered_troops; /// Bestellter Goldmünzen std::list ordered_coins; + std::list ordered_armor; /// Gibt an, ob gerade die Eroberer in das Gebäude gehen (und es so nicht angegegriffen werden sollte) bool capturing; /// Anzahl der Soldaten, die das Militärgebäude gerade noch einnehmen @@ -65,8 +68,10 @@ class nobMilitary : public nobBaseMilitary std::list far_away_capturers; /// Gold-Bestell-Event const GameEvent* goldorder_event; + const GameEvent* armororder_event; /// Beförderung-Event const GameEvent* upgrade_event; + const GameEvent* armor_upgrade_event; /// Is the military building regulating its troops at the moment? (then block furthere RegulateTroop calls) bool is_regulating_troops; /// Soldatenbesatzung @@ -81,9 +86,11 @@ class nobMilitary : public nobBaseMilitary std::unique_ptr ProvideDefender(nofAttacker& attacker) override; /// Will/kann das Gebäude noch Münzen bekommen? bool WantCoins() const; + bool WantArmor() const; /// Prüft, ob Goldmünzen und Soldaten, die befördert werden können, vorhanden sind und meldet ggf. ein /// Beförderungsevent an void PrepareUpgrading(); + void PrepareArmorUpgrading(); /// Gets the total amount of soldiers (ordered, stationed, on mission) size_t GetTotalSoldiers() const; std::array GetTotalSoldiersByRank() const; @@ -115,6 +122,7 @@ class nobMilitary : public nobBaseMilitary /// Liefert Militärradius des Gebäudes unsigned GetMilitaryRadius() const override; unsigned GetMaxCoinCt() const; + unsigned GetMaxArmorCt() const; unsigned GetMaxTroopsCt() const; /// Sucht feindliche Miitärgebäude im Umkreis und setzt die frontier_distance entsprechend (sowohl selber als @@ -155,6 +163,7 @@ class nobMilitary : public nobBaseMilitary /// Berechnet, wie dringend eine Goldmünze gebraucht wird, in Punkten, je höher desto dringender unsigned CalcCoinsPoints() const; + unsigned CalcArmorPoints() const; /// Wird aufgerufen, wenn ein Soldat kommt void GotWorker(Job job, noFigure& worker) override; @@ -218,11 +227,19 @@ class nobMilitary : public nobBaseMilitary /// Fragt ab, ob Goldzufuhr ausgeschaltet ist (real) bool IsGoldDisabled() const { return coinsDisabled; } unsigned char GetNumCoins() const { return numCoins; } + + void ToggleArmorVirtual() { armorDisabledVirtual = !armorDisabledVirtual; } + void SetArmorAllowed(bool enabled); + bool IsArmorDisabledVirtual() const { return armorDisabledVirtual; } + bool IsArmorDisabled() const { return armorDisabled; } + unsigned char GetNumArmor() const { return numArmor; } + /// is there a max rank soldier in the building? bool HasMaxRankSoldier() const; /// Sucht sämtliche Lagerhäuser nach Goldmünzen ab und bestellt ggf. eine, falls eine gebraucht wird void SearchCoins(); + void SearchArmor(); /// Gebäude wird von einem Katapultstein getroffen void HitOfCatapultStone(); diff --git a/libs/s25main/figures/nofActiveSoldier.cpp b/libs/s25main/figures/nofActiveSoldier.cpp index 164cc20030..af9944fd09 100644 --- a/libs/s25main/figures/nofActiveSoldier.cpp +++ b/libs/s25main/figures/nofActiveSoldier.cpp @@ -18,7 +18,6 @@ nofActiveSoldier::nofActiveSoldier(const MapPoint pos, const unsigned char player, nobBaseMilitary& home, const unsigned char rank, const SoldierState init_state) : nofSoldier(pos, player, home, rank), state(init_state), enemy(nullptr) - {} nofActiveSoldier::nofActiveSoldier(const nofSoldier& other, const SoldierState init_state) @@ -342,7 +341,10 @@ void nofActiveSoldier::InformTargetsAboutCancelling() void nofActiveSoldier::TakeHit() { - RTTR_Assert(hitpoints > 0u); + if(HasArmor()) + SetArmor(false); + else + RTTR_Assert(hitpoints > 0u); --hitpoints; } diff --git a/libs/s25main/figures/nofSoldier.cpp b/libs/s25main/figures/nofSoldier.cpp index bb9f84b5d3..04eaf26dd7 100644 --- a/libs/s25main/figures/nofSoldier.cpp +++ b/libs/s25main/figures/nofSoldier.cpp @@ -11,14 +11,15 @@ #include "gameData/MilitaryConsts.h" nofSoldier::nofSoldier(const MapPoint pos, const unsigned char player, nobBaseMilitary* const goal, - nobBaseMilitary* const home, const unsigned char rank) - : noFigure(SOLDIER_JOBS[rank], pos, player, goal), building(home), hitpoints(HITPOINTS[rank]) + nobBaseMilitary* const home, const unsigned char rank, bool armor) + : noFigure(SOLDIER_JOBS[rank], pos, player, goal), building(home), hitpoints(HITPOINTS[rank]), armor(armor) { RTTR_Assert(IsSoldier()); } -nofSoldier::nofSoldier(const MapPoint pos, const unsigned char player, nobBaseMilitary& home, const unsigned char rank) - : noFigure(SOLDIER_JOBS[rank], pos, player), building(&home), hitpoints(HITPOINTS[rank]) +nofSoldier::nofSoldier(const MapPoint pos, const unsigned char player, nobBaseMilitary& home, const unsigned char rank, + bool armor) + : noFigure(SOLDIER_JOBS[rank], pos, player), building(&home), hitpoints(HITPOINTS[rank]), armor(armor) { RTTR_Assert(IsSoldier()); } @@ -31,6 +32,7 @@ void nofSoldier::Serialize(SerializedGameData& sgd) const sgd.PushObject(building); sgd.PushUnsignedChar(hitpoints); + sgd.PushBool(armor); } nofSoldier::nofSoldier(SerializedGameData& sgd, const unsigned obj_id) : noFigure(sgd, obj_id) @@ -43,6 +45,10 @@ nofSoldier::nofSoldier(SerializedGameData& sgd, const unsigned obj_id) : noFigur building = nullptr; hitpoints = sgd.PopUnsignedChar(); + if(sgd.GetGameDataVersion() >= 12) + armor = sgd.PopBool(); + else + armor = false; } void nofSoldier::DrawSoldierWaiting(DrawPoint drawPt) @@ -70,3 +76,13 @@ unsigned char nofSoldier::GetHitpoints() const { return hitpoints; } + +bool nofSoldier::HasArmor() const +{ + return armor; +} + +void nofSoldier::SetArmor(bool armor) +{ + armor = armor; +} diff --git a/libs/s25main/figures/nofSoldier.h b/libs/s25main/figures/nofSoldier.h index 227e55bf73..f4c9d7af8d 100644 --- a/libs/s25main/figures/nofSoldier.h +++ b/libs/s25main/figures/nofSoldier.h @@ -17,6 +17,8 @@ class nofSoldier : public noFigure nobBaseMilitary* building; /// Hitpoints unsigned char hitpoints; + /// Armor + bool armor; /// Zeichnet den Soldaten beim ganz normalen Laufen void DrawSoldierWaiting(DrawPoint drawPt); @@ -27,8 +29,9 @@ class nofSoldier : public noFigure explicit nofSoldier(const nofSoldier&) = default; public: - nofSoldier(MapPoint pos, unsigned char player, nobBaseMilitary* goal, nobBaseMilitary* home, unsigned char rank); - nofSoldier(MapPoint pos, unsigned char player, nobBaseMilitary& home, unsigned char rank); + nofSoldier(MapPoint pos, unsigned char player, nobBaseMilitary* goal, nobBaseMilitary* home, unsigned char rank, + bool armor = false); + nofSoldier(MapPoint pos, unsigned char player, nobBaseMilitary& home, unsigned char rank, bool armor = false); nofSoldier(SerializedGameData& sgd, unsigned obj_id); void Destroy() override @@ -41,6 +44,8 @@ class nofSoldier : public noFigure /// Liefert Rang des Soldaten unsigned char GetRank() const; unsigned char GetHitpoints() const; + bool HasArmor() const; + void SetArmor(bool armor); bool HasNoHome() const { return building == nullptr; } }; diff --git a/libs/s25main/gameData/BuildingConsts.cpp b/libs/s25main/gameData/BuildingConsts.cpp index c09aed8805..87f7b64d8a 100644 --- a/libs/s25main/gameData/BuildingConsts.cpp +++ b/libs/s25main/gameData/BuildingConsts.cpp @@ -375,3 +375,33 @@ const helpers::MultiEnumArray BUILDING_SMOKE_C babylonians[BuildingType::Mint] = SmokeConst(3, {11, -58}); return result; }(); + +const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_OFFSET_CONSTS = []() { + std::remove_const_t result{}; + auto& africans = result[Nation::Africans]; + africans[BuildingType::Barracks] = DrawPoint(8, 15); + africans[BuildingType::Guardhouse] = DrawPoint(11, 18); + africans[BuildingType::Watchtower] = DrawPoint(0, 19); + africans[BuildingType::Fortress] = DrawPoint(2, 19); + auto& japanese = result[Nation::Japanese]; + japanese[BuildingType::Barracks] = DrawPoint(0, 8); + japanese[BuildingType::Guardhouse] = DrawPoint(0, 8); + japanese[BuildingType::Watchtower] = DrawPoint(0, 10); + japanese[BuildingType::Fortress] = DrawPoint(-12, 5); + auto& romans = result[Nation::Romans]; + romans[BuildingType::Barracks] = DrawPoint(0, 8); + romans[BuildingType::Guardhouse] = DrawPoint(0, 8); + romans[BuildingType::Watchtower] = DrawPoint(19, -2); + romans[BuildingType::Fortress] = DrawPoint(0, 10); + auto& vikings = result[Nation::Vikings]; + vikings[BuildingType::Barracks] = DrawPoint(-19, 10); + vikings[BuildingType::Guardhouse] = DrawPoint(-20, 7); + vikings[BuildingType::Watchtower] = DrawPoint(0, 11); + vikings[BuildingType::Fortress] = DrawPoint(-9, 3); + auto& babylonians = result[Nation::Babylonians]; + babylonians[BuildingType::Barracks] = DrawPoint(14, 5); + babylonians[BuildingType::Guardhouse] = DrawPoint(0, -9); + babylonians[BuildingType::Watchtower] = DrawPoint(0, 13); + babylonians[BuildingType::Fortress] = DrawPoint(0, 24); + return result; +}(); diff --git a/libs/s25main/gameData/BuildingConsts.h b/libs/s25main/gameData/BuildingConsts.h index 307843d173..574df4c674 100644 --- a/libs/s25main/gameData/BuildingConsts.h +++ b/libs/s25main/gameData/BuildingConsts.h @@ -106,6 +106,9 @@ constexpr helpers::MultiEnumArray SUPPRESS_UNUS {11, -7}, {1, -22}, {7, -12}, {14, -16}, {21, -18}, {13, -11}, {5, -17}, {-2, -29}, {18, -20}, {0, 0}, {0, 0}, {14, -13}, {3, -17}, {0, -18}, {12, -10}, {16, 0}, {4, -16}, {-15, -11}, {-24, -9}, {0, 0}}}}}; +/// Offset of the armor stop signs per building +extern const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_OFFSET_CONSTS; + /// Position der nubischen Feuer für alle 4 Bergwerke /// (Granit, Kohle, Eisen, Gold) constexpr std::array SUPPRESS_UNUSED NUBIAN_MINE_FIRE = {{ diff --git a/libs/s25main/gameData/MilitaryConsts.h b/libs/s25main/gameData/MilitaryConsts.h index ecfaeecf40..c5796b7813 100644 --- a/libs/s25main/gameData/MilitaryConsts.h +++ b/libs/s25main/gameData/MilitaryConsts.h @@ -42,6 +42,9 @@ constexpr helpers::EnumArray, Nation> NUM_TRO constexpr helpers::EnumArray, Nation> NUM_GOLDS = { {{1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}}}; +constexpr helpers::EnumArray, Nation> NUM_ARMOR = { + {{1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}, {1, 2, 4, 6}}}; + /// Radien der Militärgebäude constexpr std::array SUPPRESS_UNUSED MILITARY_RADIUS = {{8, 9, 10, 11}}; // Radius für einzelne Hafen(baustellen) From 264b5d6d65143aedb271fbdc8991575a394a15de Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 17:42:22 +0100 Subject: [PATCH 11/32] LeatherAddon military (3): Add armor gui elements to military building - refactor gui to handle adding new stuff more easily --- .../ingameWindows/iwMilitaryBuilding.cpp | 125 ++++++++++++++---- 1 file changed, 98 insertions(+), 27 deletions(-) diff --git a/libs/s25main/ingameWindows/iwMilitaryBuilding.cpp b/libs/s25main/ingameWindows/iwMilitaryBuilding.cpp index ced147f5cd..2a92b5bf62 100644 --- a/libs/s25main/ingameWindows/iwMilitaryBuilding.cpp +++ b/libs/s25main/ingameWindows/iwMilitaryBuilding.cpp @@ -6,6 +6,7 @@ #include "iwMilitaryBuilding.h" #include "GamePlayer.h" #include "GlobalGameSettings.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "addons/const_addons.h" @@ -25,71 +26,94 @@ #include "gameData/BuildingConsts.h" #include "gameData/MilitaryConsts.h" #include "gameData/const_gui_ids.h" -#include + +constexpr unsigned ARMOR_ENABLE_BUTTON_ID = 10 + NUM_SOLDIER_RANKS * 4 + 1; +constexpr unsigned HEIGHT_OF_ROW = 38; iwMilitaryBuilding::iwMilitaryBuilding(GameWorldView& gwv, GameCommandFactory& gcFactory, nobMilitary* const building) : IngameWindow(CGI_BUILDING + MapBase::CreateGUIID(building->GetPos()), IngameWindow::posAtMouse, Extent(226, 194), _(BUILDING_NAMES[building->GetBuildingType()]), LOADER.GetImageN("resource", 41)), gwv(gwv), gcFactory(gcFactory), building(building) { - unsigned btOffset = 0; - if(gwv.GetWorld().GetGGS().getSelection(AddonId::MILITARY_CONTROL) == 2) + auto addonStatusMilitaryControl = gwv.GetWorld().GetGGS().getSelection(AddonId::MILITARY_CONTROL); + + DrawPoint btOffset(0, 0); + if(addonStatusMilitaryControl == 2) + btOffset.y += 154; + + DrawPoint btOffsetLeatherAddon(0, 0); + if(leatheraddon::isAddonActive(gwv.GetWorld())) { - btOffset = 154; - Resize(Extent(226, 348)); + btOffsetLeatherAddon = DrawPoint(addonStatusMilitaryControl == 0 ? 0 : 36, HEIGHT_OF_ROW); + btOffset += btOffsetLeatherAddon; } + Resize(Extent(226 + btOffset.x, 194 + btOffset.y)); + // Schwert AddImage(0, DrawPoint(28, 39), LOADER.GetMapTexture(2298)); AddImage(1, DrawPoint(28, 39), LOADER.GetWareTex(GoodType::Sword)); // Schild - AddImage(2, DrawPoint(196, 39), LOADER.GetMapTexture(2298)); - AddImage(3, DrawPoint(196, 39), LOADER.GetWareTex(GoodType::ShieldRomans)); + AddImage(2, DrawPoint(196 + btOffset.x, 39), LOADER.GetMapTexture(2298)); + AddImage(3, DrawPoint(196 + btOffset.x, 39), LOADER.GetWareTex(GoodType::ShieldRomans)); // Hilfe - AddImageButton(4, DrawPoint(16, btOffset + 147), Extent(30, 32), TextureColor::Grey, LOADER.GetImageN("io", 225), + AddImageButton(4, DrawPoint(16, btOffset.y + 147), Extent(30, 32), TextureColor::Grey, LOADER.GetImageN("io", 225), _("Help")); // Abreißen - AddImageButton(5, DrawPoint(50, btOffset + 147), Extent(34, 32), TextureColor::Grey, LOADER.GetImageN("io", 23), + AddImageButton(5, DrawPoint(50, btOffset.y + 147), Extent(34, 32), TextureColor::Grey, LOADER.GetImageN("io", 23), _("Demolish house")); // Gold an/aus (227,226) - AddImageButton(6, DrawPoint(90, btOffset + 147), Extent(32, 32), TextureColor::Grey, + AddImageButton(6, DrawPoint(90, btOffset.y + 147), Extent(32, 32), TextureColor::Grey, LOADER.GetImageN("io", ((building->IsGoldDisabledVirtual()) ? 226 : 227)), _("Gold delivery")); // "Gehe Zu Ort" - AddImageButton(7, DrawPoint(179, btOffset + 147), Extent(30, 32), TextureColor::Grey, LOADER.GetImageN("io", 107), - _("Go to place")); + AddImageButton(7, DrawPoint(179 + btOffset.x, btOffset.y + 147), Extent(30, 32), TextureColor::Grey, + LOADER.GetImageN("io", 107), _("Go to place")); // Gebäudebild - AddImage(8, DrawPoint(117, 114), &building->GetBuildingImage()); + AddImage(8, DrawPoint(117 + btOffset.x / 2, 114), &building->GetBuildingImage()); // "Go to next" (building of same type) - AddImageButton(9, DrawPoint(179, btOffset + 115), Extent(30, 32), TextureColor::Grey, + AddImageButton(9, DrawPoint(179 + btOffset.x, btOffset.y + 115), Extent(30, 32), TextureColor::Grey, LOADER.GetImageN("io_new", 11), _("Go to next military building")); - if(gwv.GetWorld().GetGGS().getSelection(AddonId::MILITARY_CONTROL) == 1) + if(leatheraddon::isAddonActive(gwv.GetWorld())) + { + AddImageButton(ARMOR_ENABLE_BUTTON_ID, DrawPoint(126 + btOffsetLeatherAddon.x, btOffset.y + 147), + Extent(32, 32), TextureColor::Grey, + LOADER.GetImageN("leather_bobs", + leatheraddon::bobIndex[building->IsArmorDisabledVirtual() ? + leatheraddon::BobTypes::DISABLE_DELIVERY_ARMOR_ICON : + leatheraddon::BobTypes::ARMOR_DELIVER_ICON]), + _("Armor delivery")); + } + + if(addonStatusMilitaryControl == 1) { // Minimal troop controls - AddImageButton(10, DrawPoint(126, btOffset + 147), Extent(32, 32), TextureColor::Grey, + AddImageButton(10, DrawPoint(126, btOffset.y + 147), Extent(32, 32), TextureColor::Grey, LOADER.GetImageN("io_new", 12), _("Send max rank soldiers to a warehouse")); - } else if(gwv.GetWorld().GetGGS().getSelection(AddonId::MILITARY_CONTROL) == 2) + } else if(addonStatusMilitaryControl == 2) { // Full troop controls - AddImageButton(10, DrawPoint(126, btOffset + 147), Extent(32, 32), TextureColor::Grey, + AddImageButton(10, DrawPoint(126, btOffset.y + 147), Extent(32, 32), TextureColor::Grey, LOADER.GetImageN("io_new", 12), _("Send soldiers home")); const unsigned Y_SPACING = 30; for(unsigned i = 0; i < NUM_SOLDIER_RANKS; ++i) { // Minus - AddImageButton(11 + (4 * i), DrawPoint(69, 136 + Y_SPACING * i), Extent(24, 24), TextureColor::Red1, - LOADER.GetImageN("io", 139), _("Fewer")); + AddImageButton(11 + (4 * i), DrawPoint(69 + btOffset.x / 2, 136 + btOffsetLeatherAddon.y + Y_SPACING * i), + Extent(24, 24), TextureColor::Red1, LOADER.GetImageN("io", 139), _("Fewer")); // Background - AddImage(12 + (4 * i), DrawPoint(113, 148 + Y_SPACING * i), LOADER.GetMapTexture(2298)); + AddImage(12 + (4 * i), DrawPoint(113 + btOffset.x / 2, 148 + btOffsetLeatherAddon.y + Y_SPACING * i), + LOADER.GetMapTexture(2298)); // Rank image - AddImage(13 + (4 * i), DrawPoint(113, 148 + Y_SPACING * i), LOADER.GetMapTexture(2321 + i)); + AddImage(13 + (4 * i), DrawPoint(113 + btOffset.x / 2, 148 + btOffsetLeatherAddon.y + Y_SPACING * i), + LOADER.GetMapTexture(2321 + i)); // Plus - AddImageButton(14 + (4 * i), DrawPoint(133, 136 + Y_SPACING * i), Extent(24, 24), TextureColor::Green2, - LOADER.GetImageN("io", 138), _("More")); + AddImageButton(14 + (4 * i), DrawPoint(133 + btOffset.x / 2, 136 + btOffsetLeatherAddon.y + Y_SPACING * i), + Extent(24, 24), TextureColor::Green2, LOADER.GetImageN("io", 138), _("More")); } } } @@ -101,9 +125,11 @@ void iwMilitaryBuilding::Draw_() if(IsMinimized()) return; + unsigned btOffsetY = 60; + // Schwarzer Untergrund für Goldanzeige const unsigned maxCoinCt = building->GetMaxCoinCt(); - DrawPoint goldPos = GetDrawPos() + DrawPoint((GetSize().x - 22 * maxCoinCt) / 2, 60); + DrawPoint goldPos = GetDrawPos() + DrawPoint((GetSize().x - 22 * maxCoinCt) / 2, btOffsetY); DrawRectangle(Rect(goldPos, Extent(22 * maxCoinCt, 24)), 0x96000000); // Gold goldPos += DrawPoint(12, 12); @@ -112,6 +138,24 @@ void iwMilitaryBuilding::Draw_() LOADER.GetMapTexture(2278)->DrawFull(goldPos, (i >= building->GetNumCoins() ? 0xFFA0A0A0 : 0xFFFFFFFF)); goldPos.x += 22; } + btOffsetY += HEIGHT_OF_ROW; + + if(leatheraddon::isAddonActive(gwv.GetWorld())) + { + // Black background for armor display + const unsigned maxArmorCt = building->GetMaxArmorCt(); + DrawPoint armorPos = GetDrawPos() + DrawPoint((GetSize().x - 22 * maxArmorCt) / 2, btOffsetY); + DrawRectangle(Rect(armorPos, Extent(22 * maxArmorCt, 24)), 0x96000000); + // Armor + armorPos += DrawPoint(12, 12); + for(unsigned short i = 0; i < maxArmorCt; ++i) + { + LOADER.GetImageN("leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::ARMOR_WARE_ICON]) + ->DrawFull(armorPos, (i >= building->GetNumArmor() ? 0xFFA0A0A0 : 0xFFFFFFFF)); + armorPos.x += 22; + } + btOffsetY += HEIGHT_OF_ROW; + } // Sammeln aus der Rausgeh-Liste und denen, die wirklich noch drinne sind boost::container::flat_set soldiers; @@ -128,7 +172,7 @@ void iwMilitaryBuilding::Draw_() } const unsigned maxSoldierCt = building->GetMaxTroopsCt(); - DrawPoint troopsPos = GetDrawPos() + DrawPoint((GetSize().x - 22 * maxSoldierCt) / 2, 98); + DrawPoint troopsPos = GetDrawPos() + DrawPoint((GetSize().x - 22 * maxSoldierCt) / 2, btOffsetY); // Schwarzer Untergrund für Soldatenanzeige DrawRectangle(Rect(troopsPos, Extent(22 * maxSoldierCt, 24)), 0x96000000); @@ -136,6 +180,11 @@ void iwMilitaryBuilding::Draw_() DrawPoint curTroopsPos = troopsPos + DrawPoint(12, 12); for(const auto* soldier : soldiers) { + if(leatheraddon::isAddonActive(gwv.GetWorld()) && soldier->HasArmor()) + { + LOADER.GetImageN("leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::ARMOR_WARE_ICON]) + ->DrawFull(curTroopsPos, 0xFFA0A0A0); + } LOADER.GetMapTexture(2321 + soldier->GetRank())->DrawFull(curTroopsPos); curTroopsPos.x += 22; } @@ -164,15 +213,21 @@ void iwMilitaryBuilding::Draw_() hitpointsColour = COLOR_ORANGE; } NormalFont->Draw(healthPos, std::to_string(hitpoints), FontStyle::CENTER, hitpointsColour); + if(leatheraddon::isAddonActive(gwv.GetWorld()) && soldier->HasArmor()) + { + SmallFont->Draw(healthPos + DrawPoint(7, 0), "+", FontStyle::CENTER, hitpointsColour); + SmallFont->Draw(healthPos + DrawPoint(10, 0), "1", FontStyle::CENTER, hitpointsColour); + } healthPos.x += 22; } } + btOffsetY += HEIGHT_OF_ROW; if(gwv.GetWorld().GetGGS().getSelection(AddonId::MILITARY_CONTROL) == 2) { const unsigned Y_SPACING = 30; for(unsigned i = 0; i < NUM_SOLDIER_RANKS; ++i) - NormalFont->Draw(GetDrawPos() + DrawPoint(101, 136 + Y_SPACING * i), + NormalFont->Draw(GetDrawPos() + DrawPoint(GetSize().x / 2 - 12, btOffsetY + Y_SPACING * i), std::to_string(building->GetTroopLimit(i)), FontStyle::LEFT, COLOR_YELLOW); } } @@ -266,6 +321,22 @@ void iwMilitaryBuilding::Msg_ButtonClick(const unsigned ctrl_id) } } break; + case ARMOR_ENABLE_BUTTON_ID: + { + if(!GAMECLIENT.IsReplayModeOn()) + { + // NC senden + if(gcFactory.SetArmorAllowed(building->GetPos(), building->IsArmorDisabledVirtual())) + { + building->ToggleArmorVirtual(); + GetCtrl(ctrl_id)->SetImage(LOADER.GetImageN( + "leather_bobs", leatheraddon::bobIndex[building->IsArmorDisabledVirtual() ? + leatheraddon::BobTypes::DISABLE_DELIVERY_ARMOR_ICON : + leatheraddon::BobTypes::ARMOR_DELIVER_ICON])); + } + } + } + break; default: { if(ctrl_id > 10) From 817e3c1c55216da20129b31a27ae3d069cd985b6 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 18:08:23 +0100 Subject: [PATCH 12/32] fixup! LeatherAddon military (2): Add logic for armor in military building as for coins fix wrong logic c++ code --- libs/s25main/figures/nofActiveSoldier.cpp | 4 +++- libs/s25main/figures/nofSoldier.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/s25main/figures/nofActiveSoldier.cpp b/libs/s25main/figures/nofActiveSoldier.cpp index af9944fd09..c8851a4971 100644 --- a/libs/s25main/figures/nofActiveSoldier.cpp +++ b/libs/s25main/figures/nofActiveSoldier.cpp @@ -344,8 +344,10 @@ void nofActiveSoldier::TakeHit() if(HasArmor()) SetArmor(false); else + { RTTR_Assert(hitpoints > 0u); - --hitpoints; + --hitpoints; + } } bool nofActiveSoldier::IsReadyForFight() const diff --git a/libs/s25main/figures/nofSoldier.cpp b/libs/s25main/figures/nofSoldier.cpp index 04eaf26dd7..ed5a637cec 100644 --- a/libs/s25main/figures/nofSoldier.cpp +++ b/libs/s25main/figures/nofSoldier.cpp @@ -84,5 +84,5 @@ bool nofSoldier::HasArmor() const void nofSoldier::SetArmor(bool armor) { - armor = armor; + this->armor = armor; } From 727adb9057a83c068679986abc9105cab00ee346 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 19:11:35 +0100 Subject: [PATCH 13/32] Add test for SetArmorAllowed --- .../s25Main/integration/testGameCommands.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/s25Main/integration/testGameCommands.cpp b/tests/s25Main/integration/testGameCommands.cpp index 67208925fe..2cb935756c 100644 --- a/tests/s25Main/integration/testGameCommands.cpp +++ b/tests/s25Main/integration/testGameCommands.cpp @@ -621,6 +621,33 @@ BOOST_FIXTURE_TEST_CASE(ChangeCoinAccept, WorldWithGCExecution2P) BOOST_TEST_REQUIRE(!bld->IsGoldDisabled()); } +BOOST_FIXTURE_TEST_CASE(ChangeArmorAccept, WorldWithGCExecution2P) +{ + const MapPoint bldPt = hqPos + MapPoint(3, 0); + auto* bld = dynamic_cast( + BuildingFactory::CreateBuilding(world, BuildingType::Watchtower, bldPt, curPlayer, Nation::Romans)); + BOOST_TEST_REQUIRE(bld); + BOOST_TEST_REQUIRE(!bld->IsArmorDisabled()); //-V522 + + // Enable (already is) + this->SetArmorAllowed(bldPt, true); + BOOST_TEST_REQUIRE(!bld->IsArmorDisabled()); + + // Disable + this->SetArmorAllowed(bldPt, false); + BOOST_TEST_REQUIRE(bld->IsArmorDisabled()); + + // Reenable + this->SetArmorAllowed(bldPt, true); + BOOST_TEST_REQUIRE(!bld->IsArmorDisabled()); + + // Production should have no effect + this->SetProductionEnabled(bldPt, true); + BOOST_TEST_REQUIRE(!bld->IsArmorDisabled()); + this->SetProductionEnabled(bldPt, false); + BOOST_TEST_REQUIRE(!bld->IsArmorDisabled()); +} + BOOST_FIXTURE_TEST_CASE(DisableProduction, WorldWithGCExecution2P) { const MapPoint bldPt = hqPos + MapPoint(3, 0); @@ -646,6 +673,12 @@ BOOST_FIXTURE_TEST_CASE(DisableProduction, WorldWithGCExecution2P) BOOST_TEST_REQUIRE(!bld->IsProductionDisabled()); this->SetCoinsAllowed(bldPt, false); BOOST_TEST_REQUIRE(!bld->IsProductionDisabled()); + + // Armor should have no effect + this->SetArmorAllowed(bldPt, true); + BOOST_TEST_REQUIRE(!bld->IsProductionDisabled()); + this->SetArmorAllowed(bldPt, false); + BOOST_TEST_REQUIRE(!bld->IsProductionDisabled()); } namespace { From c0546ba83609f0810145a1ab85ea9fdc5032c527 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 20:26:51 +0100 Subject: [PATCH 14/32] fixup! Add compatibilty code add missing comp code for new ham distribution category --- libs/s25main/GamePlayer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/s25main/GamePlayer.cpp b/libs/s25main/GamePlayer.cpp index 941fd2ec1c..efdc101a6b 100644 --- a/libs/s25main/GamePlayer.cpp +++ b/libs/s25main/GamePlayer.cpp @@ -272,6 +272,13 @@ void GamePlayer::Deserialize(SerializedGameData& sgd) Distribution& dist = distribution[i]; helpers::popContainer(sgd, dist.percent_buildings); + // Set standard value otherwise its zero and Slaughterhouse never gets ham + // because the ham distribution was not there in earlier versions + if(sgd.GetGameDataVersion() < 12 && i == GoodType::Ham) + { + dist.percent_buildings[BuildingType::Slaughterhouse] = 8; + } + if(sgd.GetGameDataVersion() < 7) { dist.client_buildings.resize(sgd.PopUnsignedInt()); From 70485bbbe6baf8aa84cdf4c757cadfc7db212ffe Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 20:30:23 +0100 Subject: [PATCH 15/32] Add compatibility code for ChangeDistribution and increase game command version to 2 --- libs/s25main/GameCommand.cpp | 3 ++- libs/s25main/GameCommands.cpp | 40 ++++++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/libs/s25main/GameCommand.cpp b/libs/s25main/GameCommand.cpp index 0603675a24..8d2fa939e5 100644 --- a/libs/s25main/GameCommand.cpp +++ b/libs/s25main/GameCommand.cpp @@ -13,7 +13,8 @@ namespace gc { unsigned Deserializer::getCurrentVersion() { // 1: Add wine addon --> 3 new values in distribution - return 1; + // 2: Add leather addon --> 3 new values in distribution + return 2; } GameCommandPtr GameCommand::Deserialize(Deserializer& ser) diff --git a/libs/s25main/GameCommands.cpp b/libs/s25main/GameCommands.cpp index 3e9e673976..15ca14f66b 100644 --- a/libs/s25main/GameCommands.cpp +++ b/libs/s25main/GameCommands.cpp @@ -4,6 +4,7 @@ #include "GameCommands.h" #include "GamePlayer.h" +#include "LeatherLoader.h" #include "WineLoader.h" #include "buildings/nobBaseWarehouse.h" #include "buildings/nobHarborBuilding.h" @@ -90,20 +91,43 @@ void UpgradeRoad::Execute(GameWorld& world, uint8_t playerId) ChangeDistribution::ChangeDistribution(Deserializer& ser) : GameCommand(GCType::ChangeDistribution) { - if(ser.getDataVersion() >= 1) + if(ser.getDataVersion() >= 2) helpers::popContainer(ser, data); else { - std::array::value - 3> - tmpData; // 3 entries for wine addon - helpers::popContainer(ser, tmpData); + const unsigned wineAddonAdditionalDistributions = 3; + const unsigned leatherAddonAdditionalDistributions = 3; + + auto const additionalDistributions = + leatherAddonAdditionalDistributions + (ser.getDataVersion() < 1 ? wineAddonAdditionalDistributions : 0); + + std::vector tmpData(std::tuple_size::value - additionalDistributions); + + auto skipBuilding = [&](DistributionMapping const& mapping) { + // Skipped and standard distribution in skipped case + std::tuple result = {false, 0}; + if(ser.getDataVersion() < 1) + { + // skip over wine buildings + std::get<0>(result) |= wineaddon::isWineAddonBuildingType(std::get(mapping)); + } + + // skip over leather addon buildings and leather addon wares only + std::get<0>(result) |= leatheraddon::isLeatherAddonBuildingType(std::get(mapping)); + + if(std::get(mapping) == BuildingType::Slaughterhouse + && (std::get(mapping) == GoodType::Ham)) + result = {true, 8}; + return result; + }; + + helpers::popContainer(ser, tmpData, true); size_t srcIdx = 0, tgtIdx = 0; for(const auto& mapping : distributionMap) { - // skip over wine buildings in tmpData - const auto setting = - wineaddon::isWineAddonBuildingType(std::get(mapping)) ? 0 : tmpData[srcIdx++]; + // skip over not stored buildings in tmpData + const auto skipped = skipBuilding(mapping); + const auto setting = std::get<0>(skipped) ? std::get<1>(skipped) : tmpData[srcIdx++]; data[tgtIdx++] = setting; } } From fb8639d9a01ed5dd2b4bcec8a142056c47800560 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 23:42:08 +0100 Subject: [PATCH 16/32] fixup! Adding ware workflow, buildings and menus for leather addon code review --- libs/s25main/Loader.cpp | 10 ++++++---- libs/s25main/figures/nofLeatherWorker.h | 1 - libs/s25main/gameData/BuildingConsts.cpp | 2 +- libs/s25main/ingameWindows/iwShip.cpp | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libs/s25main/Loader.cpp b/libs/s25main/Loader.cpp index 0ca63a50f6..da74aa669a 100644 --- a/libs/s25main/Loader.cpp +++ b/libs/s25main/Loader.cpp @@ -924,16 +924,18 @@ void Loader::fillCaches() { leatheraddon::BobTypes carrierEnum; if(ware == GoodType::Skins) + { carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS : leatheraddon::BobTypes::THIN_CARRIER_CARRYING_SKINS; - - if(ware == GoodType::Leather) + } else if(ware == GoodType::Leather) + { carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_LEATHER : leatheraddon::BobTypes::THIN_CARRIER_CARRYING_LEATHER; - - if(ware == GoodType::Armor) + } else if(ware == GoodType::Armor) + { carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_ARMOR : leatheraddon::BobTypes::THIN_CARRIER_CARRYING_ARMOR; + } const unsigned bodyIdx = static_cast(imgDir) * 8 + ani_step; bmp.add(dynamic_cast( diff --git a/libs/s25main/figures/nofLeatherWorker.h b/libs/s25main/figures/nofLeatherWorker.h index 351f6f4af7..9d08c8987d 100644 --- a/libs/s25main/figures/nofLeatherWorker.h +++ b/libs/s25main/figures/nofLeatherWorker.h @@ -19,7 +19,6 @@ class nofLeatherWorker : public nofWorkman void DrawWorking(DrawPoint drawPt) override; /// Id in jobs.bob or carrier.bob when carrying a ware [[noreturn]] unsigned short GetCarryID() const override; - /// Der Arbeiter erzeugt eine Ware helpers::OptionalEnum ProduceWare() override; /// Draws the figure while returning home / entering the building (often carrying wares) diff --git a/libs/s25main/gameData/BuildingConsts.cpp b/libs/s25main/gameData/BuildingConsts.cpp index 87f7b64d8a..6e6e419eb4 100644 --- a/libs/s25main/gameData/BuildingConsts.cpp +++ b/libs/s25main/gameData/BuildingConsts.cpp @@ -130,7 +130,7 @@ const helpers::EnumArray BUILDING_HELP_STRINGS = {{ "desired mineral can be selected by " "toggling the output button."), // Tannery building - gettext_noop("The tanner works animals skins to form leather. " + gettext_noop("The tanner works animal skins to form leather. " "Before tanning; the skins are cured, scraped and " "stretched on wooden frames made from boards. " "Leather is used to produce armor at the leatherworks."), diff --git a/libs/s25main/ingameWindows/iwShip.cpp b/libs/s25main/ingameWindows/iwShip.cpp index 0f8beb2ccc..853be71db7 100644 --- a/libs/s25main/ingameWindows/iwShip.cpp +++ b/libs/s25main/ingameWindows/iwShip.cpp @@ -271,7 +271,7 @@ void iwShip::DrawCargo() leatheraddon::BobTypes type = leatheraddon::BobTypes::SKINNER_WALKING; if(job == Job::Tanner) type = leatheraddon::BobTypes::TANNER_WALKING; - if(job == Job::LeatherWorker) + else if(job == Job::LeatherWorker) type = leatheraddon::BobTypes::LEATHERWORKER_WALKING; LOADER From ea18d5f84eb97aa01d136614557e779020b20343 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 8 Dec 2024 23:46:57 +0100 Subject: [PATCH 17/32] fixup! Adding ware workflow, buildings and menus for leather addon temporary fix we clean this up later --- libs/s25main/Loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/s25main/Loader.cpp b/libs/s25main/Loader.cpp index da74aa669a..8c551c4bce 100644 --- a/libs/s25main/Loader.cpp +++ b/libs/s25main/Loader.cpp @@ -922,7 +922,7 @@ void Loader::fillCaches() + static_cast(imgDir)))); } else if(leatheraddon::isLeatherAddonGoodType(ware)) { - leatheraddon::BobTypes carrierEnum; + leatheraddon::BobTypes carrierEnum = leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS; if(ware == GoodType::Skins) { carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS : From 0340c200d0242a415977f490e966e1a3d6fc068d Mon Sep 17 00:00:00 2001 From: Sunrise Date: Tue, 10 Dec 2024 19:40:27 +0100 Subject: [PATCH 18/32] fixup! Add fixed animations from leather_bobs.lst Use correct index for fat armor carrier 280 instead of 282, which is wrong in docu --- libs/s25main/LeatherLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/s25main/LeatherLoader.cpp b/libs/s25main/LeatherLoader.cpp index 4088c8a0d7..c646864a79 100644 --- a/libs/s25main/LeatherLoader.cpp +++ b/libs/s25main/LeatherLoader.cpp @@ -30,7 +30,7 @@ bool isLeatherAddonJobType(Job job) } helpers::EnumArray bobIndex = {0, 21, 69, 117, 125, 173, 221, 244, 292, 340, 388, - 436, 484, 532, 582, 628, 629, 630, 630, 631, 631, 632, + 436, 484, 532, 580, 628, 629, 630, 630, 631, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643}; ITexture* GetWareTex(const GoodType good) From 55c25c8ee1ba157c0f58a4e7077dbd631f3b2209 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Tue, 10 Dec 2024 19:41:28 +0100 Subject: [PATCH 19/32] fixup! Skinner goes out to get skins from carcass if he has no pigs (naturally died our died by the hunter) Add check so skinner do not skinn the same animal, which leads to crash --- libs/s25main/nodeObjs/noAnimal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/s25main/nodeObjs/noAnimal.cpp b/libs/s25main/nodeObjs/noAnimal.cpp index 1fa374b9cd..0ab96be27b 100644 --- a/libs/s25main/nodeObjs/noAnimal.cpp +++ b/libs/s25main/nodeObjs/noAnimal.cpp @@ -311,7 +311,7 @@ helpers::OptionalEnum noAnimal::FindDir() bool noAnimal::CanSkinned() const { - return (species != Species::Duck && state == State::Dead); + return (species != Species::Duck && state == State::Dead && !skinner); } bool noAnimal::IsSkinned() const From 0ceb01c9c802a8fa5692b73626ad5313afc67ded Mon Sep 17 00:00:00 2001 From: Sunrise Date: Wed, 11 Dec 2024 16:42:14 +0100 Subject: [PATCH 20/32] fixup! LeatherAddon military (2): Add logic for armor in military building as for coins Use corretc x sign offsets --- libs/s25main/buildings/nobMilitary.cpp | 3 +- libs/s25main/gameData/BuildingConsts.cpp | 44 ++++++++++++------------ libs/s25main/gameData/BuildingConsts.h | 2 +- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/libs/s25main/buildings/nobMilitary.cpp b/libs/s25main/buildings/nobMilitary.cpp index dba81a6d42..c939409ecf 100644 --- a/libs/s25main/buildings/nobMilitary.cpp +++ b/libs/s25main/buildings/nobMilitary.cpp @@ -255,8 +255,7 @@ void nobMilitary::Draw(DrawPoint drawPt) if(armorDisabledVirtual) LOADER.GetImageN("leather_bobs", leatheraddon::bobIndex[leatheraddon::BobTypes::STOP_ARMOR_X_SIGN]) - ->DrawFull(drawPt + BUILDING_SIGN_CONSTS[nation][bldType_] - + BUILDING_ARMOR_SIGN_OFFSET_CONSTS[nation][bldType_]); + ->DrawFull(drawPt + BUILDING_ARMOR_SIGN_CONSTS[nation][bldType_]); } // Wenn Goldzufuhr gestoppt ist, Schild außen am Gebäude zeichnen zeichnen else diff --git a/libs/s25main/gameData/BuildingConsts.cpp b/libs/s25main/gameData/BuildingConsts.cpp index 6e6e419eb4..9c9698d568 100644 --- a/libs/s25main/gameData/BuildingConsts.cpp +++ b/libs/s25main/gameData/BuildingConsts.cpp @@ -376,32 +376,32 @@ const helpers::MultiEnumArray BUILDING_SMOKE_C return result; }(); -const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_OFFSET_CONSTS = []() { - std::remove_const_t result{}; +const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_CONSTS = []() { + std::remove_const_t result{}; auto& africans = result[Nation::Africans]; - africans[BuildingType::Barracks] = DrawPoint(8, 15); - africans[BuildingType::Guardhouse] = DrawPoint(11, 18); - africans[BuildingType::Watchtower] = DrawPoint(0, 19); - africans[BuildingType::Fortress] = DrawPoint(2, 19); + africans[BuildingType::Barracks] = DrawPoint(11, -19); + africans[BuildingType::Guardhouse] = DrawPoint(8, -21); + africans[BuildingType::Watchtower] = DrawPoint(23, -38); + africans[BuildingType::Fortress] = DrawPoint(27, -42); auto& japanese = result[Nation::Japanese]; - japanese[BuildingType::Barracks] = DrawPoint(0, 8); - japanese[BuildingType::Guardhouse] = DrawPoint(0, 8); - japanese[BuildingType::Watchtower] = DrawPoint(0, 10); - japanese[BuildingType::Fortress] = DrawPoint(-12, 5); + japanese[BuildingType::Barracks] = DrawPoint(12, -18); + japanese[BuildingType::Guardhouse] = DrawPoint(13, -18); + japanese[BuildingType::Watchtower] = DrawPoint(25, -12); + japanese[BuildingType::Fortress] = DrawPoint(22, -19); auto& romans = result[Nation::Romans]; - romans[BuildingType::Barracks] = DrawPoint(0, 8); - romans[BuildingType::Guardhouse] = DrawPoint(0, 8); - romans[BuildingType::Watchtower] = DrawPoint(19, -2); - romans[BuildingType::Fortress] = DrawPoint(0, 10); + romans[BuildingType::Barracks] = DrawPoint(15, -11); + romans[BuildingType::Guardhouse] = DrawPoint(14, -10); + romans[BuildingType::Watchtower] = DrawPoint(-19, 2); + romans[BuildingType::Fortress] = DrawPoint(20, -49); auto& vikings = result[Nation::Vikings]; - vikings[BuildingType::Barracks] = DrawPoint(-19, 10); - vikings[BuildingType::Guardhouse] = DrawPoint(-20, 7); - vikings[BuildingType::Watchtower] = DrawPoint(0, 11); - vikings[BuildingType::Fortress] = DrawPoint(-9, 3); + vikings[BuildingType::Barracks] = DrawPoint(14, -10); + vikings[BuildingType::Guardhouse] = DrawPoint(15, -7); + vikings[BuildingType::Watchtower] = DrawPoint(-7, -16); + vikings[BuildingType::Fortress] = DrawPoint(26, -13); auto& babylonians = result[Nation::Babylonians]; - babylonians[BuildingType::Barracks] = DrawPoint(14, 5); - babylonians[BuildingType::Guardhouse] = DrawPoint(0, -9); - babylonians[BuildingType::Watchtower] = DrawPoint(0, 13); - babylonians[BuildingType::Fortress] = DrawPoint(0, 24); + babylonians[BuildingType::Barracks] = DrawPoint(5, -11); + babylonians[BuildingType::Guardhouse] = DrawPoint(19, -11); + babylonians[BuildingType::Watchtower] = DrawPoint(5, -28); + babylonians[BuildingType::Fortress] = DrawPoint(20, -34); return result; }(); diff --git a/libs/s25main/gameData/BuildingConsts.h b/libs/s25main/gameData/BuildingConsts.h index 574df4c674..410b665ed2 100644 --- a/libs/s25main/gameData/BuildingConsts.h +++ b/libs/s25main/gameData/BuildingConsts.h @@ -107,7 +107,7 @@ constexpr helpers::MultiEnumArray SUPPRESS_UNUS {0, 0}, {14, -13}, {3, -17}, {0, -18}, {12, -10}, {16, 0}, {4, -16}, {-15, -11}, {-24, -9}, {0, 0}}}}}; /// Offset of the armor stop signs per building -extern const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_OFFSET_CONSTS; +extern const helpers::MultiEnumArray BUILDING_ARMOR_SIGN_CONSTS; /// Position der nubischen Feuer für alle 4 Bergwerke /// (Granit, Kohle, Eisen, Gold) From 592231abdbc3867e4cd795be086f835057c34356 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Wed, 11 Dec 2024 17:02:27 +0100 Subject: [PATCH 21/32] fixup! Adding ware workflow, buildings and menus for leather addon Change different offsets and animations --- data/RTTR/assets/base/leather_bobs.lst | Bin 196430 -> 196207 bytes libs/s25main/gameData/BuildingConsts.cpp | 2 +- libs/s25main/gameData/BuildingConsts.h | 4 ++-- libs/s25main/gameData/DoorConsts.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/data/RTTR/assets/base/leather_bobs.lst b/data/RTTR/assets/base/leather_bobs.lst index 4df82f2ad71d927b7af44c6114dcca8ac739deb6..2931658dc7b114c07ee82ba997ca7c31a0dca7a8 100644 GIT binary patch delta 1146 zcmb7DTSyd982_!(fh|n@a!UxH$f7TUL@}YT{^ABgf+kgJkIwb!Xlua=! z$|Zmh1S4!Urj}cqZ3@dNC2$+Y3Sc)|$!hRgZNnFBp)IviOn$eE;_=Ils zp&tYIjSw=EqcX2jlo)o20t#6W#UwJ5Bq0+y$ir6b!6BSLHLl?#bg>09`F^xlzm($AQjnIjg8pJl*e%nmvIF*n6?g& z*j+1Lu)8l1g~sP;mH;@M!QZ%^#jzG)6$-E&2T_hHT*Ot}LJb~rw5MpnD|W=tV(~q= zAk`dzTNwU@>zPPK7ILu;+i(D7IE(WE?FVRNcpEDRz>y+1G)yFhq>l0M^`9O_0t}P1 z;3YbSX`GYS|0leOBaDJ4i=xok>A@J?hlxB~#Z7+`8}MW_$#Qw^ID(!DLX0JN%@gA9 z#d0}iGI^DzcH*~i%dz9=CiZg+_n`M=oF7Z38Rhb#Amz@hZegY+k*1+^*U5P?{p1TQd!OVb!9j)p~~d z==ol9s=eN=>@H4V`I`2@hTJdp)#DCuIuo%hV=`5jm z(cNWH`#-lD_`A47idVb45{c~k-V9G;GX<$xU#l(T6w|giJ$z^}s`>X0T_*R`bWdBZ u6e79@qSgALLcdh4i%yeRdC4Ju493;{B+4Ulh>pwlip>V9+iZ|}fBgkPM>4kn delta 2071 zcmbuAYitx%6vzMP&TPA7A1!UOZKmB}`%wAfoA`hVAAGcy^noT~Fhpyj3HSjMUny;~ zmUQKVQE0BR31EVLLv0jCfF^uE*8NXr@7jX$!VNjS#sFDH!87u9UuNWKai?ReuW(DuXay*1) ztjF`%jMuOO@8M${f{P;<#P=A-X`ID*T);bA<6 z4R`@@Y{M?>#XjuEVf5h}jIi)2j`uuAt0no6t8zBUy}qX!3$j#=c~n=T9&51?FXB~f z$8NljPjHX}9`Gpq!~vhPIaurtNaR&PmIvMOc_y7*0P2nig7~@cX z!=JN~I@GT2%YHfN_sj2cm(7V-%q#!zh(E<=_!3`X2tPnae3thuE80PxKBcbG5p_+I(PnP#a)vziz3>8g~A+{hvTR^i` z*;`53BwRaTxSs7xD_f9j_owx>H|=()v@ldFkFr}XM5=>TRhw#MV!CQG5HstXldf@O zsvwiE^DR_Y?MeLNro}B3ig;BQ_A;PWP8KbRr#acraV3Fr zxj_|EDJ`L;bUW4XmR09ucGvI>Z#C~(HDBFI)12Mo3T2Us37(za?wGcQsb)ABSsd8c z95f$3hlLrRnRJKw6;2F2!RZm5xpTGe>$6Q?%FZzpL_8f;{C?j4=nc&uX(d*cS6rm{HNVn2* zUeC2MV&ql)W89nqdRXX!s^nbHDk!01{D86os)AX0ut`2!+z?kb-w!L>U{WTNTClV{ zE=7Co9>^ zLCEk#*omATG?IapJie< BUILDING_SMOKE_C vikings[BuildingType::DonkeyBreeder] = SmokeConst(4, {-27, -40}); vikings[BuildingType::Vineyard] = SmokeConst(1, {18, -48}); vikings[BuildingType::Winery] = SmokeConst(1, {-14, -32}); - vikings[BuildingType::Skinner] = SmokeConst(1, {7, -39}); + vikings[BuildingType::Skinner] = SmokeConst(1, {-7, -39}); vikings[BuildingType::Tannery] = SmokeConst(3, {-12, -46}); vikings[BuildingType::LeatherWorks] = SmokeConst(2, {-15, -37}); auto& babylonians = result[Nation::Babylonians]; diff --git a/libs/s25main/gameData/BuildingConsts.h b/libs/s25main/gameData/BuildingConsts.h index 410b665ed2..cc97bcb9d9 100644 --- a/libs/s25main/gameData/BuildingConsts.h +++ b/libs/s25main/gameData/BuildingConsts.h @@ -82,7 +82,7 @@ extern const helpers::MultiEnumArray BUILDING_ constexpr helpers::MultiEnumArray SUPPRESS_UNUSED BUILDING_SIGN_CONSTS = { {// Nubier {{{0, 0}, {19, -4}, {19, -3}, {-14, -1}, {23, -19}, {22, -7}, {-8, -10}, {9, -24}, {-16, -10}, {29, -23}, - {-2, -15}, {2, -13}, {-5, -16}, {-5, -15}, {0, 0}, {22, 6}, {0, 0}, {4, -16}, {9, -12}, {7, -10}, + {-2, -15}, {2, -13}, {-5, -16}, {-5, -15}, {0, 0}, {22, -6}, {0, 0}, {4, -16}, {9, -12}, {7, -10}, {28, -18}, {-6, -16}, {-3, -15}, {21, -11}, {14, -7}, {-14, -9}, {11, -9}, {-5, -24}, {-18, -34}, {0, 0}, {0, 0}, {3, -13}, {13, -13}, {-4, -20}, {7, -14}, {15, -4}, {0, 0}, {-22, -16}, {-14, -8}, {0, 0}}}, // Japaner @@ -102,7 +102,7 @@ constexpr helpers::MultiEnumArray SUPPRESS_UNUS {0, 0}, {-8, -2}, {-17, -4}, {28, -16}, {-1, 0}, {8, -9}, {16, -15}, {-2, -25}, {-29, -9}, {0, 0}}}, // Babylonier {{{0, 0}, {19, -6}, {19, -20}, {-7, -3}, {5, -15}, {-32, -20}, {4, -16}, {10, -18}, {3, -18}, {20, -10}, - {15, -10}, {15, -10}, {15, -10}, {15, -10}, {0, 0}, {5, -4}, {13, -5}, {-5, -13}, {15, -20}, {15, -1}, + {15, -10}, {15, -10}, {15, -10}, {15, -10}, {0, 0}, {15, -31}, {13, -5}, {-5, -13}, {15, -20}, {15, -1}, {11, -7}, {1, -22}, {7, -12}, {14, -16}, {21, -18}, {13, -11}, {5, -17}, {-2, -29}, {18, -20}, {0, 0}, {0, 0}, {14, -13}, {3, -17}, {0, -18}, {12, -10}, {16, 0}, {4, -16}, {-15, -11}, {-24, -9}, {0, 0}}}}}; diff --git a/libs/s25main/gameData/DoorConsts.h b/libs/s25main/gameData/DoorConsts.h index 9166a0c712..1f77fa4e35 100644 --- a/libs/s25main/gameData/DoorConsts.h +++ b/libs/s25main/gameData/DoorConsts.h @@ -18,8 +18,8 @@ constexpr helpers::MultiEnumArray DOOR_CONSTS = { {9, 1, 5, 9, 12, -6, 9, -4, 9, 7, 8, 8, 8, 8, 5, 13, 10, 9, 5, 3, 9, 10, 3, 12, 10, 13, 7, 0, -8, 14, 0, 11, 10, 9, 11, 0, 15, -7, -5, 16}, // Römer - {4, 6, 8, 11, 12, 8, 16, 4, 8, -3, 8, 8, 8, 8, 6, 12, 10, 12, 14, 12, - 9, 12, 12, 16, 19, 14, 16, 0, -8, 17, 0, 6, 9, 8, 14, 6, 4, -13, -8, 2}, + {4, 6, 8, 11, 12, 8, 16, 4, 8, -3, 8, 8, 8, 8, 6, 8, 10, 12, 14, 12, + 9, 12, 12, 16, 19, 14, 16, 0, -8, 17, 0, 6, 9, 8, 14, 6, 4, -13, -8, 2}, // Wikinger {10, 12, 11, 12, 11, -5, 9, 19, 17, 14, 9, 9, 9, 9, 4, 8, 10, 10, 10, 12, 12, 19, 11, 13, 6, 11, 14, 0, -3, 11, 0, 9, 11, 10, 16, 0, 16, -6, -2, 10}, From 1e7cea9fdf08cf9ac23c1e4f916bf157a1decb26 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Wed, 11 Dec 2024 17:06:28 +0100 Subject: [PATCH 22/32] fixup! LeatherAddon military (2): Add logic for armor in military building as for coins Invert upgrade order for armor. Now same as for gold --- libs/s25main/buildings/nobMilitary.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/s25main/buildings/nobMilitary.cpp b/libs/s25main/buildings/nobMilitary.cpp index c939409ecf..7608bce138 100644 --- a/libs/s25main/buildings/nobMilitary.cpp +++ b/libs/s25main/buildings/nobMilitary.cpp @@ -367,10 +367,10 @@ void nobMilitary::HandleEvent(const unsigned id) { armor_upgrade_event = nullptr; - auto canidate = std::find_if(troops.begin(), troops.end(), + auto canidate = std::find_if(troops.rbegin(), troops.rend(), [](OwnedSortedTroops::value_type& troop) { return !troop->HasArmor(); }); - if(canidate != troops.end()) + if(canidate != troops.rend()) { (*canidate)->SetArmor(true); From f5db3a7d2990b23829dbe47205f537bd042a850a Mon Sep 17 00:00:00 2001 From: Sunrise Date: Wed, 11 Dec 2024 18:37:18 +0100 Subject: [PATCH 23/32] fixup! Add fixed animations from leather_bobs.lst Use function for convertion and add invalid enum type --- libs/s25main/LeatherLoader.cpp | 18 +++++++++++++++--- libs/s25main/LeatherLoader.h | 4 +++- libs/s25main/Loader.cpp | 17 ++--------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/libs/s25main/LeatherLoader.cpp b/libs/s25main/LeatherLoader.cpp index c646864a79..7a083ee10e 100644 --- a/libs/s25main/LeatherLoader.cpp +++ b/libs/s25main/LeatherLoader.cpp @@ -29,9 +29,9 @@ bool isLeatherAddonJobType(Job job) return job == Job::Skinner || job == Job::Tanner || job == Job::LeatherWorker; } -helpers::EnumArray bobIndex = {0, 21, 69, 117, 125, 173, 221, 244, 292, 340, 388, - 436, 484, 532, 580, 628, 629, 630, 630, 631, 631, 632, - 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643}; +helpers::EnumArray bobIndex = {0, 0, 21, 69, 117, 125, 173, 221, 244, 292, 340, 388, + 436, 484, 532, 580, 628, 629, 630, 630, 631, 631, 632, 633, + 634, 635, 636, 637, 638, 639, 640, 641, 642, 643}; ITexture* GetWareTex(const GoodType good) { @@ -86,4 +86,16 @@ bool isAddonActive(const GameWorldBase& gwb) return gwb.GetGGS().isEnabled(AddonId::LEATHER); } +BobTypes wareToCarrierBobIndex(const GoodType good, const bool fat) +{ + switch(good) + { + default: return BobTypes::INVALID; + case GoodType::Skins: return fat ? BobTypes::FAT_CARRIER_CARRYING_SKINS : BobTypes::THIN_CARRIER_CARRYING_SKINS; + case GoodType::Leather: + return fat ? BobTypes::FAT_CARRIER_CARRYING_LEATHER : BobTypes::THIN_CARRIER_CARRYING_LEATHER; + case GoodType::Armor: return fat ? BobTypes::FAT_CARRIER_CARRYING_ARMOR : BobTypes::THIN_CARRIER_CARRYING_ARMOR; + } +} + } // namespace leatheraddon \ No newline at end of file diff --git a/libs/s25main/LeatherLoader.h b/libs/s25main/LeatherLoader.h index a921a48d9d..2cec4e8bbb 100644 --- a/libs/s25main/LeatherLoader.h +++ b/libs/s25main/LeatherLoader.h @@ -23,6 +23,7 @@ bool isLeatherAddonJobType(Job job); enum class BobTypes { + INVALID, SKINNER_SKINNING_ANIMAL_CARCASS_ANIMATION, SKINNER_WALKING, SKINNER_CARRYING_SKINS, @@ -55,7 +56,7 @@ enum class BobTypes ARMOR_WARE_ON_GROUND_OF_FLAG, DONKEY_BOAT_CARRYING_ARMOR_WARE, STOP_COINS_X_SIGN_OVERRIDE, - STOP_ARMOR_X_SIGN + STOP_ARMOR_X_SIGN, }; constexpr auto maxEnumValue(BobTypes) @@ -70,5 +71,6 @@ ITexture* GetWareStackTex(GoodType good); ITexture* GetWareDonkeyTex(GoodType good); ITexture* GetJobTex(Job job); bool isAddonActive(const GameWorldBase& gwb); +BobTypes wareToCarrierBobIndex(const GoodType good, const bool fat); } // namespace leatheraddon diff --git a/libs/s25main/Loader.cpp b/libs/s25main/Loader.cpp index 8c551c4bce..90fdcabfe4 100644 --- a/libs/s25main/Loader.cpp +++ b/libs/s25main/Loader.cpp @@ -922,21 +922,8 @@ void Loader::fillCaches() + static_cast(imgDir)))); } else if(leatheraddon::isLeatherAddonGoodType(ware)) { - leatheraddon::BobTypes carrierEnum = leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS; - if(ware == GoodType::Skins) - { - carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_SKINS : - leatheraddon::BobTypes::THIN_CARRIER_CARRYING_SKINS; - } else if(ware == GoodType::Leather) - { - carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_LEATHER : - leatheraddon::BobTypes::THIN_CARRIER_CARRYING_LEATHER; - } else if(ware == GoodType::Armor) - { - carrierEnum = fat ? leatheraddon::BobTypes::FAT_CARRIER_CARRYING_ARMOR : - leatheraddon::BobTypes::THIN_CARRIER_CARRYING_ARMOR; - } - + const auto carrierEnum = leatheraddon::wareToCarrierBobIndex(ware, fat); + RTTR_Assert(carrierEnum != leatheraddon::BobTypes::INVALID); const unsigned bodyIdx = static_cast(imgDir) * 8 + ani_step; bmp.add(dynamic_cast( leather_bob_carrier.get(leatheraddon::bobIndex[carrierEnum] + bodyIdx))); From de070299bbb75253775e5bef7accb2595aa5d24a Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sat, 14 Dec 2024 14:12:39 +0100 Subject: [PATCH 24/32] fixup! Adding ware workflow, buildings and menus for leather addon Refactor credits for more readable code --- libs/s25main/desktops/dskCredits.cpp | 55 ++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/libs/s25main/desktops/dskCredits.cpp b/libs/s25main/desktops/dskCredits.cpp index 46438a5bce..2e484c94d6 100644 --- a/libs/s25main/desktops/dskCredits.cpp +++ b/libs/s25main/desktops/dskCredits.cpp @@ -359,7 +359,7 @@ void dskCredits::DrawCredit() template T randEnum() { - return T(rand() % (helpers::NumEnumValues_v - 5)); + return T(rand() % (helpers::NumEnumValues_v)); } void dskCredits::DrawBobs() @@ -397,26 +397,51 @@ void dskCredits::DrawBobs() } b.color = PLAYER_COLORS[rand() % PLAYER_COLORS.size()]; - const auto job = randEnum(); - // exclude "headless" bobs - if(job == Job::Miller || job == Job::Baker || job == Job::Brewer || job == Job::Armorer - || job == Job::CharBurner /* Comes from another file */ || wineaddon::isWineAddonJobType(job) - || leatheraddon::isLeatherAddonJobType(job)) - { - const auto ware = randEnum(); - // Japanese shield is missing - b.id = rttr::enum_cast((ware == GoodType::ShieldJapanese) ? GoodType::ShieldRomans : ware); - b.hasWare = true; - } else + auto isHeadlessBob = [](Job const& job) { + return job == Job::Miller || job == Job::Baker || job == Job::Brewer || job == Job::Armorer; + }; + + auto isJobDrawable = [&isHeadlessBob](Job const& job) { + if(job == Job::CharBurner) + return false; + else if(wineaddon::isWineAddonJobType(job)) + return false; + else if(leatheraddon::isLeatherAddonJobType(job)) + return false; + else if(isHeadlessBob(job)) + return false; + return true; + }; + + auto isWareDrawable = [](GoodType const& ware) { + if(wineaddon::isWineAddonGoodType(ware)) + return false; + else if(leatheraddon::isLeatherAddonGoodType(ware)) + return false; + return true; + }; + + const auto job = randEnum(); + if(isJobDrawable(job)) { // only native nations are loaded b.id = JOB_SPRITE_CONSTS[job].getBobId(Nation(rand() % NUM_NATIVE_NATIONS)); b.hasWare = false; + b.pos.y = GetCtrl(0)->GetPos().y - 20 - rand() % 150; + bobs.push_back(b); + } else + { + const auto ware = randEnum(); + if(isWareDrawable(ware)) + { + // Japanese shield is missing + b.id = rttr::enum_cast((ware == GoodType::ShieldJapanese) ? GoodType::ShieldRomans : ware); + b.hasWare = true; + b.pos.y = GetCtrl(0)->GetPos().y - 20 - rand() % 150; + bobs.push_back(b); + } } - - b.pos.y = GetCtrl(0)->GetPos().y - 20 - rand() % 150; - bobs.push_back(b); } // draw bobs From 8d77cd302673862f69ac242ee3ff334c53857b65 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sat, 14 Dec 2024 14:15:21 +0100 Subject: [PATCH 25/32] fixup! Add fixed animations from leather_bobs.lst Fix clang tidy --- libs/s25main/LeatherLoader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/s25main/LeatherLoader.h b/libs/s25main/LeatherLoader.h index 2cec4e8bbb..fb85593fc2 100644 --- a/libs/s25main/LeatherLoader.h +++ b/libs/s25main/LeatherLoader.h @@ -71,6 +71,6 @@ ITexture* GetWareStackTex(GoodType good); ITexture* GetWareDonkeyTex(GoodType good); ITexture* GetJobTex(Job job); bool isAddonActive(const GameWorldBase& gwb); -BobTypes wareToCarrierBobIndex(const GoodType good, const bool fat); +BobTypes wareToCarrierBobIndex(GoodType good, bool fat); } // namespace leatheraddon From 1b8743f1a14fc5c4efb563dd905c976a854492f0 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sat, 14 Dec 2024 14:32:52 +0100 Subject: [PATCH 26/32] fixup! Adding ware workflow, buildings and menus for leather addon Use enums for buttons and add buttons without offsets first --- libs/s25main/ingameWindows/iwBuildings.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libs/s25main/ingameWindows/iwBuildings.cpp b/libs/s25main/ingameWindows/iwBuildings.cpp index 83f958d796..34e463b785 100644 --- a/libs/s25main/ingameWindows/iwBuildings.cpp +++ b/libs/s25main/ingameWindows/iwBuildings.cpp @@ -69,6 +69,14 @@ const Extent iconSpacing(40, 48); // Abstand der Schriften unter den Icons const unsigned short font_distance_y = 20; +namespace { +enum +{ + ID_Help, + ID_BuildingsStart, +}; +} + iwBuildings::iwBuildings(GameWorldView& gwv, GameCommandFactory& gcFactory) : IngameWindow(CGI_BUILDINGS, IngameWindow::posLastOrCenter, Extent(185, 480), _("Buildings"), LOADER.GetImageN("resource", 41)), @@ -88,14 +96,14 @@ iwBuildings::iwBuildings(GameWorldView& gwv, GameCommandFactory& gcFactory) Extent btSize = Extent(32, 32); DrawPoint btPos = bldContentOffset - btSize / 2 + iconSpacing * DrawPoint(x, y); - AddImageButton(y * 4 + x, btPos, btSize, TextureColor::Grey, + AddImageButton(ID_BuildingsStart + y * 4 + x, btPos, btSize, TextureColor::Grey, LOADER.GetNationIcon(playerNation, bts[y * 4 + x]), _(BUILDING_NAMES[bts[y * 4 + x]])); } } // "Help" button Extent btSize = Extent(30, 32); - AddImageButton(38, GetFullSize() - DrawPoint(14, 20) - btSize, btSize, TextureColor::Grey, + AddImageButton(ID_Help, GetFullSize() - DrawPoint(14, 20) - btSize, btSize, TextureColor::Grey, LOADER.GetImageN("io", 225), _("Help")); } @@ -127,7 +135,7 @@ void iwBuildings::Msg_PaintAfter() void iwBuildings::Msg_ButtonClick(const unsigned ctrl_id) { - if(ctrl_id == 38) // Help button + if(ctrl_id == ID_Help) // Help button { WINDOWMANAGER.ReplaceWindow( std::make_unique(_("The building statistics window gives you an insight into " @@ -142,7 +150,7 @@ void iwBuildings::Msg_ButtonClick(const unsigned ctrl_id) const GamePlayer& localPlayer = gwv.GetViewer().GetPlayer(); const BuildingRegister& buildingRegister = localPlayer.GetBuildingRegister(); - BuildingType bldType = bts[ctrl_id]; + BuildingType bldType = bts[ctrl_id - ID_BuildingsStart]; if(BuildingProperties::IsMilitary(bldType)) GoToFirstMatching(bldType, buildingRegister.GetMilitaryBuildings()); else if(bldType == BuildingType::HarborBuilding) From ccc57024e156425f45a86384b1b7373d8d47eeed Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 19:10:09 +0100 Subject: [PATCH 27/32] Add new transportation type leatherworking and compatibility code for save game and replays --- libs/s25main/GameCommand.cpp | 2 +- libs/s25main/GameCommands.cpp | 22 +++++++ libs/s25main/GameCommands.h | 2 +- libs/s25main/GamePlayer.cpp | 2 + libs/s25main/gameData/SettingTypeConv.cpp | 6 +- libs/s25main/gameTypes/SettingsTypes.h | 2 +- libs/s25main/ingameWindows/iwTransport.cpp | 76 ++++++++++++++++------ libs/s25main/ingameWindows/iwTransport.h | 7 +- 8 files changed, 91 insertions(+), 28 deletions(-) diff --git a/libs/s25main/GameCommand.cpp b/libs/s25main/GameCommand.cpp index 8d2fa939e5..c30c8457a9 100644 --- a/libs/s25main/GameCommand.cpp +++ b/libs/s25main/GameCommand.cpp @@ -13,7 +13,7 @@ namespace gc { unsigned Deserializer::getCurrentVersion() { // 1: Add wine addon --> 3 new values in distribution - // 2: Add leather addon --> 3 new values in distribution + // 2: Add leather addon --> 3 new values in distribution, 1 new value in transport order and transport order default values changed return 2; } diff --git a/libs/s25main/GameCommands.cpp b/libs/s25main/GameCommands.cpp index 15ca14f66b..18a3a7a877 100644 --- a/libs/s25main/GameCommands.cpp +++ b/libs/s25main/GameCommands.cpp @@ -17,6 +17,7 @@ #include "world/GameWorld.h" #include "nodeObjs/noFlag.h" #include "nodeObjs/noShip.h" +#include "gameData/SettingTypeConv.h" #include #include @@ -153,6 +154,27 @@ void DestroyBuilding::Execute(GameWorld& world, uint8_t playerId) world.DestroyBuilding(pt_, playerId); } +ChangeTransport::ChangeTransport(Deserializer& ser) : GameCommand(GCType::ChangeTransport) +{ + if(ser.getDataVersion() >= 2) + helpers::popContainer(ser, data); + else + { + const unsigned leatherAddonAdditionalTransportOrders = 1; + std::vector tmpData(std::tuple_size::value + - leatherAddonAdditionalTransportOrders); + + helpers::popContainer(ser, tmpData, true); + std::copy(tmpData.begin(), tmpData.end(), data.begin()); + // all transport prios greater equal 7 are increased by one because the new leatherwork + // uses prio 7 + std::transform(data.begin(), data.end() - leatherAddonAdditionalTransportOrders, data.begin(), + [](uint8_t& prio) { return prio < 7 ? prio : prio + 1; }); + data[std::tuple_size::value - leatherAddonAdditionalTransportOrders] = + STD_TRANSPORT_PRIO[GoodType::Leather]; + } +} + void ChangeTransport::Execute(GameWorld& world, uint8_t playerId) { world.GetPlayer(playerId).ConvertTransportData(data); diff --git a/libs/s25main/GameCommands.h b/libs/s25main/GameCommands.h index 87e8e0c155..7234df0f66 100644 --- a/libs/s25main/GameCommands.h +++ b/libs/s25main/GameCommands.h @@ -248,7 +248,7 @@ class ChangeTransport : public GameCommand protected: ChangeTransport(const TransportOrders& data) : GameCommand(GCType::ChangeTransport), data(data) {} - ChangeTransport(Serializer& ser) : GameCommand(GCType::ChangeTransport) { helpers::popContainer(ser, data); } + ChangeTransport(Deserializer& ser); public: void Serialize(Serializer& ser) const override diff --git a/libs/s25main/GamePlayer.cpp b/libs/s25main/GamePlayer.cpp index efdc101a6b..67d47a3a6f 100644 --- a/libs/s25main/GamePlayer.cpp +++ b/libs/s25main/GamePlayer.cpp @@ -315,6 +315,8 @@ void GamePlayer::Deserialize(SerializedGameData& sgd) std::vector transportPrio_raw(transportPrio.size() - countOfNotAvailableGoodsInSaveGame); helpers::popContainer(sgd, transportPrio_raw, true); std::copy(transportPrio_raw.begin(), transportPrio_raw.end(), transportPrio.begin()); + std::transform(transportPrio.begin(), transportPrio.end() - countOfNotAvailableGoodsInSaveGame, + transportPrio.begin(), [](uint8_t& prio) { return prio < 7 ? prio : prio + 1; }); } else { helpers::popContainer(sgd, build_order); diff --git a/libs/s25main/gameData/SettingTypeConv.cpp b/libs/s25main/gameData/SettingTypeConv.cpp index 9f118b2b6e..6fef129a09 100644 --- a/libs/s25main/gameData/SettingTypeConv.cpp +++ b/libs/s25main/gameData/SettingTypeConv.cpp @@ -10,9 +10,9 @@ /// Max value for each setting. /// Note: We skip the first 2 steppings for the occupation (last 4 values) as they had no effect in S2 const MilitarySettings SUPPRESS_UNUSED MILITARY_SETTINGS_SCALE = {{10, 5, 5, 5, 8, 8, 8, 8}}; -const TransportPriorities STD_TRANSPORT_PRIO = {{2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, - 12, 13, 1, 3, 11, 11, 11, 1, 9, 7, 8, 1, 1, 11, - 0, 4, 5, 6, 11, 11, 1, 11, 11, 12, 12, 12}}; +const TransportPriorities STD_TRANSPORT_PRIO = {{2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 11, 11, 13, 13, + 13, 14, 1, 3, 12, 12, 12, 1, 10, 8, 9, 1, 1, 12, + 0, 4, 5, 6, 12, 12, 1, 12, 12, 7, 7, 1}}; unsigned GetTransportPrioFromOrdering(const TransportOrders& ordering, GoodType good) { diff --git a/libs/s25main/gameTypes/SettingsTypes.h b/libs/s25main/gameTypes/SettingsTypes.h index 6bb34c5e14..6170e96866 100644 --- a/libs/s25main/gameTypes/SettingsTypes.h +++ b/libs/s25main/gameTypes/SettingsTypes.h @@ -25,7 +25,7 @@ using BuildOrders = std::array standard transport priority of ware(group): /// E.g. std prio of coins = 0 -> TransportOrders[0] = stdPrio[COINS] = 0 /// New prio of coins = 1 -> TransportOrders[1] = stdPrio[COINS] = 0 -using TransportOrders = std::array; +using TransportOrders = std::array; using TransportPriorities = helpers::EnumArray; /// Priority of each tool using ToolSettings = helpers::EnumArray; diff --git a/libs/s25main/ingameWindows/iwTransport.cpp b/libs/s25main/ingameWindows/iwTransport.cpp index aaf2d54eff..83f0e0adc9 100644 --- a/libs/s25main/ingameWindows/iwTransport.cpp +++ b/libs/s25main/ingameWindows/iwTransport.cpp @@ -5,34 +5,60 @@ #include "iwTransport.h" #include "DrawPoint.h" #include "GamePlayer.h" +#include "LeatherLoader.h" #include "Loader.h" #include "WindowManager.h" #include "controls/ctrlImageButton.h" #include "controls/ctrlOptionGroup.h" +#include "helpers/containerUtils.h" #include "iwHelp.h" #include "network/GameClient.h" #include "world/GameWorldViewer.h" #include "gameData/GoodConsts.h" +#include "gameData/SettingTypeConv.h" #include "gameData/const_gui_ids.h" +void iwTransport::fillTransportOrder(const TransportOrders& transport_order) +{ + pendingOrder.assign(transport_order.begin(), transport_order.end()); + + auto isUnused = [&](uint8_t const& stdTransportPrio) { + if(!leatheraddon::isAddonActive(gwv.GetWorld()) && stdTransportPrio == STD_TRANSPORT_PRIO[GoodType::Leather]) + return true; + return false; + }; + helpers::erase_if(pendingOrder, isUnused); +} + iwTransport::iwTransport(const GameWorldViewer& gwv, GameCommandFactory& gcFactory) : TransmitSettingsIgwAdapter(CGI_TRANSPORT, IngameWindow::posLastOrCenter, Extent(166, 333), _("Transport"), LOADER.GetImageN("io", 5)), gwv(gwv), gcFactory(gcFactory) { - AddImageButton(0, DrawPoint(18, 285), Extent(30, 30), TextureColor::Grey, LOADER.GetImageN("io", 225), _("Help")); + unsigned btOffsetY = 0; + if(leatheraddon::isAddonActive(gwv.GetWorld())) + { + btOffsetY = 17; + Resize(Extent(166, 333 + btOffsetY)); + } + + AddImageButton(0, DrawPoint(18, 285 + btOffsetY), Extent(30, 30), TextureColor::Grey, LOADER.GetImageN("io", 225), + _("Help")); // Standard - AddImageButton(1, DrawPoint(60, 285), Extent(48, 30), TextureColor::Grey, LOADER.GetImageN("io", 191), + AddImageButton(1, DrawPoint(60, 285 + btOffsetY), Extent(48, 30), TextureColor::Grey, LOADER.GetImageN("io", 191), _("Default")); // ganz hoch - AddImageButton(2, DrawPoint(118, 235), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 215), _("Top")); + AddImageButton(2, DrawPoint(118, 235 + btOffsetY), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 215), + _("Top")); // hoch - AddImageButton(3, DrawPoint(118, 255), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 33), _("Up")); + AddImageButton(3, DrawPoint(118, 255 + btOffsetY), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 33), + _("Up")); // runter - AddImageButton(4, DrawPoint(118, 275), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 34), _("Down")); + AddImageButton(4, DrawPoint(118, 275 + btOffsetY), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 34), + _("Down")); // ganz runter - AddImageButton(5, DrawPoint(118, 295), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 216), + AddImageButton(5, DrawPoint(118, 295 + btOffsetY), Extent(30, 20), TextureColor::Grey, LOADER.GetImageN("io", 216), _("Bottom")); // Buttons der einzelnen Waren anlegen @@ -46,6 +72,7 @@ iwTransport::iwTransport(const GameWorldViewer& gwv, GameCommandFactory& gcFacto {getGoodTex(GoodType::Gold), WARE_NAMES[GoodType::Gold]}, {getGoodTex(GoodType::IronOre), WARE_NAMES[GoodType::IronOre]}, {getGoodTex(GoodType::Coal), WARE_NAMES[GoodType::Coal]}, + {getGoodTex(GoodType::Leather), gettext_noop("Leatherworking")}, {getGoodTex(GoodType::Boards), WARE_NAMES[GoodType::Boards]}, {getGoodTex(GoodType::Stones), WARE_NAMES[GoodType::Stones]}, {getGoodTex(GoodType::Wood), WARE_NAMES[GoodType::Wood]}, @@ -53,6 +80,7 @@ iwTransport::iwTransport(const GameWorldViewer& gwv, GameCommandFactory& gcFacto {LOADER.GetTextureN("io", 80), gettext_noop("Food")}, {getGoodTex(GoodType::Hammer), gettext_noop("Tools")}, {getGoodTex(GoodType::Boat), WARE_NAMES[GoodType::Boat]}}}; + // Positionen der einzelnen Buttons const std::array BUTTON_POS = {{{20, 25}, {52, 42}, @@ -67,13 +95,14 @@ iwTransport::iwTransport(const GameWorldViewer& gwv, GameCommandFactory& gcFacto {84, 195}, {52, 212}, {20, 229}, - {52, 246}}}; + {52, 246}, + {84, 263}}}; // Get current transport order - pendingOrder = GAMECLIENT.visual_settings.transport_order; + fillTransportOrder(GAMECLIENT.visual_settings.transport_order); // Einstellungen festlegen - for(unsigned char i = 0; i < buttonData.size(); ++i) + for(unsigned char i = 0; i < pendingOrder.size(); ++i) { group->AddImageButton(i, BUTTON_POS[i], Extent(30, 30), TextureColor::Grey, buttonData[pendingOrder[i]].sprite, _(buttonData[pendingOrder[i]].tooltip)); @@ -87,10 +116,20 @@ void iwTransport::TransmitSettings() return; if(settings_changed) { + TransportOrders transmitPendingTransportOrder; + unsigned int i = 0; + for(; i < pendingOrder.size(); i++) + transmitPendingTransportOrder[i] = pendingOrder[i]; + + if(!leatheraddon::isAddonActive(gwv.GetWorld())) + { + transmitPendingTransportOrder[i++] = STD_TRANSPORT_PRIO[GoodType::Leather]; + } + // Daten übertragen - if(gcFactory.ChangeTransport(pendingOrder)) + if(gcFactory.ChangeTransport(transmitPendingTransportOrder)) { - GAMECLIENT.visual_settings.transport_order = pendingOrder; + GAMECLIENT.visual_settings.transport_order = transmitPendingTransportOrder; settings_changed = false; } } @@ -114,11 +153,10 @@ void iwTransport::Msg_ButtonClick(const unsigned ctrl_id) { auto* group = GetCtrl(6); - pendingOrder = GAMECLIENT.default_settings.transport_order; - - for(unsigned char i = 0; i < buttonData.size(); ++i) + fillTransportOrder(GAMECLIENT.default_settings.transport_order); + for(unsigned char i = 0; i < pendingOrder.size(); ++i) { - const auto& data = buttonData[i]; + const auto& data = buttonData[pendingOrder[i]]; group->GetCtrl(i)->SetImage(data.sprite); group->GetCtrl(i)->SetTooltip(_(data.tooltip)); } @@ -167,7 +205,7 @@ void iwTransport::Msg_ButtonClick(const unsigned ctrl_id) auto* group = GetCtrl(6); // Wenn wir schon ganz unten sind, gehts nicht weiter runter - if(group->GetSelection() < 13) + if(group->GetSelection() < (pendingOrder.size() - 1)) { std::swap(pendingOrder[group->GetSelection()], pendingOrder[group->GetSelection() + 1]); ctrlImageButton& btPrev = *group->GetCtrl(group->GetSelection()); @@ -185,7 +223,7 @@ void iwTransport::Msg_ButtonClick(const unsigned ctrl_id) auto* group = GetCtrl(6); // Wenn wir schon ganz unten sind, gehts nicht weiter runter - while(group->GetSelection() < 13) + while(group->GetSelection() < (pendingOrder.size() - 1)) { std::swap(pendingOrder[group->GetSelection()], pendingOrder[group->GetSelection() + 1]); ctrlImageButton& btPrev = *group->GetCtrl(group->GetSelection()); @@ -206,12 +244,12 @@ void iwTransport::UpdateSettings() if(GAMECLIENT.IsReplayModeOn()) { gwv.GetPlayer().FillVisualSettings(GAMECLIENT.visual_settings); - pendingOrder = GAMECLIENT.visual_settings.transport_order; + fillTransportOrder(GAMECLIENT.visual_settings.transport_order); } auto* group = GetCtrl(6); // Einstellungen festlegen - for(unsigned char i = 0; i < buttonData.size(); ++i) + for(unsigned char i = 0; i < pendingOrder.size(); ++i) { const auto& data = buttonData[pendingOrder[i]]; group->GetCtrl(i)->SetImage(data.sprite); diff --git a/libs/s25main/ingameWindows/iwTransport.h b/libs/s25main/ingameWindows/iwTransport.h index be8a252de3..1c4e990d5a 100644 --- a/libs/s25main/ingameWindows/iwTransport.h +++ b/libs/s25main/ingameWindows/iwTransport.h @@ -6,7 +6,7 @@ #include "TransmitSettingsIgwAdapter.h" #include "gameTypes/SettingsTypes.h" -#include +#include class ITexture; class GameWorldViewer; @@ -25,8 +25,7 @@ class iwTransport final : public TransmitSettingsIgwAdapter static constexpr auto numButtons = std::tuple_size::value; std::array buttonData; - - TransportOrders pendingOrder; + std::vector pendingOrder; public: iwTransport(const GameWorldViewer& gwv, GameCommandFactory& gcFactory); @@ -38,4 +37,6 @@ class iwTransport final : public TransmitSettingsIgwAdapter void TransmitSettings() override; void Msg_ButtonClick(unsigned ctrl_id) override; + + void fillTransportOrder(const TransportOrders& transport_order); }; From 24d46daab5dca932b0e72ddcdd793f8d2048552c Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 19:11:54 +0100 Subject: [PATCH 28/32] Fix wrong default build order --- libs/s25main/ingameWindows/iwBuildOrder.cpp | 11 +++++------ libs/s25main/ingameWindows/iwBuildOrder.h | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/s25main/ingameWindows/iwBuildOrder.cpp b/libs/s25main/ingameWindows/iwBuildOrder.cpp index 6b09ecca99..b35654db88 100644 --- a/libs/s25main/ingameWindows/iwBuildOrder.cpp +++ b/libs/s25main/ingameWindows/iwBuildOrder.cpp @@ -19,10 +19,9 @@ #include "gameData/BuildingConsts.h" #include "gameData/const_gui_ids.h" -void iwBuildOrder::fillBuildOrder() +void iwBuildOrder::fillBuildOrder(const BuildOrders& build_order) { - pendingBuildOrder.assign(GAMECLIENT.visual_settings.build_order.begin(), - GAMECLIENT.visual_settings.build_order.end()); + pendingBuildOrder.assign(build_order.begin(), build_order.end()); auto isUnused = [&](BuildingType const& bld) { if(!wineaddon::isAddonActive(gwv.GetWorld()) && wineaddon::isWineAddonBuildingType(bld)) @@ -43,7 +42,7 @@ iwBuildOrder::iwBuildOrder(const GameWorldViewer& gwv) { ctrlList* list = AddList(0, DrawPoint(15, 60), Extent(150, 220), TextureColor::Grey, NormalFont); - fillBuildOrder(); + fillBuildOrder(GAMECLIENT.visual_settings.build_order); for(const auto buildOrder : pendingBuildOrder) list->AddString(_(BUILDING_NAMES[buildOrder])); //-V807 @@ -205,7 +204,7 @@ void iwBuildOrder::Msg_ButtonClick(const unsigned ctrl_id) case 10: // Standardwerte { // Baureihenfolge vom Spieler kopieren - fillBuildOrder(); + fillBuildOrder(GAMECLIENT.default_settings.build_order); auto* list = GetCtrl(0); list->DeleteAllItems(); @@ -228,7 +227,7 @@ void iwBuildOrder::UpdateSettings() if(GAMECLIENT.IsReplayModeOn()) { gwv.GetPlayer().FillVisualSettings(GAMECLIENT.visual_settings); - fillBuildOrder(); + fillBuildOrder(GAMECLIENT.visual_settings.build_order); useCustomBuildOrder = GAMECLIENT.visual_settings.useCustomBuildOrder; } GetCtrl(6)->SetSelection(useCustomBuildOrder ? 1 : 0); diff --git a/libs/s25main/ingameWindows/iwBuildOrder.h b/libs/s25main/ingameWindows/iwBuildOrder.h index 1e6fcab134..c2a338acb4 100644 --- a/libs/s25main/ingameWindows/iwBuildOrder.h +++ b/libs/s25main/ingameWindows/iwBuildOrder.h @@ -5,6 +5,7 @@ #pragma once #include "TransmitSettingsIgwAdapter.h" +#include "gameTypes/SettingsTypes.h" #include class GameWorldViewer; @@ -29,5 +30,5 @@ class iwBuildOrder final : public TransmitSettingsIgwAdapter void Msg_ButtonClick(unsigned ctrl_id) override; void Msg_ComboSelectItem(unsigned ctrl_id, unsigned selection) override; - void fillBuildOrder(); + void fillBuildOrder(const BuildOrders& build_order); }; From 61152b6fde9f8418ee4b4a796e8414fe83b2d3c7 Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 19:16:14 +0100 Subject: [PATCH 29/32] fixup! Add new transportation type leatherworking and compatibility code for save game and replays Formatting --- libs/s25main/GameCommand.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/s25main/GameCommand.cpp b/libs/s25main/GameCommand.cpp index c30c8457a9..0768f62528 100644 --- a/libs/s25main/GameCommand.cpp +++ b/libs/s25main/GameCommand.cpp @@ -13,7 +13,8 @@ namespace gc { unsigned Deserializer::getCurrentVersion() { // 1: Add wine addon --> 3 new values in distribution - // 2: Add leather addon --> 3 new values in distribution, 1 new value in transport order and transport order default values changed + // 2: Add leather addon --> 3 new values in distribution, 1 new value in transport order and transport order default + // values changed return 2; } From dbb9e25c901ae07a42801ae6dd055a4494b9e1cb Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 19:21:49 +0100 Subject: [PATCH 30/32] fixup! Adding ware workflow, buildings and menus for leather addon Clang tidy --- libs/s25main/desktops/dskCredits.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/s25main/desktops/dskCredits.cpp b/libs/s25main/desktops/dskCredits.cpp index 2e484c94d6..8d75e18c55 100644 --- a/libs/s25main/desktops/dskCredits.cpp +++ b/libs/s25main/desktops/dskCredits.cpp @@ -405,11 +405,11 @@ void dskCredits::DrawBobs() auto isJobDrawable = [&isHeadlessBob](Job const& job) { if(job == Job::CharBurner) return false; - else if(wineaddon::isWineAddonJobType(job)) + if(wineaddon::isWineAddonJobType(job)) return false; - else if(leatheraddon::isLeatherAddonJobType(job)) + if(leatheraddon::isLeatherAddonJobType(job)) return false; - else if(isHeadlessBob(job)) + if(isHeadlessBob(job)) return false; return true; }; @@ -417,7 +417,7 @@ void dskCredits::DrawBobs() auto isWareDrawable = [](GoodType const& ware) { if(wineaddon::isWineAddonGoodType(ware)) return false; - else if(leatheraddon::isLeatherAddonGoodType(ware)) + if(leatheraddon::isLeatherAddonGoodType(ware)) return false; return true; }; From 1d3e96acf54cc8bc8c6ff0f37deb2570005ed8de Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 20:06:05 +0100 Subject: [PATCH 31/32] fixup! Add new transportation type leatherworking and compatibility code for save game and replays Clang tidy --- libs/s25main/ingameWindows/iwTransport.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/s25main/ingameWindows/iwTransport.cpp b/libs/s25main/ingameWindows/iwTransport.cpp index 83f0e0adc9..43e4be9cec 100644 --- a/libs/s25main/ingameWindows/iwTransport.cpp +++ b/libs/s25main/ingameWindows/iwTransport.cpp @@ -23,9 +23,8 @@ void iwTransport::fillTransportOrder(const TransportOrders& transport_order) pendingOrder.assign(transport_order.begin(), transport_order.end()); auto isUnused = [&](uint8_t const& stdTransportPrio) { - if(!leatheraddon::isAddonActive(gwv.GetWorld()) && stdTransportPrio == STD_TRANSPORT_PRIO[GoodType::Leather]) - return true; - return false; + return !leatheraddon::isAddonActive(gwv.GetWorld()) + && stdTransportPrio == STD_TRANSPORT_PRIO[GoodType::Leather]; }; helpers::erase_if(pendingOrder, isUnused); } From 28693f7b0b6f7ed9698ed9dac45070d0d94ebbaf Mon Sep 17 00:00:00 2001 From: Sunrise Date: Sun, 19 Jan 2025 20:08:16 +0100 Subject: [PATCH 32/32] Solider has 30 percent chance to not die if he has an armor and is hit by a catapult (losing his armor) --- libs/s25main/buildings/nobMilitary.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libs/s25main/buildings/nobMilitary.cpp b/libs/s25main/buildings/nobMilitary.cpp index 7608bce138..f9de98064a 100644 --- a/libs/s25main/buildings/nobMilitary.cpp +++ b/libs/s25main/buildings/nobMilitary.cpp @@ -1444,12 +1444,18 @@ void nobMilitary::HitOfCatapultStone() // Ein Soldat weniger, falls es noch welche gibt if(!troops.empty()) { - std::unique_ptr soldier = std::move(*troops.begin()); - helpers::pop_front(troops); - // Shortcut for Die(): No need to remove from world as it is inside and we can delete it right away - soldier->RemoveFromInventory(); - soldier->LeftBuilding(); - soldier->Destroy(); + // 30 percent chance to not die if the soldier has an armor + bool die = !(*troops.begin())->HasArmor() || (RANDOM_RAND(99) < 70); + if(die) + { + std::unique_ptr soldier = std::move(*troops.begin()); + helpers::pop_front(troops); + // Shortcut for Die(): No need to remove from world as it is inside and we can delete it right away + soldier->RemoveFromInventory(); + soldier->LeftBuilding(); + soldier->Destroy(); + } else + (*troops.begin())->SetArmor(false); } // If there are troops left, order some more, else this will be destroyed