|
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 add_one_drop_quest_item(object *op, const char *quest_name) 00038 { 00039 object *quest_container = get_archetype(QUEST_CONTAINER_ARCHETYPE); 00040 00041 /* Mark this quest as completed. */ 00042 quest_container->magic = QUEST_STATUS_COMPLETED; 00043 /* Store the quest name. */ 00044 FREE_AND_COPY_HASH(quest_container->name, quest_name); 00045 /* Insert it inside player's quest container. */ 00046 insert_ob_in_ob(quest_container, CONTR(op)->quest_container); 00047 } 00048 00055 static object *find_quest(object *where, const char *quest_name) 00056 { 00057 object *tmp; 00058 00059 /* Go through the objects in the quest container */ 00060 for (tmp = where->inv; tmp; tmp = tmp->below) 00061 { 00062 if (tmp->name == quest_name) 00063 { 00064 return tmp; 00065 } 00066 } 00067 00068 return NULL; 00069 } 00070 00082 static int has_quest_item(object *op, object *quest_item, sint32 flag, sint64 *num) 00083 { 00084 object *tmp; 00085 00086 /* Go through the objects in the object's inventory. */ 00087 for (tmp = op->inv; tmp; tmp = tmp->below) 00088 { 00089 /* Compare the values. */ 00090 if (tmp->name == quest_item->name && tmp->arch->name == quest_item->arch->name && (!flag || QUERY_FLAG(tmp, flag))) 00091 { 00092 if (num) 00093 { 00094 *num += MAX(1, tmp->nrof); 00095 } 00096 else 00097 { 00098 return 1; 00099 } 00100 } 00101 00102 /* If it has inventory and is not a system object, go on recursively. */ 00103 if (tmp->inv && !QUERY_FLAG(tmp, FLAG_SYS_OBJECT)) 00104 { 00105 int ret = has_quest_item(tmp, quest_item, flag, num); 00106 00107 if (ret && !num) 00108 { 00109 return 1; 00110 } 00111 } 00112 } 00113 00114 return 0; 00115 } 00116 00122 static void check_quest_container(object *op, object *quest_container, object *quest_object) 00123 { 00124 char buf[HUGE_BUF]; 00125 object *tmp; 00126 00127 /* If this is not a one-drop item quest, it must first be accepted. */ 00128 if (quest_container->sub_type != QUEST_TYPE_ITEM && (!quest_object || quest_object->magic == QUEST_STATUS_COMPLETED)) 00129 { 00130 return; 00131 } 00132 00133 tmp = quest_container->inv; 00134 00135 /* Check for events in this quest container. */ 00136 if (HAS_EVENT(quest_container, EVENT_TRIGGER)) 00137 { 00138 /* Advance through the quest object's inventory, skipping the 00139 * event object. */ 00140 if (tmp->type == EVENT_OBJECT) 00141 { 00142 tmp = tmp->below; 00143 } 00144 00145 if (trigger_event(EVENT_TRIGGER, op, quest_container, tmp, NULL, 0, 0, 0, SCRIPT_FIX_NOTHING)) 00146 { 00147 return; 00148 } 00149 } 00150 00151 switch (quest_container->sub_type) 00152 { 00153 case QUEST_TYPE_ITEM: 00154 { 00155 object *clone; 00156 int one_drop; 00157 00158 if (!tmp) 00159 { 00160 return; 00161 } 00162 00163 one_drop = QUERY_FLAG(tmp, FLAG_ONE_DROP); 00164 00165 /* Not one-drop, but we already have the quest object (keys, 00166 * for example). */ 00167 if (!one_drop && has_quest_item(op, tmp, 0, NULL)) 00168 { 00169 return; 00170 } 00171 /* One-drop and we already found this quest object before 00172 * (Rhun's cloak, for example). */ 00173 else if (one_drop && quest_object) 00174 { 00175 return; 00176 } 00177 00178 clone = get_object(); 00179 copy_object_with_inv(tmp, clone); 00180 SET_FLAG(clone, FLAG_IDENTIFIED); 00181 /* Insert the quest item inside the player. */ 00182 insert_ob_in_ob(clone, op); 00183 esrv_send_item(op, clone); 00184 00185 if (one_drop) 00186 { 00187 /* So the item will never drop again for this player. */ 00188 add_one_drop_quest_item(op, quest_container->name); 00189 snprintf(buf, sizeof(buf), "You solved the one drop quest %s!\n", quest_container->name); 00190 } 00191 else 00192 { 00193 snprintf(buf, sizeof(buf), "You found the special drop %s!\n", query_short_name(clone, NULL)); 00194 } 00195 00196 new_draw_info(NDI_ANIM, COLOR_NAVY, op, buf); 00197 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "event01.ogg", 0, 0, 0, 0); 00198 break; 00199 } 00200 00201 case QUEST_TYPE_KILL: 00202 /* The +1 makes it so no messages are displayed when player 00203 * kills more same monsters. */ 00204 if (quest_object->last_sp <= quest_object->last_grace + 1) 00205 { 00206 quest_object->last_sp++; 00207 } 00208 00209 /* Display an informative message about the quest status. */ 00210 if (quest_object->last_sp <= quest_object->last_grace) 00211 { 00212 if (quest_object->last_sp == quest_object->last_grace) 00213 { 00214 if (quest_object->env->type == QUEST_CONTAINER && quest_object->env->sub_type == QUEST_TYPE_MULTI) 00215 { 00216 snprintf(buf, sizeof(buf), "Quest '%s: %s' completed!\n", quest_object->env->name, quest_container->name); 00217 } 00218 else 00219 { 00220 snprintf(buf, sizeof(buf), "Quest '%s' completed!\n", quest_container->name); 00221 } 00222 00223 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "event01.ogg", 0, 0, 0, 0); 00224 } 00225 else 00226 { 00227 if (quest_object->env->type == QUEST_CONTAINER && quest_object->env->sub_type == QUEST_TYPE_MULTI) 00228 { 00229 snprintf(buf, sizeof(buf), "Quest %s (%s): %d/%d.\n", quest_object->env->name, quest_container->name, quest_object->last_sp, quest_object->last_grace); 00230 } 00231 else 00232 { 00233 snprintf(buf, sizeof(buf), "Quest %s: %d/%d.\n", quest_container->name, quest_object->last_sp, quest_object->last_grace); 00234 } 00235 } 00236 00237 new_draw_info(NDI_ANIM, COLOR_NAVY, op, buf); 00238 } 00239 00240 break; 00241 00242 case QUEST_TYPE_KILL_ITEM: 00243 { 00244 object *clone; 00245 sint64 num = 0; 00246 00247 /* Have we found this item already? */ 00248 if (!tmp || (!quest_object->last_grace && has_quest_item(op, tmp, FLAG_QUEST_ITEM, NULL))) 00249 { 00250 return; 00251 } 00252 00253 if (quest_object->last_grace) 00254 { 00255 has_quest_item(op, tmp, FLAG_QUEST_ITEM, &num); 00256 00257 if (num >= quest_object->last_grace) 00258 { 00259 return; 00260 } 00261 } 00262 00263 clone = get_object(); 00264 copy_object_with_inv(tmp, clone); 00265 SET_FLAG(clone, FLAG_QUEST_ITEM); 00266 SET_FLAG(clone, FLAG_STARTEQUIP); 00267 CLEAR_FLAG(clone, FLAG_SYS_OBJECT); 00268 /* Insert the quest item inside the player. */ 00269 clone = insert_ob_in_ob(clone, op); 00270 esrv_send_item(op, clone); 00271 00272 if (quest_object->env->type == QUEST_CONTAINER && quest_object->env->sub_type == QUEST_TYPE_MULTI) 00273 { 00274 new_draw_info_format(NDI_ANIM, COLOR_NAVY, op, "Quest %s (%s): You found the quest item %s (%"FMT64"/%d)!\n", quest_object->env->name, quest_container->name, query_base_name(clone, NULL), num + 1, quest_object->last_grace); 00275 } 00276 else 00277 { 00278 new_draw_info_format(NDI_ANIM, COLOR_NAVY, op, "Quest %s: You found the quest item %s!\n", quest_container->name, query_base_name(clone, NULL)); 00279 } 00280 00281 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "event01.ogg", 0, 0, 0, 0); 00282 break; 00283 } 00284 00285 default: 00286 LOG(llevBug, "Quest object '%s' has unknown sub type (%d).\n", quest_container->name, quest_container->sub_type); 00287 } 00288 } 00289 00298 void check_quest(object *op, object *quest_container) 00299 { 00300 object *quest_object = find_quest(CONTR(op)->quest_container, quest_container->name); 00301 00302 /* Handle multi-part quests. */ 00303 if (quest_container->sub_type == QUEST_TYPE_MULTI) 00304 { 00305 object *tmp; 00306 00307 /* No quest object, can't go on. */ 00308 if (!quest_object) 00309 { 00310 return; 00311 } 00312 00313 for (tmp = quest_container->inv; tmp; tmp = tmp->below) 00314 { 00315 check_quest_container(op, tmp, find_quest(quest_object, tmp->name)); 00316 } 00317 } 00318 else 00319 { 00320 check_quest_container(op, quest_container, quest_object); 00321 } 00322 }
1.7.4