Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 CrossFire, A Multiplayer game for X-windows 00003 00004 Copyright (C) 2007 Mark Wedel & Crossfire Development Team 00005 Copyright (C) 1992 Frank Tore Johansen 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 00021 The authors can be reached via e-mail at crossfire-devel@real-time.com 00022 */ 00027 #include <global.h> 00028 #include <sproto.h> 00029 #include <ob_methods.h> 00030 #include <ob_types.h> 00031 00036 void stop_projectile(object *op) { 00037 /* Lauwenmark: Handle for plugin stop event */ 00038 execute_event(op, EVENT_STOP, NULL, NULL, NULL, SCRIPT_FIX_NOTHING); 00039 if (op->inv) { 00040 object *payload = op->inv; 00041 00042 remove_ob(payload); 00043 clear_owner(payload); 00044 insert_ob_in_map(payload, op->map, payload, 0); 00045 remove_ob(op); 00046 free_object(op); 00047 } else { 00048 op = fix_stopped_arrow(op); 00049 if (op) 00050 merge_ob(op, NULL); 00051 } 00052 } 00053 00062 method_ret common_process_projectile(ob_methods *context, object *op) { 00063 object *tmp; 00064 sint16 new_x, new_y; 00065 int was_reflected, mflags; 00066 mapstruct *m; 00067 00068 if (op->map == NULL) { 00069 LOG(llevError, "BUG: Projectile had no map.\n"); 00070 remove_ob(op); 00071 free_object(op); 00072 return METHOD_ERROR; 00073 } 00074 00075 /* Calculate target map square */ 00076 new_x = op->x+DIRX(op); 00077 new_y = op->y+DIRY(op); 00078 was_reflected = 0; 00079 00080 m = op->map; 00081 mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y); 00082 00083 if (mflags&P_OUT_OF_MAP) { 00084 stop_projectile(op); 00085 return METHOD_OK; 00086 } 00087 00088 /* only need to look for living creatures if this flag is set */ 00089 if (mflags&P_IS_ALIVE) { 00090 for (tmp = GET_MAP_OB(m, new_x, new_y); tmp != NULL; tmp = tmp->above) 00091 if (QUERY_FLAG(tmp, FLAG_ALIVE)) 00092 break; 00093 00094 00095 /* Not really fair, but don't let monsters hit themselves with 00096 * their own arrow - this can be because they fire it then 00097 * move into it. 00098 */ 00099 00100 if (tmp != NULL && tmp != op->owner) { 00101 /* Found living object, but it is reflecting the missile. Update 00102 * as below. (Note that for living creatures there is a small 00103 * chance that reflect_missile fails.) 00104 */ 00105 00106 if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE) 00107 && (rndm(0, 99)) < (90-op->level/10)) { 00108 int number = op->face->number; 00109 00110 op->direction = absdir(op->direction+4); 00111 op->state = 0; 00112 if (GET_ANIM_ID(op)) { 00113 number += 4; 00114 if (number > GET_ANIMATION(op, 8)) 00115 number -= 8; 00116 op->face = &new_faces[number]; 00117 } 00118 was_reflected = 1; /* skip normal movement calculations */ 00119 } else { 00120 /* Attack the object. */ 00121 op = hit_with_arrow(op, tmp); 00122 if (op == NULL) 00123 return METHOD_OK; 00124 } 00125 } /* if this is not hitting its owner */ 00126 } /* if there is something alive on this space */ 00127 00128 if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y))) { 00129 int retry = 0; 00130 00131 /* if the object doesn't reflect, stop the arrow from moving 00132 * note that this code will now catch cases where a monster is 00133 * on a wall but has reflecting - the arrow won't reflect. 00134 * Mapmakers shouldn't put monsters on top of wall in the first 00135 * place, so I don't consider that a problem. 00136 */ 00137 if (!QUERY_FLAG(op, FLAG_REFLECTING) || !(rndm(0, 19))) { 00138 stop_projectile(op); 00139 return METHOD_OK; 00140 } else { 00141 /* If one of the major directions (n,s,e,w), just reverse it */ 00142 if (op->direction&1) { 00143 op->direction = absdir(op->direction+4); 00144 retry = 1; 00145 } 00146 /* There were two blocks with identical code - 00147 * use this retry here to make this one block 00148 * that did the same thing. 00149 */ 00150 while (retry < 2) { 00151 int left, right, mflags; 00152 mapstruct *m1; 00153 sint16 x1, y1; 00154 00155 retry++; 00156 00157 /* Need to check for P_OUT_OF_MAP: if the arrow is tavelling 00158 * over a corner in a tiled map, it is possible that 00159 * op->direction is within an adjacent map but either 00160 * op->direction-1 or op->direction+1 does not exist. 00161 */ 00162 mflags = get_map_flags(op->map, &m1, op->x+freearr_x[absdir(op->direction-1)], op->y+freearr_y[absdir(op->direction-1)], &x1, &y1); 00163 left = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, (GET_MAP_MOVE_BLOCK(m1, x1, y1))); 00164 00165 mflags = get_map_flags(op->map, &m1, op->x+freearr_x[absdir(op->direction+1)], op->y+freearr_y[absdir(op->direction+1)], &x1, &y1); 00166 right = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, (GET_MAP_MOVE_BLOCK(m1, x1, y1))); 00167 00168 if (left == right) 00169 op->direction = absdir(op->direction+4); 00170 else if (left) 00171 op->direction = absdir(op->direction+2); 00172 else if (right) 00173 op->direction = absdir(op->direction-2); 00174 00175 mflags = get_map_flags(op->map, &m1, op->x+DIRX(op), op->y+DIRY(op), &x1, &y1); 00176 00177 /* If this space is not out of the map and not blocked, valid space - 00178 * don't need to retry again. 00179 */ 00180 if (!(mflags&P_OUT_OF_MAP) 00181 && !OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m1, x1, y1))) 00182 break; 00183 } 00184 /* Couldn't find a direction to move the arrow to - just 00185 * top it from moving. 00186 */ 00187 if (retry == 2) { 00188 stop_projectile(op); 00189 return METHOD_OK; 00190 } 00191 /* update object image for new facing */ 00192 /* many thrown objects *don't *have more than one face */ 00193 if (GET_ANIM_ID(op)) 00194 SET_ANIMATION(op, op->direction); 00195 } /* object is reflected */ 00196 } /* object ran into a wall */ 00197 00198 /* Move the arrow. */ 00199 remove_ob(op); 00200 op->x = new_x; 00201 op->y = new_y; 00202 00203 /* decrease the speed as it flies. 0.05 means a standard bow will shoot 00204 * about 17 squares. Tune as needed. 00205 */ 00206 op->speed -= 0.05; 00207 insert_ob_in_map(op, m, op, 0); 00208 return METHOD_OK; 00209 } 00210 00219 method_ret common_projectile_move_on(ob_methods *context, object *trap, object *victim, object *originator) { 00220 if (common_pre_ob_move_on(trap, victim, originator) == METHOD_ERROR) 00221 return METHOD_OK; 00222 if (trap->inv == NULL) { 00223 common_post_ob_move_on(trap, victim, originator); 00224 return METHOD_OK; 00225 } 00226 00227 /* bad bug: monster throw a object, make a step forwards, step on object , 00228 * trigger this here and get hit by own missile - and will be own enemy. 00229 * Victim then is his own enemy and will start to kill herself (this is 00230 * removed) but we have not synced victim and his missile. To avoid senseless 00231 * action, we avoid hits here 00232 */ 00233 if ((QUERY_FLAG(victim, FLAG_ALIVE) && trap->speed) 00234 && trap->owner != victim) 00235 hit_with_arrow(trap, victim); 00236 common_post_ob_move_on(trap, victim, originator); 00237 return METHOD_OK; 00238 }