static void _doc_process_var(doc_ptr doc, cptr name) { if (strcmp(name, "version") == 0) { string_ptr s = string_alloc_format("%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH); doc_insert(doc, string_buffer(s)); string_free(s); } else if (strlen(name) > 3 && strncmp(name, "FF_", 3) == 0) { char buf[100]; int f_idx; sprintf(buf, "%s", name + 3); f_idx = f_tag_to_index(buf); if (0 <= f_idx && f_idx < max_f_idx) { string_ptr s = string_alloc(); feature_type *feat = &f_info[f_idx]; string_printf(s, "<color:%c>%c</color>", attr_to_attr_char(feat->d_attr[F_LIT_STANDARD]), feat->d_char[F_LIT_STANDARD]); doc_insert(doc, string_buffer(s)); string_free(s); } } }
static void _doc_process_tag(doc_ptr doc, doc_tag_ptr tag) { if ( tag->type == DOC_TAG_CLOSE_COLOR || tag->type == DOC_TAG_CLOSE_STYLE || tag->type == DOC_TAG_CLOSE_INDENT ) { doc_pop_style(doc); } else if (tag->type == DOC_TAG_COLOR) { assert(tag->arg); if (tag->arg_size == 1) { if (tag->arg[0] == '*') doc_pop_style(doc); else { doc_style_t style = *doc_current_style(doc); /* copy */ switch (tag->arg[0]) { case 'd': style.color = TERM_DARK; break; case 'w': style.color = TERM_WHITE; break; case 's': style.color = TERM_SLATE; break; case 'o': style.color = TERM_ORANGE; break; case 'r': style.color = TERM_RED; break; case 'g': style.color = TERM_GREEN; break; case 'b': style.color = TERM_BLUE; break; case 'u': style.color = TERM_UMBER; break; case 'D': style.color = TERM_L_DARK; break; case 'W': style.color = TERM_L_WHITE; break; case 'v': style.color = TERM_VIOLET; break; case 'y': style.color = TERM_YELLOW; break; case 'R': style.color = TERM_L_RED; break; case 'G': style.color = TERM_L_GREEN; break; case 'B': style.color = TERM_L_BLUE; break; case 'U': style.color = TERM_L_UMBER; break; } doc_push_style(doc, &style); } } else { string_ptr arg = string_copy_sn(tag->arg, tag->arg_size); doc_style_t style = *doc_current_style(doc); /* copy */ doc_style_f f = _get_doc_style_f(doc, string_buffer(arg)); if (f) f(&style); {/* We don't copy the named style, just its color. */ /* Also, we damn well better push a style or we'll be upset when the good little user pops! */ doc_style_t copy = *doc_current_style(doc); copy.color = style.color; doc_push_style(doc, ©); } string_free(arg); } } else if (tag->type == DOC_TAG_INDENT) { doc_style_t style = *doc_current_style(doc); style.left = doc->cursor.x; doc_push_style(doc, &style); } else { string_ptr arg = string_copy_sn(tag->arg, tag->arg_size); switch (tag->type) { case DOC_TAG_STYLE: if (tag->arg_size == 1 && tag->arg[0] == '*') doc_pop_style(doc); else {/* Better silently add one if name doesn't exist ... */ doc_style_t copy = *doc_current_style(doc); doc_style_f f = _get_doc_style_f(doc, string_buffer(arg)); if (f) f(©); doc_push_style(doc, ©); } break; case DOC_TAG_VAR: _doc_process_var(doc, string_buffer(arg)); break; case DOC_TAG_TAB: { int pos = atoi(string_buffer(arg)) + doc_current_style(doc)->left; if (pos > doc->cursor.x) doc_insert_space(doc, pos - doc->cursor.x); else doc_rollback(doc, doc_pos_create(pos, doc->cursor.y)); break; } case DOC_TAG_TOPIC: { doc_bookmark_ptr mark = malloc(sizeof(doc_bookmark_t)); mark->name = arg; /* steal ownership */ arg = NULL; mark->pos = doc->cursor; vec_add(doc->bookmarks, mark); break; } case DOC_TAG_LINK: { doc_link_ptr link = malloc(sizeof(doc_link_t)); int split = string_chr(arg, 0, '#'); int ch = 'a' + int_map_count(doc->links); if (split >= 0) { substring_t left = string_left(arg, split); substring_t right = string_right(arg, string_length(arg) - split - 1); link->file = substring_copy(&left); link->topic = substring_copy(&right); } else { link->file = arg; /* steal ownership */ arg = NULL; link->topic = NULL; } link->location.start = doc->cursor; int_map_add(doc->links, ch, link); { /* TODO: This is flawed. Here's a real world example: "(see below <link:birth.txt#PrimaryStats>)." Can you see the problem? We might line break after "[a]" right before ").". Instead, "[a])." should be treated as the current word. To fix this, we'll need a parser with a token queue that we can push onto, but this raises storage issues. */ string_ptr s = string_alloc_format("<style:link>[%c]</style>", ch); doc_insert(doc, string_buffer(s)); string_free(s); link->location.stop = doc->cursor; } break; } } string_free(arg); } }
void gray_mage_gain_spell(void) { int item; if (p_ptr->blind || no_lite()) { msg_print("You cannot see!"); return; } if (p_ptr->confused) { msg_print("You are too confused!"); return; } if (!p_ptr->new_spells) { msg_print("You cannot learn any new spells!"); return; } item_tester_hook = _spell_book_p; if (get_item(&item, "Study which book?", "You have no books that you can read.", USE_INVEN)) { object_type *o_ptr = &inventory[item]; int spell_idx; _slot_info_ptr slot_ptr; /* Pick a spell to learn */ spell_idx = _choose_spell_to_gain(o_ptr); if (spell_idx == -1) return; /* Pick a slot for storage (possibly replacing an already learned spell) */ slot_ptr = _choose("Replace", _ALLOW_EMPTY | _SHOW_INFO); if (!slot_ptr) return; if (slot_ptr->realm != REALM_NONE) { string_ptr prompt = string_alloc_format( "Really replace %s? <color:y>[y/N]</color>", do_spell(slot_ptr->realm, slot_ptr->spell, SPELL_NAME)); if (msg_prompt(string_buffer(prompt), "ny", PROMPT_DEFAULT) == 'n') { string_free(prompt); return; } string_free(prompt); } /* Learn the spell: Note, we don't bother with spell_learned# and spell_order[], since these are hard coded for 2 spell realms. Hopefully, ticking up learned_spells is enough? */ p_ptr->learned_spells++; slot_ptr->realm = tval2realm(o_ptr->tval); slot_ptr->spell = spell_idx; msg_format("You have learned the spell '%s'.", do_spell(slot_ptr->realm, slot_ptr->spell, SPELL_NAME)); p_ptr->update |= PU_SPELLS; p_ptr->redraw |= PR_EFFECTS; energy_use = 100; } }