From 85a0d4aa9a0676656effc6ae69b143375a8239e2 Mon Sep 17 00:00:00 2001
From: drallensmith <drallensmith@users.noreply.github.com>
Date: Sun, 6 Aug 2017 14:40:48 -0500
Subject: [PATCH] Revise feedback with enum, use of ACTION_STATUS_UNKNOWN when
 appropriate

---
 doc/manual.pdf                               | Bin 303244 -> 303230 bytes
 doc/manual.tex                               |   6 +-
 example/explore_offense_actions_fullstate.py | 141 ++++++++++++++---
 hfo/hfo.py                                   |   6 +-
 src/HFO.cpp                                  |   2 +-
 src/HFO.hpp                                  |   2 +-
 src/agent.cpp                                | 151 ++++++++++++-------
 src/agent.h                                  |  27 ++--
 src/bhv_basic_move.cpp                       |  30 +++-
 src/bhv_basic_move.h                         |   4 +-
 src/common.hpp                               |  43 +++++-
 11 files changed, 300 insertions(+), 112 deletions(-)

diff --git a/doc/manual.pdf b/doc/manual.pdf
index 7f9e2ac90a5957ea3186140037fff524b6364bf8..4a0b8719c0df7472ac4bdd7caf13dbf5d316ff45 100644
GIT binary patch
delta 4481
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
Q8lni3r4ST^n`l$~A0PZ?{{R30

delta 4464
zcmV-$5s&Wvz!HqX5`csOv;yZ(0yr|0Q3EKK5l{jr9FnM|WP828e(wc9ilitej`3iV
z1S#O);_%#iL6=le0w;eTk2#I9X`U|NOv~tGy3LE#=J@x^e?nDeL@7z6v{g|}1Q(+*
zV}vU0>iR9F+CNKM&r)JI9mVdc$%pZWbN3k4&Bp`)HA(f@cL0H@=-q0TPt$F-!Al)&
z=jqnn*v>O|lHO*kW4z@qH}m3dG4oHSpN^S{GIzBq{10reNMC=i#!?Z+Mq{v<5b7zt
z`uQ&3_H~LWB6+h@g3ETNpeseyxdUCw%6q)b%Bt(m2s(Pi?iF|L;vwJ6n-#(_E0_5S
z8tT;l(;KYrgS&7|-REVoTH?8hwq)1e9eKu55);Fab54{LHGQO~&&hhdfL>iMvL5oZ
zjS{zcbBVZEqAh;|al9M@v81X5E=-h`{<(DVfS6PK_qg$8jpp&;-(neKbvi1x-kMk|
zjTVo-w)MI!)@2UnfoCa!p@Cj_EGD|Pzs(i}{`A4MvE5al?}iZXJj^q&Zi$`6-ZlAC
z*c)Rmv}fMNUtn**xGm&(1CbXigo#)AjXPp3S?8CQ(fEH0%Eja_zTOJi414uGlt~>;
zu@m#m9zMCp8vQfaKi`Hw*`c{9%Fa#Ki@vU=*Vkos4;J;kL@KXl?qmhSu<^tK;YdiL
zm_jn>m<VZr5eAC5tLUU|;^-fjNB=p(*DM|(9Sw;oA4vlo6v=41Jo@$bcr=5X0EY0y
zj2`TxOMHLa5^l5@T^#*<^a|Cm)h?BsBngGOG-2HL;4}p`Gb*CXW5c66ypYme;2ohv
z^nM=}1L?x1Lcn4&CJE<lSnn?pNgPLK)yXNID3I%S`*1k0ISykaE)DpKq>bhbn>H%C
zfFmeEbPh)e$I}u`WJL5Dk1~!vBDdaFi19?wB&vUoXXpFSorgl?LJk3!T!OP;aPE-r
z*Fd2L{gf*9I}gr)B0)4G1{{;^`$e|E7n1YHX;rbwEmdt%Zsqg-7$}o2^4S1?RYEun
z(ewBV+ABNou5f4)?v9!@j)zGb01K0XD3!FaOu#@fj58dm);gN}2q&B~JUPhO0ARR;
zI@Et27Am-M7?6$j1WV9DhSCVH6HqsNGSSo?4ftw%RPX~Ucw-(j62}^J&w=QW;@-y_
z;ARRduu}*NtfOudM177RQiJ0)VF;p7QAEQK;1RAWLo`ngb0h#925@4@+i;+9My2sw
z;m+D1C6mJp2>_*HNY^km4?w$q^w-Td$;5x=^ZWpdDbwc1t8}p#6b=1FoDd*b2@Ass
zs58+$qG4Z&>fM+OFd_h$S~Z$rD%H69az+GzQZb@~#EyLPD7bE#2cdN(!<WlsM+pvr
zvpPfx7upZY1^N>RT?g3#VL6}+!w$$0V<rx}6!)SWCPx4)wOll@RB};~1F=YD20bE5
z04yAYLW_MY)((5Fr7f+}n+yqZ<u&8VYsQr)2xWwc4wsZv0wF3=t40S)OEs>%YFr)W
zMF1$3YBZ5dI@Z`zjVrGjZBqDhnbf3+LDiV)Czsz;0v~^x5gjZ~Wkdid6(jbn(qV+s
zd@r(agoxXOXsASN2-mDlh!1NYQLOyb%^|7yqO?RLnt)z~Ax2CINcC3}BLtS37#%DX
zF>G4mR9cw<W`w{}F{24((haz-`U-a3*!LiHh!K-+QUcU?o=gZMiK1a-LYRcG`0HgN
z1eS^oT`Yf3l!*{fJQ?<_(z3?WWMXn?HU$9-`pmfy1LG*bc3Kf5l5Pz9Dfd&0NGhB<
zJWMLh2~%NaK3ZVDhExHt)THWQ*&|gVcyu^Q4FLtCR29oMly6Yw5<SSOL?|0sGm*Fm
zn{t;1Cv`N!5=ykvhjN%zv325NiD15n2#OMLX<>hepae0A7$(9%G8+O*O@t<v$<x&(
z0F+8y_N>xLW|0SzrvxFr>H>gioIFomfN>-?U_1$R3hE%g!C<#6{+A7W2oRXCOA&@e
z&BiC5Mf;NghglQ=OU<GVmi>uToAw^2Q2;DlYCF~0#?qYp=ti@38Z7;6$iS=!1FvLg
zr6_;?%fjno0U=4gx^=Sh@bVfZ=J4oqML?v&jJ}A8G;&`<+LMBZM?V0TYR;pD#kS3u
ziwP6zq&hZq$eRSfQq6hnWAT%t2aW)(@+PL~O&I0IK}K(q5Yx$I_J)4FNYRx%`Y+#y
zNr2h62qXc_5Y>ps>X~w>WmFv}Lo5gYhQWXP#^KFqf^lz^&@C2F9jo4H`-%nuz|=Ho
zfax23G)&V{T^djg!*3tZitl*9NDMsv3=#aC`F4N<-hTw)098b3**`Vj{C;$p1Od?0
zBxs_st!rc9Fe;h<XvK%(i2zt?4m7cRg%p50aG7h8m_GIL0R?s6?VcG>#E@pgP{e<N
zaOQp2hu?rJ*=jQsl|mw|xeP<3X4~DUbn*r1NdPQ$Jki1O)TlH7lqxFSv&uluJ86A%
zi|bgTGyQ@7L~!2Lk<;u3$NJk&hH_h^i+q3q+!&(6q$M2WjVpCHE%AzSkO2X(R65ea
z($bOUN4CQZ2mr+sVBabOX~|@lmN0+FGFmFqm@H>T6G(U31bFL4+73UishT-L;IgQJ
z;m72eg%JR5Vj?IV_{jP>PZ9!6&44DFuVFv{ER`o|VQGFyJCvFpn4;JPmE9$VV@?fW
z3^f6W8#6x}Vi#b>Zj~RWGCC{VS2Vv$6ymCBv0S=EYj8W?xT8}KxLam;KU;szvSS*}
zT$x)T2Tv8=zvS+dt}C=*tggaXU!PxI2WNJvCR9?-pt;ftALc)(VAMp{cUxCBO;_&3
zE`lsd{~LtSvnJ26eg}!E4kYM^UtEhXiR%om9WC?Q+pKhP7%t?imehKjG+Ov|lLM=R
zIRqc^-a6X$NVV6|o~GZ~g>8RuvYCJHn!Y@SZ0F9G!v%}(%GLJ{kG)KH_h^*58K_0(
zpLp+YzOO9Yx9-=2II!?{2=M#Mp87l50u)s6TRTe+tRHxTIFYmy*K``U3und1rcl)z
zWQ|bx{+?BUTHM|Tm0)rp!+=T*2%a7Qby|TsE%WQ%c|it}00~YIJj{Ox$fL~wo_8M3
zJGU}8E2r6d+sh1)971u~v!#Z73N_BU0|Boawy%=t!r!`>7k-Vhzj1DF;F?Mpwsf<>
zVhDUr%eMXe)31H$>vZdu`1<mXc=6WX{Fu$|raczt2>=(#2xnrXlFza@2Q~>sZC$l<
zKUv-OjWnjEI#9cUC4@V5+jS$|)3D%#B{EFI0=!|Y+YMvH;YZ-Kvc3&Nd%m(s4)2T>
zLBL4JoFLcg17pJ@p`pUKBX1SJw>_62S^^e-@CZR$b}@L6c0nl<-D(y;Sa_duR=sFv
zDSE&j)n+k+Y*z)r!eT|JX@fa$d*OP=g(i^N3+I&-hwM#*A2skZzgq&7$8ESc&F+tJ
zzs{mqJ1-4!aq13}?7?rsz?~$VMcYH$Fcbl?^f4j+2-36N_LGgfUV5PR!tWb!7qiTN
zxfg)oc5cjEdA@ST*DqeU6O1bGc>cHr#iP-R9FHL{Mg85CufD}S7#w8J6)p<wmPO=C
zY+QsV^P8e>$qD#PI<4+iPkX3Y?_Py`wb=q4vKclijjtN)+1Px8mu@Epo~^QMhBc!(
z3%`+}y(7p_qFAN=`Ep&9P>G}tZqERJD4b8x)er2xkFu{~76SuS_1sNaEU{YYtbq0J
z+LF;Xy^aa8ZfSU<Dcta)W$Z=(y5xomx|wfXLB6TFJ<T?owDeZ!?>dkT-nK-wZT#1K
zHC^06tZYI4?WZ>%$b7y2q2F_IaGkX+Yy{3A!Aln#^pKG2W2B5Fi+uITm87?SDUPBm
zw&RDTn|WGh{?`RiK#J(kY`S$f7x{IGUFkEj&_u<xiQvhX@CPO)o8G}Q5Zmqs?_mzC
zv28+vu+9PG?RUL~0@K0^j(JH!Wa7Wl{@{l0_658eFWh<d-*mZNWG^3!yYi1!_V5St
za!aPT;0LWae&?Rslv7{uFIND6pnbu=7vGM{b-JDZ-IvK|yr`+z)f&hW?e4CI)O-Zr
zRc0#~|1Xe_U+M3_kR*;Spc6nY4r%+Vv@El2wV#ah=FhdZp1X>b(ocTMmql-mLAlBt
z+~&q*?{29y^Jx(jyjeVACMRfgats`v-KVQ5p4c6A$X&m-+TC?!KNWa?;g>{RViOq_
zq{|0Pp?dm<OZ}y(M;I5=#5_8mpJLzaeyB~pvB??r2_=;Nvht}`xv7@&x)nMKw1Fp`
ztzkEf1P2DZ+B4<%{hi!xwmFI-My!ns<@_i9z~B7k;>6!Mg|~Hy?RxR^*&O8f!j8g-
zad5HJ03wY4eQZp5<^TQ#4|j;_W`{Ig0*5qR1Gh9?1T-@SFgP+aF*%oRkOUnDFgP+a
zF*&!9kOW5yQaM6KFgZdoL_{z(H9|%~ML0AxFhxc*HbO)}IYvb}G(I3aIYLG-IYKc+
zL@+fqLPkMFI5adcMMg9>LPSA1MnyR^K3xhgOl59obZ8(kFfuliQ3EJ{C6!A|RaX>-
z_uBUsL_i)Y;0wi#f)7+g5K&RV7lMEaA|h|oS;w6<O*&}0)24MmVq!Fou!AN|8rz9Z
z*4)G<ooGj$7&~cA6HV->z2C2c&%M5T?%|yEx*>!=|BE5SV4>n}>A&FBrE~7a8Hl)b
zxFduGP{h^Xx(Gi4Ww>pBxWk0yU=40Nu9L6=ti>hVA;L;fg=@tfB&-JOaJz5^2x~ws
zZV#@5unyGY_Tu&vt_K@%`*8aRH-ZM-LEK)#M$m*igxf>732er7;@SzffUUU0xHiIV
zpc&VN+fBF~?7*GC?ILUeJ8>s*t%M11@@1StU0k}0CF+p*M${jFYR4H)x6(uMswv|5
zYf&$_A6LNXF_fGGxFU`xjY=%9nl|I~3MvY(mA2q`%cz1L!EMFq_0<eLIMtU7#iO7X
zcLt}_9Rq#1b2zdaj{{PY&f}E!lb|1W0Y_!xDR3G$j8n<ZfC1bHj;h8%a29tNr*fYI
z=fMSV5e$J#U>J;lfXiSMjDc}*1zZK!zyz2C*TEFH0j9xCFas9B5}3CTY8ae&3(WFV
zYk($Tj*}`wKgVSXuPI};T(iYQxh9G^a?KInbxjX5<C+;J#hHM(V4={fyHs)KYO}9D
zF3oS_2{}sU>clz=wfE)J!0K4Fw`PXaxh92VdxM3pe|0f`HS#74-9Ia&v`&wEi-j-S
z<<!*7o3~l`W>t=6&1-?inQh@67FOQsQ-;`k0G;E#fPV2l3qLdm{;`LA#%y>%-=K`%
zZQ=eO3XgMVrKum#FMb-(B|ZS?4L=L$2v@@?r)o3yRif}d3+BK)7_#vFhjdawrx~2i
z@nH);eWnk8XdkD2eAKM!6FJ>#+^qVYLK?~GA*Y9&9&&ofr_3hGbP0{*(`J)n3h5?a
zG<$eEnEn0>v!C?13ud1`)+I|kcm=5B(@j=*zoP3}K$+Rf7Ydtz7IGP<X29M}J3u+0
zClj|y)F@S&t$wQS(nG1#Ly!Ja$f{4Zpw8^o1G##CupVr%SpGzABWSQ#QLnHOXjXSx
z?EO)WEuUEHi9MdQ;o5-q8hboxo3W{rc320{=3-MP?JIV1(w1V|ChewfppA4CXb&9&
z+CH>O(#~P;CT*HiK>Ot)7_>OpqleTk83#ia$9|Q&1V%}x5^)7w1=qj?m;~3s6u1GV
z!A&rKV{vv$x4LC<wN0m4i_bq4dCuZL&vcr%Lf;FW7Oe2yZ#pen;puCgmaOpdE1j0D
zSpG&o4#A3d`b%i-RA^S5)(x_L66yfe$|NU~oJ?{u$;l)qYmW3Ar5`1dlSxh{Ia$k`
zGUh=*a<Z1WhDmco{_+qYO<C)D#ERekU3#hrdpZ0MoF@INmsOwyAPF`y3MC~)Peuy6
Ce`YcO

diff --git a/doc/manual.tex b/doc/manual.tex
index 2d763ff..62964be 100644
--- a/doc/manual.tex
+++ b/doc/manual.tex
@@ -622,13 +622,13 @@ Team. unum invalid      & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & N  &
 Opponent loc invalid    & Y  & Y  & Y  & Y  & Y  & Y  & Y? & Y  & N  & Y? & Y  & Y? & Y  & Y  & Y  & Y  & N \\
 Opp. unum invalid       & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & N \\
 \hline
-Ball kickable           & Y  & Y  & Y  & Y  & Y  & Y  & Y  & ?  & *  & Y  & Y  & Y  & Y  & ?  & ?  & ?  & Y \\
+Ball kickable           & Y  & Y  & Y  & Y  & Y  & Y  & Y  & N  & *  & Y  & Y  & Y  & Y  & ?  & ?  & N  & Y \\
 Ball not kickable       & Y  & Y  & Y  & N  & N  & Y  & Y  & Y  & Y  & N  & N  & N  & Y  & Y  & Y  & Y  & Y \\
 \hline
 Frozen                  & N  & N  & N  & N  & N  & N  & N? & N  & N? & N  & N  & Y  & N? & N  & N  & N  & N \\
-Colliding w/ball        & Y  & Y  & ?  & ?  & ?  & Y? & ?  & ?  & ?  & ?  & ?  & ?  & ?  & ?  & ?  & ?  & ? \\
+Colliding w/ball        & Y  & Y  & ?  & N  & Y  & Y  & Y  & Y  & ?  & ?  & ?  & ?  & ?  & ?  & ?  & N  & ? \\
 Colliding w/player      & Y  & Y? & ?  & N? & N? & Y? & ?  & Y? & ?  & ?  & ?  & Y? & ?  & ?  & ?  & Y? & ? \\
-Colliding w/post        & Y  & Y  & N? & N? & N? & Y  & ?  & Y  & ?  & ?  & ?  & ?  & ?  & ?  & ?  & Y  & ? \\
+Colliding w/post        & Y  & Y  & N? & N? & N? & Y  & Y  & Y  & Y  & ?  & ?  & Y  & ?  & Y  & Y  & Y  & Y \\
 \hline
 Offense                 & Y  & Y  & N  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & Y  & N  & N  & N  & Y  & N \\
 Defense, not goalie     & Y  & Y  & Y  & N? & N? & Y  & N  & Y  & Y  & N  & N  & N  & N  & Y  & ?  & Y  & Y \\
diff --git a/example/explore_offense_actions_fullstate.py b/example/explore_offense_actions_fullstate.py
index 75444a7..db55f11 100755
--- a/example/explore_offense_actions_fullstate.py
+++ b/example/explore_offense_actions_fullstate.py
@@ -284,7 +284,7 @@ def get_abs_x_y_pos(abs_angle, dist, self_x_pos, self_y_pos, warn=True, of_what=
       if dist < 10:
         raise RuntimeError("\n".join(error_strings))
       else:
-        if warn or (dist < 60):
+        if warn or (dist < 50):
           print("\n".join(error_strings), file=sys.stderr)
           sys.stderr.flush()
         return (None, None)
@@ -641,9 +641,36 @@ def evaluate_previous_action(hfo_env,
   action_status_observed = hfo.ACTION_STATUS_UNKNOWN # NOTE: Check intent + other bitflags!
 
   if namespace.action == hfo.DASH:
-    pass # TODO
+    if (namespace.intent !=
+      INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent !=
+          INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or
+                                                          ((not namespace.prestate_bit_list[4]) and bit_list[4])):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    else:
+      pass # TODO
   elif namespace.action == hfo.TURN:
-    if (namespace.prestate_self_dict['body_angle'] is not None) and (self_dict['body_angle'] is not None):
+    if (namespace.intent !=
+        INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent !=
+          INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or
+                                                          ((not namespace.prestate_bit_list[4]) and bit_list[4])):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.prestate_self_dict['body_angle'] is not None) and (self_dict['body_angle'] is not None):
       intended_body_angle = namespace.prestate_self_dict['body_angle'] + namespace.action_params[0]
       if get_angle_diff(namespace.prestate_self_dict['body_angle'],
                         intended_body_angle) > get_angle_diff(self_dict['body_angle'],
@@ -652,7 +679,15 @@ def evaluate_previous_action(hfo_env,
       else:
         action_status_observed = hfo.ACTION_STATUS_BAD
   elif namespace.action == hfo.KICK:
-    pass # TODO
+    if bit_list[4]:
+      if namespace.prestate_bit_list[2] and (not bit_list[2]):
+        action_status_observed = hfo.ACTION_STATUS_MAYBE
+      elif namespace.prestate_bit_list[3] and (not bit_list[3]):
+        action_status_observed = hfo.ACTION_STATUS_MAYBE
+      else:
+        action_status_observed = hfo.ACTION_STATUS_BAD
+    else:
+      pass # TODO
   elif namespace.action == hfo.KICK_TO:
     if (namespace.prestate_ball_dict['x_pos'] is not None) and (ball_dict['x_pos'] is not None):
       dist_before = get_dist_real(namespace.prestate_ball_dict['x_pos'],
@@ -665,10 +700,30 @@ def evaluate_previous_action(hfo_env,
                                  namespace.action_params[1])
       if dist_before > dist_after:
         action_status_observed = hfo.ACTION_STATUS_MAYBE
+      elif bit_list[4]:
+        if namespace.prestate_bit_list[2] and (not bit_list[2]):
+          action_status_observed = hfo.ACTION_STATUS_MAYBE
+        elif namespace.prestate_bit_list[3] and (not bit_list[3]):
+          action_status_observed = hfo.ACTION_STATUS_MAYBE
+        else:
+          action_status_observed = hfo.ACTION_STATUS_BAD
       else:
         action_status_observed = hfo.ACTION_STATUS_BAD
   elif namespace.action == hfo.MOVE_TO:
-    if (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None):
+    if (namespace.intent !=
+        INTENT_GOAL_COLLISION) and namespace.prestate_bit_list[3] and (not bit_list[3]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent !=
+          INTENT_BALL_COLLISION) and namespace.prestate_bit_list[2] and (not bit_list[2]):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_KICKABLE) and (not namespace.prestate_bit_list[4]) and bit_list[4]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_GOAL_COLLISION) and (not namespace.prestate_bit_list[3]) and bit_list[3]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_COLLISION) and (((not namespace.prestate_bit_list[2]) and bit_list[2]) or
+                                                          ((not namespace.prestate_bit_list[4]) and bit_list[4])):
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None):
       dist_before = get_dist_real(namespace.prestate_self_dict['x_pos'],
                                   namespace.prestate_self_dict['y_pos'],
                                   namespace.action_params[0],
@@ -685,6 +740,10 @@ def evaluate_previous_action(hfo_env,
     if namespace.prestate_bit_list[4]:
       if not bit_list[4]:
         action_status_observed = hfo.ACTION_STATUS_BAD
+      elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision
+        action_status_observed = hfo.ACTION_STATUS_MAYBE
+      elif namespace.prestate_bit_list[2] and (not bit_list[2]): # ball collision
+        action_status_observed = hfo.ACTION_STATUS_MAYBE
       elif (namespace.prestate_self_dict['x_pos'] is not None) and (self_dict['x_pos'] is not None):
         dist_before = get_dist_real(namespace.prestate_self_dict['x_pos'],
                                     namespace.prestate_self_dict['y_pos'],
@@ -700,6 +759,10 @@ def evaluate_previous_action(hfo_env,
           action_status_observed = hfo.ACTION_STATUS_BAD
     elif bit_list[4]:
       action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif namespace.prestate_bit_list[2] and (not bit_list[2]): # ball collision
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
     elif namespace.prestate_ball_dict['dist'] > ball_dict['dist']:
       action_status_observed = hfo.ACTION_STATUS_MAYBE
     elif namespace.prestate_ball_dict['dist'] < ball_dict['dist']:
@@ -709,11 +772,20 @@ def evaluate_previous_action(hfo_env,
   elif (namespace.action == hfo.INTERCEPT) or (namespace.action == hfo.GO_TO_BALL):
     if namespace.prestate_bit_list[4]:
       if bit_list[4]:
-        action_status_observed = hfo.ACTION_STATUS_MAYBE
+        if (namespace.intent != INTENT_BALL_COLLISION) and bit_list[2]:
+          action_status_observed = hfo.ACTION_STATUS_BAD
+        elif (namespace.intent != INTENT_GOAL_COLLISION) and bit_list[3]:
+          action_status_observed = hfo.ACTION_STATUS_BAD
+        else:
+          action_status_observed = hfo.ACTION_STATUS_MAYBE
       else:
         action_status_observed = hfo.ACTION_STATUS_BAD
     elif bit_list[4]:
       action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif namespace.prestate_bit_list[3] and (not bit_list[3]): # goal collision
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
+    elif (namespace.intent == INTENT_BALL_COLLISION) and (not namespace.prestate_bit_list[2]) and bit_list[2]:
+      action_status_observed = hfo.ACTION_STATUS_MAYBE
     elif namespace.prestate_ball_dict['dist'] > ball_dict['dist']:
       action_status_observed = hfo.ACTION_STATUS_MAYBE
     elif namespace.prestate_ball_dict['dist'] < ball_dict['dist']:
@@ -759,16 +831,18 @@ def evaluate_previous_action(hfo_env,
     namespace.struct_tried[pack_action_bit_list(namespace.action,namespace.prestate_bit_list)] += 1
     # further analysis...
 
-  # further analysis...
-  if namespace.prestate_bit_list[3] and (namespace.action in (hfo.DASH, hfo.MOVE_TO)) and (action_status_guessed == hfo.ACTION_STATUS_MAYBE):
-    print("OK status from {0!s} despite goal collision in prestate (poststate: {1!s})".format(
-      action_string, bit_list[3]))
-    sys.stdout.flush()
-  
-  if namespace.prestate_bit_list[2] and (namespace.action in (hfo.DASH, hfo.TURN, hfo.MOVE_TO)) and (action_status_guessed == hfo.ACTION_STATUS_MAYBE):
-    print("OK status from {0!s} despite ball collision in prestate (poststate: {1!s})".format(
-      action_string, bit_list[2]))
-    sys.stdout.flush()
+  if action_status_guessed == hfo.ACTION_STATUS_MAYBE:
+    # further analysis...
+    if namespace.prestate_bit_list[3] and (namespace.action in (hfo.KICK, hfo.KICK_TO)):
+      print("OK status from {0!s} despite goal collision in prestate (poststate: {1!s})".format(
+        action_string, bit_list[3]))
+      sys.stdout.flush()
+      
+    if namespace.prestate_bit_list[2] and (namespace.action in (hfo.KICK, hfo.MOVE_TO,
+                                                                hfo.GO_TO_BALL)):
+      print("OK status from {0!s} despite ball collision in prestate (poststate: {1!s})".format(
+        action_string, bit_list[2]))
+      sys.stdout.flush()
 
 def save_action_prestate(action,
                          prestate_bit_list,
@@ -886,6 +960,8 @@ def do_intent(hfo_env,
       poss_actions_list.append(hfo.TURN)
     if abs(ball_rel_angle) < 1.0:
       poss_actions_list.append(hfo.DASH)
+    if bit_list[0] and (ball_dict['x_pos'] is not None):
+      poss_actions_list.append(hfo.MOVE_TO)
 
     action = determine_which_action(poss_actions_list, namespace, bit_list)
 
@@ -899,6 +975,11 @@ def do_intent(hfo_env,
       hfo_env.act(*save_action_prestate(action=hfo.DASH,
                                         action_params=[80, ball_rel_angle],
                                         **prestate_dict))
+    elif action == hfo.MOVE_TO:
+      hfo_env.act(*save_action_prestate(action=hfo.MOVE_TO,
+                                        action_params=[ball_dict['x_pos'],
+                                                       ball_dict['y_pos']],
+                                        **prestate_dict))
     else:
       raise RuntimeError("Unknown action {0!r}".format(action))
 
@@ -1023,13 +1104,15 @@ def do_next_action(hfo_env,
 
   # figure out what to do next
 
-  if not (bit_list[2] or bit_list[3] or bit_list[4]):
+  if not (bit_list[2] or bit_list[3]):
     poss_intent_set = set([INTENT_BALL_KICKABLE,INTENT_BALL_COLLISION,INTENT_GOAL_COLLISION])
     if not bit_list[5]:
       poss_intent_set.remove(INTENT_BALL_KICKABLE)
       poss_intent_set.remove(INTENT_BALL_COLLISION)
     if not bit_list[0]:
       poss_intent_set.remove(INTENT_GOAL_COLLISION)
+    if bit_list[4]:
+      poss_intent_set.remove(INTENT_BALL_KICKABLE)
     if not poss_intent_set:
       raise NotImplementedError("Not yet set up for self+ball location invalid")
     
@@ -1044,14 +1127,22 @@ def do_next_action(hfo_env,
     
     return do_intent(hfo_env, state, namespace)
 
-  elif bit_list[4]: # kickable
-    actions_want_check = set([hfo.INTERCEPT, hfo.GO_TO_BALL])
-    if bit_list[2] or bit_list[3]:
-      actions_want_check |= set([hfo.KICK, hfo.KICK_TO])
-  else: # colliding
-    actions_want_check = set([hfo.DASH, hfo.TURN, hfo.KICK, hfo.KICK_TO,
-                             hfo.MOVE_TO, hfo.DRIBBLE_TO, hfo.INTERCEPT,
-                             hfo.GO_TO_BALL])
+##  elif bit_list[4]: # kickable
+##    actions_want_check = set([hfo.INTERCEPT, hfo.GO_TO_BALL])
+##    if bit_list[2] or bit_list[3]:
+##      actions_want_check |= set([hfo.KICK, hfo.KICK_TO])
+  elif bit_list[2]: # colliding with ball
+    actions_want_check = set([hfo.GO_TO_BALL])
+    if bit_list[3]: # colliding with goal
+      actions_want_check |= set([hfo.KICK, hfo.KICK_TO, hfo.DRIBBLE_TO])
+  else: # colliding with goal
+    actions_want_check = set([hfo.KICK, hfo.KICK_TO, hfo.DRIBBLE_TO])
+
+  if prior_intent is not None:
+    print("INTENT: WAS {}".format(INTENT_DICT[prior_intent]))
+  else:
+    print("INTENT: NONE")
+  sys.stdout.flush()
 
   if bit_list[4] and (prior_intent not in (None, INTENT_BALL_KICKABLE)):
     namespace.intent_done[INTENT_BALL_KICKABLE] += 1
diff --git a/hfo/hfo.py b/hfo/hfo.py
index 7e5c8b8..feaf774 100644
--- a/hfo/hfo.py
+++ b/hfo/hfo.py
@@ -68,9 +68,6 @@ STATUS_STRINGS = {IN_GAME: "InGame",
                   OUT_OF_TIME: "OutOfTime",
                   SERVER_DOWN: "ServerDown"}
 
-"""Possible sides."""
-RIGHT, NEUTRAL, LEFT = list(range(-1,2))
-
 """Possible action result statuses."""
 ACTION_STATUS_UNKNOWN, ACTION_STATUS_BAD, ACTION_STATUS_MAYBE = list(range(-1,2))
 ACTION_STATUS_MAYBE_OK = ACTION_STATUS_MAYBE # typos
@@ -78,6 +75,9 @@ ACTION_STATUS_STRINGS = {ACTION_STATUS_UNKNOWN: "Unknown",
                          ACTION_STATUS_BAD: "Bad",
                          ACTION_STATUS_MAYBE: "MaybeOK"}
 
+"""Possible sides."""
+RIGHT, NEUTRAL, LEFT = list(range(-1,2))
+
 class Player(Structure): pass
 Player._fields_ = [
     ('side', c_int),
diff --git a/src/HFO.cpp b/src/HFO.cpp
index 47d47f3..dda1c6e 100644
--- a/src/HFO.cpp
+++ b/src/HFO.cpp
@@ -123,7 +123,7 @@ int HFOEnvironment::getNumOpponents() {
   return agent->getNumOpponents();
 }
 
-int HFOEnvironment::getLastActionStatus(action_t last_action) {
+action_status_t HFOEnvironment::getLastActionStatus(action_t last_action) {
   return agent->getLastActionStatus(last_action);
 }
 
diff --git a/src/HFO.hpp b/src/HFO.hpp
index ced8384..c64daf7 100644
--- a/src/HFO.hpp
+++ b/src/HFO.hpp
@@ -55,7 +55,7 @@ class HFOEnvironment {
   // Returns the number of opponents
   virtual int getNumOpponents();
 
-  virtual int getLastActionStatus(action_t last_action);
+  virtual action_status_t getLastActionStatus(action_t last_action);
 
   // Get the current player holding the ball
   virtual Player playerOnBall();
diff --git a/src/agent.cpp b/src/agent.cpp
index 10d418b..3ac3df2 100644
--- a/src/agent.cpp
+++ b/src/agent.cpp
@@ -153,7 +153,7 @@ Agent::Agent()
 
     // setup last_action variables
     last_action_with_status = NOOP;
-    last_action_status = -1;
+    last_action_status = ACTION_STATUS_UNKNOWN;
 }
 
 Agent::~Agent() {
@@ -166,20 +166,27 @@ int Agent::getUnum() {
   return world().self().unum();
 }
 
-int Agent::getLastActionStatus(action_t last_action) {
+action_status_t Agent::getLastActionStatus(action_t last_action) {
   if (last_action == last_action_with_status) {
     return last_action_status;
   } else {
-    return -1;
+    return ACTION_STATUS_UNKNOWN;
   }
 }
 
-void Agent::addLastActionStatus(action_t last_action, bool action_status) {
+void Agent::addLastActionStatus(action_t last_action, action_status_t action_status) {
   last_action_with_status = last_action;
-  if (action_status) {
-    last_action_status = 1;
+  last_action_status = action_status;
+}
+
+void Agent::addLastActionStatusCollision(action_t last_action, bool may_fix, bool likely_success) {
+  last_action_with_status = last_action;
+  if (likely_success) {
+    last_action_status = ACTION_STATUS_MAYBE;
+  } else if (may_fix) {
+    last_action_status = ACTION_STATUS_UNKNOWN;
   } else {
-    last_action_status = 0;
+    last_action_status = ACTION_STATUS_BAD;
   }
 }
 
@@ -268,42 +275,55 @@ void Agent::actionImpl() {
               << " parameters, given " << params.size() << std::endl;
     exit(1);
   }
+
+  // For now let's not worry about turning the neck or setting the vision.
+  // But do the settings now, so that doesn't override any set by the actions below.
+  // TODO: Add setViewActionDefault, setNeckActionDefault to librcsc that only set if not already set.
+  this->setViewAction(new View_Tactical());
+  this->setNeckAction(new Neck_TurnToBallOrScan());
+
+  const WorldModel & wm = this->world();
+  bool may_fix = wm.self().collidesWithPost();
+
   switch(requested_action) {
     case DASH:
-      addLastActionStatus(DASH, this->doDash(params[0], params[1]));
+      addLastActionStatusCollision(DASH, may_fix, this->doDash(params[0], params[1]));
       break;
     case TURN:
-      addLastActionStatus(TURN, this->doTurn(params[0]));
+      addLastActionStatusCollision(TURN, may_fix, this->doTurn(params[0]));
       break;
     case TACKLE:
-      addLastActionStatus(TACKLE, this->doTackle(params[0], false));
+      addLastActionStatus(TACKLE, BooleanToActionStatus(this->doTackle(params[0], false)));
       break;
     case KICK:
-      addLastActionStatus(KICK, this->doKick(params[0], params[1]));
+      addLastActionStatus(KICK, BooleanToActionStatus(this->doKick(params[0], params[1])));
       break;
     case KICK_TO:
       if (feature_extractor != NULL) {
-        addLastActionStatus(KICK_TO, Body_SmartKick(Vector2D(feature_extractor->absoluteXPos(params[0]),
-							 feature_extractor->absoluteYPos(params[1])),
-						params[2], params[2] * 0.99, 3).execute(this));
+        addLastActionStatus(KICK_TO,
+			    BooleanToActionStatus(Body_SmartKick(Vector2D(feature_extractor->absoluteXPos(params[0]),
+									  feature_extractor->absoluteYPos(params[1])),
+								 params[2], params[2] * 0.99, 3).execute(this)));
       }
       break;
     case MOVE_TO:
       if (feature_extractor != NULL) {
-        addLastActionStatus(MOVE_TO, Body_GoToPoint(Vector2D(feature_extractor->absoluteXPos(params[0]),
-							 feature_extractor->absoluteYPos(params[1])), 0.25,
-						ServerParam::i().maxDashPower()).execute(this));
+        addLastActionStatusCollision(MOVE_TO, may_fix,
+				     Body_GoToPoint(Vector2D(feature_extractor->absoluteXPos(params[0]),
+							     feature_extractor->absoluteYPos(params[1])), 0.25,
+						    ServerParam::i().maxDashPower()).execute(this));
       }
       break;
     case DRIBBLE_TO:
       if (feature_extractor != NULL) {
-        addLastActionStatus(DRIBBLE_TO, Body_Dribble(Vector2D(feature_extractor->absoluteXPos(params[0]),
-							  feature_extractor->absoluteYPos(params[1])), 1.0,
-						 ServerParam::i().maxDashPower(), 2).execute(this));
+        addLastActionStatusCollision(DRIBBLE_TO, may_fix,
+				     Body_Dribble(Vector2D(feature_extractor->absoluteXPos(params[0]),
+							   feature_extractor->absoluteYPos(params[1])), 1.0,
+						  ServerParam::i().maxDashPower(), 2).execute(this));
       }
       break;
     case INTERCEPT:
-      addLastActionStatus(INTERCEPT, Body_Intercept().execute(this));
+      addLastActionStatusCollision(INTERCEPT, may_fix, Body_Intercept().execute(this));
       break;
     case MOVE:
       addLastActionStatus(MOVE, this->doMove());
@@ -318,7 +338,7 @@ void Agent::actionImpl() {
       addLastActionStatus(DRIBBLE, this->doDribble());
       break;
     case CATCH:
-      addLastActionStatus(CATCH, this->doCatch());
+      addLastActionStatus(CATCH, BooleanToActionStatus(this->doCatch()));
       break;
     case NOOP:
       break;
@@ -343,9 +363,7 @@ void Agent::actionImpl() {
                 << requested_action << std::endl;
       exit(1);
   }
-  // For now let's not worry about turning the neck or setting the vision.
-  this->setViewAction(new View_Tactical());
-  this->setNeckAction(new Neck_TurnToBallOrScan());
+
 }
 
 void
@@ -723,7 +741,7 @@ Agent::doPreprocess()
 /*!
 
 */
-bool
+action_status_t
 Agent::doShoot()
 {
     const WorldModel & wm = this->world();
@@ -738,21 +756,23 @@ Agent::doShoot()
 
         // reset intention
         this->setIntention( static_cast< SoccerIntention * >( 0 ) );
-        return true;
+        return ACTION_STATUS_MAYBE;
     }
 
-    return false;
+    return ACTION_STATUS_BAD;
 }
 
-bool
+action_status_t
 Agent::doSmartKick()
 {
     const ShootGenerator::Container & cont =
         ShootGenerator::instance().courses(this->world(), false);
     ShootGenerator::Container::const_iterator best_shoot
         = std::min_element(cont.begin(), cont.end(), ShootGenerator::ScoreCmp());
-    return Body_SmartKick(best_shoot->target_point_, best_shoot->first_ball_speed_,
-			  best_shoot->first_ball_speed_ * 0.99, 3).execute(this);
+    return BooleanToActionStatus(Body_SmartKick(best_shoot->target_point_,
+						best_shoot->first_ball_speed_,
+						best_shoot->first_ball_speed_ * 0.99,
+						3).execute(this));
 }
 
 
@@ -769,19 +789,19 @@ Agent::doPass()
     return true;
 }
 
-bool
+action_status_t
 Agent::doPassTo(int receiver)
 {
     Force_Pass pass;
     pass.get_pass_to_player(this->world(), receiver);
-    return pass.execute(this);
+    return BooleanToActionStatus(pass.execute(this));
 }
 
 /*-------------------------------------------------------------------*/
 /*!
 
 */
-bool
+action_status_t
 Agent::doDribble()
 {
   bool success = false;
@@ -795,9 +815,9 @@ Agent::doDribble()
   success = doPreprocess();
   ActionChainHolder::instance().update( world() );
   if (Bhv_ChainAction(ActionChainHolder::instance().graph()).execute(this)) {
-    return true;
+    return ACTION_STATUS_MAYBE;
   } else {
-    return success;
+    return BooleanToActionStatus(success);
   }
 }
 
@@ -805,19 +825,19 @@ Agent::doDribble()
 /*!
 
 */
-bool
+action_status_t
 Agent::doMove()
 {
   Strategy::instance().update( world() );
-  int role_num = Strategy::i().roleNumber(world().self().unum());
-  return Bhv_BasicMove().execute(this);
+  int role_num = Strategy::i().roleNumber(world().self().unum()); // Unused?
+  return Bhv_BasicMove().action_execute(this);
 }
 
 /*-------------------------------------------------------------------*/
 /*!
  * This Action marks the player with the specified uniform number.
 */
-bool Agent::doMarkPlayer(int unum) {
+action_status_t Agent::doMarkPlayer(int unum) {
   const WorldModel & wm = this->world();
   Vector2D kicker_pos = Vector2D :: INVALIDATED;
   Vector2D player_pos =  Vector2D :: INVALIDATED;
@@ -841,19 +861,27 @@ bool Agent::doMarkPlayer(int unum) {
 
   if (!player_pos.isValid()) {
       //Player to be marked not found
-      return false;
+      return ACTION_STATUS_BAD;
   }
   if (!kicker_pos.isValid()) {
       //Kicker not found
-      return false;
+      return ACTION_STATUS_BAD;
   }
   if (unum == kicker_unum || kicker_pos.equals(player_pos)) {
     //Player to be marked is kicker
-    return false;
+    return ACTION_STATUS_BAD;
   }
   double x = player_pos.x + (kicker_pos.x - player_pos.x)*0.1;
   double y = player_pos.y + (kicker_pos.y - player_pos.y)*0.1;
-  return Body_GoToPoint(Vector2D(x,y), 0.25, ServerParam::i().maxDashPower()).execute(this);
+  bool may_fix = wm.self().collidesWithPost();
+
+  if (Body_GoToPoint(Vector2D(x,y), 0.25, ServerParam::i().maxDashPower()).execute(this)) {
+    return ACTION_STATUS_MAYBE;
+  } else if (may_fix) {
+    return ACTION_STATUS_UNKNOWN;
+  } else {
+    return ACTION_STATUS_BAD;
+  }
 }
 
 /*-------------------------------------------------------------------*/
@@ -867,7 +895,7 @@ bool compare_y_pos (PlayerObject* i, PlayerObject* j) {
   return i->pos().y < j->pos().y;
 }
 
-bool Agent::doReduceAngleToGoal() {
+action_status_t Agent::doReduceAngleToGoal() {
   const WorldModel & wm = this->world();
   Vector2D goal_pos1( -ServerParam::i().pitchHalfLength(), ServerParam::i().goalHalfWidth() );
   Vector2D goal_pos2( -ServerParam::i().pitchHalfLength(), -ServerParam::i().goalHalfWidth() );
@@ -876,7 +904,7 @@ bool Agent::doReduceAngleToGoal() {
 
   const BallObject& ball = wm.ball();
   if (! ball.rposValid()) {
-    return false;
+    return ACTION_STATUS_BAD;
   }
 
   Vector2D ball_pos = ball.pos();
@@ -945,23 +973,30 @@ bool Agent::doReduceAngleToGoal() {
   double dist_to_end2 = targetLineEnd2.dist2(ball_pos);
   double ratio = dist_to_end2/(dist_to_end1+dist_to_end2);
   Vector2D target = targetLineEnd1 * ratio + targetLineEnd2 * (1-ratio);
-  return Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this);
+  bool may_fix = wm.self().collidesWithPost();
+  if (Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this)) {
+    return ACTION_STATUS_MAYBE;
+  } else if (may_fix) {
+    return ACTION_STATUS_UNKNOWN;
+  } else {
+    return ACTION_STATUS_BAD;
+  }
 }
 
 /*-------------------------------------------------------------------*/
 
 /*!
  *
- * This action cuts off the angle between the shooter and the goal the players always moves on a fixed line.
+ * This action cuts off the angle between the shooter and the goal; the player always moves on a fixed line.
  */
 
-bool Agent::doDefendGoal() {
+action_status_t Agent::doDefendGoal() {
   const WorldModel & wm = this->world();
   Vector2D goal_pos1( -ServerParam::i().pitchHalfLength() + ServerParam::i().goalAreaLength(), ServerParam::i().goalHalfWidth() );
   Vector2D goal_pos2( -ServerParam::i().pitchHalfLength() + ServerParam::i().goalAreaLength(), -ServerParam::i().goalHalfWidth() );
   const BallObject& ball = wm.ball();
   if (! ball.rposValid()) {
-    return false;
+    return ACTION_STATUS_BAD;
   }
 
   Vector2D ball_pos = ball.pos();
@@ -969,7 +1004,15 @@ bool Agent::doDefendGoal() {
   double dist_to_post2 = goal_pos2.dist2(ball_pos);
   double ratio = dist_to_post2/(dist_to_post1+dist_to_post2);
   Vector2D target = goal_pos1 * ratio + goal_pos2 * (1-ratio);
-  return Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this);
+  bool may_fix = wm.self().collidesWithPost();
+
+  if (Body_GoToPoint(target, 0.25, ServerParam::i().maxDashPower()).execute(this)) {
+    return ACTION_STATUS_MAYBE;
+  } else if (may_fix) {
+    return ACTION_STATUS_UNKNOWN;
+  } else {
+    return ACTION_STATUS_BAD;
+  }
 }
 
 /*-------------------------------------------------------------------*/
@@ -980,13 +1023,13 @@ bool Agent::doDefendGoal() {
  */
 
 
-bool Agent::doGoToBall() {
+action_status_t Agent::doGoToBall() {
   const WorldModel & wm = this->world();
   const BallObject& ball = wm.ball();
   if (! ball.rposValid()) {
-    return false;
+    return ACTION_STATUS_BAD;
   }
-  return Body_GoToPoint(ball.pos(), 0.25, ServerParam::i().maxDashPower()).execute(this);
+  return BooleanToActionStatus(Body_GoToPoint(ball.pos(), 0.25, ServerParam::i().maxDashPower()).execute(this));
 }
 
 /*-------------------------------------------------------------------*/
diff --git a/src/agent.h b/src/agent.h
index 2a22911..3f4112f 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -1,3 +1,5 @@
+// -*-c++-*-
+
 #ifndef AGENT_H
 #define AGENT_H
 
@@ -64,7 +66,7 @@ protected:
   int num_teammates;                   // Number of teammates
   int num_opponents;                   // Number of opponents
   hfo::action_t last_action_with_status; // Last action with a recorded return status
-  int last_action_status;              // Recorded return status of last action (1 = true, 0 = false, -1 = not available)
+  hfo::action_status_t last_action_status;  // Recorded return status of last action
 
  public:
   inline const std::vector<float>& getState() { return state; }
@@ -74,7 +76,7 @@ protected:
   int getUnum(); // Returns the uniform number of the player
   inline int getNumTeammates() { return num_teammates; }
   inline int getNumOpponents() { return num_opponents; }
-  int getLastActionStatus(hfo::action_t last_action); // if last_action is correct, returns status if available
+  hfo::action_status_t getLastActionStatus(hfo::action_t last_action); // if last_action is correct, returns status if available
 
   inline void setFeatureSet(hfo::feature_set_t fset) { feature_set = fset; }
   inline std::vector<float>* mutable_params() { return &params; }
@@ -83,21 +85,22 @@ protected:
 
  private:
   bool doPreprocess();
-  bool doSmartKick();
-  bool doShoot();
+  hfo::action_status_t doSmartKick();
+  hfo::action_status_t doShoot();
   bool doPass();
-  bool doPassTo(int receiver);
-  bool doDribble();
-  bool doMove();
+  hfo::action_status_t doPassTo(int receiver);
+  hfo::action_status_t doDribble();
+  hfo::action_status_t doMove();
   bool doForceKick();
   bool doHeardPassReceive();
-  bool doMarkPlayer(int unum);
+  hfo::action_status_t doMarkPlayer(int unum);
   bool doMarkPlayerNearIndex(int near_index);
-  bool doReduceAngleToGoal();
-  bool doDefendGoal();
-  bool doGoToBall();
+  hfo::action_status_t doReduceAngleToGoal();
+  hfo::action_status_t doDefendGoal();
+  hfo::action_status_t doGoToBall();
   bool doNewAction1();
-  void addLastActionStatus(hfo::action_t last_action, bool action_status);
+  void addLastActionStatus(hfo::action_t last_action, hfo::action_status_t action_status);
+  void addLastActionStatusCollision(hfo::action_t last_action, bool may_fix, bool likely_success);
 
 
   Communication::Ptr M_communication;
diff --git a/src/bhv_basic_move.cpp b/src/bhv_basic_move.cpp
index 1c1bf94..9c10ca7 100644
--- a/src/bhv_basic_move.cpp
+++ b/src/bhv_basic_move.cpp
@@ -48,25 +48,36 @@
 #include <rcsc/common/server_param.h>
 
 #include "neck_offensive_intercept_neck.h"
+#include "common.hpp"
 
 using namespace rcsc;
 
+bool
+Bhv_BasicMove::execute( PlayerAgent * agent )
+{
+  if (Bhv_BasicMove::action_execute(agent) == hfo::ACTION_STATUS_MAYBE) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
 /*-------------------------------------------------------------------*/
 /*!
 
  */
-bool
-Bhv_BasicMove::execute( PlayerAgent * agent )
+hfo::action_status_t
+Bhv_BasicMove::action_execute( PlayerAgent * agent )
 {
     dlog.addText( Logger::TEAM,
                   __FILE__": Bhv_BasicMove" );
-    bool success = true;
+    hfo::action_status_t success = hfo::ACTION_STATUS_UNKNOWN;
 
     //-----------------------------------------------
     // tackle
     if ( Bhv_BasicTackle( 0.8, 80.0 ).execute( agent ) )
     {
-        return true;
+      return hfo::ACTION_STATUS_MAYBE;
     }
 
     const WorldModel & wm = agent->world();
@@ -85,9 +96,8 @@ Bhv_BasicMove::execute( PlayerAgent * agent )
     {
         dlog.addText( Logger::TEAM,
                       __FILE__": intercept" );
-        success = Body_Intercept().execute( agent );
+        success = hfo::BooleanToActionStatus(Body_Intercept().execute( agent ));
         agent->setNeckAction( new Neck_OffensiveInterceptNeck() );
-
         return success;
     }
 
@@ -96,7 +106,9 @@ Bhv_BasicMove::execute( PlayerAgent * agent )
 
     const BallObject& ball = wm.ball();
     if (! ball.rposValid()) {
-      success = false;
+      if (! wm.self().collidesWithPost()) {
+	success = hfo::ACTION_STATUS_BAD;
+      }
     }
 
     double dist_thr = ball.distFromSelf() * 0.1;
@@ -115,8 +127,10 @@ Bhv_BasicMove::execute( PlayerAgent * agent )
                            ).execute( agent ) )
     {
       if (! Body_TurnToBall().execute( agent )) {
-	success = false;
+	success = hfo::ACTION_STATUS_BAD;
       }
+    } else if (success != hfo::ACTION_STATUS_BAD) {
+      success = hfo::ACTION_STATUS_MAYBE;
     }
 
     if ( wm.existKickableOpponent() &&
diff --git a/src/bhv_basic_move.h b/src/bhv_basic_move.h
index 1a13568..092c2cd 100644
--- a/src/bhv_basic_move.h
+++ b/src/bhv_basic_move.h
@@ -29,6 +29,7 @@
 
 #include <rcsc/geom/vector_2d.h>
 #include <rcsc/player/soccer_action.h>
+#include "common.hpp"
 
 class Bhv_BasicMove
     : public rcsc::SoccerBehavior {
@@ -36,7 +37,8 @@ public:
     Bhv_BasicMove()
       { }
 
-    bool execute( rcsc::PlayerAgent * agent );
+  bool execute( rcsc::PlayerAgent * agent );
+  hfo::action_status_t action_execute( rcsc::PlayerAgent * agent );
 
 private:
     double getDashPower( const rcsc::PlayerAgent * agent );
diff --git a/src/common.hpp b/src/common.hpp
index 255f9be..5e544f3 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -5,6 +5,7 @@
 #include <stdlib.h>
 #include <iostream>
 #include <sstream>
+#include <vector>
 
 namespace hfo {
 
@@ -33,14 +34,14 @@ enum action_t
   DRIBBLE,    // [High-Level] Dribble(): Offensive dribble
   CATCH,      // [High-Level] Catch(): Catch the ball (Goalie only!)
   NOOP,       // Do nothing
-  QUIT,        // Special action to quit the game
+  QUIT,       // Special action to quit the game
   REDUCE_ANGLE_TO_GOAL, // [High-Level] Reduce_Angle_To_Goal : Reduces the shooting angle
-  MARK_PLAYER, 			// [High-Level] Mark_Player(opponent_unum [0,11]) : Moves to the position in between the kicker and a given player
+  MARK_PLAYER, // [High-Level] Mark_Player(opponent_unum [0,11]) : Moves to the position in between the kicker and a given player
   DEFEND_GOAL,
   GO_TO_BALL
 };
 
-// Status of a HFO game
+// Status of an HFO game
 enum status_t
 {
   IN_GAME,             // Game is currently active
@@ -51,6 +52,24 @@ enum status_t
   SERVER_DOWN          // Server is not alive
 };
 
+// Action status
+enum action_status_t {
+  ACTION_STATUS_UNKNOWN = -1, // cannot tell or invalid action # in status request
+  ACTION_STATUS_BAD = 0, // definitely not OK
+  ACTION_STATUS_MAYBE = 1, // may be OK, may not
+};
+
+/**
+ * Translates from boolean false (bad) or true (maybe OK) to action status
+ */
+inline action_status_t BooleanToActionStatus(const bool status) {
+  if (status) {
+    return ACTION_STATUS_MAYBE;
+  } else{
+    return ACTION_STATUS_BAD;
+  }
+}
+
 // Configuration of the HFO domain including the team names and player
 // numbers for each team. This struct is populated by ParseConfig().
 struct Config {
@@ -171,7 +190,7 @@ inline std::string ActionToString(action_t action) {
 };
 
 /**
- * Returns a string representation of a game_status.
+ * Returns a string representation of a game status.
  */
 inline std::string StatusToString(status_t status) {
   switch (status) {
@@ -192,6 +211,22 @@ inline std::string StatusToString(status_t status) {
   }
 };
 
+/**
+ * Returns a string representation of an action status.
+ */
+inline std::string ActionStatusToString(action_status_t status) {
+  switch (status) {
+  case ACTION_STATUS_BAD:
+    return "Bad";
+  case ACTION_STATUS_MAYBE:
+    return "MaybeOK";
+  case ACTION_STATUS_UNKNOWN:
+    return "Unknown";
+  default:
+    return "Invalid";
+  }
+}
+
 /**
  * Parse a Trainer message to populate config. Returns a bool
  * indicating if the struct was correctly parsed.
-- 
2.24.1