|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00037 static void rune_attack(object *op, object *victim) 00038 { 00039 int dam = op->stats.dam; 00040 00041 op->stats.dam = (sint16) ((float) dam * (LEVEL_DAMAGE(op->level) * 0.925f)); 00042 00043 if (victim) 00044 { 00045 tag_t tag = victim->count; 00046 hit_player(victim, op->stats.dam, op, AT_INTERNAL); 00047 00048 if (was_destroyed(victim, tag)) 00049 { 00050 op->stats.dam = dam; 00051 return; 00052 } 00053 00054 /* If there's a disease in the needle, put it in the player */ 00055 if (op->randomitems != NULL) 00056 { 00057 create_treasure(op->randomitems, op, 0, op->level ? op->level : victim->map->difficulty, T_STYLE_UNSET, ART_CHANCE_UNSET, 0, NULL); 00058 } 00059 00060 if (op->inv && op->inv->type == DISEASE) 00061 { 00062 object *disease = op->inv; 00063 00064 infect_object(victim, disease, 1); 00065 remove_ob(disease); 00066 check_walk_off(disease, NULL, MOVE_APPLY_VANISHED); 00067 } 00068 } 00069 else 00070 { 00071 hit_map(op, 0, 0); 00072 } 00073 00074 op->stats.dam = dam; 00075 } 00076 00083 void spring_trap(object *trap, object *victim) 00084 { 00085 object *env; 00086 00087 /* Prevent recursion. */ 00088 if (trap->stats.hp == 0) 00089 { 00090 return; 00091 } 00092 00093 /* Only living objects can trigger runes that don't cast spells, as 00094 * doing direct damage to a non-living object doesn't work anyway. 00095 * Typical example is an arrow attacking a door. */ 00096 if (!IS_LIVE(victim) && trap->stats.sp == -1) 00097 { 00098 return; 00099 } 00100 00101 if (victim && victim->type == PLAYER && trap->msg) 00102 { 00103 new_draw_info(0, COLOR_WHITE, victim, trap->msg); 00104 } 00105 00106 env = get_env_recursive(trap); 00107 trap_show(trap, env); 00108 00109 if (victim->type == PLAYER) 00110 { 00111 CONTR(victim)->stat_traps_sprung++; 00112 } 00113 00114 /* No spell, simple attack. */ 00115 if (trap->stats.sp == -1) 00116 { 00117 tag_t trap_tag = trap->count; 00118 00119 rune_attack(trap, victim); 00120 00121 if (was_destroyed(trap, trap_tag)) 00122 { 00123 return; 00124 } 00125 } 00126 else 00127 { 00128 object *old_env = trap->env; 00129 00130 /* This is necessary if the trap is inside something else, otherwise 00131 * the rune couldn't cast its spell. */ 00132 if (!trap->map) 00133 { 00134 remove_ob(trap); 00135 trap->x = env->x; 00136 trap->y = env->y; 00137 00138 if (!insert_ob_in_map(trap, victim->map, trap, 0)) 00139 { 00140 return; 00141 } 00142 } 00143 00144 cast_spell(trap, trap, trap->stats.maxsp, trap->stats.sp, 1, CAST_NORMAL, NULL); 00145 00146 /* Add the trap back to the object it was in, unless it was on 00147 * map to begin with. */ 00148 if (old_env) 00149 { 00150 remove_ob(trap); 00151 check_walk_off(trap, NULL, MOVE_APPLY_VANISHED); 00152 insert_ob_in_ob(trap, old_env); 00153 } 00154 } 00155 00156 /* Decrement detonation count and see if it's the last one, but only 00157 * if the count is not -1 already (infinite). */ 00158 if (trap->stats.hp != -1 && --trap->stats.hp == 0) 00159 { 00160 /* Make the trap impotent */ 00161 trap->type = MISC_OBJECT; 00162 CLEAR_FLAG(trap, FLAG_FLY_ON); 00163 CLEAR_FLAG(trap, FLAG_WALK_ON); 00164 FREE_AND_CLEAR_HASH2(trap->msg); 00165 /* Make it stick around until its spells are gone */ 00166 trap->stats.food = 20; 00167 SET_FLAG(trap, FLAG_IS_USED_UP); 00168 trap->speed = trap->speed_left = 1.0f; 00169 update_ob_speed(trap); 00170 /* Clear trapped flag. */ 00171 set_trapped_flag(env); 00172 return; 00173 } 00174 } 00175 00183 int trap_see(object *op, object *trap, int level) 00184 { 00185 int chance = rndm(0, 99); 00186 00187 /* Decide if we can see the rune or not */ 00188 if ((trap->level <= level && rndm_chance(10)) || trap->stats.Cha == 1 || (chance > MIN(95, MAX(5, ((int) ((float) (op->map->difficulty + trap->level + trap->stats.Cha - op->level) / 10.0 * 50.0)))))) 00189 { 00190 new_draw_info_format(0, COLOR_WHITE, op, "You spot a %s (lvl %d)!", trap->name, trap->level); 00191 00192 if (trap->stats.Cha != 1) 00193 { 00194 CONTR(op)->stat_traps_found++; 00195 } 00196 00197 return 1; 00198 } 00199 00200 return 0; 00201 } 00202 00208 int trap_show(object *trap, object *where) 00209 { 00210 object *env; 00211 00212 if (where == NULL) 00213 { 00214 return 0; 00215 } 00216 00217 env = trap->env; 00218 /* We must remove and reinsert it so the layer is updated correctly. */ 00219 remove_ob(trap); 00220 CLEAR_FLAG(trap, FLAG_SYS_OBJECT); 00221 CLEAR_MULTI_FLAG(trap, FLAG_IS_INVISIBLE); 00222 trap->layer = LAYER_EFFECT; 00223 00224 /* The trap is not hidden anymore. */ 00225 if (trap->stats.Cha > 1) 00226 { 00227 trap->stats.Cha = 1; 00228 } 00229 00230 if (env && env->type != PLAYER && env->type != MONSTER && env->type != DOOR && !QUERY_FLAG(env, FLAG_NO_PASS)) 00231 { 00232 insert_ob_in_ob(trap, env); 00233 set_trapped_flag(env); 00234 } 00235 else 00236 { 00237 insert_ob_in_map(trap, where->map, NULL, 0); 00238 } 00239 00240 return 1; 00241 } 00242 00248 int trap_disarm(object *disarmer, object *trap) 00249 { 00250 object *env = trap->env; 00251 int disarmer_level = CONTR(disarmer)->exp_ptr[EXP_AGILITY]->level; 00252 00253 if ((trap->level <= disarmer_level && rndm_chance(10)) || !(rndm(0, (MAX(2, MIN(20, trap->level - disarmer_level + 5 - disarmer->stats.Dex / 2)) - 1)))) 00254 { 00255 new_draw_info_format(0, COLOR_WHITE, disarmer, "You successfully remove the %s (lvl %d)!", trap->name, trap->level); 00256 remove_ob(trap); 00257 check_walk_off(trap, NULL, MOVE_APPLY_VANISHED); 00258 set_trapped_flag(env); 00259 CONTR(disarmer)->stat_traps_disarmed++; 00260 return 1; 00261 } 00262 else 00263 { 00264 new_draw_info_format(0, COLOR_WHITE, disarmer, "You fail to remove the %s (lvl %d).", trap->name, trap->level); 00265 00266 if (trap->level > disarmer_level * 1.4f || rndm(0, 2)) 00267 { 00268 if (!(rndm(0, (MAX(2, disarmer_level - trap->level + disarmer->stats.Dex / 2 - 6)) - 1))) 00269 { 00270 new_draw_info(0, COLOR_WHITE, disarmer, "In fact, you set it off!"); 00271 spring_trap(trap, disarmer); 00272 } 00273 } 00274 00275 return 0; 00276 } 00277 } 00278 00284 void trap_adjust(object *trap, int difficulty) 00285 { 00286 int off, level, hide; 00287 00288 if (difficulty < 1) 00289 { 00290 difficulty = 1; 00291 } 00292 00293 off = (int) ((float) difficulty * 0.2f); 00294 level = rndm(difficulty - off, difficulty + off); 00295 level = MAX(1, MIN(level, MAXLEVEL)); 00296 hide = rndm(0, 19) + rndm(difficulty - off, difficulty + off); 00297 hide = MAX(1, MIN(hide, SINT8_MAX)); 00298 00299 trap->level = level; 00300 trap->stats.Cha = hide; 00301 }
1.7.4