From daf89a01ff88c7771f0c252808de2b3eede23927 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 4 Nov 2007 00:19:41 +0000 Subject: [PATCH] added skins, tweaked prediction like hell --- data/skins/bluekitty.png | Bin 0 -> 5810 bytes data/skins/bluestripe.png | Bin 0 -> 5482 bytes data/skins/brownbear.png | Bin 0 -> 5546 bytes data/skins/cammo.png | Bin 0 -> 5863 bytes data/skins/cammostripes.png | Bin 0 -> 5314 bytes data/skins/coala.png | Bin 0 -> 5674 bytes data/skins/limekitty.png | Bin 0 -> 5754 bytes data/skins/ninja.png | Bin 0 -> 4615 bytes data/skins/pinky.png | Bin 0 -> 5199 bytes data/skins/redbopp.png | Bin 0 -> 5426 bytes data/skins/redstripe.png | Bin 0 -> 5343 bytes data/skins/saddo.png | Bin 0 -> 5551 bytes data/skins/toptri.png | Bin 0 -> 5152 bytes data/skins/twinbop.png | Bin 0 -> 5634 bytes data/skins/twintri.png | Bin 0 -> 5233 bytes data/skins/warpaint.png | Bin 0 -> 5181 bytes datasrc/teewars.ds | 25 +-- src/engine/client/client.c | 51 ++++-- src/engine/client/gfx.c | 4 +- src/engine/config_variables.h | 2 + src/engine/interface.h | 7 + src/engine/protocol.h | 24 +++ src/engine/server/server.c | 32 +++- src/game/client/game_client.cpp | 274 +++++++++++++++++++++++--------- src/game/client/menu.cpp | 9 +- src/game/game_protocol.h | 12 +- src/game/game_variables.h | 3 + src/game/server/game_server.cpp | 119 ++++++++------ src/game/server/srv_common.cpp | 1 + src/game/server/srv_common.h | 7 +- src/game/server/srv_ctf.cpp | 2 + src/game/server/srv_tdm.cpp | 5 + src/game/server/srv_tdm.h | 1 + src/tools/crapnet.cpp | 4 +- 34 files changed, 419 insertions(+), 163 deletions(-) create mode 100644 data/skins/bluekitty.png create mode 100644 data/skins/bluestripe.png create mode 100644 data/skins/brownbear.png create mode 100644 data/skins/cammo.png create mode 100644 data/skins/cammostripes.png create mode 100644 data/skins/coala.png create mode 100644 data/skins/limekitty.png create mode 100644 data/skins/ninja.png create mode 100644 data/skins/pinky.png create mode 100644 data/skins/redbopp.png create mode 100644 data/skins/redstripe.png create mode 100644 data/skins/saddo.png create mode 100644 data/skins/toptri.png create mode 100644 data/skins/twinbop.png create mode 100644 data/skins/twintri.png create mode 100644 data/skins/warpaint.png diff --git a/data/skins/bluekitty.png b/data/skins/bluekitty.png new file mode 100644 index 0000000000000000000000000000000000000000..dbb4d508a6183b1a47482f8b4b99a3a0eadc1453 GIT binary patch literal 5810 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 literal 0 HcmV?d00001 diff --git a/data/skins/cammo.png b/data/skins/cammo.png new file mode 100644 index 0000000000000000000000000000000000000000..83b4a79500e558f4777cf6e582a695477d3f5365 GIT binary patch literal 5863 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 literal 0 HcmV?d00001 diff --git a/data/skins/cammostripes.png b/data/skins/cammostripes.png new file mode 100644 index 0000000000000000000000000000000000000000..3e2cd14713a0821e70b3b1cfdf413edb8d74a4b2 GIT binary patch literal 5314 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 U-oX^tf&c&j07*qoM6N<$f)JMl4FCWD literal 0 HcmV?d00001 diff --git a/data/skins/coala.png b/data/skins/coala.png new file mode 100644 index 0000000000000000000000000000000000000000..d4fe0e2a26fc80db89be1757097baa7077d537c2 GIT binary patch literal 5674 zcmV+_7S-vAP)q|`OLZZ ze3B=5ckj7pW}cbnnJ;I~Tvb(-nlPa)Qn*)YocM%Px_$W&CwYQAxEk)zy`;;@$%$)7 zrQ4McaiS;4!llvp+)KK=+?=?CRJv{X5GQ+r9DEv%&%LC}9fA{TNToZNkqMgt&i1n| z?JjmmrQ4c`R6)(_7|JA#RAMM!o5)G@kZz1Fm11+fbly|Iy2Zp(fRJvaK9w?by>FV* z983+mJvNxDgXdA6$Lu_I&ZFu8K0AFL#o!&K8)E26;jDaVVXs+Z_6`BQw$!euwpG6f z@!5&<$oxxL2hyB(q&0+di+s07N)0hoBjy&0w9rQ+{w#C?k@(8guIQJ-+S=NxuDIf0 zjcb4V9o748zPbMUUDv&{I-FlqU9@$P?uiSJ;z77GoP zU`odObw*&$3bp9z4;(m9-FftA_3#(JR6YOv^PM>JttYDcAH1*Hw|}2Dfy|*;5I=Kir=hwd#)|18->AkL1cMQ{I!kAJ*Z^i7;T^Of2J z79)Yup-7m+bBVuN+;24!ZHS|ZH4?uLJ=a9fohsq^q#)g8KGZ^3w#Q%kR?)p6Zut;d{J=M#eX2Hq_uO~`5}p&&Zt}>5)kwG@jw;qf{D@3-Hz4$6M>@XO)@Z3c zA4@QCcMiS3i}=kEz`_8iiT6F?OTz%BSdBFhzmB2#CwjC(U05gR>aj!&0Kvdty{hkO z0FOWYn2!O35I>&*L=L_A!FExq2$mCzSOf7R>cuY$pr@Mkd`>lhOzqBpbH(sP!q))s zXwOCb-~aw|wfG$kAXh0HfKco#fSxAnxelL;^*TBd51zP^D@Bf`JBL76kv!JFf9DfJ`yeuJ$&+-%R7Eaxeq|@#o5Y%cvIEkp=oVp+b+|xbBO5+B}t5h6A57mqozuoc;Dv z{2m72Q-}Np;1HRzf0SV}w9gf7NQ&OCRNV&Cnm==UC;o1^?@&HhBBJ;?dhD^Ga3RVv z>c@cC`A3=iV*^l&0nCYM+iEAg0T2T{{+@=2?UOfLe|`Nt^>2?ItAW3{_eoy=iV|p zHWXCCEMvJ5sI6_ZiT`U)KDtNzz&qdlJILdVn0BsGFaTm;NH*7rLEtt!s9*>Uf#DuY zfx;wkFPlBs8n_NyH(@+2CQ}1xQg(RZ+D1M}n_MRGkJ1F{Q2;uYJ`=#OzfJtWC6``8 zZYzs`X>fAXZbFRWuSE;NLDbZ_69fjq;vR5aTLYoo8}~(J`rH>Q!v?ABCP0jB#oI{6 z4APnaA!?4%u0Mazsp`4szE}755dAZ=Z|zy|YvK>yzicbHL%Nyb-4JxNH5H~_X!*93 z&2VW*tiJc?g6(~uc>EhRx<1Ef#2}XRc#2W{w$JJ}1>LW_`bRwyz>7T)^~rmVcZ$A6 z{OvE{*u}DA^#tzG{iC>dN(cw9-p%M{t_%ggq#zL=qxX#)u0;d%Wm_MLrXl^Dl<|0JP!r zR;5nYcbZpp-rchy;>K0i8&eScr~dNTil~5-Cr%|}1oz#0e`_91oci1sYBMvxXRI%j z6w(+Bpj7f=OA&JliH=WO^g=SGe-OASPQ5b{Mv=SRyeE+6T+#R#Ua}O9|<+(W>Fh&8+YXL62Pv}HRA=6{u#d?HCL#&_oW3}EC1QyS1goI(Y zwD3(}|Mq82-aVLaj26uA8EXOCk$5kayvS0M+w>zXYznjiv`qz?Mus;V)o!CBZTXzm0D{5Uh}Yc&TFd59&~4na?bxK|Lf{yN z{wB;9JU;jNdwLfz@j9{EZFuc3TUb;EF*fnNe+srKWZD?OI+#FbxjYJ4;J(-h(-Z}^ z`0BNQlvn+`pwDy%@KgY!0FOMjRMAu z=DBVF9ubj>E?prCu*j8}_H8un}q$PFnd*z*>H>yVg%`L%W1`d5_8UPM|(4XVY zN8`*umPSX6Ov#HaHHh^7sRWw=I23AmFa_lR#njO>04xmZ&x{v&U1vgWZS&81+#_+rTwfOuvTYWdN?j zQrDkUN(JU`yP3H4kN;3tP#LO1CKDh5LP=Tt5O7^LuluFfRad;_t<^iOy|()Oo8MdG zPj0_s`8V)ehY#1+{K^~N&@5v?O<2kRN~G;_DsW0@dkO&j`6vD?iUBzAK3DQ$l)#Ka zQe^QLY9V}x{?3nnjD!!}dRukXZ(Ln}UtKT)@@YpRBY<@^fcqc3FIvMRhO`hRVNX&# z@n`3;1M$B9g9TaqCNN6C$Y4=cj3!u3fV%;UMluW{t}Zq#Mo<|_AO04-?# zz~f{9NyDC`cm`1I+rOXP0D#LbzZ{wIK81P|2JqsGFINBdv!7M}`N}KRFJ61C2L68O zrI+f@%xhnG;f4DD@%d~2^WW9~{qHa8zyJN`Kd*lDqkpkZ^X&J&+xv?zYBGS-U{6v+ z1Hfv22m^qzaF(09;B1S45I#iQhnHV|xxV%%KmKuT4t>|o=l@Zg#8A3@^Z#iPFiF^x z6wd&5&{K1Z9}9wuM}%{(a&s5FR15}yUVBLV8tCP1ul=uAUmY}ozTyA$7%(}^C?rKR zfNdm)$9T1HKYT}Z%dNLnANW8~-E`A?2Z8HwJ#hP<-no1%X!QOiSGlzt zZ3XQD7)DpxU621_Zv=ASeWv8aI2pi&SpIDL>tFxN)&Bhls<*!7$`xGo>sM9zHF+m+ z&A~TcQC)s{W|n!Iv&`HD&yl95PC zqX{5?9A`LU(GSAUxyu`(;Lhg*U=c5d0bo6V+WQ0h_V3db5`6n9F^(#EF-oAIkmPFs z4)tP2rgjBPh11JH*5wH`9Buw!hz%gj7zTg^Lu&7DEC8|}I?2HKrv6@FMj?sA06a|~ zN|4GDsyD)Exl{w7Ea>^dOxHXL++zM8?bI1!Y}yM!a|$_J;!oWK$mIx7*bMnNaNxiw z3_$-H(2xNfdfOr0@Yr9-VB&pS$%`^3M2`PT*#w-*5U8;A!Uy$S0LtS(AK-DI?a&`M zdCzf?UWXXVlbJRI(TsQuCg7a^Km{$3C+gDxZ0Lz$0N7-N^qzX=%%J#z!}&G3(WQRu z)Lh96GX|m>aq1@EmG{t%k-8YDxABGqwh=dv{_gAjFWR~Yg&)JAlckauXADF);#5t* zJKq5dSs;J-h0QkH4DzFBO07BQ-Vsro_!4G|W?a4>2#orkEM?Z3!f%8Ji zi!}ra3JL2de(rL`DCF|R2#M2z@ryn-&-ptx{mfNDJq|HuN?x#>m{AJ9uHxq|U#!9| zkFLJs_7AW8&Rz&$uHW}+uZ8&84`7Vkz}9IhzVrwpT=)n~5k`7+eHGw%jKEuhqu04Gd#(VzBi{Fv+ zZ52nX+}NfRGVwYH8lnc^KnCX4bL1QE*njHSCs~9{1$Oxv@AxM-=ihJ>n8Z&EQ3G%w z1&dTOwW#p-+<3#vXdo1j4$@N>8rw`IwAvq#^Rb*9w65aM)P;jSN(1`;GM}3xL=C`^ z9L(|RDFOD}hcp7*7ju1MgU^m4&M{p`POL!|N?zc7C@6(VoNGj`b`6d4LE1;%&4$i~Bk)Y#~O#<2EyAeJDA&OO?nZLR!QLa1ODS%6(*@M`F&R*D(VA zwj4R~F;wq$lavV+4QcTv%6X=Chwg>i`y5-NP)yIW%@_%HD0fT)0KB(Jr%tL!NQ-t8 zIq!-Q@m8w%1~BvGaty>q4Qa7%BIjK(GR{gh8Nj$3q;!MZM9#ZHnybkG(j+-ZNOQ1h zd=G^*M~+=9oCpdQFlrCFpNFk&-VCJY$BN2aHHfeHWG*apOj{y=PUFLxN9MGW#or!URJ*y})w zgOIV3mbB1PL@e@Sq%Y0GSnEKFgBYatohC6*_w{dNUVQPz`oNHL%Ark&i!K$oR)B$$ zO1@|MI3cF+Ni((pQxX4AenyaHiCbNN-McHqsk`siZE!}-i@5MoflCFnAfr}*XZkP! z((mpua*(UtlWSPgCx-s{cs&9`J}?~4s5kP=2ht@S&E1x!L%KV^_N#BK%((5ATXY-D zy)(0kpjLotHvs2z+C9=|`H@J6Jj@i62@&In>gHe9ffFANq0^*)(a(76Uf+yYUwK7O z2ezFvvZ-*XfDX)ExMxV;Y5wQIfl_;?LCz*XjOMZ1`s}>s&zY0?a13VysK4ySK?$L^ z#oP14y6p5!Y%+*}p=Or>kZ#7DKFRq##jnH51RT=RJwMXSTCOph-CsNlwI#`nn1>!hvwF27Scjq=hj5&Jxw)o-$ z575(>7GDY=M(PGYN}n-8n*e2aTPlYU(Lije)t+8r1hCUJ0+nxe#c~ z|7oKxY2l>;Vw9>~fSD`z#3)+QChrJLAw0y#mbRw}c&F)*?hKoO%uxW=1(ZV@6c=7f zAV#wnCOI!d`rD243zzgIBewYZ(vFc2#xyYssNV;`v;V~oK&KI?xad*>G4x|03;}JP zP46L|DG$XW54lhJ5)oT`Hfe{II;AkKGnh zYJbfiYor$0+RtdNeA`zAF1QCshiWU{BA_Ba$P?-v=@xF+Ck$3eKPJ{|Ui&-IJI{Yxj7vXoarCLbxh($v zUGKRd`op)pDf+Ef{if-OyEWPe;tm2k;%7x5-$q-E{)(<8zm9wmuip)lo__uMH$_)p z_2p>)fxXc$fAvZs9(ZhDbj3Aaj9&K#XBrU*E!qY0gSd6cZ_v%P(-xzjqHD>oBOk=; z&IL(t|MhKKCz3vkAM9U@MIado^eozhIXoBnqvU$0+i8o@ebEV$|BR&gfcX`40={`E zH^RifZpvqpuMT3j4D#>Zy^BPCVCm=s(T;sPqThex8_b#j#Wv!=Nq#dDIo(!E{(4X@ z01Fce!YovQa3rEJ0OXoW>`$8G=J#5bxgh!o!HhQj!{3p~4?KK)DHebW-}f%GV??yQ zX1#$Cr`z&Wh@D{d7KS)sD_}$7FI(XWkv}9B2j-jefjcn>lj~FGwQRW{`a4ALZ$tj{ z2p|!FeDW1z(k(uD0U$P}n{fha2xae4lgkX#3&D>;aQbZ)w!#wsTysB?206#i(cO3z6L4Gj-h>7)kulen=B)jZ=48owK7fSibR(JyBkLRxp z1%uqpS;o2(@Z7?RsCB_50JybhL;mIee<3Enr2ur8V&+BwEQ%l|)sGJCiVmL~ME`ul z)zPM}Y>Ynm;XjMcU4KrVlZ!Qqt_a<{VuXG80e`-=Vi770Sm4M5F^1LxaCG!Pbp&7obL>O~pbx_!8OW7~o%h@r6Y#=|&d=+8 zIz)SUL>Q&73p=o91St;}U-E9&!V?exuAWy5MjUw{#?X2SV21xwIRzj#Bp!yE-n9%6 zgO7glL)qy9dXwx{#xOY5+oX~H{g?zG^rt_2SuW`x9PNqrKJj1C;-ic4zxcnaw*Dh) z;Ry`?r3vc-wMS#bI1X$U0Y}dtACtd^0E`^Pu$}-A8xap>K;|^rwjcgpv}3qy4dJo? zQ6U6xSa+6j+&tV+H88R8ptpypWUv3@<9EeA{QJ@^(Kimm|^uC5vAYGbp1~)&vGrIfeow;Iw zo;$mMh@UsSfOsJY1U3Zxw+C;YNIsA=PY5uD0HLvfST>Eo z=pj4h0I9!o@U~o=H#~T2bjweEF#Z`M6Z{SAaTT6t0pQ#}t_k@&*@$@{#xfoS;2D5P zB7k9k9{IQ3vMu`E)y|8wmXu(?9KU=Ka#)BX7&fHEaNm$@=WusSydojMh~VHe_f}dr zr~*to(%0W}{Qj8qcOKaj9Yykv4#vO3XN~A^7M@1|kS3~2gdDjb#&||Cbn~s> zj(+}&lW}hk(m(R#;WZ0>S-kJh-)sEt5N!rYTRArb<&R`t7os8I?j!%XhJcSe_tRJi zK*TfwF-pKx!3@Q@fb|FT?)^izM^C);R7`yQ3qT0c_RZg-=JwPO(=#@yvCBn==D zi7~G6NB|G^TyW9((dV~pimw0u^@YU8?^5I+5N&1i$sq!`Mt%*uEX4EzV0!)!!W;5| zh`{#4y9(C2d}*Bb&bOFhzac-V^C+-ecUspiyuQmq1cCB~;deZG_n3Sj;?Wm|&WWGJp=b6+ zkH2^%_F>G06xt#o8Kj7cy z4x1xlyvh$Gaa4#f8WYG6&aA$F`{2%)a3CHCIDGa#@8nNo_}oKdF~Za&EdaO`>8kKr z0kFcrMIMMTmPYzqz&t@PB7{z>eDvY65J4bAwCvFT(Vra@C4L(4<>u5hzz6{DU?f59 zyC^&dap&HGs|`*Bpn)R52cH69hX0z#Z*blIo1%Z&zv`n|i@+TW*M-L%_W=XRG^6-z zJBBSm5W>lYvfqo>l<#2!MEx>=AKW9R($xi{hc0v;g2}@0J9(h<950%#PpV2)2nI+$PW>?cK=PS0O*9bJh&vFB-XUiWg(`C zRrKVaHhgR8)>r_5J088G6##wc`pktZ5=!B;_BjefJOz*@vklBN0NA{OSHJdEB8Arq zKp{rH^Wch%zLDEDM?vV}S$=6U+hTJf0Kf+~eL}48EaE;ABBgJTj*M$XV8Vk@u6m;M zHsGdVYf1osv(}y2gyCmLn3O&t_K3C%a=OOE_Bd#Ch$J;x0I(@2EdZU5U1|!?>+L{d z-1`cM=@X&PTr^b}O8s`wxcEexNe6*yM|vR;n7{Knk-{U!-POw^v_kx(CN1Qz<-3Ch z#!pA(9m&-cVDVMFOz#maXaH((lPk{5nBgTECfQ%C8y3PYbZa`@2OHq-} zeqi~AEJ*rH~3--jl~U7Cne=()~A&Agya;>B4UFMjCoTbeQ-($*hijDdLn58&zJyo6cAAg1DAQIk&`e; zUMjMC_b%&Ki~|@YU}TWA7o!PQ5oiS<2icu~zV8GOW8MmYJ^_gL!cbl-Rt8KFlF>lE9t3I^0aZh*04$@Y<|aQD1e05YBd&IHH+9x8&27O{@6Xn5?uJ8=3pWCRh=$b9E}xi4Nb@-Z zD*2B*zqID>Cy5Bi58n>|?=ZUenPGJ8;l*|%P&44|i9ljLu=_9W3}3(Qtmr+LToirs zb03fKnJ;aOzOd!&#dfVeK{lweC9>k-}7Ty8y-6MOVdq#)j z-hazOJ5LjU_y6rjOwoCH4xJeHIR#|&ji$V;#XCrCanRt#9SD*=0xS>84+J?w0U>>3 z!ABmNCIaMkIA|;gvgXy`no;!R--O|R=&SIEai6s_0mRM%&?*8}ZE(=g&?IT+JvWLI zylm*dxrF?g+kXR}MMsQ#R{<$~VdOIpO%MTV|6TS*7hm%3%4Ebs9M%RVE!J@WdlAf{ z;+6{J$AO?yF9#vU9MgbVIT*C(GY{HDpqB5B8rd<)sxk`5-m-Hg0%<$)E0u1@92*5kuf1zmaZyEP#9|eSxxzHj4 zZ2tNvM!YAm?3i$~2H=YPSn&JTgFB<$PdyZqzkg)UMDnK|{RKLbMMsSJG_M7S-ulxb z0<6CJDn`nJAUANUugYqF!O&kt(GlZ5uYj!FSPles{%IpWce{KvvSX6?>Cax~mH6oO zw^i8WlO_Mz>qAp?Lrq0TjQcjUD$$pZVgaVq&@`J`VPz^!hnF z{@4#-^ju(JFg;U&zNS1#lb^GlJ{#RP37y;YiFo@hj^E-WKCXxB+7Lgp=m)4Gzh%rj z3dma*szza2$j{YQ-;E!O03NOZ>983G$8haAc9#|D@pt(9Dw}#L4*P-b6ct=o0f}v) ze%>!Zdd@aW1Ys-!=y5?lLqzo4IFcK^IEL_eOD`7i4Dd7lAHUz4eBPGy27i6SmC;%2 z&P*4a`nje>%$xYQu(~OjM)KEfyHqg7YXazbam%ePk!_HA#J3RzH$x(zJ{Qu2=Zb-3 zP&z?sk?O*^_pTWYxC8_zGvprx%7>avG4CoMcNs9}pH}jR!Ks5jdMTLy3u|24Di+eg z0qMq%vEtr4_TIY^0uVoSuAk{?NYD366dZHR$1ki@2=zj2K}rz2PmDR@0AU~rp-oIQ z1!>LMX;>fl@Rb{DlOAG%p?;>vkCLR2k6V%^J5$WVK;J%rp7vbSt!Yb)0?D@ndlUiF zJFO{9j0$jX9wbH&UN$nG0%=UaH`PVjdRQ65R~(bLG<WG;w4_8DVVh8{=kv<6ZIq)DtK=AES2Fsd3= zEY3kf28`TlkzO(vL?3;h%*?V&Qgc9C^6QN`3a^s^3(+;@g6L<5NMH`sKB8WGP+RiP zNX#|ng6M0HfzVV8>c+AOft{Ixo7I?W%>~ilRsfn_kkSP=i!s-n3!={wr!X~F05lb( zbfL{+%$tx8qTd|>0jPakop_L?i&DDnvlj2B<$~CTk!Jx2r$PWE3RAkR8X!&hCgg+I z4xevn?s3FdJixvSQ@U;1&=Q|LM%|{6KW>|JaD5c0bQ_w0miVmk=>+_5YsSW(e!%=< z6!E}vCPdn&X+cYTwz!xLQ@BIW%V018i>c3b1LBKmD6tj~Y75<%b<(?thYwV4k90s= zG!L^tber~T0jVw0!EDi@iI65amk5govPFxgLYnLxBQWtGHWk6=E?)x)`_eIJp+p2~ z)S-9)n}{s=eT#sk@U+OuhXUf;)`WQQnuemF`y!;I@D%x>DF+gM#NR6+KQ#^_#nV)j z1>JQKYAbx{(T^q}j{i>y`6)5*S~yKc)u6j7Kn+D-=Et<>pv;f>cM6D4iGg<_H4!#} z=PW=CMPJpAY0W`ZKjP0QA%B$^h?7e@>I9yn05udn)sJb*fo%+=iC-lK;snzS*THvb zUpfxck^`w2aJ9S4A90dtg^%F7wl5urrsqH^1}?~7xcY?A-BrtrqSe){Xhmw#@i1AWrcD8KJ6@b(0F&(Z9NW%=FA-P>s`c(^5eS)mFt^+JZ_usrOR{&Crfz|CxlTQPP z37AAcX#oIS_QFN*Ap&NI-z9u@p3#1%B<|KVK#c=>`n<0nE*+rTmnNSE5ED>FKvMFh z?K8r)2vCN%CPqEx_Voh!5x{cM2%r^!RsdWG0IoNvi1gkFZV^~cQ022`8o)UM$b-Zh zz@TUi;F{ZSYu5lg2!Qk=V3*5&Mf6JSO#&wYsl96GAQoBFin(R}2iZLU<_jZ(pt?w| zLYjOUKuo}f2?bBO1!HMHC*%N!VnO51B#PR z3y4WDi%ePg+6a{0hMb;@iW90ysF4GpAFS?0u(oO20c95gQ}ch?s7so7T0l%fFUTig z=&AU+Ikw3=0yUrp`PgjN6oJ|{E$j}k87Mspz`8(SQG?>d(*$A?vb``#c^T~YGxobS z_I(hoY78W8`|yL&CPo4A^8mQ_pX>m%8i9(FP7{bpFt>#;1e_Bpgl^(PrzylMi-DwV zmwq^~2@yz7MNx&2M!K6{g)-cYQF_y=;$F@W`V)+6bCf^A(P{xuni^`gYjl}PKbA@~p4N_P6eSuAD zS*#GyfTeofozFeT_wC;=aNzJE{=w3c`1d_?bNrXjKARR`)PN?GyUywfKbr*d&2i$b z8+F5Mff!oPx1wR#ErkE#%P;YhVaPxI>@)twU;bK%8=rp4KRA9ood|*&)Ij_jthxBh z6Op5&lN+@t`&K88#tiX`-X6j)6MYt!mX}2mU|Zt5SA&v!OrQ9H_1sb%B;6UK7HA*q z#Id-=y!*!Ls*?DDm0P#?N0%=0=U;e1t_i4^NIaUcnOl-$gga-{LhWOHI1+mVS1`9% z6@NMbys~?@6rhR?nEnKi??c}kTNR@gZ6E8yf%wJZ+n;ZLL6HDPtnCS)Yep^JKGp{@ z2czA4_S6zTaBXEpB!ELlkJL#3Cd6+q0d&=!WQ6;8qj~@%JtP^u?$}O;8`<7;9{6acanlpHGjH&oO_FlmD-H7n*_*@KJjTAcz0G zN&tN`YH=H`4~RBmdUl}!NEk>UK@+Deb5d&&@K2wAJ`sO!76EG-o^^%^f+^p{=hzP& zv#p95mH^*bOMZXaZ_4tgeK*&rMQ%X+-~zq8sU8SG9Yu8=w8#s5RC)~f`JFpr1CWLU zV5$zDHiE_$v-}JOPVVV?v9^X+N zXDxAqHn@phfYY}AO7Sn>y!nLqQyYPb_u}W9iH$(|6M&*UvA6lfT`%$1_w5y!eepM? zj^lHD@6DqJ`N6jj^LLKT=i=zX+u}QO`}gr(yI2qggj04qznf`hi=9Xfy!HFIQ!aMx#(Lw?5 zKlD2xUWgL^UL^LaK*E5?e|z8!ksMG)-uK|suU~k+oU8()7Jg0fN38rzxou$YyOqSN zXfcYyNZ_N37kTvMmy@|ZMh58xzbtSvFo|thwNRFfK$t#$*K$j-L}G-ZAh4!_HVGt$ zR1%0(0&J1^<iJy)MhUD%qX0$IeZ@Ty3sV|6cvS~b8 zAWbZ!yt;Qcxv;AOz9s~QDuH_O_a+HYTKZnVqJ)6YFz25>`mjKlxY$6)f}Sb-ere%} z|Awy#k+Djkj*4IRVv=pRI34JYSs+Uck&0H|UBTIp&g4x4l%C%@Dt_1J{L_Hs<>JDi z79&qS78+nHhW{tep5z~2IzRbuJc?vn4bZ7Q0g5(Y^a9p_5p(kqVI!kXK2JGefFLpd zcX{}q#vfL$O_BgM6ETZJP*dD@2>Ex~6_`byTWca#!{mthzw5*Q^fX}gk1IU<@O1id zpwfkoj)=eQ^Zp`OOU7NdNt}j>*=W<_KP(0!0RZnWF33jb#5#bY4H&&xO<=?9CVK_~;7^rANMlVv6uwEBkvE0~9_WpR3MlEPn96NDrk^q1M2j3*= zd7ALv1LPlUDKLV1aLx+jGTHm%1Rk}Z>mZ!~u3Wn)8{J3;;f5RDfYFQ721x3nt%;yC z9s@y(6=rMct!V|L5S=kw=XaS=aBL%EK4QMESj2=U_HBF8)SY{gDqd=Vi5J+oR|H~4< z^&8h@qZ^v6kea;rZT>GYP$7v({PGtih!slnJ2q^Z%j*kl7h%q%xW&-X3D8 zLK1=aF-3ux`Rwd0KO3IrU){aSzkTo^7k6&o=2tIWz9TCm)Ljue5^qmY*({1*?1h1NzkB#lN%&bq;y?mn+X+wWBDC(n#l8R2 z1a|7&DZUggiEX#kV#f)<4^A%fGv`lFt_DjV2=WQQc~mxw2>^?eVz{r%Fhxj41I1T- z*NB@W0h~BihF%NXbOp*Zdk^m*r;$J+q=o3J@;NpFO{Mf>R_5=Vsa`+IO z(YE$MmH+_s%-2`0l8PTAg0xTPFP!rUpk1hJb;a*e0>G05opF;U0N~xl_e2kDTliS$ z%bQ*l&HsG@a2A!#VglH}qdXIqJR)><1Ryp$)Sa)}NCXf*rXP7eWbXpVB6TV-)KvjK z0dz6}#3&BW^kM(|`DecIoE90ba zN{&_$~yGL{jxB0;VD> zH?Nl_fE_z_fRK^S3ed#6cKd^LsQ8qZMHv%`|y$2YmkYZB&)JdSR-v)ym zF-J!MRmGp_{X?4-)0Fp)BUB;8MgpKn0$O}F-5a^~c3>6pr}qAn_BeHT?=XfcWY`kF z?IfVhU&8^SvYdEBFc$n&#GiRFXh2ap4S4VJC?HfJ!gd0%kp#5*YB;!nC9kWZyeJgA z1j|nO#p~)#k3=5F~=I5qKS(s8NG0Ifn?jSi{jTA zqs^ejGinU2(JMosCWL?T?8(Z{_e&o6K{%wZozld4$moTu0|S+y`yhT@vDyrLaz+|S z0P}3j%fk=1Z{uw;$H!UzIz4_)&+n}GYw{j3dI2|qwKM;16TdXF1kf}IV5MCO5aPuu zy&N6njS#SskG~%em&Et*8gJG4ecpm!YR>Px_-pb$VDv(+D}JY@VXlc^8d(CUnFK_G z#047|b~h1l6CeSlR{KY+CF1W%67b?zG_nLxlaQDtm5rmeS8C4N>-PGoAwPf>b7vb{ z50gMw#V_9u3`A^80}*R@`A6Ew5_M^=~?U{0Q1AJEa`<4A8x_yBst zz$Cd2H_VW^`H1kIY9J1C4Dk*%aDv1Unc~F-qNK@76ekT6f<5xq5q|D``F(vw^LvOs zb(2pc;j56^k|Y4WUD+&zMjomL;4rt5A&#`~g>Z$iw9O<0K9xPOU9lW_nqBBM0APE zp;1!D-Z#Fd88tTzxf(IM2_R_7EjhtdjgmTEYPe|BoM_<5<}{#j?=Rw`CfIhvq>j%u zxMI{iXyhnjEfK$njhb8=jgvZ#Hh{{g<2J-k$jt1fTxXi!i$G4S?uwxHukEm9)Nxwk zMqU6Cr%<$sDvJSYxT&gAOw^=$xCs+R9h0lPn6S$6P!sCW4w!6&ZG-Ek6bm((9v*Fk ztELnve$aiY;JUqI9wh4dYH#Kn{9$i7( z#4miNCe6d6OK6k$g}>BrMCdtFYgAU{lczAfwf!qNP z4-Yz!JK*8rK?iaNJUl$;K< z{&}MEm&dr5;(v{x4(=so+m3xEiJSlQ__4s)HtN&`Ma6XiGYR2o+pJRo4a(n4dCDt5~H-xGWSS4{MPEKxGQjWc9wtl@FD&*QjMLW;dB8p&$pqa@&~Ch zZ3|E$odj+9FrSnq4durPAEV6QZ6pC{p=I7D;+L44+bexpQ~5pHjixI|H^Qvh5JJ}A zPe{N+HVK&aL6)^qP}UmXuA6m>^SuyJ==|? z3kZ3+#l+<=6L4Z939KvdJ5=~?RZL6#X*1adhIek?&P@Qv78Ydrl@pNdhSCLuyxdGy zz6<3S!E_RkL;JA8ch{2d4mHOYbNUfLl>|`v_b3`l+d(}Am{xwIxx9dH^}fRj$ga-o z9F52XQ02Q}@?F#G0MbIk<)pFx?SltpQ-DpC-?Qa(*Fe1pI4UVW&|KCUuWtj5e#|Jw zW^*w%v{05rgaWbZpG^SY+`o^Hl#-q;r@Mxj=i9J@4_Y%8cY0^10Eh8bRc)Y x!^49Pcy;o(7t{{z;A#nKzj$2b50002ovPDHLkV1miP%})RT literal 0 HcmV?d00001 diff --git a/data/skins/pinky.png b/data/skins/pinky.png new file mode 100644 index 0000000000000000000000000000000000000000..2308c4b4b4676333506d66a66f3f4eac0f048d57 GIT binary patch literal 5199 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 Xg9wT}d(`>gm*{l^bNyOfr}+N?vONNQ literal 0 HcmV?d00001 diff --git a/data/skins/redstripe.png b/data/skins/redstripe.png new file mode 100644 index 0000000000000000000000000000000000000000..6cbbef0f5c076a1035e1df9782076af8ae7ff4c5 GIT binary patch literal 5343 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 literal 0 HcmV?d00001 diff --git a/data/skins/saddo.png b/data/skins/saddo.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb744e62de9b34d068d1d67e3c14d6aa646f1fd GIT binary patch literal 5551 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 literal 0 HcmV?d00001 diff --git a/data/skins/toptri.png b/data/skins/toptri.png new file mode 100644 index 0000000000000000000000000000000000000000..3849e01ffc3d855795a796ef45d801f9a3742cbb GIT binary patch literal 5152 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 literal 0 HcmV?d00001 diff --git a/data/skins/twintri.png b/data/skins/twintri.png new file mode 100644 index 0000000000000000000000000000000000000000..a12bfb0c7e273d970399333166fa2db0643717fa GIT binary patch literal 5233 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 literal 0 HcmV?d00001 diff --git a/data/skins/warpaint.png b/data/skins/warpaint.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9142c59e479cc5a4b82b3ddf4d73bfa74244e0 GIT binary patch literal 5181 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 literal 0 HcmV?d00001 diff --git a/datasrc/teewars.ds b/datasrc/teewars.ds index 0b6818970..2a28d89e6 100644 --- a/datasrc/teewars.ds +++ b/datasrc/teewars.ds @@ -618,19 +618,20 @@ sprites { } - tees images.char_default 16 64 { - tee_body 0 0 4 4 - tee_body_outline 4 0 4 4 - tee_foot 8 3 2 1 - tee_foot_outline 13 2 2 1 - tee_hand 8 0 2 2 - tee_hand_outline 13 0 2 2 + tees images.char_default 8 4 { + tee_body 0 0 3 3 + tee_body_outline 3 0 3 3 + tee_foot 6 1 2 1 + tee_foot_outline 6 2 2 1 + tee_hand 6 0 1 1 + tee_hand_outline 7 0 1 1 - tee_eye_normal 10 2 1 1 - tee_eye_pain 11 3 1 1 - tee_eye_happy 11 2 1 1 - tee_eye_surprise 12 0 1 1 - tee_eye_angry 10 3 1 1 + tee_eye_normal 2 3 1 1 + tee_eye_angry 3 3 1 1 + tee_eye_pain 4 3 1 1 + tee_eye_happy 5 3 1 1 + tee_eye_dead 6 3 1 1 + tee_eye_surprise 7 3 1 1 } chatbubbles images.chat_bubbles 4 4 { diff --git a/src/engine/client/client.c b/src/engine/client/client.c index 9445e6d79..df53d1429 100644 --- a/src/engine/client/client.c +++ b/src/engine/client/client.c @@ -19,7 +19,7 @@ #include -const int prediction_margin = 5; /* magic network prediction value */ +const int prediction_margin = 10; /* magic network prediction value */ /* Server Time @@ -182,6 +182,7 @@ SMOOTHTIME game_time; SMOOTHTIME predicted_time; GRAPH intra_graph; +GRAPH predict_graph; /* --- input snapping --- */ static int input_data[MAX_INPUT_SIZE] = {0}; @@ -272,11 +273,11 @@ static void client_send_info() msg_pack_string(config.player_name, 128); msg_pack_string(config.clan_name, 128); msg_pack_string(config.password, 128); - msg_pack_string("myskin", 128); msg_pack_end(); client_send_msg(); } + static void client_send_entergame() { msg_pack_start_system(NETMSG_ENTERGAME, MSGFLAG_VITAL); @@ -284,6 +285,13 @@ static void client_send_entergame() client_send_msg(); } +static void client_send_ready() +{ + msg_pack_start_system(NETMSG_READY, MSGFLAG_VITAL); + msg_pack_end(); + client_send_msg(); +} + static void client_send_error(const char *error) { /* @@ -380,6 +388,14 @@ static void client_on_enter_game() current_recv_tick = 0; } +void client_entergame() +{ + /* now we will wait for two snapshots */ + /* to finish the connection */ + client_send_entergame(); + client_on_enter_game(); +} + void client_connect(const char *server_address_str) { char buf[512]; @@ -412,6 +428,8 @@ void client_connect(const char *server_address_str) graph_init(&intra_graph, 0.0f, 1.0f); graph_init(&input_late_graph, 0.0f, 1.0f); + graph_init(&predict_graph, 0.0f, 200.0f); + } void client_disconnect() @@ -463,8 +481,9 @@ static void client_debug_render() /* render graphs */ gfx_mapscreen(0,0,400.0f,300.0f); - graph_render(&game_time.graph, 300, 10, 90, 50); + graph_render(&predict_graph, 300, 10, 90, 50); graph_render(&predicted_time.graph, 300, 10+50+10, 90, 50); + graph_render(&intra_graph, 300, 10+50+10+50+10, 90, 50); graph_render(&input_late_graph, 300, 10+50+10+50+10+50+10, 90, 50); @@ -574,13 +593,15 @@ static void client_process_packet(NETPACKET *packet) if(map_load(map)) { + dbg_msg("client/network", "loading done"); + client_send_ready(); + modc_connected(); + + /* modc_entergame(); client_send_entergame(); - dbg_msg("client/network", "loading done"); - /* now we will wait for two snapshots */ - /* to finish the connection */ - - client_on_enter_game(); + */ + /*client_on_enter_game();*/ } else { @@ -736,7 +757,7 @@ static void client_process_packet(NETPACKET *packet) if(recived_snapshots == 2) { /* start at 200ms and work from there */ - st_init(&predicted_time, (game_tick+10)*time_freq()/50); + st_init(&predicted_time, game_tick*time_freq()/50); st_init(&game_time, (game_tick-1)*time_freq()/50); snapshots[SNAP_PREV] = snapshot_storage.first; snapshots[SNAP_CURRENT] = snapshot_storage.last; @@ -744,6 +765,11 @@ static void client_process_packet(NETPACKET *packet) client_set_state(CLIENTSTATE_ONLINE); } + { + int64 now = time_get(); + graph_add(&predict_graph, (st_get(&predicted_time, now)-st_get(&game_time, now))/(float)time_freq()); + } + st_update(&game_time, (game_tick-1)*time_freq()/50); /* ack snapshot */ @@ -950,15 +976,16 @@ static void client_run(const char *direct_connect_server) if(inp_key_pressed(KEY_F2)) inp_mouse_mode_relative(); - if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed('Q')) - break; - if(inp_key_pressed(KEY_F5)) { ack_game_tick = -1; client_send_input(); } } + + /* panic quit button */ + if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed(KEY_LSHIFT) && inp_key_pressed('Q')) + break; /* pump the network */ client_pump_network(); diff --git a/src/engine/client/gfx.c b/src/engine/client/gfx.c index 3bf8cfe48..31a87611a 100644 --- a/src/engine/client/gfx.c +++ b/src/engine/client/gfx.c @@ -536,8 +536,10 @@ void gfx_swap() for(; index < 1000; index++) { - IOHANDLE io = io_open(filename, IOFLAG_READ); + IOHANDLE io; sprintf(filename, "screenshot%04d.png", index); + io = io_open(filename, IOFLAG_READ); + if(io) io_close(io); else diff --git a/src/engine/config_variables.h b/src/engine/config_variables.h index 4ef8958e4..f38209019 100644 --- a/src/engine/config_variables.h +++ b/src/engine/config_variables.h @@ -2,7 +2,9 @@ MACRO_CONFIG_INT(volume, 200, 0, 255) MACRO_CONFIG_INT(cpu_throttle, 0, 0, 1) + MACRO_CONFIG_STR(player_name, 32, "nameless tee") + MACRO_CONFIG_STR(clan_name, 32, "") MACRO_CONFIG_STR(password, 32, "") diff --git a/src/engine/interface.h b/src/engine/interface.h index c57c170de..0eaabc20d 100644 --- a/src/engine/interface.h +++ b/src/engine/interface.h @@ -743,9 +743,12 @@ int modmenu_render(int ingame); /* undocumented callbacks */ +void modc_connected(); void modc_message(int msg); void modc_predict(); + void mods_message(int msg, int client_id); +void mods_connected(int client_id); const char *modc_net_version(); @@ -753,6 +756,9 @@ const char *mods_net_version(); /* server */ int server_getclientinfo(int client_id, CLIENT_INFO *info); +const char *server_clientname(int client_id); +void server_setclientname(int client_id, const char *name); + int server_tick(); int server_tickspeed(); @@ -823,6 +829,7 @@ int *client_get_input(int tick); void client_connect(const char *address); void client_disconnect(); void client_quit(); +void client_entergame(); void client_rcon(const char *cmd); diff --git a/src/engine/protocol.h b/src/engine/protocol.h index 96ad1e6bf..822a735ff 100644 --- a/src/engine/protocol.h +++ b/src/engine/protocol.h @@ -1,5 +1,28 @@ #include "system.h" +/* + Connection diagram - How the initilization works. + + Client -> INFO -> Server + Contains version info, name, and some other info. + + Client <- MAP <- Server + Contains current map. + + Client -> READY -> Server + The client has loaded the map and is ready to go, + but the mod needs to send it's information aswell. + modc_connected is called on the client and + mods_connected is called on the server. + The client should call client_entergame when the + mod has done it's initilization. + + Client -> ENTERGAME -> Server + Tells the server to start sending snapshots. + client_entergame and server_client_enter is called. +*/ + + enum { NETMSG_NULL=0, @@ -15,6 +38,7 @@ enum NETMSG_SNAPSMALL, /* sent by client */ + NETMSG_READY, NETMSG_ENTERGAME, NETMSG_INPUT, NETMSG_CMD, diff --git a/src/engine/server/server.c b/src/engine/server/server.c index 8fa10d7bf..b1bf5e4de 100644 --- a/src/engine/server/server.c +++ b/src/engine/server/server.c @@ -57,8 +57,9 @@ static int snap_id_inited = 0; enum { SRVCLIENT_STATE_EMPTY = 0, - SRVCLIENT_STATE_CONNECTING = 1, - SRVCLIENT_STATE_INGAME = 2 + SRVCLIENT_STATE_CONNECTING, + SRVCLIENT_STATE_READY, + SRVCLIENT_STATE_INGAME }; typedef struct @@ -161,6 +162,20 @@ void snap_free_id(int id) } } +const char *server_clientname(int client_id) +{ + if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY) + return "(invalid client)"; + return clients[client_id].name; +} + +void server_setclientname(int client_id, const char *name) +{ + if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY) + return; + strncpy(clients[client_id].name, name, MAX_NAME_LENGTH); +} + int server_tick() { return current_tick; @@ -404,7 +419,6 @@ static void server_process_client_packet(NETPACKET *packet) { char version[64]; const char *password; - const char *skin; strncpy(version, msg_unpack_string(), 64); if(strcmp(version, mods_net_version()) != 0) { @@ -418,9 +432,6 @@ static void server_process_client_packet(NETPACKET *packet) strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH); strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH); password = msg_unpack_string(); - skin = msg_unpack_string(); - (void)password; /* ignore these variables */ - (void)skin; if(config.password[0] != 0 && strcmp(config.password, password) != 0) { @@ -431,6 +442,15 @@ static void server_process_client_packet(NETPACKET *packet) server_send_map(cid); } + else if(msg == NETMSG_READY) + { + if(clients[cid].state == SRVCLIENT_STATE_CONNECTING) + { + dbg_msg("server", "player is ready. cid=%x", cid); + clients[cid].state = SRVCLIENT_STATE_READY; + mods_connected(cid); + } + } else if(msg == NETMSG_ENTERGAME) { if(clients[cid].state != SRVCLIENT_STATE_INGAME) diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp index 471cb6049..e966287e8 100644 --- a/src/game/client/game_client.cpp +++ b/src/game/client/game_client.cpp @@ -26,10 +26,8 @@ enum data_container *data = 0x0; -static int charids[16] = {2,10,0,4,12,6,9,1,3,15,13,11,7,5,8,14}; - int gametype = GAMETYPE_DM; -static int skinseed = 0; +//static int skinseed = 0; static int music_menu = -1; static int music_menu_id = -1; @@ -53,13 +51,42 @@ static const obj_player_character *local_prev_character = 0; static const obj_player_info *local_info = 0; static const obj_game *gameobj = 0; -struct client_data +// do this better and nicer +struct skin +{ + int org_texture; + int color_texture; + char name[31]; + const char term[1]; +}; + +enum +{ + MAX_SKINS=256, +}; + +struct tee_render_info +{ + int texture; + vec4 color; +}; + +static skin skins[MAX_SKINS] = {{-1, -1, {0}, {0}}}; +static int num_skins = 0; + +static struct client_data { char name[64]; + char skin_name[64]; + int skin_id; + int skin_color; int team; int emoticon; int emoticon_start; player_core predicted; + + tee_render_info skin_info; + } client_datas[MAX_CLIENTS]; class client_effects @@ -514,6 +541,46 @@ static void render_loading(float percent) gfx_swap(); } +static void skinscan(const char *name, int is_dir, void *user) +{ + int l = strlen(name); + if(l < 4 || is_dir || num_skins == MAX_SKINS) + return; + if(strcmp(name+l-4, ".png") != 0) + return; + + char buf[512]; + sprintf(buf, "data/skins/%s", name); + IMAGE_INFO info; + if(!gfx_load_png(&info, buf)) + { + dbg_msg("game", "failed to load skin from %s", name); + return; + } + + skins[num_skins].org_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); + + // create colorless version + unsigned char *d = (unsigned char *)info.data; + int step = info.format == IMG_RGBA ? 4 : 3; + + for(int i = 0; i < info.width*info.height; i++) + { + int v = (d[i*step]+d[i*step+1]+d[i*step+2])/3; + d[i*step] = v; + d[i*step+1] = v; + d[i*step+2] = v; + } + + skins[num_skins].color_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); + mem_free(info.data); + + // set skin data + strncpy(skins[num_skins].name, name, min((int)sizeof(skins[num_skins].name),l-4)); + dbg_msg("game", "load skin %s", skins[num_skins].name); + num_skins++; +} + extern "C" void modc_init() { // setup sound channels @@ -556,27 +623,13 @@ extern "C" void modc_init() data->images[i].id = gfx_load_texture(data->images[i].filename); current++; } + + // load skins + fs_listdir("data/skins", skinscan, 0); } extern "C" void modc_entergame() { - col_init(32); - img_init(); - tilemap_init(); - chat_reset(); - - proj_particles.reset(); - - for(int i = 0; i < MAX_CLIENTS; i++) - { - client_datas[i].name[0] = 0; - client_datas[i].team = 0; - client_datas[i].emoticon = 0; - client_datas[i].emoticon_start = -1; - } - - for(int i = 0; i < killmsg_max; i++) - killmsgs[i].tick = -100000; } extern "C" void modc_shutdown() @@ -755,6 +808,10 @@ extern "C" void modc_predict() // predict for(int tick = client_tick()+1; tick <= client_predtick(); tick++) { + // fetch the local + if(tick == client_predtick() && world.players[local_cid]) + predicted_prev_player = *world.players[local_cid]; + // first calculate where everyone should move for(int c = 0; c < MAX_CLIENTS; c++) { @@ -781,16 +838,10 @@ extern "C" void modc_predict() world.players[c]->move(); world.players[c]->quantize(); - - // get the data from the local player - if(local_cid == c && world.players[local_cid]) - { - if(tick == client_predtick()) - predicted_player = *world.players[local_cid]; - else if(tick == client_predtick()-1) - predicted_prev_player = *world.players[local_cid]; - } } + + if(tick == client_predtick() && world.players[local_cid]) + predicted_player = *world.players[local_cid]; } } @@ -850,10 +901,15 @@ extern "C" void modc_newsnapshot() } } -void send_changename_request(const char *name) +void send_info(bool start) { - msg_pack_start(MSG_CHANGENAME, MSGFLAG_VITAL); - msg_pack_string(name, 64); + if(start) + msg_pack_start(MSG_STARTINFO, MSGFLAG_VITAL); + else + msg_pack_start(MSG_CHANGEINFO, MSGFLAG_VITAL); + msg_pack_string(config.player_name, 64); + msg_pack_string(config.player_skin, 64); + msg_pack_int(config.player_color); msg_pack_end(); client_send_msg(); } @@ -1043,10 +1099,11 @@ static void anim_eval_add(animstate *state, animation *anim, float time, float a anim_add(state, &add, amount); } -static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) +static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) { // for drawing hand - int shift = charids[skin%16]; + skin_id = skin_id%num_skins; + float basesize = 10.0f; //dir = normalize(hook_pos-pos); @@ -1066,7 +1123,8 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset, hand_pos += dirx * post_rot_offset.x; hand_pos += diry * post_rot_offset.y; - gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + gfx_texture_set(skins[skin_id].color_texture); gfx_quads_begin(); // two passes @@ -1074,7 +1132,7 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset, { bool outline = i == 0; - select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, shift*4); + select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0); gfx_quads_setrotation(angle); gfx_quads_draw(hand_pos.x, hand_pos.y, 2*basesize, 2*basesize); } @@ -1083,30 +1141,33 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset, gfx_quads_end(); } -static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) +static void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos) { - vec2 direction = dir; + vec2 direction = dir; vec2 position = pos; - gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + gfx_texture_set(info->texture); gfx_quads_begin(); + gfx_setcolor(info->color.r, info->color.g, info->color.b, info->color.a); + //gfx_quads_draw(pos.x, pos.y-128, 128, 128); - // draw foots + // first pass we draw the outline + // second pass we draw the filling for(int p = 0; p < 2; p++) { - // first pass we draw the outline - // second pass we draw the filling int outline = p==0 ? 1 : 0; - int shift = skin; + //int shift = skin; for(int f = 0; f < 2; f++) { - float basesize = 10.0f; + float basesize = 16.0f; if(f == 1) { gfx_quads_setrotation(anim->body.angle*pi*2); + // draw body - select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, shift*4); + select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0); gfx_quads_draw(position.x+anim->body.x, position.y+anim->body.y, 4*basesize, 4*basesize); // draw eyes @@ -1115,34 +1176,34 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) switch (emote) { case EMOTE_PAIN: - select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, shift*4); + select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, 0); break; case EMOTE_HAPPY: - select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, shift*4); + select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, 0); break; case EMOTE_SURPRISE: - select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, shift*4); + select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, 0); break; case EMOTE_ANGRY: - select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, shift*4); + select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, 0); break; default: - select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, shift*4); + select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, 0); break; } int h = emote == EMOTE_BLINK ? (int)(basesize/3) : (int)(basesize); - gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize, h); - gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, -basesize, h); + gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize*1.5f, h*1.5f); + gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, -basesize*1.5f, h*1.5f); } } // draw feet - select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, shift*4); + select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, 0); keyframe *foot = f ? &anim->front_foot : &anim->back_foot; - float w = basesize*2.5f; - float h = basesize*1.425f; + float w = basesize*2.5f*1.5f; + float h = basesize*1.425f*1.5f; gfx_quads_setrotation(foot->angle*pi*2); gfx_quads_draw(position.x+foot->x, position.y+foot->y, w, h); @@ -1249,10 +1310,10 @@ static void render_player( intratick = client_intrapredtick(); } - int skin = charids[info.clientid]; - - if(gametype != GAMETYPE_DM) - skin = info.team*9; // 0 or 9 + // TODO: proper skin selection + int skin_id = client_datas[info.clientid].skin_id; //charids[info.clientid]; + //if(gametype != GAMETYPE_DM) + //skin_id = info.team*9; // 0 or 9 vec2 direction = get_direction(player.angle); float angle = player.angle/256.0f; @@ -1317,7 +1378,7 @@ static void render_player( gfx_quads_setrotation(0); gfx_quads_end(); - render_hand(skin, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); + render_hand(skin_id, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); } // draw gun @@ -1437,9 +1498,9 @@ static void render_player( switch (player.weapon) { - case WEAPON_GUN: render_hand(skin, p, direction, -3*pi/4, vec2(-15, 4)); break; - case WEAPON_SHOTGUN: render_hand(skin, p, direction, -pi/2, vec2(-5, 4)); break; - case WEAPON_ROCKET: render_hand(skin, p, direction, -pi/2, vec2(-4, 7)); break; + case WEAPON_GUN: render_hand(skin_id, p, direction, -3*pi/4, vec2(-15, 4)); break; + case WEAPON_SHOTGUN: render_hand(skin_id, p, direction, -pi/2, vec2(-5, 4)); break; + case WEAPON_ROCKET: render_hand(skin_id, p, direction, -pi/2, vec2(-4, 7)); break; } } @@ -1448,11 +1509,13 @@ static void render_player( if(info.local && config.debug) { vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); - render_tee(&state, 15, player.emote, direction, ghost_position); // render ghost + tee_render_info ghost = client_datas[info.clientid].skin_info; + ghost.color.a = 0.5f; + render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost } // render the tee - render_tee(&state, skin, player.emote, direction, position); + render_tee(&state, &client_datas[info.clientid].skin_info, player.emote, direction, position); if(player.state == STATE_CHATTING) { @@ -1785,7 +1848,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) gfx_pretty_text(x+w-tw-35, y, font_size, buf, -1); // render avatar - render_tee(&idlestate, info->clientid, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); + render_tee(&idlestate, &client_datas[info->clientid].skin_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); y += 50.0f; } } @@ -1882,7 +1945,7 @@ void render_world(float center_x, float center_y, float zoom) const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); if(prev && prev_info && info) { - client_datas[((const obj_player_info *)data)->clientid].team = ((const obj_player_info *)data)->team; + client_datas[((const obj_player_info *)info)->clientid].team = ((const obj_player_info *)info)->team; render_player( (const obj_player_character *)prev, (const obj_player_character *)data, @@ -1905,6 +1968,22 @@ void render_world(float center_x, float center_y, float zoom) damageind.render(); } +static void next_skin() +{ + int skin_id = 0; + for(int i = 0; i < num_skins; i++) + { + if(strcmp(config.player_skin, skins[i].name) == 0) + { + skin_id = (i+1)%num_skins; + break; + } + } + + config_set_player_skin(&config, skins[skin_id].name); + send_info(false); +} + static void do_input(int *v, int key) { *v += inp_key_presses(key) + inp_key_releases(key); @@ -1915,6 +1994,9 @@ static void do_input(int *v, int key) void render_game() { + if(inp_key_down('L')) + next_skin(); + float width = 400*3.0f; float height = 300*3.0f; @@ -2319,8 +2401,8 @@ void render_game() // render victim tee x -= 24.0f; - int skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].victim].team : killmsgs[r].victim; - render_tee(&idlestate, skin, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); + //int skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].victim].team : killmsgs[r].victim; + render_tee(&idlestate, &client_datas[killmsgs[r].victim].skin_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); x -= 32.0f; // render weapon @@ -2337,8 +2419,8 @@ void render_game() // render killer tee x -= 24.0f; - skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].killer].team : killmsgs[r].killer; - render_tee(&idlestate, skin, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); + //skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].killer].team : killmsgs[r].killer; + render_tee(&idlestate, &client_datas[killmsgs[r].killer].skin_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); x -= 32.0f; // render killer name @@ -2532,6 +2614,7 @@ extern "C" void modc_render() render_game(); // handle team switching + // TODO: FUGLY!!! if(config.team != -10) { msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL); @@ -2586,11 +2669,33 @@ extern "C" void modc_message(int msg) else snd_play(CHN_GUI, data->sounds[SOUND_CHAT_SERVER].sounds[0].id, 0); } - else if(msg == MSG_SETNAME) + else if(msg == MSG_SETINFO) { int cid = msg_unpack_int(); const char *name = msg_unpack_string(); + const char *skinname = msg_unpack_string(); + int color = msg_unpack_int(); + (void)color; strncpy(client_datas[cid].name, name, 64); + strncpy(client_datas[cid].skin_name, skinname, 64); + client_datas[cid].skin_info.color = vec4(1,1,1,1); //color; + + // find new skin + client_datas[cid].skin_id = 0; + for(int i = 0; i < num_skins; i++) + { + if(strcmp(skins[i].name, client_datas[cid].skin_name) == 0) + { + client_datas[cid].skin_id = i; + break; + } + } + + client_datas[cid].skin_info.texture = skins[client_datas[cid].skin_id].org_texture; + } + else if(msg == MSG_READY_TO_ENTER) + { + client_entergame(); } else if(msg == MSG_KILLMSG) { @@ -2609,5 +2714,28 @@ extern "C" void modc_message(int msg) } } +extern "C" void modc_connected() +{ + // init some stuff + col_init(32); + img_init(); + tilemap_init(); + chat_reset(); + + proj_particles.reset(); + + for(int i = 0; i < MAX_CLIENTS; i++) + { + client_datas[i].name[0] = 0; + client_datas[i].team = 0; + client_datas[i].emoticon = 0; + client_datas[i].emoticon_start = -1; + } + + for(int i = 0; i < killmsg_max; i++) + killmsgs[i].tick = -100000; + + send_info(true); +} extern "C" const char *modc_net_version() { return TEEWARS_NETVERSION; } diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp index 48f7147c1..afcb1cfe1 100644 --- a/src/game/client/menu.cpp +++ b/src/game/client/menu.cpp @@ -1303,7 +1303,7 @@ static int settings_sound_render() } extern void draw_round_rect(float x, float y, float w, float h, float r); -void send_changename_request(const char *name); +extern void send_info(bool); static int settings_render(bool ingame) { @@ -1344,10 +1344,13 @@ static int settings_render(bool ingame) if (ui_do_button(&save_button, "Save", 0, 482, 490, 128, 48, draw_teewars_button, 0)) { // did we change our name? - if (ingame && strcmp(config.player_name, config_copy.player_name) != 0) - send_changename_request(config_copy.player_name); + bool name_changed = strcmp(config.player_name, config_copy.player_name) != 0; config = config_copy; + + if (ingame && name_changed) + send_info(false); + #ifdef CONF_PLATFORM_MACOSX config_save("~/.teewars"); #else diff --git a/src/game/game_protocol.h b/src/game/game_protocol.h index 6be89e35d..982a14b23 100644 --- a/src/game/game_protocol.h +++ b/src/game/game_protocol.h @@ -38,15 +38,17 @@ enum enum { MSG_NULL=0, - MSG_SAY, - MSG_CHAT, - MSG_SETNAME, - MSG_KILLMSG, + MSG_SAY, // client -> server + MSG_CHAT, // server -> client + MSG_SETINFO, // server -> client - contains name, skin and color info + MSG_KILLMSG, // server -> client MSG_SETTEAM, MSG_JOIN, MSG_QUIT, MSG_EMOTICON, - MSG_CHANGENAME, + MSG_STARTINFO, // client -> server + MSG_CHANGEINFO, // client -> server + MSG_READY_TO_ENTER // server -> client }; enum diff --git a/src/game/game_variables.h b/src/game/game_variables.h index 352675bae..32e277f19 100644 --- a/src/game/game_variables.h +++ b/src/game/game_variables.h @@ -39,6 +39,9 @@ MACRO_CONFIG_INT(dynamic_camera, 1, 0, 1) MACRO_CONFIG_INT(warmup, 0, 0, 0) MACRO_CONFIG_INT(team, -10, -1, 0) +MACRO_CONFIG_INT(player_color, -1, -1, 256) +MACRO_CONFIG_STR(player_skin, 64, "default") + MACRO_CONFIG_INT(dbg_new_gui, 0, 0, 1) diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp index 8aaa9ab27..f88eefa9a 100644 --- a/src/game/server/game_server.cpp +++ b/src/game/server/game_server.cpp @@ -355,11 +355,6 @@ player::player() void player::init() { proximity_radius = phys_size; - name[0] = 'n'; - name[1] = 'o'; - name[2] = 'o'; - name[3] = 'b'; - name[4] = 0; client_id = -1; team = -1; // -1 == spectator extrapowerflags = 0; @@ -406,7 +401,6 @@ void player::set_weapon(int w) active_weapon = w; } - void player::respawn() { spawning = true; @@ -504,9 +498,8 @@ void player::try_respawn() weapons[WEAPON_GUN].got = true; weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo; - weapons[WEAPON_SNIPER].got = true; - weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo; - + //weapons[WEAPON_SNIPER].got = true; + //weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo; active_weapon = WEAPON_GUN; last_weapon = WEAPON_HAMMER; @@ -1006,7 +999,9 @@ void player::die(int killer, int weapon) { gameobj->on_player_death(this, get_player(killer), weapon); - dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d", killer, players[killer].name, client_id, name, weapon); + dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d", + killer, server_clientname(killer), + client_id, server_clientname(client_id), weapon); // send the kill message msg_pack_start(MSG_KILLMSG, MSGFLAG_VITAL); @@ -1292,7 +1287,8 @@ void powerup::tick() if(respawntime >= 0) { - dbg_msg("game", "pickup player='%d:%s' item=%d/%d", pplayer->client_id, pplayer->name, type, subtype); + dbg_msg("game", "pickup player='%d:%s' item=%d/%d", + pplayer->client_id, server_clientname(pplayer->client_id), type, subtype); spawntick = server_tick() + server_tickspeed() * respawntime; } } @@ -1448,7 +1444,7 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) void send_chat(int cid, int team, const char *msg) { if(cid >= 0 && cid < MAX_CLIENTS) - dbg_msg("chat", "%d:%d:%s: %s", cid, team, players[cid].name, msg); + dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), msg); else dbg_msg("chat", "*** %s", msg); @@ -1523,17 +1519,15 @@ void mods_client_input(int client_id, void *input) } } -void send_set_name(int cid, const char *old_name, const char *new_name) +void send_info(int who, int to_who) { - msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL); - msg_pack_int(cid); - msg_pack_string(new_name, 64); + msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL); + msg_pack_int(who); + msg_pack_string(server_clientname(who), 64); + msg_pack_string(players[who].skin_name, 64); + msg_pack_int(players[who].skin_color); msg_pack_end(); - server_send_msg(-1); - - char msg[256]; - sprintf(msg, "*** %s changed name to %s", old_name, new_name); - send_chat(-1, -1, msg); + server_send_msg(to_who); } void send_emoticon(int cid, int emoticon) @@ -1547,21 +1541,21 @@ void send_emoticon(int cid, int emoticon) void mods_client_enter(int client_id) { - players[client_id].init(); - players[client_id].client_id = client_id; world->insert_entity(&players[client_id]); players[client_id].respawn(); + dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id)); + + char buf[512]; + sprintf(buf, "%s has joined the game", server_clientname(client_id)); + send_chat(-1, -1, buf); +} - CLIENT_INFO info; // fetch login name - if(server_getclientinfo(client_id, &info)) - { - strcpy(players[client_id].name, info.name); - } - else - strcpy(players[client_id].name, "(bot)"); +void mods_connected(int client_id) +{ + players[client_id].init(); + players[client_id].client_id = client_id; - - dbg_msg("game", "join player='%d:%s'", client_id, players[client_id].name); + //dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id)); // Check which team the player should be on if(gameobj->gametype == GAMETYPE_DM) @@ -1570,9 +1564,10 @@ void mods_client_enter(int client_id) players[client_id].team = gameobj->getteam(client_id); // - msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL); + /* + msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL); msg_pack_int(client_id); - msg_pack_string(players[client_id].name, 64); + msg_pack_string(server_clientname(client_id), 64); msg_pack_end(); server_send_msg(-1); @@ -1580,26 +1575,23 @@ void mods_client_enter(int client_id) { if(players[client_id].client_id != -1) { - msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL); + msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL); msg_pack_int(i); - msg_pack_string(players[i].name, 64); + msg_pack_string(server_clientname(i), 64); msg_pack_end(); server_send_msg(client_id); } - } + }*/ - char buf[512]; - sprintf(buf, "%s has joined the game", players[client_id].name); - send_chat(-1, -1, buf); } void mods_client_drop(int client_id) { char buf[512]; - sprintf(buf, "%s has left the game", players[client_id].name); + sprintf(buf, "%s has left the game", server_clientname(client_id)); send_chat(-1, -1, buf); - dbg_msg("game", "leave player='%d:%s'", client_id, players[client_id].name); + dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id)); gameobj->on_player_death(&players[client_id], 0, -1); world->remove_entity(&players[client_id]); @@ -1623,18 +1615,50 @@ void mods_message(int msg, int client_id) // Switch team on given client and kill/respawn him players[client_id].set_team(msg_unpack_int()); } - else if (msg == MSG_CHANGENAME) + else if (msg == MSG_CHANGEINFO || msg == MSG_STARTINFO) { const char *name = msg_unpack_string(); + const char *skin_name = msg_unpack_string(); + int skin_color = msg_unpack_int(); // check for invalid chars const char *p = name; while (*p) - if (*p++ < 32) + { + if(*p < 32) return; + p++; + } - send_set_name(client_id, players[client_id].name, name); - strcpy(players[client_id].name, name); + + // + if(msg == MSG_CHANGEINFO && strcmp(name, server_clientname(client_id)) != 0) + { + char msg[256]; + sprintf(msg, "*** %s changed name to %s", server_clientname(client_id), name); + send_chat(-1, -1, msg); + } + + //send_set_name(client_id, players[client_id].name, name); + strncpy(players[client_id].skin_name, skin_name, 64); + server_setclientname(client_id, name); + players[client_id].skin_color = skin_color; + + if(msg == MSG_STARTINFO) + { + // send all info to this client + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(players[i].client_id != -1) + send_info(i, client_id); + } + + msg_pack_start(MSG_READY_TO_ENTER, MSGFLAG_VITAL); + msg_pack_end(); + server_send_msg(client_id); + } + + send_info(client_id, -1); } else if (msg == MSG_EMOTICON) { @@ -1742,8 +1766,9 @@ void mods_init() {*/ for(int i = 0; i < config.dbg_bots ; i++) { + mods_connected(MAX_CLIENTS-i-1); mods_client_enter(MAX_CLIENTS-i-1); - strcpy(players[MAX_CLIENTS-i-1].name, "(bot)"); + //strcpy(players[MAX_CLIENTS-i-1].name, "(bot)"); if(gameobj->gametype != GAMETYPE_DM) players[MAX_CLIENTS-i-1].team = i&1; } diff --git a/src/game/server/srv_common.cpp b/src/game/server/srv_common.cpp index 6d2abf0c7..638d31c6d 100644 --- a/src/game/server/srv_common.cpp +++ b/src/game/server/srv_common.cpp @@ -28,6 +28,7 @@ gameobject::gameobject() sudden_death = 0; round_start_tick = server_tick(); round_count = 0; + is_teamplay = false; } void gameobject::endround() diff --git a/src/game/server/srv_common.h b/src/game/server/srv_common.h index 1e5447531..46c17ed8c 100644 --- a/src/game/server/srv_common.h +++ b/src/game/server/srv_common.h @@ -121,6 +121,8 @@ protected: int warmup; int round_count; + bool is_teamplay; + public: int gametype; gameobject(); @@ -237,7 +239,8 @@ public: // int client_id; - char name[64]; + char skin_name[64]; + int skin_color; // input player_input previnput; @@ -287,7 +290,7 @@ public: void respawn(); void set_team(int team); - + bool is_grounded(); void set_weapon(int w); diff --git a/src/game/server/srv_ctf.cpp b/src/game/server/srv_ctf.cpp index 57d81aefb..c4cbd5749 100644 --- a/src/game/server/srv_ctf.cpp +++ b/src/game/server/srv_ctf.cpp @@ -21,6 +21,8 @@ gameobject_ctf::gameobject_ctf() // report massive failure } } + + is_teamplay = true; } void gameobject_ctf::on_player_spawn(class player *p) diff --git a/src/game/server/srv_tdm.cpp b/src/game/server/srv_tdm.cpp index ba3ff2384..c9e4c6860 100644 --- a/src/game/server/srv_tdm.cpp +++ b/src/game/server/srv_tdm.cpp @@ -2,6 +2,11 @@ #include "srv_common.h" #include "srv_tdm.h" +gameobject_tdm::gameobject_tdm() +{ + is_teamplay = true; +} + void gameobject_tdm::tick() { if(game_over_tick == -1) diff --git a/src/game/server/srv_tdm.h b/src/game/server/srv_tdm.h index 748c2e9ee..5caa00c31 100644 --- a/src/game/server/srv_tdm.h +++ b/src/game/server/srv_tdm.h @@ -2,5 +2,6 @@ class gameobject_tdm : public gameobject { public: + gameobject_tdm(); virtual void tick(); }; diff --git a/src/tools/crapnet.cpp b/src/tools/crapnet.cpp index 842a602d2..68e76fa44 100644 --- a/src/tools/crapnet.cpp +++ b/src/tools/crapnet.cpp @@ -97,12 +97,12 @@ int run(int port, NETADDR4 dest) // send and remove packet //if((rand()%20) != 0) // heavy packetloss - // net_udp4_send(socket, &p->send_to, p->data, p->data_size); + net_udp4_send(socket, &p->send_to, p->data, p->data_size); // update lag double flux = rand()/(double)RAND_MAX; int ms_spike = 0; - int ms_flux = 50; + int ms_flux = 20; int ms_ping = 50; current_latency = ((time_freq()*ms_ping)/1000) + (int64)(((time_freq()*ms_flux)/1000)*flux); // 50ms